001/** 002 * Copyright 2005-2016 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 japa.parser.ast.expr.StringLiteralExpr; 026import org.apache.commons.lang.ClassUtils; 027import org.apache.commons.lang.StringUtils; 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030import org.apache.ojb.broker.metadata.DescriptorRepository; 031import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; 032import org.kuali.rice.devtools.jpa.eclipselink.conv.ojb.OjbUtil; 033import org.kuali.rice.devtools.jpa.eclipselink.conv.parser.helper.NodeData; 034 035import java.util.ArrayList; 036import java.util.Collection; 037import java.util.List; 038 039public class ManyToOneResolver extends AbstractMappedFieldResolver { 040 private static final Log LOG = LogFactory.getLog(ManyToOneResolver.class); 041 042 public static final String PACKAGE = "javax.persistence"; 043 public static final String SIMPLE_NAME = "ManyToOne"; 044 045 public ManyToOneResolver(Collection<DescriptorRepository> descriptorRepositories) { 046 super(descriptorRepositories); 047 } 048 @Override 049 public String getFullyQualifiedName() { 050 return PACKAGE + "." + SIMPLE_NAME; 051 } 052 053 /** gets the annotation but also adds an import in the process if a Convert annotation is required. */ 054 @Override 055 protected NodeData getAnnotationNodes(String enclosingClass, String fieldName, String mappedClass) { 056 final ObjectReferenceDescriptor ord = OjbUtil.findObjectReferenceDescriptor(mappedClass, fieldName, descriptorRepositories); 057 if (ord != null) { 058 final List<MemberValuePair> pairs = new ArrayList<MemberValuePair>(); 059 final Collection<ImportDeclaration> additionalImports = new ArrayList<ImportDeclaration>(); 060 061 final Collection<String> fks = ord.getForeignKeyFields(); 062 if (fks == null || fks.isEmpty()) { 063 LOG.error(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has a reference descriptor for " + fieldName 064 + " but does not have any foreign keys configured"); 065 return null; 066 } 067 068 final Collection<String> pks = OjbUtil.getPrimaryKeyNames(mappedClass, descriptorRepositories); 069 070 if (!(pks.size() == fks.size() && pks.containsAll(fks))) { 071 final String className = ord.getItemClassName(); 072 if (StringUtils.isBlank(className)) { 073 LOG.error(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has a reference descriptor for " + fieldName 074 + " but does not class name attribute"); 075 } else { 076 final String shortClassName = ClassUtils.getShortClassName(className); 077 final String packageName = ClassUtils.getPackageName(className); 078 pairs.add(new MemberValuePair("targetEntity", new NameExpr(shortClassName + ".class"))); 079 additionalImports.add(new ImportDeclaration(new QualifiedNameExpr(new NameExpr(packageName), shortClassName), false, false)); 080 } 081 082 final boolean proxy = ord.isLazy(); 083 if (proxy) { 084 pairs.add(new MemberValuePair("fetch", new NameExpr("FetchType.LAZY"))); 085 additionalImports.add(new ImportDeclaration(new QualifiedNameExpr(new NameExpr(PACKAGE), "FetchType"), false, false)); 086 } 087 088 final boolean refresh = ord.isRefresh(); 089 if (refresh) { 090 LOG.error(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has refresh set to " + refresh + ", unsupported conversion to @OneToOne attributes"); 091 } 092 093 final List<Expression> cascadeTypes = new ArrayList<Expression>(); 094 final boolean autoRetrieve = ord.getCascadeRetrieve(); 095 if (autoRetrieve) { 096 cascadeTypes.add(new NameExpr("CascadeType.REFRESH")); 097 } else { 098 // updated default logging - false would result no additional annotations 099 if ( LOG.isDebugEnabled() ) { 100 LOG.debug(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-retrieve set to " + autoRetrieve + ", unsupported conversion to CascadeType"); 101 } 102 } 103 104 final int autoDelete = ord.getCascadingDelete(); 105 if (autoDelete == ObjectReferenceDescriptor.CASCADE_NONE) { 106 // updated default logging - none would result no additional annotations 107 if ( LOG.isDebugEnabled() ) { 108 LOG.debug(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-delete set to none, unsupported conversion to CascadeType"); 109 } 110 } else if (autoDelete == ObjectReferenceDescriptor.CASCADE_LINK) { 111 LOG.warn(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-delete set to link, unsupported conversion to CascadeType"); 112 } else if (autoDelete == ObjectReferenceDescriptor.CASCADE_OBJECT) { 113 cascadeTypes.add(new NameExpr("CascadeType.REMOVE")); 114 } else { 115 LOG.error(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-delete set to an invalid value"); 116 } 117 118 final int autoUpdate = ord.getCascadingStore(); 119 if (autoUpdate == ObjectReferenceDescriptor.CASCADE_NONE) { 120 // updated default logging - none would result no additional annotations 121 if ( LOG.isDebugEnabled() ) { 122 LOG.debug(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-update set to none, unsupported conversion to CascadeType"); 123 } 124 } else if (autoUpdate == ObjectReferenceDescriptor.CASCADE_LINK) { 125 LOG.warn(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-update set to link, unsupported conversion to CascadeType"); 126 } else if (autoUpdate == ObjectReferenceDescriptor.CASCADE_OBJECT) { 127 cascadeTypes.add(new NameExpr("CascadeType.PERSIST")); 128 } else { 129 LOG.error(ResolverUtil.logMsgForField(enclosingClass, fieldName, mappedClass) + " field has auto-update set to an invalid value"); 130 } 131 132 if (!cascadeTypes.isEmpty()) { 133 pairs.add(new MemberValuePair("cascade", new ArrayInitializerExpr(cascadeTypes))); 134 additionalImports.add(new ImportDeclaration(new QualifiedNameExpr(new NameExpr(PACKAGE), "CascadeType"), false, false)); 135 } 136 137 return new NodeData(new NormalAnnotationExpr(new NameExpr(SIMPLE_NAME), pairs), 138 new ImportDeclaration(new QualifiedNameExpr(new NameExpr(PACKAGE), SIMPLE_NAME), false, false), 139 additionalImports); 140 } 141 } 142 return null; 143 } 144}