001/**
002 * Copyright 2005-2018 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.krad.datadictionary;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.krad.datadictionary.parse.BeanTag;
020import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
021import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
022
023/**
024 * The primitiveAttribute element identifies one pair of
025 * corresponding fields in the primary business object and
026 * the related business object.
027 *
028 * JSTL: primitiveAttribute is a Map which is accessed by the
029 * sequential key of "0", "1", etc.  Each entry contains the following
030 * keys:
031 * sourceName (String)
032 * targetName (String)
033 * The value corresponding to the sourceName key is the attribute name defined
034 * for the primary business object.
035 * The value corresponding to the targetName key is the attribute name for
036 * the object being referenced by objectAttributeName.
037 */
038@BeanTag(name = "primitiveAttributeDefinition")
039public class PrimitiveAttributeDefinition extends DataDictionaryDefinitionBase {
040    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PrimitiveAttributeDefinition.class);
041    private static final long serialVersionUID = -715128943756700821L;
042
043    protected String sourceName;
044    protected String targetName;
045
046    public PrimitiveAttributeDefinition() {}
047
048    @BeanTagAttribute(name = "sourceName")
049    public String getSourceName() {
050        return sourceName;
051    }
052
053    /**
054     * sourceName is the name of the POJO property of the business object
055     *
056     * @throws IllegalArgumentException if the given sourceName is blank
057     */
058    public void setSourceName(String sourceName) {
059        if (StringUtils.isBlank(sourceName)) {
060            throw new IllegalArgumentException("invalid (blank) sourceName");
061        }
062
063        this.sourceName = sourceName;
064    }
065
066    @BeanTagAttribute(name = "targetName")
067    public String getTargetName() {
068        return targetName;
069    }
070
071    /**
072     * targetName is the name of attribute that corresponds to the sourceName in the looked up BO
073     *
074     * @throws IllegalArgumentException if the given targetName is blank
075     */
076    public void setTargetName(String targetName) {
077        if (StringUtils.isBlank(targetName)) {
078            throw new IllegalArgumentException("invalid (blank) targetName");
079        }
080
081        this.targetName = targetName;
082    }
083
084    /**
085     * Directly validate simple fields.
086     *
087     * @see org.kuali.rice.krad.datadictionary.DataDictionaryDefinition#completeValidation(java.lang.Class,
088     *      java.lang.Class)
089     */
090    @Override
091    public void completeValidation(Class rootBusinessObjectClass, Class otherBusinessObjectClass) {
092        completeValidation(rootBusinessObjectClass, otherBusinessObjectClass, new ValidationTrace());
093    }
094
095    /**
096     * Directly validate simple fields
097     *
098     * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntry#completeValidation(org.kuali.rice.krad.datadictionary.validator.ValidationTrace)
099     */
100    @Override
101    public void completeValidation(Class rootBusinessObjectClass, Class otherBusinessObjectClass,
102            ValidationTrace tracer) {
103        tracer.addBean(this.getClass().getSimpleName(), ValidationTrace.NO_BEAN_ID);
104
105        try {
106            if (!DataDictionary.isPropertyOf(rootBusinessObjectClass, sourceName)) {
107                String currentValues[] = {"attribute = " + getSourceName(), "class = " + rootBusinessObjectClass};
108                tracer.createError("Unable to find attribute on class", currentValues);
109            }
110        } catch (RuntimeException ex) {
111            String currentValues[] = {"attribute = " + getSourceName(), "class = " + rootBusinessObjectClass,
112                    "Exception = " + ex.getMessage()};
113            tracer.createError("Unable to find attribute on class", currentValues);
114            LOG.error( "Exception while validating PrimitiveAttributeDefintion on " + rootBusinessObjectClass + ": " + this, ex);
115        }
116        try {
117            if (!DataDictionary.isPropertyOf(otherBusinessObjectClass, targetName)) {
118                String currentValues[] = {"attribute = " + getTargetName(), "class = " + otherBusinessObjectClass};
119                tracer.createError("Unable to find attribute on class", currentValues);
120            }
121        } catch (RuntimeException ex) {
122            String currentValues[] = {"attribute = " + getTargetName(), "class = " + otherBusinessObjectClass,
123                    "Exception = " + ex.getMessage()};
124            tracer.createError("Unable to find attribute on class", currentValues);
125            LOG.error( "Exception while validating PrimitiveAttributeDefintion on " + rootBusinessObjectClass + ": " + this, ex);
126        }
127        try {
128            Class sourceClass = DataDictionary.getAttributeClass(rootBusinessObjectClass, sourceName);
129            Class targetClass = DataDictionary.getAttributeClass(otherBusinessObjectClass, targetName);
130            if ((null == sourceClass && null != targetClass)
131                    || (null != sourceClass && null == targetClass)
132                    || !StringUtils.equals(sourceClass.getName(), targetClass.getName())) {
133                String sourceClassName = rootBusinessObjectClass.getName();
134                String targetClassName = otherBusinessObjectClass.getName();
135                String sourcePath = sourceClassName + "." + sourceName;
136                String targetPath = targetClassName + "." + targetName;
137
138                // Just a temp hack to ignore null Person objects
139                if ((sourcePath != null && !StringUtils.contains(sourcePath, ".principalId"))
140                        && (targetPath != null && !StringUtils.contains(targetPath, ".principalId")) ) {
141                    String currentValues[] = {"source = " + sourcePath + "' (" + sourceClass + ")",
142                            "target = " + targetPath + "' (" + targetClass + ")"};
143                    tracer.createError("Source and target of different types", currentValues);
144                }
145            }
146        } catch (RuntimeException ex) {
147            String currentValues[] = {"Exception = " + ex.getMessage()};
148            tracer.createError("Unable to validate property", currentValues);
149            LOG.error( "Exception while validating PrimitiveAttributeDefintion on " + rootBusinessObjectClass + ": " + this, ex);
150        }
151    }
152
153    @Override
154    public String toString() {
155        StringBuilder builder = new StringBuilder();
156        builder.append("PrimitiveAttributeDefinition [sourceName=").append(this.sourceName).append(", targetName=")
157                .append(this.targetName).append("]");
158        return builder.toString();
159    }
160
161}