001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.jaxws.builder;
017:
018: import java.io.IOException;
019: import java.io.InputStream;
020: import java.net.MalformedURLException;
021: import java.net.URI;
022: import java.net.URISyntaxException;
023: import java.net.URL;
024: import java.util.ArrayList;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029: import java.util.jar.JarFile;
030: import java.util.zip.ZipEntry;
031:
032: import javax.wsdl.Binding;
033: import javax.wsdl.Definition;
034: import javax.wsdl.Port;
035: import javax.wsdl.PortType;
036: import javax.wsdl.Service;
037: import javax.wsdl.WSDLException;
038: import javax.wsdl.extensions.ExtensibilityElement;
039: import javax.wsdl.extensions.soap.SOAPAddress;
040: import javax.wsdl.factory.WSDLFactory;
041: import javax.wsdl.xml.WSDLLocator;
042: import javax.wsdl.xml.WSDLReader;
043: import javax.xml.namespace.QName;
044: import javax.xml.ws.WebServiceClient;
045:
046: import org.apache.commons.logging.Log;
047: import org.apache.commons.logging.LogFactory;
048: import org.apache.geronimo.common.DeploymentException;
049: import org.apache.geronimo.jaxws.JAXWSUtils;
050: import org.apache.geronimo.jaxws.client.EndpointInfo;
051: import org.apache.geronimo.xbeans.geronimo.naming.GerPortType;
052: import org.apache.geronimo.xbeans.geronimo.naming.GerServiceRefType;
053: import org.apache.geronimo.xbeans.javaee.PortComponentRefType;
054: import org.xml.sax.InputSource;
055:
056: public class EndpointInfoBuilder {
057:
058: private static final Log LOG = LogFactory
059: .getLog(EndpointInfoBuilder.class);
060:
061: private JarFile moduleFile;
062:
063: private URI wsdlURI;
064:
065: private QName serviceQName;
066:
067: private Class serviceClass;
068:
069: private GerServiceRefType serviceRefType;
070:
071: private Map<Object, EndpointInfo> portInfoMap = new HashMap<Object, EndpointInfo>();
072:
073: private Map<Class, PortComponentRefType> portComponentRefMap;
074:
075: public EndpointInfoBuilder(Class serviceClass,
076: GerServiceRefType serviceRefType,
077: Map<Class, PortComponentRefType> portComponentRefMap,
078: JarFile moduleFile, URI wsdlURI, QName serviceQName) {
079: this .serviceClass = serviceClass;
080: this .serviceRefType = serviceRefType;
081: this .portComponentRefMap = portComponentRefMap;
082: this .moduleFile = moduleFile;
083: this .wsdlURI = wsdlURI;
084: this .serviceQName = serviceQName;
085: }
086:
087: public URI getWsdlURI() {
088: return this .wsdlURI;
089: }
090:
091: public QName getServiceQName() {
092: return this .serviceQName;
093: }
094:
095: public Map<Object, EndpointInfo> getEndpointInfo() {
096: return this .portInfoMap;
097: }
098:
099: public void build() throws DeploymentException {
100: if (this .wsdlURI == null) {
101: // wsdl was not explicitly specified
102: if (javax.xml.ws.Service.class.equals(this .serviceClass)) {
103: // Generic Service class specified.
104: // Service API requires a service qname so create a dummy one
105: this .serviceQName = new QName("http://noservice",
106: "noservice");
107: return;
108: } else {
109: // Generated Service class specified.
110: // Get the wsdl and service qname from the WebServiceClient annotation
111: // of the generated Service class
112: WebServiceClient webServiceClient = (WebServiceClient) this .serviceClass
113: .getAnnotation(WebServiceClient.class);
114: if (webServiceClient != null) {
115: this .wsdlURI = getWSDLLocation(webServiceClient);
116: this .serviceQName = getServiceQName(webServiceClient);
117: }
118:
119: // wsdl really shouldn't be null at this point
120: if (this .wsdlURI == null) {
121: return;
122: }
123: }
124: }
125:
126: JarWSDLLocator wsdlLocator = null;
127: URL wsdlURL = null;
128: try {
129: wsdlURL = new URL(this .wsdlURI.toString());
130: } catch (MalformedURLException e1) {
131: // not a URL, assume it's a local reference
132: wsdlLocator = new JarWSDLLocator(this .wsdlURI);
133: }
134:
135: Definition definition;
136: WSDLFactory wsdlFactory;
137: try {
138: wsdlFactory = WSDLFactory.newInstance();
139: } catch (WSDLException e) {
140: throw new DeploymentException(
141: "Could not create WSDLFactory", e);
142: }
143: WSDLReader wsdlReader = wsdlFactory.newWSDLReader();
144: wsdlReader.setFeature("javax.wsdl.importDocuments", true);
145: wsdlReader.setFeature("javax.wsdl.verbose", false);
146: try {
147: if (wsdlURL != null) {
148: definition = wsdlReader.readWSDL(wsdlURL.toString());
149: } else if (wsdlLocator != null) {
150: definition = wsdlReader.readWSDL(wsdlLocator);
151: } else {
152: throw new DeploymentException("unknown");
153: }
154: } catch (WSDLException e) {
155: throw new DeploymentException(
156: "Failed to read wsdl document", e);
157: } catch (RuntimeException e) {
158: throw new DeploymentException(e.getMessage(), e);
159: }
160:
161: verifyPortComponentList(definition);
162:
163: Map services = definition.getServices();
164: if (services.size() == 0) {
165: // partial wsdl, return as is
166:
167: if (this .serviceRefType != null
168: && this .serviceRefType.isSetServiceCompletion()) {
169: LOG
170: .warn("Service completion is not supported with partial wsdl");
171: }
172: } else {
173: // full wsdl
174:
175: if (this .serviceRefType != null
176: && this .serviceRefType.isSetServiceCompletion()) {
177: throw new DeploymentException(
178: "Full wsdl, but service completion supplied");
179: }
180:
181: Service service = null;
182: if (this .serviceQName != null) {
183: service = definition.getService(this .serviceQName);
184: if (service == null) {
185: throw new DeploymentException(
186: "No service wsdl for supplied service qname "
187: + this .serviceQName);
188: }
189: } else if (services.size() == 1) {
190: service = (Service) services.values().iterator().next();
191: this .serviceQName = service.getQName();
192: } else {
193: throw new DeploymentException(
194: "No service qname supplied, and there are "
195: + services.size() + " services");
196: }
197:
198: // organize the extra port info
199: Map<String, GerPortType> portMap = new HashMap<String, GerPortType>();
200: if (serviceRefType != null) {
201: GerPortType[] ports = serviceRefType.getPortArray();
202: for (int i = 0; i < ports.length; i++) {
203: GerPortType port = ports[i];
204: String portName = port.getPortName().trim();
205: portMap.put(portName, port);
206: }
207: }
208:
209: Map wsdlPortMap = service.getPorts();
210: for (Iterator iterator = wsdlPortMap.entrySet().iterator(); iterator
211: .hasNext();) {
212: Map.Entry entry = (Map.Entry) iterator.next();
213: String portName = (String) entry.getKey();
214: Port port = (Port) entry.getValue();
215:
216: GerPortType gerPort = portMap.get(portName);
217:
218: URL location = (gerPort == null) ? getAddressLocation(port)
219: : getLocation(gerPort);
220: // skip non-soap ports
221: if (location == null) {
222: continue;
223: }
224: String credentialsName = (gerPort == null) ? null
225: : getCredentialsName(gerPort);
226:
227: Binding binding = port.getBinding();
228: if (binding == null) {
229: throw new DeploymentException(
230: "No binding for port: " + portName);
231: }
232:
233: PortType portType = binding.getPortType();
234: if (portType == null) {
235: throw new DeploymentException(
236: "No portType for binding: "
237: + binding.getQName());
238: }
239:
240: boolean mtomEnabled = isMTOMEnabled(portType.getQName());
241:
242: EndpointInfo info = new EndpointInfo(location,
243: credentialsName, mtomEnabled);
244: this .portInfoMap.put(portName, info);
245: // prefer first binding listed in wsdl
246: if (!this .portInfoMap.containsKey(portType.getQName())) {
247: this .portInfoMap.put(portType.getQName(), info);
248: }
249: }
250: }
251: }
252:
253: private QName getServiceQName(WebServiceClient webServiceClient) {
254: if (webServiceClient.targetNamespace() != null
255: && webServiceClient.name() != null) {
256: return new QName(webServiceClient.targetNamespace(),
257: webServiceClient.name());
258: } else {
259: return null;
260: }
261: }
262:
263: private URI getWSDLLocation(WebServiceClient webServiceClient)
264: throws DeploymentException {
265: String wsdlLocation = webServiceClient.wsdlLocation();
266: if (wsdlLocation != null && wsdlLocation.trim().length() > 0) {
267: try {
268: return new URI(wsdlLocation.trim());
269: } catch (URISyntaxException e) {
270: throw new DeploymentException(
271: "Invalid wsdl location in annotation: "
272: + wsdlLocation, e);
273: }
274: }
275:
276: return null;
277: }
278:
279: private String getCredentialsName(GerPortType port) {
280: String credentialsName = port.getCredentialsName();
281: return (credentialsName == null) ? null : credentialsName
282: .trim();
283: }
284:
285: private URL getLocation(GerPortType port)
286: throws DeploymentException {
287: String protocol = port.getProtocol().trim();
288: String host = port.getHost().trim();
289: int portNum = port.getPort();
290: String uri = port.getUri().trim();
291: String locationURIString = protocol + "://" + host + ":"
292: + portNum + uri;
293: URL location = getURL(locationURIString);
294: return location;
295: }
296:
297: private URL getAddressLocation(Port port)
298: throws DeploymentException {
299: SOAPAddress soapAddress = (SOAPAddress) getExtensibilityElement(
300: SOAPAddress.class, port.getExtensibilityElements());
301: URL location = null;
302: if (soapAddress != null) {
303: String locationURIString = soapAddress.getLocationURI();
304: location = getURL(locationURIString);
305: }
306: return location;
307: }
308:
309: private URL getURL(String locationURIString)
310: throws DeploymentException {
311: try {
312: return new URL(locationURIString);
313: } catch (MalformedURLException e) {
314: throw new DeploymentException(
315: "Could not construct web service location URL from "
316: + locationURIString, e);
317: }
318: }
319:
320: public static ExtensibilityElement getExtensibilityElement(
321: Class clazz, List extensibilityElements) {
322: for (Iterator iterator = extensibilityElements.iterator(); iterator
323: .hasNext();) {
324: ExtensibilityElement extensibilityElement = (ExtensibilityElement) iterator
325: .next();
326: if (clazz.isAssignableFrom(extensibilityElement.getClass())) {
327: return extensibilityElement;
328: }
329: }
330: return null;
331: }
332:
333: private void verifyPortComponentList(Definition wsdl)
334: throws DeploymentException {
335: if (this .portComponentRefMap == null) {
336: return;
337: }
338: for (Class sei : this .portComponentRefMap.keySet()) {
339: QName portType = JAXWSUtils.getPortType(sei);
340: if (portType == null) {
341: continue;
342: }
343: if (wsdl.getPortType(portType) == null) {
344: throw new DeploymentException(
345: "No portType found in WSDL for SEI: "
346: + sei.getName());
347: }
348: }
349: }
350:
351: private boolean isMTOMEnabled(QName portType) {
352: boolean mtomEnabled = false;
353: PortComponentRefType portRef = getPortComponentRef(portType);
354: if (portRef != null && portRef.isSetEnableMtom()) {
355: mtomEnabled = portRef.getEnableMtom().getBooleanValue();
356: }
357: return mtomEnabled;
358: }
359:
360: private PortComponentRefType getPortComponentRef(QName portType) {
361: if (this .portComponentRefMap == null) {
362: return null;
363: }
364: for (Class sei : this .portComponentRefMap.keySet()) {
365: QName seiPortType = JAXWSUtils.getPortType(sei);
366: if (seiPortType == null) {
367: continue;
368: }
369: if (portType.equals(seiPortType)) {
370: return this .portComponentRefMap.get(sei);
371: }
372: }
373: return null;
374: }
375:
376: private class JarWSDLLocator implements WSDLLocator {
377:
378: private final List<InputStream> streams = new ArrayList<InputStream>();
379:
380: private final URI wsdlURI;
381:
382: private URI latestImportURI;
383:
384: public JarWSDLLocator(URI wsdlURI) {
385: this .wsdlURI = wsdlURI;
386: }
387:
388: public InputSource getBaseInputSource() {
389: InputStream wsdlInputStream;
390: ZipEntry entry = moduleFile.getEntry(wsdlURI.toString());
391: if (entry == null) {
392: throw new RuntimeException(
393: "WSDL file does not exist in the module "
394: + wsdlURI.toString());
395: }
396: try {
397: wsdlInputStream = moduleFile.getInputStream(entry);
398: streams.add(wsdlInputStream);
399: } catch (Exception e) {
400: throw new RuntimeException(
401: "Could not open stream to wsdl file", e);
402: }
403: return new InputSource(wsdlInputStream);
404: }
405:
406: public String getBaseURI() {
407: return wsdlURI.toString();
408: }
409:
410: public InputSource getImportInputSource(String parentLocation,
411: String relativeLocation) {
412: URI parentURI = URI.create(parentLocation);
413: latestImportURI = parentURI.resolve(relativeLocation);
414: InputStream importInputStream;
415: ZipEntry entry = moduleFile.getEntry(latestImportURI
416: .toString());
417: if (entry == null) {
418: throw new RuntimeException(
419: "File does not exist in the module "
420: + latestImportURI.toString());
421: }
422: try {
423: importInputStream = moduleFile.getInputStream(entry);
424: streams.add(importInputStream);
425: } catch (Exception e) {
426: throw new RuntimeException(
427: "Could not open stream to import file", e);
428: }
429: InputSource inputSource = new InputSource(importInputStream);
430: inputSource.setSystemId(getLatestImportURI());
431: return inputSource;
432: }
433:
434: public String getLatestImportURI() {
435: return latestImportURI.toString();
436: }
437:
438: public void close() {
439: for (InputStream inputStream : this .streams) {
440: try {
441: inputStream.close();
442: } catch (IOException e) {
443: // ignore
444: }
445: }
446: streams.clear();
447: }
448: }
449: }
|