001: /*
002: * Copyright 2001-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: /*
018: * Modified by Nabh Information Systems, Inc. for Stringbeans Web Services
019: * Framework.
020: *
021: * Modifications (c) 2005 Nabh Information Systems, Inc.
022: */
023: package com.nabhinc.ws.soap;
024:
025: import java.io.IOException;
026:
027: import org.apache.axis.AxisFault;
028: import org.apache.axis.Constants;
029: import org.apache.axis.description.ServiceDesc;
030: import org.apache.axis.handlers.soap.SOAPService;
031: import org.apache.axis.wsdl.fromJava.Emitter;
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.w3c.dom.Document;
035: import org.w3c.dom.Element;
036: import org.w3c.dom.Node;
037: import org.w3c.dom.NodeList;
038:
039: import com.nabhinc.ws.core.WebServiceException;
040: import com.nabhinc.ws.server.WebServiceServlet;
041:
042: /**
043: * Handles requests for WSDL documents corresponding to the services hosted by
044: * this server
045: *
046: * @author Padmanabh Dabke
047: * (c) 2005 Nabh Information Systems, Inc. All Rights Reserved.
048: */
049: public class WSDLProcessor {
050: public static final String OPTION_WSDL_PORTTYPE = "wsdlPortType";
051: public static final String OPTION_WSDL_SERVICEELEMENT = "wsdlServiceElement";
052: public static final String OPTION_WSDL_SERVICEPORT = "wsdlServicePort";
053: public static final String OPTION_WSDL_TARGETNAMESPACE = "wsdlTargetNamespace";
054: public static final String OPTION_WSDL_INPUTSCHEMA = "wsdlInputSchema";
055: public static final String OPTION_WSDL_SOAPACTION_MODE = "wsdlSoapActionMode";
056: public static final String OPTION_EXTRACLASSES = "extraClasses";
057:
058: private Log wpLogger = LogFactory.getLog(this .getClass());
059:
060: private SOAPRequestProcessor wpRequestProcessor = null;
061:
062: protected WSDLProcessor(SOAPRequestProcessor rp) {
063: wpRequestProcessor = rp;
064: }
065:
066: protected Document getWSDL(String serviceName, String serverURL,
067: String requestURL) throws IOException, WebServiceException {
068: Document wsdlDoc = generateWSDL(serviceName, serverURL,
069: requestURL);
070: if (wsdlDoc != null) {
071: try {
072: updateSoapAddressLocationURLs(wsdlDoc, serviceName);
073: } catch (RuntimeException re) {
074: wpLogger
075: .warn(
076: "Failed to update soap:address location URL(s) in WSDL.",
077: re);
078: }
079: }
080: return wsdlDoc;
081:
082: }
083:
084: /**
085: * Updates the soap:address locations for all ports in the WSDL using the URL from the request as
086: * the base portion for the updated locations, ensuring the WSDL returned to the client contains
087: * the correct location URL.
088: *
089: * @param wsdlDoc the WSDL as a DOM document
090: * @param msgContext the current Axis JAX-RPC message context
091: * @throws AxisFault if we fail to obtain the list of deployed service names from the server config
092: */
093: protected void updateSoapAddressLocationURLs(Document wsdlDoc,
094: String endpointURL) throws WebServiceException {
095: NodeList wsdlPorts = wsdlDoc
096: .getDocumentElement()
097: .getElementsByTagNameNS(Constants.NS_URI_WSDL11, "port");
098: if (wsdlPorts != null) {
099: String baseEndpointURL = endpointURL.substring(0,
100: endpointURL.lastIndexOf("/") + 1);
101: for (int i = 0; i < wsdlPorts.getLength(); i++) {
102: Element portElem = (Element) wsdlPorts.item(i);
103: Node portNameAttrib = portElem.getAttributes()
104: .getNamedItem("name");
105: if (portNameAttrib == null) {
106: continue;
107: }
108: String portName = portNameAttrib.getNodeValue();
109: NodeList soapAddresses = portElem
110: .getElementsByTagNameNS(
111: Constants.URI_WSDL11_SOAP, "address");
112: if (soapAddresses == null
113: || soapAddresses.getLength() == 0) {
114: soapAddresses = portElem.getElementsByTagNameNS(
115: Constants.URI_WSDL12_SOAP, "address");
116: }
117: if (soapAddresses != null) {
118: for (int j = 0; j < soapAddresses.getLength(); j++) {
119: Element addressElem = (Element) soapAddresses
120: .item(j);
121: Node addressLocationAttrib = addressElem
122: .getAttributes().getNamedItem(
123: "location");
124: if (addressLocationAttrib == null) {
125: continue;
126: }
127: String addressLocation = addressLocationAttrib
128: .getNodeValue();
129: String addressServiceName = addressLocation
130: .substring(addressLocation
131: .lastIndexOf("/") + 1);
132: String newServiceName = getNewServiceName(
133: addressServiceName, portName);
134: if (newServiceName != null) {
135: String newAddressLocation = baseEndpointURL
136: + newServiceName;
137: addressLocationAttrib
138: .setNodeValue(newAddressLocation);
139: wpLogger
140: .debug("Setting soap:address location values in WSDL for port "
141: + portName
142: + " to: "
143: + newAddressLocation);
144: } else {
145: wpLogger
146: .debug("For WSDL port: "
147: + portName
148: + ", unable to match port name or the last component of "
149: + "the SOAP address url with a "
150: + "service name deployed in server-config.wsdd. Leaving SOAP address: "
151: + addressLocation
152: + " unmodified.");
153: }
154: }
155: }
156: }
157: }
158: }
159:
160: private String getNewServiceName(String currentServiceEndpointName,
161: String portName) throws WebServiceException {
162: String endpointName = null;
163: if (WebServiceServlet.getInstance().getWebServiceInfo(
164: currentServiceEndpointName) != null) {
165: endpointName = currentServiceEndpointName;
166: } else if (WebServiceServlet.getInstance().getWebServiceInfo(
167: portName) != null) {
168: endpointName = portName;
169: }
170: return endpointName;
171: }
172:
173: public Document generateWSDL(String serviceName, String serverURL,
174: String reqURL) throws WebServiceException {
175: if (wpLogger.isDebugEnabled())
176: wpLogger.debug("Enter: BasicProvider::generateWSDL ("
177: + this + ")");
178:
179: SOAPService service = wpRequestProcessor
180: .getSOAPService(serviceName);
181: ServiceDesc serviceDesc = service.getServiceDescription();
182:
183: // Calculate the appropriate namespaces for the WSDL we're going
184: // to put out.
185: //
186: // If we've been explicitly told which namespaces to use, respect
187: // that. If not:
188: //
189: // The "interface namespace" should be either:
190: // 1) The namespace of the ServiceDesc
191: // 2) The transport URL (if there's no ServiceDesc ns)
192:
193: // Location URL is whatever is explicitly set in the MC
194: //String locationUrl = msgContext.getStrProp(MessageContext.WSDLGEN_SERV_LOC_URL);
195:
196: try {
197: String locationUrl = serverURL;
198:
199: if (locationUrl == null) {
200: // If nothing, try what's explicitly set in the ServiceDesc
201: locationUrl = serviceDesc.getEndpointURL();
202: }
203:
204: if (locationUrl == null) {
205: // If nothing, use the actual transport URL
206: locationUrl = reqURL;
207:
208: }
209:
210: // Interface namespace is whatever is explicitly set
211: String interfaceNamespace = null; // msgContext.getStrProp(MessageContext.WSDLGEN_INTFNAMESPACE);
212:
213: //if (interfaceNamespace == null) {
214: // If nothing, use the default namespace of the ServiceDesc
215: interfaceNamespace = serviceDesc.getDefaultNamespace();
216: //}
217:
218: if (interfaceNamespace == null) {
219: // If nothing still, use the location URL determined above
220: interfaceNamespace = locationUrl;
221: }
222:
223: //Do we want to do this?
224: //
225: // if (locationUrl == null) {
226: // locationUrl = url;
227: // } else {
228: // try {
229: // URL urlURL = new URL(url);
230: // URL locationURL = new URL(locationUrl);
231: // URL urlTemp = new URL(urlURL.getProtocol(),
232: // locationURL.getHost(),
233: // locationURL.getPort(),
234: // urlURL.getFile());
235: // interfaceNamespace += urlURL.getFile();
236: // locationUrl = urlTemp.toString();
237: // } catch (Exception e) {
238: // locationUrl = url;
239: // interfaceNamespace = url;
240: // }
241: // }
242:
243: Emitter emitter = new Emitter();
244:
245: // This seems like a good idea, but in fact isn't because the
246: // emitter will figure out a reasonable name (<classname>Service)
247: // for the WSDL service element name. We provide the 'alias'
248: // setting to explicitly set this name. See bug 13262 for more info.
249: //emitter.setServiceElementName(serviceDesc.getName());
250:
251: // service alias may be provided if exact naming is required,
252: // otherwise Axis will name it according to the implementing class name
253: String alias = (String) service.getOption("alias");
254: if (alias != null)
255: emitter.setServiceElementName(alias);
256:
257: // Set style/use
258: emitter.setStyle(serviceDesc.getStyle());
259: emitter.setUse(serviceDesc.getUse());
260:
261: if (serviceDesc instanceof JavaServiceDesc) {
262: emitter.setClsSmart(((JavaServiceDesc) serviceDesc)
263: .getImplClass(), locationUrl);
264: }
265:
266: // If a wsdl target namespace was provided, use the targetNamespace.
267: // Otherwise use the interfaceNamespace constructed above.
268: String targetNamespace = (String) service
269: .getOption(OPTION_WSDL_TARGETNAMESPACE);
270: if (targetNamespace == null
271: || targetNamespace.length() == 0) {
272: targetNamespace = interfaceNamespace;
273: }
274: emitter.setIntfNamespace(targetNamespace);
275:
276: emitter.setLocationUrl(locationUrl);
277: emitter.setServiceDesc(serviceDesc);
278: emitter.setTypeMappingRegistry(service
279: .getTypeMappingRegistry());
280:
281: String wsdlPortType = (String) service
282: .getOption(OPTION_WSDL_PORTTYPE);
283: String wsdlServiceElement = (String) service
284: .getOption(OPTION_WSDL_SERVICEELEMENT);
285: String wsdlServicePort = (String) service
286: .getOption(OPTION_WSDL_SERVICEPORT);
287: String wsdlInputSchema = (String) service
288: .getOption(OPTION_WSDL_INPUTSCHEMA);
289: String wsdlSoapActinMode = (String) service
290: .getOption(OPTION_WSDL_SOAPACTION_MODE);
291: String extraClasses = (String) service
292: .getOption(OPTION_EXTRACLASSES);
293:
294: if (wsdlPortType != null && wsdlPortType.length() > 0) {
295: emitter.setPortTypeName(wsdlPortType);
296: }
297: if (wsdlServiceElement != null
298: && wsdlServiceElement.length() > 0) {
299: emitter.setServiceElementName(wsdlServiceElement);
300: }
301: if (wsdlServicePort != null && wsdlServicePort.length() > 0) {
302: emitter.setServicePortName(wsdlServicePort);
303: }
304: if (wsdlInputSchema != null && wsdlInputSchema.length() > 0) {
305: emitter.setInputSchema(wsdlInputSchema);
306: }
307: if (wsdlSoapActinMode != null
308: && wsdlSoapActinMode.length() > 0) {
309: emitter.setSoapAction(wsdlSoapActinMode);
310: }
311:
312: if (extraClasses != null && extraClasses.length() > 0) {
313: emitter.setExtraClasses(extraClasses);
314: }
315:
316: //if (msgContext.isPropertyTrue(AxisEngine.PROP_EMIT_ALL_TYPES)) {
317: emitter.setEmitAllTypes(true);
318: //}
319:
320: Document doc = emitter.emit(Emitter.MODE_ALL);
321: return doc;
322: // msgContext.setProperty("WSDL", doc);
323:
324: } catch (Exception e) {
325: throw new WebServiceException(
326: "Failed to construct WSDL from service description.",
327: e);
328: }
329:
330: }
331:
332: }
|