blob: 33a3462785b39f2225e2808e63005e36e7afe332 [file] [log] [blame]
package org.jboss.resteasy.util;
import org.jboss.resteasy.spi.LoggableFailure;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.io.Serializable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MediaTypeHelper
{
public static MediaType getConsumes(Class declaring, AccessibleObject method)
{
Consumes consume = method.getAnnotation(Consumes.class);
if (consume == null)
{
consume = (Consumes) declaring.getAnnotation(Consumes.class);
if (consume == null) return null;
}
return MediaType.valueOf(consume.value()[0]);
}
public static MediaType getProduces(Class declaring, Method method)
{
Produces consume = method.getAnnotation(Produces.class);
if (consume == null)
{
consume = (Produces) declaring.getAnnotation(Produces.class);
}
if (consume == null) return null;
return MediaType.valueOf(consume.value()[0]);
}
public static float getQ(MediaType type)
{
float rtn = getQWithParamInfo(type);
if (rtn == 2.0F) return 1.0F;
return rtn;
}
public static float getQWithParamInfo(MediaType type)
{
if (type.getParameters() != null)
{
String val = type.getParameters().get("q");
try
{
if (val != null)
{
float rtn = Float.valueOf(val);
if (rtn > 1.0F)
throw new LoggableFailure("MediaType q value cannot be greater than 1.0: " + type.toString(), HttpResponseCodes.SC_BAD_REQUEST);
return rtn;
}
}
catch (NumberFormatException e)
{
throw new RuntimeException("MediaType q parameter must be a float: " + type, e);
}
}
return 2.0f;
}
/**
* subtypes like application/*+xml
*
* @param subtype
* @return
*/
public static boolean isCompositeWildcardSubtype(String subtype)
{
return subtype.startsWith("*+");
}
/**
* subtypes like application/*+xml
*
* @param subtype
* @return
*/
public static boolean isWildcardCompositeSubtype(String subtype)
{
return subtype.endsWith("+*");
}
public static boolean isComposite(String subtype)
{
return (isCompositeWildcardSubtype(subtype) || isWildcardCompositeSubtype(subtype));
}
private static class MediaTypeComparator implements Comparator<MediaType>, Serializable
{
private static final long serialVersionUID = -5828700121582498092L;
public int compare(MediaType mediaType2, MediaType mediaType)
{
float q = getQWithParamInfo(mediaType);
boolean wasQ = q != 2.0f;
if (q == 2.0f) q = 1.0f;
float q2 = getQWithParamInfo(mediaType2);
boolean wasQ2 = q2 != 2.0f;
if (q2 == 2.0f) q2 = 1.0f;
if (q < q2) return -1;
if (q > q2) return 1;
if (mediaType.isWildcardType() && !mediaType2.isWildcardType()) return -1;
if (!mediaType.isWildcardType() && mediaType2.isWildcardType()) return 1;
if (mediaType.isWildcardSubtype() && !mediaType2.isWildcardSubtype()) return -1;
if (!mediaType.isWildcardSubtype() && mediaType2.isWildcardSubtype()) return 1;
if (isComposite(mediaType.getSubtype()) && !isComposite(mediaType2.getSubtype()))
return -1;
if (!isComposite(mediaType.getSubtype()) && isComposite(mediaType2.getSubtype()))
return 1;
if (isCompositeWildcardSubtype(mediaType.getSubtype()) && !isCompositeWildcardSubtype(mediaType2.getSubtype()))
return -1;
if (!isCompositeWildcardSubtype(mediaType.getSubtype()) && isCompositeWildcardSubtype(mediaType2.getSubtype()))
return 1;
if (isWildcardCompositeSubtype(mediaType.getSubtype()) && !isWildcardCompositeSubtype(mediaType2.getSubtype()))
return -1;
if (!isWildcardCompositeSubtype(mediaType.getSubtype()) && isWildcardCompositeSubtype(mediaType2.getSubtype()))
return 1;
int numNonQ = 0;
if (mediaType.getParameters() != null)
{
numNonQ = mediaType.getParameters().size();
if (wasQ) numNonQ--;
}
int numNonQ2 = 0;
if (mediaType2.getParameters() != null)
{
numNonQ2 = mediaType2.getParameters().size();
if (wasQ2) numNonQ2--;
}
if (numNonQ < numNonQ2) return -1;
if (numNonQ > numNonQ2) return 1;
return 0;
}
}
public static int compareWeight(MediaType one, MediaType two)
{
return new MediaTypeComparator().compare(one, two);
}
public static boolean sameWeight(MediaType one, MediaType two)
{
return new MediaTypeComparator().compare(one, two) == 0;
}
public static void sortByWeight(List<MediaType> types)
{
if (types == null || types.size() <= 1) return;
Collections.sort(types, new MediaTypeComparator());
}
public static MediaType getBestMatch(List<MediaType> desired, List<MediaType> provided)
{
sortByWeight(desired);
sortByWeight(provided);
boolean emptyDesired = desired == null || desired.size() == 0;
boolean emptyProvided = provided == null || provided.size() == 0;
if (emptyDesired && emptyProvided) return null;
if (emptyDesired && !emptyProvided) return provided.get(0);
if (emptyProvided && !emptyDesired) return desired.get(0);
for (MediaType desire : desired)
{
for (MediaType provide : provided)
{
if (provide.isCompatible(desire)) return provide;
}
}
return null;
}
public static List<MediaType> parseHeader(String header)
{
ArrayList<MediaType> types = new ArrayList<MediaType>();
String[] medias = header.split(",");
for (int i = 0; i < medias.length; i++)
{
types.add(MediaType.valueOf(medias[i].trim()));
}
return types;
}
public static boolean equivalent(MediaType m1, MediaType m2)
{
if (m1 == m2) return true;
if (!m1.getType().equals(m2.getType())) return false;
if (!m1.getSubtype().equals(m2.getSubtype())) return false;
return equivalentParams(m1, m2);
}
public static boolean equivalentParams(MediaType m1, MediaType m2)
{
Map<String, String> params1 = m1.getParameters();
Map<String, String> params2 = m2.getParameters();
if (params1 == params2) return true;
if (params1 == null || params2 == null) return false;
if (params1.size() == 0 && params2.size() == 0) return true;
int numParams1 = params1.size();
if (params1.containsKey("q")) numParams1--;
int numParams2 = params2.size();
if (params2.containsKey("q")) numParams2--;
if (numParams1 != numParams2) return false;
if (numParams1 == 0) return true;
for (Map.Entry<String, String> entry : params1.entrySet())
{
String key = entry.getKey();
if (key.equals("q")) continue;
String value = entry.getValue();
String value2 = params2.get(key);
if (value == value2) continue; // both null
if (value == null || value2 == null) return false;
if (value.equals(value2) == false) return false;
}
return true;
}
}