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 */ 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 import org.kuali.rice.krms.api.KrmsConstants; 024 025 import javax.xml.bind.annotation.XmlAccessType; 026 import javax.xml.bind.annotation.XmlAccessorType; 027 import javax.xml.bind.annotation.XmlAnyElement; 028 import javax.xml.bind.annotation.XmlElement; 029 import javax.xml.bind.annotation.XmlRootElement; 030 import javax.xml.bind.annotation.XmlType; 031 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 032 import java.io.Serializable; 033 import java.util.Collection; 034 import java.util.Collections; 035 import java.util.HashMap; 036 import 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 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 }) 062 public 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 if (StringUtils.isBlank(ruleId)) { 323 throw new IllegalArgumentException("rule id is blank"); 324 } 325 this.ruleId = ruleId; 326 } 327 328 /** 329 * Sets the value of the sequenceNumber on this builder to the given value. 330 * 331 * @param sequenceNumber the sequenceNumber value to set, must not be null or blank 332 * @throws IllegalArgumentException if the sequenceNumber is null or blank 333 */ 334 public void setSequenceNumber(Integer sequenceNumber) { 335 if (sequenceNumber == null) { 336 throw new IllegalArgumentException("sequence number is null"); 337 } 338 this.sequenceNumber = sequenceNumber; 339 } 340 341 /** 342 * Sets the value of the attributes on this builder to the given value. 343 * 344 * @param attributes the attributes value to set, can be null 345 */ 346 public void setAttributes(Map<String, String> attributes){ 347 if (attributes == null){ 348 this.attributes = Collections.emptyMap(); 349 } 350 this.attributes = Collections.unmodifiableMap(attributes); 351 } 352 353 /** 354 * Sets the value of the versionNumber on this builder to the given value. 355 * 356 * @param versionNumber the versionNumber value to set 357 */ 358 public void setVersionNumber(Long versionNumber){ 359 this.versionNumber = versionNumber; 360 } 361 362 @Override 363 public String getId() { 364 return id; 365 } 366 367 @Override 368 public String getName() { 369 return name; 370 } 371 372 @Override 373 public String getNamespace() { 374 return namespace; 375 } 376 377 @Override 378 public String getDescription() { 379 return description; 380 } 381 382 @Override 383 public String getTypeId() { 384 return typeId; 385 } 386 387 @Override 388 public String getRuleId() { 389 return ruleId; 390 } 391 392 @Override 393 public Integer getSequenceNumber() { 394 return sequenceNumber; 395 } 396 397 @Override 398 public Map<String, String> getAttributes() { 399 return attributes; 400 } 401 402 @Override 403 public Long getVersionNumber() { 404 return versionNumber; 405 } 406 407 /** 408 * Builds an instance of a Action based on the current state of the builder. 409 * 410 * @return the fully-constructed Action 411 */ 412 @Override 413 public ActionDefinition build() { 414 return new ActionDefinition(this); 415 } 416 417 } 418 419 /** 420 * Defines some internal constants used on this class. 421 */ 422 static class Constants { 423 final static String ROOT_ELEMENT_NAME = "action"; 424 final static String TYPE_NAME = "ActionType"; 425 } 426 427 /** 428 * A private class which exposes constants which define the XML element names to use 429 * when this object is marshalled to XML. 430 */ 431 public static class Elements { 432 final static String ID = "id"; 433 final static String NAME = "name"; 434 final static String NAMESPACE = "namespace"; 435 final static String DESC = "description"; 436 final static String TYPE_ID = "typeId"; 437 final static String RULE_ID = "ruleId"; 438 final static String SEQUENCE_NUMBER = "sequenceNumber"; 439 final static String ATTRIBUTES = "attributes"; 440 } 441 442 public static class Cache { 443 public static final String NAME = KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0 + "/" + ActionDefinition.Constants.TYPE_NAME; 444 } 445 446 }