package songbook.server; import java.util.*; /** * * Utility class to find the best match mime type. * see Header Accept chapter of rfc2616 * @author llgcode * */ public class MimeParser { static class MimeTypePattern { final String acceptedMimeType; final Map<String, String> parameters; protected MimeTypePattern(String acceptedMimeType, Map<String, String> parameters) { this.acceptedMimeType = acceptedMimeType; this.parameters = parameters; } } /** * Does the mimeType match with the mimeTypePattern * * * @param mimeType * @param acceptedMimeType * @return */ public static boolean match(String mimeType, String acceptedMimeType) { final String[] typeSubType1 = mimeType.split("/"); final String[] typeSubType2 = acceptedMimeType.split("/"); if (typeSubType1.length == 2 && typeSubType2.length == 2) { final String type1 = typeSubType1[0].trim(); final String subType1 = typeSubType1[1].trim(); final String type2 = typeSubType2[0].trim(); final String subType2 = typeSubType2[1].trim(); if ("*".equals(type2) || type1.equals(type2)) { return "*".equals(subType2) || subType1.equals(subType2); } } return false; } /** * Returns a list of mimetype patterns ordered by priority (see Header Accept chapter of rfc2616) * * @param acceptHeaderMimeType * @return */ public static String[] getMimeTypesByPriority(String acceptHeaderMimeType) { final String[] mimetypePatternsWithParams = acceptHeaderMimeType.split(","); final List<MimeTypePattern> mimeTypes = new ArrayList<MimeTypePattern>(); for (String m : mimetypePatternsWithParams) { final String[] mimetypePatternWithParams = m.split(";"); if (mimetypePatternWithParams.length > 0) { final String acceptedMimeType = mimetypePatternWithParams[0]; final Map<String, String> parameters = new HashMap<String, String>(); for (int i = 1; i < mimetypePatternWithParams.length; i++) { final String[] paramsPair = mimetypePatternWithParams[1].split("="); if (paramsPair.length == 1) { parameters.put(paramsPair[0].trim(), ""); } else if (paramsPair.length == 2) { parameters.put(paramsPair[0].trim(), paramsPair[1].trim()); } } if (!parameters.containsKey("q")) { parameters.put("q", "1"); } mimeTypes.add(new MimeTypePattern(acceptedMimeType.trim(), parameters)); } } Collections.sort(mimeTypes, new Comparator<MimeTypePattern>() { @Override public int compare(MimeTypePattern m1, MimeTypePattern m2) { float q1 = Float.parseFloat(m1.parameters.get("q")); float q2 = Float.parseFloat(m2.parameters.get("q")); if (q1 == q2) { if (m1.acceptedMimeType.equals(m2.acceptedMimeType)) { if (m1.parameters.size() == m2.parameters.size()) { return 0; } return m1.parameters.size() > m2.parameters.size() ? -1 : 1; } if (m1.acceptedMimeType.contains("*")) { return 1; } return 1; } return q1 < q2 ? 1 : -1; } }); String[] mimeTypesStr= new String[mimeTypes.size()]; for (int i = 0; i < mimeTypesStr.length; i++) { mimeTypesStr[i] = mimeTypes.get(i).acceptedMimeType; } return mimeTypesStr; } /** * Returns the best match mime type comparing supported mime types and accepted mime types (see HTTP Header Accept). * If no match is found return the first supported mime type of the array * @param acceptHeaderMimeType * @param supportedMimeTypes * @return */ public static String bestMatch(String acceptHeaderMimeType, String... supportedMimeTypes) { if (acceptHeaderMimeType == null || acceptHeaderMimeType.length() == 0) { return supportedMimeTypes[0]; } String[] mimeTypesByPriority = getMimeTypesByPriority(acceptHeaderMimeType); for (String acceptedMimeType : mimeTypesByPriority) { for (String supportedMimeType : supportedMimeTypes) { if (match(supportedMimeType, acceptedMimeType)) { return supportedMimeType; } } } return supportedMimeTypes[0]; } }