001    /**
002     * Copyright 2005-2013 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     */
016    package org.kuali.rice.krad.datadictionary;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.krad.bo.BusinessObject;
020    import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
021    import org.kuali.rice.krad.datadictionary.parse.BeanTag;
022    import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
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-bean")
039    public 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<? extends BusinessObject> collectionBusinessObjectClass;
047        protected Class<? extends BusinessObject> 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 the
116         * displayFieldName
117         * is set is
118         * defined by whether it has any non-whitespace content in it.
119         *
120         * @return
121         */
122        public boolean isDisplayFieldNameSet() {
123            return StringUtils.isNotBlank(displayFieldName);
124        }
125    
126        @BeanTagAttribute(name = "collection")
127        public String getCollection() {
128            return collection;
129        }
130    
131        /**
132         * collection is the name of a collection that must exist
133         */
134        public void setCollection(String collection) {
135            this.collection = collection;
136        }
137    
138        public boolean isCollectionReference() {
139            return StringUtils.isNotBlank(getCollection());
140        }
141    
142        @BeanTagAttribute(name = "collectionBusinessObjectClass")
143        public Class<? extends BusinessObject> getCollectionBusinessObjectClass() {
144            if (collectionBusinessObjectClass == null && isCollectionReference()) {
145                collectionBusinessObjectClass = DataDictionary.getCollectionElementClass(businessObjectClass, collection);
146            }
147    
148            return collectionBusinessObjectClass;
149        }
150    
151        /**
152         * Class that the specified collection represents.  Does not need to be set.  The DD
153         * Will set this attribute through introspection.
154         */
155        public void setCollectionBusinessObjectClass(Class<? extends BusinessObject> collectionBusinessObjectClass) {
156            this.collectionBusinessObjectClass = collectionBusinessObjectClass;
157        }
158    
159        /**
160         * Directly validate simple fields.
161         *
162         * @see org.kuali.rice.krad.datadictionary.DataDictionaryDefinition#completeValidation(java.lang.Class,
163         *      java.lang.Object)
164         */
165        public void completeValidation(Class rootBusinessObjectClass, Class otherBusinessObjectClass) {
166    
167            // make sure the attributeName is actually a property of the BO
168            String tmpAttributeName = isCollectionReference() ? collection : attributeName;
169            if (!DataDictionary.isPropertyOf(rootBusinessObjectClass, tmpAttributeName)) {
170                throw new AttributeValidationException("unable to find attribute '"
171                        + tmpAttributeName
172                        + "' in rootBusinessObjectClass '"
173                        + rootBusinessObjectClass.getName()
174                        + "' ("
175                        + ""
176                        + ")");
177            }
178            // make sure the attributeToHighlightOnFail is actually a property of the BO
179            if (isCollectionReference()) {
180                getCollectionBusinessObjectClass(); // forces loading of the class
181                if (collectionBusinessObjectClass == null) {
182                    throw new AttributeValidationException(
183                            "Unable to determine collectionBusinessObjectClass for collection '" + businessObjectClass
184                                    .getName() + "." + collection + "'");
185                }
186    
187                if (!DataDictionary.isPropertyOf(collectionBusinessObjectClass, attributeToHighlightOnFail)) {
188                    throw new AttributeValidationException("unable to find attribute '"
189                            + attributeToHighlightOnFail
190                            + "' in collectionBusinessObjectClass '"
191                            + collectionBusinessObjectClass.getName()
192                            + "' ("
193                            + ""
194                            + ")");
195                }
196            } else {
197                if (!DataDictionary.isPropertyOf(rootBusinessObjectClass, attributeToHighlightOnFail)) {
198                    throw new AttributeValidationException("unable to find attribute '"
199                            + attributeToHighlightOnFail
200                            + "' in rootBusinessObjectClass '"
201                            + rootBusinessObjectClass.getName()
202                            + "' ("
203                            + ""
204                            + ")");
205                }
206            }
207    
208        }
209    
210        /**
211         * @see java.lang.Object#toString()
212         */
213        public String toString() {
214            return "ReferenceDefinition for attribute " + getAttributeName();
215        }
216    
217        @BeanTagAttribute(name = "businessObjectClass")
218        public Class<? extends BusinessObject> getBusinessObjectClass() {
219            return businessObjectClass;
220        }
221    
222        public void setBusinessObjectClass(Class<? extends BusinessObject> businessObjectClass) {
223            this.businessObjectClass = businessObjectClass;
224        }
225    }