/* * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) 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 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wso2.carbon.registry.extensions.handlers.utils; import org.apache.ws.commons.schema.XmlSchema; import org.apache.ws.commons.schema.XmlSchemaCollection; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.core.jdbc.handlers.RequestContext; import org.wso2.carbon.registry.core.*; import org.wso2.carbon.registry.extensions.utils.CommonConstants; import javax.wsdl.Definition; import javax.wsdl.Import; import javax.wsdl.Types; import javax.wsdl.WSDLException; import javax.wsdl.extensions.schema.Schema; import javax.wsdl.factory.WSDLFactory; import javax.wsdl.xml.WSDLReader; import javax.wsdl.xml.WSDLWriter; import java.io.ByteArrayOutputStream; import java.util.*; public class WSDLFileProcessor { // remove this when it is not needed private int i; public static final String IMPORT_TAG = "import"; public static final String INCLUDE_TAG = "include"; /** * Buffer to hold associations until all the resources are added. We should add associations * only after both ends (resources) of the association is added to the registry. Otherwise, it * will cause an error as the registry tries to find the both end resources before setting the * association. */ private List <Association> associationsBuffer = new ArrayList <Association> (); /** * saves a wsdl file including its imports and imported schemas. * * @param context the active request * @param location URL to WSDL document * * @param registryBasePath base path of registry * @param processImports if true, we should pull imports in. If not, we won't. * @param metadata a "template" resource containing the WSDL metadata * @return the actual path * @throws RegistryException */ public String saveWSDLFileToRegistry(RequestContext context, String location, String registryBasePath, boolean processImports, Resource metadata) throws RegistryException { WSDLReader wsdlReader; String fileNameToSave; Registry registry = context.getRegistry(); try { wsdlReader = WSDLFactory.newInstance().newWSDLReader(); } catch (WSDLException e) { String msg = "Could not initiate the wsdl reader. Caused by: " + e.getMessage(); throw new RegistryException(msg); } wsdlReader.setFeature("javax.wsdl.importDocuments", true); wsdlReader.setFeature("javax.wsdl.verbose", false); Definition wsdlDefinition; try { wsdlDefinition = wsdlReader.readWSDL(location); String baseUri = wsdlDefinition.getDocumentBaseURI(); String wsdlFileName = baseUri.substring(baseUri.lastIndexOf("/") + 1); fileNameToSave = getFileNameToSave(wsdlFileName, ".wsdl"); } catch (WSDLException e) { String msg = "Could not read the wsdl at location " + location + ". Caused by: " + e.getMessage(); throw new RegistryException(msg); } Map processedWSDLMap = new HashMap(); calculateWSDLNamesAndChangeTypes(registry, wsdlDefinition, processedWSDLMap, new HashMap(), new HashSet(), registryBasePath, processImports); saveWSDLFileToRegistry(registry, wsdlDefinition, processedWSDLMap, new HashSet(), registryBasePath, processImports, metadata , true); persistAssociations(registry, associationsBuffer); return fileNameToSave; } private String getFileNameToSave(String wsdlFileName, String suffix) { String fileNameToSave = wsdlFileName; if (wsdlFileName.indexOf(".") > 0) { fileNameToSave = wsdlFileName.substring(0, wsdlFileName.indexOf(".")) + suffix; } else if (wsdlFileName.indexOf("?") > 0) { fileNameToSave = wsdlFileName.substring(0, wsdlFileName.indexOf("?")) + suffix; } else if (!wsdlFileName.endsWith("wsdl")) { fileNameToSave = wsdlFileName + suffix; } return fileNameToSave; } static HashMap changed = new HashMap(); static HashSet visited = new HashSet(); /** * saves the given wsdl definition file with its imported wsdls and imported and included * schemas. * * @param wsdlDefinition - wsdl file to save * @param processedWSDLMap - map with original source URI vs new uris for wsdls * @param processedScheamMap - map with orignal source URI vs new uris for schemas */ public void calculateWSDLNamesAndChangeTypes(Registry registry, Definition wsdlDefinition, Map processedWSDLMap, Map processedScheamMap, Set visitedWSDLs, String registryBasePath, boolean processImports) throws RegistryException { // first we have to process the imports and change the // schema locations suite for the registry if (processImports) { Iterator iter = wsdlDefinition.getImports().values().iterator(); Vector values; Import wsdlImport; // add this to visited list to stop recursion visitedWSDLs.add(wsdlDefinition.getDocumentBaseURI()); for (; iter.hasNext();) { values = (Vector)iter.next(); for (Object value : values) { wsdlImport = (Import)value; // process the types recuresiveilt Definition innerDefinition = wsdlImport.getDefinition(); if (!visitedWSDLs.contains(innerDefinition.getDocumentBaseURI())) { // we have not process this wsdl file earlier calculateWSDLNamesAndChangeTypes(registry, innerDefinition, processedWSDLMap, processedScheamMap, visitedWSDLs, registryBasePath, processImports); } } } } // change the schema names String baseUri = wsdlDefinition.getDocumentBaseURI(); String wsdlFileName = baseUri.substring(baseUri.lastIndexOf("/") + 1); String fileNameToSave = getFileNameToSave(wsdlFileName, ".wsdl"); while (processedWSDLMap.containsValue(fileNameToSave)) { fileNameToSave = getFileNameToSave(wsdlFileName, ++i + ".wsdl"); } Types types = wsdlDefinition.getTypes(); if (types != null) { List extensibleElements = types.getExtensibilityElements(); Schema schemaExtension; Object extensionObject; XmlSchema xmlSchema; XmlSchemaCollection xmlSchemaCollection; SchemaFileProcessor schemaFileProcessor; Map changedLocationMap; String basuri = wsdlDefinition.getDocumentBaseURI(); basuri = basuri.substring(0, basuri.lastIndexOf("/") + 1); for (Object extensibleElement : extensibleElements) { extensionObject = extensibleElement; if (extensionObject instanceof Schema) { // first get the schema object schemaExtension = (Schema)extensionObject; // create an xml schema object to be processed by SchemaFile procesor. xmlSchemaCollection = new XmlSchemaCollection(); xmlSchemaCollection.setBaseUri(basuri); xmlSchema = xmlSchemaCollection.read(schemaExtension.getElement()); schemaFileProcessor = new SchemaFileProcessor(registry); changedLocationMap = new HashMap(); HashSet visitedSchemas = new HashSet(); schemaFileProcessor.calculateNewSchemaNames( xmlSchema, processedScheamMap, visitedSchemas, true, processImports); schemaFileProcessor.saveSchemaFileToRegistry( xmlSchema, processedScheamMap, changedLocationMap, new HashSet(), true, registryBasePath, processImports, null); schemaFileProcessor.persistAssociations(); ArrayList xsdPaths = schemaFileProcessor.getSchemaPath(); for (Object xsdPath : xsdPaths) { String xsd = (String)xsdPath; String assocPath = "/" + fileNameToSave; if (!"/".equals(registryBasePath)) { assocPath = registryBasePath + assocPath; } associationsBuffer.add(new Association(assocPath, xsd, CommonConstants.DEPENDS)); associationsBuffer.add(new Association(xsd, assocPath, CommonConstants.USED_BY)); } // update the current schema locations with the generated ones. changeLocations(schemaExtension.getElement(), changedLocationMap); } } } // after processing the defintions save this to the registry // TODO: save this to the registry for the moment save this to the // folder and omit any exception occurs. // add this entry to the proccessed wsdl map processedWSDLMap.put(baseUri, fileNameToSave); } /** * * @param wsdlDefinition * @param processedWSDLMap * @param visitedWSDLs * @param registryBasePath * @param processImports * @param metadata * @param original : To indicate whether the resource is the top most resource of imported one * @throws RegistryException */ public void saveWSDLFileToRegistry(Registry registry, Definition wsdlDefinition, Map processedWSDLMap, Set visitedWSDLs, String registryBasePath, boolean processImports, Resource metadata , boolean original) throws RegistryException { List associations = new ArrayList(); if (processImports) { // first we have to process the imports and change the // schema locations suite for the registry Iterator iter = wsdlDefinition.getImports().values().iterator(); Vector values; Import wsdlImport; // add this to visited list to stop recursion visitedWSDLs.add(wsdlDefinition.getDocumentBaseURI()); for (; iter.hasNext();) { values = (Vector)iter.next(); for (Object value : values) { wsdlImport = (Import)value; // process the types recuresiveilt Definition innerDefinition = wsdlImport.getDefinition(); if (!visitedWSDLs.contains(innerDefinition.getDocumentBaseURI())) { // we have not process this wsdl file earlier saveWSDLFileToRegistry(registry, innerDefinition, processedWSDLMap, visitedWSDLs, registryBasePath, processImports, null ,false); } // set the import location according to the new location wsdlImport.setLocationURI((String)processedWSDLMap.get( innerDefinition.getDocumentBaseURI())); // add this wsdl as an association String innerImportedResourceName = (String)processedWSDLMap.get(innerDefinition.getDocumentBaseURI()); String innerWsdlPath = getWSDLPath(registryBasePath, innerImportedResourceName); associations.add(innerWsdlPath); } } } // after processing the defintions save this to the registry // save this to the registry String importedResourceName = (String)processedWSDLMap.get(wsdlDefinition.getDocumentBaseURI()); try { WSDLWriter wsdlWriter = WSDLFactory.newInstance().newWSDLWriter(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); wsdlWriter.writeWSDL(wsdlDefinition, byteArrayOutputStream); byte[] wsdlResourceContent = byteArrayOutputStream.toByteArray(); // create a resource this wsdlResourceContent and put it to the registry with the name // importedResourceName (in some path) String wsdlPath = getWSDLPath(registryBasePath, importedResourceName); Resource wsdlResource = new ResourceImpl(); if (metadata != null) { wsdlResource.setMediaType(metadata.getMediaType()); wsdlResource.setDescription(metadata.getDescription()); } // getting the paramentes //Commented to fix REGISTRY-2329 /*if (wsdlDefinition.getQName() != null) { String name = wsdlDefinition.getQName().getLocalPart(); if (name != null) { wsdlResource.addProperty("registry.wsdl.Name", name); } }*/ if (wsdlDefinition.getDocumentationElement() != null) { String document = wsdlDefinition.getDocumentationElement().getTextContent(); if (document != null) { wsdlResource.addProperty("registry.wsdl.documentation", document); } } String targetNamespace = wsdlDefinition.getTargetNamespace(); //Commented to fix REGISTRY-2329 //wsdlResource.addProperty("registry.wsdl.TargetNamespace", targetNamespace); wsdlResource.setContent(wsdlResourceContent); registry.put(wsdlPath, wsdlResource); //Commented to fix REGISTRY-2329 /*if (metadata !=null && original) { metadata.addProperty("registry.wsdl.TargetNamespace", targetNamespace); if (wsdlDefinition.getQName() != null) { String name = wsdlDefinition.getQName().getLocalPart(); if (name != null) { metadata.addProperty("registry.wsdl.Name", name); } } if (wsdlDefinition.getDocumentationElement() != null) { String document = wsdlDefinition.getDocumentationElement().getTextContent(); if (document != null) { metadata.addProperty("registry.wsdl.documentation", document); } } }*/ // add the associations String associatedWSDL; for (Object association : associations) { associatedWSDL = (String)association; associationsBuffer.add(new Association(wsdlPath, associatedWSDL, CommonConstants.DEPENDS)); } } catch (WSDLException e) { throw new RegistryException("Invalid WSDL file"); } } private String getWSDLPath(String registryBasePath, String importedResourceName) { String wsdlPath; if (RegistryConstants.ROOT_PATH.equals(registryBasePath)) { wsdlPath = RegistryConstants.ROOT_PATH + importedResourceName; } else { wsdlPath = registryBasePath + RegistryConstants.PATH_SEPARATOR + importedResourceName; } return wsdlPath; } private void changeLocations(Element element, Map changedLocationMap) { NodeList nodeList = element.getChildNodes(); String tagName; for (int i = 0; i < nodeList.getLength(); i++) { tagName = nodeList.item(i).getLocalName(); if (IMPORT_TAG.equals(tagName) || INCLUDE_TAG.equals(tagName)) { processImport(nodeList.item(i), changedLocationMap); } } } private void processImport(Node importNode, Map changedLocationMap) { NamedNodeMap nodeMap = importNode.getAttributes(); Node attribute; String attributeValue; for (int i = 0; i < nodeMap.getLength(); i++) { attribute = nodeMap.item(i); if (attribute.getNodeName().equals("schemaLocation")) { attributeValue = attribute.getNodeValue(); if (changedLocationMap.get(attributeValue) != null) { attribute.setNodeValue((String)changedLocationMap.get(attributeValue)); } } } } private void persistAssociations(Registry registry, List <Association> associations) throws RegistryException { Iterator <Association> associationIterator = associations.iterator(); while(associationIterator.hasNext()) { Association association = associationIterator.next(); registry.addAssociation(association.getSourcePath(), association.getDestinationPath(), association.getAssociationType()); } } }