001/** 002 * Copyright 2005-2015 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.devtools.jpa.eclipselink.conv.parser.helper.resolver; 017 018import japa.parser.ast.ImportDeclaration; 019import japa.parser.ast.expr.ArrayInitializerExpr; 020import japa.parser.ast.expr.Expression; 021import japa.parser.ast.expr.MemberValuePair; 022import japa.parser.ast.expr.NameExpr; 023import japa.parser.ast.expr.NormalAnnotationExpr; 024import japa.parser.ast.expr.QualifiedNameExpr; 025import org.apache.commons.lang.ClassUtils; 026import org.apache.commons.lang.StringUtils; 027import org.apache.logging.log4j.Logger; 028import org.apache.logging.log4j.LogManager; 029import org.apache.ojb.broker.metadata.DescriptorRepository; 030import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; 031import org.kuali.rice.devtools.jpa.eclipselink.conv.ojb.OjbUtil; 032import org.kuali.rice.devtools.jpa.eclipselink.conv.parser.helper.NodeData; 033 034import java.util.ArrayList; 035import java.util.Collection; 036import java.util.List; 037 038public class ManyToOneResolver extends AbstractMappedFieldResolver { 039 private static final Logger LOG = LogManager.getLogger(ManyToOneResolver.class); 040 041 public static final String PACKAGE = "javax.persistence"; 042 public static final String SIMPLE_NAME = "ManyToOne"; 043 044 public ManyToOneResolver(Collection<DescriptorRepository> descriptorRepositories) { 045 super(descriptorRepositories); 046 } 047 @Override 048 public String getFullyQualifiedName() { 049 return PACKAGE + "." + SIMPLE_NAME; 050 } 051 052 /** gets the annotation but also adds an import in the process if a Convert annotation is required. */ 053 @Override 054 protected NodeData getAnnotationNodes(String enclosingClass, String fieldName, String mappedClass) { 055 final ObjectReferenceDescriptor ord = OjbUtil.findObjectReferenceDescriptor(mappedClass, fieldName, descriptorRepositories); 056 if (ord != null) { 057 final List<MemberValuePair> pairs = new ArrayList<MemberValuePair>(); 058 final Collection<ImportDeclaration> additionalImports = new ArrayList<ImportDeclaration>(); 059 060 final Collection<String> fks = ord.getForeignKeyFields(); 061 if (fks == null || fks.isEmpty()) { 062 LOG.error(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has a reference descriptor for " + fieldName 063 + " but does not have any foreign keys configured"); 064 return null; 065 } 066 067 final Collection<String> pks = OjbUtil.getPrimaryKeyNames(mappedClass, descriptorRepositories); 068 069 if (!(pks.size() == fks.size() && pks.containsAll(fks))) { 070 final String className = ord.getItemClassName(); 071 if (StringUtils.isBlank(className)) { 072 LOG.error(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has a reference descriptor for " + fieldName 073 + " but does not class name attribute"); 074 } else { 075 final String shortClassName = ClassUtils.getShortClassName(className); 076 final String packageName = ClassUtils.getPackageName(className); 077 pairs.add(new MemberValuePair("targetEntity", new NameExpr(shortClassName + ".class"))); 078 additionalImports.add(new ImportDeclaration(new QualifiedNameExpr(new NameExpr(packageName), shortClassName), false, false)); 079 } 080 081 final boolean proxy = ord.isLazy(); 082 if (proxy) { 083 pairs.add(new MemberValuePair("fetch", new NameExpr("FetchType.LAZY"))); 084 additionalImports.add(new ImportDeclaration(new QualifiedNameExpr(new NameExpr(PACKAGE), "FetchType"), false, false)); 085 } 086 087 final boolean refresh = ord.isRefresh(); 088 if (refresh) { 089 LOG.error(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has refresh set to " + refresh + ", unsupported conversion to @OneToOne attributes"); 090 } 091 092 final List<Expression> cascadeTypes = new ArrayList<Expression>(); 093 final boolean autoRetrieve = ord.getCascadeRetrieve(); 094 if (autoRetrieve) { 095 cascadeTypes.add(new NameExpr("CascadeType.REFRESH")); 096 } else { 097 // updated default logging - false would result no additional annotations 098 if ( LOG.isDebugEnabled() ) { 099 LOG.debug(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-retrieve set to " + autoRetrieve + ", unsupported conversion to CascadeType"); 100 } 101 } 102 103 final int autoDelete = ord.getCascadingDelete(); 104 if (autoDelete == ObjectReferenceDescriptor.CASCADE_NONE) { 105 // updated default logging - none would result no additional annotations 106 if ( LOG.isDebugEnabled() ) { 107 LOG.debug(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-delete set to none, unsupported conversion to CascadeType"); 108 } 109 } else if (autoDelete == ObjectReferenceDescriptor.CASCADE_LINK) { 110 LOG.warn(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-delete set to link, unsupported conversion to CascadeType"); 111 } else if (autoDelete == ObjectReferenceDescriptor.CASCADE_OBJECT) { 112 cascadeTypes.add(new NameExpr("CascadeType.REMOVE")); 113 } else { 114 LOG.error(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-delete set to an invalid value"); 115 } 116 117 final int autoUpdate = ord.getCascadingStore(); 118 if (autoUpdate == ObjectReferenceDescriptor.CASCADE_NONE) { 119 // updated default logging - none would result no additional annotations 120 if ( LOG.isDebugEnabled() ) { 121 LOG.debug(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-update set to none, unsupported conversion to CascadeType"); 122 } 123 } else if (autoUpdate == ObjectReferenceDescriptor.CASCADE_LINK) { 124 LOG.warn(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-update set to link, unsupported conversion to CascadeType"); 125 } else if (autoUpdate == ObjectReferenceDescriptor.CASCADE_OBJECT) { 126 cascadeTypes.add(new NameExpr("CascadeType.PERSIST")); 127 } else { 128 LOG.error(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-update set to an invalid value"); 129 } 130 131 if (!cascadeTypes.isEmpty()) { 132 pairs.add(new MemberValuePair("cascade", new ArrayInitializerExpr(cascadeTypes))); 133 additionalImports.add(new ImportDeclaration(new QualifiedNameExpr(new NameExpr(PACKAGE), "CascadeType"), false, false)); 134 } 135 136 return new NodeData(new NormalAnnotationExpr(new NameExpr(SIMPLE_NAME), pairs), 137 new ImportDeclaration(new QualifiedNameExpr(new NameExpr(PACKAGE), SIMPLE_NAME), false, false), 138 additionalImports); 139 } 140 } 141 return null; 142 } 143}