/*******************************************************************************
* Copyright (c) 2010 SAP AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Emil Simeonov - initial API and implementation.
* Dimitar Donchev - initial API and implementation.
* Dimitar Tenev - initial API and implementation.
* Nevena Manova - initial API and implementation.
* Georgi Konstantinov - initial API and implementation.
* Stanislav Nichev - initial API and implementation.
*******************************************************************************/
package org.eclipse.wst.sse.sieditor.command.emf.common.utils;
import java.util.Map;
import org.eclipse.xsd.XSDAttributeDeclaration;
import org.eclipse.xsd.XSDAttributeGroupDefinition;
import org.eclipse.xsd.XSDElementDeclaration;
import org.eclipse.xsd.XSDModelGroupDefinition;
import org.eclipse.xsd.XSDNamedComponent;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.XSDSchemaContent;
import org.eclipse.xsd.XSDSimpleTypeDefinition;
import org.eclipse.xsd.XSDTypeDefinition;
import org.eclipse.xsd.util.XSDConstants;
import org.w3c.dom.Element;
import org.eclipse.wst.sse.sieditor.model.utils.ElementAttributeUtils;
import org.eclipse.wst.sse.sieditor.model.utils.EmfXsdUtils;
/**
* Utility class. This class has methods for updating element prefixes.
*
*/
public class UpdateNSPrefixUtils {
private static final UpdateNSPrefixUtils INSTANCE = new UpdateNSPrefixUtils();
private UpdateNSPrefixUtils() {
}
public static UpdateNSPrefixUtils instance() {
return INSTANCE;
}
public void updateXsdElementDeclaration(final XSDSchema changedSchema, final String namespacePrefix,
final XSDElementDeclaration xsdElementDeclaration) {
final XSDElementDeclaration resolvedElementDeclaration = xsdElementDeclaration.getResolvedElementDeclaration();
final boolean resolvedElementSchemaMatches = resolvedElementDeclaration.getSchema() == changedSchema;
final XSDTypeDefinition typeDefinition = xsdElementDeclaration.getTypeDefinition();
final boolean isElementReference = typeDefinition == null;
final XSDNamedComponent elementNamedComponentType = isElementReference ? resolvedElementDeclaration : typeDefinition;
updateSchemaContent(changedSchema, namespacePrefix, xsdElementDeclaration.getElement(), xsdElementDeclaration,
resolvedElementSchemaMatches, elementNamedComponentType.getTargetNamespace(), elementNamedComponentType
.getSchema());
}
public void updateXsdAttributeDeclaration(final XSDSchema changedSchema, final String namespacePrefix,
final XSDAttributeDeclaration xsdAttributeDeclaration) {
final XSDAttributeDeclaration resolvedAttributeDeclaration = xsdAttributeDeclaration.getResolvedAttributeDeclaration();
final boolean resolvedAttributeSchemaMatches = resolvedAttributeDeclaration.getSchema() == changedSchema;
final XSDSimpleTypeDefinition typeDefinition = xsdAttributeDeclaration.getTypeDefinition();
final boolean isAttributeReference = typeDefinition == null;
final XSDNamedComponent attributeNamedComponentType = isAttributeReference ? resolvedAttributeDeclaration
: typeDefinition;
updateSchemaContent(changedSchema, namespacePrefix, xsdAttributeDeclaration.getElement(), xsdAttributeDeclaration,
resolvedAttributeSchemaMatches, attributeNamedComponentType.getTargetNamespace(), attributeNamedComponentType
.getSchema());
}
public void updateXsdAttributeGroupDeclaration(final XSDSchema changedSchema, final String namespacePrefix,
final XSDAttributeGroupDefinition attributeGroup) {
final XSDAttributeGroupDefinition resolvedAttributeGroupDefinition = attributeGroup.getResolvedAttributeGroupDefinition();
final boolean resolvedAttributeGroupDefinitionMatches = resolvedAttributeGroupDefinition.getSchema() == changedSchema;
updateSchemaContent(changedSchema, namespacePrefix, attributeGroup.getElement(), attributeGroup,
resolvedAttributeGroupDefinitionMatches, resolvedAttributeGroupDefinition.getTargetNamespace(),
resolvedAttributeGroupDefinition.getSchema());
}
public void updateXsdModelGroupDeclaration(final XSDSchema changedSchema, final String namespacePrefix,
final XSDModelGroupDefinition xsdModelGroupDefinition) {
final XSDModelGroupDefinition resolvedModelGroupDefinition = xsdModelGroupDefinition.getResolvedModelGroupDefinition();
final boolean resolvedModelGroupDefinitionMatches = resolvedModelGroupDefinition.getSchema() == changedSchema;
updateSchemaContent(changedSchema, namespacePrefix, xsdModelGroupDefinition.getElement(), xsdModelGroupDefinition,
resolvedModelGroupDefinitionMatches, resolvedModelGroupDefinition.getTargetNamespace(),
resolvedModelGroupDefinition.getSchema());
}
public void updateSchemaContent(final XSDSchema changedSchema, final String namespacePrefix,
final Element schemaContentElement, final XSDSchemaContent schemaContent,
final boolean resolvedSchemaOfSchemaContentMatches, final String resolvedElementTargetNamespace,
final XSDSchema resolvedElementContentSchema) {
final boolean shouldCheckAttributeType = resolvedElementTargetNamespace != null
&& !EmfXsdUtils.isSchemaForSchemaNS(resolvedElementTargetNamespace);
final boolean shouldEditElement = shouldCheckAttributeType
&& changedSchema.getTargetNamespace().equals(resolvedElementTargetNamespace);
if (schemaContentElement != null && shouldEditElement
&& (resolvedSchemaOfSchemaContentMatches || resolvedElementContentSchema == changedSchema)) {
updateElementAttributes(namespacePrefix, schemaContentElement, schemaContent, changedSchema);
}
}
/**
* Utility method. Updates the {@link XSDConstants#REF_ATTRIBUTE} or
* {@link XSDConstants#TYPE_ATTRIBUTE} attributes of the given schema
* element to include the given namespacePrefix
*
* @param namespacePrefix
* @param contentElement
* @param schema
*/
private void updateElementAttributes(final String namespacePrefix, final Element element,
final XSDSchemaContent contentElement, final XSDSchema schema) {
updateElementAttribute(XSDConstants.TYPE_ATTRIBUTE, namespacePrefix, element, contentElement, schema
.getQNamePrefixToNamespaceMap());
updateElementAttribute(XSDConstants.REF_ATTRIBUTE, namespacePrefix, element, contentElement, schema
.getQNamePrefixToNamespaceMap());
updateElementAttribute(XSDConstants.BASE_ATTRIBUTE, namespacePrefix, element, contentElement, schema
.getQNamePrefixToNamespaceMap());
}
/**
* Utility method. Updates the element's given attribute (if needed)
*/
private void updateElementAttribute(final String attributeName, final String namespacePrefix, final Element element,
final XSDSchemaContent contentElement, final Map<String, String> prefixMap) {
if (ElementAttributeUtils.hasAttributeValue(element, attributeName)
&& prefixNeedsUpdate(namespacePrefix, element.getAttribute(attributeName), prefixMap)) {
final String newAttributeValue = createNewAttributeValue(namespacePrefix, element, attributeName);
element.setAttribute(attributeName, newAttributeValue);
contentElement.elementChanged(element);
}
}
/**
* Utility method. It determines whether the given attribute value should be
* updated with the given namespacePrefix
*
* @param namespacePrefix
* - the namespace prefix we need to update the old ones with
* @param attributeValueToCheck
* @param prefixMap
* @return <code>true</code> if the element prefix needs to be updated with
* the given one
*/
private boolean prefixNeedsUpdate(final String namespacePrefix, final String attributeValueToCheck,
final Map<String, String> prefixMap) {
if (attributeValueToCheck == null)
return false;
boolean prefixNeedsUpdate = EmfXsdUtils.XMLNS_PREFIX.equals(namespacePrefix)
|| !attributeValueToCheck.startsWith(namespacePrefix + ':');
if (prefixNeedsUpdate) {
final int endIndex = attributeValueToCheck.indexOf(':');
if (endIndex != -1) {
// for some reason, we are receiving types which points to the
// schema-for-schema namespace. we need to exclude those
final String originalPrefix = attributeValueToCheck.substring(0, endIndex);
prefixNeedsUpdate &= !EmfXsdUtils.isSchemaForSchemaNS(prefixMap.get(originalPrefix));
}
}
return prefixNeedsUpdate;
}
private String createNewAttributeValue(String namespacePrefix, final Element element, final String attributeName) {
if (EmfXsdUtils.XMLNS_PREFIX.equals(namespacePrefix)) {
namespacePrefix = ""; //$NON-NLS-1$
} else {
namespacePrefix = namespacePrefix + ':';
}
// extract the element name from the attribute value
final int beginIndex = element.getAttribute(attributeName).indexOf(':') + 1;
final String elementName = element.getAttribute(attributeName).substring(beginIndex);
return namespacePrefix + elementName;
}
// =========================================================
// helpers
// =========================================================
/**
* Extracts the TNS prefix from the given QName.
*/
public String extractPrefixFromQName(final String qname) {
final int endIndex = qname.indexOf(':');
if (endIndex != -1) {
return qname.substring(0, endIndex);
}
return null;
}
}