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: ServiceSchemaManager.java,v 1.12 2009/07/25 05:11:55 qcheng Exp $ 026 * 027 * Portions Copyrighted 2012-2016 ForgeRock AS. 028 */ 029package com.sun.identity.sm; 030 031import com.iplanet.services.util.AMEncryption; 032import com.iplanet.sso.SSOException; 033import com.iplanet.sso.SSOToken; 034import com.iplanet.ums.IUMSConstants; 035import com.sun.identity.shared.debug.Debug; 036import com.sun.identity.shared.xml.XMLUtils; 037import java.io.IOException; 038import java.io.InputStream; 039import java.util.Collections; 040import java.util.HashSet; 041import java.util.Iterator; 042import java.util.Set; 043import org.forgerock.util.Function; 044import org.w3c.dom.Document; 045import org.w3c.dom.Node; 046 047/** 048 * The class <code>ServiceSchemaManager</code> provides interfaces to manage 049 * the service's schema. It provides access to <code>ServiceSchema</code>, 050 * which represents a single "schema" in the service. 051 * 052 * @supported.api 053 */ 054public class ServiceSchemaManager { 055 056 private SSOToken token; 057 058 private String serviceName; 059 060 private String version; 061 062 private ServiceSchemaManagerImpl ssm; 063 064 private static Debug debug = Debug.getInstance("amSMS"); 065 066 /** 067 * Constructor for service's schema manager to manage the attributes and 068 * sub configurations. Assumes service version number to be <class>1.0 069 * </class>. 070 * 071 * @throws SMSException 072 * if an error occurred while trying to perform the operation 073 * @throws SSOException 074 * if the single sign on token is invalid or expired 075 */ 076 public ServiceSchemaManager(String serviceName, SSOToken token) 077 throws SMSException, SSOException { 078 this(token, serviceName, ServiceManager.isCoexistenceMode() ? 079 ServiceManager.serviceDefaultVersion(token, serviceName) : 080 ServiceManager.getVersion(serviceName)); 081 } 082 083 /** 084 * Creates an instance of 085 * <code>ServiceSchemaManager</code> for the given service and version 086 * pair. It requires an user identity, that will used to perform operations 087 * with. It is assumed that the application calling this constructor should 088 * authenticate the user. 089 * 090 * @param token 091 * single sign on token of the user identity on whose behalf the 092 * operations are performed. 093 * @param serviceName 094 * the name of the service. 095 * @param version 096 * the version of the service. 097 * @throws SMSException 098 * if an error occurred while trying to perform the operation 099 * @throws SSOException 100 * if the single sign on token is invalid or expired 101 * 102 * @supported.api 103 */ 104 public ServiceSchemaManager(SSOToken token, String serviceName, 105 String version) throws SMSException, SSOException { 106 if (token == null || serviceName == null || version == null) { 107 throw new IllegalArgumentException(SMSEntry.bundle 108 .getString(IUMSConstants.SMS_INVALID_PARAMETERS)); 109 } 110 SMSEntry.validateToken(token); 111 this.token = token; 112 this.serviceName = serviceName; 113 this.version = version; 114 ssm = ServiceSchemaManagerImpl.getInstance(token, serviceName, version); 115 } 116 117 /** 118 * Returns the name of the service. 119 * 120 * @return the name of the service 121 * 122 * @supported.api 123 */ 124 public String getName() { 125 return (serviceName); 126 } 127 128 /** 129 * Returns the version of the service. 130 * 131 * @return the version of the service 132 * 133 * @supported.api 134 */ 135 public String getVersion() { 136 return (version); 137 } 138 139 /** 140 * Returns the I18N properties file name for the 141 * service. 142 * 143 * @return the I18N properties file name for the service 144 * 145 * @supported.api 146 */ 147 public String getI18NFileName() { 148 validate(); 149 return (ssm.getI18NFileName()); 150 } 151 152 /** 153 * Sets the I18N properties file name for the service 154 * 155 * @param url 156 * properties file name 157 * @throws SMSException 158 * if an error occurred while trying to perform the operation 159 * @throws SSOException 160 * if the single sign on token is invalid or expired 161 * 162 * @supported.api 163 */ 164 public void setI18NFileName(String url) throws SMSException, SSOException { 165 SMSEntry.validateToken(token); 166 validateServiceSchemaManagerImpl(); 167 String tmpS = ssm.getI18NFileName(); 168 ssm.setI18NFileName(url); 169 try { 170 replaceSchema(ssm.getDocument()); 171 } catch (SMSException se) { 172 ssm.setI18NFileName(tmpS); 173 throw se; 174 } 175 } 176 177 /** 178 * Returns the URL of the JAR file that contains the 179 * I18N properties file. The method could return null, in which case the 180 * properties file should be in <code>CLASSPATH</code>. 181 * 182 * @return the URL of the JAR file containing the <code>I18N</code> 183 * properties file. 184 * 185 * @supported.api 186 */ 187 public String getI18NJarURL() { 188 validate(); 189 return (ssm.getI18NJarURL()); 190 } 191 192 /** 193 * Sets the URL of the JAR file that contains the I18N 194 * properties 195 * 196 * @param url 197 * URL 198 * @throws SMSException 199 * if an error occurred while trying to perform the operation 200 * @throws SSOException 201 * if the single sign on token is invalid or expired 202 * 203 * @supported.api 204 */ 205 206 public void setI18NJarURL(String url) throws SMSException, SSOException { 207 SMSEntry.validateToken(token); 208 validateServiceSchemaManagerImpl(); 209 String tmpS = ssm.getI18NJarURL(); 210 ssm.setI18NJarURL(url); 211 try { 212 replaceSchema(ssm.getDocument()); 213 } catch (SMSException se) { 214 ssm.setI18NJarURL(tmpS); 215 throw se; 216 } 217 } 218 219 /** 220 * Returns the service's hierarchy. 221 * 222 * @return service hierarchy in slash format. 223 * 224 * @supported.api 225 */ 226 public String getServiceHierarchy() { 227 validate(); 228 return (ssm.getServiceHierarchy()); 229 } 230 231 /** 232 * Sets the service's hierarchy 233 * 234 * @param newhierarchy 235 * service hierarchy 236 * @throws SMSException 237 * if an error occurred while trying to perform the operation 238 * @throws SSOException 239 * if the single sign on token is invalid or expired 240 * 241 * @supported.api 242 */ 243 public void setServiceHierarchy(String newhierarchy) throws SMSException, 244 SSOException { 245 SMSEntry.validateToken(token); 246 validateServiceSchemaManagerImpl(); 247 String tmpS = getServiceHierarchy(); 248 ssm.setServiceHierarchy(newhierarchy); 249 try { 250 replaceSchema(ssm.getDocument()); 251 } catch (SMSException e) { 252 ssm.setServiceHierarchy(tmpS); 253 throw e; 254 } 255 } 256 257 /** 258 * Returns i18nKey of the schema. 259 * 260 * @return i18nKey of the schema. 261 * 262 * @supported.api 263 */ 264 public String getI18NKey() { 265 validate(); 266 return (ssm.getI18NKey()); 267 } 268 269 /** 270 * Sets the i18nKey of the schema. 271 * 272 * @param i18nKey 273 * <code>i18nKey</code> of the schema. 274 * @throws SMSException 275 * if an error occurred while trying to perform the operation. 276 * @throws SSOException 277 * if the single sign on token is invalid or expired. 278 * 279 * @supported.api 280 */ 281 public void setI18NKey(String i18nKey) throws SMSException, SSOException { 282 SMSEntry.validateToken(token); 283 validateServiceSchemaManagerImpl(); 284 String tmp = ssm.getI18NKey(); 285 ssm.setI18NKey(i18nKey); 286 287 try { 288 replaceSchema(ssm.getDocument()); 289 } catch (SMSException e) { 290 ssm.setI18NKey(tmp); 291 throw e; 292 } 293 } 294 295 /** 296 * Returns URL of the view bean for the service 297 * 298 * @return URL for view bean 299 * 300 * @supported.api 301 */ 302 public String getPropertiesViewBeanURL() { 303 validate(); 304 return (ssm.getPropertiesViewBeanURL()); 305 } 306 307 /** 308 * Sets the URL of the view bean for the service. 309 * 310 * @param url 311 * of the view bean for the service. 312 * @throws SMSException 313 * if an error occurred while trying to perform the operation. 314 * @throws SSOException 315 * if the single sign on token is invalid or expired. 316 * 317 * @supported.api 318 */ 319 public void setPropertiesViewBeanURL(String url) throws SMSException, 320 SSOException { 321 SMSEntry.validateToken(token); 322 validateServiceSchemaManagerImpl(); 323 String tmpS = ssm.getPropertiesViewBeanURL(); 324 ssm.setPropertiesViewBeanURL(url); 325 try { 326 replaceSchema(ssm.getDocument()); 327 } catch (SMSException e) { 328 ssm.setPropertiesViewBeanURL(tmpS); 329 throw e; 330 } 331 } 332 333 /** 334 * Returns the service's resource name for CREST representation, or the 335 * service name if a resource name is not defined. 336 * @supported.api 337 */ 338 public String getResourceName() { 339 validate(); 340 String resourceName = ssm.getResourceName(); 341 return resourceName == null ? getName() : resourceName; 342 } 343 344 /** 345 * Sets the service's resource name for CREST representation. 346 * 347 * @param name 348 * resource name for CREST representation 349 * @throws SMSException 350 * if an error occurred while trying to perform the operation 351 * @throws SSOException 352 * if the single sign on token is invalid or expired 353 * 354 * @supported.api 355 */ 356 public void setResourceName(String name) throws SMSException, 357 SSOException { 358 SMSEntry.validateToken(token); 359 validateServiceSchemaManagerImpl(); 360 String tmpS = getResourceName(); 361 ssm.setResourceName(name); 362 try { 363 replaceSchema(ssm.getDocument()); 364 } catch (SMSException e) { 365 ssm.setResourceName(tmpS); 366 throw e; 367 } 368 } 369 370 /** 371 * iPlanet_PUBLIC-METHOD Returns the revision number of the service schema. 372 * 373 * @return the revision number of the service schema 374 */ 375 public int getRevisionNumber() { 376 validate(); 377 return (ssm.getRevisionNumber()); 378 } 379 380 /** 381 * iPlanet_PUBLIC-METHOD Sets the revision number for the service schema. 382 * 383 * @param revisionNumber 384 * revision number of the service schema. 385 * @throws SMSException 386 * if there is a problem setting the value in the data store. 387 * @throws SSOException 388 * If the user has an invalid SSO token. 389 */ 390 public void setRevisionNumber(int revisionNumber) throws SMSException, 391 SSOException { 392 SMSEntry.validateToken(token); 393 validateServiceSchemaManagerImpl(); 394 int tmpS = ssm.getRevisionNumber(); 395 ssm.setRevisionNumber(revisionNumber); 396 try { 397 replaceSchema(ssm.getDocument()); 398 } catch (SMSException e) { 399 ssm.setRevisionNumber(tmpS); 400 throw (e); 401 } 402 } 403 404 /** 405 * Returns the schema types available with this 406 * service. 407 * 408 * @return set of <code>SchemaTypes</code> in this service. 409 * @throws SMSException 410 * if an error occurred while trying to perform the operation 411 * 412 * @supported.api 413 */ 414 public Set<SchemaType> getSchemaTypes() throws SMSException { 415 SMSEntry.validateToken(token); 416 validate(); 417 return (ssm.getSchemaTypes()); 418 } 419 420 /** 421 * Returns the configuration schema for the given 422 * schema type 423 * 424 * @param type 425 * schema type. 426 * @return service schema. 427 * @throws SMSException 428 * if an error occurred while trying to perform the operation 429 * 430 * @supported.api 431 */ 432 public ServiceSchema getSchema(String type) throws SMSException { 433 validate(); 434 SchemaType t = null; 435 if (type.equalsIgnoreCase("role") 436 || type.equalsIgnoreCase("filteredrole") 437 || type.equalsIgnoreCase("realm")) { 438 t = SchemaType.DYNAMIC; 439 } else if (type.equalsIgnoreCase("user")) { 440 t = SchemaType.USER; 441 } else { 442 t = new SchemaType(type); 443 } 444 return (getSchema(t)); 445 } 446 447 /** 448 * Returns the configuration schema for the given 449 * schema type 450 * 451 * @param type 452 * schema type. 453 * @return service schema. 454 * @throws SMSException 455 * if an error occurred while trying to perform the operation 456 * 457 * @supported.api 458 */ 459 public ServiceSchema getSchema(SchemaType type) throws SMSException { 460 SMSEntry.validateToken(token); 461 validate(); 462 ServiceSchemaImpl ss = ssm.getSchema(type); 463 if ((ss == null) && type.equals(SchemaType.USER)) { 464 type = SchemaType.DYNAMIC; 465 ss = ssm.getSchema(type); 466 } 467 if (ss != null) { 468 return (new ServiceSchema(ss, "", type, this)); 469 } 470 return (null); 471 } 472 473 /** 474 * Returns the organization creation configuration schema if present; else 475 * returns <code>null</code> 476 * 477 * @return service schema. 478 * @throws SMSException 479 * if an error occurred while trying to perform the operation 480 */ 481 public ServiceSchema getOrganizationCreationSchema() throws SMSException { 482 SMSEntry.validateToken(token); 483 validate(); 484 ServiceSchemaImpl ss = ssm.getSchema(SchemaType.ORGANIZATION); 485 if (ss != null) { 486 ServiceSchemaImpl ssi = ss.getOrgAttrSchema(); 487 if (ssi != null) { 488 return (new ServiceSchema(ssi, "", SchemaType.ORGANIZATION, 489 this, true)); 490 } 491 } 492 return (null); 493 } 494 495 /** 496 * Returns the attribute schemas for the given schema 497 * type excluding status and service identifier attributes. 498 * 499 * @param type 500 * schema type. 501 * @return service schema. 502 * @throws SMSException 503 * if an error occurred while trying to perform the operation 504 * 505 * @supported.api 506 */ 507 public Set getServiceAttributeNames(SchemaType type) throws SMSException { 508 SMSEntry.validateToken(token); 509 validate(); 510 ServiceSchema ss = getSchema(type); 511 return (ss.getServiceAttributeNames()); 512 } 513 514 /** 515 * Returns the global service configuration schema. 516 * 517 * @return the global service configuration schema 518 * @throws SMSException 519 * if an error occurred while trying to perform the operation 520 * 521 * @supported.api 522 */ 523 public ServiceSchema getGlobalSchema() throws SMSException { 524 return (getSchema(SchemaType.GLOBAL)); 525 } 526 527 /** 528 * Returns the organization service configuration 529 * schema. 530 * 531 * @return the organization service configuration schema 532 * @throws SMSException 533 * if an error occurred while trying to perform the operation 534 * 535 * @supported.api 536 */ 537 public ServiceSchema getOrganizationSchema() throws SMSException { 538 return (getSchema(SchemaType.ORGANIZATION)); 539 } 540 541 /** 542 * Returns the dynamic service configuration schema. 543 * 544 * @return the dynamic service configuration schema 545 * @throws SMSException 546 * if an error occurred while trying to perform the operation 547 * 548 * @supported.api 549 */ 550 public ServiceSchema getDynamicSchema() throws SMSException { 551 return (getSchema(SchemaType.DYNAMIC)); 552 } 553 554 /** 555 * Returns the user service configuration schema. 556 * 557 * @return the user service configuration schema 558 * @throws SMSException 559 * if an error occurred while trying to perform the operation 560 * 561 * @supported.api 562 */ 563 public ServiceSchema getUserSchema() throws SMSException { 564 return (getSchema(SchemaType.USER)); 565 } 566 567 /** 568 * Returns the policy service configuration schema. 569 * 570 * @return the policy service configuration schema 571 * @throws SMSException 572 * if an error occurred while trying to perform the operation 573 * 574 * @supported.api 575 */ 576 public ServiceSchema getPolicySchema() throws SMSException { 577 return (getSchema(SchemaType.POLICY)); 578 } 579 580 /** 581 * Returns the service schema in XML for this service. 582 * 583 * @return the service schema in XML for this service 584 * @throws SMSException 585 * if an error occurred while trying to perform the operation 586 * 587 * @supported.api 588 */ 589 public InputStream getSchema() throws SMSException { 590 SMSEntry.validateToken(token); 591 validate(); 592 return (ssm.getSchema()); 593 } 594 595 /** 596 * Replaces the existing service schema with the given 597 * schema defined by the XML input stream that follows the SMS DTD. 598 * 599 * @param xmlServiceSchema 600 * the XML format of the service schema 601 * @throws SMSException 602 * if an error occurred while trying to perform the operation 603 * @throws SSOException 604 * if the single sign on token is invalid or expired 605 * @throws IOException 606 * if an error occurred with the <code> InputStream </code> 607 * 608 * @supported.api 609 */ 610 public void replaceSchema(InputStream xmlServiceSchema) 611 throws SSOException, SMSException, IOException { 612 SMSEntry.validateToken(token); 613 validateServiceSchemaManagerImpl(); 614 CachedSMSEntry smsEntry = ssm.getCachedSMSEntry(); 615 smsEntry.writeXMLSchema(token, xmlServiceSchema); 616 } 617 618 // @Override 619 public int hashCode() { 620 int hash = 7; 621 hash = 67 * hash + (serviceName != null ? serviceName.hashCode() : 0); 622 hash = 67 * hash + (version != null ? version.hashCode() : 0); 623 return hash; 624 } 625 626 /** 627 * Returns true if the given object equals this 628 * object. 629 * 630 * @param o 631 * object for comparison. 632 * @return true if the given object equals this object. 633 * 634 * @supported.api 635 */ 636 public boolean equals(Object o) { 637 if (o instanceof ServiceSchemaManager) { 638 ServiceSchemaManager ossm = (ServiceSchemaManager) o; 639 if (serviceName.equals(ossm.serviceName) 640 && version.equals(ossm.version)) { 641 return (true); 642 } 643 } 644 return (false); 645 } 646 647 /** 648 * Returns the string representation of the Service 649 * Schema. 650 * 651 * @return the string representation of the Service Schema. 652 * 653 * @supported.api 654 */ 655 public String toString() { 656 validate(); 657 return (ssm.toString()); 658 } 659 660 /** 661 * Registers for changes to service's schema. The 662 * object will be called when schema for this service and version is 663 * changed. 664 * 665 * @param listener 666 * callback object that will be invoked when schema changes. 667 * @return an ID of the registered listener. 668 * 669 * @supported.api 670 */ 671 public String addListener(ServiceListener listener) { 672 validate(); 673 return (ssm.addListener(listener)); 674 } 675 676 /** 677 * Removes the listener from the service for the given 678 * listener ID. The ID was issued when the listener was registered. 679 * 680 * @param listenerID 681 * the listener ID issued when the listener was registered 682 * 683 * @supported.api 684 */ 685 public void removeListener(String listenerID) { 686 if (ssm !=null ) { 687 ssm.removeListener(listenerID); 688 } 689 } 690 691 /** 692 * Returns the last modified time stamp of this service schema. This method 693 * is expensive because it does not cache the modified time stamp but goes 694 * directly to the data store to obtain the value of this entry 695 * 696 * @return The last modified time stamp as a string with the format of 697 * <code>yyyyMMddhhmmss</code> 698 * @throws SMSException if there is an error trying to read from the 699 * datastore. 700 * @throws SSOException if the single sign-on token of the user is invalid. 701 */ 702 public String getLastModifiedTime() throws SMSException, SSOException { 703 validateServiceSchemaManagerImpl(); 704 CachedSMSEntry ce = ssm.getCachedSMSEntry(); 705 if (ce.isDirty()) { 706 ce.refresh(); 707 } 708 SMSEntry e = ce.getSMSEntry(); 709 String vals[] = e.getAttributeValues(SMSEntry.ATTR_MODIFY_TIMESTAMP, 710 true); 711 String mTS = null; 712 if (vals != null) { 713 mTS = vals[0]; 714 } 715 return mTS; 716 } 717 718 // ================= Plugin Interface Methods ======== 719 720 /** 721 * Returns the names of the plugin interfaces used by the service 722 * 723 * @return service's plugin interface names 724 */ 725 public Set getPluginInterfaceNames() { 726 validate(); 727 return (ssm.getPluginInterfaceNames()); 728 } 729 730 /** 731 * Returns the <code>PluginInterface</code> object of the service for the 732 * specified plugin interface name 733 * 734 * @param pluginInterfaceName 735 * name of the plugin interface 736 * @return plugin interface configured for the service; else 737 * <code>null</code> 738 */ 739 public PluginInterface getPluginInterface(String pluginInterfaceName) { 740 validate(); 741 return (ssm.getPluginInterface(pluginInterfaceName)); 742 } 743 744 /** 745 * Adds a new plugin interface objct to service's schema. 746 * 747 * @param interfaceName 748 * name for the plugin interface 749 * @param interfaceClass 750 * fully qualified interface class name 751 * @param i18nKey 752 * I18N key that will by used by UI to get messages to display 753 * the interface name 754 */ 755 public void addPluginInterface(String interfaceName, String interfaceClass, 756 String i18nKey) throws SMSException, SSOException { 757 SMSEntry.validateToken(token); 758 validateServiceSchemaManagerImpl(); 759 if ((interfaceName == null) || (interfaceClass == null)) { 760 throw (new IllegalArgumentException()); 761 } 762 StringBuilder sb = new StringBuilder(100); 763 sb.append("<").append(SMSUtils.PLUGIN_INTERFACE).append(" ").append( 764 SMSUtils.NAME).append("=\"").append(interfaceName) 765 .append("\" ").append(SMSUtils.PLUGIN_INTERFACE_CLASS).append( 766 "=\"").append(interfaceClass).append("\""); 767 if (i18nKey != null) { 768 sb.append(" ").append(SMSUtils.I18N_KEY).append("=\"").append( 769 i18nKey).append("\""); 770 } 771 sb.append("></").append(SMSUtils.PLUGIN_INTERFACE).append(">"); 772 // Construct XML document 773 Document pluginDoc = SMSSchema.getXMLDocument(sb.toString(), false); 774 Node node = XMLUtils.getRootNode(pluginDoc, SMSUtils.PLUGIN_INTERFACE); 775 776 // Added to XML document and write it 777 Document schemaDoc = ssm.getDocumentCopy(); 778 Node pluginNode = schemaDoc.importNode(node, true); 779 Node schemaNode = XMLUtils.getRootNode(schemaDoc, SMSUtils.SCHEMA); 780 schemaNode.appendChild(pluginNode); 781 replaceSchema(schemaDoc); 782 } 783 784 /** 785 * Removes the plugin interface object from the service schema. 786 * 787 * @param interfacename Name of the plugin class. 788 */ 789 public void removePluginInterface(String interfacename) 790 throws SMSException, SSOException { 791 SMSEntry.validateToken(token); 792 validateServiceSchemaManagerImpl(); 793 Document schemaDoc = ssm.getDocumentCopy(); 794 Node schemaNode = XMLUtils.getRootNode(schemaDoc, SMSUtils.SCHEMA); 795 // Get the plugin interface node 796 Node pluginNode = XMLUtils.getNamedChildNode(schemaNode, 797 SMSUtils.PLUGIN_INTERFACE, SMSUtils.NAME, interfacename); 798 if (pluginNode != null) { 799 schemaNode.removeChild(pluginNode); 800 replaceSchema(schemaDoc); 801 } 802 } 803 804 // ----------------------------------------------------------- 805 // Plugin Schema 806 // ----------------------------------------------------------- 807 /** 808 * Returns the names of plugins configured for the plugin interface. If 809 * organization is <code>null</code>, returns the plugins configured for 810 * the "root" organization. 811 */ 812 public Set getPluginSchemaNames(String interfaceName, String orgName) 813 throws SMSException { 814 SMSEntry.validateToken(token); 815 validate(); 816 // Construct the DN to get CachedSubEntries 817 StringBuilder sb = new StringBuilder(100); 818 sb.append("ou=").append(interfaceName).append(",").append( 819 CreateServiceConfig.PLUGIN_CONFIG_NODE).append("ou=").append( 820 version).append(",").append("ou=").append(serviceName).append( 821 ",").append(SMSEntry.SERVICES_RDN).append(",").append( 822 DNMapper.orgNameToDN(orgName)); 823 CachedSubEntries cse = CachedSubEntries.getInstance(token, sb 824 .toString()); 825 try { 826 return (cse.getSubEntries(token)); 827 } catch (SSOException s) { 828 debug.error("ServiceSchemaManager: Unable to get " 829 + "Plugin Schema Names", s); 830 } 831 return (Collections.EMPTY_SET); 832 } 833 834 /** 835 * Returns the PluginSchema object given the schema name and the interface 836 * name for the specified organization. If organization is 837 * <code>null</code>, returns the PluginSchema for the "root" organization. 838 */ 839 public PluginSchema getPluginSchema(String pluginSchemaName, 840 String interfaceName, String orgName) throws SMSException { 841 SMSEntry.validateToken(token); 842 validate(); 843 return (new PluginSchema(token, serviceName, version, pluginSchemaName, 844 interfaceName, orgName)); 845 } 846 847 /** 848 * Returns true if admin token cached within this class is valid 849 * 850 * @return true is admin token is valid 851 */ 852 public boolean isSSOTokenValid() { 853 try { 854 SMSEntry.validateToken(token); 855 return true; 856 } catch (SMSException smse) { 857 debug.warning("ServiceSchemaManager: token is not valid.", smse); 858 } 859 return false; 860 } 861 862 // ----------------------------------------------------------- 863 // Internal protected method 864 // ----------------------------------------------------------- 865 SSOToken getSSOToken() { 866 return (token); 867 } 868 869 protected Document getDocumentCopy() throws SMSException { 870 validate(); 871 return (ssm.getDocumentCopy()); 872 } 873 874 protected synchronized void replaceSchema(Document document) 875 throws SSOException, SMSException { 876 validate(); 877 CachedSMSEntry smsEntry = ssm.getCachedSMSEntry(); 878 SMSSchema smsSchema = new SMSSchema(document); 879 smsEntry.writeXMLSchema(token, smsSchema.getSchema()); 880 } 881 882 public <E extends Exception> void modifySchema(Function<Document, Boolean, E> modifier) throws E, SMSException, SSOException { 883 Document schema = getDocumentCopy(); 884 if (modifier.apply(schema)) { 885 replaceSchema(schema); 886 } 887 } 888 889 private void validate() { 890 try { 891 validateServiceSchemaManagerImpl(); 892 } catch (SSOException e) { 893 // Since method signatures cannot be changed, a runtime 894 // exception is thrown. This conditions would happen only 895 // when SSOToken has become invalid or service has been 896 // removed. 897 debug.error("ServiceSchemaManager:validate failed for SN: " + 898 serviceName, e); 899 throw (new RuntimeException(e.getMessage())); 900 } catch (SMSException e) { 901 // Ignore the exception 902 } 903 } 904 905 private void validateServiceSchemaManagerImpl() 906 throws SMSException, SSOException { 907 if (ssm == null || !ssm.isValid()) { 908 // Recreate the SSM 909 ssm = ServiceSchemaManagerImpl.getInstance(token, 910 serviceName, version); 911 } 912 } 913 914 // ----------------------------------------------------------- 915 // Static method to create a new service schema 916 // ----------------------------------------------------------- 917 static void createService(SSOToken token, SMSSchema smsSchema) 918 throws SMSException, SSOException { 919 // Service node 920 SMSEntry smsEntry = new SMSEntry(token, ServiceManager 921 .getServiceNameDN(smsSchema.getServiceName())); 922 923 if (smsEntry.isNewEntry()) { 924 // create this entry 925 smsEntry.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_TOP); 926 smsEntry.addAttribute(SMSEntry.ATTR_OBJECTCLASS, 927 SMSEntry.OC_SERVICE); 928 smsEntry.save(); 929 } 930 // Version node 931 CachedSMSEntry cEntry = CachedSMSEntry.getInstance(token, 932 ServiceManager.getServiceNameDN(smsSchema.getServiceName(), 933 smsSchema.getServiceVersion())); 934 if (cEntry.isDirty()) { 935 cEntry.refresh(); 936 } 937 smsEntry = cEntry.getSMSEntry(); 938 String[] schema = new String[1]; 939 if ((smsEntry.getAttributeValues(SMSEntry.ATTR_SCHEMA) == null) 940 || ((smsEntry.getAttributeValues(SMSEntry.ATTR_SCHEMA))[0] 941 .equalsIgnoreCase(SMSSchema.getDummyXML(smsSchema 942 .getServiceName(), smsSchema 943 .getServiceVersion())))) { 944 schema[0] = smsSchema.getSchema(); 945 smsEntry.setAttribute(SMSEntry.ATTR_SCHEMA, schema); 946 } else { 947 // Throw service already exists exception 948 Object[] args = { smsSchema.getServiceName(), 949 smsSchema.getServiceVersion() }; 950 throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME, 951 IUMSConstants.SMS_service_already_exists, args)); 952 } 953 if (smsEntry.isNewEntry()) { 954 // add object classes 955 smsEntry.addAttribute(SMSEntry.ATTR_OBJECTCLASS, SMSEntry.OC_TOP); 956 smsEntry.addAttribute(SMSEntry.ATTR_OBJECTCLASS, 957 SMSEntry.OC_SERVICE); 958 } 959 smsEntry.save(token); 960 cEntry.refresh(smsEntry); 961 } 962 963 public String toXML(AMEncryption encryptObj) 964 throws SMSException { 965 validate(); 966 String xml = ssm.toXML(encryptObj); 967 int idx = xml.lastIndexOf("</" + SMSUtils.SERVICE + ">"); 968 StringBuffer buff = new StringBuffer(); 969 buff.append(xml.substring(0, idx)); 970 971 Set realms = new HashSet(); 972 realms.add("/"); 973 974 for (Iterator i = getPluginInterfaceNames().iterator(); i.hasNext(); ) { 975 String iName = (String)i.next(); 976 getPlugSchemaXML(buff, iName, realms); 977 } 978 979 buff.append("</" + SMSUtils.SERVICE + ">"); 980 return buff.toString(); 981 } 982 983 private void getPlugSchemaXML( 984 StringBuffer buff, 985 String interfaceName, 986 Set realms 987 ) throws SMSException { 988 for (Iterator i = realms.iterator(); i.hasNext(); ){ 989 String realm = (String)i.next(); 990 Set schemaNames = getPluginSchemaNames(interfaceName, realm); 991 for (Iterator j = schemaNames.iterator(); j.hasNext();) { 992 String pName = (String)j.next(); 993 PluginSchema pSchema = getPluginSchema( 994 pName, interfaceName, realm); 995 buff.append(pSchema.toXML()); 996 } 997 } 998 } 999}