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 }