View Javadoc

1   /*
2    * Copyright 2000-2001,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  
17  package org.apache.jetspeed.webservices.finance.stockmarket;
18  
19  import java.io.InputStream;
20  import java.io.OutputStream;
21  import java.io.PrintStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.ByteArrayInputStream;
24  
25  import java.net.URL;
26  import java.net.HttpURLConnection;
27  import java.rmi.RemoteException;
28  import org.xml.sax.helpers.XMLFilterImpl;
29  import org.xml.sax.InputSource;
30  
31  import org.apache.turbine.services.TurbineBaseService;
32  
33  /***
34      Implements StockQuoteService,
35      providing a web service for getting stock quotes.
36          
37      @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
38      @version $Id: JetspeedStockQuoteService.java,v 1.7 2004/02/23 03:15:29 jford Exp $
39  */
40  
41  public class JetspeedStockQuoteService extends TurbineBaseService implements StockQuoteService
42  {
43      boolean debugIO = false;
44      PrintStream debugOutputStream = System.out;
45  
46      // basic SOAP envelope
47      private static final String BASE_SOAP_ENVELOPE =
48          "<?xml version=\"1.0\"?>\n" +
49          "<SOAP-ENV:Envelope " +
50          "\n     xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"" +
51          "\n     xmlns:xsd1=\"urn:DataQuoteService\"" +
52          "\n     xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"" +
53          "\n     xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" +
54          "\n     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
55          "  <SOAP-ENV:Body>\n";
56      private static final String END_SOAP_ENVELOPE = 
57          "  </SOAP-ENV:Body>\n</SOAP-ENV:Envelope>\n";
58      private final static String SOAP_ENCODING = " SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n";
59                                                    
60      // SOAP Service definitions
61      private static final String SERVICE_END_POINT =        
62       "http://www.bluesunrise.com/webservices/container/BlueSunriseFinance/BlueSunriseFinanceService/BlueSunriseFinancePort/";
63  
64      private static final String WSDL_SERVICE_NAMESPACE = "urn:QuoteService";
65      private static final String SOAP_METHOD_QUOTE = WSDL_SERVICE_NAMESPACE + "/quote";
66      private static final String SOAP_METHOD_FULLQUOTE = WSDL_SERVICE_NAMESPACE + "/fullQuote";
67      private static final String SOAP_METHOD_FULLQUOTES = WSDL_SERVICE_NAMESPACE + "/fullQuotes";
68  
69      private String soapEndPoint = SERVICE_END_POINT;
70  
71      // results
72      private static final String QUOTE_RESULT = "quoteResult";
73      private static final String FULL_QUOTE_RESULT = "fullQuoteResult";
74      private static final String FULL_QUOTES_RESULT = "fullQuotesResult";
75      private static final String DEFAULT_RETURN = "return";
76  
77  
78      /***
79          Get a single stock quote, given a symbol return the current price.
80  
81          @param symbol The stock symbol.
82          @return String The current price.
83        */
84      public String quote( String symbol )
85              throws RemoteException
86      {
87          StringBuffer envelope = new StringBuffer(BASE_SOAP_ENVELOPE);        
88          envelope.append("    <m1:quote xmlns:m1=\"urn:QuoteService\"" );
89          envelope.append(SOAP_ENCODING);
90          envelope.append("      <symbol xsi:type=\"xsd:string\">");
91          envelope.append(symbol);
92          envelope.append("</symbol>\n");
93          envelope.append("    </m1:quote>\n");        
94          envelope.append(END_SOAP_ENVELOPE);
95  
96          SOAPResponseHandler handler = new SOAPResponseHandler(WSDL_SERVICE_NAMESPACE, 
97                                                                QUOTE_RESULT, 
98                                                                DEFAULT_RETURN);
99  
100         doSOAPRequest(SOAP_METHOD_QUOTE, envelope, handler);
101 
102         if (handler.isFault()) {
103            throw new RemoteException(handler.getFaultContent());
104         }
105 
106         try 
107         {
108             String resultString = handler.getResult();
109             if (resultString == null) 
110                 throw new RemoteException("Could not find return in soap response");
111             return resultString;
112 
113         } catch (Exception e) {
114             throw new RemoteException("Error generating result.",e);
115         } 
116     }
117 
118     /***
119         Get a single stock quote record, given a symbol return a StockQuote object.
120 
121         @param symbol The stock symbol.
122         @return StockQuote A full stock quote record.
123       */
124     public StockQuote fullQuote( String symbol )
125             throws RemoteException
126     {
127         StringBuffer envelope = new StringBuffer(BASE_SOAP_ENVELOPE);        
128         envelope.append("    <m1:fullQuote xmlns:m1=\"urn:QuoteService\"" );
129         envelope.append(SOAP_ENCODING);
130         envelope.append("      <symbol xsi:type=\"xsd:string\">");
131         envelope.append(symbol);
132         envelope.append("</symbol>\n");
133         envelope.append("    </m1:fullQuote>\n");
134         envelope.append(END_SOAP_ENVELOPE);
135 
136 
137         SOAPResponseHandler handler = new SOAPResponseHandler(WSDL_SERVICE_NAMESPACE, 
138                                                               FULL_QUOTE_RESULT,
139                                                               DEFAULT_RETURN); 
140 
141 
142 
143         StockQuoteHandler quoteHandler = new StockQuoteHandler();
144         handler.setResultHandler(quoteHandler);
145 
146         doSOAPRequest(SOAP_METHOD_FULLQUOTE, envelope, handler);
147         if (handler.isFault()) {
148            throw new RemoteException(handler.getFaultContent());
149         }
150         try {
151             return quoteHandler.getResult();
152         } catch (Exception e) {
153             throw new RemoteException("Error generating result.",e);
154         } 
155 
156     }
157 
158     /***
159         Get an array of quote records, given a array of stock symbols.
160 
161         @param symbols[] The array of stock symbols.
162         @return StockQuote[] An array of full stock quotes for each stock symbol.
163       */
164     public StockQuote[] fullQuotes( String [] symbols )
165             throws RemoteException
166     {
167         if (null == symbols || symbols.length < 1)
168             throw new RemoteException("Invalid symbols[] parameter");
169 
170         StringBuffer envelope = new StringBuffer(BASE_SOAP_ENVELOPE);        
171         envelope.append("    <m1:fullQuotes xmlns:m1=\"urn:QuoteService\"" );
172         envelope.append(SOAP_ENCODING);
173         envelope.append(
174           "      <symbols xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:string["+ symbols.length + "]\">\n");
175 
176         for (int ix = 0; ix < symbols.length; ix++) 
177         {
178             envelope.append("        <item xsi:type=\"xsd:string\">");
179             envelope.append(symbols[ix]);
180             envelope.append("</item>\n");
181         }
182         envelope.append("      ");
183         envelope.append("</symbols>\n");                
184         envelope.append("    </m1:fullQuotes>\n");
185         envelope.append(END_SOAP_ENVELOPE);
186 
187         SOAPResponseHandler handler = new SOAPResponseHandler(WSDL_SERVICE_NAMESPACE, 
188                                                               FULL_QUOTES_RESULT,
189                                                               DEFAULT_RETURN); 
190 
191 
192         StockQuoteArrayHandler quoteHandler = new StockQuoteArrayHandler();
193         handler.setResultHandler(quoteHandler);
194 
195         doSOAPRequest(SOAP_METHOD_FULLQUOTES, envelope, handler);
196         if (handler.isFault()) {
197            throw new RemoteException(handler.getFaultContent());
198         }
199         try {
200             return quoteHandler.getResult();
201         } catch (Exception e) {
202             throw new RemoteException("Error generating result.",e);
203         } 
204 
205     }
206 
207     /***
208         Set the name of the web service used by this service to retrieve stock quotes.
209 
210         @param service The name of the web service.
211       */
212     public void setWebService( String service )
213     {
214         this.soapEndPoint = service;
215     }
216 
217     /***
218         Get the name of the web service used by this service to retrieve stock quotes.
219 
220         @return String The name of the web service.
221       */
222     public String getWebService()
223     {
224         return soapEndPoint;
225     }
226 
227 
228     /***
229         make a SOAP Request to the web service.
230 
231      */      
232     private void doSOAPRequest(String soapAction, StringBuffer envelope, XMLFilterImpl handler) 
233         throws RemoteException 
234     {
235         try {
236             if (debugIO) {
237                 debugOutputStream.println("SOAPURL: "+soapEndPoint);
238                 debugOutputStream.println("SoapAction: "+soapAction);
239                 debugOutputStream.println("SoapEnvelope:");
240                 debugOutputStream.println(envelope.toString());
241             }
242 
243             URL url = new URL(soapEndPoint);
244             HttpURLConnection connect = (HttpURLConnection)url.openConnection();
245             connect.setDoOutput(true);
246             byte bytes[] = envelope.toString().getBytes();
247             connect.setRequestProperty("SOAPAction","\""+soapAction+"\"");
248             connect.setRequestProperty("content-type","text/xml");
249             connect.setRequestProperty("content-length",""+bytes.length);
250 
251             OutputStream out = connect.getOutputStream();
252             out.write(bytes);
253             out.flush();
254 
255             int rc = connect.getResponseCode();
256             InputStream stream = null;
257             if (rc == HttpURLConnection.HTTP_OK) {
258                 stream = connect.getInputStream();
259             } else if (rc == HttpURLConnection.HTTP_INTERNAL_ERROR) {
260                 stream = connect.getErrorStream();
261             }
262             if (stream != null) {
263                 if (debugIO) {
264                     ByteArrayOutputStream bout = new ByteArrayOutputStream();
265                     int bt = stream.read();
266                     while (bt != -1) {
267                         bout.write(bt);
268                         bt = stream.read();
269                     }
270                     debugOutputStream.println("Response:");
271                     debugOutputStream.println(new String(bout.toByteArray()));
272                     stream.close();
273                     stream = new ByteArrayInputStream(bout.toByteArray());
274                 }
275                 String contentType = connect.getContentType();
276                 if (contentType.indexOf("text/xml") == -1) {
277                     throw new RemoteException("Content-type not text/xml.  Instead, found "+contentType);
278                 }
279                 org.apache.xerces.parsers.SAXParser xmlreader = new org.apache.xerces.parsers.SAXParser();
280                 // TODO TODO
281                 // uncomment this block and comment out the above line to use a generic parser
282                 //SAXParserFactory factory = SAXParserFactory.newInstance();
283                 //factory.setNamespaceAware(true);
284                 //SAXParser saxparser = factory.newSAXParser();
285                 //XMLReader xmlreader = saxparser.getXMLReader();
286                 handler.setParent(xmlreader);
287                 xmlreader.setContentHandler(handler);
288                 xmlreader.parse(new InputSource(stream));
289                 stream.close();
290             } else {
291                 throw new RemoteException("Communication error: "+rc+" "+connect.getResponseMessage());
292             }
293         } catch (RemoteException rex) {
294             throw rex;
295         } catch (Exception ex) {
296             throw new RemoteException("Error doing soap stuff",ex);
297         }
298     }
299 
300 
301     ///////////////////////////////////////////////////////////////////////////
302 
303     /***
304       usage: 
305          
306           java JetspeedStockQuoteService [option] method [params]
307 
308           method:           parameter:       description:
309           ----------------------------------------------------------------------
310             quote             symbol       get the price for the given symbol  
311             quotes            symbols..    get the prices for 1..n symbols 
312             fullQuote         symbol       get a stock quote record for the given symbol
313             fullQuotes        symbols...   1..n symbols to look up multiple stock quote records
314 
315 
316           options:
317           --------
318             -debug            print to stdout the SOAP request and response packets
319 
320           Examples:
321              java JetspeedStockQuoteService quote IBM
322              java JetspeedStockQuoteService quotes IONA CSCO NOK ADSK
323              java JetspeedStockQuoteService -debug fullQuote DST
324              java JetspeedStockQuoteService fullQuotes SUNW MSFT ORCL
325 
326 
327 
328      **/
329     public static void main (String args[]) {
330          try {
331              JetspeedStockQuoteService service = new JetspeedStockQuoteService();
332 
333              if (args.length == 0) {
334                  return;
335              }
336 
337              int index = 0;
338              // any options
339              if (args[index].startsWith("-"))
340              {
341                 if ("-debug".equals(args[0])) 
342                 {
343                     service.debugIO = true;
344                     index++;
345                 }
346              }
347              if (index >= args.length)
348                 return;
349 
350              if ("quote".equals(args[index]))
351              {
352                 index++;
353                 if (index >= args.length)
354                     return;
355                 System.out.println( service.quote(args[index]) );
356              }
357              else if ("quotes".equals(args[index]))
358              {
359                 // NOT YET IMPLEMENTED
360              }
361              else if ("fullQuote".equals(args[index]))
362              {
363                 index++;
364                 if (index >= args.length)
365                     return;
366                 System.out.println( service.fullQuote(args[index]));
367              }
368              else if ("fullQuotes".equals(args[index]))
369              {
370                 index++;
371                 String[] symbols = new String[args.length - index];
372                 for (int ix = 0 ; ix < symbols.length; ix++)
373                 {
374                     symbols[ix] = args[index];
375                     index++;
376                 }
377                 StockQuote[] stocks = service.fullQuotes( symbols );
378                 for (int ix = 0; ix < stocks.length; ix++)
379                     System.out.println( stocks[ix] );
380              }
381          } catch (Exception ex) {
382              ex.printStackTrace();
383          }
384      }
385 
386 }