/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 *******************************************************************************/ package org.ebayopensource.turmeric.eclipse.typelibrary.ui.wst; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import org.apache.commons.lang.StringUtils; import org.apache.xerces.util.DOMUtil; import org.ebayopensource.turmeric.common.config.LibraryType; import org.ebayopensource.turmeric.eclipse.core.logging.SOALogger; import org.ebayopensource.turmeric.eclipse.core.resources.constants.SOATypeLibraryConstants; import org.ebayopensource.turmeric.eclipse.exception.core.SOABadParameterException; import org.ebayopensource.turmeric.eclipse.typelibrary.resources.SOAMessages; import org.ebayopensource.turmeric.eclipse.typelibrary.ui.TypeLibraryUIActivator; import org.ebayopensource.turmeric.eclipse.typelibrary.utils.TypeLibraryUtil; import org.ebayopensource.turmeric.eclipse.utils.lang.StringUtil; import org.eclipse.wst.sse.core.internal.document.IDocumentLoader; import org.eclipse.wst.sse.core.internal.encoding.CodedIO; import org.eclipse.wst.sse.core.internal.encoding.EncodingRule; import org.eclipse.wst.sse.core.internal.provisional.IModelLoader; import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; import org.eclipse.wst.xml.core.internal.modelhandler.ModelHandlerForXML; import org.eclipse.wst.xsd.ui.internal.common.util.XSDCommonUIUtils; import org.eclipse.xsd.XSDAnnotation; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDTypeDefinition; import org.eclipse.xsd.util.XSDConstants; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * The WTP Copy Utility Class. WTP has its own mechanism to copy existing xsds * to wsdl files. SOA reuse that functionality rather than re inventing the * wheel. This class if the copy functionality touch point. * * @author smathew * */ public class WTPCopyUtil { private static IStructuredModel loadUsingWTP(URL url) throws IOException { IStructuredDocument document = null; IStructuredModel model = null; ModelHandlerForXML xmlModelHandler = new ModelHandlerForXML(); IDocumentLoader loader = xmlModelHandler.getDocumentLoader(); InputStream inputStream = getMarkSupportedStream(url.openStream()); document = (IStructuredDocument) loader.createNewStructuredDocument( null, inputStream, EncodingRule.FORCE_DEFAULT); IModelLoader xmlModelLoader = xmlModelHandler.getModelLoader(); String path = url.getPath(); if (path.startsWith("file:")) path = path.substring(5); IStructuredModel retModel = xmlModelLoader.createModel(document, path, xmlModelHandler); return retModel; } private static InputStream getMarkSupportedStream(InputStream inputStream) { if (!inputStream.markSupported()) { inputStream = new BufferedInputStream(inputStream, CodedIO.MAX_BUF_SIZE); } inputStream.mark(CodedIO.MAX_MARK_SIZE); return inputStream; } public static void copy(XSDSchema dstSchema, XSDSchema srcSchema, String typeName, URL srcURL, boolean typeFolding, String libraryName, String libraryNamespace) throws SOABadParameterException { XSDTypeDefinition srcTypeDefinition = null; for (XSDTypeDefinition typeDefiniton : srcSchema.getTypeDefinitions()) { if (StringUtils.equals(typeDefiniton.getName(), typeName)) { srcTypeDefinition = typeDefiniton; break; } } if (srcTypeDefinition == null || srcTypeDefinition.getElement() == null) { throw new SOABadParameterException(StringUtil.formatString( SOAMessages.INVALID_XSD, srcURL, typeName)); } addAnnotation(srcTypeDefinition, libraryName, libraryNamespace); transformQNamePrefix(dstSchema, srcSchema, typeFolding); } /** * Copies the schema specified in the source URL derived from the library * type to the destination XSD Schema. The name of the type inside the * schema should be specified in the name parameter. Throws Bad Parameter * Exception if the specified URL derived from the library type is invalid * or if it is not accessible. Clients are supposed to validate the * parameters or react to the exception and show it to the user * meaningfully. * * @param dstSchema the dst schema * @param srcType the src type * @param typeFolding the type folding * @throws SOABadParameterException the sOA bad parameter exception */ public static void copy(XSDSchema dstSchema, LibraryType srcType, boolean typeFolding) throws SOABadParameterException { String name = srcType.getName(); URL srcURL = null; XSDSchema srcSchema = null; try { srcURL = TypeLibraryUtil.getXSD(srcType); srcSchema = TypeLibraryUtil.parseSchema(srcURL); } catch (Exception e) { SOALogger.getLogger().error(e); throw new SOABadParameterException(StringUtil.formatString( SOAMessages.INVALID_XSD_URL, srcURL)); } copy(dstSchema, srcSchema, name, srcURL, typeFolding, srcType.getLibraryInfo().getLibraryName(), srcType.getLibraryInfo().getLibraryNamespace()); } public static void transformQNamePrefix(XSDSchema dstSchema, XSDSchema srcSchema, boolean typeFolding) throws SOABadParameterException { String targetNameSpace = dstSchema.getTargetNamespace(); String targetNameSpaceprefix = ""; Map<String, String> srcPrefixes = srcSchema .getQNamePrefixToNamespaceMap(); Map<String, String> dstPrefixes = dstSchema .getQNamePrefixToNamespaceMap(); Map<String, String> srcToDstPrefixMap = new TreeMap<String, String>(); Map<String, String> additionalSrcPrefixes = new TreeMap<String, String>(); // finding the targetNameSpacePrefix in the destination schema for (Entry<String, String> entry : dstPrefixes.entrySet()) { if (StringUtils.equals(entry.getValue(), targetNameSpace)) { targetNameSpaceprefix = entry.getKey(); break; } } // if the destination schema does not have a name space prefix for // its own target name space if (StringUtils.isEmpty(targetNameSpaceprefix)) targetNameSpaceprefix = StringUtils.stripEnd(TypeLibraryUIActivator .getPrefix(dstSchema, targetNameSpace), ":"); for (Entry<String, String> srcEntry : srcPrefixes.entrySet()) { if (!XSDConstants.isSchemaForSchemaNamespace(srcEntry.getValue())) { if (typeFolding) { srcToDstPrefixMap.put(srcEntry.getKey(), targetNameSpaceprefix); } else { boolean foundCorrespondingPrefix = false; for (Entry<String, String> dstEntry : dstPrefixes .entrySet()) { if (StringUtils.equals(dstEntry.getValue(), srcEntry .getValue())) { srcToDstPrefixMap.put(srcEntry.getKey(), dstEntry .getKey()); foundCorrespondingPrefix = true; } } // if there is no corresponding prefix add one to // the destination schema and replace it in the src // schema if (!foundCorrespondingPrefix) { String newPrefix = StringUtils .stripEnd(TypeLibraryUIActivator.getPrefix(dstSchema, srcEntry.getValue()), ":"); // we add this to the src schema also to make sure // that the prefix changes does not make it invalid additionalSrcPrefixes.put(newPrefix, srcEntry .getValue()); srcToDstPrefixMap.put(srcEntry.getKey(), newPrefix); } } } } srcPrefixes.putAll(additionalSrcPrefixes); Element srcElement = srcSchema.getTypeDefinitions().get(0).getElement(); Element dstElement = (Element) dstSchema.getElement(); // setting the Schema for Schema prefix for eg: xs to xsd or // whatever. srcSchema.setSchemaForSchemaQNamePrefix(dstSchema .getSchemaForSchemaQNamePrefix()); updatePrefixes(srcElement, srcToDstPrefixMap); DOMUtil.copyInto(srcElement, dstElement); } private static void updatePrefixes(Element element, Map<String, String> prefixMap) { NamedNodeMap namedNodeMap = element.getAttributes(); for (int i = 0; i < namedNodeMap.getLength(); i++) { String attrValue = namedNodeMap.item(i).getNodeValue(); String attrName = namedNodeMap.item(i).getNodeName(); for (String str : prefixMap.keySet()) { if (StringUtils.isNotEmpty(attrValue) && attrValue.trim().startsWith(str + ":")) { String trimmedAttrValue = attrValue.trim(); String newAttrValue = trimmedAttrValue; if (trimmedAttrValue.startsWith(str + ":xs:")) { newAttrValue = StringUtils.replaceOnce(trimmedAttrValue, str + ":xs:", "xs:"); } else if (StringUtils.countMatches(trimmedAttrValue, ":") == 2) { //already contains a prefix trimmedAttrValue = StringUtils.substringAfter(trimmedAttrValue, ":"); String oldPrefix = StringUtils.substringBefore(trimmedAttrValue, ":"); newAttrValue = StringUtils.replaceOnce(trimmedAttrValue, oldPrefix + ":", prefixMap.get(oldPrefix) + ":"); } else { newAttrValue = StringUtils.replaceOnce(trimmedAttrValue, str + ":", prefixMap.get(str) + ":"); } element.getAttributeNode(attrName).setValue(newAttrValue); } } } NodeList children = element.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if (child instanceof Element) updatePrefixes((Element) child, prefixMap); } } /** * Adds the annotation. * * @param typeDefinition the type definition * @param libraryType the library type */ public static void addAnnotation(XSDTypeDefinition typeDefinition, LibraryType type) { addAnnotation(typeDefinition, type.getLibraryInfo().getLibraryName(), type.getLibraryInfo().getLibraryNamespace()); } /** * Adds the annotation. * * @param typeDefinition the type definition * @param libraryType the library type * @param libraryNamespace the namespace */ public static void addAnnotation(XSDTypeDefinition typeDefinition, String libraryName, String libraryNamespace) { XSDAnnotation annotation = XSDCommonUIUtils.getInputXSDAnnotation( typeDefinition, true); Element appInfoElement = null; if (annotation.getApplicationInformation(null).size() <= 0 || annotation.getApplicationInformation(null).get(0) == null) { appInfoElement = annotation.createApplicationInformation(null); } else { appInfoElement = annotation.getApplicationInformation().get(0); } if (StringUtils.isNotBlank(libraryName) && StringUtils.isNotBlank(libraryNamespace)) { fillAppInfo(appInfoElement, libraryName, libraryNamespace); } annotation.getElement().appendChild(appInfoElement); } public static void fillAppInfo(Element appInfoElement, String libraryName, String libraryNamespace) { NodeList children = appInfoElement.getChildNodes(); Element typeLibElement = null; for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if (child instanceof Element) { Element childElement = (Element) child; if (SOATypeLibraryConstants.TAG_TYPE_LIB.equals(childElement .getTagName())) { typeLibElement = childElement; break; } } } //no element exists already if (typeLibElement == null) { typeLibElement = appInfoElement.getOwnerDocument().createElement( SOATypeLibraryConstants.TAG_TYPE_LIB); appInfoElement.appendChild(typeLibElement); } typeLibElement.setAttribute(SOATypeLibraryConstants.ATTR_LIB, libraryName); typeLibElement.setAttribute(SOATypeLibraryConstants.ATTR_NMSPC, libraryNamespace); } }