View Javadoc

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