package org.odata4j.producer.resources; import java.util.Properties; import java.util.logging.Logger; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; import org.odata4j.core.Throwables; import org.odata4j.producer.ODataProducer; import org.odata4j.producer.ODataProducerFactory; /** * Default OData producer provider. * * <p>OData producer instances can either be set statically (method {@code setInstance}) * or created by a factory ({@link ODataProducerFactory}) specified by the corresponding * system property (constant {@code FACTORY_PROPNAME}). * * <p>To introduce an additional container-specific setting, it is required to extend * this class and override method {@code createInstanceFromFactoryInContainerSpecificSetting}. * Furthermore a subclass of {@link AbstractODataApplication} has to be created to make * the new provider available to the JAX-RS runtime. */ @Provider public class DefaultODataProducerProvider implements ContextResolver<ODataProducer> { /** * Constant used as system property name. */ public static final String FACTORY_PROPNAME = "odata4j.producerfactory"; private static ODataProducer STATIC; /** * Sets the given OData producer as a static singleton. * * @param producer the OData producer */ public static void setInstance(ODataProducer producer) { STATIC = producer; } private final Logger log = Logger.getLogger(getClass().getName()); private ODataProducer instance; @Override public final ODataProducer getContext(Class<?> type) { if (!type.equals(ODataProducer.class)) throw new RuntimeException("Invalid context type"); if (instance != null) return instance; initializeInstance(); return instance; } private void initializeInstance() { instance = setInstanceToStaticSingleton(); if (instance == null) instance = createInstanceFromFactoryInContainerSpecificSetting(); if (instance == null) instance = createInstanceFromFactoryInSystemProperties(); if (instance == null) throw new RuntimeException("Unable to find an OData producer implementation. Call ODataProducerProvider.setInstance to set the static singleton or set the producer factory property \'" + FACTORY_PROPNAME + "\' in either the system properties or a container-specifc manner to a class name that implements ODataProducerFactory."); } private ODataProducer setInstanceToStaticSingleton() { if (STATIC != null) { log("Setting producer instance to static singleton: " + STATIC); return STATIC; } return null; } /** * Creates an OData producer instance using a factory specified in a container-specific * setting. * * <p>The default implementation returns {@code null}. Implementers can use the helper * methods {@code newProducerFromFactory} and {@code log}. * * @return the OData producer or {@code null} if no container-specific setting exists */ protected ODataProducer createInstanceFromFactoryInContainerSpecificSetting() { return null; } private ODataProducer createInstanceFromFactoryInSystemProperties() { if (System.getProperty(FACTORY_PROPNAME) != null) { String factoryTypeName = System.getProperty(FACTORY_PROPNAME); log("Creating producer from factory in system properties: " + factoryTypeName); return newProducerFromFactory(factoryTypeName, System.getProperties()); } return null; } /** * Helper method to create an OData producer instance from a given producer factory * ({@link ODataProducerFactory}). * * @param factoryTypeName the factory's type name (fully qualified) * @param props the properties to use when constructing the producer * @return the new producer */ protected final ODataProducer newProducerFromFactory(String factoryTypeName, Properties props) { try { Class<?> factoryType = Class.forName(factoryTypeName); Object obj = factoryType.newInstance(); ODataProducerFactory factory = (ODataProducerFactory) obj; return factory.create(props); } catch (Exception e) { throw Throwables.propagate(e); } } /** * Helper method to log an INFO message. * * @param msg the log message */ protected final void log(String msg) { log.info(msg); } }