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