aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.ws.wsdl.writer; aoqi@0: aoqi@0: import com.sun.istack.internal.NotNull; aoqi@0: import com.sun.xml.internal.ws.api.server.PortAddressResolver; aoqi@0: import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; aoqi@0: import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; aoqi@0: import com.sun.xml.internal.ws.addressing.W3CAddressingConstants; aoqi@0: import com.sun.xml.internal.ws.addressing.v200408.MemberSubmissionAddressingConstants; aoqi@0: import com.sun.istack.internal.Nullable; aoqi@0: aoqi@0: import javax.xml.namespace.QName; aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: import java.util.logging.Logger; aoqi@0: aoqi@0: /** aoqi@0: * Patches WSDL with the correct endpoint address and the relative paths aoqi@0: * to other documents. aoqi@0: * aoqi@0: * @author Jitendra Kotamraju aoqi@0: * @author Kohsuke Kawaguchi aoqi@0: */ aoqi@0: public final class WSDLPatcher extends XMLStreamReaderToXMLStreamWriter { aoqi@0: aoqi@0: private static final String NS_XSD = "http://www.w3.org/2001/XMLSchema"; aoqi@0: private static final QName SCHEMA_INCLUDE_QNAME = new QName(NS_XSD, "include"); aoqi@0: private static final QName SCHEMA_IMPORT_QNAME = new QName(NS_XSD, "import"); aoqi@0: private static final QName SCHEMA_REDEFINE_QNAME = new QName(NS_XSD, "redefine"); aoqi@0: aoqi@0: private static final Logger logger = Logger.getLogger( aoqi@0: com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".wsdl.patcher"); aoqi@0: aoqi@0: private final DocumentLocationResolver docResolver; aoqi@0: private final PortAddressResolver portAddressResolver; aoqi@0: aoqi@0: // aoqi@0: // fields accumulated as we parse through documents aoqi@0: // aoqi@0: private String targetNamespace; aoqi@0: private QName serviceName; aoqi@0: private QName portName; aoqi@0: private String portAddress; aoqi@0: aoqi@0: // true inside // aoqi@0: private boolean inEpr; aoqi@0: // true inside /// aoqi@0: private boolean inEprAddress; aoqi@0: aoqi@0: /** aoqi@0: * Creates a {@link WSDLPatcher} for patching WSDL. aoqi@0: * aoqi@0: * @param portAddressResolver aoqi@0: * address of the endpoint is resolved using this docResolver. aoqi@0: * @param docResolver aoqi@0: * Consulted to get the import/include document locations. aoqi@0: * Must not be null. aoqi@0: */ aoqi@0: public WSDLPatcher(@NotNull PortAddressResolver portAddressResolver, aoqi@0: @NotNull DocumentLocationResolver docResolver) { aoqi@0: this.portAddressResolver = portAddressResolver; aoqi@0: this.docResolver = docResolver; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: protected void handleAttribute(int i) throws XMLStreamException { aoqi@0: QName name = in.getName(); aoqi@0: String attLocalName = in.getAttributeLocalName(i); aoqi@0: aoqi@0: if((name.equals(SCHEMA_INCLUDE_QNAME) && attLocalName.equals("schemaLocation")) aoqi@0: || (name.equals(SCHEMA_IMPORT_QNAME) && attLocalName.equals("schemaLocation")) aoqi@0: || (name.equals(SCHEMA_REDEFINE_QNAME) && attLocalName.equals("schemaLocation")) aoqi@0: || (name.equals(WSDLConstants.QNAME_IMPORT) && attLocalName.equals("location"))) { aoqi@0: // patch this attribute value. aoqi@0: aoqi@0: String relPath = in.getAttributeValue(i); aoqi@0: String actualPath = getPatchedImportLocation(relPath); aoqi@0: if (actualPath == null) { aoqi@0: return; // skip this attribute to leave it up to "implicit reference". aoqi@0: } aoqi@0: aoqi@0: logger.fine("Fixing the relative location:"+relPath aoqi@0: +" with absolute location:"+actualPath); aoqi@0: writeAttribute(i, actualPath); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: if (name.equals(WSDLConstants.NS_SOAP_BINDING_ADDRESS) || aoqi@0: name.equals(WSDLConstants.NS_SOAP12_BINDING_ADDRESS)) { aoqi@0: aoqi@0: if(attLocalName.equals("location")) { aoqi@0: portAddress = in.getAttributeValue(i); aoqi@0: String value = getAddressLocation(); aoqi@0: if (value != null) { aoqi@0: logger.fine("Service:"+serviceName+ " port:"+portName aoqi@0: + " current address "+portAddress+" Patching it with "+value); aoqi@0: writeAttribute(i, value); aoqi@0: return; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: super.handleAttribute(i); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Writes out an {@code i}-th attribute but with a different value. aoqi@0: * @param i attribute index aoqi@0: * @param value attribute value aoqi@0: * @throws XMLStreamException when an error encountered while writing attribute aoqi@0: */ aoqi@0: private void writeAttribute(int i, String value) throws XMLStreamException { aoqi@0: String nsUri = in.getAttributeNamespace(i); aoqi@0: if(nsUri!=null) aoqi@0: out.writeAttribute( in.getAttributePrefix(i), nsUri, in.getAttributeLocalName(i), value ); aoqi@0: else aoqi@0: out.writeAttribute( in.getAttributeLocalName(i), value ); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: protected void handleStartElement() throws XMLStreamException { aoqi@0: QName name = in.getName(); aoqi@0: aoqi@0: if (name.equals(WSDLConstants.QNAME_DEFINITIONS)) { aoqi@0: String value = in.getAttributeValue(null,"targetNamespace"); aoqi@0: if (value != null) { aoqi@0: targetNamespace = value; aoqi@0: } aoqi@0: } else if (name.equals(WSDLConstants.QNAME_SERVICE)) { aoqi@0: String value = in.getAttributeValue(null,"name"); aoqi@0: if (value != null) { aoqi@0: serviceName = new QName(targetNamespace, value); aoqi@0: } aoqi@0: } else if (name.equals(WSDLConstants.QNAME_PORT)) { aoqi@0: String value = in.getAttributeValue(null,"name"); aoqi@0: if (value != null) { aoqi@0: portName = new QName(targetNamespace,value); aoqi@0: } aoqi@0: } else if (name.equals(W3CAddressingConstants.WSA_EPR_QNAME) aoqi@0: || name.equals(MemberSubmissionAddressingConstants.WSA_EPR_QNAME)) { aoqi@0: if (serviceName != null && portName != null) { aoqi@0: inEpr = true; aoqi@0: } aoqi@0: } else if (name.equals(W3CAddressingConstants.WSA_ADDRESS_QNAME) aoqi@0: || name.equals(MemberSubmissionAddressingConstants.WSA_ADDRESS_QNAME)) { aoqi@0: if (inEpr) { aoqi@0: inEprAddress = true; aoqi@0: } aoqi@0: } aoqi@0: super.handleStartElement(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: protected void handleEndElement() throws XMLStreamException { aoqi@0: QName name = in.getName(); aoqi@0: if (name.equals(WSDLConstants.QNAME_SERVICE)) { aoqi@0: serviceName = null; aoqi@0: } else if (name.equals(WSDLConstants.QNAME_PORT)) { aoqi@0: portName = null; aoqi@0: } else if (name.equals(W3CAddressingConstants.WSA_EPR_QNAME) aoqi@0: || name.equals(MemberSubmissionAddressingConstants.WSA_EPR_QNAME)) { aoqi@0: if (inEpr) { aoqi@0: inEpr = false; aoqi@0: } aoqi@0: } else if (name.equals(W3CAddressingConstants.WSA_ADDRESS_QNAME) aoqi@0: || name.equals(MemberSubmissionAddressingConstants.WSA_ADDRESS_QNAME)) { aoqi@0: if (inEprAddress) { aoqi@0: String value = getAddressLocation(); aoqi@0: if (value != null) { aoqi@0: logger.fine("Fixing EPR Address for service:"+serviceName+ " port:"+portName aoqi@0: + " address with "+value); aoqi@0: out.writeCharacters(value); aoqi@0: } aoqi@0: inEprAddress = false; aoqi@0: } aoqi@0: } aoqi@0: super.handleEndElement(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: protected void handleCharacters() throws XMLStreamException { aoqi@0: // handleCharacters() may be called multiple times. aoqi@0: if (inEprAddress) { aoqi@0: String value = getAddressLocation(); aoqi@0: if (value != null) { aoqi@0: // will write the address with end element aoqi@0: return; aoqi@0: } aoqi@0: } aoqi@0: super.handleCharacters(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Returns the location to be placed into the generated document. aoqi@0: * aoqi@0: * @param relPath relative URI to be resolved aoqi@0: * @return aoqi@0: * null to leave it to the "implicit reference". aoqi@0: */ aoqi@0: private @Nullable String getPatchedImportLocation(String relPath) { aoqi@0: return docResolver.getLocationFor(null, relPath); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * For the given service, port names it matches the correct endpoint and aoqi@0: * reutrns its endpoint address aoqi@0: * aoqi@0: * @return returns the resolved endpoint address aoqi@0: */ aoqi@0: private String getAddressLocation() { aoqi@0: return (portAddressResolver == null || portName == null) aoqi@0: ? null : portAddressResolver.getAddressFor(serviceName, portName.getLocalPart(), portAddress); aoqi@0: } aoqi@0: }