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.kew.api.document.attribute;
017
018import java.io.Serializable;
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025
026import javax.xml.bind.annotation.XmlAccessType;
027import javax.xml.bind.annotation.XmlAccessorType;
028import javax.xml.bind.annotation.XmlAnyElement;
029import javax.xml.bind.annotation.XmlElement;
030import javax.xml.bind.annotation.XmlElementWrapper;
031import javax.xml.bind.annotation.XmlRootElement;
032import javax.xml.bind.annotation.XmlType;
033
034import org.apache.commons.lang.StringUtils;
035import org.kuali.rice.core.api.CoreConstants;
036import org.kuali.rice.core.api.mo.AbstractDataTransferObject;
037import org.kuali.rice.core.api.mo.ModelBuilder;
038import org.kuali.rice.kew.api.document.PropertyDefinition;
039import org.w3c.dom.Element;
040
041/**
042 * Encapsulates parameters that can be sent to an attribute when using that attribute to perform various operations
043 * (primarily, in the case of workflow attributes, during the generation of XML).
044 *
045 * The distinction between parameters and properties is that parameters are used to initially construct the attribute
046 * (via the attribute class constructor), while property definitions are used to set properties on the attribute thereafter.
047 *
048 * @author Kuali Rice Team (rice.collab@kuali.org)
049 */
050@XmlRootElement(name = WorkflowAttributeDefinition.Constants.ROOT_ELEMENT_NAME)
051@XmlAccessorType(XmlAccessType.NONE)
052@XmlType(name = WorkflowAttributeDefinition.Constants.TYPE_NAME, propOrder = {
053                WorkflowAttributeDefinition.Elements.ATTRIBUTE_NAME,
054                WorkflowAttributeDefinition.Elements.PARAMETERS,
055                WorkflowAttributeDefinition.Elements.PROPERTY_DEFINITIONS,
056                CoreConstants.CommonElements.FUTURE_ELEMENTS
057})
058public final class WorkflowAttributeDefinition extends AbstractDataTransferObject {
059    
060        @XmlElement(name = Elements.ATTRIBUTE_NAME, required = true)
061    private final String attributeName;
062        
063        @XmlElementWrapper(name = Elements.PARAMETERS, required = false)
064        @XmlElement(name = Elements.PARAMETER, required = false)
065    private final List<String> parameters;
066        
067        @XmlElementWrapper(name = Elements.PROPERTY_DEFINITIONS, required = false)
068        @XmlElement(name = Elements.PROPERTY_DEFINITION, required = false)
069    private final List<PropertyDefinition> propertyDefinitions;
070    
071        @SuppressWarnings("unused")
072    @XmlAnyElement
073    private final Collection<Element> _futureElements = null;
074        
075        /**
076     * Private constructor used only by JAXB.
077     */
078        private WorkflowAttributeDefinition() {
079            this.attributeName = null;
080            this.parameters = null;
081            this.propertyDefinitions = null;
082        }
083        
084        private WorkflowAttributeDefinition(Builder builder) {
085                this.attributeName = builder.getAttributeName();
086                if (builder.getParameters() == null) {
087                        this.parameters = Collections.emptyList();
088                } else {
089                        this.parameters = new ArrayList<String>(builder.getParameters());
090                }
091                if (builder.getPropertyDefinitions() == null) {
092                        this.propertyDefinitions = Collections.emptyList();
093                } else {
094                        this.propertyDefinitions = new ArrayList<PropertyDefinition>(builder.getPropertyDefinitions());
095                }
096        }
097
098    /**
099     * Returns the name of the attribute for this workflow attribute definition.  Should never be a null or blank value.
100     *
101     * @return the name of the attribute for this workflow attribute definition
102     */
103    public String getAttributeName() {
104        return attributeName;
105    }
106
107    /**
108     * Returns an unmodifiable list of parameters that will be used to construct the attribute as a list of string
109     * values.  This list will never be null but it may be empty.
110     *
111     * @return the list of parameters used to construct the attribute
112     */
113    public List<String> getParameters() {
114        return Collections.unmodifiableList(parameters);
115    }
116
117    /**
118     * Returns an unmodifiable list of property names and values that will be passed to the attribute upon construction.
119     * This list will never be null but it may be empty.
120     *
121     * @return the list of property names and values to will be be passed to the attribute upon construction
122     */
123    public List<PropertyDefinition> getPropertyDefinitions() {
124        return Collections.unmodifiableList(propertyDefinitions);
125    }
126
127    /**
128     * Returns the property definitions on this attribute definition as a map of strings instead of a list of
129     * {@code PropertyDefinition} objects.
130     *
131     * @return a map representation of the property definitions on this workflow attribute definition
132     */
133    public Map<String, String> getPropertyDefinitionsAsMap() {
134        Map<String, String> propertiesDefinitionsMap = new HashMap<String, String>();
135        for (PropertyDefinition propertyDefinition : getPropertyDefinitions()) {
136            propertiesDefinitionsMap.put(propertyDefinition.getName(), propertyDefinition.getValue());
137        }
138        return Collections.unmodifiableMap(propertiesDefinitionsMap);
139    }
140
141    /**
142     * A builder which can be used to construct instances of {@code WorkflowAttributeDefinition}.
143     */
144    public final static class Builder implements Serializable, ModelBuilder {
145
146                private static final long serialVersionUID = 7549637048594326790L;
147
148                private String attributeName;
149                private List<String> parameters;
150                private List<PropertyDefinition> propertyDefinitions;
151
152                private Builder(String attributeName) {
153                        setAttributeName(attributeName);
154                        setParameters(new ArrayList<String>());
155                        setPropertyDefinitions(new ArrayList<PropertyDefinition>());
156                }
157                
158                private Builder(WorkflowAttributeDefinition definition) {
159                    setAttributeName(definition.getAttributeName());
160                    setParameters(definition.getParameters());
161                    setPropertyDefinitions(definition.getPropertyDefinitions());
162                }
163
164        /**
165         * Creates a new builder copying the properties from the given definition into it.
166         *
167         * @param definition the definition from which to copy properties
168         * @return a builder initialized with the properties copied from the given definition
169         */
170                public static Builder create(WorkflowAttributeDefinition definition) {
171                    if (definition == null) {
172                        throw new IllegalArgumentException("definition was null");
173                    }
174                    return new Builder(definition);
175                }
176
177        /**
178         * Constructs a builder which is initialized with the given attribute name.
179         *
180         * @param attributeName the attribute name to use when initializing this builder, cannot be a null or empty
181         * value
182         *
183         * @return an instance of a builder initialized with the given attribute name
184         *
185         * @throws IllegalArgumentException if {@code attributeName} is a null or blank value
186         */
187                public static Builder create(String attributeName) {
188                        return new Builder(attributeName);
189                        
190                }
191
192        @Override
193                public WorkflowAttributeDefinition build() {
194                        return new WorkflowAttributeDefinition(this);
195                }
196
197        /**
198         * Returns the attribute name that is set on this builder.
199         *
200         * @return the attribute name this is set on this builder
201         */
202                public String getAttributeName() {
203                        return attributeName;
204                }
205
206        /**
207         * Returns a list of string parameters that have been set on this builder.
208         *
209         * @return a list of string parameters that have been set on this builder
210         */
211                public List<String> getParameters() {
212                return parameters;
213                }
214
215        /**
216         * Returns a list of {@code PropertyDefinition} objects that have been set on this builder.
217         *
218         * @return a list of property definitions that have been set on this builder
219         */
220                public List<PropertyDefinition> getPropertyDefinitions() {
221                        return propertyDefinitions;
222                }
223
224        /**
225         * Sets the attribute name on this builder to the given value.  Must not be a null or blank value.
226         *
227         * @param attributeName the value of the attributeName to set
228         * @throws IllegalArgumentException if {@code attributeName} is a null or blank value
229         */
230                public void setAttributeName(String attributeName) {
231                        if (StringUtils.isBlank(attributeName)) {
232                                throw new IllegalArgumentException("attributeName was null or blank");
233                        }
234                        this.attributeName = attributeName;
235                }
236
237        /**
238         * Adds a parameter to the list of parameters maintained by this builder.
239         *
240         * @param parameter the parameter value to add
241         */
242                public void addParameter(String parameter) {
243                        parameters.add(parameter);
244                }
245
246        /**
247         * Removes a parameter with the given value from the list of parameters maintained by this builder.
248         *
249         * @param parameter the parameter value to remove
250         */
251                public void removeParameter(String parameter) {
252                        parameters.remove(parameter);
253                }
254
255        /**
256         * Sets the list of parameters on this builder.
257         *
258         * @param parameters the list of parameters to set
259         */
260                public void setParameters(List<String> parameters) {
261                        this.parameters = new ArrayList<String>(parameters);
262                }
263
264        /**
265         * Adds the given property definition to the list of property definitions maintained by this builder.
266         *
267         * @param propertyDefinition the property definition to set, should not be null
268         * @throws IllegalArgumentException if the given property definition is null
269         */
270                public void addPropertyDefinition(PropertyDefinition propertyDefinition) {
271                        if (propertyDefinition == null) {
272                                throw new IllegalArgumentException("propertyDefinition must be non-null.");
273                        }
274                        propertyDefinitions.add(propertyDefinition);
275                }
276
277        /**
278         * Sets the list of property definitions maintained by this build to the given list.
279         *
280         * @param propertyDefinitions the list of property definitions to set
281         */
282                public void setPropertyDefinitions(List<PropertyDefinition> propertyDefinitions) {
283                        if (propertyDefinitions == null) {
284                                setPropertyDefinitions(new ArrayList<PropertyDefinition>());
285                        }
286                        this.propertyDefinitions = new ArrayList<PropertyDefinition>(propertyDefinitions);
287                        
288                }
289
290        /**
291         * Add a property definition constructed from the given name and value to the list of property definitions
292         * on this builder.
293         *
294         * @param name name of the property definition to add, must not be a null or blank value
295         * @param value value of the property definition to add
296         *
297         * @throws IllegalArgumentException if the given name is a null or blank value
298         */
299                public void addPropertyDefinition(String name, String value) {
300                        addPropertyDefinition(PropertyDefinition.create(name, value));
301                }
302
303        /**
304         * Returns the property definition on this build which has the given name if it exists.  This method will return
305         * a null value if a definition with the given name cannot be found.
306         *
307         * @param name the name of the property definition to retrieve
308         *
309         * @return the property definition with the given name, or null if no such property definition is found
310         *
311         * @throws IllegalArgumentException if the given name is a null or blank value
312         */
313            public PropertyDefinition getPropertyDefinition(String name) {
314                if (StringUtils.isBlank(name)) {
315                    throw new IllegalArgumentException("name was null or blank");
316                }
317                for (PropertyDefinition propertyDefinition : propertyDefinitions) {
318                    if (propertyDefinition.equals(name)) {
319                        return propertyDefinition;
320                    }
321                }
322                return null;
323            }
324
325                
326    }
327    
328    /**
329     * Defines some internal constants used on this class.
330     */
331    static class Constants {
332        final static String ROOT_ELEMENT_NAME = "workflowAttributeDefinition";
333        final static String TYPE_NAME = "WorkflowAttributeDefinitionType";
334    }
335
336    /**
337     * A private class which exposes constants which define the XML element names to use when this object is marshalled to XML.
338     */
339    static class Elements {
340        final static String ATTRIBUTE_NAME = "attributeName";
341        final static String PARAMETERS = "parameters";
342        final static String PARAMETER = "parameter";
343        final static String PROPERTY_DEFINITIONS = "propertyDefinitions";
344        final static String PROPERTY_DEFINITION = "propertyDefinition";
345    }
346    
347}