/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* https://opensso.dev.java.net/public/CDDLv1.0.html or
* opensso/legal/CDDLv1.0.txt
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id: ServiceSchema.java,v 1.12 2008/08/30 16:46:47 goodearth Exp $
*
* Portions Copyrighted 2011-2016 ForgeRock AS.
*/
package com.sun.identity.sm;
import static java.util.Arrays.asList;
import com.iplanet.sso.SSOException;
import com.iplanet.ums.IUMSConstants;
import com.sun.identity.shared.Constants;
import com.sun.identity.common.CaseInsensitiveHashSet;
import com.sun.identity.shared.debug.Debug;
import com.sun.identity.shared.xml.XMLUtils;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* The class <code>ServiceSchema</code> provides interfaces to manage the
* schema information of a service. The schema for a service can be one of the
* following types: GLOBAL, ORGANIZATION, DYNAMIC, USER, and POLICY.
*
* @supported.all.api
*/
public class ServiceSchema {
// Pointer to service's schema manager & type
ServiceSchemaImpl ss;
String componentName;
SchemaType type;
ServiceSchemaManager ssm;
boolean orgAttrSchema;
/**
* Default constructor (private).
*/
private ServiceSchema() {
// do nothing
}
protected ServiceSchema(ServiceSchemaImpl ssi, String compName,
SchemaType type, ServiceSchemaManager ssm) {
this(ssi, compName, type, ssm, false);
}
protected ServiceSchema(ServiceSchemaImpl ssi, String compName,
SchemaType type, ServiceSchemaManager ssm, boolean isOrgAttrSchema)
{
this.ss = ssi;
this.componentName = compName;
this.type = type;
this.ssm = ssm;
this.orgAttrSchema = isOrgAttrSchema;
this.ss.isOrgAttrSchema = isOrgAttrSchema;
this.ss.serviceName = ssm.getName();
}
/**
* Returns the name of the service.
*
* @return the name of the schema
*/
public String getServiceName() {
return (ssm.getName());
}
/**
* Returns the version of the service.
*
* @return version of the service schema
*/
public String getVersion() {
return (ssm.getVersion());
}
/**
* Returns the name of the schema.
*
* @return the name of the schema
*/
public String getName() {
return (ss.getName());
}
/**
* Returns the schema type.
*
* @return the schema type.
*/
public SchemaType getServiceType() {
return (type);
}
/**
* Returns the I18N key that points to the description of the service.
*
* @return the I18N key that points to the description of the service
*/
public String getI18NKey() {
return (ss.getI18NKey());
}
/**
* Returns <code>true</code> if service schema supports multiple
* configurations; <code>false</code> otherwise
*
* @return <code>true</code> if service schema supports multiple
* configurations; <code>false</code> otherwise
*/
public boolean supportsMultipleConfigurations() {
return (ss.supportsMultipleConfigurations());
}
/**
* Sets the value of the I18N key in the service schema.
*
* @param key
* Value to be set for the I18N key of the service schema.
* @throws SMSException
* if there is a problem setting the value in the data store.
* @throws SSOException
* If the user has an invalid SSO token.
*/
public void setI18Nkey(String key) throws SMSException, SSOException {
SMSEntry.validateToken(ssm.getSSOToken());
Node sNode = ss.getSchemaNode();
((Element) sNode).setAttribute(SMSUtils.I18N_KEY, key);
ssm
.replaceSchema((ServiceSchemaManagerImpl.getInstance(ssm
.getSSOToken(), ssm.getName(), ssm.getVersion()))
.getDocument());
ss.i18nKey = key;
}
/**
* Set the value of inheritance attribute in service schema.
*
* @param value
* New value of inheritance attribute.
* @throws SMSException
* if there is a problem setting the value in the data store.
* @throws SSOException
* if the user has an invalid single sign on token.
*/
public void setInheritance(String value) throws SMSException, SSOException {
if (!value.equals("single") && !value.equals("multiple")) {
String[] arg = { value };
throw new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
"sms-invalid-inheritance-value", arg);
}
SMSEntry.validateToken(ssm.getSSOToken());
Node sNode = ss.getSchemaNode();
((Element) sNode).setAttribute(SMSUtils.INHERITANCE, value);
ssm
.replaceSchema((ServiceSchemaManagerImpl.getInstance(ssm
.getSSOToken(), ssm.getName(), ssm.getVersion()))
.getDocument());
ss.inheritance = value;
}
/**
* Returns the view bean URL for this service
*
* @return file name that contains I18N messages
*/
public String getPropertiesViewBeanURL() {
return (ssm.getPropertiesViewBeanURL());
}
/**
* Returns the name of the status attribute, as defined in the Service
* schema
*
* @return String name of status attribute
*/
public String getStatusAttribute() {
return (ss.getStatusAttribute());
}
/**
* Returns <code>true</code> if the service configuration created can be
* exported to other organizations.
*
* @return <code>true</code> if service configurations for this schema can
* be exported to other organizations; <code>false</code>
* otherwise.
*/
public boolean isExportable() {
return (false);
}
/**
* Sets the exportable nature of the service configurations created for this
* schema. Setting it to <code>true</code> allows the configurations to be
* exported to other organizations and a value of <code>false</code>
* disables exporting of configuration data.
*
* @param exportable
* <code>true</code> if service configurations for this schema
* can be exported to other organizations; <code>false</code>
* otherwise.
*/
public void setExportable(boolean exportable) {
}
/**
* Returns the I18N properties file name for the service schema.
*
* @return the I18N properties file name for the service schema
*/
public String getI18NFileName() {
String i18nFileName = ss.getI18NFileName();
return i18nFileName == null ? ssm.getI18NFileName() : i18nFileName;
}
/**
* Sets the I18N properties file name for the service schema
*
* @param url
* properties file name
* @throws SMSException
* if an error occurred while trying to perform the operation
* @throws SSOException
* if the single sign on token is invalid or expired
*/
public void setI18NFileName(String url) throws SMSException, SSOException {
ssm.setI18NFileName(url);
}
/**
* Returns the name for the service schema when used in a CREST representation.
*/
public String getResourceName() {
for (String name : asList(ss.getResourceName(), getName())) {
if (name != null) {
return name;
}
}
return getServiceName();
}
/**
* Should this service schema be hidden in the Configuration UI.
* @return True if it should be hidden.
*/
public boolean isHiddenInConfigUI() {
return ss.isHiddenInConfigUI();
}
/**
* During the creation of a new organisation/realm the services assigned to the parent realm are copied to the
* child realm. This will include the sub configs for that service, which in some cases are realm specific and will
* fail validation if copied. The schemas of these sub configs should set {@code realmCloneable} to {@code no} to
* avoid being copied.
*
* @return {@code true} if the config is cloneable between realms.
*/
public boolean isRealmCloneable() {
return ss.isRealmCloneable();
}
/**
* Sets the CREST resource name for the service schema.
*
* @param name
* resource name.
* @throws SMSException
* if an error occurred while trying to perform the operation
* @throws SSOException
* if the single sign on token is invalid or expired
*/
public void setResourceName(String name) throws SMSException, SSOException {
SMSEntry.validateToken(ssm.getSSOToken());
Node sNode = ss.getSchemaNode();
((Element) sNode).setAttribute(SMSUtils.RESOURCE_NAME, name);
ssm.replaceSchema((ServiceSchemaManagerImpl.getInstance(ssm.getSSOToken(), ssm.getName(), ssm.getVersion()))
.getDocument());
ss.resourceName = name;
}
/**
* Returns the names of the schema attributes defined for the service. It
* does not return the schema attributes defined for the sub-schema.
*
* @return the names of schema attributes defined for the service
*/
public Set getAttributeSchemaNames() {
return (ss.getAttributeSchemaNames());
}
/**
* Returns the names of the schema attributes defined for the service which
* are searchable. It does not return the schema attributes defined for the
* sub-schema.
*
* @return the names of schema attributes defined for the service which are
* searchable attributes.
*/
protected Set getSearchableAttributeNames() {
return (ss.getSearchableAttributeNames());
}
/**
* Returns the schema for an attribute given the name of the attribute,
* defined for this service. It returns only the attribute schema defined at
* the top level for the service and not from the sub-schema.
*
* @param attributeName
* the name of the schema attribute
* @return the schema for the attribute
*/
public AttributeSchema getAttributeSchema(String attributeName) {
AttributeSchemaImpl as = ss.getAttributeSchema(attributeName);
return ((as == null) ? null : new AttributeSchema(as, ssm, this));
}
/**
* Returns the attribute schemas defined for the service. It does not return
* the schema attributes defined for the sub-schema.
*
* @return attribute schemas defined for the service
*/
public Set<AttributeSchema> getAttributeSchemas() {
Set answer = new HashSet();
for (Iterator items = getAttributeSchemaNames().iterator(); items
.hasNext();) {
String attrName = (String) items.next();
answer.add(getAttributeSchema(attrName));
}
return (answer);
}
/**
* Returns the attribute schemas defined for the service that is not a
* status attribute and is not a service attribute. It does not return the
* schema attributes defined for the sub-schema.
*
* @return attribute schemas defined for the service
*/
public Set getServiceAttributeNames() {
return (ss.getServiceAttributeNames());
}
/**
* Validates the <code>attrMap</code> against the attributes defined in
* this schema of the service. It will throw an exception if the map
* contains any attribute not listed in the schema. It will also pick up
* default values for any attributes not in the map but which are listed in
* the schema, if the boolean <Code>inherit</Code> is set to true.
*
* @param attrMap
* map of attributes
* @param inherit
* if true, then inherit the default values
* @return Map of validated attributes with default values
* @throws SMSException
* if invalid attribute names are present in the
* <code>attrMap</code>.
*/
public Map validateAndInheritDefaults(Map attrMap, boolean inherit)
throws SMSException {
return (validateAndInheritDefaults(attrMap, null, inherit));
}
/**
* Validates the <code>attrMap</code> against the attributes defined in
* this schema of the service for the given organization. It will throw an
* exception if the map contains any attribute not listed in the schema. It
* will also pick up default values for any attributes not in the map but
* which are listed in the schema, if the boolean <Code>inherit</Code> is
* set to true.
*
* @param attrMap
* map of attributes
* @param inherit
* if true, then inherit the default values
* @return Map of validated attributes with default values
* @throws SMSException
* if invalid attribute names are present in the
* <code>attrMap</code>.
*/
public Map validateAndInheritDefaults(Map attrMap, String orgName,
boolean inherit) throws SMSException {
SMSEntry.validateToken(ssm.getSSOToken());
if (attrMap == null || attrMap.isEmpty()) {
attrMap = new HashMap();
}
Iterator keys = attrMap.keySet().iterator();
Set defAttrSet = ss.getAttributeSchemaNames();
while (keys.hasNext()) {
String attr = (String) keys.next();
if (!defAttrSet.contains(attr)) {
// This attribute is not listed in the service.
debug.error("ServiceSchema.validateAndInheritDefaults: " + attr
+ " is not listed in the service " + getServiceName());
throw new InvalidAttributeNameException(
IUMSConstants.UMS_BUNDLE_NAME,
"services_validator_invalid_attr_name", null);
}
}
// If orgName is not null, populate the envMap
Map envMap = Collections.EMPTY_MAP;
if (orgName != null) {
envMap = new HashMap();
envMap.put(Constants.ORGANIZATION_NAME, orgName);
envMap.put(Constants.SSO_TOKEN, ssm.getSSOToken());
}
Iterator ass = ss.getAttributeSchemaNames().iterator();
while (ass.hasNext()) {
String attr = (String) ass.next();
AttributeSchemaImpl as = ss.getAttributeSchema(attr);
AttributeValidator av = ss.getAttributeValidator(attr);
String anyValue = as.getAny();
if (inherit && (anyValue != null) &&
(anyValue.indexOf("required") > -1)) {
// Inherit default values of this attribute, if
// required
attrMap = av.inheritDefaults(attrMap);
Set attrVals = (Set) attrMap.get(attr);
if (attrVals == null || attrVals.isEmpty()) {
// A required attribute is being deleted
// throw an exception.
debug.error("ServiceSchema.validateAndInheritDefaults: "
+ attr + " is a required attribute and cannot"
+ " be deleted");
Object args[] = { attr };
throw new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
"sms-required-attribute-delete", args);
}
} else if (inherit) {
attrMap = av.inheritDefaults(attrMap);
}
// validate the attribute against Schema
Set valSet = (Set) attrMap.get(attr);
if (valSet != null) {
String i18nFileName = (ssm != null) ? ssm.getI18NFileName()
: null;
av.validate(valSet, i18nFileName, false, envMap);
}
}
if (debug.messageEnabled()) {
debug.error("ServiceSchema.validate&InheritDef: "
+ " returning attrMap: " + attrMap.toString());
}
return attrMap;
}
/**
* Adds the attribute schema to this service. The schema is defined in XML
* input stream that follows the SMS DTD.
*
* @param xmlAttrSchema
* the XML format of the attribute schema
* @throws SMSException
* if an error occurred while performing the operation
* @throws SSOException
* if the single sign on token is invalid or expired
*/
public void addAttributeSchema(InputStream xmlAttrSchema)
throws SSOException, SMSException {
SMSEntry.validateToken(ssm.getSSOToken());
// Check if attribute exists
Document doc = SMSSchema.getXMLDocument(xmlAttrSchema, false);
NodeList nl = doc.getElementsByTagName(SMSUtils.SCHEMA_ATTRIBUTE);
CaseInsensitiveHashSet asNames =
new CaseInsensitiveHashSet(ss.getAttributeSchemaNames());
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
AttributeSchemaImpl as = new AttributeSchemaImpl(node);
if (asNames.contains(as.getName())) {
Object[] args = { as.getName() };
throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
"sms-attributeschema-already-exists", args));
}
}
appendAttributeSchema(nl);
}
/**
* Removes the attribute schema from this service.
*
* @param attrName
* the name of the attribute schema
* @throws SMSException
* if an error occurred while performing the operation
* @throws SSOException
* if the single sign on token is invalid or expired
*/
public void removeAttributeSchema(String attrName) throws SSOException,
SMSException {
removeChildNode(SMSUtils.SCHEMA_ATTRIBUTE, attrName);
}
/**
* Returns a map of all the attribute and their default values in this
* schema.
*
* @return Map of Attribute Names and Sets of their default values as
* defined in the Schema
*/
public Map<String, Set<String>> getAttributeDefaults() {
return (ss.getAttributeDefaults());
}
/**
* Returns a map of all the attribute and their example values in this
* schema.
*
* @return Map of Attribute Names and Sets of their example values as
* defined in the Schema
*/
public Map<String, Set<String>> getAttributeExamples() {
return (ss.getAttributeExamples());
}
/**
* Returns an unmodifiable map of all the attribute and their default values
* in this schema.
*
* @return Map of Attribute Names and Sets of their default values as
* defined in the Schema
*/
public Map getReadOnlyAttributeDefaults() {
return (ss.getReadOnlyAttributeDefaults());
}
/**
* Method to change the default values of attributes in the schema.
*
* @param attrs
* A map of the names of <code>AttributeSchema</code> to
* modify, and a Set of Values which should replace the default
* values of the current schema.
* @throws SMSException
* if an error occurred while performing the operation
* @throws SSOException
* if the single sign on token is invalid or expired
*/
public void setAttributeDefaults(Map attrs) throws SSOException,
SMSException {
SMSEntry.validateToken(ssm.getSSOToken());
// Get a copy of the XML document
Document document = ssm.getDocumentCopy();
Iterator items = attrs.keySet().iterator();
while (items.hasNext()) {
String attrName = (String) items.next();
AttributeSchema as = getAttributeSchema(attrName);
if (as == null) {
Object[] args = { attrName };
throw (new SchemaException(IUMSConstants.UMS_BUNDLE_NAME,
"sms-invalid-attr-name", args));
}
as.setDefaultValues((Set) attrs.get(attrName), document);
}
// Save the document
ssm.replaceSchema(document);
}
/**
* Method to change default value for a specific attribute.
*
* @param attrName
* Name of the attribute for which defaults values need to be
* replaced.
* @param values
* Set of new values to replace the old ones.
* @throws SchemaException
* if an error occurred while parsing the XML
* @throws SMSException
* if an error occurred while performing the operation
* @throws SSOException
* if the single sign on token is invalid or expired
*/
public void setAttributeDefaults(String attrName, Set values)
throws SchemaException, SMSException, SSOException {
SMSEntry.validateToken(ssm.getSSOToken());
AttributeSchema as = getAttributeSchema(attrName);
if (as == null) {
Object[] args = { attrName };
throw (new SchemaException(IUMSConstants.UMS_BUNDLE_NAME,
"sms-invalid-attr-name", args));
}
as.setDefaultValues(values);
}
/**
* Removes the default values of attributes in the schema.
*
* @param attrs
* A set of the names of <code>AttributeSchema</code>.
* @throws SMSException
* if an error occurred while performing the operation
* @throws SSOException
* if the single sign on token is invalid or expired
*/
public void removeAttributeDefaults(Set attrs) throws SMSException,
SSOException {
SMSEntry.validateToken(ssm.getSSOToken());
Iterator it = attrs.iterator();
while (it.hasNext()) {
String asName = (String) it.next();
AttributeSchema as = getAttributeSchema(asName);
if (as == null) {
throw (new InvalidAttributeNameException(
IUMSConstants.UMS_BUNDLE_NAME,
IUMSConstants.services_validator_invalid_attr_name,
null));
}
as.removeDefaultValues();
}
}
/**
* Returns the names of sub-schemas for the service.
*
* @return the names of service's sub-schemas
*/
public Set<String> getSubSchemaNames() {
return ss.getSubSchemaNames();
}
/**
* Returns <code>ServiceSchema</code> object given the name of the
* service's sub-schema.
*
* @param subSchemaName
* the name of the service's sub-schema
* @return <code>ServiceSchema</code> object
* @throws SMSException
* if an error occurred while performing the operation
*
*/
public ServiceSchema getSubSchema(String subSchemaName) throws SMSException
{
SMSEntry.validateToken(ssm.getSSOToken());
ServiceSchema answer = null;
ServiceSchemaImpl ssi = ss.getSubSchema(subSchemaName);
if (ssi != null) {
answer = new ServiceSchema(ssi,
componentName + "/" + subSchemaName, type, ssm);
}
return (answer);
}
/**
* Adds the service's sub-schema given the XML input stream that follows the
* SMS DTD.
*
* @param xmlSubSchema
* the XML format of the sub-schema
* @throws SMSException
* if an error occurred while performing the operation
* @throws SSOException
* if the single sign on token is invalid or expired
*/
public void addSubSchema(InputStream xmlSubSchema) throws SSOException,
SMSException {
SMSEntry.validateToken(ssm.getSSOToken());
// Check if attribute exists
Document doc = SMSSchema.getXMLDocument(xmlSubSchema, false);
NodeList nl = doc.getElementsByTagName(SMSUtils.SUB_SCHEMA);
Set asNames = ss.getSubSchemaNames();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
String nodeName = XMLUtils.getNodeAttributeValue(node,
SMSUtils.NAME);
if (asNames.contains(nodeName)) {
Object[] args = { nodeName };
throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
"sms-subschema-already-exists", args));
}
}
appendSubSchema(doc);
}
/**
* Removes the service's sub-schema from the service.
*
* @param subSchemaName
* the name of the service's sub-schema
* @throws SMSException
* if an error occurred while performing the operation
* @throws SSOException
* if the single sign on token is invalid or expired
*/
public void removeSubSchema(String subSchemaName) throws SSOException,
SMSException {
SMSEntry.validateToken(ssm.getSSOToken());
removeChildNode(SMSUtils.SUB_SCHEMA, subSchemaName);
}
/**
* Determines whether each attribute in the attribute set is valid. Iterates
* though the set checking each element to see if there is a validator that
* needs to execute.
*
* @param attributeSet
* the <code>Map</code> where key is the attribute name and
* value is the <code>Set</code> of attribute values
* @return true if all attributes are valid
* @throws SMSException
* if an error occurred while performing the operation
*/
public boolean validateAttributes(Map attributeSet) throws SMSException {
SMSEntry.validateToken(ssm.getSSOToken());
return (ss.validateAttributes(ssm.getSSOToken(), attributeSet, false,
null));
}
/**
* Determines whether each attribute in the attribute set is valid for the
* given organization. Iterates though the set checking each element to see
* if there is a validator that needs to execute.
*
* @param attributeSet
* the <code>Map</code> where key is the attribute name and
* value is the <code>Set</code> of attribute values
* @param orgName
* organization name
* @return true if all attributes are valid
* @throws SMSException
* if an error occurred while performing the operation
*/
public boolean validateAttributes(Map attributeSet, String orgName)
throws SMSException {
SMSEntry.validateToken(ssm.getSSOToken());
return (ss.validateAttributes(ssm.getSSOToken(), attributeSet, false,
orgName));
}
/**
* Returns string representation of the schema.
*
* @return string representation of the schema.
*/
public String toString() {
return (ss.toString());
}
/**
* Returns the Node of this schema element. Used by Policy component's
* <code>ServiceType</code> to get <code>ActionSchema</code>.
*
* @return the Node of this schema element. Used by Policy component's
* <code>ServiceType</code> to get <code>ActionSchema</code>.
*/
public Node getSchemaNode() {
Node node = null;
try {
node = getSchemaNode(ssm.getDocumentCopy());
} catch (SMSException ssme) {
debug.error("ServiceSchema::getSchemaNode: invalid schema");
}
return (node);
}
/**
* Removes the attribute schema from this service.
*
* @param attrName
* the name of the attribute schema
* @throws SMSException
* if an error occurred while performing the operation
* @throws SSOException
* if the single sign on token is invalid or expired
*/
public void replaceAttributeSchema(String attrName, Node attributeSchemaNode) throws SSOException,
SMSException {
replaceChildNode(SMSUtils.SCHEMA_ATTRIBUTE, attrName, attributeSchemaNode);
}
private void appendAttributeSchema(NodeList nodes) throws SSOException, SMSException {
if (nodes == null || nodes.getLength() == 0) {
throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
IUMSConstants.SMS_SMSSchema_no_schema_element, null));
}
Document schemaDoc = ssm.getDocumentCopy();
try {
Node schemaNode = getSchemaNode(schemaDoc);
NodeList childrens = schemaNode.getChildNodes();
Node nextSibling = null;
for (int i = 0; i < childrens.getLength(); i++) {
Node child = childrens.item(i);
if (Node.ELEMENT_NODE == child.getNodeType()
&& !SMSUtils.SCHEMA_ATTRIBUTE.equals(child.getNodeName())) {
nextSibling = child;
break;
}
}
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
Node iNode = schemaDoc.importNode(node, true);
schemaNode.insertBefore(iNode, nextSibling);
}
} catch (Exception e) {
throw (new SMSException(e.getMessage(), e, "sms-cannot_append_NODE"));
}
ssm.replaceSchema(schemaDoc);
}
private void appendSubSchema(Document doc) throws SSOException, SMSException {
if (doc == null) {
throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
IUMSConstants.SMS_SMSSchema_no_schema_element, null));
}
Document schemaDoc = ssm.getDocumentCopy();
try {
Node schemaNode = getSchemaNode(schemaDoc);
Node node = XMLUtils.getRootNode(doc, SMSUtils.SUB_SCHEMA);
NodeList childrens = schemaNode.getChildNodes();
Node nextSibling = null;
for (int i = 0; i < childrens.getLength(); i++) {
Node child = childrens.item(i);
if (Node.ELEMENT_NODE == child.getNodeType()
&& !SMSUtils.SCHEMA_ATTRIBUTE.equals(child.getNodeName())) {
//In this case we've found an entry that is not an AttributeSchema, so this is definitely an
//element before which we can place a SubSchema. (i.e. the found element was a SubSchema or
//an OrganizationAttributeSchema). Note that this will change the order of the SubSchema
//elements in the service description, however the order should not matter for SMS.
nextSibling = child;
break;
}
}
Node iNode = schemaDoc.importNode(node, true);
schemaNode.insertBefore(iNode, nextSibling);
} catch (Exception ex) {
throw (new SMSException(ex.getMessage(), ex, "sms-cannot_append_NODE"));
}
ssm.replaceSchema(schemaDoc);
}
// -----------------------------------------------------------
// Protected methods
// -----------------------------------------------------------
void removeChildNode(String nodeType, String nodeName) throws SSOException,
SMSException {
if (debug.messageEnabled()) {
debug.message("ServiceSchema::removeChildNode called for: "
+ getServiceName() + "(" + ssm.getVersion() + ") "
+ componentName);
}
Document schemaDoc = ssm.getDocumentCopy();
Node schemaNode = getSchemaNode(schemaDoc);
if (schemaNode != null) {
Node node = XMLUtils.getNamedChildNode(schemaNode, nodeType,
SMSUtils.NAME, nodeName);
if (node != null) {
schemaNode.removeChild(node);
ssm.replaceSchema(schemaDoc);
}
}
}
void replaceChildNode(String nodeType, String nodeName, Node attributeSchemaNode) throws SSOException,
SMSException {
if (debug.messageEnabled()) {
debug.message("ServiceSchema::replaceChildNode called for: "
+ getServiceName() + "(" + ssm.getVersion() + ") "
+ componentName);
}
Document schemaDoc = ssm.getDocumentCopy();
Node schemaNode = getSchemaNode(schemaDoc);
if (schemaNode != null) {
Node oldNode = XMLUtils.getNamedChildNode(schemaNode, nodeType,
SMSUtils.NAME, nodeName);
if (oldNode != null) {
Node newNode = schemaDoc.importNode(attributeSchemaNode, true);
schemaNode.replaceChild(newNode, oldNode);
ssm.replaceSchema(schemaDoc);
}
} else {
if (debug.messageEnabled()) {
debug.message("ServiceSchema::replaceChildNode failed to retrieve service schema for : "
+ getServiceName() + "(" + ssm.getVersion() + ") "
+ componentName);
}
}
}
// -----------------------------------------------------------
// Method to obtain schema node
// -----------------------------------------------------------
Node getSchemaNode(Document document) throws SMSException {
NodeList nodes = document.getElementsByTagName(SMSUtils.SCHEMA);
if ((nodes == null) || (nodes.getLength() == 0)) {
throwInvalidSchemaException();
}
Node rNode = nodes.item(0);
// Get the schema type node
String schemaType = SMSUtils.GLOBAL_SCHEMA;
if (type.equals(SchemaType.ORGANIZATION)) {
schemaType = SMSUtils.ORG_SCHEMA;
} else if (type.equals(SchemaType.DYNAMIC)) {
schemaType = SMSUtils.DYNAMIC_SCHEMA;
} else if (type.equals(SchemaType.USER)) {
schemaType = SMSUtils.USER_SCHEMA;
} else if (type.equals(SchemaType.POLICY)) {
schemaType = SMSUtils.POLICY_SCHEMA;
} else if (type.equals(SchemaType.GROUP)) {
schemaType = SMSUtils.GROUP_SCHEMA;
} else if (type.equals(SchemaType.DOMAIN)) {
schemaType = SMSUtils.DOMAIN_SCHEMA;
}
Node stNode = XMLUtils.getChildNode(rNode, schemaType);
if (stNode == null) {
throwInvalidSchemaException();
}
// Walk the component name
if ((componentName == null) || (componentName.length() == 0)) {
return (stNode);
} else if (orgAttrSchema) {
// OrganizationAttributeSchema
return (XMLUtils
.getChildNode(stNode, SMSUtils.ORG_ATTRIBUTE_SCHEMA));
}
StringTokenizer st = new StringTokenizer(componentName, "/");
while (st.hasMoreTokens()) {
String tokenName = st.nextToken();
if ((tokenName == null) || (tokenName.length() == 0)) {
continue;
}
if ((stNode = XMLUtils.getNamedChildNode(stNode,
SMSUtils.SUB_SCHEMA, SMSUtils.NAME, tokenName)) == null) {
throwInvalidSchemaException();
}
}
return (stNode);
}
// -----------------------------------------------------------
// Method to obtain organizationattributeschema node
// -----------------------------------------------------------
Node getOrgAttrSchemaNode(Document doc) throws SMSException {
NodeList nodes = doc.getElementsByTagName(
SMSUtils.ORG_ATTRIBUTE_SCHEMA);
if (nodes == null || (nodes.getLength() == 0)) {
// Throw an exception
throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
"sms-invalid-orgattr-schema-document", null));
}
Node rNode = nodes.item(0);
if (rNode == null) {
throwInvalidSchemaException();
}
return (rNode);
}
void throwInvalidSchemaException() throws SMSException {
SMSEntry.debug.error("ServiceSchema::getSchemaNode: "
+ "Invalid service schema XML: " + getServiceName() + "("
+ ssm.getVersion() + ")");
throw (new SMSException(IUMSConstants.UMS_BUNDLE_NAME,
IUMSConstants.SMS_SMSSchema_no_service_element, null));
}
Debug debug = Debug.getInstance("amSMS");
}