/******************************************************************************* * Copyright 2013 SAP AG * * Licensed 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 com.sap.core.odata.processor.core.jpa.model; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import com.sap.core.odata.api.annotation.edm.FunctionImport.Multiplicity; import com.sap.core.odata.api.annotation.edm.FunctionImport.ReturnType; import com.sap.core.odata.api.annotation.edm.Parameter; import com.sap.core.odata.api.edm.EdmMultiplicity; import com.sap.core.odata.api.edm.EdmSimpleTypeKind; import com.sap.core.odata.api.edm.provider.ComplexType; import com.sap.core.odata.api.edm.provider.EntityType; import com.sap.core.odata.api.edm.provider.Facets; import com.sap.core.odata.api.edm.provider.FunctionImport; import com.sap.core.odata.api.edm.provider.FunctionImportParameter; import com.sap.core.odata.api.edm.provider.Mapping; import com.sap.core.odata.processor.api.jpa.access.JPAEdmBuilder; import com.sap.core.odata.processor.api.jpa.exception.ODataJPAModelException; import com.sap.core.odata.processor.api.jpa.exception.ODataJPARuntimeException; import com.sap.core.odata.processor.api.jpa.model.JPAEdmComplexTypeView; import com.sap.core.odata.processor.api.jpa.model.JPAEdmEntityTypeView; import com.sap.core.odata.processor.api.jpa.model.JPAEdmFunctionImportView; import com.sap.core.odata.processor.api.jpa.model.JPAEdmMapping; import com.sap.core.odata.processor.api.jpa.model.JPAEdmSchemaView; import com.sap.core.odata.processor.core.jpa.access.model.JPAEdmNameBuilder; import com.sap.core.odata.processor.core.jpa.access.model.JPATypeConvertor; public class JPAEdmFunctionImport extends JPAEdmBaseViewImpl implements JPAEdmFunctionImportView { private List<FunctionImport> consistentFunctionImportList = new ArrayList<FunctionImport>(); private JPAEdmBuilder builder = null; private JPAEdmSchemaView schemaView; public JPAEdmFunctionImport(final JPAEdmSchemaView view) { super(view); schemaView = view; } @Override public JPAEdmBuilder getBuilder() { if (builder == null) { builder = new JPAEdmFunctionImportBuilder(); } return builder; } @Override public List<FunctionImport> getConsistentFunctionImportList() { return consistentFunctionImportList; } protected class JPAEdmFunctionImportBuilder implements JPAEdmBuilder { private JPAEdmEntityTypeView jpaEdmEntityTypeView = null; private JPAEdmComplexTypeView jpaEdmComplexTypeView = null; @Override public void build() throws ODataJPAModelException, ODataJPARuntimeException { HashMap<Class<?>, String[]> customOperations = schemaView .getRegisteredOperations(); jpaEdmEntityTypeView = schemaView.getJPAEdmEntityContainerView() .getJPAEdmEntitySetView().getJPAEdmEntityTypeView(); jpaEdmComplexTypeView = schemaView.getJPAEdmComplexTypeView(); if (customOperations != null) { for (Class<?> clazz : customOperations.keySet()) { String[] operationNames = customOperations.get(clazz); Method[] methods = clazz.getMethods(); Method method = null; int length = 0; if (operationNames != null) { length = operationNames.length; } else { length = methods.length; } boolean found = false; for (int i = 0; i < length; i++) { try { if (operationNames != null) { for (Method method2 : methods) { if (method2.getName().equals( operationNames[i])) { found = true; method = method2; break; } } if (found == true) { found = false; } else { continue; } } else { method = methods[i]; } FunctionImport functionImport = buildFunctionImport(method); if (functionImport != null) { consistentFunctionImportList .add(functionImport); } } catch (SecurityException e) { throw ODataJPAModelException.throwException( ODataJPAModelException.GENERAL, e); } } } } } private FunctionImport buildFunctionImport(final Method method) throws ODataJPAModelException { com.sap.core.odata.api.annotation.edm.FunctionImport annotation = method .getAnnotation(com.sap.core.odata.api.annotation.edm.FunctionImport.class); if (annotation != null && annotation.returnType() != ReturnType.NONE) { FunctionImport functionImport = new FunctionImport(); if (annotation.name().equals("")) { functionImport.setName(method.getName()); } else { functionImport.setName(annotation.name()); } JPAEdmMapping mapping = new JPAEdmMappingImpl(); ((Mapping) mapping).setInternalName(method.getName()); mapping.setJPAType(method.getDeclaringClass()); functionImport.setMapping((Mapping) mapping); functionImport.setHttpMethod(annotation.httpMethod().name().toString()); buildReturnType(functionImport, method, annotation); buildParameter(functionImport, method); return functionImport; } return null; } private void buildParameter(final FunctionImport functionImport, final Method method) throws ODataJPAModelException { Annotation[][] annotations = method.getParameterAnnotations(); Class<?>[] parameterTypes = method.getParameterTypes(); List<FunctionImportParameter> funcImpList = new ArrayList<FunctionImportParameter>(); JPAEdmMapping mapping = null; int j = 0; for (Annotation[] annotationArr : annotations) { Class<?> parameterType = parameterTypes[j++]; for (Annotation element : annotationArr) { if (element instanceof Parameter) { Parameter annotation = (Parameter) element; FunctionImportParameter functionImportParameter = new FunctionImportParameter(); if (annotation.name().equals("")) { throw ODataJPAModelException.throwException( ODataJPAModelException.FUNC_PARAM_NAME_EXP .addContent(method .getDeclaringClass() .getName(), method .getName()), null); } else { functionImportParameter.setName(annotation.name()); } functionImportParameter.setType(JPATypeConvertor .convertToEdmSimpleType(parameterType, null)); functionImportParameter.setMode(annotation.mode() .toString()); Facets facets = new Facets(); if (annotation.facets().maxLength() > 0) { facets.setMaxLength(annotation.facets().maxLength()); } if (annotation.facets().nullable() == false) { facets.setNullable(false); } else { facets.setNullable(true); } if (annotation.facets().precision() > 0) { facets.setPrecision(annotation.facets().precision()); } if (annotation.facets().scale() >= 0) { facets.setScale(annotation.facets().scale()); } functionImportParameter.setFacets(facets); mapping = new JPAEdmMappingImpl(); mapping.setJPAType(parameterType); functionImportParameter.setMapping((Mapping) mapping); funcImpList.add(functionImportParameter); } } } if (!funcImpList.isEmpty()) { functionImport.setParameters(funcImpList); } } private void buildReturnType(final FunctionImport functionImport, final Method method, final com.sap.core.odata.api.annotation.edm.FunctionImport annotation) throws ODataJPAModelException { ReturnType returnType = annotation.returnType(); Multiplicity multiplicity = null; if (returnType != ReturnType.NONE) { com.sap.core.odata.api.edm.provider.ReturnType functionReturnType = new com.sap.core.odata.api.edm.provider.ReturnType(); multiplicity = annotation.multiplicity(); if (multiplicity == Multiplicity.MANY) { functionReturnType.setMultiplicity(EdmMultiplicity.MANY); } else { functionReturnType.setMultiplicity(EdmMultiplicity.ONE); } if (returnType == ReturnType.ENTITY_TYPE) { String entitySet = annotation.entitySet(); if (entitySet.equals("")) { throw ODataJPAModelException .throwException( ODataJPAModelException.FUNC_ENTITYSET_EXP, null); } functionImport.setEntitySet(entitySet); } Class<?> methodReturnType = method.getReturnType(); if (methodReturnType == null || methodReturnType.getName().equals("void")) { throw ODataJPAModelException.throwException( ODataJPAModelException.FUNC_RETURN_TYPE_EXP .addContent(method.getDeclaringClass(), method.getName()), null); } switch (returnType) { case ENTITY_TYPE: EntityType edmEntityType = null; if (multiplicity == Multiplicity.ONE) { edmEntityType = jpaEdmEntityTypeView .searchEdmEntityType(methodReturnType .getSimpleName()); } else if (multiplicity == Multiplicity.MANY) { edmEntityType = jpaEdmEntityTypeView .searchEdmEntityType(getReturnTypeSimpleName(method)); } if (edmEntityType == null) { throw ODataJPAModelException .throwException( ODataJPAModelException.FUNC_RETURN_TYPE_ENTITY_NOT_FOUND .addContent( method.getDeclaringClass(), method.getName(), methodReturnType .getSimpleName()), null); } functionReturnType.setTypeName(JPAEdmNameBuilder.build( schemaView, edmEntityType.getName())); break; case SCALAR: EdmSimpleTypeKind edmSimpleTypeKind = JPATypeConvertor .convertToEdmSimpleType(methodReturnType, null); functionReturnType.setTypeName(edmSimpleTypeKind .getFullQualifiedName()); break; case COMPLEX_TYPE: ComplexType complexType = null; if (multiplicity == Multiplicity.ONE) { complexType = jpaEdmComplexTypeView .searchEdmComplexType(methodReturnType .getName()); } else if (multiplicity == Multiplicity.MANY) { complexType = jpaEdmComplexTypeView .searchEdmComplexType(getReturnTypeName(method)); } if (complexType == null) { throw ODataJPAModelException .throwException( ODataJPAModelException.FUNC_RETURN_TYPE_ENTITY_NOT_FOUND .addContent( method.getDeclaringClass(), method.getName(), methodReturnType .getSimpleName()), null); } functionReturnType.setTypeName(JPAEdmNameBuilder.build( schemaView, complexType.getName())); break; default: break; } functionImport.setReturnType(functionReturnType); } } private String getReturnTypeName(final Method method) { try { ParameterizedType pt = (ParameterizedType) method .getGenericReturnType(); Type t = pt.getActualTypeArguments()[0]; return ((Class<?>) t).getName(); } catch (ClassCastException e) { return method.getReturnType().getName(); } } private String getReturnTypeSimpleName(final Method method) { try { ParameterizedType pt = (ParameterizedType) method .getGenericReturnType(); Type t = pt.getActualTypeArguments()[0]; return ((Class<?>) t).getSimpleName(); } catch (ClassCastException e) { return method.getReturnType().getSimpleName(); } } } }