001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.wsrp.services;
023:
024: import org.jboss.logging.Logger;
025: import org.jboss.portal.common.io.IOTools;
026: import org.jboss.portal.common.net.URLTools;
027: import org.jboss.portal.common.util.ParameterValidation;
028: import org.xml.sax.InputSource;
029:
030: import javax.wsdl.Definition;
031: import javax.wsdl.Port;
032: import javax.wsdl.WSDLException;
033: import javax.wsdl.extensions.ExtensibilityElement;
034: import javax.wsdl.extensions.soap.SOAPAddress;
035: import javax.wsdl.factory.WSDLFactory;
036: import javax.wsdl.xml.WSDLLocator;
037: import javax.xml.namespace.QName;
038: import java.io.IOException;
039: import java.io.InputStream;
040: import java.net.MalformedURLException;
041: import java.net.URL;
042: import java.util.Collection;
043: import java.util.Iterator;
044:
045: /**
046: * @author <a href="mailto:chris.laprun@jboss.com">Chris Laprun</a>
047: * @version $Revision: 9349 $
048: * @since 2.4 (May 3, 2006)
049: */
050: public class RemoteSOAPInvokerServiceFactory extends
051: PerEndpointSOAPInvokerServiceFactory {
052: private final Logger log = Logger.getLogger(getClass());
053:
054: private String wsdlDefinitionURL;
055:
056: private static final String WSRP_URN = "urn:oasis:names:tc:wsrp:v1:wsdl";
057: private static final String DEFAULT_SERVICE_NAME = "WSRPService";
058:
059: // Used to heuristically determine which interface to use for a port based on its name
060: private static final String DESCRIPTION = "description";
061: private static final String MARKUP = "markup";
062: private static final String BASE = "base"; // some WSDL use WSRPBaseService instead of Markup
063: private static final String MANAGEMENT = "management";
064: private static final String REGISTRATION = "registration";
065: private boolean available;
066:
067: public String getWsdlDefinitionURL() {
068: return wsdlDefinitionURL;
069: }
070:
071: public void setWsdlDefinitionURL(String wsdlDefinitionURL)
072: throws Exception {
073: if (wsdlDefinitionURL == null
074: || wsdlDefinitionURL.length() == 0) {
075: throw new IllegalArgumentException(
076: "Require a non-empty, non-null URL specifying where to find the WSRP "
077: + "services definition");
078: }
079: this .wsdlDefinitionURL = wsdlDefinitionURL;
080: try {
081: initServices();
082: available = true;
083: failed = false;
084: } catch (MalformedURLException e) {
085: IllegalArgumentException iae = new IllegalArgumentException(
086: "Require a well-formed URL specifying where to "
087: + "find the WSRP services definition");
088: iae.initCause(e);
089: available = false;
090: failed = true;
091: throw iae;
092: } catch (Exception e) {
093: log
094: .info(
095: "Couldn't access WSDL information. Service won't be available",
096: e);
097: available = false;
098: failed = true;
099: throw e;
100: }
101: }
102:
103: public boolean isAvailable() {
104: return available && !failed;
105: }
106:
107: private void initServices() throws MalformedURLException {
108: try {
109: URL wsdlURL = new URL(wsdlDefinitionURL);
110:
111: Definition def = getWSDLDefinition(wsdlURL);
112: javax.wsdl.Service serve = def.getService(new QName(
113: WSRP_URN, DEFAULT_SERVICE_NAME));
114: Collection ports = serve.getPorts().values();
115: for (Iterator iterator = ports.iterator(); iterator
116: .hasNext();) {
117: Port port = (Port) iterator.next();
118: initServiceURL(port.getName(), getLocation(port));
119: }
120: } catch (WSDLException e) {
121: throw new RuntimeException(
122: "Couldn't initialize services for WSDL at '"
123: + wsdlDefinitionURL + "'", e);
124: }
125: }
126:
127: /**
128: * Heuristically try to determine which service we're trying to configure.
129: *
130: * @param serviceURL the port location as defined in the given WSDL file
131: * @param portName the port name as defined in the given WSDL file
132: */
133: private void initServiceURL(String portName, String serviceURL) {
134: String normalizedPortName = portName.toLowerCase();
135: log.debug("Service URL: " + serviceURL);
136:
137: if (doesString1ContainString2(normalizedPortName, DESCRIPTION)) {
138: log.info("Found service description port from port name: "
139: + portName);
140: serviceDescriptionURL = serviceURL;
141: return;
142: }
143: if (doesString1ContainString2(normalizedPortName, MARKUP)
144: || doesString1ContainString2(normalizedPortName, BASE)) {
145: log.info("Found markup port from port name: " + portName);
146: markupURL = serviceURL;
147: return;
148: }
149: if (doesString1ContainString2(normalizedPortName, MANAGEMENT)) {
150: log.info("Found porlet management port from port name: "
151: + portName);
152: portletManagementURL = serviceURL;
153: return;
154: }
155: if (doesString1ContainString2(normalizedPortName, REGISTRATION)) {
156: log.info("Found registration port from port name: "
157: + portName);
158: registrationURL = serviceURL;
159: return;
160: }
161: log.warn("Could not find service port matching port name: "
162: + portName);
163: }
164:
165: private boolean doesString1ContainString2(String string1,
166: String string2) {
167: return string1.indexOf(string2) > 0;
168: }
169:
170: //Requires wsdl4j
171: private Definition getWSDLDefinition(URL url) throws WSDLException {
172: log.info("Retrieving WSDL from " + url);
173: WSDLFactory wsdlFactory = WSDLFactory.newInstance();
174: javax.wsdl.xml.WSDLReader wsdlReader = wsdlFactory
175: .newWSDLReader();
176: try {
177: return wsdlReader.readWSDL(new WSDLLocatorImpl(url));
178: } catch (RuntimeException e) {
179: throw new WSDLException(WSDLException.PARSER_ERROR,
180: "Error while reading WSDL", e);
181: }
182: }
183:
184: /** A WSDLLocator that can handle wsdl imports */
185: public static class WSDLLocatorImpl implements WSDLLocator {
186: private URL wsdlURL;
187: private String latestImportURI;
188: private final Logger log = Logger.getLogger(getClass());
189: private static final int TIME_OUT_MS = 10000;
190:
191: private static final String XML_XSD = "http://www.w3.org/2001/xml.xsd";
192: private static final String LOCAL_XML_XSD = "xsd/xml.xsd";
193:
194: public WSDLLocatorImpl(URL wsdlFile) {
195: ParameterValidation.throwIllegalArgExceptionIfNull(
196: wsdlFile, "WSDL URL");
197:
198: this .wsdlURL = wsdlFile;
199: }
200:
201: public void close() {
202: // nothing to do since we don't hold any resources
203: }
204:
205: public InputSource getBaseInputSource() {
206: log.debug("getBaseInputSource [wsdlUrl=" + wsdlURL + "]");
207:
208: try {
209: return new InputSource(URLTools
210: .getContentAsInputStream(wsdlURL, TIME_OUT_MS,
211: TIME_OUT_MS));
212: } catch (IOException e) {
213: throw new RuntimeException(
214: "Couldn't retrieve WSDL for " + wsdlURL, e);
215: }
216: }
217:
218: public String getBaseURI() {
219: return wsdlURL.toExternalForm();
220: }
221:
222: public InputSource getImportInputSource(String parent,
223: String resource) {
224: log.debug("getImportInputSource [parent=" + parent
225: + ",resource=" + resource + "]");
226:
227: URL parentURL;
228: try {
229: parentURL = new URL(parent);
230: } catch (MalformedURLException e) {
231: log.error("Not a valid URL: " + parent);
232: return null;
233: }
234:
235: String wsdlImport;
236: String external = parentURL.toExternalForm();
237:
238: // An external URL
239: if (resource.startsWith("http://")
240: || resource.startsWith("https://")) {
241: wsdlImport = resource;
242: if (XML_XSD.equals(resource)) {
243: InputStream is = Thread.currentThread()
244: .getContextClassLoader()
245: .getResourceAsStream(LOCAL_XML_XSD);
246: log.debug("Using local xml.xsd");
247: return getWSDLImport(wsdlImport, is);
248: }
249: }
250:
251: // Absolute path
252: else if (resource.startsWith("/")) {
253: String beforePath = external.substring(0, external
254: .indexOf(parentURL.getPath()));
255: wsdlImport = beforePath + resource;
256: }
257:
258: // A relative path
259: else {
260: String parentDir = external.substring(0, external
261: .lastIndexOf("/"));
262:
263: // remove references to current dir
264: while (resource.startsWith("./")) {
265: resource = resource.substring(2);
266: }
267:
268: // remove references to parentdir
269: while (resource.startsWith("../")) {
270: parentDir = parentDir.substring(0, parentDir
271: .lastIndexOf("/"));
272: resource = resource.substring(3);
273: }
274:
275: wsdlImport = parentDir + "/" + resource;
276: }
277:
278: try {
279: return getWSDLImport(wsdlImport, new URL(wsdlImport)
280: .openStream());
281: } catch (IOException e) {
282: throw new RuntimeException(
283: "Cannot access imported wsdl [" + wsdlImport
284: + "], " + e.getMessage());
285: }
286: }
287:
288: private InputSource getWSDLImport(String wsdlImport,
289: InputStream inputStream) {
290: log.debug("Resolved to: " + wsdlImport);
291: InputStream is = IOTools.safeBufferedWrapper(inputStream);
292: if (is == null) {
293: throw new IllegalArgumentException(
294: "Cannot import wsdl from [" + wsdlImport + "]");
295: }
296:
297: latestImportURI = wsdlImport;
298: return new InputSource(is);
299: }
300:
301: public String getLatestImportURI() {
302: return latestImportURI;
303: }
304: }
305:
306: private String getLocation(Port port) {
307: String loc = "";
308: Iterator iter = port.getExtensibilityElements().iterator();
309: while (iter.hasNext()) {
310: ExtensibilityElement ext = (ExtensibilityElement) iter
311: .next();
312: if (ext instanceof SOAPAddress) {
313: SOAPAddress add = (SOAPAddress) ext;
314: loc = add.getLocationURI();
315: }
316: }
317: return loc;
318: }
319: }
|