001    /**
002     * Copyright 2005-2012 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.krms.api.repository.action;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.core.api.CoreConstants;
020    import org.kuali.rice.core.api.mo.AbstractDataTransferObject;
021    import org.kuali.rice.core.api.mo.ModelBuilder;
022    import org.kuali.rice.core.api.util.jaxb.MapStringStringAdapter;
023    
024    import javax.xml.bind.annotation.XmlAccessType;
025    import javax.xml.bind.annotation.XmlAccessorType;
026    import javax.xml.bind.annotation.XmlAnyElement;
027    import javax.xml.bind.annotation.XmlElement;
028    import javax.xml.bind.annotation.XmlRootElement;
029    import javax.xml.bind.annotation.XmlType;
030    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
031    import java.io.Serializable;
032    import java.util.Collection;
033    import java.util.Collections;
034    import java.util.HashMap;
035    import java.util.Map;
036    
037    /**
038     * Concrete model object implementation of KRMS Repository Action 
039     * immutable. 
040     * Instances of Action can be (un)marshalled to and from XML.
041     *
042     * @see org.kuali.rice.krms.framework.engine.Action
043     * @see ActionDefinitionContract
044     *
045     * @author Kuali Rice Team (rice.collab@kuali.org)
046     */
047    @XmlRootElement(name = ActionDefinition.Constants.ROOT_ELEMENT_NAME)
048    @XmlAccessorType(XmlAccessType.NONE)
049    @XmlType(name = ActionDefinition.Constants.TYPE_NAME, propOrder = {
050                    ActionDefinition.Elements.ID,
051                    ActionDefinition.Elements.NAME,
052                    ActionDefinition.Elements.NAMESPACE,
053                    ActionDefinition.Elements.DESC,
054                    ActionDefinition.Elements.TYPE_ID,
055                    ActionDefinition.Elements.RULE_ID,
056                    ActionDefinition.Elements.SEQUENCE_NUMBER,
057                    ActionDefinition.Elements.ATTRIBUTES,
058            CoreConstants.CommonElements.VERSION_NUMBER,
059                    CoreConstants.CommonElements.FUTURE_ELEMENTS
060    })
061    public final class ActionDefinition extends AbstractDataTransferObject implements ActionDefinitionContract {
062            private static final long serialVersionUID = 2783959459503209577L;
063    
064            @XmlElement(name = Elements.ID, required=true)
065            private String id;
066            @XmlElement(name = Elements.NAME, required=true)
067            private String name;
068            @XmlElement(name = Elements.NAMESPACE, required=true)
069            private String namespace;
070            @XmlElement(name = Elements.DESC, required=true)
071            private String description;
072            @XmlElement(name = Elements.TYPE_ID, required=true)
073            private String typeId;
074            @XmlElement(name = Elements.RULE_ID, required=true)
075            private String ruleId;
076            @XmlElement(name = Elements.SEQUENCE_NUMBER, required=true)
077            private Integer sequenceNumber;
078            
079            @XmlElement(name = Elements.ATTRIBUTES, required = false)
080            @XmlJavaTypeAdapter(value = MapStringStringAdapter.class)
081            private final Map<String, String> attributes;
082            
083        @XmlElement(name = CoreConstants.CommonElements.VERSION_NUMBER, required = false)
084        private final Long versionNumber;
085            
086            @SuppressWarnings("unused")
087        @XmlAnyElement
088        private final Collection<org.w3c.dom.Element> _futureElements = null;
089            
090            
091             /** 
092         * This constructor should never be called.  
093         * It is only present for use during JAXB unmarshalling. 
094         */
095        private ActionDefinition() {
096            this.id = null;
097            this.name = null;
098            this.namespace = null;
099            this.description = null;
100            this.typeId = null;
101            this.ruleId = null;
102            this.sequenceNumber = null;
103            this.attributes = null;
104            this.versionNumber = null;
105        }
106        
107        /**
108             * Constructs a KRMS Repository Action object from the given builder.  
109             * This constructor is private and should only ever be invoked from the builder.
110             * 
111             * @param builder the Builder from which to construct the Action
112             */
113        private ActionDefinition(Builder builder) {
114            this.id = builder.getId();
115            this.name = builder.getName();
116            this.namespace = builder.getNamespace();
117            this.description = builder.getDescription();
118            this.typeId = builder.getTypeId();
119            this.ruleId = builder.getRuleId();
120            this.sequenceNumber = builder.getSequenceNumber();
121            if (builder.attributes != null){
122                    this.attributes = Collections.unmodifiableMap(builder.getAttributes());
123            } else {
124                    this.attributes = null;
125            }
126            this.versionNumber = builder.getVersionNumber();
127        }
128        
129            @Override
130            public String getId() {
131                    return this.id;
132            }
133    
134            @Override
135            public String getName() {
136                    return this.name;
137            }
138    
139            @Override
140            public String getNamespace() {
141                    return this.namespace;
142            }
143    
144            @Override
145            public String getDescription() {
146                    return this.description;
147            }
148    
149            @Override
150            public String getTypeId() {
151                    return this.typeId;
152            }
153    
154            @Override
155            public String getRuleId() {
156                    return this.ruleId;
157            }
158    
159            @Override
160            public Integer getSequenceNumber() {
161                    return this.sequenceNumber;
162            }
163    
164        /**
165         * Returns the internal representation of the set of attributes associated with the
166         * Action.  The attributes are represented as name/value pairs.
167         *
168         * @return internal representation of the set of ActionAttribute objects.
169         */
170            @Override
171            public Map<String, String> getAttributes() {
172                    return this.attributes; 
173            }
174    
175        @Override
176        public Long getVersionNumber() {
177            return versionNumber;
178        }
179            
180            /**
181         * This builder is used to construct instances of KRMS Repository Action.  It enforces the constraints of the {@link ActionDefinitionContract}.
182         */
183        public static class Builder implements ActionDefinitionContract, ModelBuilder, Serializable {
184            private static final long serialVersionUID = -6773634512570180267L;
185    
186            private String id;
187            private String name;
188            private String namespace;
189            private String description;
190            private String typeId;
191            private String ruleId;
192            private Integer sequenceNumber;
193            private Map<String, String> attributes;
194            private Long versionNumber;
195    
196            /**
197             * Private constructor for creating a builder with all of it's required attributes.
198             *
199             * @param actionId the actionId value to set, must no tbe null or blank
200             * @param name the name value to set, must not be null or blank
201             * @param namespace the namespace value to set, must not be null or blank
202             * @param typeId the typeId value to set
203             * @param ruleId the ruleId value to set, must not be null or blank
204             * @param sequenceNumber the sequenceNumber value to set, must not be null or blank
205             */
206            private Builder(String actionId, String name, String namespace, String typeId, String ruleId, Integer sequenceNumber) {
207                setId(actionId);
208                setName(name);
209                setNamespace(namespace);
210                setTypeId(typeId);
211                setRuleId(ruleId);
212                setSequenceNumber(sequenceNumber);
213                setAttributes(new HashMap<String, String>());
214            }
215    
216            /**
217             * Create a builder with the given parameters
218             * 
219             * @param actionId the actionId value to set, must no tbe null or blank
220             * @param name the name value to set, must not be null or blank
221             * @param namespace the namespace value to set, must not be null or blank
222             * @param typeId the typeId value to set
223             * @param ruleId the ruleId value to set, must not be null or blank
224             * @param sequenceNumber the sequenceNumber value to set, must not be null or blank
225             * @return an instance of the builder populated with given data
226             */
227            public static Builder create(String actionId, String name, String namespace, String typeId, String ruleId, Integer sequenceNumber){
228                    return new Builder(actionId, name, namespace, typeId, ruleId, sequenceNumber);
229            }
230            /**
231             * Creates a builder by populating it with data from the given {@link ActionDefinitionContract}.
232             * 
233             * @param contract the contract from which to populate this builder
234             * @return an instance of the builder populated with data from the contract
235             * @throws IllegalArgumentException if the contract is null
236             */
237            public static Builder create(ActionDefinitionContract contract) {
238                    if (contract == null) {
239                    throw new IllegalArgumentException("contract is null");
240                }
241                Builder builder =  new Builder(contract.getId(), contract.getName(),
242                            contract.getNamespace(), contract.getTypeId(), contract.getRuleId(),
243                            contract.getSequenceNumber());
244                builder.setDescription(contract.getDescription());
245                    if (contract.getAttributes() != null){
246                    builder.setAttributes(new HashMap<String, String>(contract.getAttributes()));
247                    }
248                builder.setVersionNumber(contract.getVersionNumber());
249                return builder;
250            }
251    
252                    /**
253                     * Sets the value of the id on this builder to the given value.
254                     * 
255             * @param actionId the actionId value to set, must no tbe null or blank
256                     * @throws IllegalArgumentException if the actionId is non-null and blank
257                     */
258            public void setId(String actionId) {
259                if (actionId != null && StringUtils.isBlank(actionId)) {
260                    throw new IllegalArgumentException("action ID must be null or non-blank");
261                }
262                            this.id = actionId;
263                    }
264    
265    
266            /**
267             * Sets the value of the name on this builder to the given value.
268             *
269             * @param name the name value to set, must not be null or blank
270             * @throws IllegalArgumentException if the name is non-null and blank
271             */
272            public void setName(String name) {
273                if (StringUtils.isBlank(name)) {
274                    throw new IllegalArgumentException("name is blank");
275                }
276                            this.name = name;
277                    }
278    
279            /**
280             * Sets the value of the namespace on this builder to the given value.
281             *
282             * @param namespace the namespace value to set, must not be null or blank
283             * @throws IllegalArgumentException if the namespace is non-null and blank
284             */
285            public void setNamespace(String namespace) {
286                if (StringUtils.isBlank(namespace)) {
287                    throw new IllegalArgumentException("namespace is blank");
288                }
289                            this.namespace = namespace;
290                    }
291    
292            /**
293             * Sets the value of the description on this builder to the given value.
294             *
295             * @param desc the description value to set
296             */
297                    public void setDescription(String desc) {
298                            this.description = desc;
299                    }
300    
301            /**
302             * Sets the value of the typeId on this builder to the given value.
303             *
304             * @param typeId the typeId value to set, must not be null or blank.
305             * @throws IllegalArgumentException if the typeId is null or blank
306             */
307                    public void setTypeId(String typeId) {
308                            if (StringUtils.isBlank(typeId)) {
309                            throw new IllegalArgumentException("KRMS type id is blank");
310                            }
311                            this.typeId = typeId;
312                    }
313    
314            /**
315             * Sets the value of the ruleId on this builder to the given value.
316             *
317             * @param ruleId the ruleId value to set, must not be null or blank
318             * @throws IllegalArgumentException if the ruleId is null or blank
319             */
320                    public void setRuleId(String ruleId) {
321                            if (StringUtils.isBlank(ruleId)) {
322                            throw new IllegalArgumentException("rule id is blank");
323                            }
324                            this.ruleId = ruleId;
325                    }
326    
327            /**
328             * Sets the value of the sequenceNumber on this builder to the given value.
329             *
330             * @param sequenceNumber the sequenceNumber value to set, must not be null or blank
331             * @throws IllegalArgumentException if the sequenceNumber is null or blank
332             */
333                    public void setSequenceNumber(Integer sequenceNumber) {
334                            if (sequenceNumber == null) {
335                            throw new IllegalArgumentException("sequence number is null");
336                            }
337                            this.sequenceNumber = sequenceNumber;
338                    }
339    
340            /**
341             * Sets the value of the attributes on this builder to the given value.
342             *
343             * @param attributes the attributes value to set, can be null
344             */
345                    public void setAttributes(Map<String, String> attributes){
346                            if (attributes == null){
347                                    this.attributes = Collections.emptyMap();
348                            }
349                            this.attributes = Collections.unmodifiableMap(attributes);
350                    }
351    
352            /**
353             * Sets the value of the versionNumber on this builder to the given value.
354             *
355             * @param versionNumber the versionNumber value to set
356             */
357            public void setVersionNumber(Long versionNumber){
358                this.versionNumber = versionNumber;
359            }
360            
361                    @Override
362                    public String getId() {
363                            return id;
364                    }
365    
366                    @Override
367                    public String getName() {
368                            return name;
369                    }
370    
371                    @Override
372                    public String getNamespace() {
373                            return namespace;
374                    }
375    
376                    @Override
377                    public String getDescription() {
378                            return description;
379                    }
380    
381                    @Override
382                    public String getTypeId() {
383                            return typeId;
384                    }
385    
386                    @Override
387                    public String getRuleId() {
388                            return ruleId;
389                    }
390    
391                    @Override
392                    public Integer getSequenceNumber() {
393                            return sequenceNumber;
394                    }
395    
396                    @Override
397                    public Map<String, String> getAttributes() {
398                            return attributes;
399                    }
400    
401            @Override
402            public Long getVersionNumber() {
403                return versionNumber;
404            }
405    
406                    /**
407                     * Builds an instance of a Action based on the current state of the builder.
408                     * 
409                     * @return the fully-constructed Action
410                     */
411            @Override
412            public ActionDefinition build() {
413                return new ActionDefinition(this);
414            }
415                    
416        }
417            
418            /**
419             * Defines some internal constants used on this class.
420             */
421            static class Constants {
422                    final static String ROOT_ELEMENT_NAME = "action";
423                    final static String TYPE_NAME = "ActionType";
424            }
425            
426            /**
427             * A private class which exposes constants which define the XML element names to use
428             * when this object is marshalled to XML.
429             */
430            public static class Elements {
431                    final static String ID = "id";
432                    final static String NAME = "name";
433                    final static String NAMESPACE = "namespace";
434                    final static String DESC = "description";
435                    final static String TYPE_ID = "typeId";
436                    final static String RULE_ID = "ruleId";
437                    final static String SEQUENCE_NUMBER = "sequenceNumber";
438                    final static String ATTRIBUTES = "attributes";
439            }
440    
441    }