/*******************************************************************************
* 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.reflect.AnnotatedElement;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.metamodel.Attribute;
import com.sap.core.odata.api.edm.provider.Association;
import com.sap.core.odata.api.edm.provider.AssociationEnd;
import com.sap.core.odata.api.edm.provider.EntityType;
import com.sap.core.odata.api.edm.provider.Property;
import com.sap.core.odata.api.edm.provider.PropertyRef;
import com.sap.core.odata.api.edm.provider.ReferentialConstraintRole;
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.model.JPAEdmAssociationView;
import com.sap.core.odata.processor.api.jpa.model.JPAEdmEntityTypeView;
import com.sap.core.odata.processor.api.jpa.model.JPAEdmMapping;
import com.sap.core.odata.processor.api.jpa.model.JPAEdmPropertyView;
import com.sap.core.odata.processor.api.jpa.model.JPAEdmReferentialConstraintRoleView;
public class JPAEdmReferentialConstraintRole extends JPAEdmBaseViewImpl
implements JPAEdmReferentialConstraintRoleView {
/*
* Static Buffer
*/
private static Attribute<?, ?> bufferedJPAAttribute = null;
private static ArrayList<JoinColumn> bufferedJoinColumns = new ArrayList<JoinColumn>();
/*
* Static Buffer
*/
private boolean firstBuild = true;
private JPAEdmEntityTypeView entityTypeView;
private JPAEdmReferentialConstraintRoleView.RoleType roleType;
private Attribute<?, ?> jpaAttribute;
private ArrayList<String> jpaColumnNames;
private Association association;
private boolean roleExists = false;
private JPAEdmRefConstraintRoleBuilder builder;
private ReferentialConstraintRole currentRole;
public JPAEdmReferentialConstraintRole(
final JPAEdmReferentialConstraintRoleView.RoleType roleType,
final JPAEdmEntityTypeView entityTypeView,
final JPAEdmPropertyView propertyView,
final JPAEdmAssociationView associationView) {
super(entityTypeView);
this.entityTypeView = entityTypeView;
this.roleType = roleType;
jpaAttribute = propertyView.getJPAAttribute();
association = associationView.getEdmAssociation();
}
@Override
public boolean isExists() {
return roleExists;
}
@Override
public JPAEdmBuilder getBuilder() {
if (builder == null) {
builder = new JPAEdmRefConstraintRoleBuilder();
}
return builder;
}
@Override
public RoleType getRoleType() {
return roleType;
}
@Override
public ReferentialConstraintRole getEdmReferentialConstraintRole() {
return currentRole;
}
@Override
public String getJPAColumnName() {
return null;
}
@Override
public String getEdmEntityTypeName() {
return null;
}
@Override
public String getEdmAssociationName() {
return null;
}
private class JPAEdmRefConstraintRoleBuilder implements JPAEdmBuilder {
@Override
public void build() throws ODataJPAModelException {
if (firstBuild) {
firstBuild();
} else if (roleExists) {
try {
buildRole();
} catch (SecurityException e) {
throw ODataJPAModelException.throwException(
ODataJPAModelException.GENERAL.addContent(e
.getMessage()), e);
} catch (NoSuchFieldException e) {
throw ODataJPAModelException.throwException(
ODataJPAModelException.GENERAL.addContent(e
.getMessage()), e);
}
}
}
private void firstBuild() {
firstBuild = false;
isConsistent = false;
extractJoinColumns();
if (!roleExists) {
return;
}
jpaColumnNames = new ArrayList<String>();
for (JoinColumn joinColumn : bufferedJoinColumns) {
if (roleType == RoleType.PRINCIPAL) {
jpaColumnNames.add(joinColumn.referencedColumnName());
} else if (roleType == RoleType.DEPENDENT) {
jpaColumnNames.add(joinColumn.name());
}
}
}
private void buildRole() throws SecurityException, NoSuchFieldException {
if (currentRole == null) {
currentRole = new ReferentialConstraintRole();
String jpaAttributeType = null;
EntityType edmEntityType = null;
if (roleType == RoleType.PRINCIPAL) {
jpaAttributeType = jpaAttribute.getJavaType()
.getSimpleName();
if (jpaAttributeType.equals("List")) {
Type type = ((ParameterizedType) jpaAttribute
.getJavaMember().getDeclaringClass()
.getDeclaredField(jpaAttribute.getName())
.getGenericType()).getActualTypeArguments()[0];
int lastIndexOfDot = type.toString().lastIndexOf(".");
jpaAttributeType = type.toString().substring(
lastIndexOfDot + 1);
}
edmEntityType = entityTypeView
.searchEdmEntityType(jpaAttributeType);
}
else if (roleType == RoleType.DEPENDENT) {
edmEntityType = entityTypeView
.searchEdmEntityType(jpaAttribute
.getDeclaringType().getJavaType()
.getSimpleName());
}
List<PropertyRef> propertyRefs = new ArrayList<PropertyRef>();
if (edmEntityType != null) {
for (String columnName : jpaColumnNames) {
for (Property property : edmEntityType.getProperties()) {
if (columnName.equals(((JPAEdmMapping) property
.getMapping()).getJPAColumnName())) {
PropertyRef propertyRef = new PropertyRef();
propertyRef.setName(property.getName());
propertyRefs.add(propertyRef);
break;
}
}
}
currentRole.setPropertyRefs(propertyRefs);
if (propertyRefs.isEmpty()) {
isConsistent = false;
return;
}
AssociationEnd end = association.getEnd1();
if (end.getType().getName().equals(edmEntityType.getName())) {
currentRole.setRole(end.getRole());
isConsistent = true;
} else {
end = association.getEnd2();
if (end.getType().getName()
.equals(edmEntityType.getName())) {
currentRole.setRole(end.getRole());
isConsistent = true;
}
}
}
}
}
private void extractJoinColumns() {
/*
* Check against Static Buffer whether the join column was already
* extracted.
*/
if (!jpaAttribute.equals(bufferedJPAAttribute)) {
bufferedJPAAttribute = jpaAttribute;
bufferedJoinColumns.clear();
} else if (bufferedJoinColumns.isEmpty()) {
roleExists = false;
return;
} else {
roleExists = true;
return;
}
AnnotatedElement annotatedElement = (AnnotatedElement) jpaAttribute
.getJavaMember();
if (annotatedElement == null) {
return;
}
JoinColumn joinColumn = annotatedElement
.getAnnotation(JoinColumn.class);
if (joinColumn == null) {
JoinColumns joinColumns = annotatedElement
.getAnnotation(JoinColumns.class);
if (joinColumns != null) {
JoinColumn[] joinColumnArray = joinColumns.value();
for (JoinColumn element : joinColumnArray) {
bufferedJoinColumns.add(element);
}
} else {
return;
}
} else {
bufferedJoinColumns.add(joinColumn);
}
roleExists = true;
}
}
}