KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > generation > WebServiceProxyGenerator


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.generation;
17
18 import org.apache.avalon.framework.parameters.Parameters;
19 import org.apache.avalon.framework.service.ServiceException;
20 import org.apache.cocoon.ProcessingException;
21 import org.apache.cocoon.components.source.SourceUtil;
22 import org.apache.cocoon.environment.ObjectModelHelper;
23 import org.apache.cocoon.environment.Request;
24 import org.apache.cocoon.environment.Session;
25 import org.apache.cocoon.environment.SourceResolver;
26 import org.apache.commons.httpclient.HostConfiguration;
27 import org.apache.commons.httpclient.HttpClient;
28 import org.apache.commons.httpclient.HttpMethod;
29 import org.apache.commons.httpclient.NameValuePair;
30 import org.apache.commons.httpclient.URI;
31 import org.apache.commons.httpclient.URIException;
32 import org.apache.commons.httpclient.methods.GetMethod;
33 import org.apache.commons.httpclient.methods.PostMethod;
34 import org.apache.commons.lang.StringUtils;
35 import org.apache.excalibur.source.Source;
36 import org.apache.excalibur.source.SourceException;
37 import org.apache.excalibur.xml.sax.SAXParser;
38 import org.apache.regexp.RE;
39 import org.xml.sax.InputSource JavaDoc;
40 import org.xml.sax.SAXException JavaDoc;
41
42 import java.io.ByteArrayInputStream JavaDoc;
43 import java.io.IOException JavaDoc;
44 import java.util.ArrayList JavaDoc;
45 import java.util.Enumeration JavaDoc;
46 import java.util.Map JavaDoc;
47 import java.util.StringTokenizer JavaDoc;
48
49 /**
50  *
51  * The WebServiceProxyGenerator is intended to:
52  *
53  * 1) Allow easy syndication of dynamic interactive content as a natural extension of the currently popular static content syndication with RSS.
54  *
55  * 2) Allow transparent routing of web service request through GET, POST, SOAP-RPC and SOAP-DOC binding methods.
56  *
57  * 3) Allow almost full control through sitemap configuration.
58  *
59  * 4) Allow use of Cocoon components for content formatting, aggregation and styling through a tight integration with the Cocoon sitemap.
60  *
61  * 5) Require 0 (zero) lines of Java or other business logic code in most cases.
62  *
63  * 6) Be generic and flexible enough to allow custom extensions for advanced and non-typical uses.
64  *
65  * 7) Support sessions, authentication, http 1.1, https, request manipulation, redirects following, connection pooling, and others.
66  *
67  * 8) Use the Jakarta HttpClient library which provides many sophisticated features for HTTP connections.
68  *
69  * 9) (TBD) Use Axis for SOAP-RPC and SOAP-DOC bindings.
70  *
71  *
72  * @author <a HREF="mailto:ivelin@apache.org">Ivelin Ivanov</a>, June 30, 2002
73  * @author <a HREF="mailto:tony@apache.org">Tony Collen</a>, December 2, 2002
74  * @version CVS $Id: WebServiceProxyGenerator.java 53915 2004-10-06 21:54:58Z antonio $
75  */

76 public class WebServiceProxyGenerator extends ServiceableGenerator {
77
78     private static final String JavaDoc HTTP_CLIENT = "HTTP_CLIENT";
79     private static final String JavaDoc METHOD_GET = "GET";
80     private static final String JavaDoc METHOD_POST = "POST";
81
82     private HttpClient httpClient = null;
83     private String JavaDoc configuredHttpMethod = null;
84
85     public void setup(SourceResolver resolver, Map JavaDoc objectModel, String JavaDoc src, Parameters par) throws ProcessingException, SAXException JavaDoc, IOException JavaDoc {
86         super.setup(resolver, objectModel, src, par);
87
88         try {
89             Source inputSource = resolver.resolveURI(super.source);
90             this.source = inputSource.getURI();
91         } catch (SourceException se) {
92             throw SourceUtil.handle("Unable to resolve " + super.source, se);
93         }
94
95         this.configuredHttpMethod = par.getParameter("wsproxy-method", METHOD_GET);
96         this.httpClient = this.getHttpClient();
97     }
98
99     /**
100      * Generate XML data.
101      */

102     public void generate() throws IOException JavaDoc, SAXException JavaDoc, ProcessingException {
103         SAXParser parser = null;
104         try {
105             if (this.getLogger().isDebugEnabled()) {
106                 this.getLogger().debug("processing Web Service request: " + this.source);
107             }
108
109             // forward request and bring response back
110
byte[] response = this.fetch();
111             if (this.getLogger().isDebugEnabled()) {
112                 this.getLogger().debug("response: " + new String JavaDoc(response));
113             }
114
115             /* TODO: Though I avoided the getResponseBodyAsString(), the content
116              * seems not to be parsed correctly. Who cares about the encoding
117              * in the XML declaration?
118              * {@link http://jakarta.apache.org/commons/httpclient/apidocs/org/apache/commons/httpclient/HttpMethodBase.html#getResponseBodyAsString()}
119              */

120             ByteArrayInputStream JavaDoc responseStream = new ByteArrayInputStream JavaDoc(response);
121             InputSource JavaDoc inputSource = new InputSource JavaDoc(responseStream);
122             parser = (SAXParser)this.manager.lookup(SAXParser.ROLE);
123             parser.parse(inputSource, super.xmlConsumer);
124
125         } catch (ServiceException ex) {
126             throw new ProcessingException("WebServiceProxyGenerator.generate() error", ex);
127         } finally {
128             this.manager.release(parser);
129         }
130
131     } // generate
132

133     /**
134      * Recycle this component.
135      * All instance variables are set to <code>null</code>.
136      */

137     public void recycle() {
138         this.httpClient = null;
139         this.configuredHttpMethod = null;
140         super.recycle();
141     }
142
143     /**
144      * Forwards the request and returns the response.
145      *
146      * The rest is probably out of date:
147      * Will use a UrlGetMethod to benefit the cacheing mechanism
148      * and intermediate proxy servers.
149      * It is potentially possible that the size of the request
150      * may grow beyond a certain limit for GET and it will require POST instead.
151      *
152      * @return byte[] XML response
153      */

154     public byte[] fetch() throws ProcessingException {
155         HttpMethod method = null;
156
157         // check which method (GET or POST) to use.
158
if (this.configuredHttpMethod.equalsIgnoreCase(METHOD_POST)) {
159             method = new PostMethod(this.source);
160         } else {
161             method = new GetMethod(this.source);
162         }
163
164         if (this.getLogger().isDebugEnabled()) {
165             this.getLogger().debug("request HTTP method: " + method.getName());
166         }
167
168         // this should probably be exposed as a sitemap option
169
method.setFollowRedirects(true);
170
171         // copy request parameters and merge with URL parameters
172
Request request = ObjectModelHelper.getRequest(objectModel);
173
174         ArrayList JavaDoc paramList = new ArrayList JavaDoc();
175         Enumeration JavaDoc enumeration = request.getParameterNames();
176         while (enumeration.hasMoreElements()) {
177             String JavaDoc pname = (String JavaDoc)enumeration.nextElement();
178             String JavaDoc[] paramsForName = request.getParameterValues(pname);
179             for (int i = 0; i < paramsForName.length; i++) {
180                 NameValuePair pair = new NameValuePair(pname, paramsForName[i]);
181                 paramList.add(pair);
182             }
183         }
184
185         if (paramList.size() > 0) {
186             NameValuePair[] allSubmitParams = new NameValuePair[paramList.size()];
187             paramList.toArray(allSubmitParams);
188
189             String JavaDoc urlQryString = method.getQueryString();
190
191             // use HttpClient encoding routines
192
method.setQueryString(allSubmitParams);
193             String JavaDoc submitQryString = method.getQueryString();
194
195             // set final web service query string
196

197             // sometimes the querystring is null here...
198
if (null == urlQryString) {
199                 method.setQueryString(submitQryString);
200             } else {
201                 method.setQueryString(urlQryString + "&" + submitQryString);
202             }
203             
204         } // if there are submit parameters
205

206         byte[] response = null;
207         try {
208             int httpStatus = httpClient.executeMethod(method);
209             if (httpStatus < 400) {
210                 if (this.getLogger().isDebugEnabled()) {
211                     this.getLogger().debug("Return code when accessing the remote Url: " + httpStatus);
212                 }
213             } else {
214                 throw new ProcessingException("The remote returned error " + httpStatus + " when attempting to access remote URL:" + method.getURI());
215             }
216         } catch (URIException e) {
217             throw new ProcessingException("There is a problem with the URI: " + this.source, e);
218         } catch (IOException JavaDoc e) {
219             try {
220                 throw new ProcessingException("Exception when attempting to access the remote URL: " + method.getURI(), e);
221             } catch (URIException ue) {
222                 throw new ProcessingException("There is a problem with the URI: " + this.source, ue);
223             }
224         } finally {
225             /* It is important to always read the entire response and release the
226              * connection regardless of whether the server returned an error or not.
227              * {@link http://jakarta.apache.org/commons/httpclient/tutorial.html}
228              */

229             response = method.getResponseBody();
230             method.releaseConnection();
231         }
232
233         return response;
234     } // fetch
235

236     /**
237      * Create one per client session.
238      */

239     protected HttpClient getHttpClient() throws ProcessingException {
240         URI uri = null;
241         String JavaDoc host = null;
242         Request request = ObjectModelHelper.getRequest(objectModel);
243         Session session = request.getSession(true);
244         HttpClient httpClient = null;
245         if (session != null) {
246             httpClient = (HttpClient)session.getAttribute(HTTP_CLIENT);
247         }
248         if (httpClient == null) {
249             httpClient = new HttpClient();
250             HostConfiguration config = httpClient.getHostConfiguration();
251             if (config == null) {
252                 config = new HostConfiguration();
253             }
254             
255             
256             /* TODO: fixme!
257              * When the specified source sent to the wsproxy is not "http"
258              * (e.g. "cocoon:/"), the HttpClient throws an exception. Does the source
259              * here need to be resolved before being set in the HostConfiguration?
260              */

261             try {
262                 uri = new URI(this.source);
263                 host = uri.getHost();
264                 config.setHost(uri);
265             } catch (URIException ex) {
266                 throw new ProcessingException("URI format error: " + ex, ex);
267             }
268
269             // Check the http.nonProxyHosts to see whether or not the current
270
// host needs to be served through the proxy server.
271
boolean proxiableHost = true;
272             String JavaDoc nonProxyHosts = System.getProperty("http.nonProxyHosts");
273             if (nonProxyHosts != null)
274             {
275                 StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(nonProxyHosts, "|");
276
277                 while (tok.hasMoreTokens()) {
278                     String JavaDoc nonProxiableHost = tok.nextToken().trim();
279
280                     // XXX is there any other characters that need to be
281
// escaped?
282
nonProxiableHost = StringUtils.replace(nonProxiableHost, ".", "\\.");
283                     nonProxiableHost = StringUtils.replace(nonProxiableHost, "*", ".*");
284
285                     // XXX do we want .example.com to match
286
// computer.example.com? it seems to be a very common
287
// idiom for the nonProxyHosts, in that case then we want
288
// to change "^" to "^.*"
289
RE re = null;
290                     try {
291                         re = new RE("^" + nonProxiableHost + "$");
292                     }
293                     catch (Exception JavaDoc ex) {
294                         throw new ProcessingException("Regex syntax error: " + ex, ex);
295                     }
296
297                     if (re.match(host))
298                     {
299                         proxiableHost = false;
300                         break;
301                     }
302                 }
303             }
304
305             if (proxiableHost && System.getProperty("http.proxyHost") != null) {
306                 String JavaDoc proxyHost = System.getProperty("http.proxyHost");
307                 int proxyPort = Integer.parseInt(System.getProperty("http.proxyPort"));
308                 config.setProxy(proxyHost, proxyPort);
309             }
310
311             httpClient.setHostConfiguration(config);
312
313             session.setAttribute(HTTP_CLIENT, httpClient);
314         }
315         return httpClient;
316     }
317
318
319 } // class
320
Popular Tags