View Javadoc

1   /*
2    * $Id: PromptStdioConnector.java 19198 2010-08-25 21:43:19Z aperepel $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transport.stdio;
12  
13  import org.mule.api.MuleContext;
14  import org.mule.api.MuleException;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.endpoint.ImmutableEndpoint;
17  import org.mule.api.lifecycle.InitialisationException;
18  import org.mule.api.transport.Connector;
19  import org.mule.config.i18n.MessageFactory;
20  import org.mule.util.StringUtils;
21  
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  
25  /**
26   * <code>PromptStdioConnector</code> connects to the System streams in and out by
27   * default and add some basic fuctionality for writing out prompt messages.
28   */
29  public class PromptStdioConnector extends StdioConnector
30  {   
31      private String promptMessage;
32      private String promptMessageCode = null;
33      private String resourceBundle = null;
34      private String outputMessage;
35      private String outputMessageCode = null;
36      private long messageDelayTime = 3000;
37      private boolean firstTime = true;
38  
39      public PromptStdioConnector(MuleContext context)
40      {
41          super(context);
42          
43          inputStream = System.in;
44          outputStream = System.out;
45      }
46  
47      protected void doInitialise() throws InitialisationException
48      {
49          // We need to use the same classloder that creates and initalizes this
50          // connector when looking for resources
51          StdioMessageFactory stdioMessageFactory = new StdioMessageFactory(Thread.currentThread()
52              .getContextClassLoader());
53  
54          // Load messages from resource bundle if resourceBundle and
55          // promptMessageCode are both set
56          if (StringUtils.isNotBlank(resourceBundle) && StringUtils.isNotBlank(promptMessageCode))
57          {
58              promptMessage = stdioMessageFactory.getString(resourceBundle, promptMessageCode);
59          }
60          if (StringUtils.isNotBlank(resourceBundle) && StringUtils.isNotBlank(outputMessageCode))
61          {
62              outputMessage = stdioMessageFactory.getString(resourceBundle, outputMessageCode);
63          }
64      }
65  
66      protected void doDispose()
67      {
68          // Override as a no-op.
69          // The reason is System.in/out shouldn't be closed.
70          // It is valid for them to remain open (consider, e.g. tail -F).
71          // Trying to close System.in will result in I/O block, and
72          // available() will always return 0 bytes for System.in.
73  
74          // There is a scheme to get a ref to System.in via NIO,
75          // e.g. :
76          // FileInputStream fis = new FileInputStream(FileDescriptor.in);
77          // InputStream is = Channels.newInputStream(fis.getChannel);
78          //
79          // It is then possible to register a watchdog thread for the caller
80          // which will interrupt this (now wrapped with NIO) read() call.
81  
82          // Well, it isn't absolutely required for the reasons stated above,
83          // just following the KISS principle.
84      }
85  
86      protected void doConnect() throws Exception
87      {
88          // template method
89      }
90  
91      protected void doDisconnect() throws Exception
92      {
93          // template method
94      }
95  
96      public InputStream getInputStream()
97      {
98          return inputStream;
99      }
100 
101     public void doStart()
102     {
103         firstTime = false;
104     }
105 
106     public OutputStream getOutputStream()
107     {
108         return outputStream;
109     }
110 
111     /**
112      * @return Returns the promptMessage.
113      */
114     public String getPromptMessage()
115     {
116         return promptMessage;
117     }
118 
119     /**
120      * @param promptMessage The promptMessage to set.
121      */
122     public void setPromptMessage(String promptMessage)
123     {
124         this.promptMessage = promptMessage;
125     }
126 
127     /**
128      * @return Returns the promptMessageCode.
129      */
130     public String getPromptMessageCode()
131     {
132         return promptMessageCode;
133     }
134 
135     /**
136      * @param promptMessageCode The promptMessageCode to set.
137      */
138     public void setPromptMessageCode(String promptMessageCode)
139     {
140         this.promptMessageCode = promptMessageCode;
141     }
142 
143     /**
144      * @return Returns the resourceBundle.
145      */
146     public String getResourceBundle()
147     {
148         return resourceBundle;
149     }
150 
151     /**
152      * @param resourceBundle The resourceBundle to read the message from. This property is 
153      * only needed in conjunction with promptMessageCode or outputMessageCode.
154      */
155     public void setResourceBundle(String resourceBundle)
156     {
157         this.resourceBundle = resourceBundle;
158     }
159 
160     /**
161      * @return Returns the outputMessage.
162      */
163     public String getOutputMessage()
164     {
165         return outputMessage;
166     }
167 
168     /**
169      * @param outputMessage The outputMessage to set.
170      */
171     public void setOutputMessage(String outputMessage)
172     {
173         this.outputMessage = outputMessage;
174     }
175 
176     /**
177      * @return Returns the outputMessageCode.
178      */
179     public String getOutputMessageCode()
180     {
181         return outputMessageCode;
182     }
183 
184     /**
185      * @param outputMessageCode The outputMessageCode to set.
186      */
187     public void setOutputMessageCode(String outputMessageCode)
188     {
189         this.outputMessageCode = outputMessageCode;
190     }
191 
192     public Connector getConnector()
193     {
194         return this;
195     }
196 
197     public long getMessageDelayTime()
198     {
199         if (firstTime)
200         {
201             return messageDelayTime + 4000;
202         }
203         else
204         {
205             return messageDelayTime;
206         }
207     }
208 
209     public void setMessageDelayTime(long messageDelayTime)
210     {
211         this.messageDelayTime = messageDelayTime;
212     }
213 
214 
215     public OutputStream getOutputStream(ImmutableEndpoint endpoint, MuleMessage message) throws MuleException
216     {
217         OutputStream out;
218         String streamName = endpoint.getEndpointURI().getAddress();
219 
220         if (STREAM_SYSTEM_OUT.equalsIgnoreCase(streamName))
221         {
222             out = System.out;
223         }
224         else if (STREAM_SYSTEM_ERR.equalsIgnoreCase(streamName))
225         {
226             out = System.err;
227         }
228         else
229         {
230             out = getOutputStream();
231         }
232         return out;
233     }
234     
235     /**
236      * {@link PromptStdioConnector} needs a way to access other modules' messages.
237      * The default way to access messages is by using {@link MessageFactory} which
238      * itself is not meant to be used directly. In order not to soften this
239      * requiement this private subclass offers access to {@link MessageFactory}'s
240      * methods.
241      */
242     private static class StdioMessageFactory extends MessageFactory
243     {
244         private ClassLoader resourceClassLoader;
245 
246         public StdioMessageFactory(ClassLoader classLoader)
247         {
248             super();
249             resourceClassLoader = classLoader;
250         }
251 
252         protected String getString(String bundlePath, String code)
253         {
254             return super.getString(bundlePath, Integer.parseInt(code));
255         }
256 
257         @Override
258         protected ClassLoader getClassLoader()
259         {
260             return resourceClassLoader;
261         }
262     }
263 }