View Javadoc

1   /**
2    * $Id: ServerSocketLineReaderConsumer.java 55 2006-11-08 14:06:59Z maldito_orco $
3    * $Revision: 55 $
4    * $Date: 2006-11-08 11:06:59 -0300 (Wed, 08 Nov 2006) $
5    *
6    * =========================================================================
7    *
8    * Copyright 2005 Tubo
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *     http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   */
22  package org.tubo.resource.consumer.serversocketlinereader;
23  
24  //log
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  //tubo
28  import org.tubo.resource.consumer.serversocket.ServerSocketConsumer;
29  import org.tubo.resource.flow.FlowContext;
30  import org.tubo.exception.TuboConsumerException;
31  import org.tubo.item.Item;
32  //io
33  import java.io.InputStream;
34  import java.io.OutputStream;
35  import java.io.PrintWriter;
36  import java.io.BufferedReader;
37  import java.io.InputStreamReader;
38  import java.io.IOException;
39  //net
40  import java.net.Socket;
41  //util
42  import java.util.Map;
43  import java.util.StringTokenizer;
44  import java.util.HashMap;
45  
46  /**
47   * <p>
48   * This class is a Consumer Component based on ServerSocket.
49   * When the connection is established on ServerSocketConsumerWorker this class
50   * call process(Socket) on ServerSocketConsumer which is overwited by this
51   * class.
52   * When a process(Socket) is call, streams are opened and delegate procesing
53   * to process(InputStream,OutputStream). In this method tree event are throw:
54   * <li>
55   *   <ul>NEW_CONNECTION_EVENT: which can be used to sey hello :)</ul>
56   *   <ul>READ_LINE_EVENT: which is throw when a new line of text is read</ul>
57   *   <ul>GOODBYE_EVENT: which is throw when the text read matches with 'goodbye-words' property</ul>
58   * </li>
59   * </p>
60   * <p>
61   * The method process(Socket) is override by this class,
62   * </p>
63   *
64   * <p>
65   * Created: Oct 19, 2006, 6:12:44 PM<br>
66   * Last Modification Date: $Date: 2006-11-08 11:06:59 -0300 (Wed, 08 Nov 2006) $
67   * </p>
68   *
69   * @author maldito_orco (maldito_orco@users.sourceforge.net)
70   * @version $Revision: 55 $
71   */
72  public class ServerSocketLineReaderConsumer extends ServerSocketConsumer {
73      public static final String RCS_ID = "$Id: ServerSocketLineReaderConsumer.java 55 2006-11-08 14:06:59Z maldito_orco $";
74      private static Log log = LogFactory.getLog(ServerSocketLineReaderConsumer.class);
75  
76      public static final String SERVERSOCKET_LINE_READER_INPUT_PROPERTY = "SSLINEREADER_INPUT";
77      public static final String SERVERSOCKET_LINE_READER_OUTPUT_PROPERTY = "SSLINEREADER_OUTPUT";
78  
79      public static final String READ_LINE_EVENT = "READ_LINE_EVENT";
80      public static final String GOODBYE_EVENT = "GOODBYE_EVENT";
81  
82      /** Singleton item for this consumer thread */
83      private Item item = null;
84      private PrintWriter out = null;
85      private BufferedReader in = null;
86  
87      private Map goodbyeWords = null;
88  
89      /**
90       * <p>
91       * Override normal ServerSocketConsumer behavior. On this implementation
92       * obtains in and out streams. Delegate the stream procesing on other
93       * method.
94       * </p>
95       *
96       * @param socket A new socket open from client
97       * @throws TuboConsumerException When geting InputStream or OutputStream from socket
98       */
99      public void process(Socket socket) throws TuboConsumerException {
100         InputStream is = null;
101         OutputStream os = null;
102         try {
103             //
104             // get input
105             is = socket.getInputStream();
106             //
107             // get output
108             os = socket.getOutputStream();
109             //
110             // process streams
111             process(is,os);
112         } catch (IOException e) {
113             throw getResourceManager().getExceptionManager().getException(3510,e);
114         } finally {
115             if (os!=null)
116                 try {
117                     //
118                     // close os
119                     os.flush();
120                     os.close();
121                 } catch (IOException e) {
122                     log.info("Error closing OutputStream",e);
123                 }
124             if (is!=null)
125                 try {
126                     //
127                     // close is
128                     is.close();
129                 } catch (IOException e) {
130                     log.info("Error closing InputStream",e);
131                 }
132         }
133     }
134 
135 
136     /**
137      * <p>
138      * Streams Procesing.
139      * </p>
140      *
141      * @param is Socket input
142      * @param os Socket output
143      * @throws TuboConsumerException
144      */
145     public void process(InputStream is, OutputStream os) throws TuboConsumerException {
146         //
147         // load goodbye words (cut condition)
148         if (goodbyeWords==null)
149             loadGoodbyeWords();
150         //
151         // process is
152         try {
153             //
154             // create in
155             in = new BufferedReader(new InputStreamReader(is));
156             //
157             // create out
158             out = new PrintWriter(os, true);
159             //
160             // ey! can you say HELO!!!
161             // calling consume life cycle with newconnection event
162             doConsumerLifeCycle(NEW_CONNECTION_EVENT,null);
163             //
164             //read/write cycle
165             String inputLine;
166             boolean goodbye =false;
167             while ((!goodbye) && ((inputLine = in.readLine()) != null)) {
168                 //
169                 // check cut condition
170                 if (goodbyeWords.containsKey(inputLine)) {
171                     goodbye=true;
172                     doConsumerLifeCycle(GOODBYE_EVENT, inputLine);
173                 } else
174                     doConsumerLifeCycle(READ_LINE_EVENT, inputLine);
175             }
176         } catch (IOException e) {
177             throw getResourceManager().getExceptionManager().getException(3511,e);
178         } finally {
179             if (out!=null)
180                 try {
181                     out.flush();
182                 } catch (Exception e) {
183                     log.info("Error flushing OutputStream",e);
184                 }
185         }
186     }
187 
188 
189     /**
190      * Override this method to create only one item.
191      * To create the item the super method is used.
192      *
193      * @return The item
194      * TODO: move this behavior to BaseConsumerImpl...
195      */
196     protected Item createItem() {
197         if (item == null)
198             item = super.createItem();
199         return item;
200 
201     }
202 
203     /**
204      * Hook from consumer life cycle called before listener execution.
205      * This method have the responsability of set input line like a
206      * item property.
207      *
208      * @param flowContext The flowContext
209      */
210     protected void preOriginFlowEvent(FlowContext flowContext) {
211         if (!NEW_CONNECTION_EVENT.equals(flowContext.getOriginEvent().getAction())) {
212         String inputLine = (String)flowContext.getItem().getConsumedRawData();
213         if (inputLine!=null)
214             item.setProperty(SERVERSOCKET_LINE_READER_INPUT_PROPERTY,inputLine);
215         }
216     }
217 
218 
219     /**
220      * Hook from consumer life cycle called after listener execution.
221      *  
222      * @param flowContext The item
223      */
224     protected void postOriginFlowEvent(FlowContext flowContext) {
225         //
226         // get output
227         String outputLine = (String)flowContext.getItem().getProperty(SERVERSOCKET_LINE_READER_OUTPUT_PROPERTY);
228         //
229         // print output
230         if (outputLine != null)
231             out.println(outputLine);
232         //
233         // TODO: EXEPTIONS!!!!
234     }
235 
236     /**
237      * Load goodbyeWords Map. This words are cut condition for read/write cycle.
238      *
239      * @throws TuboConsumerException This exception is throw if property 'goodbye-words' is not configured or with a wrong format. 
240      */
241     private void loadGoodbyeWords() throws TuboConsumerException {
242         goodbyeWords = new HashMap();
243         //
244         // get goodbye words
245         String goodbyeWordsString = super.getProperty("goodbye-words");
246         //
247         // check if null
248         if (goodbyeWordsString==null || "".equals(goodbyeWordsString.trim()))
249                 throw getResourceManager().getExceptionManager().getException(3512);
250         //
251         // create tokenizer
252         StringTokenizer tokenizer = new StringTokenizer(goodbyeWordsString,",",false);
253         //
254         // check number of tokens
255         if (tokenizer.countTokens()==0)
256             throw getResourceManager().getExceptionManager().getException(3513,goodbyeWordsString);
257         //
258         // iterate words
259         while (tokenizer.hasMoreElements()) {
260             //
261             // get word
262             String word = tokenizer.nextToken();
263             //
264             // put word
265             goodbyeWords.put(word,word);
266         }
267     }
268 }