/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.service; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import org.restlet.Context; import org.restlet.data.MediaType; import org.restlet.data.Preference; import org.restlet.engine.Engine; import org.restlet.engine.converter.ConverterHelper; import org.restlet.engine.converter.ConverterUtils; import org.restlet.engine.resource.VariantInfo; import org.restlet.representation.Representation; import org.restlet.representation.Variant; import org.restlet.resource.Resource; /** * Application service converting between representation and regular Java * objects. The conversion can work in both directions. Actual converters can be * plugged into the engine to support this service.<br> * <br> * Root object classes used for conversion shouldn't be generic classes * otherwise important contextual type information will be missing at runtime * due to Java type erasure mechanism. If needed, create a fully resolved * subclasses and/or a container classes. * * @author Jerome Louvel */ public class ConverterService extends Service { /** * Constructor. */ public ConverterService() { super(); } /** * Constructor. * * @param enabled * True if the service has been enabled. */ public ConverterService(boolean enabled) { super(enabled); } /** * Applies a patch representation to an initial representation in order to * obtain a modified one. The patch must have a recognized media type in * order for the {@link ConverterService} to be able to process it. * * @param initial * The initial representation on which the patch must be applied. * @param patch * The patch representation to apply. * @return The modified representation. * @throws IOException */ public Representation applyPatch(Representation initial, Representation patch) throws IOException { return null; } /** * Creates a patch representation by calculating a diff between initial and * modified representations. * * @param initial * The initial representation. * @param modified * The modified representation. * @return The patch representation able to convert the initial * representation into the modified representation. * @throws IOException */ public Representation createPatch(Representation initial, Representation modified) throws IOException { return null; } /** * Returns the list of object classes that can be converted from a given * variant. * * @param source * The source variant. * @return The list of object class that can be converted. */ public List<Class<?>> getObjectClasses(Variant source) { List<Class<?>> result = null; List<Class<?>> helperObjectClasses = null; for (ConverterHelper ch : Engine.getInstance() .getRegisteredConverters()) { helperObjectClasses = ch.getObjectClasses(source); if (helperObjectClasses != null) { if (result == null) { result = new ArrayList<Class<?>>(); } result.addAll(helperObjectClasses); } } return result; } /** * Returns the list of patch media types available for the given * representation types. * * @param representationType * The representation media type or null for all supported patch * types. * @return The list of patch media types available. */ public List<MediaType> getPatchTypes(MediaType representationType) { return null; } /** * Returns the list of variants that can be converted from a given object * class. * * @param source * The source class. * @param target * The expected representation metadata. * @return The list of variants that can be converted. * @throws IOException */ public List<? extends Variant> getVariants(Class<?> source, Variant target) throws IOException { return ConverterUtils.getVariants(source, target); } /** * Reverts a patch representation from a modified representation in order to * obtain the initial one. The patch must have a recognized media type in * order for the {@link ConverterService} to be able to process it. * * @param modified * The modified representation from which the patch must be * reverted. * @param patch * The patch representation to revert. * @return The initial representation. * @throws IOException */ public Representation revertPatch(Representation modified, Representation patch) throws IOException { return null; } /** * Converts a Representation into a regular Java object. * * @param source * The source representation to convert. * @return The converted Java object. * @throws IOException */ public Object toObject(Representation source) throws IOException { return toObject(source, null, null); } /** * Converts a Representation into a regular Java object. * * @param <T> * The expected class of the Java object. * @param source * The source representation to convert. * @param target * The target class of the Java object. * @param resource * The parent resource. * @return The converted Java object. * @throws IOException */ public <T> T toObject(Representation source, Class<T> target, Resource resource) throws IOException { T result = null; boolean loggable = (resource == null) ? true : resource.isLoggable(); if ((source != null) && source.isAvailable() && (source.getSize() != 0)) { ConverterHelper ch = ConverterUtils.getBestHelper(source, target, resource); if (ch != null) { if (loggable && Context.getCurrentLogger().isLoggable(Level.FINE)) { Context.getCurrentLogger().fine( "The following converter was selected for the " + source + " representation: " + ch); } result = ch.toObject(source, target, resource); if (result instanceof Representation) { Representation resultRepresentation = (Representation) result; // Copy the variant metadata resultRepresentation.setCharacterSet(source .getCharacterSet()); resultRepresentation.setMediaType(source.getMediaType()); resultRepresentation.getEncodings().addAll( source.getEncodings()); resultRepresentation.getLanguages().addAll( source.getLanguages()); } } else { if (loggable) { Context.getCurrentLogger().warning( "Unable to find a converter for this representation : " + source); } } } return result; } /** * Converts a regular Java object into a Representation. The converter will * use the preferred variant of the selected converter. * * @param source * The source object to convert. * @return The converted representation. * @throws IOException */ public Representation toRepresentation(Object source) throws IOException { return toRepresentation(source, null, null); } /** * Converts a regular Java object into a Representation. * * @param source * The source object to convert. * @param target * The target representation media type. * @return The converted representation. * @throws IOException */ public Representation toRepresentation(Object source, MediaType target) throws IOException { return toRepresentation(source, new Variant(target)); } /** * Converts a regular Java object into a Representation. * * @param source * The source object to convert. * @param target * The target representation variant. * @return The converted representation. * @throws IOException */ public Representation toRepresentation(Object source, Variant target) throws IOException { return toRepresentation(source, target, null); } /** * Converts a regular Java object into a Representation. * * @param source * The source object to convert. * @param target * The target representation variant. * @param resource * The parent resource. * @return The converted representation. * @throws IOException */ public Representation toRepresentation(Object source, Variant target, Resource resource) throws IOException { Representation result = null; boolean loggable = (resource == null) ? true : resource.isLoggable(); ConverterHelper ch = ConverterUtils.getBestHelper(source, target, resource); if (ch != null) { if (loggable && Context.getCurrentLogger().isLoggable(Level.FINE)) { Context.getCurrentLogger().fine( "Converter selected for " + source.getClass().getSimpleName() + ": " + ch.getClass().getSimpleName()); } if (target == null) { List<VariantInfo> variants = ch.getVariants(source.getClass()); if ((variants != null) && !variants.isEmpty()) { if (resource != null) { target = resource.getConnegService() .getPreferredVariant(variants, resource.getRequest(), resource.getMetadataService()); } else { target = variants.get(0); } } else { target = new Variant(); } } result = ch.toRepresentation(source, target, resource); if (result != null) { // Copy the variant metadata if necessary if (result.getCharacterSet() == null) { result.setCharacterSet(target.getCharacterSet()); } if ((result.getMediaType() == null) || !result.getMediaType().isConcrete()) { if ((target.getMediaType() != null) && target.getMediaType().isConcrete()) { result.setMediaType(target.getMediaType()); } else if (resource != null) { result.setMediaType(resource.getMetadataService() .getDefaultMediaType()); } else { result.setMediaType(MediaType.APPLICATION_OCTET_STREAM); } } if (result.getEncodings().isEmpty()) { result.getEncodings().addAll(target.getEncodings()); } if (result.getLanguages().isEmpty()) { result.getLanguages().addAll(target.getLanguages()); } } } else { if (loggable) { Context.getCurrentLogger().warning( "Unable to find a converter for this object : " + source); } } return result; } /** * Updates the media type preferences with available conversion capabilities * for the given entity class. * * @param preferences * The media type preferences. * @param entity * The entity class to convert. */ public void updatePreferences(List<Preference<MediaType>> preferences, Class<?> entity) { for (ConverterHelper ch : Engine.getInstance() .getRegisteredConverters()) { ch.updatePreferences(preferences, entity); } } }