001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: CreationTemplate.java,v 1.4 2008/06/25 05:41:44 qcheng Exp $ 026 * 027 */ 028 029/** 030 * Portions Copyrighted [2011] [ForgeRock AS] 031 */ 032package com.iplanet.ums; 033 034import java.util.ArrayList; 035import java.util.Enumeration; 036import java.util.Vector; 037 038import com.iplanet.services.ldap.Attr; 039import com.iplanet.services.ldap.AttrSet; 040import com.iplanet.services.util.I18n; 041import com.iplanet.ums.validation.DataConstraintException; 042import com.iplanet.ums.validation.Validation; 043import com.iplanet.ums.validation.ValidationElement; 044 045/** 046 * Represents templates for creating objects in UMS. CreationTemplate is used to 047 * aid in creating objects in which it serves as reusable guidelines to 048 * instantiate UMS objects properly at runtime. The guidelines are used to 049 * instantiate objects in memory correctly so that subsequent storage in 050 * persistent storage can be done successfully. It is the intention that 051 * CreationTemplate allows applications to determine what is correct so that 052 * some control is given in the application for early detection of problems of 053 * UMS object creations. Reusability and flexibility are two desired goals of 054 * CreationTemplate. 055 * 056 * @see Template 057 * @see SearchTemplate 058 * 059 * @supported.api 060 */ 061public class CreationTemplate extends Template { 062 063 private static I18n i18n = I18n.getInstance(IUMSConstants.UMS_PKG); 064 065 /** 066 * Default constructor for deserialization 067 * 068 */ 069 public CreationTemplate() { 070 super(); 071 } 072 073 /** 074 * Creates a template with required and optional attributes. 075 * 076 * @param name 077 * Template name 078 * @param required 079 * Set of required attributes 080 * @param optional 081 * Set of optional attributes 082 * @param classes 083 * Array of classes that this CreationTemplate is associated with 084 * for object creation 085 */ 086 public CreationTemplate(String name, AttrSet required, AttrSet optional, 087 ArrayList classes) { 088 super(name); 089 setRequiredAttributeSet(required); 090 setOptionalAttributeSet(optional); 091 setCreationClasses(classes); 092 } 093 094 /** 095 * Creates a template with required and optional attributes. 096 * 097 * @param name 098 * Template name 099 * @param required 100 * Set of required attributes 101 * @param optional 102 * Set of optional attributes 103 * @param cls 104 * Class that this CreationTemplate is associated with for object 105 * creation 106 */ 107 public CreationTemplate(String name, AttrSet required, AttrSet optional, 108 Class cls) { 109 this(name, required, optional); 110 ArrayList classes = new ArrayList(); 111 classes.add(cls); 112 setCreationClasses(classes); 113 } 114 115 /** 116 * Creates a template with required and optional attributes. 117 * 118 * @param name 119 * Template name 120 * @param required 121 * Set of required attributes 122 * @param optional 123 * Set of optional attributes 124 */ 125 public CreationTemplate(String name, AttrSet required, AttrSet optional) { 126 // No definition for the class 127 // 128 // this( name, required, optional, null ); 129 super(name); 130 setRequiredAttributeSet(required); 131 setOptionalAttributeSet(optional); 132 } 133 134 /** 135 * Gets the value of a given attribute in the template. 136 * 137 * @param attributeName 138 * Name of attribute for which to return values 139 * @return The attribute with the specified name, or <CODE>null</CODE> if 140 * attributeName is <CODE>null</CODE>, or the attribute is not 141 * found. 142 * 143 * @supported.api 144 */ 145 public Attr getAttribute(String attributeName) { 146 if (attributeName == null) { 147 return null; 148 } 149 Attr attr = null; 150 if (m_required != null) { 151 attr = m_required.getAttribute(attributeName); 152 } 153 if ((attr == null) && (m_optional != null)) { 154 attr = m_optional.getAttribute(attributeName); 155 } 156 return attr; 157 } 158 159 /** 160 * Gets a list of required attribute names defined in the object. 161 * 162 * @return Names of all required attributes defined 163 * 164 * @supported.api 165 */ 166 public String[] getRequiredAttributeNames() { 167 return (m_required == null) ? new String[0] : m_required 168 .getAttributeNames(); 169 } 170 171 /** 172 * Gets a list of optional attribute names defined in the object. 173 * 174 * @return Names of all optional attributes defined 175 * 176 * @supported.api 177 */ 178 public String[] getOptionalAttributeNames() { 179 return (m_optional == null) ? new String[0] : m_optional 180 .getAttributeNames(); 181 } 182 183 /** 184 * Gets the required attributes for object creation. 185 * 186 * @return set of required attributes 187 * 188 * @supported.api 189 */ 190 public AttrSet getRequiredAttributeSet() { 191 return m_required; 192 } 193 194 /** 195 * Gets the optional attributes for object creation. 196 * 197 * @return set of optional attributes 198 * 199 * @supported.api 200 */ 201 public AttrSet getOptionalAttributeSet() { 202 return m_optional; 203 } 204 205 /** 206 * Get the classes that the CreationTemplate is associated with. 207 * 208 * @return classes associated with this template 209 * 210 * @supported.api 211 */ 212 public ArrayList getCreationClasses() { 213 return m_classes; 214 } 215 216 /** 217 * Gets enumeration of ValidationElement for the attribute name 218 * 219 * @param attrName 220 * Attribute name 221 * @return Enumeration of ValidationElement 222 * 223 * @supported.api 224 */ 225 public Enumeration getValidation(String attrName) { 226 Vector v = new Vector(); 227 if (attrName != null && m_validated != null) { 228 Attr attr = m_validated.getAttribute(attrName); 229 if (attr != null) { 230 String[] validationStrings = attr.getStringValues(); 231 for (int i = 0; i < validationStrings.length; i++) { 232 v.add(decodeValidationString(validationStrings[i])); 233 } 234 } 235 } 236 return v.elements(); 237 } 238 239 AttrSet getValidation() { 240 return m_validated; 241 } 242 243 /** 244 * Gets a list of attribute names registered for validation. 245 * 246 * @return a list of attribute names registered for validation 247 * 248 * @supported.api 249 */ 250 public String[] getValidatedAttributeNames() { 251 return (m_validated == null) ? new String[0] : m_validated 252 .getAttributeNames(); 253 } 254 255 /** 256 * Gets enumeration of attributes for object creation. 257 * 258 * @return enumeration of required and optional attributes 259 */ 260 public Enumeration getAttributes() { 261 Vector v = new Vector(); 262 if (m_required != null) { 263 for (int i = 0; i < m_required.size(); i++) { 264 v.add(m_required.elementAt(i)); 265 } 266 } 267 268 if (m_optional != null) { 269 for (int i = 0; i < m_optional.size(); i++) { 270 v.add(m_optional.elementAt(i)); 271 } 272 } 273 274 return v.elements(); 275 } 276 277 /** 278 * Sets the required attributes. 279 * 280 * @param attrSet 281 * set of required attributes 282 */ 283 public void setRequiredAttributeSet(AttrSet attrSet) { 284 // ??? Should we clone attrSet instead of keeping a reference? 285 m_required = attrSet; 286 } 287 288 /** 289 * Sets the optional attributes. 290 * 291 * @param attrSet 292 * set of optional attributes 293 */ 294 public void setOptionalAttributeSet(AttrSet attrSet) { 295 // ??? Should we clone attrSet instead of keeping a reference? 296 m_optional = attrSet; 297 } 298 299 /** 300 * Set the class that the CreationTemplate is associated with. 301 * 302 * @param classes 303 * Classes associated with this template 304 */ 305 public void setCreationClasses(ArrayList classes) { 306 m_classes = classes; 307 } 308 309 /** 310 * Adds the attribute to the required attributes. 311 * 312 * @param attr 313 * The attribute to be added 314 */ 315 public void addRequiredAttribute(Attr attr) { 316 if (m_required == null) { 317 m_required = new AttrSet(); 318 } 319 m_required.add(attr); 320 } 321 322 /** 323 * Adds the attribute to the optional attributes. 324 * 325 * @param attr 326 * The attribute to be added 327 */ 328 public void addOptionalAttribute(Attr attr) { 329 if (m_optional == null) { 330 m_optional = new AttrSet(); 331 } 332 m_optional.add(attr); 333 } 334 335 /** 336 * Sets the validation table 337 * 338 * @param attrSet 339 * validation table in attribute set format 340 */ 341 void setValidation(AttrSet attrSet) { 342 // ??? Should we clone attrSet instead of keeping a reference? 343 m_validated = attrSet; 344 } 345 346 /** 347 * Adds the validator and the rule for the attribute name. 348 * 349 * @param attrName Attribute name to validate. 350 * @param validatorClass Validator class name used for validation. 351 * @param rule The optional rule used by the validator. 352 */ 353 public void addValidation( 354 String attrName, 355 String validatorClass, 356 String rule 357 ) { 358 if (validatorClass != null && attrName != null) { 359 String validationString = encodeValidationString(validatorClass, 360 rule); 361 if (validationString != null) { 362 if (m_validated == null) { 363 m_validated = new AttrSet(); 364 } 365 if (!m_validated.contains(attrName, validationString)) { 366 m_validated.add(new Attr(attrName, validationString)); 367 } 368 } 369 } 370 } 371 372 /** 373 * Removes all validations from the attribute. 374 * 375 * @param attrName 376 * attribute name of the validations to be removed 377 */ 378 public void removeValidation(String attrName) { 379 if (m_validated != null) { 380 m_validated.remove(attrName); 381 } 382 } 383 384 /** 385 * Sets the naming attribute. 386 * 387 * @param namingAttribute 388 * naming attribute 389 */ 390 void setNamingAttribute(String namingAttribute) { 391 m_namingAttribute = namingAttribute; 392 } 393 394 /** 395 * Gets the naming attribute. 396 * 397 * @return the naming attribute 398 * 399 * @supported.api 400 */ 401 public String getNamingAttribute() { 402 return m_namingAttribute; 403 } 404 405 /** 406 * Returns a copy of the template. 407 * 408 * @return a copy of the template 409 * 410 * @supported.api 411 */ 412 public Object clone() { 413 CreationTemplate t = (CreationTemplate) super.clone(); 414 if (m_required != null) { 415 t.setRequiredAttributeSet((AttrSet) m_required.clone()); 416 } 417 if (m_optional != null) { 418 t.setOptionalAttributeSet((AttrSet) m_optional.clone()); 419 } 420 if (m_validated != null) { 421 t.setValidation((AttrSet) m_validated.clone()); 422 } 423 return t; 424 } 425 426 /** 427 * Encode an attrSet in a single attribute with multiple values using the 428 * given attribute name and the values (tag,value) found in the given 429 * attribute set. For example: 430 * 431 * <pre> 432 * required: objectclass=top 433 * required: objectclass=groupofuniquenames 434 * required: cn 435 * required: sn 436 * </pre> 437 * 438 * @param attrName 439 * Name of the encoded attribute 440 * @param attrSet 441 * Attribute Set to be encoded in a single attribute 442 * @param delimiter 443 * String token used as delimiter for the encoding 444 * @return Encoded attribute or null object if attrSet is empty 445 */ 446 static Attr encodeAttrSet(String attrName, AttrSet attrSet, 447 String delimiter) 448 { 449 if (attrSet == null || attrSet.size() == 0) { 450 return null; 451 } 452 453 Enumeration attrEnum = attrSet.getAttributes(); 454 Attr encodedAttr = new Attr(attrName); 455 456 while (attrEnum.hasMoreElements()) { 457 Attr a = (Attr) attrEnum.nextElement(); 458 String[] values = a.getStringValues(); 459 String[] encodedValues = new String[values.length]; 460 461 if (values.length == 0) { 462 encodedAttr.addValue(a.getName()); 463 } else { 464 for (int i = 0; i < values.length; i++) { 465 encodedValues[i] = a.getName() + delimiter + values[i]; 466 } 467 encodedAttr.addValues(encodedValues); 468 } 469 } 470 471 return encodedAttr; 472 } 473 474 private static String encodeValidationString(String className, String rule) 475 { 476 if (rule == null) { 477 return className; 478 } 479 StringBuilder sb = new StringBuilder(); 480 sb.append(className); 481 sb.append("("); 482 sb.append(rule); 483 sb.append(")"); 484 return sb.toString(); 485 } 486 487 private static ValidationElement decodeValidationString(String value) { 488 int index = value.indexOf('('); 489 if (index < 0) { 490 return (new ValidationElement(value, null)); 491 } 492 String className = value.substring(0, index); 493 String rule = value.substring(index + 1, value.length() - 1); 494 return (new ValidationElement(className, rule)); 495 } 496 497 /** 498 * Render the object. 499 * 500 * @return The object in printable form 501 * 502 * @supported.api 503 */ 504 public String toString() { 505 return "CreationTemplate: " + getName() + " { Required " + m_required 506 + " Optional " + m_optional + " Validation " + m_validated 507 + " Naming Attribute " + m_namingAttribute + " }"; 508 } 509 510 /** 511 * Validate attrSet according to the definition of required and optional 512 * attributes defined in the template. 513 * 514 * @param attrSet 515 * Attribute set to be validated 516 * @return true if the given attrSet conforms to the template 517 * @throws UMSException 518 * if attrSet doesn't conform to the template 519 */ 520 boolean validateAttrSet(AttrSet attrSet) throws UMSException { 521 AttrSet reqAttrs = getRequiredAttributeSet(); 522 AttrSet optionalAttrs = getOptionalAttributeSet(); 523 if (reqAttrs == null && optionalAttrs == null) { 524 throw new UMSException(i18n 525 .getString(IUMSConstants.TEMPLATE_NO_ATTR)); 526 } 527 String[] attrNames = attrSet.getAttributeNames(); 528 int attrSetSize = (attrNames != null) ? attrNames.length : -1; 529 String attrName = null; 530 531 // Loop on attributes in the template comparing with the argument 532 // attSet and ensure all required attributtes are supplied 533 // or have a default 534 if (reqAttrs != null) { 535 Enumeration attrEnum = reqAttrs.getAttributes(); 536 while (attrEnum.hasMoreElements()) { 537 Attr anAttr = (Attr) attrEnum.nextElement(); 538 // if ( !attrSet.contains(anAttr.getName().toLowerCase())) { 539 if (!attrSet.contains(anAttr.getName())) { 540 // A required attribute which was not supplied 541 if (anAttr.size() > 0) { 542 // There is a default value 543 attrSet.add((Attr) anAttr.clone()); 544 } else { 545 // No default value. This is an error! A value 546 // should have been supplied in attrSet. 547 attrName = anAttr.getName(); 548 String args[] = new String[1]; 549 args[0] = attrName; 550 String msg = i18n.getString(IUMSConstants.NO_VALUE, 551 args); 552 throw new UMSException(msg); 553 } 554 } 555 } 556 } 557 558 // If the optional attributes set is set to "*", which means allowing 559 // all attributes, then no need to ensure the given attributes are in 560 // either the required attributes set or the optional attributes set 561 if (optionalAttrs != null && optionalAttrs.contains("*")) { 562 return true; 563 } 564 565 // Loop on attributes in the argument attrSet comparing with the 566 // template and ensure all the attributes are allowed 567 // 568 boolean attrAllowed = false; 569 for (int i = 0; i < attrSetSize; i++) { 570 attrAllowed = false; 571 attrName = attrNames[i]; 572 if (reqAttrs != null && reqAttrs.contains(attrName)) { 573 attrAllowed = true; 574 } else if (optionalAttrs != null 575 && optionalAttrs.contains(attrName)) { 576 attrAllowed = true; 577 } 578 if (!attrAllowed) { 579 String args[] = new String[1]; 580 args[0] = attrName; 581 String msg = i18n.getString(IUMSConstants.ATTR_NOT_ALLOWED, 582 args); 583 // TODO: need to define new and meaningful exception for 584 // unknown attribute not conforming to the 585 // given creation template 586 // 587 throw new UMSException(msg); 588 } 589 } 590 return true; 591 } 592 593 /** 594 * Validate attrSet according to the definition of validated attributes 595 * defined in the template. 596 * 597 * @param attrSet 598 * Attribute set to be validated 599 * @return true if the given attrSet conforms to the template 600 * @throws DataConstraintException 601 * if attrSet doesn't conform to the template 602 * @throws UMSException 603 * failure 604 */ 605 boolean validateAttributes(AttrSet attrSet) throws UMSException, 606 DataConstraintException { 607 608 Enumeration en1 = attrSet.getAttributes(); 609 while (en1.hasMoreElements()) { 610 Attr attr = (Attr) en1.nextElement(); 611 Enumeration en2 = getValidation(attr.getName()); 612 while (en2.hasMoreElements()) { 613 ValidationElement vElement = (ValidationElement) en2 614 .nextElement(); 615 // calls method in Validation to validate each values 616 // of the attribute 617 Validation.validateAttribute(attr, vElement.getValidator(), 618 vElement.getRule()); 619 } 620 } 621 return true; 622 } 623 624 private AttrSet m_required = null; 625 626 private AttrSet m_optional = null; 627 628 private ArrayList m_classes = null; 629 630 private AttrSet m_validated = null; 631 632 private String m_namingAttribute = null; 633}