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