blob: 8c497d3cc6edb999f33a36545fd31ca195c09e46 [file] [log] [blame]
/*******************************************************************************
* 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.core.access.data;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.apache.olingo.odata2.api.commons.InlineCount;
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.edm.EdmEntityType;
import org.apache.olingo.odata2.api.edm.EdmException;
import org.apache.olingo.odata2.api.edm.EdmMapping;
import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
import org.apache.olingo.odata2.api.uri.UriInfo;
import org.apache.olingo.odata2.api.uri.info.DeleteUriInfo;
import org.apache.olingo.odata2.api.uri.info.GetEntityCountUriInfo;
import org.apache.olingo.odata2.api.uri.info.GetEntityLinkUriInfo;
import org.apache.olingo.odata2.api.uri.info.GetEntitySetCountUriInfo;
import org.apache.olingo.odata2.api.uri.info.GetEntitySetLinksUriInfo;
import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo;
import org.apache.olingo.odata2.api.uri.info.GetEntityUriInfo;
import org.apache.olingo.odata2.api.uri.info.GetFunctionImportUriInfo;
import org.apache.olingo.odata2.api.uri.info.PostUriInfo;
import org.apache.olingo.odata2.api.uri.info.PutMergePatchUriInfo;
import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
import org.apache.olingo.odata2.jpa.processor.api.ODataJPATombstoneContext;
import org.apache.olingo.odata2.jpa.processor.api.ODataJPATombstoneEntityListener;
import org.apache.olingo.odata2.jpa.processor.api.access.JPAFunction;
import org.apache.olingo.odata2.jpa.processor.api.access.JPAMethodContext;
import org.apache.olingo.odata2.jpa.processor.api.access.JPAProcessor;
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPAModelException;
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContextType;
import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement;
import org.apache.olingo.odata2.jpa.processor.api.model.JPAEdmMapping;
import org.apache.olingo.odata2.jpa.processor.core.ODataEntityParser;
import org.apache.olingo.odata2.jpa.processor.core.access.data.JPAPage.JPAPageBuilder;
public class JPAProcessorImpl implements JPAProcessor {
ODataJPAContext oDataJPAContext;
EntityManager em;
public JPAProcessorImpl(final ODataJPAContext oDataJPAContext) {
this.oDataJPAContext = oDataJPAContext;
em = oDataJPAContext.getEntityManager();
}
/* Process Function Import Request */
@SuppressWarnings("unchecked")
@Override
public List<Object> process(final GetFunctionImportUriInfo uriParserResultView)
throws ODataJPAModelException, ODataJPARuntimeException {
JPAMethodContext jpaMethodContext = JPAMethodContext.createBuilder(
JPQLContextType.FUNCTION, uriParserResultView).build();
List<Object> resultObj = null;
try {
JPAFunction jpaFunction = jpaMethodContext.getJPAFunctionList()
.get(0);
Method method = jpaFunction.getFunction();
Object[] args = jpaFunction.getArguments();
if (uriParserResultView.getFunctionImport().getReturnType()
.getMultiplicity().equals(EdmMultiplicity.MANY)) {
resultObj = (List<Object>) method.invoke(
jpaMethodContext.getEnclosingObject(), args);
} else {
resultObj = new ArrayList<Object>();
Object result = method.invoke(
jpaMethodContext.getEnclosingObject(), args);
resultObj.add(result);
}
} catch (EdmException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (IllegalAccessException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (IllegalArgumentException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (InvocationTargetException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getTargetException().getMessage()), e.getTargetException());
}
return resultObj;
}
/* Process Get Entity Set Request (Query) */
@Override
public List<Object> process(final GetEntitySetUriInfo uriParserResultView)
throws ODataJPAModelException, ODataJPARuntimeException {
if (uriParserResultView.getFunctionImport() != null) {
return (List<Object>) process((GetFunctionImportUriInfo) uriParserResultView);
}
InlineCount inlineCount = uriParserResultView.getInlineCount();
Integer top = uriParserResultView.getTop() == null ? 1 : uriParserResultView.getTop().intValue();
boolean hasNoAllPages = inlineCount == null ? true : !inlineCount.equals(InlineCount.ALLPAGES);
if (top.intValue() == 0 && hasNoAllPages) {
return new ArrayList<Object>();
}
JPQLContextType contextType = null;
try {
if (!uriParserResultView.getStartEntitySet().getName()
.equals(uriParserResultView.getTargetEntitySet().getName())) {
contextType = JPQLContextType.JOIN;
} else {
contextType = JPQLContextType.SELECT;
}
JPQLContext jpqlContext = null;
if (oDataJPAContext.getPageSize() > 0) {
jpqlContext = JPQLContext.createBuilder(contextType,
uriParserResultView, true).build();
} else {
jpqlContext = JPQLContext.createBuilder(contextType,
uriParserResultView).build();
}
JPQLStatement jpqlStatement = JPQLStatement.createBuilder(jpqlContext)
.build();
Map<String, String> customQueryOptions = uriParserResultView.getCustomQueryOptions();
String deltaToken = null;
if (customQueryOptions != null) {
deltaToken = uriParserResultView.getCustomQueryOptions().get("!deltatoken");
}
if (deltaToken != null) {
ODataJPATombstoneContext.setDeltaToken(deltaToken);
}
Query query = null;
List<Object> result = null;
JPAEdmMapping mapping = (JPAEdmMapping) uriParserResultView.getTargetEntitySet().getEntityType().getMapping();
ODataJPATombstoneEntityListener listener = null;
if (mapping.getODataJPATombstoneEntityListener() != null) {
listener = (ODataJPATombstoneEntityListener) mapping.getODataJPATombstoneEntityListener().newInstance();
query = listener.getQuery(uriParserResultView, em);
}
if (query == null) {
query = em.createQuery(jpqlStatement.toString());
if (listener != null) {
query.getResultList();
List<Object> deltaResult =
(List<Object>) ODataJPATombstoneContext.getDeltaResult(((EdmMapping) mapping).getInternalName());
result = handlePaging(deltaResult, uriParserResultView);
} else {
result = handlePaging(query, uriParserResultView);
}
} else {
result = handlePaging(query, uriParserResultView);
}
// Set New Token
if (listener != null) {
ODataJPATombstoneContext.setDeltaToken(listener.generateDeltaToken((List<Object>) result, query));
}
return result == null ? new ArrayList<Object>() : result;
} catch (Exception e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.ERROR_JPQL_QUERY_CREATE, e);
}
}
private List<Object> handlePaging(final List<Object> result, final GetEntitySetUriInfo uriParserResultView) {
if (result == null) {
return null;
}
JPAPageBuilder pageBuilder = new JPAPageBuilder();
pageBuilder.pageSize(oDataJPAContext.getPageSize())
.entities(result)
.skipToken(uriParserResultView.getSkipToken());
// $top/$skip with $inlinecount case handled in response builder to avoid multiple DB call
if (uriParserResultView.getSkip() != null && uriParserResultView.getInlineCount() == null) {
pageBuilder.skip(uriParserResultView.getSkip().intValue());
}
if (uriParserResultView.getTop() != null && uriParserResultView.getInlineCount() == null) {
pageBuilder.top(uriParserResultView.getTop().intValue());
}
JPAPage page = pageBuilder.build();
oDataJPAContext.setPaging(page);
return page.getPagedEntities();
}
private List<Object> handlePaging(final Query query, final GetEntitySetUriInfo uriParserResultView) {
JPAPageBuilder pageBuilder = new JPAPageBuilder();
pageBuilder.pageSize(oDataJPAContext.getPageSize())
.query(query)
.skipToken(uriParserResultView.getSkipToken());
// $top/$skip with $inlinecount case handled in response builder to avoid multiple DB call
if (uriParserResultView.getSkip() != null && uriParserResultView.getInlineCount() == null) {
pageBuilder.skip(uriParserResultView.getSkip().intValue());
}
if (uriParserResultView.getTop() != null && uriParserResultView.getInlineCount() == null) {
pageBuilder.top(uriParserResultView.getTop().intValue());
}
JPAPage page = pageBuilder.build();
oDataJPAContext.setPaging(page);
return page.getPagedEntities();
}
/* Process Get Entity Request (Read) */
@Override
public <T> Object process(GetEntityUriInfo uriParserResultView)
throws ODataJPAModelException, ODataJPARuntimeException {
JPQLContextType contextType = null;
try {
if (uriParserResultView instanceof GetEntityUriInfo) {
uriParserResultView = ((GetEntityUriInfo) uriParserResultView);
if (!((GetEntityUriInfo) uriParserResultView).getStartEntitySet().getName()
.equals(((GetEntityUriInfo) uriParserResultView).getTargetEntitySet().getName())) {
contextType = JPQLContextType.JOIN_SINGLE;
} else {
contextType = JPQLContextType.SELECT_SINGLE;
}
}
} catch (EdmException e) {
ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL, e);
}
return readEntity(uriParserResultView, contextType);
}
/* Process $count for Get Entity Set Request */
@Override
public long process(final GetEntitySetCountUriInfo resultsView)
throws ODataJPAModelException, ODataJPARuntimeException {
JPQLContextType contextType = null;
try {
if (!resultsView.getStartEntitySet().getName()
.equals(resultsView.getTargetEntitySet().getName())) {
contextType = JPQLContextType.JOIN_COUNT;
} else {
contextType = JPQLContextType.SELECT_COUNT;
}
} catch (EdmException e) {
ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL, e);
}
JPQLContext jpqlContext = JPQLContext.createBuilder(contextType,
resultsView).build();
JPQLStatement jpqlStatement = JPQLStatement.createBuilder(jpqlContext)
.build();
Query query = null;
try {
query = em.createQuery(jpqlStatement.toString());
List<?> resultList = query.getResultList();
if (resultList != null && resultList.size() == 1) {
return Long.valueOf(resultList.get(0).toString());
}
} catch (IllegalArgumentException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.ERROR_JPQL_QUERY_CREATE, e);
}
return 0;
}
/* Process $count for Get Entity Request */
@Override
public long process(final GetEntityCountUriInfo resultsView) throws ODataJPAModelException, ODataJPARuntimeException {
JPQLContextType contextType = null;
try {
if (!resultsView.getStartEntitySet().getName()
.equals(resultsView.getTargetEntitySet().getName())) {
contextType = JPQLContextType.JOIN_COUNT;
} else {
contextType = JPQLContextType.SELECT_COUNT;
}
} catch (EdmException e) {
ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL, e);
}
JPQLContext jpqlContext = JPQLContext.createBuilder(contextType,
resultsView).build();
JPQLStatement jpqlStatement = JPQLStatement.createBuilder(jpqlContext)
.build();
Query query = null;
try {
query = em.createQuery(jpqlStatement.toString());
List<?> resultList = query.getResultList();
if (resultList != null && resultList.size() == 1) {
return Long.valueOf(resultList.get(0).toString());
}
} catch (IllegalArgumentException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.ERROR_JPQL_QUERY_CREATE, e);
}
return 0;
}
/* Process Create Entity Request */
@Override
public Object process(final PostUriInfo createView, final InputStream content,
final String requestedContentType) throws ODataJPAModelException,
ODataJPARuntimeException {
return processCreate(createView, content, null, requestedContentType);
}
@Override
public Object process(final PostUriInfo createView, final Map<String, Object> content)
throws ODataJPAModelException, ODataJPARuntimeException {
return processCreate(createView, null, content, null);
}
/* Process Update Entity Request */
@Override
public Object process(final PutMergePatchUriInfo updateView,
final InputStream content, final String requestContentType)
throws ODataJPAModelException, ODataJPARuntimeException {
return processUpdate(updateView, content, null, requestContentType);
}
@Override
public Object process(final PutMergePatchUriInfo updateView, final Map<String, Object> content)
throws ODataJPAModelException, ODataJPARuntimeException {
return processUpdate(updateView, null, content, null);
}
private Object processCreate(final PostUriInfo createView, final InputStream content,
final Map<String, Object> properties,
final String requestedContentType) throws ODataJPAModelException,
ODataJPARuntimeException {
try {
final EdmEntitySet oDataEntitySet = createView.getTargetEntitySet();
final EdmEntityType oDataEntityType = oDataEntitySet.getEntityType();
final JPAEntity virtualJPAEntity = new JPAEntity(oDataEntityType, oDataEntitySet, oDataJPAContext);
Object jpaEntity = null;
if (content != null) {
final ODataEntityParser oDataEntityParser = new ODataEntityParser(oDataJPAContext);
final ODataEntry oDataEntry =
oDataEntityParser.parseEntry(oDataEntitySet, content, requestedContentType, false);
virtualJPAEntity.create(oDataEntry);
} else if (properties != null) {
virtualJPAEntity.create(properties);
} else {
return null;
}
em.getTransaction().begin();
jpaEntity = virtualJPAEntity.getJPAEntity();
em.persist(jpaEntity);
if (em.contains(jpaEntity)) {
em.getTransaction().commit();
return jpaEntity;
}
} catch (Exception e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.ERROR_JPQL_CREATE_REQUEST, e);
}
return null;
}
public <T> Object processUpdate(PutMergePatchUriInfo updateView,
final InputStream content, final Map<String, Object> properties, final String requestContentType)
throws ODataJPAModelException, ODataJPARuntimeException {
JPQLContextType contextType = null;
Object jpaEntity = null;
try {
em.getTransaction().begin();
if (updateView instanceof PutMergePatchUriInfo) {
updateView = ((PutMergePatchUriInfo) updateView);
if (!((PutMergePatchUriInfo) updateView).getStartEntitySet().getName()
.equals(((PutMergePatchUriInfo) updateView).getTargetEntitySet().getName())) {
contextType = JPQLContextType.JOIN_SINGLE;
} else {
contextType = JPQLContextType.SELECT_SINGLE;
}
}
jpaEntity = readEntity(updateView, contextType);
if (jpaEntity == null) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.RESOURCE_NOT_FOUND, null);
}
final EdmEntitySet oDataEntitySet = updateView.getTargetEntitySet();
final EdmEntityType oDataEntityType = oDataEntitySet.getEntityType();
final JPAEntity virtualJPAEntity = new JPAEntity(oDataEntityType, oDataEntitySet, oDataJPAContext);
virtualJPAEntity.setJPAEntity(jpaEntity);
if (content != null) {
final ODataEntityParser oDataEntityParser = new ODataEntityParser(oDataJPAContext);
final ODataEntry oDataEntry = oDataEntityParser.parseEntry(oDataEntitySet, content, requestContentType, false);
virtualJPAEntity.update(oDataEntry);
} else if (properties != null) {
virtualJPAEntity.update(properties);
} else {
return null;
}
em.flush();
em.getTransaction().commit();
} catch (Exception e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.ERROR_JPQL_UPDATE_REQUEST, e);
}
return jpaEntity;
}
/* Process Delete Entity Request */
@Override
public Object process(DeleteUriInfo uriParserResultView, final String contentType)
throws ODataJPAModelException, ODataJPARuntimeException {
JPQLContextType contextType = null;
try {
if (uriParserResultView instanceof DeleteUriInfo) {
if (((UriInfo) uriParserResultView).isLinks()) {
return deleteLink(uriParserResultView);
}
uriParserResultView = ((DeleteUriInfo) uriParserResultView);
if (!((DeleteUriInfo) uriParserResultView).getStartEntitySet().getName()
.equals(((DeleteUriInfo) uriParserResultView).getTargetEntitySet().getName())) {
contextType = JPQLContextType.JOIN_SINGLE;
} else {
contextType = JPQLContextType.SELECT_SINGLE;
}
}
} catch (EdmException e) {
ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL, e);
}
Object selectedObject = readEntity(uriParserResultView, contextType);
if (selectedObject != null) {
try {
em.getTransaction().begin();
em.remove(selectedObject);
em.flush();
em.getTransaction().commit();
} catch (Exception e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.ERROR_JPQL_DELETE_REQUEST, e);
}
}
return selectedObject;
}
private Object deleteLink(final DeleteUriInfo uriParserResultView) throws ODataJPARuntimeException {
JPALink link = new JPALink(oDataJPAContext);
link.delete(uriParserResultView);
link.save();
return link.getTargetJPAEntity();
}
/* Process Get Entity Link Request */
@Override
public Object process(final GetEntityLinkUriInfo uriParserResultView)
throws ODataJPAModelException, ODataJPARuntimeException {
return this.process((GetEntityUriInfo) uriParserResultView);
}
/* Process Get Entity Set Link Request */
@Override
public List<Object> process(final GetEntitySetLinksUriInfo uriParserResultView)
throws ODataJPAModelException, ODataJPARuntimeException {
return this.process((GetEntitySetUriInfo) uriParserResultView);
}
@Override
public void process(final PostUriInfo uriInfo,
final InputStream content, final String requestContentType, final String contentType)
throws ODataJPARuntimeException, ODataJPAModelException {
JPALink link = new JPALink(oDataJPAContext);
link.create(uriInfo, content, requestContentType, contentType);
link.save();
}
/* Common method for Read and Delete */
private Object readEntity(final Object uriParserResultView, final JPQLContextType contextType)
throws ODataJPAModelException, ODataJPARuntimeException {
Object selectedObject = null;
if (uriParserResultView instanceof DeleteUriInfo || uriParserResultView instanceof GetEntityUriInfo
|| uriParserResultView instanceof PutMergePatchUriInfo) {
JPQLContext selectJPQLContext = JPQLContext.createBuilder(
contextType, uriParserResultView).build();
JPQLStatement selectJPQLStatement = JPQLStatement.createBuilder(
selectJPQLContext).build();
Query query = null;
try {
query = em.createQuery(selectJPQLStatement.toString());
if (!query.getResultList().isEmpty()) {
selectedObject = query.getResultList().get(0);
}
} catch (IllegalArgumentException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.ERROR_JPQL_QUERY_CREATE, e);
}
}
return selectedObject;
}
@Override
public void process(final PutMergePatchUriInfo putUriInfo,
final InputStream content, final String requestContentType, final String contentType)
throws ODataJPARuntimeException, ODataJPAModelException {
JPALink link = new JPALink(oDataJPAContext);
link.update(putUriInfo, content, requestContentType, contentType);
link.save();
}
}