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.krad.datadictionary;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.krad.bo.BusinessObject;
020import org.kuali.rice.krad.datadictionary.parse.BeanTag;
021import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
022import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
023
024/**
025 * The reference element specifies the name of a reference
026 * object that is required to exist in order for the primary
027 * business object to be created or modified on a BO.
028 *
029 * DD: See ReferenceDefinition.java
030 *
031 * JSTL: references are Maps with the following keys:
032 * attributeName (String)
033 * activeIndicatorAttributeName (String)
034 * activeIndicatorReversed (boolean String)
035 * attributeToHighlightOnFail (String)
036 * displayFieldName (String)
037 */
038@BeanTag(name = "referenceDefinition")
039public class ReferenceDefinition extends DataDictionaryDefinitionBase {
040    private static final long serialVersionUID = 1737968024207302931L;
041
042    protected String attributeName;
043    protected String attributeToHighlightOnFail;
044    protected String displayFieldName;
045    protected String collection;
046    protected Class<?> collectionBusinessObjectClass;
047    protected Class<?> businessObjectClass;
048
049    public ReferenceDefinition() {}
050
051    /**
052     * @return attributeName
053     */
054    @BeanTagAttribute(name = "attributeName")
055    public String getAttributeName() {
056        return attributeName;
057    }
058
059    /**
060     * attributeName is the name of a reference object that
061     * must exist and not be null.  In the case of a collection,
062     * then this is the name of a reference object within the
063     * collection element.
064     *
065     * @throws IllegalArgumentException if the given attributeName is blank
066     */
067    public void setAttributeName(String attributeName) {
068        if (StringUtils.isBlank(attributeName)) {
069            throw new IllegalArgumentException("invalid (blank) attributeName");
070        }
071        this.attributeName = attributeName;
072    }
073
074    /**
075     * Gets the attributeToHighlightOnFail attribute.
076     *
077     * @return Returns the attributeToHighlightOnFail.
078     */
079    @BeanTagAttribute(name = "attributeToHighlightOnFail")
080    public String getAttributeToHighlightOnFail() {
081        return attributeToHighlightOnFail;
082    }
083
084    /**
085     * attributeToHighlightOnFail is the name of the busines
086     * object attribute which will be highlighted when
087     * the default existence check fails.
088     */
089    public void setAttributeToHighlightOnFail(String attributeToHighlightOnFail) {
090        if (StringUtils.isBlank(attributeToHighlightOnFail)) {
091            throw new IllegalArgumentException("invalid (blank) attributeToHighlightOnFail");
092        }
093        this.attributeToHighlightOnFail = attributeToHighlightOnFail;
094    }
095
096    /**
097     * Gets the displayFieldName attribute.
098     *
099     * @return Returns the displayFieldName.
100     */
101    @BeanTagAttribute(name = "displayFieldName")
102    public String getDisplayFieldName() {
103        return displayFieldName;
104    }
105
106    /**
107     * displayFieldName is the name of the field to pull the label as it will
108     * appear in an error message.  e.g. "chartOfAccountsCode".
109     */
110    public void setDisplayFieldName(String displayFieldName) {
111        this.displayFieldName = displayFieldName;
112    }
113
114    /**
115     * This method returns true if the displayFieldName is set, otherwise it returns false. Whether
116     * the displayFieldName is set is defined by whether it has any non-whitespace content in it.
117     * 
118     * @return true if the display field name is set
119     */
120    public boolean isDisplayFieldNameSet() {
121        return StringUtils.isNotBlank(displayFieldName);
122    }
123
124    @BeanTagAttribute(name = "collection")
125    public String getCollection() {
126        return collection;
127    }
128
129    /**
130     * collection is the name of a collection that must exist
131     */
132    public void setCollection(String collection) {
133        this.collection = collection;
134    }
135
136    public boolean isCollectionReference() {
137        return StringUtils.isNotBlank(getCollection());
138    }
139
140    @BeanTagAttribute(name = "collectionBusinessObjectClass")
141    public Class<?> getCollectionBusinessObjectClass() {
142        return collectionBusinessObjectClass;
143    }
144
145    /**
146     * Class that the specified collection represents.  Does not need to be set.  The DD
147     * Will set this attribute through introspection.
148     */
149    public void setCollectionBusinessObjectClass(Class<?> collectionBusinessObjectClass) {
150        this.collectionBusinessObjectClass = collectionBusinessObjectClass;
151    }
152
153    @Override
154    public void dataDictionaryPostProcessing() {
155        super.dataDictionaryPostProcessing();
156        if (collectionBusinessObjectClass == null && isCollectionReference()) {
157            collectionBusinessObjectClass = DataDictionary.getCollectionElementClass(businessObjectClass, collection);
158        }
159    }
160
161    @Override
162    public void completeValidation(Class<?> rootBusinessObjectClass, Class<?> otherBusinessObjectClass, ValidationTrace tracer) {
163        String tmpAttributeName = isCollectionReference() ? collection : attributeName;
164        // make sure the attributeName is actually a property of the BO
165        if (!DataDictionary.isPropertyOf(rootBusinessObjectClass, tmpAttributeName)) {
166            String currentValues[] = {"rootBusinessObjectClass = " + rootBusinessObjectClass.getName(),
167                    "attribute = " + tmpAttributeName};
168            tracer.createError("ReferenceDefinition attribute does not exist on parent object",
169                    currentValues);
170        }
171        // make sure the attributeToHighlightOnFail is actually a property of the BO
172        if (isCollectionReference()) {
173            if (collectionBusinessObjectClass == null) {
174                String currentValues[] = {"rootBusinessObjectClass = " + rootBusinessObjectClass.getName(),
175                        "attribute = " + tmpAttributeName};
176                tracer.createError("ReferenceDefinition: Unable to determine BO class for collection",
177                        currentValues);
178            } else {
179                    if (!DataDictionary.isPropertyOf(collectionBusinessObjectClass, attributeToHighlightOnFail)) {
180                    String currentValues[] = {"collectionBusinessObjectClass = " + collectionBusinessObjectClass.getName(),
181                            "attributeToHighlightOnFail = " + attributeToHighlightOnFail};
182                    tracer.createError("ReferenceDefinition: attributeToHighlightOnFail does not exist on collection class",
183                            currentValues);
184                    }
185            }
186        } else {
187                if (!DataDictionary.isPropertyOf(rootBusinessObjectClass, attributeToHighlightOnFail)) {
188                String currentValues[] = {"rootBusinessObjectClass = " + rootBusinessObjectClass.getName(),
189                        "attributeToHighlightOnFail = " + attributeToHighlightOnFail};
190                tracer.createError("ReferenceDefinition: attributeToHighlightOnFail does not exist on parent class",
191                        currentValues);
192                }
193        }
194    }
195
196
197    @BeanTagAttribute(name = "businessObjectClass")
198    public Class<?> getBusinessObjectClass() {
199        return businessObjectClass;
200    }
201
202    public void setBusinessObjectClass(Class<?> businessObjectClass) {
203        this.businessObjectClass = businessObjectClass;
204    }
205}