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