use of org.glassfish.jersey.message.internal.AcceptableMediaType in project jersey by jersey.
the class MethodSelectingRouter method selectMethod.
/**
* Select method to be invoked. Method is chosen among the given set of acceptors (if they are compatible with acceptable
* media types).
*
* @param acceptableMediaTypes media types acceptable by the client.
* @param satisfyingAcceptors pre-computed acceptors.
* @param effectiveContentType media type of incoming entity.
* @param singleInvokableMethod flag determining whether only one method to be invoked has been found among satisfying
* acceptors.
* @return method to be invoked.
*/
private MethodSelector selectMethod(final List<AcceptableMediaType> acceptableMediaTypes, final List<ConsumesProducesAcceptor> satisfyingAcceptors, final MediaType effectiveContentType, final boolean singleInvokableMethod) {
// Selected method we have a reader and writer for.
final MethodSelector method = new MethodSelector(null);
// If we cannot find a writer at this point use the best alternative.
final MethodSelector alternative = new MethodSelector(null);
for (final MediaType acceptableMediaType : acceptableMediaTypes) {
for (final ConsumesProducesAcceptor satisfiable : satisfyingAcceptors) {
final CombinedMediaType produces = CombinedMediaType.create(acceptableMediaType, satisfiable.produces);
if (produces != CombinedMediaType.NO_MATCH) {
final CombinedMediaType consumes = CombinedMediaType.create(effectiveContentType, satisfiable.consumes);
final RequestSpecificConsumesProducesAcceptor candidate = new RequestSpecificConsumesProducesAcceptor(consumes, produces, satisfiable.produces.isDerived(), satisfiable.methodRouting);
if (singleInvokableMethod) {
// Only one possible method and it's compatible.
return new MethodSelector(candidate);
} else if (candidate.compareTo(method.selected) < 0) {
// Candidate is better than the previous one.
if (method.selected == null || candidate.methodRouting.method != method.selected.methodRouting.method) {
// No candidate so far or better candidate.
if (isReadable(candidate) && isWriteable(candidate)) {
method.consider(candidate);
} else {
alternative.consider(candidate);
}
} else {
// Same resource method - better candidate, no need to compare anything else.
method.consider(candidate);
}
}
}
}
}
return method.selected != null ? method : alternative;
}
use of org.glassfish.jersey.message.internal.AcceptableMediaType in project jersey by jersey.
the class MethodSelectingRouter method getMethodRouter.
private List<Router> getMethodRouter(final RequestProcessingContext context) {
final ContainerRequest request = context.request();
final List<ConsumesProducesAcceptor> acceptors = consumesProducesAcceptors.get(request.getMethod());
if (acceptors == null) {
throw new NotAllowedException(Response.status(Status.METHOD_NOT_ALLOWED).allow(consumesProducesAcceptors.keySet()).build());
}
final List<ConsumesProducesAcceptor> satisfyingAcceptors = new LinkedList<>();
final Set<ResourceMethod> differentInvokableMethods = Collections.newSetFromMap(new IdentityHashMap<>());
for (ConsumesProducesAcceptor cpi : acceptors) {
if (cpi.isConsumable(request)) {
satisfyingAcceptors.add(cpi);
differentInvokableMethods.add(cpi.methodRouting.method);
}
}
if (satisfyingAcceptors.isEmpty()) {
throw new NotSupportedException();
}
final List<AcceptableMediaType> acceptableMediaTypes = request.getQualifiedAcceptableMediaTypes();
final MediaType requestContentType = request.getMediaType();
final MediaType effectiveContentType = requestContentType == null ? MediaType.WILDCARD_TYPE : requestContentType;
final MethodSelector methodSelector = selectMethod(acceptableMediaTypes, satisfyingAcceptors, effectiveContentType, differentInvokableMethods.size() == 1);
if (methodSelector.selected != null) {
final RequestSpecificConsumesProducesAcceptor selected = methodSelector.selected;
if (methodSelector.sameFitnessAcceptors != null) {
reportMethodSelectionAmbiguity(acceptableMediaTypes, methodSelector.selected, methodSelector.sameFitnessAcceptors);
}
context.push(new Function<ContainerResponse, ContainerResponse>() {
@Override
public ContainerResponse apply(final ContainerResponse responseContext) {
// - either there is an entity, or we are responding to a HEAD request
if (responseContext.getMediaType() == null && ((responseContext.hasEntity() || HttpMethod.HEAD.equals(request.getMethod())))) {
MediaType effectiveResponseType = determineResponseMediaType(responseContext.getEntityClass(), responseContext.getEntityType(), methodSelector.selected, acceptableMediaTypes);
if (MediaTypes.isWildcard(effectiveResponseType)) {
if (effectiveResponseType.isWildcardType() || "application".equalsIgnoreCase(effectiveResponseType.getType())) {
effectiveResponseType = MediaType.APPLICATION_OCTET_STREAM_TYPE;
} else {
throw new NotAcceptableException();
}
}
responseContext.setMediaType(effectiveResponseType);
}
return responseContext;
}
});
return selected.methodRouting.routers;
}
throw new NotAcceptableException();
}
use of org.glassfish.jersey.message.internal.AcceptableMediaType in project jersey by jersey.
the class MethodSelectingRouter method determineResponseMediaType.
/**
* Determine the {@link MediaType} of the {@link Response} based on writers suitable for the given entity class,
* pre-selected method and acceptable media types.
*
* @param entityClass entity class to determine the media type for.
* @param entityType entity type for writers.
* @param selectedMethod pre-selected (invoked) method.
* @param acceptableMediaTypes acceptable media types from request.
* @return media type of the response.
*/
private MediaType determineResponseMediaType(final Class<?> entityClass, final Type entityType, final RequestSpecificConsumesProducesAcceptor selectedMethod, final List<AcceptableMediaType> acceptableMediaTypes) {
// Return pre-selected MediaType.
if (usePreSelectedMediaType(selectedMethod, acceptableMediaTypes)) {
return selectedMethod.produces.combinedType;
}
final ResourceMethod resourceMethod = selectedMethod.methodRouting.method;
final Invocable invocable = resourceMethod.getInvocable();
// Entity class can be null when considering HEAD method || empty entity.
final Class<?> responseEntityClass = entityClass == null ? invocable.getRawRoutingResponseType() : entityClass;
final Method handlingMethod = invocable.getHandlingMethod();
// Media types producible by method.
final List<MediaType> methodProducesTypes = !resourceMethod.getProducedTypes().isEmpty() ? resourceMethod.getProducedTypes() : Collections.singletonList(MediaType.WILDCARD_TYPE);
// Applicable entity providers
final List<WriterModel> writersForEntityType = workers.getWritersModelsForType(responseEntityClass);
CombinedMediaType selected = null;
for (final MediaType acceptableMediaType : acceptableMediaTypes) {
for (final MediaType methodProducesType : methodProducesTypes) {
if (!acceptableMediaType.isCompatible(methodProducesType)) {
// no need to go deeper if acceptable and method produces type are incompatible
continue;
}
// Use writers suitable for entity class to determine the media type.
for (final WriterModel model : writersForEntityType) {
for (final MediaType writerProduces : model.declaredTypes()) {
if (!writerProduces.isCompatible(acceptableMediaType) || !methodProducesType.isCompatible(writerProduces)) {
continue;
}
final CombinedMediaType.EffectiveMediaType effectiveProduces = new CombinedMediaType.EffectiveMediaType(MediaTypes.mostSpecific(methodProducesType, writerProduces), false);
final CombinedMediaType candidate = CombinedMediaType.create(acceptableMediaType, effectiveProduces);
if (candidate != CombinedMediaType.NO_MATCH) {
// Look for a better compatible worker.
if (selected == null || CombinedMediaType.COMPARATOR.compare(candidate, selected) < 0) {
if (model.isWriteable(responseEntityClass, entityType, handlingMethod.getDeclaredAnnotations(), candidate.combinedType)) {
selected = candidate;
}
}
}
}
}
}
}
// Found media type for current writer.
if (selected != null) {
return selected.combinedType;
}
// so it can be written.
return selectedMethod.produces.combinedType;
}
use of org.glassfish.jersey.message.internal.AcceptableMediaType in project jersey by jersey.
the class AcceptMediaTypeProviderTest method testOneMediaTypeWithParameters.
@Test
public void testOneMediaTypeWithParameters() throws Exception {
String header = "application/xml;charset=utf8";
List<AcceptableMediaType> l = HttpHeaderReader.readAcceptMediaType(header);
assertEquals(1, l.size());
MediaType m = l.get(0);
assertEquals("application", m.getType());
assertEquals("xml", m.getSubtype());
assertEquals(1, m.getParameters().size());
assertTrue(m.getParameters().containsKey("charset"));
assertEquals("utf8", m.getParameters().get("charset"));
}
use of org.glassfish.jersey.message.internal.AcceptableMediaType in project jersey by jersey.
the class AcceptMediaTypeProviderTest method testMediaTypeSpecifityHTTPExample1.
@Test
public void testMediaTypeSpecifityHTTPExample1() throws Exception {
String header = "text/*, text/html, text/html;level=1, */*";
List<AcceptableMediaType> l = HttpHeaderReader.readAcceptMediaType(header);
MediaType m;
m = l.get(0);
assertEquals("text", m.getType());
assertEquals("html", m.getSubtype());
assertEquals(0, m.getParameters().size());
m = l.get(1);
assertEquals("text", m.getType());
assertEquals("html", m.getSubtype());
assertEquals(1, m.getParameters().size());
m = l.get(2);
assertEquals("text", m.getType());
assertEquals("*", m.getSubtype());
assertEquals(0, m.getParameters().size());
m = l.get(3);
assertEquals("*", m.getType());
assertEquals("*", m.getSubtype());
assertEquals(0, m.getParameters().size());
}
Aggregations