001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036: package com.sun.xml.ws.server;
037:
038: import com.sun.xml.ws.api.server.PortAddressResolver;
039: import com.sun.xml.ws.api.server.WSEndpoint;
040: import com.sun.xml.ws.api.server.DocumentAddressResolver;
041: import com.sun.xml.ws.api.server.SDDocument;
042: import com.sun.xml.ws.util.xml.XMLStreamReaderToXMLStreamWriter;
043: import com.sun.xml.ws.wsdl.parser.WSDLConstants;
044: import com.sun.xml.ws.addressing.W3CAddressingConstants;
045: import com.sun.istack.Nullable;
046:
047: import javax.xml.namespace.QName;
048: import javax.xml.stream.XMLStreamException;
049: import java.net.MalformedURLException;
050: import java.net.URL;
051: import java.util.logging.Logger;
052:
053: /**
054: * Patches WSDL with the correct endpoint address and the relative paths
055: * to other documents.
056: *
057: * @author Jitendra Kotamraju
058: * @author Kohsuke Kawaguchi
059: */
060: final class WSDLPatcher extends XMLStreamReaderToXMLStreamWriter {
061:
062: private static final String NS_XSD = "http://www.w3.org/2001/XMLSchema";
063: private static final QName SCHEMA_INCLUDE_QNAME = new QName(NS_XSD,
064: "include");
065: private static final QName SCHEMA_IMPORT_QNAME = new QName(NS_XSD,
066: "import");
067: private static final QName SCHEMA_REDEFINE_QNAME = new QName(
068: NS_XSD, "redefine");
069:
070: private static final Logger logger = Logger
071: .getLogger(com.sun.xml.ws.util.Constants.LoggingDomain
072: + ".wsdl.patcher");
073:
074: /**
075: * {@link WSEndpoint} that owns the WSDL we are patching right now.
076: */
077: private final WSEndpointImpl<?> endpoint;
078:
079: /**
080: * Document that is being patched.
081: */
082: private final SDDocumentImpl current;
083:
084: private final DocumentAddressResolver resolver;
085: private final PortAddressResolver portAddressResolver;
086:
087: //
088: // fields accumulated as we parse through documents
089: //
090: private String targetNamespace;
091: private QName serviceName;
092: private QName portName;
093:
094: private enum EPR_ADDRESS_STATE {
095: IN, OUT, DONE
096: }
097:
098: private EPR_ADDRESS_STATE eprAddressState = EPR_ADDRESS_STATE.OUT;
099:
100: /**
101: * Creates a {@link WSDLPatcher} for patching WSDL.
102: *
103: * @param endpoint
104: * The endpoint that we are patchinig WSDL for. This object is consulted
105: * to check other {@link SDDocument}s. Must not be null.
106: * @param current
107: * The document that we are patching. Must not be null.
108: * @param portAddressResolver
109: * address of the endpoint is resolved using this resolver.
110: * @param resolver
111: * Consulted to generate references among {@link SDDocument}s.
112: * Must not be null.
113: */
114: public WSDLPatcher(WSEndpointImpl<?> endpoint,
115: SDDocumentImpl current,
116: PortAddressResolver portAddressResolver,
117: DocumentAddressResolver resolver) {
118: this .endpoint = endpoint;
119: this .current = current;
120: this .portAddressResolver = portAddressResolver;
121: this .resolver = resolver;
122: }
123:
124: @Override
125: protected void handleAttribute(int i) throws XMLStreamException {
126: QName name = in.getName();
127: String attLocalName = in.getAttributeLocalName(i);
128:
129: if ((name.equals(SCHEMA_INCLUDE_QNAME) && attLocalName
130: .equals("schemaLocation"))
131: || (name.equals(SCHEMA_IMPORT_QNAME) && attLocalName
132: .equals("schemaLocation"))
133: || (name.equals(SCHEMA_REDEFINE_QNAME) && attLocalName
134: .equals("schemaLocation"))
135: || (name.equals(WSDLConstants.QNAME_IMPORT) && attLocalName
136: .equals("location"))) {
137: // patch this attribute value.
138:
139: String relPath = in.getAttributeValue(i);
140: String actualPath = getPatchedImportLocation(relPath);
141: if (actualPath == null) {
142: return; // skip this attribute to leave it up to "implicit reference".
143: }
144:
145: logger.fine("Fixing the relative location:" + relPath
146: + " with absolute location:" + actualPath);
147: writeAttribute(i, actualPath);
148: return;
149: }
150:
151: if (name.equals(WSDLConstants.NS_SOAP_BINDING_ADDRESS)
152: || name.equals(WSDLConstants.NS_SOAP12_BINDING_ADDRESS)) {
153:
154: if (attLocalName.equals("location")) {
155: String value = getAddressLocation();
156: if (value != null) {
157: logger.fine("Fixing service:" + serviceName
158: + " port:" + portName + " address with "
159: + value);
160: writeAttribute(i, value);
161: return;
162: }
163: }
164: }
165:
166: super .handleAttribute(i);
167: }
168:
169: /**
170: * Writes out an {@code i}-th attribute but with a different value.
171: * @param i attribute index
172: * @param value attribute value
173: * @throws XMLStreamException when an error encountered while writing attribute
174: */
175: private void writeAttribute(int i, String value)
176: throws XMLStreamException {
177: String nsUri = in.getAttributeNamespace(i);
178: if (nsUri != null)
179: out.writeAttribute(in.getAttributePrefix(i), nsUri, in
180: .getAttributeLocalName(i), value);
181: else
182: out.writeAttribute(in.getAttributeLocalName(i), value);
183: }
184:
185: @Override
186: protected void handleStartElement() throws XMLStreamException {
187: QName name = in.getName();
188:
189: if (name.equals(WSDLConstants.QNAME_DEFINITIONS)) {
190: //String value = in.getAttributeValue("","targetNamespace");
191: String value = in
192: .getAttributeValue(null, "targetNamespace");
193: if (value != null) {
194: targetNamespace = value;
195: }
196: } else if (name.equals(WSDLConstants.QNAME_SERVICE)) {
197: //String value = in.getAttributeValue("","name");
198: String value = in.getAttributeValue(null, "name");
199: if (value != null) {
200: serviceName = new QName(targetNamespace, value);
201: }
202: } else if (name.equals(WSDLConstants.QNAME_PORT)) {
203: //String value = in.getAttributeValue("","name");
204: String value = in.getAttributeValue(null, "name");
205: if (value != null) {
206: portName = new QName(targetNamespace, value);
207: }
208: } else if (name
209: .equals(W3CAddressingConstants.WSA_ADDRESS_QNAME)) {
210: eprAddressState = EPR_ADDRESS_STATE.IN;
211: }
212: super .handleStartElement();
213: }
214:
215: @Override
216: protected void handleEndElement() throws XMLStreamException {
217: QName name = in.getName();
218: if (name.equals(W3CAddressingConstants.WSA_ADDRESS_QNAME)) {
219: eprAddressState = EPR_ADDRESS_STATE.OUT;
220: }
221: super .handleEndElement();
222: }
223:
224: @Override
225: protected void handleCharacters() throws XMLStreamException {
226: // handleCharacters() may be called multiple times. To take care of this,
227: // EPR_ADDRESS_STATE is used.
228: if (eprAddressState == EPR_ADDRESS_STATE.IN) {
229: String value = getAddressLocation();
230: if (value != null) {
231: logger.fine("Fixing EPR Address for service:"
232: + serviceName + " port:" + portName
233: + " address with " + value);
234: out.writeCharacters(value);
235: eprAddressState = EPR_ADDRESS_STATE.DONE;
236: }
237: }
238: if (eprAddressState != EPR_ADDRESS_STATE.DONE) {
239: super .handleCharacters();
240: }
241: }
242:
243: /**
244: * Returns the location to be placed into the generated document.
245: *
246: * @param relPath relative URI to be resolved
247: * @return
248: * null to leave it to the "implicit reference".
249: */
250: private @Nullable
251: String getPatchedImportLocation(String relPath) {
252: try {
253: ServiceDefinitionImpl def = endpoint.getServiceDefinition();
254: assert def != null; // this code is only used by ServieDefinitionImpl, so this must not be null.
255:
256: URL ref = new URL(current.getURL(), relPath);
257: SDDocument refDoc = def.getBySystemId(ref);
258: if (refDoc == null)
259: return relPath; // not something we know. just leave it as is.
260:
261: return resolver.getRelativeAddressFor(current, refDoc);
262: } catch (MalformedURLException mue) {
263: return null;
264: }
265: }
266:
267: /**
268: * For the given service, port names it matches the correct endpoint and
269: * reutrns its endpoint address
270: *
271: * @return returns the resolved endpoint address
272: */
273: private String getAddressLocation() {
274: return (portAddressResolver == null || portName == null) ? null
275: : portAddressResolver.getAddressFor(serviceName,
276: portName.getLocalPart());
277: }
278: }
|