/** * This Source Code Form is subject to the terms of the Mozilla Public License, * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. * * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS * graphic logo is a trademark of OpenMRS Inc. */ package org.openmrs.module.webservices.rest.web.resource.impl; import org.openmrs.module.webservices.rest.web.ConversionUtil; import org.openmrs.module.webservices.rest.web.Hyperlink; import org.openmrs.module.webservices.rest.web.representation.Representation; import org.openmrs.module.webservices.rest.web.resource.api.RepresentationDescription; import org.openmrs.module.webservices.rest.web.response.ConversionException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Used by implementations of {@link DelegatingCrudResource} to indicate what delegate properties, * and what methods they want to include in a particular representation */ public class DelegatingResourceDescription implements RepresentationDescription { Map<String, Property> properties = new LinkedHashMap<String, Property>(); List<Hyperlink> links = new ArrayList<Hyperlink>(); public void addProperty(String propertyName) { addProperty(propertyName, propertyName, null, false); } public void addRequiredProperty(String propertyName) { addProperty(propertyName, propertyName, null, true); } public void addProperty(String propertyName, Representation rep) { addProperty(propertyName, propertyName, rep, false); } public void addRequiredProperty(String propertyName, Representation rep) { addProperty(propertyName, propertyName, rep, true); } public void addProperty(String propertyName, Representation rep, Class<?> convertAs) { addProperty(propertyName, propertyName, rep, false, convertAs); } public void addProperty(String propertyName, Method method) { addProperty(propertyName, method, null, false); } public void addProperty(String propertyName, String delegatePropertyName) { addProperty(propertyName, delegatePropertyName, null, false); } public void addRequiredProperty(String propertyName, String delegatePropertyName) { addProperty(propertyName, delegatePropertyName, null, true); } public void addProperty(String propertyName, String delegatePropertyName, Representation rep) { addProperty(propertyName, delegatePropertyName, rep, false); } public void addRequiredProperty(String propertyName, String delegatePropertyName, Representation rep) { addProperty(propertyName, delegatePropertyName, rep, true); } public void addProperty(String propertyName, Method method, Representation rep) { addProperty(propertyName, method, rep, false); } public void addProperty(String propertyName, String delegatePropertyName, Representation rep, boolean required) { addProperty(propertyName, delegatePropertyName, rep, required, null); } public void addProperty(String propertyName, String delegatePropertyName, Representation rep, boolean required, Class<?> convertAs) { if (rep == null) rep = Representation.DEFAULT; Property property = new Property(delegatePropertyName, rep, required); property.setConvertAs(convertAs); properties.put(propertyName, property); } public void addProperty(String propertyName, Method method, Representation rep, boolean required) { if (rep == null) rep = Representation.DEFAULT; properties.put(propertyName, new Property(method, rep, required)); } /** * Removes the given property * * @param propertyName */ public void removeProperty(String propertyName) { properties.remove(propertyName); } public DelegatingResourceDescription addSelfLink() { return addLink("self", "."); } public DelegatingResourceDescription addLink(String rel, String uri) { links.add(new Hyperlink(rel, uri)); return this; } /** * @return the properties */ public Map<String, Property> getProperties() { return properties; } /** * @return the links */ public List<Hyperlink> getLinks() { return links; } /** * A property that will be included in a representation */ public class Property { private String delegateProperty; private Method method; private Representation rep; private Class<?> convertAs; private boolean required; public Property(String delegateProperty, Representation rep) { this.delegateProperty = delegateProperty; this.rep = rep; this.required = false; } public Property(String delegateProperty, Representation rep, boolean required) { this.delegateProperty = delegateProperty; this.rep = rep; this.required = required; } public Property(Method method, Representation rep) { this.method = method; this.rep = rep; this.required = false; } public Property(Method method, Representation rep, boolean required) { this.method = method; this.rep = rep; this.required = required; } /** * @return the delegateProperty */ public String getDelegateProperty() { return delegateProperty; } /** * @param delegateProperty the delegateProperty to set */ public void setDelegateProperty(String delegateProperty) { this.delegateProperty = delegateProperty; } /** * @return the method */ public Method getMethod() { return method; } /** * @param method the method to set */ public void setMethod(Method method) { this.method = method; } /** * @return the rep */ public Representation getRep() { return rep; } /** * @param rep the rep to set */ public void setRep(Representation rep) { this.rep = rep; } /** * @return the required */ public boolean isRequired() { return required; } /** * @param required the required to set */ public void setRequired(boolean required) { this.required = required; } /** * @return the specific class to convert this property as (which */ public Class<?> getConvertAs() { return convertAs; } /** * In case you want to force a specific converter, e.g. in relationship resource, force * personA to be converted by the person resource even if personA is actually a Patient * * @param convertAs convert this property with the converter for this specific class, which * should be a superclass of any object you intend to convert */ public void setConvertAs(Class<?> convertAs) { this.convertAs = convertAs; } public <T> Object evaluate(BaseDelegatingConverter<T> converter, T delegate) throws ConversionException { if (delegateProperty != null) { Object propVal = converter.getProperty(delegate, delegateProperty); if (propVal instanceof Collection) { List<Object> ret = new ArrayList<Object>(); for (Object element : (Collection<?>) propVal) ret.add(ConversionUtil.convertToRepresentation(element, rep, getConvertAs())); return ret; } else { return ConversionUtil.convertToRepresentation(propVal, rep, getConvertAs()); } } else if (method != null) { try { return method.invoke(converter, delegate); } catch (Exception ex) { throw new ConversionException("method " + method, ex); } } else { throw new RuntimeException("Property with no delegateProperty or method specified"); } } } }