View Javadoc

1   package org.kuali.rice.krms.api.repository.rule;
2   
3   import java.io.Serializable;
4   import java.util.ArrayList;
5   import java.util.Collection;
6   import java.util.Collections;
7   import java.util.HashMap;
8   import java.util.List;
9   import java.util.Map;
10  
11  import javax.xml.bind.annotation.XmlAccessType;
12  import javax.xml.bind.annotation.XmlAccessorType;
13  import javax.xml.bind.annotation.XmlAnyElement;
14  import javax.xml.bind.annotation.XmlElement;
15  import javax.xml.bind.annotation.XmlElementWrapper;
16  import javax.xml.bind.annotation.XmlRootElement;
17  import javax.xml.bind.annotation.XmlTransient;
18  import javax.xml.bind.annotation.XmlType;
19  import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
20  
21  import org.apache.commons.lang.StringUtils;
22  import org.apache.commons.lang.builder.EqualsBuilder;
23  import org.apache.commons.lang.builder.HashCodeBuilder;
24  import org.apache.commons.lang.builder.ToStringBuilder;
25  import org.kuali.rice.core.api.CoreConstants;
26  import org.kuali.rice.core.api.mo.ModelBuilder;
27  import org.kuali.rice.core.api.mo.ModelObjectComplete;
28  import org.kuali.rice.core.util.jaxb.MapStringStringAdapter;
29  import org.kuali.rice.krms.api.repository.action.ActionDefinition;
30  import org.kuali.rice.krms.api.repository.action.ActionDefinitionContract;
31  import org.kuali.rice.krms.api.repository.proposition.PropositionDefinition;
32  
33  /**
34   * Concrete model object implementation of KRMS Repository Rule 
35   * immutable. 
36   * Instances of Rule can be (un)marshalled to and from XML.
37   *
38   * @see RuleDefinitionContract
39   */
40  @XmlRootElement(name = RuleDefinition.Constants.ROOT_ELEMENT_NAME)
41  @XmlAccessorType(XmlAccessType.NONE)
42  @XmlType(name = RuleDefinition.Constants.TYPE_NAME, propOrder = {
43  		RuleDefinition.Elements.ID,
44  		RuleDefinition.Elements.NAME,
45          RuleDefinition.Elements.NAMESPACE,
46          RuleDefinition.Elements.DESCRIPTION,
47  		RuleDefinition.Elements.TYPE_ID,
48  		RuleDefinition.Elements.PROPOSITION,
49  		RuleDefinition.Elements.ACTIONS,
50  		RuleDefinition.Elements.ATTRIBUTES,
51          CoreConstants.CommonElements.VERSION_NUMBER,
52  		CoreConstants.CommonElements.FUTURE_ELEMENTS
53  })
54  public final class RuleDefinition implements RuleDefinitionContract, ModelObjectComplete{
55  	private static final long serialVersionUID = 2783959459503209577L;
56  
57  	@XmlElement(name = Elements.ID, required=true)
58  	private String id;
59      @XmlElement(name = Elements.NAME, required=true)
60  	private String name;
61  	@XmlElement(name = Elements.NAMESPACE, required=true)
62  	private String namespace;
63      @XmlElement(name = Elements.DESCRIPTION, required=false)
64      private String description;
65  	@XmlElement(name = Elements.TYPE_ID, required=true)
66  	private String typeId;
67  	@XmlElement(name = Elements.PROPOSITION, required=true)
68  	private PropositionDefinition proposition;
69  	
70  	@XmlElementWrapper(name = Elements.ACTIONS)
71  	@XmlElement(name = Elements.ACTION, required=false)
72  	private List<ActionDefinition> actions;
73  	
74  	@XmlElement(name = Elements.ATTRIBUTES, required = false)
75  	@XmlJavaTypeAdapter(value = MapStringStringAdapter.class)
76  	private final Map<String, String> attributes;
77  	
78      @XmlElement(name = CoreConstants.CommonElements.VERSION_NUMBER, required = false)
79      private final Long versionNumber;
80      	
81  	@SuppressWarnings("unused")
82      @XmlAnyElement
83      private final Collection<org.w3c.dom.Element> _futureElements = null;
84  	
85  	@XmlTransient
86  	private String propId;
87  
88  	/** 
89       * This constructor should never be called.  
90       * It is only present for use during JAXB unmarshalling. 
91       */
92      private RuleDefinition() {
93      	this.id = null;
94      	this.name = null;
95      	this.namespace = null;
96      	this.typeId = null;
97      	this.propId = null;
98      	this.proposition = null;
99      	this.actions = null;
100     	this.attributes = null;
101         this.versionNumber = null;
102     }
103     
104     /**
105 	 * Constructs a KRMS Repository Rule object from the given builder.  
106 	 * This constructor is private and should only ever be invoked from the builder.
107 	 * 
108 	 * @param builder the Builder from which to construct the Rule
109 	 */
110     private RuleDefinition(Builder builder) {
111         this.id = builder.getId();
112         this.name = builder.getName();
113         this.namespace = builder.getNamespace();
114         this.typeId = builder.getTypeId();
115         this.propId = builder.getPropId();
116         
117         if (builder.getProposition() != null) {
118             this.proposition = builder.getProposition().build();
119         }
120         
121         List<ActionDefinition> actionList = new ArrayList<ActionDefinition> ();
122         if (builder.getActions() != null){
123         	for (ActionDefinition.Builder b : builder.actions){
124         		actionList.add(b.build());
125         	}
126             this.actions = Collections.unmodifiableList(actionList);
127         }
128         if (builder.attributes != null){
129         	this.attributes = Collections.unmodifiableMap(builder.getAttributes());
130         } else {
131         	this.attributes = null;
132         }
133         this.versionNumber = builder.getVersionNumber();
134     }
135     
136 	@Override
137 	public String getId() {
138 		return this.id;
139 	}
140 
141 	@Override
142 	public String getName() {
143 		return this.name;
144 	}
145 
146     public String getDescription() {
147         return this.description;
148     }
149 
150     @Override
151 	public String getNamespace() {
152 		return this.namespace;
153 	}
154 
155 	@Override
156 	public String getTypeId() {
157 		return this.typeId;
158 	}
159 
160 	@Override
161 	public String getPropId(){
162 		return this.propId;
163 	}
164 
165 	@Override
166 	public PropositionDefinition getProposition(){
167 		return this.proposition;
168 	}
169 	
170 	@Override
171 	public List<ActionDefinition> getActions(){
172 		return this.actions;
173 	}
174 		
175 	@Override
176 	public Map<String, String> getAttributes() {
177 		return this.attributes; 
178 	}
179 
180     @Override
181     public Long getVersionNumber() {
182         return versionNumber;
183     }
184         
185 	/**
186      * This builder is used to construct instances of KRMS Repository Rule.  It enforces the constraints of the {@link RuleDefinitionContract}.
187      */
188     public static class Builder implements RuleDefinitionContract, ModelBuilder, Serializable {		
189         private static final long serialVersionUID = -7850514191699945347L;
190         
191 		private String id;
192         private String name;
193         private String description;
194         private String namespace;
195         private String typeId;
196         private String propId;
197         private PropositionDefinition.Builder proposition;
198         private List<ActionDefinition.Builder> actions;
199         private Map<String, String> attributes;
200         private Long versionNumber;
201 
202 		/**
203 		 * Private constructor for creating a builder with all of it's required attributes.
204 		 */
205         private Builder(String ruleId, String name, String namespace, String typeId, String propId) {
206             setId(ruleId);
207             setName(name);
208             setNamespace(namespace);
209             setTypeId(typeId);
210             setPropId(propId);
211             setAttributes(new HashMap<String, String>());
212         }
213         
214         public static Builder create(String ruleId, String name, String namespace, String typeId, String propId){
215         	return new Builder(ruleId, name, namespace, typeId, propId);
216         }
217         
218         /**
219          * Creates a builder by populating it with data from the given {@link RuleDefinitionContract}.
220          * 
221          * @param contract the contract from which to populate this builder
222          * @return an instance of the builder populated with data from the contract
223          */
224         public static Builder create(RuleDefinitionContract contract) {
225         	if (contract == null) {
226                 throw new IllegalArgumentException("contract is null");
227             }
228 
229         	List <ActionDefinition.Builder> actionList = new ArrayList<ActionDefinition.Builder>();
230         	if (contract.getActions() != null){
231         		for (ActionDefinitionContract actionContract : contract.getActions()){
232         			ActionDefinition.Builder actBuilder = ActionDefinition.Builder.create(actionContract);
233         			actionList.add(actBuilder);
234         		}
235         	}
236         	
237             Builder builder =  new Builder(contract.getId(), contract.getName(),
238             		contract.getNamespace(), contract.getTypeId(), contract.getPropId());
239             if (contract.getProposition() != null) {
240                 builder.setProposition(PropositionDefinition.Builder.create(contract.getProposition()));
241             }
242         	if (contract.getAttributes() != null){
243                 builder.setAttributes(new HashMap<String, String>(contract.getAttributes()));
244         	}
245             builder.setActions(actionList);
246             builder.setVersionNumber(contract.getVersionNumber());
247             builder.setDescription(contract.getDescription());
248             return builder;
249         }
250 
251 		/**
252 		 * Sets the value of the id on this builder to the given value.
253 		 * 
254 		 * @param id the id value to set, must not be null or blank
255 		 * @throws IllegalArgumentException if the id is null or blank
256 		 */
257 
258         public void setId(String ruleId) {
259             if (ruleId != null && StringUtils.isBlank(ruleId)) {
260                 throw new IllegalArgumentException("rule ID must be null or else non-blank");
261             }
262 			this.id = ruleId;
263 		}
264      
265         public void setName(String name) {
266             if (StringUtils.isBlank(name)) {
267                 throw new IllegalArgumentException("name is blank");
268             }
269             this.name = name;
270         }
271      
272         public void setDescription(String description) {
273             if (description != null && StringUtils.isBlank(description)) {
274                 throw new IllegalArgumentException("description is non-null but is blank");
275             }
276             this.description = description;
277         }
278      
279         public void setNamespace(String namespace) {
280             if (StringUtils.isBlank(namespace)) {
281                 throw new IllegalArgumentException("namespace is blank");
282             }
283 			this.namespace = namespace;
284 		}
285      
286 		public void setTypeId(String typeId) {
287 			if (StringUtils.isBlank(typeId)) {
288 	                throw new IllegalArgumentException("KRMS type id is blank");
289 			}
290 			this.typeId = typeId;
291 		}
292 		
293 		public void setPropId(String propId) {
294 		    if (propId != null && StringUtils.isBlank(propId)) {
295 		        throw new IllegalArgumentException("propId must be null or non-blank");
296 		    }
297 			this.propId = propId;
298 		}
299 		
300 		public void setProposition(PropositionDefinition.Builder prop) {
301 			this.proposition = prop;
302 			this.setPropId(prop.getId());
303 		}
304 		
305 		public void setActions(List<ActionDefinition.Builder> actions) {
306 			if (actions == null){
307 				this.actions = Collections.unmodifiableList(new ArrayList<ActionDefinition.Builder>());
308 				return;
309 			}
310 			this.actions = Collections.unmodifiableList(actions);
311 		}
312 		
313 		public void setAttributes(Map<String, String> attributes){
314 			if (attributes == null){
315 				this.attributes = Collections.emptyMap();
316 			}
317 			this.attributes = Collections.unmodifiableMap(attributes);
318 		}
319 		
320         public void setVersionNumber(Long versionNumber){
321             this.versionNumber = versionNumber;
322         }
323         
324 		@Override
325 		public String getId() {
326 			return id;
327 		}
328 
329 		@Override
330 		public String getName() {
331 			return name;
332 		}
333 		
334 		@Override
335 		public String getDescription() {
336 		    return description;
337 		}
338 
339 		@Override
340 		public String getNamespace() {
341 			return namespace;
342 		}
343 
344 		@Override
345 		public String getTypeId() {
346 			return typeId;
347 		}
348 
349 		@Override
350 		public String getPropId() {
351 			return propId;
352 		}
353 
354 		@Override
355 		public PropositionDefinition.Builder getProposition() {
356 			return proposition;
357 		}
358 
359 		@Override
360 		public List<ActionDefinition.Builder> getActions(){
361 			return actions;
362 		}
363 		@Override
364 		public Map<String, String> getAttributes() {
365 			return attributes;
366 		}
367 
368         @Override
369         public Long getVersionNumber() {
370             return versionNumber;
371         }
372 
373 		/**
374 		 * Builds an instance of a Rule based on the current state of the builder.
375 		 * 
376 		 * @return the fully-constructed Rule
377 		 */
378         @Override
379         public RuleDefinition build() {
380             return new RuleDefinition(this);
381         }
382 		
383     }
384 	@Override
385 	public int hashCode() {
386 		return HashCodeBuilder.reflectionHashCode(this, Constants.HASH_CODE_EQUALS_EXCLUDE);
387 	}
388 
389 	@Override
390 	public boolean equals(Object obj) {
391 		return EqualsBuilder.reflectionEquals(obj, this, Constants.HASH_CODE_EQUALS_EXCLUDE);
392 	}
393 
394 	@Override
395 	public String toString() {
396 		return ToStringBuilder.reflectionToString(this);
397 	}
398 	
399 	/**
400 	 * Defines some internal constants used on this class.
401 	 */
402 	public static class Constants {
403 		final static String ROOT_ELEMENT_NAME = "rule";
404 		final static String TYPE_NAME = "RuleType";
405 		final static String[] HASH_CODE_EQUALS_EXCLUDE = { CoreConstants.CommonElements.FUTURE_ELEMENTS };
406 	}
407 	
408 	/**
409 	 * A private class which exposes constants which define the XML element names to use
410 	 * when this object is marshalled to XML.
411 	 */
412 	public static class Elements {
413 		final static String ID = "id";
414         final static String NAME = "name";
415         final static String DESCRIPTION = "description";
416 		final static String NAMESPACE = "namespace";
417 		final static String TYPE_ID = "typeId";
418 		final static String PROPOSITION = "proposition";
419 		final static String ACTIONS = "actions";
420 		final static String ACTION = "action";
421 		final static String ATTRIBUTES = "attributes";
422 	}
423 
424 }