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.wink.common.internal.providers.entity.AssetProvider 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.wink.common.internal.providers.entity;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
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.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.Providers;
import org.apache.wink.common.RuntimeContext;
import org.apache.wink.common.annotations.Asset;
import org.apache.wink.common.annotations.Scope;
import org.apache.wink.common.annotations.Scope.ScopeType;
import org.apache.wink.common.internal.i18n.Messages;
import org.apache.wink.common.internal.registry.Injectable;
import org.apache.wink.common.internal.registry.Injectable.ParamType;
import org.apache.wink.common.internal.registry.InjectableFactory;
import org.apache.wink.common.internal.runtime.RuntimeContextTLS;
import org.apache.wink.common.internal.utils.AnnotationUtils;
import org.apache.wink.common.internal.utils.GenericsUtils;
import org.apache.wink.common.internal.utils.MediaTypeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Scope(ScopeType.PROTOTYPE)
@Provider
public class AssetProvider implements MessageBodyReader, MessageBodyWriter {
private static final Logger logger = LoggerFactory.getLogger(AssetProvider.class);
@Context
private Providers providers;
private MessageBodyWriter writer;
private BaseAssetMethod method;
public long getSize(Object t,
Class type,
Type genericType,
Annotation[] annotations,
MediaType mediaType) {
return -1;
}
public boolean isWriteable(Class type,
Type genericType,
Annotation[] annotations,
MediaType mediaType) {
// must be annotated with @Asset
if (type.getAnnotation(Asset.class) == null) {
return false;
}
return findProducesMethod(type, annotations, mediaType);
}
public void writeTo(Object t,
Class type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap httpHeaders,
OutputStream entityStream) throws IOException, WebApplicationException {
RuntimeContext context = getRuntimeContext();
// instantiate parameters of the asset method
Object[] args =
InjectableFactory.getInstance().instantiate(method.getFormalParameters(), context);
try {
// invoke the asset method to produce the object to write
Object object = method.getMethod().invoke(t, args);
// write the object
writer.writeTo(object,
method.getTypeClass(),
method.getType(),
annotations,
mediaType,
httpHeaders,
entityStream);
} catch (IllegalArgumentException e) {
if (logger.isErrorEnabled()) {
logger.error(Messages
.getMessage("assetMethodInvokeError", method.getMethod().getName()), e); //$NON-NLS-1$
}
throw new WebApplicationException(e);
} catch (IllegalAccessException e) {
if (logger.isErrorEnabled()) {
logger.error(Messages
.getMessage("assetMethodInvokeError", method.getMethod().getName()), e); //$NON-NLS-1$
}
throw new WebApplicationException(e);
} catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException)targetException;
}
if (logger.isErrorEnabled()) {
logger.error(Messages
.getMessage("assetMethodInvokeError", method.getMethod().getName()), e); //$NON-NLS-1$
}
throw new WebApplicationException(targetException);
}
}
public boolean isReadable(Class type,
Type genericType,
Annotation[] annotations,
MediaType mediaType) {
// must be annotated with @Asset
if (type.getAnnotation(Asset.class) == null) {
return false;
}
return findConsumesMethod(type, annotations, mediaType);
}
public Object readFrom(Class type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap httpHeaders,
InputStream entityStream) throws IOException, WebApplicationException {
RuntimeContext context = getRuntimeContext();
// instantiate parameters of the asset method.
// since the formal parameters contain an Entity parameter, it is
// populated
// during the call to the instantiate method. there is no need to
// manually call
// the reader for getting the entity
Object[] args =
InjectableFactory.getInstance().instantiate(method.getFormalParameters(), context);
try {
// create the asset
Object asset = type.newInstance();
// invoke the asset method to consume the entity that was read
method.getMethod().invoke(asset, args);
return asset;
} catch (RuntimeException e) {
throw e;
} catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException)targetException;
}
if (logger.isErrorEnabled()) {
logger.error(Messages
.getMessage("assetMethodInvokeError", method.getMethod().getName()), e); //$NON-NLS-1$
}
throw new WebApplicationException(e);
} catch (InstantiationException e) {
if (logger.isErrorEnabled()) {
logger.error(Messages.getMessage("assetMustHavePublicConstructor", type.getName()), e); //$NON-NLS-1$
}
throw new WebApplicationException(e);
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error(Messages
.getMessage("assetMethodInvokeError", method.getMethod().getName()), e); //$NON-NLS-1$
}
throw new WebApplicationException(e);
}
}
private RuntimeContext getRuntimeContext() {
return RuntimeContextTLS.getRuntimeContext();
}
@SuppressWarnings("unchecked")
private boolean findProducesMethod(Class assetType,
Annotation[] annotations,
MediaType mediaType) {
// get all writable locator methods
List methods = getProducingMethods(assetType, mediaType);
// sort the methods according to media types in descending order
Collections.sort(methods, new Comparator() {
public int compare(ProducesMethod o1, ProducesMethod o2) {
return o2.compareTo(o1);
}
});
// find a method that can be handled
// use the return type of the method to find the actual provider
for (ProducesMethod method : methods) {
MessageBodyWriter writer =
providers.getMessageBodyWriter(method.getTypeClass(),
method.getType(),
annotations,
mediaType);
if (writer != null) {
this.writer = (MessageBodyWriter)writer;
this.method = method;
return true;
}
}
// couldn't find any method in the asset that we can use
return false;
}
private boolean findConsumesMethod(Class assetType,
Annotation[] annotations,
MediaType mediaType) {
// verify that the asset has a default public constructor
try {
if (assetType.getConstructor() == null) {
if (logger.isWarnEnabled()) {
logger.warn(Messages.getMessage("assetCannotInstantiate", assetType.getName())); //$NON-NLS-1$
}
return false;
}
} catch (SecurityException e) {
if (logger.isWarnEnabled()) {
logger.warn(Messages.getMessage("assetCannotInstantiate", assetType.getName()), e); //$NON-NLS-1$
}
return false;
} catch (NoSuchMethodException e) {
if (logger.isWarnEnabled()) {
logger.warn(Messages.getMessage("assetCannotInstantiate", assetType.getName()), e); //$NON-NLS-1$
}
return false;
}
// get all writable locator methods
List methods = getConsumingMethods(assetType, mediaType);
// sort the methods according to media types in descending order
Collections.sort(methods, new Comparator() {
public int compare(ConsumesMethod o1, ConsumesMethod o2) {
return o2.compareTo(o1);
}
});
// find a consuming method that has a message body reader
for (ConsumesMethod method : methods) {
MessageBodyReader reader =
providers.getMessageBodyReader(method.getTypeClass(),
method.getType(),
annotations,
mediaType);
if (reader != null) {
// we don't need to save the reader because when we prepare the
// parameters to inject to the locator method, the entity
// parameter will also be
// populated
this.method = method;
return true;
}
}
// couldn't find any method in the asset that we can use
return false;
}
private List getProducingMethods(Class assetType, MediaType mediaType) {
// collect all the methods that are annotated with @Produces
List locators = new LinkedList();
Method[] methods = assetType.getMethods();
for (Method method : methods) {
Produces annotation = method.getAnnotation(Produces.class);
if (annotation != null) {
String[] producesArray =
AnnotationUtils.parseConsumesProducesValues(annotation.value());
List produces = toSortedMediaTypes(producesArray);
for (MediaType mt : produces) {
if (mt.isCompatible(mediaType)) {
ProducesMethod prodcuesMethod = new ProducesMethod(method, mt);
if (prodcuesMethod.getType() != null) {
locators.add(prodcuesMethod);
}
}
}
}
}
return locators;
}
private List getConsumingMethods(Class assetType, MediaType mediaType) {
// collect all the methods that are annotated with @Consumes
List locators = new LinkedList();
Method[] methods = assetType.getMethods();
for (Method method : methods) {
Consumes annotation = method.getAnnotation(Consumes.class);
if (annotation != null) {
String[] producesArray =
AnnotationUtils.parseConsumesProducesValues(annotation.value());
List produces = toSortedMediaTypes(producesArray);
for (MediaType mt : produces) {
if (mt.isCompatible(mediaType)) {
ConsumesMethod consumesMethod = new ConsumesMethod(method, mt);
if (consumesMethod.getType() != null) {
locators.add(consumesMethod);
}
}
}
}
}
return locators;
}
private List toSortedMediaTypes(String[] array) {
List list = new LinkedList();
for (String mt : array) {
list.add(MediaType.valueOf(mt));
}
// sort the list of media types
Collections.sort(list, new Comparator() {
public int compare(MediaType o1, MediaType o2) {
// compare in descending order
return MediaTypeUtils.compareTo(o2, o1);
}
});
return list;
}
private static abstract class BaseAssetMethod implements Comparable {
private Method method;
private List formalParameters;
private MediaType mediaType;
protected Type type;
protected Class typeClass;
public BaseAssetMethod(Method method, MediaType mediaType) {
this.method = method;
this.mediaType = mediaType;
createFormalParameters();
}
private void createFormalParameters() {
formalParameters = new LinkedList();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
Type[] paramTypes = method.getGenericParameterTypes();
for (int pos = 0, limit = paramTypes.length; pos < limit; pos++) {
Injectable fp =
InjectableFactory.getInstance().create(paramTypes[pos],
parameterAnnotations[pos],
method,
false,
null);
formalParameters.add(fp);
}
}
public List getFormalParameters() {
return formalParameters;
}
public Method getMethod() {
return method;
}
public MediaType getMediaType() {
return mediaType;
}
public Type getType() {
return type;
}
public Class getTypeClass() {
return typeClass;
}
@Override
public boolean equals(Object obj) {
return method.equals(obj);
}
@Override
public int hashCode() {
return method.hashCode();
}
public int compareTo(BaseAssetMethod o) {
return MediaTypeUtils.compareTo(getMediaType(), o.getMediaType());
}
}
private static class ProducesMethod extends BaseAssetMethod {
public ProducesMethod(Method method, MediaType mediaType) {
super(method, mediaType);
this.type = method.getGenericReturnType();
this.typeClass = GenericsUtils.getClassType(type, method.getDeclaringClass());
}
}
private static class ConsumesMethod extends BaseAssetMethod {
public ConsumesMethod(Method method, MediaType mediaType) {
super(method, mediaType);
for (Injectable fp : getFormalParameters()) {
if (fp.getParamType() == ParamType.ENTITY) {
if (type != null) {
// we allow to have only one entity parameter
String methodName =
method.getDeclaringClass().getName() + "." + method.getName(); //$NON-NLS-1$
if (logger.isErrorEnabled()) {
logger
.error(Messages
.getMessage("assetLocatorMethodMoreThanOneEntityParam", methodName)); //$NON-NLS-1$
}
throw new WebApplicationException();
}
type = fp.getGenericType();
typeClass = fp.getType();
}
}
}
}
}