blob: 29946b2d64ca4b9976d3ab1dd6b7121d0e69434e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.xsd.ui.internal.dialogs.types.xsd;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.wst.common.uriresolver.internal.util.URIHelper;
import org.eclipse.wst.xsd.ui.internal.actions.CreateElementAction;
import org.eclipse.wst.xsd.ui.internal.actions.DOMAttribute;
import org.eclipse.wst.xsd.ui.internal.dialogs.types.xml.XMLComponentSpecification;
import org.eclipse.wst.xsd.ui.internal.refactor.rename.XSDExternalFileCleanup;
import org.eclipse.wst.xsd.ui.internal.util.TypesHelper;
import org.eclipse.wst.xsd.ui.internal.util.XSDDOMHelper;
import org.eclipse.xsd.XSDImport;
import org.eclipse.xsd.XSDInclude;
import org.eclipse.xsd.XSDRedefine;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.XSDSchemaContent;
import org.eclipse.xsd.XSDSchemaDirective;
import org.eclipse.xsd.util.XSDConstants;
import org.eclipse.xsd.util.XSDParser;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
public class XSDSetTypeHelper {
private XSDSchema xsdSchema;
private IFile currentIFile;
public XSDSetTypeHelper(IFile iFile, XSDSchema schema) {
currentIFile = iFile;
xsdSchema = schema;
}
public void setType(Element element, String property, XMLComponentSpecification spec) {
addImportIfNecessary(element, spec);
String typeObject = getPrefixedTypeName(spec);
// Get the previous type --> previousStringType
String previousStringType = "";
Attr attr = element.getAttributeNode(property);
if (attr != null) {
attr.getValue();
}
if (!XSDDOMHelper.inputEquals(element, XSDConstants.UNION_ELEMENT_TAG, false))
{
if (spec != null && spec.getTagPath().equals("**anonymous**"))
{
if (spec.getTagPath().equals("ANONYMOUS_SIMPLE_TYPE"))
{
if (!previousStringType.equals("**anonymous**"))
{
updateElementToAnonymous(element, XSDConstants.SIMPLETYPE_ELEMENT_TAG);
}
}
else
{
if (!previousStringType.equals("**anonymous**"))
{
updateElementToAnonymous(element, XSDConstants.COMPLEXTYPE_ELEMENT_TAG);
}
}
// element.removeAttribute(XSDConstants.TYPE_ATTRIBUTE);
element.removeAttribute(property);
}
else
{
XSDDOMHelper.updateElementToNotAnonymous(element);
//element.setAttribute(XSDConstants.TYPE_ATTRIBUTE, typeObject.toString());
element.setAttribute(property, typeObject.toString());
}
}
}
public void addImportIfNecessary(Element element, XMLComponentSpecification spec) {
// Get the new type --> typeObject
if (spec != null) {
String itemType = spec.getTagPath();
if (!itemType.equals("BUILT_IN_SIMPLE_TYPE")) {
// Do an actual import if needed
XSDParser parser = new XSDParser();
parser.parse(spec.getFileLocation());
XSDSchema schema = parser.getSchema();
String tns = schema.getTargetNamespace();
boolean exists = false;
// Check if the type is defined in the 'current' file itself.
String currentFile = getNormalizedLocation(xsdSchema.getSchemaLocation());
IPath currentFilePath = new Path(currentFile);
if (currentFilePath.equals(new Path(spec.getFileLocation()))) {
exists = true;
}
if (!exists) {
if (tns.equals(xsdSchema.getTargetNamespace())) {
// Check if the schema is in a redefine/include
List existingList = getXSDIncludes();
existingList.addAll(getXSDRedefines());
Iterator it = existingList.iterator();
while (it.hasNext()) {
XSDSchemaDirective existingSchema = (XSDSchemaDirective) it.next();
String normalizedFile = getNormalizedLocation(existingSchema.getResolvedSchema().getSchemaLocation());
String normalizedSpec = spec.getFileLocation();
if (normalizedFile.equals(normalizedSpec)) {
// Found and existing one
exists = true;
}
}
}
else {
// Check if the schema is in a import
List existingList = getXSDImports();
Iterator it = existingList.iterator();
while (it.hasNext()) {
XSDSchemaDirective existingSchema = (XSDSchemaDirective) it.next();
String normalizedFile = getNormalizedLocation(existingSchema.getResolvedSchema().getSchemaLocation());
String normalizedSpec = spec.getFileLocation();
if (normalizedFile.equals(normalizedSpec)) {
// Found and existing one
exists = true;
}
}
}
}
if (!exists) {
doImport(spec.getFileLocation(), schema);
}
}
}
}
/*
* Return the prefixed type name for the type described by the given
* XMLComponentSpecification object.
* If the type described is a Built-in type, do not add the prefix
*/
public String getPrefixedTypeName(XMLComponentSpecification spec) {
String typeObject = (String) spec.getAttributeInfo("name");
TypesHelper typesHelper = new TypesHelper(xsdSchema); // ???? Is this correct?
List prefixedNames = typesHelper.getPrefixedNames(spec.getTargetNamespace(), typeObject);
if (prefixedNames.size() > 0) {
// Grab the first prefixed name
typeObject = (String) prefixedNames.get(0);
}
return typeObject;
}
private void updateElementToAnonymous(Element element, String xsdType) {
String prefix = element.getPrefix();
prefix = (prefix == null) ? "" : (prefix + ":");
XSDDOMHelper.updateElementToNotAnonymous(element);
Element childNode = null;
if (xsdType.equals(XSDConstants.COMPLEXTYPE_ELEMENT_TAG)) {
childNode = element.getOwnerDocument().createElementNS(XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001, prefix + XSDConstants.COMPLEXTYPE_ELEMENT_TAG);
}
else if (xsdType.equals(XSDConstants.SIMPLETYPE_ELEMENT_TAG)) {
childNode = element.getOwnerDocument().createElementNS(XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001, prefix + XSDConstants.SIMPLETYPE_ELEMENT_TAG);
}
if (childNode != null) {
XSDDOMHelper helper = new XSDDOMHelper();
Node annotationNode = helper.getChildNode(element, XSDConstants.ANNOTATION_ELEMENT_TAG);
if (annotationNode == null) {
Node firstChild = element.getFirstChild();
element.insertBefore(childNode, firstChild);
} else {
Node nextSibling = annotationNode.getNextSibling();
element.insertBefore(childNode, nextSibling);
}
XSDDOMHelper.formatChild(childNode);
}
}
// TODO: We shouldn't need to pass in IPath externalSchemaPath.
private void doImport(String externalSchemaPath, XSDSchema externalSchema) {
// Determine schemaLocation
String locationAttribute = URIHelper.getRelativeURI(externalSchemaPath, currentIFile.getLocation().toOSString());
boolean isInclude = false;
if (externalSchema.getTargetNamespace().equals(xsdSchema.getTargetNamespace())) {
isInclude = true;
}
if (externalSchema != null) { // In case we have problems loading the file.... we should display an error message.
Element newElement;
if (isInclude) {
List attributes = new ArrayList();
attributes.add(new DOMAttribute(XSDConstants.SCHEMALOCATION_ATTRIBUTE, locationAttribute));
newElement = createElement(XSDConstants.INCLUDE_ELEMENT_TAG, attributes);
}
else if (!isInclude) {
List attributes = new ArrayList();
attributes.add(new DOMAttribute(XSDConstants.NAMESPACE_ATTRIBUTE, externalSchema.getTargetNamespace()));
attributes.add(new DOMAttribute(XSDConstants.SCHEMALOCATION_ATTRIBUTE, locationAttribute));
newElement = createElement(XSDConstants.IMPORT_ELEMENT_TAG, attributes);
handleImportNS(newElement, externalSchema);
}
}
}
private void handleImportNS(Element importElement, XSDSchema externalSchema) {
String namespace = externalSchema.getTargetNamespace();
if (namespace == null) namespace = "";
XSDImport xsdImport = (XSDImport) xsdSchema.getCorrespondingComponent(importElement);
xsdImport.setResolvedSchema(externalSchema);
java.util.Map map = xsdSchema.getQNamePrefixToNamespaceMap();
// System.out.println("changed Import Map is " + map.values());
// System.out.println("changed import Map keys are " + map.keySet());
// Referential integrity on old import
// How can we be sure that if the newlocation is the same as the oldlocation
// the file hasn't changed
XSDSchema referencedSchema = xsdImport.getResolvedSchema();
if (referencedSchema != null)
{
XSDExternalFileCleanup cleanHelper = new XSDExternalFileCleanup(referencedSchema);
cleanHelper.visitSchema(xsdSchema);
}
Element schemaElement = xsdSchema.getElement();
// update the xmlns in the schema element first, and then update the import element next
// so that the last change will be in the import element. This keeps the selection
// on the import element
TypesHelper helper = new TypesHelper(externalSchema);
String prefix = helper.getPrefix(namespace, false);
if (map.containsKey(prefix))
{
prefix = null;
}
if (prefix == null || (prefix !=null && prefix.length() == 0))
{
StringBuffer newPrefix = new StringBuffer("pref"); //$NON-NLS-1$
int prefixExtension = 1;
while (map.containsKey(newPrefix.toString()) && prefixExtension < 100)
{
newPrefix = new StringBuffer("pref" + String.valueOf(prefixExtension));
prefixExtension++;
}
prefix = newPrefix.toString();
}
if (namespace.length() > 0)
{
// if ns already in map, use its corresponding prefix
if (map.containsValue(namespace))
{
TypesHelper typesHelper = new TypesHelper(xsdSchema);
prefix = typesHelper.getPrefix(namespace, false);
}
else // otherwise add to the map
{
schemaElement.setAttribute("xmlns:"+prefix, namespace);
}
}
// System.out.println("changed Import Map is " + map.values());
// System.out.println("changed import Map keys are " + map.keySet());
}
private Element createElement(String elementTag, List attributes) {
Node relativeNode = XSDDOMHelper.getNextElementNode(xsdSchema.getElement().getFirstChild());
CreateElementAction action = new CreateElementAction("");
action.setElementTag(elementTag);
action.setAttributes(attributes);
action.setParentNode(xsdSchema.getElement());
action.setRelativeNode(relativeNode);
action.setXSDSchema(xsdSchema);
return action.createAndAddNewChildElement();
}
private String getNormalizedLocation(String location) {
try {
URL url = new URL(location);
URL resolvedURL = Platform.resolve(url);
location = resolvedURL.getPath();
}
catch (Exception e) {
e.printStackTrace();
}
return location;
}
private List getXSDImports() {
List imports = new ArrayList();
Iterator contents = xsdSchema.getContents().iterator();
while (contents.hasNext()) {
XSDSchemaContent content = (XSDSchemaContent) contents.next();
if (content instanceof XSDImport) {
imports.add(content);
}
}
return imports;
}
private List getXSDIncludes() {
List includes = new ArrayList();
Iterator contents = xsdSchema.getContents().iterator();
while (contents.hasNext()) {
XSDSchemaContent content = (XSDSchemaContent) contents.next();
if (content instanceof XSDInclude) {
includes.add(content);
}
}
return includes;
}
private List getXSDRedefines() {
List includes = new ArrayList();
Iterator contents = xsdSchema.getContents().iterator();
while (contents.hasNext()) {
XSDSchemaContent content = (XSDSchemaContent) contents.next();
if (content instanceof XSDRedefine) {
includes.add(content);
}
}
return includes;
}
}