View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krms.api.repository.rule;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.CoreConstants;
20  import org.kuali.rice.core.api.mo.AbstractDataTransferObject;
21  import org.kuali.rice.core.api.mo.ModelBuilder;
22  import org.kuali.rice.core.api.util.jaxb.MapStringStringAdapter;
23  import org.kuali.rice.krms.api.KrmsConstants;
24  import org.kuali.rice.krms.api.repository.action.ActionDefinition;
25  import org.kuali.rice.krms.api.repository.action.ActionDefinitionContract;
26  import org.kuali.rice.krms.api.repository.proposition.PropositionDefinition;
27  
28  import javax.xml.bind.annotation.XmlAccessType;
29  import javax.xml.bind.annotation.XmlAccessorType;
30  import javax.xml.bind.annotation.XmlAnyElement;
31  import javax.xml.bind.annotation.XmlElement;
32  import javax.xml.bind.annotation.XmlElementWrapper;
33  import javax.xml.bind.annotation.XmlRootElement;
34  import javax.xml.bind.annotation.XmlTransient;
35  import javax.xml.bind.annotation.XmlType;
36  import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
37  import java.io.Serializable;
38  import java.util.ArrayList;
39  import java.util.Collection;
40  import java.util.Collections;
41  import java.util.HashMap;
42  import java.util.List;
43  import java.util.Map;
44  
45  /**
46   * Concrete model object implementation of KRMS Repository Rule 
47   * immutable. 
48   * Instances of Rule can be (un)marshalled to and from XML.
49   *
50   * @see RuleDefinitionContract
51   * @see org.kuali.rice.krms.framework.engine.Rule
52   */
53  @XmlRootElement(name = RuleDefinition.Constants.ROOT_ELEMENT_NAME)
54  @XmlAccessorType(XmlAccessType.NONE)
55  @XmlType(name = RuleDefinition.Constants.TYPE_NAME, propOrder = {
56  		RuleDefinition.Elements.ID,
57  		RuleDefinition.Elements.NAME,
58          RuleDefinition.Elements.NAMESPACE,
59          RuleDefinition.Elements.DESCRIPTION,
60  		RuleDefinition.Elements.TYPE_ID,
61          RuleDefinition.Elements.ACTIVE,
62  		RuleDefinition.Elements.PROPOSITION,
63  		RuleDefinition.Elements.ACTIONS,
64  		RuleDefinition.Elements.ATTRIBUTES,
65          CoreConstants.CommonElements.VERSION_NUMBER,
66  		CoreConstants.CommonElements.FUTURE_ELEMENTS
67  })
68  public final class RuleDefinition extends AbstractDataTransferObject implements RuleDefinitionContract {
69  	private static final long serialVersionUID = 2783959459503209577L;
70  
71  	@XmlElement(name = Elements.ID, required=true)
72  	private final String id;
73      @XmlElement(name = Elements.NAME, required=true)
74  	private final String name;
75  	@XmlElement(name = Elements.NAMESPACE, required=true)
76  	private final String namespace;
77      @XmlElement(name = Elements.DESCRIPTION, required=false)
78      private final String description;
79  	@XmlElement(name = Elements.TYPE_ID, required=true)
80  	private final String typeId;
81  	@XmlElement(name = Elements.PROPOSITION, required=true)
82  	private final PropositionDefinition proposition;
83      @XmlElement(name = Elements.ACTIVE, required = false)
84      private final boolean active;
85  
86  	@XmlElementWrapper(name = Elements.ACTIONS)
87  	@XmlElement(name = Elements.ACTION, required=false)
88  	private final List<ActionDefinition> actions;
89  	
90  	@XmlElement(name = Elements.ATTRIBUTES, required = false)
91  	@XmlJavaTypeAdapter(value = MapStringStringAdapter.class)
92  	private final Map<String, String> attributes;
93  	
94      @XmlElement(name = CoreConstants.CommonElements.VERSION_NUMBER, required = false)
95      private final Long versionNumber;
96      	
97  	@SuppressWarnings("unused")
98      @XmlAnyElement
99      private final Collection<org.w3c.dom.Element> _futureElements = null;
100 	
101 	@XmlTransient
102 	private String propId;
103 
104 	/** 
105      * This constructor should never be called.  
106      * It is only present for use during JAXB unmarshalling. 
107      */
108     private RuleDefinition() {
109     	this.id = null;
110     	this.name = null;
111     	this.namespace = null;
112         this.description = null;
113     	this.typeId = null;
114     	this.propId = null;
115         this.active = true;
116     	this.proposition = null;
117     	this.actions = null;
118     	this.attributes = null;
119         this.versionNumber = null;
120     }
121     
122     /**
123 	 * Constructs a KRMS Repository Rule object from the given builder.  
124 	 * This constructor is private and should only ever be invoked from the builder.
125 	 * 
126 	 * @param builder the Builder from which to construct the Rule
127 	 */
128     private RuleDefinition(Builder builder) {
129         this.id = builder.getId();
130         this.name = builder.getName();
131         this.namespace = builder.getNamespace();
132         this.typeId = builder.getTypeId();
133         this.propId = builder.getPropId();
134         this.description = builder.getDescription();
135         this.active = builder.isActive();
136 
137         if (builder.getProposition() != null) {
138             this.proposition = builder.getProposition().build();
139         } else {
140             this.proposition = null;
141         }
142         
143         List<ActionDefinition> actionList = new ArrayList<ActionDefinition> ();
144         if (builder.getActions() != null){
145         	for (ActionDefinition.Builder b : builder.actions){
146         		actionList.add(b.build());
147         	}
148             this.actions = Collections.unmodifiableList(actionList);
149         } else {
150             this.actions = Collections.emptyList();
151         }
152         if (builder.attributes != null){
153         	this.attributes = Collections.unmodifiableMap(builder.getAttributes());
154         } else {
155         	this.attributes = null;
156         }
157         this.versionNumber = builder.getVersionNumber();
158     }
159     
160 	@Override
161 	public String getId() {
162 		return this.id;
163 	}
164 
165 	@Override
166 	public String getName() {
167 		return this.name;
168 	}
169 
170     @Override
171     public String getDescription() {
172         return this.description;
173     }
174 
175     @Override
176 	public String getNamespace() {
177 		return this.namespace;
178 	}
179 
180 	@Override
181 	public String getTypeId() {
182 		return this.typeId;
183 	}
184 
185 	@Override
186 	public String getPropId(){
187 		return this.propId;
188 	}
189 
190     @Override
191     public boolean isActive() {
192         return this.active;
193     }
194 
195 	@Override
196 	public PropositionDefinition getProposition(){
197 		return this.proposition;
198 	}
199 	
200 	@Override
201 	public List<ActionDefinition> getActions(){
202 		return this.actions;
203 	}
204 
205     /**
206      * Returns the internal representation of the set of attributes associated with the
207      * Action.  The attributes are represented as name/value pairs.
208      *
209      * @return internal representation of the set of ActionAttribute objects.
210      */
211     @Override
212 	public Map<String, String> getAttributes() {
213 		return this.attributes;
214 	}
215 
216     @Override
217     public Long getVersionNumber() {
218         return versionNumber;
219     }
220         
221 	/**
222      * This builder is used to construct instances of KRMS Repository Rule.  It enforces the constraints of the {@link RuleDefinitionContract}.
223      */
224     public static class Builder implements RuleDefinitionContract, ModelBuilder, Serializable {		
225         private static final long serialVersionUID = -7850514191699945347L;
226         
227 		private String id;
228         private String name;
229         private String description;
230         private String namespace;
231         private String typeId;
232         private String propId;
233         private boolean active;
234         private PropositionDefinition.Builder proposition;
235         private List<ActionDefinition.Builder> actions;
236         private Map<String, String> attributes;
237         private Long versionNumber;
238 
239         /**
240          * Private constructor for creating a builder with all of it's required attributes.
241          * 
242          * @param ruleId the id value to set, must not be null or blank
243          * @param name the name value to set, must not be null or blank
244          * @param namespace the namespace value to set, must not be null or blank
245          * @param typeId the typeId value to set
246          * @param propId the propId value to set, must not be null or blank
247          */
248         private Builder(String ruleId, String name, String namespace, String typeId, String propId) {
249             setId(ruleId);
250             setName(name);
251             setNamespace(namespace);
252             setTypeId(typeId);
253             setPropId(propId);
254             setActive(true);
255             setAttributes(new HashMap<String, String>());
256         }
257 
258         /**
259          * Create a builder with the given parameters.
260          *
261          * @param ruleId the id value to set, must not be null or blank
262          * @param name the name value to set, must not be null or blank
263          * @param namespace the namespace value to set, must not be null or blank
264          * @param typeId the typeId value to set
265          * @param propId the propId value to set, must not be null or blank
266          * @return Builder with the given values set
267          */
268         public static Builder create(String ruleId, String name, String namespace, String typeId, String propId){
269         	return new Builder(ruleId, name, namespace, typeId, propId);
270         }
271         
272         /**
273          * Creates a builder by populating it with data from the given {@link RuleDefinitionContract}.
274          * 
275          * @param contract the contract from which to populate this builder
276          * @return an instance of the builder populated with data from the contract
277          */
278         public static Builder create(RuleDefinitionContract contract) {
279         	if (contract == null) {
280                 throw new IllegalArgumentException("contract is null");
281             }
282 
283         	List <ActionDefinition.Builder> actionList = new ArrayList<ActionDefinition.Builder>();
284         	if (contract.getActions() != null){
285         		for (ActionDefinitionContract actionContract : contract.getActions()){
286         			ActionDefinition.Builder actBuilder = ActionDefinition.Builder.create(actionContract);
287         			actionList.add(actBuilder);
288         		}
289         	}
290         	
291             Builder builder =  new Builder(contract.getId(), contract.getName(),
292             		contract.getNamespace(), contract.getTypeId(), contract.getPropId());
293             if (contract.getProposition() != null) {
294                 builder.setProposition(PropositionDefinition.Builder.create(contract.getProposition()));
295             }
296         	if (contract.getAttributes() != null){
297                 builder.setAttributes(new HashMap<String, String>(contract.getAttributes()));
298         	}
299             builder.setActions(actionList);
300             builder.setVersionNumber(contract.getVersionNumber());
301             builder.setDescription(contract.getDescription());
302             builder.setActive(contract.isActive());
303             return builder;
304         }
305 
306 		/**
307 		 * Sets the value of the id on this builder to the given value.
308 		 * 
309 		 * @param ruleId the id value to set, must not be null or blank
310 		 * @throws IllegalArgumentException if the id is null or blank
311 		 */
312 
313         public void setId(String ruleId) {
314             if (ruleId != null && StringUtils.isBlank(ruleId)) {
315                 throw new IllegalArgumentException("rule ID must be null or else non-blank");
316             }
317 			this.id = ruleId;
318 		}
319 
320         /**
321          * Sets the value of the name on this builder to the given value
322          * @param name the name value to set, must not be null or blank
323          * @throws IllegalArgumentException if the name is null or blank
324          */
325         public void setName(String name) {
326             if (StringUtils.isBlank(name)) {
327                 throw new IllegalArgumentException("name is blank");
328             }
329             this.name = name;
330         }
331 
332         /**
333          * Sets the value of the description on this builder to the given value
334          * @param description
335          */
336         public void setDescription(String description) {
337             this.description = description;
338         }
339 
340         /**
341          * Sets the value of the namespace on this builder to the given value
342          * @param namespace the namespace value to set, must not be null or blank
343          * @throws IllegalArgumentException if the namespace is null or blank
344          */
345         public void setNamespace(String namespace) {
346             if (StringUtils.isBlank(namespace)) {
347                 throw new IllegalArgumentException("namespace is blank");
348             }
349 			this.namespace = namespace;
350 		}
351 
352         /**
353          * Sets the value of the typeId on this builder to the given value
354          * @param typeId the typeId value to set
355          */
356 		public void setTypeId(String typeId) {
357 			this.typeId = typeId;
358 		}
359 
360         /**
361          * Sets the value of the active on this builder to the given value
362          * @param active the active value to set
363          */
364         public void setActive(boolean active) {
365             this.active = active;
366         }
367 
368         /**
369          * Sets the value of the propId on this builder to the given value
370          * @param propId the propId value to set, must not be null or blank
371          * @throws IllegalArgumentException if the propId is null or blank
372          */
373 		public void setPropId(String propId) {
374 		    if (propId != null && StringUtils.isBlank(propId)) {
375 		        throw new IllegalArgumentException("propId must be null or non-blank");
376 		    }
377 			this.propId = propId;
378 		}
379 
380         /**
381          * Sets the value of the proposition on this builder to the given value
382          * @param prop the proposition value to set, must not be null
383          */
384 		public void setProposition(PropositionDefinition.Builder prop) {
385 			this.proposition = prop;
386 			this.setPropId(prop.getId());
387 		}
388 
389         /**
390          * Sets the value of the actions on this builder to the given value
391          * @param actions the actions value to set, can be null
392          */
393 		public void setActions(List<ActionDefinition.Builder> actions) {
394 			if (actions == null){
395 				this.actions = Collections.unmodifiableList(new ArrayList<ActionDefinition.Builder>());
396 				return;
397 			}
398 			this.actions = Collections.unmodifiableList(actions);
399 		}
400 
401         /**
402          * Sets the value of the attributes on this builder to the given value
403          * @param attributes the attributes values to set, can be null
404          */
405 		public void setAttributes(Map<String, String> attributes){
406 			if (attributes == null){
407 				this.attributes = Collections.emptyMap();
408 			}
409 			this.attributes = Collections.unmodifiableMap(attributes);
410 		}
411 
412         /**
413          * Sets the value of the versionNumber on this builder to the given value
414          * @param versionNumber the versionNumber value to set
415          */
416         public void setVersionNumber(Long versionNumber){
417             this.versionNumber = versionNumber;
418         }
419         
420 		@Override
421 		public String getId() {
422 			return id;
423 		}
424 
425 		@Override
426 		public String getName() {
427 			return name;
428 		}
429 		
430 		@Override
431 		public String getDescription() {
432 		    return description;
433 		}
434 
435 		@Override
436 		public String getNamespace() {
437 			return namespace;
438 		}
439 
440 		@Override
441 		public String getTypeId() {
442 			return typeId;
443 		}
444 
445 		@Override
446 		public String getPropId() {
447 			return propId;
448 		}
449 
450         @Override
451         public boolean isActive() {
452             return active;
453         }
454 
455 		@Override
456 		public PropositionDefinition.Builder getProposition() {
457 			return proposition;
458 		}
459 
460 		@Override
461 		public List<ActionDefinition.Builder> getActions(){
462 			return actions;
463 		}
464 		@Override
465 		public Map<String, String> getAttributes() {
466 			return attributes;
467 		}
468 
469         @Override
470         public Long getVersionNumber() {
471             return versionNumber;
472         }
473 
474 		/**
475 		 * Builds an instance of a Rule based on the current state of the builder.
476 		 * 
477 		 * @return the fully-constructed Rule
478 		 */
479         @Override
480         public RuleDefinition build() {
481             return new RuleDefinition(this);
482         }
483 		
484     }
485 	
486 	/**
487 	 * Defines some internal constants used on this class.
488 	 */
489 	public static class Constants {
490 		final static String ROOT_ELEMENT_NAME = "rule";
491 		final static String TYPE_NAME = "RuleType";
492 	}
493 	
494 	/**
495 	 * A private class which exposes constants which define the XML element names to use
496 	 * when this object is marshalled to XML.
497 	 */
498 	public static class Elements {
499 		final static String ID = "id";
500         final static String NAME = "name";
501         final static String DESCRIPTION = "description";
502 		final static String NAMESPACE = "namespace";
503 		final static String TYPE_ID = "typeId";
504 		final static String PROPOSITION = "proposition";
505 		final static String ACTIONS = "actions";
506 		final static String ACTION = "action";
507         final static String ACTIVE = "active";
508 		final static String ATTRIBUTES = "attributes";
509 	}
510 
511     public static class Cache {
512         public static final String NAME = KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0 + "/" + RuleDefinition.Constants.TYPE_NAME;
513     }
514 }