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