001    /**
002     * Copyright 2005-2012 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.term;
017    
018    import java.io.Serializable;
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.Collections;
022    import java.util.List;
023    
024    import javax.xml.bind.annotation.XmlAccessType;
025    import javax.xml.bind.annotation.XmlAccessorType;
026    import javax.xml.bind.annotation.XmlAnyElement;
027    import javax.xml.bind.annotation.XmlElement;
028    import javax.xml.bind.annotation.XmlElementWrapper;
029    import javax.xml.bind.annotation.XmlRootElement;
030    import javax.xml.bind.annotation.XmlType;
031    
032    import org.apache.commons.lang.StringUtils;
033    import org.kuali.rice.core.api.CoreConstants;
034    import org.kuali.rice.core.api.mo.AbstractDataTransferObject;
035    import org.kuali.rice.core.api.mo.ModelBuilder;
036    import org.kuali.rice.krms.api.KrmsConstants;
037    import org.kuali.rice.krms.api.repository.BuilderUtils;
038    import org.kuali.rice.krms.api.repository.BuilderUtils.Transformer;
039    import org.kuali.rice.krms.api.repository.category.CategoryDefinition;
040    import org.kuali.rice.krms.api.repository.category.CategoryDefinitionContract;
041    
042    /**
043     * Immutable DTO for TermSpecifications.  Construction must be done via the {@link Builder} inner class.
044     * 
045     * @author Kuali Rice Team (rice.collab@kuali.org)
046     *
047     */
048    @XmlRootElement(name = TermSpecificationDefinition.Constants.ROOT_ELEMENT_NAME)
049    @XmlAccessorType(XmlAccessType.NONE)
050    @XmlType(name = TermSpecificationDefinition.Constants.TYPE_NAME, propOrder = {
051                    TermSpecificationDefinition.Elements.ID,
052                    TermSpecificationDefinition.Elements.NAME,
053            TermSpecificationDefinition.Elements.NAMESPACE,
054            TermSpecificationDefinition.Elements.TYPE,
055            TermSpecificationDefinition.Elements.DESCRIPTION,
056            TermSpecificationDefinition.Elements.ACTIVE,
057            CoreConstants.CommonElements.VERSION_NUMBER,
058            TermSpecificationDefinition.Elements.CATEGORIES,
059                    CoreConstants.CommonElements.FUTURE_ELEMENTS
060    })
061    public final class TermSpecificationDefinition extends AbstractDataTransferObject implements TermSpecificationDefinitionContract {
062            
063            private static final long serialVersionUID = 1L;
064            
065            @XmlElement(name = Elements.ID, required=false)
066            private final String id;
067        @XmlElement(name = Elements.NAME, required=true)
068        private final String name;
069        @XmlElement(name = Elements.NAMESPACE, required=true)
070        private final String namespace;
071            @XmlElement(name = Elements.TYPE, required=true)
072            private final String type;
073        @XmlElement(name = Elements.DESCRIPTION, required=false)
074        private final String description;
075        @XmlElement(name = Elements.ACTIVE, required = false)
076        private final boolean active;
077        @XmlElement(name = CoreConstants.CommonElements.VERSION_NUMBER, required = false)
078        private final Long versionNumber;
079    
080        @XmlElementWrapper(name = Elements.CATEGORIES, required = false)
081        @XmlElement(name = Elements.CATEGORY, required = false)
082        private final List<CategoryDefinition> categories;
083    
084            
085            @SuppressWarnings("unused")
086        @XmlAnyElement
087        private final Collection<org.w3c.dom.Element> _futureElements = null;
088            
089            /**
090             * For JAXB use only, shouldn't ever be invoked directly
091             */
092            private TermSpecificationDefinition() {
093                    id = null;
094                    name = null;
095            namespace = null;
096                    type = null;
097            description = null;
098            active = true;
099            versionNumber = null;
100            this.categories = null;
101            }
102            
103            /**
104             * Private constructor enforces use of Builder
105             * 
106             * @param b the builder to use
107             */
108            private TermSpecificationDefinition(Builder b) {
109                    id = b.getId();
110                    name = b.getName();
111            namespace = b.getNamespace();
112                    type = b.getType();
113            description = b.getDescription();
114            active = b.isActive();
115                    versionNumber = b.getVersionNumber();
116            this.categories = constructCategories(b.getCategories());
117            }
118    
119        private static List<CategoryDefinition> constructCategories(List<CategoryDefinition.Builder> categoryBuilders) {
120            List<CategoryDefinition> categories = new ArrayList<CategoryDefinition>();
121            if (categoryBuilders != null) {
122                    for (CategoryDefinition.Builder categoryBuilder : categoryBuilders) {
123                            categories.add(categoryBuilder.build());
124                    }
125            }
126            return categories;
127        }
128    
129            /**
130             * Builder for the {@link TermSpecificationDefinition} immutable DTO.  Instantiate using static factory method(s).
131             * 
132             * @author Kuali Rice Team (rice.collab@kuali.org)
133             */
134            public static class Builder implements TermSpecificationDefinitionContract, ModelBuilder, Serializable {
135                    
136                    private static final long serialVersionUID = 1L;
137                    
138                    private String termSpecificationId;
139                    private String name;
140            private String namespace;
141                    private String type;
142            private String description;
143            private boolean active;
144            private Long versionNumber;
145            private List<CategoryDefinition.Builder> categories;
146    
147                    private static final String NON_NULL_NON_EMPTY_ERROR =  " must be non-null and must contain non-whitespace chars"; 
148    
149                    /**
150                     * {@link Transformer} to ease converting lists to Builder types
151                     */
152                    public static final Transformer<TermSpecificationDefinitionContract, TermSpecificationDefinition.Builder>
153                    toBuilder = new BuilderUtils.Transformer<TermSpecificationDefinitionContract, TermSpecificationDefinition.Builder>() {
154                            public TermSpecificationDefinition.Builder transform(TermSpecificationDefinitionContract input) {
155                                    return TermSpecificationDefinition.Builder.create(input);
156                            }
157                    };
158                    
159                    private Builder(String termSpecificationId, String name, String namespace, String type) {
160                            // weird to use setters in constructor .. oh well.
161                            setId(termSpecificationId);
162                            setNamespace(namespace);
163                            setName(name);
164                            setType(type);
165                setActive(true);
166                setCategories(new ArrayList<CategoryDefinition.Builder>());
167                    }
168                    
169                    /**
170                     * static factory for a {@link Builder} from a complete set of field values for this object.
171                     * 
172                     *
173             * @param termSpecificationId the primary key field.  Must be null for service methods that
174             * create {@link org.kuali.rice.krms.api.repository.term.TermSpecificationDefinitionContract}s, and must be non-null & contain non-whitespace
175             * chars otherwise.
176             * @param name the name for the {@link org.kuali.rice.krms.api.repository.term.TermSpecificationDefinition}.  Must be non-null;.
177             * @param namespace the namespace for the {@link org.kuali.rice.krms.api.repository.term.TermSpecificationDefinition}.  Must be non-null & contain non-whitespace.
178             *@param type the type for the {@link org.kuali.rice.krms.api.repository.term.TermSpecificationDefinition}  @return a {@link Builder} object
179                     * @throws IllegalArgumentException if invalid parameters are supplied.
180                     */
181                    public static Builder create(String termSpecificationId, String name, String namespace, String type) {
182                            return new Builder(termSpecificationId, name, namespace, type);
183                    }
184                    
185                    /**
186                     * static factory for a {@link Builder} from a {@link TermSpecificationDefinitionContract}.
187                     * 
188                     * @param termSpecification may not be null;
189                     * @throws IllegalArgumentException if termSpecification is null, or violates the field invariants of the {@link Builder}.
190                     */
191                    public static Builder create(TermSpecificationDefinitionContract termSpecification) {
192                            if (termSpecification == null) throw new IllegalArgumentException("termSpecification must be non-null");
193                            Builder builder =new Builder(termSpecification.getId(), termSpecification.getName(), termSpecification.getNamespace(),
194                        termSpecification.getType());
195                builder.setDescription(termSpecification.getDescription());
196                builder.setActive(termSpecification.isActive());
197                            builder.setVersionNumber(termSpecification.getVersionNumber());
198                for (CategoryDefinitionContract category : termSpecification.getCategories()) {
199                    builder.getCategories().add(CategoryDefinition.Builder.create(category));
200                }
201    
202                            return builder;
203                    }
204    
205            public void setDescription(String description) {
206                this.description = description;
207            }
208    
209            // Setters
210                    
211                    /**
212                     * @param termSpecificationId the key for this {@link TermSpecificationDefinition}.  Must be null for
213                     * service methods that create {@link TermSpecificationDefinitionContract}s, and otherwise must be non-null & contain 
214                     * non-whitespace chars.
215                     */
216                    public void setId(String termSpecificationId) {
217                            if (termSpecificationId != null && StringUtils.isBlank(termSpecificationId))
218                                    throw new IllegalArgumentException("termSpecificationId must contain non-whitespace chars");
219                            this.termSpecificationId = termSpecificationId;
220                    }
221                    
222                    /**
223                     * @param namespace the namespace to set.  Must be non-null and contain non-whitespace chars;
224                     */
225                    public void setNamespace(String namespace) {
226                            if (StringUtils.isBlank(namespace)) {
227                                    throw new IllegalArgumentException("namespace" + NON_NULL_NON_EMPTY_ERROR);
228                            }
229                            this.namespace = namespace;
230                    }
231                    
232                    /**
233                     * @param name the name to set.  Must be non-null and contain non-whitespace chars;
234                     */
235                    public void setName(String name) {
236                            if (StringUtils.isBlank(name)) {
237                                    throw new IllegalArgumentException("name" + NON_NULL_NON_EMPTY_ERROR);
238                            }
239                            this.name = name;
240                    }
241                    /**
242                     * @param type the type to set. Must be non-null and contain non-whitespace chars;
243                     */
244                    public void setType(String type) {
245                            if (StringUtils.isBlank(type)) {
246                                    throw new IllegalArgumentException("type" + NON_NULL_NON_EMPTY_ERROR);
247                            }
248                            this.type = type;
249                    }
250                    
251                    /**
252                     * @param versionNumber the versionNumber to set.  May be null.
253                     */
254            public void setVersionNumber(Long versionNumber){
255                this.versionNumber = versionNumber;
256            }
257    
258            public void setActive(boolean active) {
259                this.active = active;
260            }
261    
262            /**
263             * @param categories the categories to set.  May not be null but can be an empty set.
264             */
265            public void setCategories(List<CategoryDefinition.Builder> categories) {
266                if (categories == null) {
267                    throw new IllegalArgumentException("categories was null");
268                }
269                this.categories = categories;
270            }
271            
272                    // Getters
273                    
274                    /**
275                     * @return the termSpecificationId
276                     */
277                    @Override
278                    public String getId() {
279                            return this.termSpecificationId;
280                    }
281    
282                    /**
283                     * @return the namespace
284                     */
285                    @Override
286                    public String getNamespace() {
287                            return this.namespace;
288                    }
289    
290                    /**
291                     * @return the name
292                     */
293                    @Override
294                    public String getName() {
295                            return this.name;
296                    }
297    
298                    /**
299                     * @return the type
300                     */
301                    @Override
302                    public String getType() {
303                            return this.type;
304                    }
305    
306            @Override
307            public String getDescription() {
308                return this.description;
309            }
310    
311            /**
312                     * @return the version number
313                     */
314            @Override
315            public Long getVersionNumber() {
316                return this.versionNumber;
317            }
318    
319            @Override
320            public boolean isActive() {
321                return active;
322            }
323    
324            /**
325             * @return the categories
326             */
327            @Override
328            public List<CategoryDefinition.Builder> getCategories() {
329                return this.categories;
330            }
331    
332    
333                    /**
334                     * Constructs a {@link TermSpecificationDefinition}
335                     * @see org.kuali.rice.core.api.mo.ModelBuilder#build()
336                     */
337                    @Override
338                    public TermSpecificationDefinition build() {
339                            return new TermSpecificationDefinition(this);
340                    }
341            }
342    
343            /**
344             * This value will be non-null for persisted  
345             * @see org.kuali.rice.krms.api.repository.term.TermSpecificationDefinitionContract#getId()
346             */
347            @Override
348            public String getId() {
349                    return id;
350            }
351    
352            /**
353             * @see org.kuali.rice.krms.api.repository.term.TermSpecificationDefinitionContract#getName()
354             */
355            @Override
356            public String getName() {
357                    return name;
358            }
359    
360        @Override
361        public String getNamespace() {
362            return namespace;
363        }
364    
365            /**
366             * @see org.kuali.rice.krms.api.repository.term.TermSpecificationDefinitionContract#getType()
367             */
368            @Override
369            public String getType() {
370                    return type;
371            }
372    
373        @Override
374        public String getDescription() {
375            return description;
376        }
377    
378        @Override
379        public boolean isActive() {
380            return active;
381        }
382    
383        /**
384             * @see org.kuali.rice.core.api.mo.common.Versioned#getVersionNumber()
385             */
386        @Override
387        public Long getVersionNumber() {
388            return versionNumber;
389        }
390    
391        /**
392         * @see TermSpecificationDefinitionContract#getCategories()
393         */
394        @Override
395        public List<CategoryDefinition> getCategories() {
396            return Collections.unmodifiableList(categories);
397        }
398            
399            /**
400             * Defines some internal constants used on this class.
401             */
402            static class Constants {
403                    final static String ROOT_ELEMENT_NAME = "termSpecification";
404                    final static String TYPE_NAME = "TermSpecificationType";
405            }
406            
407            static class Elements {
408                    public static final String ID = "id";
409                    public static final String NAME = "name";
410            public final static String NAMESPACE = "namespace";
411            public static final String TYPE = "type";
412            public static final String DESCRIPTION = "description";
413            public static final String ACTIVE = "active";
414            public final static String CATEGORIES = "categories";
415            public final static String CATEGORY = "category";
416        }
417    
418        public static class Cache {
419            public static final String NAME = KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0 + "/" + TermSpecificationDefinition.Constants.TYPE_NAME;
420        }
421    }