001 package org.kuali.rice.krms.api.repository.agenda;
002
003 import java.io.Serializable;
004 import java.util.Collection;
005 import java.util.Collections;
006 import java.util.HashMap;
007 import java.util.Map;
008
009 import javax.xml.bind.annotation.XmlAccessType;
010 import javax.xml.bind.annotation.XmlAccessorType;
011 import javax.xml.bind.annotation.XmlAnyElement;
012 import javax.xml.bind.annotation.XmlElement;
013 import javax.xml.bind.annotation.XmlRootElement;
014 import javax.xml.bind.annotation.XmlType;
015 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
016
017 import org.apache.commons.lang.StringUtils;
018 import org.apache.commons.lang.builder.EqualsBuilder;
019 import org.apache.commons.lang.builder.HashCodeBuilder;
020 import org.apache.commons.lang.builder.ToStringBuilder;
021 import org.kuali.rice.core.api.CoreConstants;
022 import org.kuali.rice.core.api.mo.ModelBuilder;
023 import org.kuali.rice.core.api.mo.ModelObjectComplete;
024 import org.kuali.rice.core.util.jaxb.MapStringStringAdapter;
025 import org.kuali.rice.krms.api.repository.context.ContextDefinitionContract;
026 import org.kuali.rice.krms.api.repository.context.ContextDefinition.Builder;
027
028 /**
029 * Concrete model object implementation of KRMS Repository Agenda
030 * immutable.
031 * Instances of Agenda can be (un)marshalled to and from XML.
032 *
033 * @see AgendaDefinitionContract
034 */
035 @XmlRootElement(name = AgendaDefinition.Constants.ROOT_ELEMENT_NAME)
036 @XmlAccessorType(XmlAccessType.NONE)
037 @XmlType(name = AgendaDefinition.Constants.TYPE_NAME, propOrder = {
038 AgendaDefinition.Elements.AGENDA_ID,
039 AgendaDefinition.Elements.NAME,
040 AgendaDefinition.Elements.NAMESPACE_CODE,
041 AgendaDefinition.Elements.TYPE_ID,
042 AgendaDefinition.Elements.CONTEXT_ID,
043 AgendaDefinition.Elements.FIRST_ITEM_ID,
044 AgendaDefinition.Elements.ATTRIBUTES,
045 CoreConstants.CommonElements.VERSION_NUMBER,
046 CoreConstants.CommonElements.FUTURE_ELEMENTS
047 })
048 public final class AgendaDefinition implements AgendaDefinitionContract, ModelObjectComplete{
049 private static final long serialVersionUID = 2783959459503209577L;
050
051 @XmlElement(name = Elements.AGENDA_ID, required = false)
052 private final String id;
053
054 @XmlElement(name = Elements.NAME, required = true)
055 private final String name;
056
057 @XmlElement(name = Elements.NAMESPACE_CODE, required = true)
058 private final String namespaceCode;
059
060 @XmlElement(name = Elements.TYPE_ID, required = false)
061 private final String typeId;
062
063 @XmlElement(name = Elements.CONTEXT_ID, required = true)
064 private final String contextId;
065
066 @XmlElement(name = Elements.FIRST_ITEM_ID, required = false)
067 private final String firstItemId;
068
069 @XmlElement(name = Elements.ATTRIBUTES, required = false)
070 @XmlJavaTypeAdapter(value = MapStringStringAdapter.class)
071 private final Map<String, String> attributes;
072
073 @XmlElement(name = CoreConstants.CommonElements.VERSION_NUMBER, required = false)
074 private final Long versionNumber;
075
076 @SuppressWarnings("unused")
077 @XmlAnyElement
078 private final Collection<org.w3c.dom.Element> _futureElements = null;
079
080 /**
081 * This constructor should never be called.
082 * It is only present for use during JAXB unmarshalling.
083 */
084 private AgendaDefinition() {
085 this.id = null;
086 this.name = null;
087 this.namespaceCode = null;
088 this.typeId = null;
089 this.contextId = null;
090 this.firstItemId = null;
091 this.attributes = null;
092 this.versionNumber = null;
093 }
094
095 /**
096 * Constructs a KRMS Repository Agenda object from the given builder.
097 * This constructor is private and should only ever be invoked from the builder.
098 *
099 * @param builder the Builder from which to construct the Agenda
100 */
101 private AgendaDefinition(Builder builder) {
102 this.id = builder.getId();
103 this.name = builder.getName();
104 this.namespaceCode = builder.getNamespaceCode();
105 this.typeId = builder.getTypeId();
106 this.contextId = builder.getContextId();
107 this.firstItemId = builder.getFirstItemId();
108 if (builder.getAttributes() != null){
109 this.attributes = Collections.unmodifiableMap(new HashMap<String, String>(builder.getAttributes()));
110 } else {
111 this.attributes = null;
112 }
113 this.versionNumber = builder.getVersionNumber();
114 }
115
116 @Override
117 public String getId() {
118 return this.id;
119 }
120
121 @Override
122 public String getName() {
123 return this.name;
124 }
125
126 @Override
127 public String getNamespaceCode() {
128 return this.namespaceCode;
129 }
130
131 @Override
132 public String getTypeId() {
133 return this.typeId;
134 }
135
136 @Override
137 public String getContextId(){
138 return this.contextId;
139 }
140
141 @Override
142 public String getFirstItemId(){
143 return this.firstItemId;
144 }
145
146 @Override
147 public Map<String, String> getAttributes() {
148 return this.attributes;
149 }
150
151 @Override
152 public Long getVersionNumber() {
153 return versionNumber;
154 }
155
156 /**
157 * This builder is used to construct instances of KRMS Repository Agenda. It enforces the constraints of the {@link AgendaDefinitionContract}.
158 */
159 public static class Builder implements AgendaDefinitionContract, ModelBuilder, Serializable {
160
161 private static final long serialVersionUID = -8862851720709537839L;
162
163 private String id;
164 private String name;
165 private String namespaceCode;
166 private String typeId;
167 private String contextId;
168 private String firstItemId;
169 private Map<String, String> attributes;
170 private Long versionNumber;
171
172 /**
173 * Private constructor for creating a builder with all of it's required attributes.
174 */
175 private Builder(String id, String name, String namespaceCode, String typeId, String contextId) {
176 setId(id);
177 setName(name);
178 setNamespaceCode(namespaceCode);
179 setTypeId(typeId);
180 setContextId(contextId);
181 setAttributes(new HashMap<String, String>());
182 }
183
184 public static Builder create(String id, String name, String namespaceCode, String typeId, String contextId){
185 return new Builder(id, name, namespaceCode, typeId, contextId);
186 }
187 /**
188 * Creates a builder by populating it with data from the given {@link AgendaDefinitionContract}.
189 *
190 * @param contract the contract from which to populate this builder
191 * @return an instance of the builder populated with data from the contract
192 */
193 public static Builder create(AgendaDefinitionContract contract) {
194 if (contract == null) {
195 throw new IllegalArgumentException("contract is null");
196 }
197 Builder builder = new Builder(contract.getId(), contract.getName(),
198 contract.getNamespaceCode(), contract.getTypeId(), contract.getContextId());
199 builder.setFirstItemId( contract.getFirstItemId() );
200 if (contract.getAttributes() != null) {
201 builder.setAttributes(new HashMap<String, String>(contract.getAttributes()));
202 }
203 builder.setVersionNumber(contract.getVersionNumber());
204 return builder;
205 }
206
207 /**
208 * Sets the value of the id on this builder to the given value.
209 *
210 * @param id the id value to set, must not be null or blank
211 * @throws IllegalArgumentException if the id is null or blank
212 */
213
214 public void setId(String agendaId) {
215 if (agendaId != null && StringUtils.isBlank(agendaId)) {
216 throw new IllegalArgumentException("agenda ID must be null or non-blank");
217 }
218 this.id = agendaId;
219 }
220
221 public void setName(String name) {
222 if (StringUtils.isBlank(name)) {
223 throw new IllegalArgumentException("name is blank");
224 }
225 this.name = name;
226 }
227
228 public void setNamespaceCode(String namespaceCode) {
229 if (StringUtils.isBlank(namespaceCode)) {
230 throw new IllegalArgumentException("namespace is blank");
231 }
232 this.namespaceCode = namespaceCode;
233 }
234
235 public void setTypeId(String typeId) {
236 if (StringUtils.isBlank(typeId)) {
237 throw new IllegalArgumentException("KRMS type id is blank");
238 }
239 this.typeId = typeId;
240 }
241
242 public void setContextId(String contextId) {
243 if (StringUtils.isBlank(contextId)) {
244 throw new IllegalArgumentException("context id is blank");
245 }
246 this.contextId = contextId;
247 }
248
249
250 public void setFirstItemId(String firstItemId) {
251 this.firstItemId = firstItemId;
252 }
253
254 public void setAttributes(Map<String, String> attributes){
255 if (attributes == null){
256 this.attributes = Collections.emptyMap();
257 }
258 this.attributes = Collections.unmodifiableMap(attributes);
259 }
260
261 /**
262 * Sets the version number for the style that will be returned by this
263 * builder.
264 *
265 * <p>In general, this value should not be manually set on the builder,
266 * but rather copied from an existing {@link ContextDefinitionContract} when
267 * invoking {@link Builder#create(ContextDefinitionContract)}.
268 *
269 * @param versionNumber the version number to set
270 */
271 public void setVersionNumber(Long versionNumber){
272 this.versionNumber = versionNumber;
273 }
274
275 @Override
276 public String getId() {
277 return id;
278 }
279
280 @Override
281 public String getName() {
282 return name;
283 }
284
285 @Override
286 public String getNamespaceCode() {
287 return namespaceCode;
288 }
289
290 @Override
291 public String getTypeId() {
292 return typeId;
293 }
294
295 @Override
296 public String getContextId() {
297 return contextId;
298 }
299
300 @Override
301 public String getFirstItemId() {
302 return firstItemId;
303 }
304
305 @Override
306 public Map<String, String> getAttributes() {
307 return attributes;
308 }
309
310 @Override
311 public Long getVersionNumber() {
312 return versionNumber;
313 }
314
315 /**
316 * Builds an instance of a Agenda based on the current state of the builder.
317 *
318 * @return the fully-constructed Agenda
319 */
320 @Override
321 public AgendaDefinition build() {
322 return new AgendaDefinition(this);
323 }
324
325 }
326 @Override
327 public int hashCode() {
328 return HashCodeBuilder.reflectionHashCode(this, Constants.HASH_CODE_EQUALS_EXCLUDE);
329 }
330
331 @Override
332 public boolean equals(Object obj) {
333 return EqualsBuilder.reflectionEquals(obj, this, Constants.HASH_CODE_EQUALS_EXCLUDE);
334 }
335
336 @Override
337 public String toString() {
338 return ToStringBuilder.reflectionToString(this);
339 }
340
341 /**
342 * Defines some constants used on this class.
343 */
344 public static class Constants {
345 final static String ROOT_ELEMENT_NAME = "agenda";
346 final static String TYPE_NAME = "AgendaType";
347 final static String[] HASH_CODE_EQUALS_EXCLUDE = { "_furutreElements" };
348 public final static String EVENT = "Event"; // key for event attribute
349 }
350
351 /**
352 * A private class which exposes constants which define the XML element names to use
353 * when this object is marshalled to XML.
354 */
355 public static class Elements {
356 final static String AGENDA_ID = "id";
357 final static String NAME = "name";
358 final static String NAMESPACE_CODE = "namespaceCode";
359 final static String TYPE_ID = "typeId";
360 final static String CONTEXT_ID = "contextId";
361 final static String FIRST_ITEM_ID = "firstItemId";
362 final static String ATTRIBUTES = "attributes";
363 final static String ATTRIBUTE = "attribute";
364 }
365
366 }