Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.cxf.jaxrs.provider.atom.AtomPojoProvider Maven / Gradle / Ivy
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.jaxrs.provider.atom;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.Consumes;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.Produces;
import javax.ws.rs.ServerErrorException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import org.apache.abdera.Abdera;
import org.apache.abdera.factory.Factory;
import org.apache.abdera.model.Content;
import org.apache.abdera.model.Element;
import org.apache.abdera.model.Entry;
import org.apache.abdera.model.ExtensibleElement;
import org.apache.abdera.model.Feed;
import org.apache.abdera.writer.Writer;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.jaxrs.ext.MessageContext;
import org.apache.cxf.jaxrs.provider.AbstractConfigurableProvider;
import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
import org.apache.cxf.jaxrs.utils.InjectionUtils;
@Produces({"application/atom+xml", "application/atom+xml;type=feed", "application/atom+xml;type=entry" })
@Consumes({"application/atom+xml", "application/atom+xml;type=feed", "application/atom+xml;type=entry" })
@Provider
public class AtomPojoProvider extends AbstractConfigurableProvider
implements MessageBodyWriter, MessageBodyReader {
private static final Logger LOG = LogUtils.getL7dLogger(AtomPojoProvider.class);
private static final Abdera ATOM_ENGINE = new Abdera();
private static final String DEFAULT_ENTRY_CONTENT_METHOD = "getContent";
private JAXBElementProvider jaxbProvider = new JAXBElementProvider();
private Map collectionGetters = Collections.emptyMap();
private Map collectionSetters = Collections.emptyMap();
private Map, AtomElementWriter, ?>> atomClassWriters = Collections.emptyMap();
private Map, AtomElementReader, ?>> atomClassReaders = Collections.emptyMap();
private Map, AbstractAtomElementBuilder>> atomClassBuilders = Collections.emptyMap();
//Consider deprecating String based maps
private Map> atomWriters = Collections.emptyMap();
private Map> atomReaders = Collections.emptyMap();
private Map> atomBuilders = Collections.emptyMap();
private MessageContext mc;
private boolean formattedOutput;
private boolean useJaxbForContent = true;
private boolean autodetectCharset;
private String entryContentMethodName = DEFAULT_ENTRY_CONTENT_METHOD;
public void setUseJaxbForContent(boolean use) {
this.useJaxbForContent = use;
}
public void setEntryContentMethodName(String name) {
this.entryContentMethodName = name;
}
@Context
public void setMessageContext(MessageContext context) {
mc = context;
for (AbstractAtomElementBuilder> builder : atomClassBuilders.values()) {
builder.setMessageContext(context);
}
for (AtomElementWriter, ?> writer : atomClassWriters.values()) {
tryInjectMessageContext(writer);
}
for (AtomElementReader, ?> reader : atomClassReaders.values()) {
tryInjectMessageContext(reader);
}
for (AbstractAtomElementBuilder> builder : atomBuilders.values()) {
builder.setMessageContext(context);
}
for (AtomElementWriter, ?> writer : atomWriters.values()) {
tryInjectMessageContext(writer);
}
for (AtomElementReader, ?> reader : atomReaders.values()) {
tryInjectMessageContext(reader);
}
}
protected void tryInjectMessageContext(Object handler) {
try {
Method m = handler.getClass().getMethod("setMessageContext",
new Class[]{MessageContext.class});
InjectionUtils.injectThroughMethod(handler, m, mc);
} catch (Throwable t) {
LOG.warning("Message context can not be injected into " + handler.getClass().getName()
+ " : " + t.getMessage());
}
}
public long getSize(Object t, Class> type, Type genericType, Annotation[] annotations, MediaType mt) {
return -1;
}
public void setCollectionGetters(Map methods) {
collectionGetters = methods;
}
public void setCollectionSetters(Map methods) {
collectionSetters = methods;
}
public boolean isWriteable(Class> type, Type genericType, Annotation[] annotations, MediaType mt) {
return !Feed.class.isAssignableFrom(type) && !Entry.class.isAssignableFrom(type);
}
public void writeTo(Object o, Class> cls, Type genericType, Annotation[] annotations,
MediaType mt, MultivaluedMap headers, OutputStream os)
throws IOException {
boolean isFeed = isFeedRequested(mt);
boolean isCollection = InjectionUtils.isSupportedCollectionOrArray(cls);
if (isFeed && isCollection) {
reportError("Atom feed can only be created from a collection wrapper", null);
} else if (!isFeed && isCollection) {
reportError("Atom entry can only be created from a single object", null);
}
Factory factory = Abdera.getNewFactory();
Element atomElement = null;
try {
if (isFeed && !isCollection) {
atomElement = createFeedFromCollectionWrapper(factory, o, cls);
} else if (!isFeed && !isCollection) {
atomElement = createEntryFromObject(factory, o, cls);
}
} catch (Exception ex) {
throw new InternalServerErrorException(ex);
}
try {
writeAtomElement(atomElement, os);
} catch (IOException ex) {
reportError("Atom element can not be serialized", ex);
}
}
private void writeAtomElement(Element atomElement, OutputStream os) throws IOException {
Writer w = formattedOutput ? createWriter("prettyxml") : null;
if (w != null) {
atomElement.writeTo(w, os);
} else {
atomElement.writeTo(os);
}
}
protected Writer createWriter(String writerName) {
return ATOM_ENGINE.getWriterFactory().getWriter(writerName);
}
public void setFormattedOutput(boolean formattedOutput) {
this.formattedOutput = formattedOutput;
}
protected Feed createFeedFromCollectionWrapper(Factory factory, Object o, Class> pojoClass)
throws Exception {
Feed feed = factory.newFeed();
boolean writerUsed = buildFeed(feed, o, pojoClass);
if (feed.getEntries().size() > 0) {
return feed;
}
String methodName = getCollectionMethod(o.getClass(), true);
Object collection = null;
Method m = null;
try {
m = o.getClass().getMethod(methodName, new Class[]{});
collection = m.invoke(o, new Object[]{});
} catch (Exception ex) {
reportError("Collection for " + o.getClass().getName() + " can not be retrieved", ex);
}
setFeedFromCollection(factory, feed, o, pojoClass, collection, m.getReturnType(),
m.getGenericReturnType(), writerUsed);
return feed;
}
private String getCollectionMethod(Class> cls, boolean getter) {
Map map = getter ? collectionGetters : collectionSetters;
String methodName = getCollectionMethod(map, cls);
if (methodName == null) {
try {
methodName = (getter ? "get" : "set") + cls.getSimpleName();
Class>[] params = getter ? new Class[]{} : new Class[]{List.class};
cls.getMethod(methodName, params);
} catch (Exception ex) {
String type = getter ? "getter" : "setter";
reportError("Collection " + type + " method for " + cls.getName()
+ " has not been specified and no default " + methodName + " is available", null);
}
}
return methodName;
}
private String getCollectionMethod(Map map, Class> pojoClass) {
if (pojoClass == Object.class) {
return null;
}
String method = map.get(pojoClass.getName());
if (method != null) {
return method;
} else {
return getCollectionMethod(map, pojoClass.getSuperclass());
}
}
@SuppressWarnings("unchecked")
protected boolean buildFeed(Feed feed, X o, Class> pojoClass) {
AtomElementWriter, ?> builder = getAtomWriter(pojoClass);
if (builder != null) {
((AtomElementWriter)builder).writeTo(feed, o);
return true;
}
return false;
}
protected AtomElementWriter, ?> getAtomWriter(Class> pojoClass) {
AtomElementWriter, ?> writer = getAtomClassElementHandler(atomClassWriters, pojoClass);
return writer == null && atomWriters != null
? getAtomElementHandler(atomWriters, pojoClass) : writer;
}
protected AtomElementReader, ?> getAtomReader(Class> pojoClass) {
AtomElementReader, ?> reader = getAtomClassElementHandler(atomClassReaders, pojoClass);
return reader == null && atomReaders != null
? getAtomElementHandler(atomReaders, pojoClass) : reader;
}
private T getAtomClassElementHandler(Map, T> handlers, Class> pojoClass) {
for (Map.Entry, T> entry : handlers.entrySet()) {
if (entry.getKey().isAssignableFrom(pojoClass)) {
return entry.getValue();
}
}
return null;
}
protected T getAtomElementHandler(Map handlers, Class> pojoClass) {
T handler = getAtomElementHandlerSuperClass(handlers, pojoClass);
if (handler == null) {
Class>[] interfaces = pojoClass.getInterfaces();
for (Class> inter : interfaces) {
handler = handlers.get(inter.getName());
if (handler != null) {
break;
}
}
}
return handler;
}
private T getAtomElementHandlerSuperClass(Map handlers, Class> pojoClass) {
if (pojoClass == null || pojoClass == Object.class) {
return null;
}
T handler = handlers.get(pojoClass.getName());
if (handler != null) {
return handler;
} else {
return getAtomElementHandlerSuperClass(handlers, pojoClass.getSuperclass());
}
}
//CHECKSTYLE:OFF
protected void setFeedFromCollection(Factory factory,
Feed feed,
Object wrapper,
Class> wrapperCls,
Object collection,
Class> collectionCls,
Type collectionType,
boolean writerUsed) throws Exception {
//CHECKSTYLE:ON
Object[] arr = collectionCls.isArray() ? (Object[])collection : ((Collection>)collection).toArray();
Class> memberClass = InjectionUtils.getActualType(collectionType);
for (Object o : arr) {
Entry entry = createEntryFromObject(factory, o, memberClass);
feed.addEntry(entry);
}
if (!writerUsed) {
setFeedProperties(factory, feed, wrapper, wrapperCls, collection, collectionCls, collectionType);
}
}
protected AbstractAtomElementBuilder> getAtomBuilder(Class> pojoClass) {
AbstractAtomElementBuilder> builder = getAtomClassElementHandler(atomClassBuilders, pojoClass);
return builder == null && atomBuilders != null
? getAtomElementHandler(atomBuilders, pojoClass) : builder;
}
@SuppressWarnings("unchecked")
protected void setFeedProperties(Factory factory,
Feed feed,
Object wrapper,
Class> wrapperCls,
Object collection,
Class> collectionCls,
Type collectionType) {
AbstractAtomElementBuilder builder =
(AbstractAtomElementBuilder)getAtomBuilder(wrapperCls);
if (builder == null) {
return;
}
setCommonElementProperties(factory, feed, builder, wrapper);
AbstractFeedBuilder theBuilder = (AbstractFeedBuilder)builder;
// the hierarchy is a bit broken in that we can not set author/title.etc on some
// common Feed/Entry super type
String author = theBuilder.getAuthor(wrapper);
if (author != null) {
feed.addAuthor(author);
} else {
feed.addAuthor("CXF JAX-RS");
}
String title = theBuilder.getTitle(wrapper);
if (title != null) {
feed.setTitle(title);
} else {
feed.setTitle(String.format(wrapper.getClass().getSimpleName()
+ " collection with %d entry(ies)", feed.getEntries().size()));
}
String id = theBuilder.getId(wrapper);
if (id != null) {
feed.setId(id);
} else {
feed.setId("uuid:" + UUID.randomUUID().toString());
}
String updated = theBuilder.getUpdated(wrapper);
if (updated != null) {
feed.setUpdated(updated);
} else {
feed.setUpdated(new Date());
}
Map links = theBuilder.getLinks(wrapper);
if (links != null) {
for (Map.Entry entry : links.entrySet()) {
feed.addLink(entry.getKey(), entry.getValue());
}
}
List terms = theBuilder.getCategories(wrapper);
if (terms != null) {
for (String term : terms) {
feed.addCategory(term);
}
}
// feed specific
String logo = theBuilder.getLogo(wrapper);
if (logo != null) {
feed.setLogo(logo);
}
String icon = theBuilder.getLogo(wrapper);
if (icon != null) {
feed.setIcon(icon);
}
}
protected Entry createEntryFromObject(Factory factory, Object o, Class> cls) throws Exception {
Entry entry = factory.getAbdera().newEntry();
if (!buildEntry(entry, o, cls)) {
setEntryProperties(factory, entry, o, cls);
}
if (entry.getContentElement() == null
&& entry.getExtensions().size() == 0) {
createEntryContent(factory, entry, o, cls);
}
return entry;
}
@SuppressWarnings("unchecked")
protected boolean buildEntry(Entry entry, Object o, Class> pojoClass) {
AtomElementWriter, ?> builder = getAtomWriter(pojoClass);
if (builder != null) {
((AtomElementWriter)builder).writeTo(entry, o);
return true;
}
return false;
}
protected void createEntryContent(Factory factory, Entry e, Object o, Class> cls) throws Exception {
String content = null;
if (useJaxbForContent) {
JAXBContext jc = jaxbProvider.getJAXBContext(cls, cls);
StringWriter writer = new StringWriter();
jc.createMarshaller().marshal(o, writer);
content = writer.toString();
} else {
Method m = cls.getMethod(entryContentMethodName, new Class[]{});
content = (String)m.invoke(o, new Object[]{});
}
setEntryContent(factory, e, content);
}
protected void setEntryContent(Factory factory, Entry e, String content) {
Content ct = factory.newContent(Content.Type.XML);
ct.setValue(content);
e.setContentElement(ct);
}
protected void setEntryProperties(Factory factory, Entry entry,
Object o, Class> cls) {
@SuppressWarnings("unchecked")
AbstractAtomElementBuilder builder
= (AbstractAtomElementBuilder)getAtomBuilder(cls);
if (builder == null) {
return;
}
setCommonElementProperties(factory, entry, builder, o);
AbstractEntryBuilder theBuilder = (AbstractEntryBuilder)builder;
String author = theBuilder.getAuthor(o);
if (author != null) {
entry.addAuthor(author);
} else {
entry.addAuthor("CXF JAX-RS");
}
String title = theBuilder.getTitle(o);
if (title != null) {
entry.setTitle(title);
} else {
entry.setTitle(o.getClass().getSimpleName());
}
String id = theBuilder.getId(o);
if (id != null) {
entry.setId(id);
} else {
entry.setId("uuid:" + UUID.randomUUID().toString());
}
String updated = theBuilder.getUpdated(o);
if (updated != null) {
entry.setUpdated(updated);
} else {
entry.setUpdated(new Date());
}
Map links = theBuilder.getLinks(o);
if (links != null) {
for (Map.Entry e : links.entrySet()) {
entry.addLink(e.getKey(), e.getValue());
}
}
// entry specific
String published = theBuilder.getPublished(o);
if (published != null) {
entry.setPublished(published);
}
String summary = theBuilder.getSummary(o);
if (summary != null) {
entry.setSummary(summary);
}
List terms = theBuilder.getCategories(o);
if (terms != null) {
for (String term : terms) {
entry.addCategory(term);
}
}
String content = theBuilder.getContent(o);
if (content != null) {
setEntryContent(factory, entry, content);
}
}
private void setCommonElementProperties(Factory factory, ExtensibleElement element,
AbstractAtomElementBuilder builder,
Object o) {
String baseUri = builder.getBaseUri(o);
if (baseUri != null) {
element.setBaseUri(baseUri);
}
}
private void reportError(String message, Exception ex, int status) {
LOG.warning(message);
Response response = Response.status(status).type("text/plain").entity(message).build();
if (ex == null) {
throw status < 500 ? new ClientErrorException(response) : new ServerErrorException(response);
} else {
throw status < 500 ? new ClientErrorException(response, ex) : new ServerErrorException(response, ex);
}
}
private void reportError(String message, Exception ex) {
reportError(message, ex, 500);
}
private boolean isFeedRequested(MediaType mt) {
if ("entry".equals(mt.getParameters().get("type"))) {
return false;
}
return true;
}
public void setAtomWriters(Map> writers) {
this.atomWriters = writers;
}
public void setAtomReaders(Map> readers) {
this.atomReaders = readers;
}
public void setAtomBuilders(Map> builders) {
this.atomBuilders = builders;
}
public void setAtomClassWriters(Map, AtomElementWriter, ?>> writers) {
this.atomClassWriters = writers;
}
public void setAtomClassReaders(Map, AtomElementReader, ?>> readers) {
this.atomClassReaders = readers;
}
public void setAtomClassBuilders(Map, AbstractAtomElementBuilder>> builders) {
this.atomClassBuilders = builders;
}
public boolean isReadable(Class> type, Type genericType, Annotation[] annotations,
MediaType mediaType) {
return true;
}
public Object readFrom(Class cls, Type type, Annotation[] anns, MediaType mt,
MultivaluedMap headers, InputStream is)
throws IOException, WebApplicationException {
boolean isFeed = isFeedRequested(mt);
if (isFeed) {
return readFromFeed(cls, mt, headers, is);
} else {
AtomEntryProvider p = new AtomEntryProvider();
p.setAutodetectCharset(autodetectCharset);
Entry entry = p.readFrom(Entry.class, Entry.class,
new Annotation[]{}, mt, headers, is);
return readFromEntry(entry, cls, mt, headers, is);
}
}
@SuppressWarnings("unchecked")
private Object readFromFeed(Class cls, MediaType mt,
MultivaluedMap headers, InputStream is)
throws IOException {
AtomFeedProvider p = new AtomFeedProvider();
p.setAutodetectCharset(autodetectCharset);
Feed feed = p.readFrom(Feed.class, Feed.class, new Annotation[]{}, mt, headers, is);
AtomElementReader, ?> reader = getAtomReader(cls);
if (reader != null) {
return ((AtomElementReader)reader).readFrom(feed);
}
Object instance = null;
try {
String methodName = getCollectionMethod(cls, false);
Method m = cls.getMethod(methodName, new Class[]{List.class});
Class realCls
= (Class)InjectionUtils.getActualType(m.getGenericParameterTypes()[0]);
List objects = new ArrayList();
for (Entry e : feed.getEntries()) {
objects.add(readFromEntry(e, realCls, mt, headers, is));
}
instance = cls.newInstance();
m.invoke(instance, new Object[]{objects});
} catch (Exception ex) {
reportError("Object of type " + cls.getName() + " can not be deserialized from Feed", ex, 400);
}
return instance;
}
@SuppressWarnings("unchecked")
private Object readFromEntry(Entry entry, Class cls, MediaType mt,
MultivaluedMap headers, InputStream is)
throws IOException {
AtomElementReader, ?> reader = getAtomReader(cls);
if (reader != null) {
return ((AtomElementReader)reader).readFrom(entry);
}
try {
Unmarshaller um =
jaxbProvider.getJAXBContext(cls, cls).createUnmarshaller();
return cls.cast(um.unmarshal(new StringReader(entry.getContent())));
} catch (Exception ex) {
reportError("Object of type " + cls.getName() + " can not be deserialized from Entry", ex, 400);
}
return null;
}
public void setAutodetectCharset(boolean autodetectCharset) {
this.autodetectCharset = autodetectCharset;
}
}