/*******************************************************************************
* 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.model;
import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
import org.apache.olingo.odata2.api.edm.FullQualifiedName;
import org.apache.olingo.odata2.api.edm.provider.AssociationEnd;
import org.apache.olingo.odata2.jpa.processor.api.access.JPAEdmBuilder;
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPAModelException;
import org.apache.olingo.odata2.jpa.processor.api.model.JPAEdmAssociationEndView;
import org.apache.olingo.odata2.jpa.processor.api.model.JPAEdmEntityTypeView;
import org.apache.olingo.odata2.jpa.processor.api.model.JPAEdmPropertyView;
import org.apache.olingo.odata2.jpa.processor.core.access.model.JPAEdmNameBuilder;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.metamodel.Attribute.PersistentAttributeType;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.util.List;
public class JPAEdmAssociationEnd extends JPAEdmBaseViewImpl implements JPAEdmAssociationEndView {
private JPAEdmEntityTypeView entityTypeView = null;
private JPAEdmPropertyView propertyView = null;
private AssociationEnd currentAssociationEnd1 = null;
private AssociationEnd currentAssociationEnd2 = null;
private String[] columnNames;
private String[] referencedColumnNames;
private String mappedBy;
private String ownerPropertyName;
public JPAEdmAssociationEnd(final JPAEdmEntityTypeView entityTypeView, final JPAEdmPropertyView propertyView) {
super(entityTypeView);
this.entityTypeView = entityTypeView;
this.propertyView = propertyView;
}
@Override
public JPAEdmBuilder getBuilder() {
if (builder == null) {
builder = new JPAEdmAssociationEndBuilder();
}
return builder;
}
@Override
public AssociationEnd getEdmAssociationEnd1() {
return currentAssociationEnd1;
}
@Override
public AssociationEnd getEdmAssociationEnd2() {
return currentAssociationEnd2;
}
private class JPAEdmAssociationEndBuilder implements JPAEdmBuilder {
@Override
public void build() throws ODataJPAModelException {
currentAssociationEnd1 = new AssociationEnd();
currentAssociationEnd2 = new AssociationEnd();
JPAEdmNameBuilder.build(JPAEdmAssociationEnd.this, entityTypeView, propertyView);
currentAssociationEnd1.setRole(currentAssociationEnd1.getType().getName());
if (currentAssociationEnd1.getType().getName().equals(currentAssociationEnd2.getType().getName())) {
currentAssociationEnd2.setRole(currentAssociationEnd2.getType().getName() + "2");
} else {
currentAssociationEnd2.setRole(currentAssociationEnd2.getType().getName());
}
setEdmMultiplicity(propertyView.getJPAAttribute().getPersistentAttributeType());
List<String[]> joinColumnNames = propertyView.getJPAJoinColumns();
if (joinColumnNames != null) {
int i = 0;
columnNames = (String[]) Array.newInstance(String.class, joinColumnNames.size());
referencedColumnNames = (String[]) Array.newInstance(String.class, joinColumnNames.size());
for (String[] jc : joinColumnNames) {
columnNames[i] = jc[0];
referencedColumnNames[i++] = jc[1];
}
}
ownerPropertyName = propertyView.getJPAAttribute().getName();
}
private void setEdmMultiplicity(final PersistentAttributeType type) {
AnnotatedElement annotatedElement = (AnnotatedElement) propertyView.getJPAAttribute().getJavaMember();
switch (type) {
case ONE_TO_MANY:
currentAssociationEnd1.setMultiplicity(EdmMultiplicity.ONE);
currentAssociationEnd2.setMultiplicity(EdmMultiplicity.MANY);
if (annotatedElement != null) {
OneToMany reln = annotatedElement.getAnnotation(OneToMany.class);
if (reln != null) {
mappedBy = reln.mappedBy();
}
}
break;
case MANY_TO_MANY:
currentAssociationEnd1.setMultiplicity(EdmMultiplicity.MANY);
currentAssociationEnd2.setMultiplicity(EdmMultiplicity.MANY);
if (annotatedElement != null) {
ManyToMany reln = annotatedElement.getAnnotation(ManyToMany.class);
if (reln != null) {
mappedBy = reln.mappedBy();
}
}
break;
case MANY_TO_ONE:
currentAssociationEnd1.setMultiplicity(EdmMultiplicity.MANY);
currentAssociationEnd2.setMultiplicity(EdmMultiplicity.ONE);
if (annotatedElement != null) {
ManyToOne reln = annotatedElement.getAnnotation(ManyToOne.class);
if (reln != null && reln.optional()) {
currentAssociationEnd2.setMultiplicity(EdmMultiplicity.ZERO_TO_ONE);
}
}
break;
case ONE_TO_ONE:
currentAssociationEnd1.setMultiplicity(EdmMultiplicity.ONE);
currentAssociationEnd2.setMultiplicity(EdmMultiplicity.ONE);
if (annotatedElement != null) {
OneToOne reln = annotatedElement.getAnnotation(OneToOne.class);
if (reln != null) {
mappedBy = reln.mappedBy();
if(reln.optional()) {
currentAssociationEnd2.setMultiplicity(EdmMultiplicity.ZERO_TO_ONE);
}
}
}
break;
default:
break;
}
}
}
@Override
public boolean compare(final AssociationEnd end1, final AssociationEnd end2) {
FullQualifiedName end1Type = end1.getType();
FullQualifiedName currentAssociationEnd1Type = currentAssociationEnd1.getType();
FullQualifiedName end2Type = end2.getType();
FullQualifiedName currentAssociationEnd2Type = currentAssociationEnd2.getType();
if(end1.getMultiplicity() == null || currentAssociationEnd1.getMultiplicity() == null) {
return false;
}
if(end2.getMultiplicity() == null || currentAssociationEnd2.getMultiplicity() == null) {
return false;
}
boolean end1eqCurEnd1 = end1.getMultiplicity().equals(currentAssociationEnd1.getMultiplicity());
boolean end2eqCurEnd2 = end2.getMultiplicity().equals(currentAssociationEnd2.getMultiplicity());
if(end1Type.equals(currentAssociationEnd1Type) && end2Type.equals(currentAssociationEnd2Type)
&& end1eqCurEnd1 && end2eqCurEnd2) {
return true;
}
boolean end1EqCurEnd2 = end1.getMultiplicity().equals(currentAssociationEnd2.getMultiplicity());
boolean end2EqCurEnd1 = end2.getMultiplicity().equals(currentAssociationEnd1.getMultiplicity());
if(end1Type.equals(currentAssociationEnd2Type) && end2Type.equals(currentAssociationEnd1Type)
&& end1EqCurEnd2 && end2EqCurEnd1) {
return true;
}
boolean end1IsZeroToOne = end1.getMultiplicity() == EdmMultiplicity.ZERO_TO_ONE;
boolean end1IsOne = end1.getMultiplicity() == EdmMultiplicity.ONE;
boolean end2IsZeroToOne = end2.getMultiplicity() == EdmMultiplicity.ZERO_TO_ONE;
boolean end2IsOne = end2.getMultiplicity() == EdmMultiplicity.ONE;
if (end1Type.equals(currentAssociationEnd1Type) && end2Type.equals(currentAssociationEnd2Type)) {
if ((end1IsZeroToOne && currentAssociationEnd1.getMultiplicity() == EdmMultiplicity.ONE
|| end1IsOne && currentAssociationEnd1.getMultiplicity() == EdmMultiplicity.ZERO_TO_ONE)
&& end2eqCurEnd2) {
return true;
}
if ((end2IsZeroToOne && currentAssociationEnd2.getMultiplicity() == EdmMultiplicity.ONE
|| end2IsOne && currentAssociationEnd2.getMultiplicity() == EdmMultiplicity.ZERO_TO_ONE)
&& end1eqCurEnd1) {
return true;
}
}
if (end2Type.equals(currentAssociationEnd1Type) && end1Type.equals(currentAssociationEnd2Type)) {
if ((end1IsZeroToOne && currentAssociationEnd2.getMultiplicity() == EdmMultiplicity.ONE
|| end1IsOne && currentAssociationEnd2.getMultiplicity() == EdmMultiplicity.ZERO_TO_ONE)
&& end2EqCurEnd1) {
return true;
}
if ((end2IsZeroToOne && currentAssociationEnd1.getMultiplicity() == EdmMultiplicity.ONE
|| end2IsOne && currentAssociationEnd1.getMultiplicity() == EdmMultiplicity.ZERO_TO_ONE)
&& end1EqCurEnd2) {
return true;
}
}
return false;
}
@Override
public String[] getJoinColumnNames() {
return columnNames;
}
@Override
public String[] getJoinColumnReferenceColumnNames() {
return referencedColumnNames;
}
@Override
public String getMappedByName() {
return mappedBy;
}
@Override
public String getOwningPropertyName() {
return ownerPropertyName;
}
}