001/**
002 * Copyright 2005-2015 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 */
016package org.kuali.rice.krms.api.repository.term;
017
018import java.io.Serializable;
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.Collections;
022import java.util.List;
023
024import javax.xml.bind.annotation.XmlAccessType;
025import javax.xml.bind.annotation.XmlAccessorType;
026import javax.xml.bind.annotation.XmlAnyElement;
027import javax.xml.bind.annotation.XmlElement;
028import javax.xml.bind.annotation.XmlElementWrapper;
029import javax.xml.bind.annotation.XmlRootElement;
030import javax.xml.bind.annotation.XmlType;
031
032import org.apache.commons.lang.StringUtils;
033import org.kuali.rice.core.api.CoreConstants;
034import org.kuali.rice.core.api.mo.AbstractDataTransferObject;
035import org.kuali.rice.core.api.mo.ModelBuilder;
036import org.kuali.rice.krms.api.KrmsConstants;
037import org.kuali.rice.krms.api.repository.BuilderUtils;
038import org.kuali.rice.krms.api.repository.BuilderUtils.Transformer;
039import org.kuali.rice.krms.api.repository.category.CategoryDefinition;
040import 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})
061public 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}