001/** 002 * Copyright 2005-2017 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.kim.api.type; 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.kim.api.KimConstants; 037import org.w3c.dom.Element; 038 039/** 040 * An immutable representation of a {@link KimTypeContract}. 041 * 042 * <p>To construct an instance of a KimType, use the {@link KimType.Builder} class.<p/> 043 * 044 * @see KimTypeContract 045 */ 046@XmlRootElement(name = KimType.Constants.ROOT_ELEMENT_NAME) 047@XmlAccessorType(XmlAccessType.NONE) 048@XmlType(name = KimType.Constants.TYPE_NAME, propOrder = { 049 KimType.Elements.ID, 050 KimType.Elements.SERVICE_NAME, 051 KimType.Elements.NAMESPACE_CODE, 052 KimType.Elements.NAME, 053 KimType.Elements.ATTRIBUTE_DEFNS, 054 KimType.Elements.ACTIVE, 055 CoreConstants.CommonElements.VERSION_NUMBER, 056 CoreConstants.CommonElements.OBJECT_ID, 057 CoreConstants.CommonElements.FUTURE_ELEMENTS 058}) 059public final class KimType extends AbstractDataTransferObject implements KimTypeContract { 060 private static final long serialVersionUID = 1L; 061 062 @XmlElement(name = KimType.Elements.ID, required = false) 063 private final String id; 064 065 @XmlElement(name = KimType.Elements.SERVICE_NAME, required = false) 066 private final String serviceName; 067 068 @XmlElement(name = KimType.Elements.NAMESPACE_CODE, required = false) 069 private final String namespaceCode; 070 071 @XmlElement(name = KimType.Elements.NAME, required = false) 072 private final String name; 073 074 @XmlElementWrapper(name = Elements.ATTRIBUTE_DEFNS, required = false) 075 @XmlElement(name = KimType.Elements.ATTRIBUTE_DEFN, required = false) 076 private final List<KimTypeAttribute> attributeDefinitions; 077 078 @XmlElement(name = KimType.Elements.ACTIVE, required = false) 079 private final boolean active; 080 081 @XmlElement(name = CoreConstants.CommonElements.VERSION_NUMBER, required = false) 082 private final Long versionNumber; 083 084 @XmlElement(name = CoreConstants.CommonElements.OBJECT_ID, required = false) 085 private final String objectId; 086 087 @SuppressWarnings("unused") 088 @XmlAnyElement 089 private final Collection<Element> _futureElements = null; 090 091 /** 092 * This constructor should never be called except during JAXB unmarshalling. 093 */ 094 private KimType() { 095 this.id = null; 096 this.serviceName = null; 097 this.namespaceCode = null; 098 this.name = null; 099 this.attributeDefinitions = Collections.<KimTypeAttribute>emptyList(); 100 this.active = false; 101 this.versionNumber = Long.valueOf(1L); 102 this.objectId = null; 103 } 104 105 private KimType(Builder builder) { 106 this.id = builder.getId(); 107 this.serviceName = builder.getServiceName(); 108 this.namespaceCode = builder.getNamespaceCode(); 109 this.name = builder.getName(); 110 final List<KimTypeAttribute> temp = new ArrayList<KimTypeAttribute>(); 111 for (KimTypeAttribute.Builder attr : builder.getAttributeDefinitions()) { 112 //associate each attribute with this kimType's id 113 attr.setKimTypeId(this.id); 114 temp.add(attr.build()); 115 } 116 this.attributeDefinitions = Collections.unmodifiableList(temp); 117 118 this.active = builder.isActive(); 119 this.versionNumber = builder.getVersionNumber(); 120 this.objectId = builder.getObjectId(); 121 } 122 123 /** 124 * Gets the KimTypeAttribute matching the id of it's KimAttribute. If no attribute definition exists with that 125 * id then null is returned. 126 * 127 * <p> 128 * If multiple exist with the same id then the first match is returned. Since id 129 * is supposed to be unique this should not be a problem in practice. 130 * </p> 131 * 132 * @param id the KimTypeAttribute.KimAttribute's id 133 * @return the KimTypeAttribute or null 134 * @throws IllegalArgumentException if the id is blank 135 */ 136 public KimTypeAttribute getAttributeDefinitionById(String id) { 137 if (StringUtils.isBlank(id)) { 138 throw new IllegalArgumentException("id is blank"); 139 } 140 141 if (this.attributeDefinitions != null) { 142 for (KimTypeAttribute att : this.attributeDefinitions) { 143 if (att != null && att.getKimAttribute() != null 144 && id.equals(att.getKimAttribute().getId())) { 145 return att; 146 } 147 } 148 } 149 return null; 150 } 151 152 /** 153 * Gets the KimTypeAttribute matching the name of it's KimAttribute. If no attribute definition exists with that 154 * name then null is returned. 155 * 156 * <p> 157 * If multiple exist with the same name then the first match is returned. Since name 158 * is supposed to be unique this should not be a problem in practice. 159 * </p> 160 * 161 * @param name the KimTypeAttribute's name 162 * @return the KimTypeAttribute or null 163 * @throws IllegalArgumentException if the name is blank 164 */ 165 public KimTypeAttribute getAttributeDefinitionByName(String name) { 166 if (StringUtils.isBlank(name)) { 167 throw new IllegalArgumentException("name is blank"); 168 } 169 170 if (this.attributeDefinitions != null) { 171 for (KimTypeAttribute att : this.attributeDefinitions) { 172 if (att != null && att.getKimAttribute() != null 173 && name.equals(att.getKimAttribute().getAttributeName())) { 174 return att; 175 } 176 } 177 } 178 return null; 179 } 180 181 @Override 182 public String getId() { 183 return id; 184 } 185 186 @Override 187 public String getServiceName() { 188 return serviceName; 189 } 190 191 @Override 192 public String getNamespaceCode() { 193 return namespaceCode; 194 } 195 196 @Override 197 public String getName() { 198 return name; 199 } 200 201 @Override 202 public List<KimTypeAttribute> getAttributeDefinitions() { 203 return attributeDefinitions; 204 } 205 206 @Override 207 public boolean isActive() { 208 return active; 209 } 210 211 @Override 212 public Long getVersionNumber() { 213 return versionNumber; 214 } 215 216 @Override 217 public String getObjectId() { 218 return objectId; 219 } 220 221 /** 222 * This builder constructs an KimType enforcing the constraints of the {@link KimTypeContract}. 223 */ 224 public static final class Builder implements KimTypeContract, ModelBuilder, Serializable { 225 private String id; 226 private String serviceName; 227 private String namespaceCode; 228 private String name; 229 private List<KimTypeAttribute.Builder> attributeDefinitions = new ArrayList<KimTypeAttribute.Builder>(); 230 private boolean active; 231 private Long versionNumber; 232 private String objectId; 233 234 private Builder() { 235 } 236 237 /** 238 * creates a KimType with the required fields. 239 */ 240 public static Builder create() { 241 return new Builder(); 242 } 243 244 /** 245 * creates a KimType from an existing {@link KimTypeContract}. 246 */ 247 public static Builder create(KimTypeContract contract) { 248 if (contract == null) { 249 throw new IllegalArgumentException("contract was null"); 250 } 251 Builder builder = new Builder(); 252 builder.setId(contract.getId()); 253 builder.setServiceName(contract.getServiceName()); 254 builder.setNamespaceCode(contract.getNamespaceCode()); 255 builder.setName(contract.getName()); 256 257 if (contract.getAttributeDefinitions() != null) { 258 final List<KimTypeAttribute.Builder> temp = new ArrayList<KimTypeAttribute.Builder>(); 259 for (KimTypeAttributeContract attr : contract.getAttributeDefinitions()) { 260 if ( attr != null ) { 261 temp.add(KimTypeAttribute.Builder.create(attr)); 262 } 263 } 264 265 builder.setAttributeDefinitions(Collections.unmodifiableList(temp)); 266 } 267 268 builder.setActive(contract.isActive()); 269 builder.setVersionNumber(contract.getVersionNumber()); 270 builder.setObjectId(contract.getObjectId()); 271 return builder; 272 } 273 274 @Override 275 public String getId() { 276 return id; 277 } 278 279 public void setId(final String id) { 280 this.id = id; 281 } 282 283 @Override 284 public String getServiceName() { 285 return serviceName; 286 } 287 288 public void setServiceName(final String serviceName) { 289 this.serviceName = serviceName; 290 } 291 292 @Override 293 public String getNamespaceCode() { 294 return namespaceCode; 295 } 296 297 public void setNamespaceCode(final String namespaceCode) { 298 this.namespaceCode = namespaceCode; 299 } 300 301 @Override 302 public String getName() { 303 return name; 304 } 305 306 public void setName(final String name) { 307 this.name = name; 308 } 309 310 @Override 311 public List<KimTypeAttribute.Builder> getAttributeDefinitions() { 312 return attributeDefinitions; 313 } 314 315 public void setAttributeDefinitions(final List<KimTypeAttribute.Builder> attributeDefinitions) { 316 if (attributeDefinitions == null) { 317 throw new IllegalArgumentException("attributeDefinitions is null"); 318 } 319 320 this.attributeDefinitions = attributeDefinitions; 321 } 322 323 @Override 324 public boolean isActive() { 325 return active; 326 } 327 328 public void setActive(final boolean active) { 329 this.active = active; 330 } 331 332 @Override 333 public Long getVersionNumber() { 334 return versionNumber; 335 } 336 337 public void setVersionNumber(final Long versionNumber) { 338 this.versionNumber = versionNumber; 339 } 340 341 @Override 342 public String getObjectId() { 343 return objectId; 344 } 345 346 public void setObjectId(final String objectId) { 347 this.objectId = objectId; 348 } 349 350 @Override 351 public KimType build() { 352 return new KimType(this); 353 } 354 } 355 356 /** 357 * Defines some internal constants used on this class. 358 */ 359 static class Constants { 360 static final String ROOT_ELEMENT_NAME = "kimType"; 361 static final String TYPE_NAME = "KimTypeType"; 362 } 363 364 /** 365 * A private class which exposes constants which define the XML element names to use 366 * when this object is marshalled to XML. 367 */ 368 static class Elements { 369 static final String ID = "id"; 370 static final String SERVICE_NAME = "serviceName"; 371 static final String NAMESPACE_CODE = "namespaceCode"; 372 static final String NAME = "name"; 373 static final String ATTRIBUTE_DEFNS = "attributeDefinitions"; 374 static final String ATTRIBUTE_DEFN = "attributeDefinition"; 375 static final String ACTIVE = "active"; 376 } 377 378 public static class Cache { 379 public static final String NAME = KimConstants.Namespaces.KIM_NAMESPACE_2_0 + "/" + KimType.Constants.TYPE_NAME; 380 } 381}