/******************************************************************************* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. ******************************************************************************/ package org.apache.olingo.odata2.jpa.processor.api; import org.apache.olingo.odata2.api.ODataCallback; import org.apache.olingo.odata2.api.ODataService; import org.apache.olingo.odata2.api.ODataServiceFactory; import org.apache.olingo.odata2.api.edm.provider.EdmProvider; import org.apache.olingo.odata2.api.exception.ODataException; import org.apache.olingo.odata2.api.processor.ODataContext; import org.apache.olingo.odata2.api.processor.ODataErrorCallback; import org.apache.olingo.odata2.api.processor.ODataSingleProcessor; import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPAErrorCallback; import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException; import org.apache.olingo.odata2.jpa.processor.api.factory.ODataJPAAccessFactory; import org.apache.olingo.odata2.jpa.processor.api.factory.ODataJPAFactory; /** * <p> * Extend this factory class and create own instance of {@link org.apache.olingo.odata2.api.ODataService} that * transforms Java Persistence * Models into an OData Service. The factory class instantiates instances of * type {@link org.apache.olingo.odata2.api.edm.provider.EdmProvider} and * {@link org.apache.olingo.odata2.api.processor.ODataSingleProcessor}. The OData * JPA Processor library provides a default implementation for EdmProvider and * OData Single Processor. * </p> * <p> * The factory implementation is passed as servlet init parameter to a JAX-RS * runtime which will instantiate a {@link org.apache.olingo.odata2.api.ODataService} implementation using this factory. * </p> * * <p> * <b>Mandatory:</b> Implement the abstract method initializeODataJPAContext. Fill * {@link org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext} with context * values. * </p> * * <b>Sample Configuration:</b> * * <pre> {@code * <servlet> * <servlet-name>ReferenceScenarioServlet</servlet-name> * <servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class> * <init-param> * <param-name>javax.ws.rs.Application</param-name> * <param-value>org.apache.olingo.odata2.core.rest.ODataApplication</param-value> * </init-param> * <init-param> * <param-name>org.apache.olingo.odata2.service.factory</param-name> * <param-value>foo.bar.sample.service.SampleProcessorFactory</param-value> * </init-param> * <init-param> * <param-name>org.apache.olingo.odata2.path.split</param-name> * <param-value>2</param-value> * </init-param> * <load-on-startup>1</load-on-startup> * </servlet> * } </pre> */ public abstract class ODataJPAServiceFactory extends ODataServiceFactory { private ODataJPAContext oDataJPAContext; private ODataContext oDataContext; private boolean setDetailErrors = false; private OnJPAWriteContent onJPAWriteContent = null; private ODataJPATransaction oDataJPATransaction = null; /** * Implement this method and initialize OData JPA Context. It is mandatory * to set an instance of type {@link javax.persistence.EntityManagerFactory} into the context. An exception of type * {@link org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException} is thrown if * EntityManagerFactory is not initialized. <br> * <br> * <b>Sample Code:</b> <code> * <p>public class JPAReferenceServiceFactory extends ODataJPAServiceFactory{</p> * * <blockquote>private static final String PUNIT_NAME = "punit"; * <br> * public ODataJPAContext initializeODataJPAContext() { * <blockquote>ODataJPAContext oDataJPAContext = this.getODataJPAContext(); * <br> * EntityManagerFactory emf = Persistence.createEntityManagerFactory(PUNIT_NAME); * <br> * oDataJPAContext.setEntityManagerFactory(emf); * oDataJPAContext.setPersistenceUnitName(PUNIT_NAME); * <br> return oDataJPAContext;</blockquote> * }</blockquote> * } </code> * <p> * * @return an instance of type {@link org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext} * @throws ODataJPARuntimeException */ public abstract ODataJPAContext initializeODataJPAContext() throws ODataJPARuntimeException; /** * Creates an OData Service based on the values set in * {@link org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext} and * {@link org.apache.olingo.odata2.api.processor.ODataContext}. */ @Override public final ODataService createService(final ODataContext ctx) throws ODataException { oDataContext = ctx; // Initialize OData JPA Context oDataJPAContext = initializeODataJPAContext(); validatePreConditions(); ODataJPAFactory factory = ODataJPAFactory.createFactory(); ODataJPAAccessFactory accessFactory = factory.getODataJPAAccessFactory(); // OData JPA Processor if (oDataJPAContext.getODataContext() == null) { oDataJPAContext.setODataContext(ctx); } ODataSingleProcessor odataJPAProcessor = createCustomODataProcessor(oDataJPAContext); if(odataJPAProcessor == null) { odataJPAProcessor = accessFactory.createODataProcessor(oDataJPAContext); } // OData Entity Data Model Provider based on JPA EdmProvider edmProvider = accessFactory.createJPAEdmProvider(oDataJPAContext); return createODataSingleProcessorService(edmProvider, odataJPAProcessor); } public ODataSingleProcessor createCustomODataProcessor(ODataJPAContext oDataJPAContext) { return null; } /** * @return an instance of type {@link ODataJPAContext} * @throws ODataJPARuntimeException */ public final ODataJPAContext getODataJPAContext() throws ODataJPARuntimeException { if (oDataJPAContext == null) { oDataJPAContext = ODataJPAFactory.createFactory().getODataJPAAccessFactory().createODataJPAContext(); } if (oDataContext != null) { oDataJPAContext.setODataContext(oDataContext); } return oDataJPAContext; } @SuppressWarnings("unchecked") @Override public <T extends ODataCallback> T getCallback(final Class<T> callbackInterface) { if (setDetailErrors == true) { if (callbackInterface.isAssignableFrom(ODataErrorCallback.class)) { return (T) new ODataJPAErrorCallback(); } } if (onJPAWriteContent != null) { if (callbackInterface.isAssignableFrom(OnJPAWriteContent.class)) { return (T) onJPAWriteContent; } } if (oDataJPATransaction != null) { if (callbackInterface.isAssignableFrom(ODataJPATransaction.class)) { return (T) oDataJPATransaction; } } return null; } /** * The methods sets the context with a callback implementation for JPA provider specific content. * For details refer to {@link org.apache.olingo.odata2.jpa.processor.api.OnJPAWriteContent} * @param onJPAWriteContent is an instance of type * {@link org.apache.olingo.odata2.jpa.processor.api.OnJPAWriteContent} */ protected void setOnWriteJPAContent(final OnJPAWriteContent onJPAWriteContent) { this.onJPAWriteContent = onJPAWriteContent; } /** * The methods sets the context with a callback implementation for JPA transaction specific content. * For details refer to {@link ODataJPATransaction} * @param oDataJPATransaction is an instance of type * {@link org.apache.olingo.odata2.jpa.processor.api.ODataJPATransaction} */ protected void setODataJPATransaction(final ODataJPATransaction oDataJPATransaction) { this.oDataJPATransaction = oDataJPATransaction; } /** * The method sets the context whether a detail error message should be thrown * or a less detail error message should be thrown by the library. * @param setDetailErrors takes * <ul><li>true - to indicate that library should throw a detailed error message</li> * <li>false - to indicate that library should not throw a detailed error message</li> * </ul> * */ protected void setDetailErrors(final boolean setDetailErrors) { this.setDetailErrors = setDetailErrors; } private void validatePreConditions() throws ODataJPARuntimeException { if (oDataJPAContext.getEntityManager() == null) { throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.ENTITY_MANAGER_NOT_INITIALIZED, null); } } }