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.agenda; 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 Agenda 040 * immutable. 041 * Instances of Agenda can be (un)marshalled to and from XML. 042 * 043 * @see AgendaDefinitionContract 044 */ 045 @XmlRootElement(name = AgendaDefinition.Constants.ROOT_ELEMENT_NAME) 046 @XmlAccessorType(XmlAccessType.NONE) 047 @XmlType(name = AgendaDefinition.Constants.TYPE_NAME, propOrder = { 048 AgendaDefinition.Elements.AGENDA_ID, 049 AgendaDefinition.Elements.NAME, 050 AgendaDefinition.Elements.TYPE_ID, 051 AgendaDefinition.Elements.CONTEXT_ID, 052 AgendaDefinition.Elements.ACTIVE, 053 AgendaDefinition.Elements.FIRST_ITEM_ID, 054 AgendaDefinition.Elements.ATTRIBUTES, 055 CoreConstants.CommonElements.VERSION_NUMBER, 056 CoreConstants.CommonElements.FUTURE_ELEMENTS 057 }) 058 public final class AgendaDefinition extends AbstractDataTransferObject implements AgendaDefinitionContract { 059 private static final long serialVersionUID = 2783959459503209577L; 060 061 @XmlElement(name = Elements.AGENDA_ID, required = false) 062 private final String id; 063 064 @XmlElement(name = Elements.NAME, required = true) 065 private final String name; 066 067 @XmlElement(name = Elements.TYPE_ID, required = false) 068 private final String typeId; 069 070 @XmlElement(name = Elements.CONTEXT_ID, required = true) 071 private final String contextId; 072 073 @XmlElement(name = Elements.ACTIVE, required = false) 074 private final boolean active; 075 076 @XmlElement(name = Elements.FIRST_ITEM_ID, required = false) 077 private final String firstItemId; 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 * This constructor should never be called. 092 * It is only present for use during JAXB unmarshalling. 093 */ 094 private AgendaDefinition() { 095 this.id = null; 096 this.name = null; 097 this.typeId = null; 098 this.contextId = null; 099 this.active = true; 100 this.firstItemId = null; 101 this.attributes = null; 102 this.versionNumber = null; 103 } 104 105 /** 106 * Constructs a KRMS Repository Agenda object from the given builder. 107 * This constructor is private and should only ever be invoked from the builder. 108 * 109 * @param builder the Builder from which to construct the Agenda 110 */ 111 private AgendaDefinition(Builder builder) { 112 this.id = builder.getId(); 113 this.name = builder.getName(); 114 this.typeId = builder.getTypeId(); 115 this.contextId = builder.getContextId(); 116 this.active = builder.isActive(); 117 this.firstItemId = builder.getFirstItemId(); 118 if (builder.getAttributes() != null){ 119 this.attributes = Collections.unmodifiableMap(new HashMap<String, String>(builder.getAttributes())); 120 } else { 121 this.attributes = null; 122 } 123 this.versionNumber = builder.getVersionNumber(); 124 } 125 126 @Override 127 public String getId() { 128 return this.id; 129 } 130 131 @Override 132 public String getName() { 133 return this.name; 134 } 135 136 @Override 137 public String getTypeId() { 138 return this.typeId; 139 } 140 141 @Override 142 public String getContextId(){ 143 return this.contextId; 144 } 145 146 @Override 147 public boolean isActive() { 148 return this.active; 149 } 150 151 @Override 152 public String getFirstItemId(){ 153 return this.firstItemId; 154 } 155 156 /** 157 * Returns the internal list of custom/remote attributes associated with the 158 * agenda. 159 * 160 * @return the internal list of custom/remote attribute of the agenda. 161 */ 162 public Map<String, String> getAttributes() { 163 return this.attributes; 164 } 165 166 @Override 167 public Long getVersionNumber() { 168 return versionNumber; 169 } 170 171 /** 172 * This builder is used to construct instances of KRMS Repository Agenda. It enforces the constraints of the {@link AgendaDefinitionContract}. 173 */ 174 public static class Builder implements AgendaDefinitionContract, ModelBuilder, Serializable { 175 176 private static final long serialVersionUID = -8862851720709537839L; 177 178 private String id; 179 private String name; 180 private String typeId; 181 private String contextId; 182 private boolean active; 183 private String firstItemId; 184 private Map<String, String> attributes; 185 private Long versionNumber; 186 187 /** 188 * Private constructor for creating a builder with all of it's required attributes. 189 */ 190 private Builder(String id, String name, String typeId, String contextId) { 191 setId(id); 192 setName(name); 193 setTypeId(typeId); 194 setContextId(contextId); 195 setActive(true); 196 setAttributes(new HashMap<String, String>()); 197 } 198 199 /** 200 * Create a builder with the given parameters. 201 * 202 * @param id 203 * @param name 204 * @param typeId 205 * @param contextId 206 * @return Builder 207 */ 208 public static Builder create(String id, String name, String typeId, String contextId){ 209 return new Builder(id, name, typeId, contextId); 210 } 211 212 /** 213 * Creates a builder by populating it with data from the given {@link AgendaDefinitionContract}. 214 * 215 * @param contract the contract from which to populate this builder 216 * @return an instance of the builder populated with data from the contract 217 * @throws IllegalArgumentException if the contract is null 218 */ 219 public static Builder create(AgendaDefinitionContract contract) { 220 if (contract == null) { 221 throw new IllegalArgumentException("contract is null"); 222 } 223 Builder builder = new Builder(contract.getId(), contract.getName(), contract.getTypeId(), contract.getContextId()); 224 builder.setActive(contract.isActive()); 225 builder.setFirstItemId( contract.getFirstItemId() ); 226 if (contract.getAttributes() != null) { 227 builder.setAttributes(new HashMap<String, String>(contract.getAttributes())); 228 } 229 builder.setVersionNumber(contract.getVersionNumber()); 230 return builder; 231 } 232 233 /** 234 * Sets the value of the id on this builder to the given value. 235 * 236 * @param agendaId the agenda id value to set, may be null, must not be blank 237 * <p>The agenda id is generated by the system. For new agendas (not yet persisted) this field is null. 238 * For existing agendas this field is the generated id.</p> 239 * @throws IllegalArgumentException if the id is blank 240 */ 241 public void setId(String agendaId) { 242 if (agendaId != null && StringUtils.isBlank(agendaId)) { 243 throw new IllegalArgumentException("agenda ID must be null or non-blank"); 244 } 245 this.id = agendaId; 246 } 247 248 /** 249 * Set the value of the name on this builder to the given value. 250 * 251 * @param name the name of the agenda to set, must not be null or blank 252 * @throws IllegalArgumentException if the name is null or blank 253 */ 254 public void setName(String name) { 255 if (StringUtils.isBlank(name)) { 256 throw new IllegalArgumentException("name is blank"); 257 } 258 this.name = name; 259 } 260 261 /** 262 * Set the value of the type id on this builder to the given value. 263 * @param typeId the type id of the agenda to set 264 */ 265 public void setTypeId(String typeId) { 266 this.typeId = typeId; 267 } 268 269 /** 270 * Set the value of the context id on this builder to the given value. 271 * 272 * @param contextId the context id of the agenda to set, must not be null or blank 273 * @throws IllegalArgumentException if the name is null or blank 274 */ 275 public void setContextId(String contextId) { 276 if (StringUtils.isBlank(contextId)) { 277 throw new IllegalArgumentException("context id is blank"); 278 } 279 this.contextId = contextId; 280 } 281 282 /** 283 * Set the value of the active indicator on this builder to the given value. 284 * 285 * @param active the active indicator of the agenda to set 286 */ 287 public void setActive(boolean active) { 288 this.active = active; 289 } 290 291 /** 292 * Set the value of the first agenda item id on this builder to the given value. 293 * 294 * @param firstItemId the first agenda item of the agenda tree to set 295 */ 296 public void setFirstItemId(String firstItemId) { 297 this.firstItemId = firstItemId; 298 } 299 300 /** 301 * Set the value of the remote/custom attributes on this builder to the given value. 302 * 303 * @param attributes the remote/custom attributes of the agenda to set 304 */ 305 public void setAttributes(Map<String, String> attributes){ 306 if (attributes == null){ 307 this.attributes = Collections.emptyMap(); 308 } 309 this.attributes = Collections.unmodifiableMap(attributes); 310 } 311 312 /** 313 * Sets the version number on this builder to the given value. 314 * 315 * @param versionNumber the version number to set 316 */ 317 public void setVersionNumber(Long versionNumber){ 318 this.versionNumber = versionNumber; 319 } 320 321 @Override 322 public String getId() { 323 return id; 324 } 325 326 @Override 327 public String getName() { 328 return name; 329 } 330 331 @Override 332 public String getTypeId() { 333 return typeId; 334 } 335 336 @Override 337 public String getContextId() { 338 return contextId; 339 } 340 341 @Override 342 public boolean isActive() { 343 return active; 344 } 345 346 @Override 347 public String getFirstItemId() { 348 return firstItemId; 349 } 350 351 @Override 352 public Map<String, String> getAttributes() { 353 return attributes; 354 } 355 356 @Override 357 public Long getVersionNumber() { 358 return versionNumber; 359 } 360 361 /** 362 * Builds an instance of a Agenda based on the current state of the builder. 363 * 364 * @return the fully-constructed Agenda 365 */ 366 @Override 367 public AgendaDefinition build() { 368 return new AgendaDefinition(this); 369 } 370 371 } 372 373 /** 374 * Defines some constants used on this class. 375 */ 376 public static class Constants { 377 final static String ROOT_ELEMENT_NAME = "agenda"; 378 final static String TYPE_NAME = "AgendaType"; 379 final static String[] HASH_CODE_EQUALS_EXCLUDE = { "_futureElements" }; 380 public final static String EVENT = "Event"; // key for event attribute 381 } 382 383 /** 384 * A private class which exposes constants which define the XML element names to use 385 * when this object is marshalled to XML. 386 */ 387 public static class Elements { 388 final static String AGENDA_ID = "id"; 389 final static String NAME = "name"; 390 final static String TYPE_ID = "typeId"; 391 final static String CONTEXT_ID = "contextId"; 392 final static String ACTIVE = "active"; 393 final static String FIRST_ITEM_ID = "firstItemId"; 394 final static String ATTRIBUTES = "attributes"; 395 final static String ATTRIBUTE = "attribute"; 396 } 397 398 public static class Cache { 399 public static final String NAME = KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0 + "/" + AgendaDefinition.Constants.TYPE_NAME; 400 } 401 }