001 /**
002 * Copyright 2005-2014 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 } else {
309 this.attributes = Collections.unmodifiableMap(attributes);
310 }
311 }
312
313 /**
314 * Sets the version number on this builder to the given value.
315 *
316 * @param versionNumber the version number to set
317 */
318 public void setVersionNumber(Long versionNumber){
319 this.versionNumber = versionNumber;
320 }
321
322 @Override
323 public String getId() {
324 return id;
325 }
326
327 @Override
328 public String getName() {
329 return name;
330 }
331
332 @Override
333 public String getTypeId() {
334 return typeId;
335 }
336
337 @Override
338 public String getContextId() {
339 return contextId;
340 }
341
342 @Override
343 public boolean isActive() {
344 return active;
345 }
346
347 @Override
348 public String getFirstItemId() {
349 return firstItemId;
350 }
351
352 @Override
353 public Map<String, String> getAttributes() {
354 return attributes;
355 }
356
357 @Override
358 public Long getVersionNumber() {
359 return versionNumber;
360 }
361
362 /**
363 * Builds an instance of a Agenda based on the current state of the builder.
364 *
365 * @return the fully-constructed Agenda
366 */
367 @Override
368 public AgendaDefinition build() {
369 return new AgendaDefinition(this);
370 }
371
372 }
373
374 /**
375 * Defines some constants used on this class.
376 */
377 public static class Constants {
378 final static String ROOT_ELEMENT_NAME = "agenda";
379 final static String TYPE_NAME = "AgendaType";
380 final static String[] HASH_CODE_EQUALS_EXCLUDE = { "_futureElements" };
381 public final static String EVENT = "Event"; // key for event attribute
382 }
383
384 /**
385 * A private class which exposes constants which define the XML element names to use
386 * when this object is marshalled to XML.
387 */
388 public static class Elements {
389 public final static String AGENDA_ID = "id";
390 final static String NAME = "name";
391 final static String TYPE_ID = "typeId";
392 final static String CONTEXT_ID = "contextId";
393 final static String ACTIVE = "active";
394 final static String FIRST_ITEM_ID = "firstItemId";
395 final static String ATTRIBUTES = "attributes";
396 final static String ATTRIBUTE = "attribute";
397 }
398
399 public static class Cache {
400 public static final String NAME = KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0 + "/" + AgendaDefinition.Constants.TYPE_NAME;
401 }
402 }