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    }