/** * The contents of this file are subject to the OpenMRS Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.api.impl; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.openmrs.api.APIException; import org.openmrs.api.AttributeService; import org.openmrs.api.context.Context; import org.openmrs.attribute.AttributeType; import org.openmrs.attribute.handler.AttributeHandler; import org.openmrs.attribute.handler.StringAttributeHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; /** * Core implementation of {@link AttributeService} * @since 1.9 */ public class AttributeServiceImpl extends BaseOpenmrsService implements AttributeService { @Autowired private List<AttributeHandler<?>> allRegisteredHandlers; private transient Map<String, Class<? extends AttributeHandler<?>>> prioritizedHandlerClasses; /** * @see org.openmrs.api.AttributeService#getDatatypes() */ @Override public Set<String> getDatatypes() { if (prioritizedHandlerClasses == null) { prioritizeHandlers(); } return Collections.unmodifiableSet(prioritizedHandlerClasses.keySet()); } /** * @see org.openmrs.api.AttributeService#getHandler(java.lang.String, java.lang.String) */ @Override public AttributeHandler<?> getHandler(String logicalType, String handlerConfig) { if (prioritizedHandlerClasses == null) { prioritizeHandlers(); } Class<? extends AttributeHandler<?>> handlerClass = prioritizedHandlerClasses.get(logicalType); if (handlerClass == null) return newDefaultHandler(); AttributeHandler<?> handler; try { handler = handlerClass.newInstance(); if (handlerConfig != null) handler.setConfiguration(handlerConfig); return handler; } catch (Exception ex) { throw new APIException("Error instantiating handler", ex); } } /** * @return a newly-instantiated default handler, for use when no suitable handler is found, but we need * to do _something_ */ private AttributeHandler<?> newDefaultHandler() { return new StringAttributeHandler(); } /** * @see org.openmrs.api.AttributeService#getHandler(org.openmrs.attribute.AttributeType) */ @Override public AttributeHandler<?> getHandler(AttributeType<?> attributeType) { return Context.getAttributeService().getHandler(attributeType.getDatatype(), attributeType.getHandlerConfig()); } /** * private method that prioritizes all registered handlers so we can quickly determin which to use for * each logical type */ @SuppressWarnings( { "rawtypes", "unchecked" }) private synchronized void prioritizeHandlers() { if (prioritizedHandlerClasses == null) { prioritizedHandlerClasses = new HashMap<String, Class<? extends AttributeHandler<?>>>(); for (AttributeHandler<?> handler : allRegisteredHandlers) { Class<? extends AttributeHandler> clazz = handler.getClass(); if (!prioritizedHandlerClasses.containsKey(handler.getDatatypeHandled())) { prioritizedHandlerClasses .put(handler.getDatatypeHandled(), (Class<? extends AttributeHandler<?>>) clazz); } else { int candidateOrder = getOrder((Class<? extends AttributeHandler<?>>) clazz); int existingOrder = getOrder(prioritizedHandlerClasses.get(handler.getDatatypeHandled())); if (candidateOrder < existingOrder) prioritizedHandlerClasses.put(handler.getDatatypeHandled(), (Class<? extends AttributeHandler<?>>) clazz); } } } } /** * @return the value of any {@link Order} annotation if defined, otherwise defaults to the lowest * precedence */ private int getOrder(Class<?> clazz) { int order = Ordered.LOWEST_PRECEDENCE; Order orderAnnotation = clazz.getAnnotation(Order.class); if (orderAnnotation != null) order = orderAnnotation.value(); return order; } }