001    /**
002     * Copyright 2005-2011 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.repository.context.ContextDefinitionContract;
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 = false;
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            @Override
157            public Map<String, String> getAttributes() {
158                    return this.attributes; 
159            }
160    
161        @Override
162        public Long getVersionNumber() {
163            return versionNumber;
164        }
165        
166            /**
167         * This builder is used to construct instances of KRMS Repository Agenda.  It enforces the constraints of the {@link AgendaDefinitionContract}.
168         */
169        public static class Builder implements AgendaDefinitionContract, ModelBuilder, Serializable {
170                    
171            private static final long serialVersionUID = -8862851720709537839L;
172            
173                    private String id;
174            private String name;
175            private String typeId;
176            private String contextId;
177            private boolean active;
178            private String firstItemId;
179            private Map<String, String> attributes;
180            private Long versionNumber;
181    
182                    /**
183                     * Private constructor for creating a builder with all of it's required attributes.
184                     */
185            private Builder(String id, String name, String typeId, String contextId) {
186                    setId(id);
187                setName(name);
188                setTypeId(typeId);
189                setContextId(contextId);
190                setActive(true);
191                setAttributes(new HashMap<String, String>());
192            }
193            
194            public static Builder create(String id, String name, String typeId, String contextId){
195                    return new Builder(id, name, typeId, contextId);
196            }
197            /**
198             * Creates a builder by populating it with data from the given {@link AgendaDefinitionContract}.
199             * 
200             * @param contract the contract from which to populate this builder
201             * @return an instance of the builder populated with data from the contract
202             */
203            public static Builder create(AgendaDefinitionContract contract) {
204                    if (contract == null) {
205                    throw new IllegalArgumentException("contract is null");
206                }
207                Builder builder =  new Builder(contract.getId(), contract.getName(), contract.getTypeId(), contract.getContextId());
208                builder.setActive(contract.isActive());
209                builder.setFirstItemId( contract.getFirstItemId() );
210                if (contract.getAttributes() != null) {
211                    builder.setAttributes(new HashMap<String, String>(contract.getAttributes()));
212                }
213                builder.setVersionNumber(contract.getVersionNumber());
214                return builder;
215            }
216    
217                    /**
218                     * Sets the value of the id on this builder to the given value.
219                     * 
220                     * @param id the id value to set, must not be null or blank
221                     * @throws IllegalArgumentException if the id is null or blank
222                     */
223    
224            public void setId(String agendaId) {
225                if (agendaId != null && StringUtils.isBlank(agendaId)) {
226                    throw new IllegalArgumentException("agenda ID must be null or non-blank");
227                }
228                            this.id = agendaId;
229                    }
230         
231            public void setName(String name) {
232                if (StringUtils.isBlank(name)) {
233                    throw new IllegalArgumentException("name is blank");
234                }
235                            this.name = name;
236                    }
237         
238                    public void setTypeId(String typeId) {
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            public void setActive(boolean active) {
250                this.active = active;
251            }
252                    
253                    public void setFirstItemId(String firstItemId) {
254                            this.firstItemId = firstItemId;
255                    }
256                    
257                    public void setAttributes(Map<String, String> attributes){
258                            if (attributes == null){
259                                    this.attributes = Collections.emptyMap();
260                            }
261                            this.attributes = Collections.unmodifiableMap(attributes);
262                    }
263                    
264                    /**
265             * Sets the version number for the style that will be returned by this
266             * builder.
267             * 
268             * <p>In general, this value should not be manually set on the builder,
269             * but rather copied from an existing {@link ContextDefinitionContract} when
270             * invoking {@link Builder#create(ContextDefinitionContract)}.
271             * 
272             * @param versionNumber the version number to set
273             */
274            public void setVersionNumber(Long versionNumber){
275                this.versionNumber = versionNumber;
276            }
277            
278                    @Override
279                    public String getId() {
280                            return id;
281                    }
282    
283                    @Override
284                    public String getName() {
285                            return name;
286                    }
287    
288                    @Override
289                    public String getTypeId() {
290                            return typeId;
291                    }
292    
293                    @Override
294                    public String getContextId() {
295                            return contextId;
296                    }
297    
298            @Override
299            public boolean isActive() {
300                return active;
301            }
302    
303                    @Override
304                    public String getFirstItemId() {
305                            return firstItemId;
306                    }
307    
308                    @Override
309                    public Map<String, String> getAttributes() {
310                            return attributes;
311                    }
312    
313            @Override
314            public Long getVersionNumber() {
315                return versionNumber;
316            }
317    
318                    /**
319                     * Builds an instance of a Agenda based on the current state of the builder.
320                     * 
321                     * @return the fully-constructed Agenda
322                     */
323            @Override
324            public AgendaDefinition build() {
325                return new AgendaDefinition(this);
326            }
327                    
328        }
329            
330            /**
331             * Defines some constants used on this class.
332             */
333            public static class Constants {
334                    final static String ROOT_ELEMENT_NAME = "agenda";
335                    final static String TYPE_NAME = "AgendaType";
336                    final static String[] HASH_CODE_EQUALS_EXCLUDE = { "_furutreElements" };
337            public final static String EVENT = "Event";   // key for event attribute
338            }
339            
340            /**
341             * A private class which exposes constants which define the XML element names to use
342             * when this object is marshalled to XML.
343             */
344            public static class Elements {
345                    final static String AGENDA_ID = "id";
346                    final static String NAME = "name";
347                    final static String TYPE_ID = "typeId";
348                    final static String CONTEXT_ID = "contextId";
349            final static String ACTIVE = "active";
350                    final static String FIRST_ITEM_ID = "firstItemId";
351                    final static String ATTRIBUTES = "attributes";
352                    final static String ATTRIBUTE = "attribute";
353            }
354    
355    }