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: ServiceSchema.java,v 1.12 2008/08/30 16:46:47 goodearth Exp $ 026 * 027 * Portions Copyrighted 2011-2016 ForgeRock AS. 028 */ 029package com.sun.identity.sm; 030 031import static java.util.Arrays.asList; 032 033import com.iplanet.sso.SSOException; 034import com.iplanet.ums.IUMSConstants; 035import com.sun.identity.shared.Constants; 036import com.sun.identity.common.CaseInsensitiveHashSet; 037import com.sun.identity.shared.debug.Debug; 038import com.sun.identity.shared.xml.XMLUtils; 039import java.io.InputStream; 040import java.util.Collections; 041import java.util.HashMap; 042import java.util.HashSet; 043import java.util.Iterator; 044import java.util.Map; 045import java.util.Set; 046import java.util.StringTokenizer; 047import org.w3c.dom.Document; 048import org.w3c.dom.Element; 049import org.w3c.dom.Node; 050import org.w3c.dom.NodeList; 051 052 053/** 054 * The class <code>ServiceSchema</code> provides interfaces to manage the 055 * schema information of a service. The schema for a service can be one of the 056 * following types: GLOBAL, ORGANIZATION, DYNAMIC, USER, and POLICY. 057 * 058 * @supported.all.api 059 */ 060public class ServiceSchema { 061 062 // Pointer to service's schema manager & type 063 ServiceSchemaImpl ss; 064 065 String componentName; 066 067 SchemaType type; 068 069 ServiceSchemaManager ssm; 070 071 boolean orgAttrSchema; 072 073 /** 074 * Default constructor (private). 075 */ 076 private ServiceSchema() { 077 // do nothing 078 } 079 080 protected ServiceSchema(ServiceSchemaImpl ssi, String compName, 081 SchemaType type, ServiceSchemaManager ssm) { 082 this(ssi, compName, type, ssm, false); 083 } 084 085 protected ServiceSchema(ServiceSchemaImpl ssi, String compName, 086 SchemaType type, ServiceSchemaManager ssm, boolean isOrgAttrSchema) 087 { 088 this.ss = ssi; 089 this.componentName = compName; 090 this.type = type; 091 this.ssm = ssm; 092 this.orgAttrSchema = isOrgAttrSchema; 093 this.ss.isOrgAttrSchema = isOrgAttrSchema; 094 this.ss.serviceName = ssm.getName(); 095 } 096 097 /** 098 * Returns the name of the service. 099 * 100 * @return the name of the schema 101 */ 102 public String getServiceName() { 103 return (ssm.getName()); 104 } 105 106 /** 107 * Returns the version of the service. 108 * 109 * @return version of the service schema 110 */ 111 public String getVersion() { 112 return (ssm.getVersion()); 113 } 114 115 /** 116 * Returns the name of the schema. 117 * 118 * @return the name of the schema 119 */ 120 public String getName() { 121 return (ss.getName()); 122 } 123 124 /** 125 * Returns the schema type. 126 * 127 * @return the schema type. 128 */ 129 public SchemaType getServiceType() { 130 return (type); 131 } 132 133 /** 134 * Returns the I18N key that points to the description of the service. 135 * 136 * @return the I18N key that points to the description of the service 137 */ 138 public String getI18NKey() { 139 return (ss.getI18NKey()); 140 } 141 142 /** 143 * Returns <code>true</code> if service schema supports multiple 144 * configurations; <code>false</code> otherwise 145 * 146 * @return <code>true</code> if service schema supports multiple 147 * configurations; <code>false</code> otherwise 148 */ 149 public boolean supportsMultipleConfigurations() { 150 return (ss.supportsMultipleConfigurations()); 151 } 152 153 /** 154 * Sets the value of the I18N key in the service schema. 155 * 156 * @param key 157 * Value to be set for the I18N key of the service schema. 158 * @throws SMSException 159 * if there is a problem setting the value in the data store. 160 * @throws SSOException 161 * If the user has an invalid SSO token. 162 */ 163 public void setI18Nkey(String key) throws SMSException, SSOException { 164 SMSEntry.validateToken(ssm.getSSOToken()); 165 Node sNode = ss.getSchemaNode(); 166 ((Element) sNode).setAttribute(SMSUtils.I18N_KEY, key); 167 ssm 168 .replaceSchema((ServiceSchemaManagerImpl.getInstance(ssm 169 .getSSOToken(), ssm.getName(), ssm.getVersion())) 170 .getDocument()); 171 ss.i18nKey = key; 172 } 173 174 /** 175 * Set the value of inheritance attribute in service schema. 176 * 177 * @param value 178 * New value of inheritance attribute. 179 * @throws SMSException 180 * if there is a problem setting the value in the data store. 181 * @throws SSOException 182 * if the user has an invalid single sign on token. 183 */ 184 public void setInheritance(String value) throws SMSException, SSOException { 185 if (!value.equals("single") && !value.equals("multiple")) { 186 String[] arg = { value }; 187 throw new SMSException(IUMSConstants.UMS_BUNDLE_NAME, 188 "sms-invalid-inheritance-value", arg); 189 } 190 191 SMSEntry.validateToken(ssm.getSSOToken()); 192 Node sNode = ss.getSchemaNode(); 193 ((Element) sNode).setAttribute(SMSUtils.INHERITANCE, value); 194 ssm 195 .replaceSchema((ServiceSchemaManagerImpl.getInstance(ssm 196 .getSSOToken(), ssm.getName(), ssm.getVersion())) 197 .getDocument()); 198 ss.inheritance = value; 199 } 200 201 /** 202 * Returns the view bean URL for this service 203 * 204 * @return file name that contains I18N messages 205 */ 206 public String getPropertiesViewBeanURL() { 207 return (ssm.getPropertiesViewBeanURL()); 208 } 209 210 /** 211 * Returns the name of the status attribute, as defined in the Service 212 * schema 213 * 214 * @return String name of status attribute 215 */ 216 public String getStatusAttribute() { 217 return (ss.getStatusAttribute()); 218 } 219 220 /** 221 * Returns <code>true</code> if the service configuration created can be 222 * exported to other organizations. 223 * 224 * @return <code>true</code> if service configurations for this schema can 225 * be exported to other organizations; <code>false</code> 226 * otherwise. 227 */ 228 public boolean isExportable() { 229 return (false); 230 } 231 232 /** 233 * Sets the exportable nature of the service configurations created for this 234 * schema. Setting it to <code>true</code> allows the configurations to be 235 * exported to other organizations and a value of <code>false</code> 236 * disables exporting of configuration data. 237 * 238 * @param exportable 239 * <code>true</code> if service configurations for this schema 240 * can be exported to other organizations; <code>false</code> 241 * otherwise. 242 */ 243 public void setExportable(boolean exportable) { 244 } 245 246 /** 247 * Returns the I18N properties file name for the service schema. 248 * 249 * @return the I18N properties file name for the service schema 250 */ 251 public String getI18NFileName() { 252 String i18nFileName = ss.getI18NFileName(); 253 return i18nFileName == null ? ssm.getI18NFileName() : i18nFileName; 254 } 255 256 /** 257 * Sets the I18N properties file name for the service schema 258 * 259 * @param url 260 * properties file name 261 * @throws SMSException 262 * if an error occurred while trying to perform the operation 263 * @throws SSOException 264 * if the single sign on token is invalid or expired 265 */ 266 public void setI18NFileName(String url) throws SMSException, SSOException { 267 ssm.setI18NFileName(url); 268 } 269 270 /** 271 * Returns the name for the service schema when used in a CREST representation. 272 */ 273 public String getResourceName() { 274 for (String name : asList(ss.getResourceName(), getName())) { 275 if (name != null) { 276 return name; 277 } 278 } 279 return getServiceName(); 280 } 281 282 /** 283 * Should this service schema be hidden in the Configuration UI. 284 * @return True if it should be hidden. 285 */ 286 public boolean isHiddenInConfigUI() { 287 return ss.isHiddenInConfigUI(); 288 } 289 290 /** 291 * During the creation of a new organisation/realm the services assigned to the parent realm are copied to the 292 * child realm. This will include the sub configs for that service, which in some cases are realm specific and will 293 * fail validation if copied. The schemas of these sub configs should set {@code realmCloneable} to {@code no} to 294 * avoid being copied. 295 * 296 * @return {@code true} if the config is cloneable between realms. 297 */ 298 public boolean isRealmCloneable() { 299 return ss.isRealmCloneable(); 300 } 301 302 /** 303 * Sets the CREST resource name for the service schema. 304 * 305 * @param name 306 * resource name. 307 * @throws SMSException 308 * if an error occurred while trying to perform the operation 309 * @throws SSOException 310 * if the single sign on token is invalid or expired 311 */ 312 public void setResourceName(String name) throws SMSException, SSOException { 313 SMSEntry.validateToken(ssm.getSSOToken()); 314 Node sNode = ss.getSchemaNode(); 315 ((Element) sNode).setAttribute(SMSUtils.RESOURCE_NAME, name); 316 ssm.replaceSchema((ServiceSchemaManagerImpl.getInstance(ssm.getSSOToken(), ssm.getName(), ssm.getVersion())) 317 .getDocument()); 318 ss.resourceName = name; 319 } 320 321 /** 322 * Returns the names of the schema attributes defined for the service. It 323 * does not return the schema attributes defined for the sub-schema. 324 * 325 * @return the names of schema attributes defined for the service 326 */ 327 public Set getAttributeSchemaNames() { 328 return (ss.getAttributeSchemaNames()); 329 } 330 331 /** 332 * Returns the names of the schema attributes defined for the service which 333 * are searchable. It does not return the schema attributes defined for the 334 * sub-schema. 335 * 336 * @return the names of schema attributes defined for the service which are 337 * searchable attributes. 338 */ 339 protected Set getSearchableAttributeNames() { 340 return (ss.getSearchableAttributeNames()); 341 } 342 343 /** 344 * Returns the schema for an attribute given the name of the attribute, 345 * defined for this service. It returns only the attribute schema defined at 346 * the top level for the service and not from the sub-schema. 347 * 348 * @param attributeName 349 * the name of the schema attribute 350 * @return the schema for the attribute 351 */ 352 public AttributeSchema getAttributeSchema(String attributeName) { 353 AttributeSchemaImpl as = ss.getAttributeSchema(attributeName); 354 return ((as == null) ? null : new AttributeSchema(as, ssm, this)); 355 } 356 357 /** 358 * Returns the attribute schemas defined for the service. It does not return 359 * the schema attributes defined for the sub-schema. 360 * 361 * @return attribute schemas defined for the service 362 */ 363 public Set<AttributeSchema> getAttributeSchemas() { 364 Set answer = new HashSet(); 365 for (Iterator items = getAttributeSchemaNames().iterator(); items 366 .hasNext();) { 367 String attrName = (String) items.next(); 368 answer.add(getAttributeSchema(attrName)); 369 } 370 return (answer); 371 } 372 373 /** 374 * Returns the attribute schemas defined for the service that is not a 375 * status attribute and is not a service attribute. It does not return the 376 * schema attributes defined for the sub-schema. 377 * 378 * @return attribute schemas defined for the service 379 */ 380 public Set getServiceAttributeNames() { 381 return (ss.getServiceAttributeNames()); 382 } 383 384 /** 385 * Validates the <code>attrMap</code> against the attributes defined in 386 * this schema of the service. It will throw an exception if the map 387 * contains any attribute not listed in the schema. It will also pick up 388 * default values for any attributes not in the map but which are listed in 389 * the schema, if the boolean <Code>inherit</Code> is set to true. 390 * 391 * @param attrMap 392 * map of attributes 393 * @param inherit 394 * if true, then inherit the default values 395 * @return Map of validated attributes with default values 396 * @throws SMSException 397 * if invalid attribute names are present in the 398 * <code>attrMap</code>. 399 */ 400 public Map validateAndInheritDefaults(Map attrMap, boolean inherit) 401 throws SMSException { 402 return (validateAndInheritDefaults(attrMap, null, inherit)); 403 } 404 405 /** 406 * Validates the <code>attrMap</code> against the attributes defined in 407 * this schema of the service for the given organization. It will throw an 408 * exception if the map contains any attribute not listed in the schema. It 409 * will also pick up default values for any attributes not in the map but 410 * which are listed in the schema, if the boolean <Code>inherit</Code> is 411 * set to true. 412 * 413 * @param attrMap 414 * map of attributes 415 * @param inherit 416 * if true, then inherit the default values 417 * @return Map of validated attributes with default values 418 * @throws SMSException 419 * if invalid attribute names are present in the 420 * <code>attrMap</code>. 421 */ 422 public Map validateAndInheritDefaults(Map attrMap, String orgName, 423 boolean inherit) throws SMSException { 424 SMSEntry.validateToken(ssm.getSSOToken()); 425 426 if (attrMap == null || attrMap.isEmpty()) { 427 attrMap = new HashMap(); 428 } 429 Iterator keys = attrMap.keySet().iterator(); 430 Set defAttrSet = ss.getAttributeSchemaNames(); 431 while (keys.hasNext()) { 432 String attr = (String) keys.next(); 433 if (!defAttrSet.contains(attr)) { 434 // This attribute is not listed in the service. 435 debug.error("ServiceSchema.validateAndInheritDefaults: " + attr 436 + " is not listed in the service " + getServiceName()); 437 throw new InvalidAttributeNameException( 438 IUMSConstants.UMS_BUNDLE_NAME, 439 "services_validator_invalid_attr_name", null); 440 } 441 } 442 443 // If orgName is not null, populate the envMap 444 Map envMap = Collections.EMPTY_MAP; 445 if (orgName != null) { 446 envMap = new HashMap(); 447 envMap.put(Constants.ORGANIZATION_NAME, orgName); 448 envMap.put(Constants.SSO_TOKEN, ssm.getSSOToken()); 449 } 450 Iterator ass = ss.getAttributeSchemaNames().iterator(); 451 while (ass.hasNext()) { 452 String attr = (String) ass.next(); 453 AttributeSchemaImpl as = ss.getAttributeSchema(attr); 454 AttributeValidator av = ss.getAttributeValidator(attr); 455 String anyValue = as.getAny(); 456 if (inherit && (anyValue != null) && 457 (anyValue.indexOf("required") > -1)) { 458 // Inherit default values of this attribute, if 459 // required 460 attrMap = av.inheritDefaults(attrMap); 461 Set attrVals = (Set) attrMap.get(attr); 462 if (attrVals == null || attrVals.isEmpty()) { 463 // A required attribute is being deleted 464 // throw an exception. 465 debug.error("ServiceSchema.validateAndInheritDefaults: " 466 + attr + " is a required attribute and cannot" 467 + " be deleted"); 468 Object args[] = { attr }; 469 throw new SMSException(IUMSConstants.UMS_BUNDLE_NAME, 470 "sms-required-attribute-delete", args); 471 } 472 } else if (inherit) { 473 attrMap = av.inheritDefaults(attrMap); 474 } 475 // validate the attribute against Schema 476 Set valSet = (Set) attrMap.get(attr); 477 if (valSet != null) { 478 String i18nFileName = (ssm != null) ? ssm.getI18NFileName() 479 : null; 480 av.validate(valSet, i18nFileName, false, envMap); 481 } 482 } 483 if (debug.messageEnabled()) { 484 debug.error("ServiceSchema.validate&InheritDef: " 485 + " returning attrMap: " + attrMap.toString()); 486 } 487 return attrMap; 488 } 489 490 /** 491 * Adds the attribute schema to this service. The schema is defined in XML 492 * input stream that follows the SMS DTD. 493 * 494 * @param xmlAttrSchema 495 * the XML format of the attribute schema 496 * @throws SMSException 497 * if an error occurred while performing the operation 498 * @throws SSOException 499 * if the single sign on token is invalid or expired 500 */ 501 public void addAttributeSchema(InputStream xmlAttrSchema) 502 throws SSOException, SMSException { 503 SMSEntry.validateToken(ssm.getSSOToken()); 504 // Check if attribute exists 505 Document doc = SMSSchema.getXMLDocument(xmlAttrSchema, false); 506 NodeList nl = doc.getElementsByTagName(SMSUtils.SCHEMA_ATTRIBUTE); 507 CaseInsensitiveHashSet asNames = 508 new CaseInsensitiveHashSet(ss.getAttributeSchemaNames()); 509 for (int i = 0; i < nl.getLength(); i++) { 510 Node node = nl.item(i); 511 AttributeSchemaImpl as = new AttributeSchemaImpl(node); 512 if (asNames.contains(as.getName())) { 513 Object[] args = { as.getName() }; 514 throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, 515 "sms-attributeschema-already-exists", args)); 516 } 517 } 518 appendAttributeSchema(nl); 519 } 520 521 /** 522 * Removes the attribute schema from this service. 523 * 524 * @param attrName 525 * the name of the attribute schema 526 * @throws SMSException 527 * if an error occurred while performing the operation 528 * @throws SSOException 529 * if the single sign on token is invalid or expired 530 */ 531 public void removeAttributeSchema(String attrName) throws SSOException, 532 SMSException { 533 removeChildNode(SMSUtils.SCHEMA_ATTRIBUTE, attrName); 534 } 535 536 /** 537 * Returns a map of all the attribute and their default values in this 538 * schema. 539 * 540 * @return Map of Attribute Names and Sets of their default values as 541 * defined in the Schema 542 */ 543 public Map<String, Set<String>> getAttributeDefaults() { 544 return (ss.getAttributeDefaults()); 545 } 546 547 /** 548 * Returns a map of all the attribute and their example values in this 549 * schema. 550 * 551 * @return Map of Attribute Names and Sets of their example values as 552 * defined in the Schema 553 */ 554 public Map<String, Set<String>> getAttributeExamples() { 555 return (ss.getAttributeExamples()); 556 } 557 558 /** 559 * Returns an unmodifiable map of all the attribute and their default values 560 * in this schema. 561 * 562 * @return Map of Attribute Names and Sets of their default values as 563 * defined in the Schema 564 */ 565 public Map getReadOnlyAttributeDefaults() { 566 return (ss.getReadOnlyAttributeDefaults()); 567 } 568 569 /** 570 * Method to change the default values of attributes in the schema. 571 * 572 * @param attrs 573 * A map of the names of <code>AttributeSchema</code> to 574 * modify, and a Set of Values which should replace the default 575 * values of the current schema. 576 * @throws SMSException 577 * if an error occurred while performing the operation 578 * @throws SSOException 579 * if the single sign on token is invalid or expired 580 */ 581 public void setAttributeDefaults(Map attrs) throws SSOException, 582 SMSException { 583 SMSEntry.validateToken(ssm.getSSOToken()); 584 // Get a copy of the XML document 585 Document document = ssm.getDocumentCopy(); 586 Iterator items = attrs.keySet().iterator(); 587 while (items.hasNext()) { 588 String attrName = (String) items.next(); 589 AttributeSchema as = getAttributeSchema(attrName); 590 if (as == null) { 591 Object[] args = { attrName }; 592 throw (new SchemaException(IUMSConstants.UMS_BUNDLE_NAME, 593 "sms-invalid-attr-name", args)); 594 } 595 as.setDefaultValues((Set) attrs.get(attrName), document); 596 } 597 // Save the document 598 ssm.replaceSchema(document); 599 } 600 601 /** 602 * Method to change default value for a specific attribute. 603 * 604 * @param attrName 605 * Name of the attribute for which defaults values need to be 606 * replaced. 607 * @param values 608 * Set of new values to replace the old ones. 609 * @throws SchemaException 610 * if an error occurred while parsing the XML 611 * @throws SMSException 612 * if an error occurred while performing the operation 613 * @throws SSOException 614 * if the single sign on token is invalid or expired 615 */ 616 public void setAttributeDefaults(String attrName, Set values) 617 throws SchemaException, SMSException, SSOException { 618 SMSEntry.validateToken(ssm.getSSOToken()); 619 AttributeSchema as = getAttributeSchema(attrName); 620 if (as == null) { 621 Object[] args = { attrName }; 622 throw (new SchemaException(IUMSConstants.UMS_BUNDLE_NAME, 623 "sms-invalid-attr-name", args)); 624 } 625 as.setDefaultValues(values); 626 } 627 628 /** 629 * Removes the default values of attributes in the schema. 630 * 631 * @param attrs 632 * A set of the names of <code>AttributeSchema</code>. 633 * @throws SMSException 634 * if an error occurred while performing the operation 635 * @throws SSOException 636 * if the single sign on token is invalid or expired 637 */ 638 public void removeAttributeDefaults(Set attrs) throws SMSException, 639 SSOException { 640 SMSEntry.validateToken(ssm.getSSOToken()); 641 Iterator it = attrs.iterator(); 642 while (it.hasNext()) { 643 String asName = (String) it.next(); 644 AttributeSchema as = getAttributeSchema(asName); 645 if (as == null) { 646 throw (new InvalidAttributeNameException( 647 IUMSConstants.UMS_BUNDLE_NAME, 648 IUMSConstants.services_validator_invalid_attr_name, 649 null)); 650 } 651 as.removeDefaultValues(); 652 } 653 } 654 655 /** 656 * Returns the names of sub-schemas for the service. 657 * 658 * @return the names of service's sub-schemas 659 */ 660 public Set<String> getSubSchemaNames() { 661 return ss.getSubSchemaNames(); 662 } 663 664 /** 665 * Returns <code>ServiceSchema</code> object given the name of the 666 * service's sub-schema. 667 * 668 * @param subSchemaName 669 * the name of the service's sub-schema 670 * @return <code>ServiceSchema</code> object 671 * @throws SMSException 672 * if an error occurred while performing the operation 673 * 674 */ 675 public ServiceSchema getSubSchema(String subSchemaName) throws SMSException 676 { 677 SMSEntry.validateToken(ssm.getSSOToken()); 678 ServiceSchema answer = null; 679 ServiceSchemaImpl ssi = ss.getSubSchema(subSchemaName); 680 if (ssi != null) { 681 answer = new ServiceSchema(ssi, 682 componentName + "/" + subSchemaName, type, ssm); 683 } 684 return (answer); 685 } 686 687 /** 688 * Adds the service's sub-schema given the XML input stream that follows the 689 * SMS DTD. 690 * 691 * @param xmlSubSchema 692 * the XML format of the sub-schema 693 * @throws SMSException 694 * if an error occurred while performing the operation 695 * @throws SSOException 696 * if the single sign on token is invalid or expired 697 */ 698 public void addSubSchema(InputStream xmlSubSchema) throws SSOException, 699 SMSException { 700 SMSEntry.validateToken(ssm.getSSOToken()); 701 // Check if attribute exists 702 Document doc = SMSSchema.getXMLDocument(xmlSubSchema, false); 703 NodeList nl = doc.getElementsByTagName(SMSUtils.SUB_SCHEMA); 704 Set asNames = ss.getSubSchemaNames(); 705 for (int i = 0; i < nl.getLength(); i++) { 706 Node node = nl.item(i); 707 String nodeName = XMLUtils.getNodeAttributeValue(node, 708 SMSUtils.NAME); 709 if (asNames.contains(nodeName)) { 710 Object[] args = { nodeName }; 711 throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, 712 "sms-subschema-already-exists", args)); 713 } 714 } 715 716 appendSubSchema(doc); 717 } 718 719 /** 720 * Removes the service's sub-schema from the service. 721 * 722 * @param subSchemaName 723 * the name of the service's sub-schema 724 * @throws SMSException 725 * if an error occurred while performing the operation 726 * @throws SSOException 727 * if the single sign on token is invalid or expired 728 */ 729 public void removeSubSchema(String subSchemaName) throws SSOException, 730 SMSException { 731 SMSEntry.validateToken(ssm.getSSOToken()); 732 removeChildNode(SMSUtils.SUB_SCHEMA, subSchemaName); 733 } 734 735 /** 736 * Determines whether each attribute in the attribute set is valid. Iterates 737 * though the set checking each element to see if there is a validator that 738 * needs to execute. 739 * 740 * @param attributeSet 741 * the <code>Map</code> where key is the attribute name and 742 * value is the <code>Set</code> of attribute values 743 * @return true if all attributes are valid 744 * @throws SMSException 745 * if an error occurred while performing the operation 746 */ 747 public boolean validateAttributes(Map attributeSet) throws SMSException { 748 SMSEntry.validateToken(ssm.getSSOToken()); 749 return (ss.validateAttributes(ssm.getSSOToken(), attributeSet, false, 750 null)); 751 } 752 753 /** 754 * Determines whether each attribute in the attribute set is valid for the 755 * given organization. Iterates though the set checking each element to see 756 * if there is a validator that needs to execute. 757 * 758 * @param attributeSet 759 * the <code>Map</code> where key is the attribute name and 760 * value is the <code>Set</code> of attribute values 761 * @param orgName 762 * organization name 763 * @return true if all attributes are valid 764 * @throws SMSException 765 * if an error occurred while performing the operation 766 */ 767 public boolean validateAttributes(Map attributeSet, String orgName) 768 throws SMSException { 769 SMSEntry.validateToken(ssm.getSSOToken()); 770 return (ss.validateAttributes(ssm.getSSOToken(), attributeSet, false, 771 orgName)); 772 } 773 774 /** 775 * Returns string representation of the schema. 776 * 777 * @return string representation of the schema. 778 */ 779 public String toString() { 780 return (ss.toString()); 781 } 782 783 /** 784 * Returns the Node of this schema element. Used by Policy component's 785 * <code>ServiceType</code> to get <code>ActionSchema</code>. 786 * 787 * @return the Node of this schema element. Used by Policy component's 788 * <code>ServiceType</code> to get <code>ActionSchema</code>. 789 */ 790 public Node getSchemaNode() { 791 Node node = null; 792 try { 793 node = getSchemaNode(ssm.getDocumentCopy()); 794 } catch (SMSException ssme) { 795 debug.error("ServiceSchema::getSchemaNode: invalid schema"); 796 } 797 return (node); 798 } 799 800 /** 801 * Removes the attribute schema from this service. 802 * 803 * @param attrName 804 * the name of the attribute schema 805 * @throws SMSException 806 * if an error occurred while performing the operation 807 * @throws SSOException 808 * if the single sign on token is invalid or expired 809 */ 810 public void replaceAttributeSchema(String attrName, Node attributeSchemaNode) throws SSOException, 811 SMSException { 812 replaceChildNode(SMSUtils.SCHEMA_ATTRIBUTE, attrName, attributeSchemaNode); 813 } 814 815 private void appendAttributeSchema(NodeList nodes) throws SSOException, SMSException { 816 if (nodes == null || nodes.getLength() == 0) { 817 throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, 818 IUMSConstants.SMS_SMSSchema_no_schema_element, null)); 819 } 820 Document schemaDoc = ssm.getDocumentCopy(); 821 try { 822 Node schemaNode = getSchemaNode(schemaDoc); 823 NodeList childrens = schemaNode.getChildNodes(); 824 Node nextSibling = null; 825 for (int i = 0; i < childrens.getLength(); i++) { 826 Node child = childrens.item(i); 827 if (Node.ELEMENT_NODE == child.getNodeType() 828 && !SMSUtils.SCHEMA_ATTRIBUTE.equals(child.getNodeName())) { 829 nextSibling = child; 830 break; 831 } 832 } 833 for (int i = 0; i < nodes.getLength(); i++) { 834 Node node = nodes.item(i); 835 Node iNode = schemaDoc.importNode(node, true); 836 schemaNode.insertBefore(iNode, nextSibling); 837 } 838 } catch (Exception e) { 839 throw (new SMSException(e.getMessage(), e, "sms-cannot_append_NODE")); 840 } 841 ssm.replaceSchema(schemaDoc); 842 } 843 844 private void appendSubSchema(Document doc) throws SSOException, SMSException { 845 if (doc == null) { 846 throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, 847 IUMSConstants.SMS_SMSSchema_no_schema_element, null)); 848 } 849 850 Document schemaDoc = ssm.getDocumentCopy(); 851 852 try { 853 Node schemaNode = getSchemaNode(schemaDoc); 854 Node node = XMLUtils.getRootNode(doc, SMSUtils.SUB_SCHEMA); 855 NodeList childrens = schemaNode.getChildNodes(); 856 Node nextSibling = null; 857 for (int i = 0; i < childrens.getLength(); i++) { 858 Node child = childrens.item(i); 859 if (Node.ELEMENT_NODE == child.getNodeType() 860 && !SMSUtils.SCHEMA_ATTRIBUTE.equals(child.getNodeName())) { 861 //In this case we've found an entry that is not an AttributeSchema, so this is definitely an 862 //element before which we can place a SubSchema. (i.e. the found element was a SubSchema or 863 //an OrganizationAttributeSchema). Note that this will change the order of the SubSchema 864 //elements in the service description, however the order should not matter for SMS. 865 nextSibling = child; 866 break; 867 } 868 } 869 Node iNode = schemaDoc.importNode(node, true); 870 schemaNode.insertBefore(iNode, nextSibling); 871 } catch (Exception ex) { 872 throw (new SMSException(ex.getMessage(), ex, "sms-cannot_append_NODE")); 873 } 874 875 ssm.replaceSchema(schemaDoc); 876 } 877 878 // ----------------------------------------------------------- 879 // Protected methods 880 // ----------------------------------------------------------- 881 void removeChildNode(String nodeType, String nodeName) throws SSOException, 882 SMSException { 883 if (debug.messageEnabled()) { 884 debug.message("ServiceSchema::removeChildNode called for: " 885 + getServiceName() + "(" + ssm.getVersion() + ") " 886 + componentName); 887 } 888 Document schemaDoc = ssm.getDocumentCopy(); 889 Node schemaNode = getSchemaNode(schemaDoc); 890 if (schemaNode != null) { 891 Node node = XMLUtils.getNamedChildNode(schemaNode, nodeType, 892 SMSUtils.NAME, nodeName); 893 if (node != null) { 894 schemaNode.removeChild(node); 895 ssm.replaceSchema(schemaDoc); 896 } 897 } 898 } 899 900 void replaceChildNode(String nodeType, String nodeName, Node attributeSchemaNode) throws SSOException, 901 SMSException { 902 if (debug.messageEnabled()) { 903 debug.message("ServiceSchema::replaceChildNode called for: " 904 + getServiceName() + "(" + ssm.getVersion() + ") " 905 + componentName); 906 } 907 Document schemaDoc = ssm.getDocumentCopy(); 908 Node schemaNode = getSchemaNode(schemaDoc); 909 if (schemaNode != null) { 910 Node oldNode = XMLUtils.getNamedChildNode(schemaNode, nodeType, 911 SMSUtils.NAME, nodeName); 912 if (oldNode != null) { 913 Node newNode = schemaDoc.importNode(attributeSchemaNode, true); 914 schemaNode.replaceChild(newNode, oldNode); 915 ssm.replaceSchema(schemaDoc); 916 } 917 } else { 918 if (debug.messageEnabled()) { 919 debug.message("ServiceSchema::replaceChildNode failed to retrieve service schema for : " 920 + getServiceName() + "(" + ssm.getVersion() + ") " 921 + componentName); 922 } 923 } 924 } 925 926 // ----------------------------------------------------------- 927 // Method to obtain schema node 928 // ----------------------------------------------------------- 929 Node getSchemaNode(Document document) throws SMSException { 930 NodeList nodes = document.getElementsByTagName(SMSUtils.SCHEMA); 931 if ((nodes == null) || (nodes.getLength() == 0)) { 932 throwInvalidSchemaException(); 933 } 934 Node rNode = nodes.item(0); 935 936 // Get the schema type node 937 String schemaType = SMSUtils.GLOBAL_SCHEMA; 938 if (type.equals(SchemaType.ORGANIZATION)) { 939 schemaType = SMSUtils.ORG_SCHEMA; 940 } else if (type.equals(SchemaType.DYNAMIC)) { 941 schemaType = SMSUtils.DYNAMIC_SCHEMA; 942 } else if (type.equals(SchemaType.USER)) { 943 schemaType = SMSUtils.USER_SCHEMA; 944 } else if (type.equals(SchemaType.POLICY)) { 945 schemaType = SMSUtils.POLICY_SCHEMA; 946 } else if (type.equals(SchemaType.GROUP)) { 947 schemaType = SMSUtils.GROUP_SCHEMA; 948 } else if (type.equals(SchemaType.DOMAIN)) { 949 schemaType = SMSUtils.DOMAIN_SCHEMA; 950 } 951 952 Node stNode = XMLUtils.getChildNode(rNode, schemaType); 953 if (stNode == null) { 954 throwInvalidSchemaException(); 955 } 956 957 // Walk the component name 958 if ((componentName == null) || (componentName.length() == 0)) { 959 return (stNode); 960 } else if (orgAttrSchema) { 961 // OrganizationAttributeSchema 962 return (XMLUtils 963 .getChildNode(stNode, SMSUtils.ORG_ATTRIBUTE_SCHEMA)); 964 } 965 966 StringTokenizer st = new StringTokenizer(componentName, "/"); 967 while (st.hasMoreTokens()) { 968 String tokenName = st.nextToken(); 969 if ((tokenName == null) || (tokenName.length() == 0)) { 970 continue; 971 } 972 if ((stNode = XMLUtils.getNamedChildNode(stNode, 973 SMSUtils.SUB_SCHEMA, SMSUtils.NAME, tokenName)) == null) { 974 throwInvalidSchemaException(); 975 } 976 } 977 return (stNode); 978 } 979 980 // ----------------------------------------------------------- 981 // Method to obtain organizationattributeschema node 982 // ----------------------------------------------------------- 983 Node getOrgAttrSchemaNode(Document doc) throws SMSException { 984 NodeList nodes = doc.getElementsByTagName( 985 SMSUtils.ORG_ATTRIBUTE_SCHEMA); 986 if (nodes == null || (nodes.getLength() == 0)) { 987 // Throw an exception 988 throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, 989 "sms-invalid-orgattr-schema-document", null)); 990 } 991 Node rNode = nodes.item(0); 992 if (rNode == null) { 993 throwInvalidSchemaException(); 994 } 995 return (rNode); 996 } 997 998 void throwInvalidSchemaException() throws SMSException { 999 SMSEntry.debug.error("ServiceSchema::getSchemaNode: " 1000 + "Invalid service schema XML: " + getServiceName() + "(" 1001 + ssm.getVersion() + ")"); 1002 throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, 1003 IUMSConstants.SMS_SMSSchema_no_service_element, null)); 1004 } 1005 1006 Debug debug = Debug.getInstance("amSMS"); 1007}