KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > james > imapserver > ImapHandler


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

17
18 package org.apache.james.imapserver;
19
20 import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
21 import org.apache.avalon.excalibur.pool.Poolable;
22 import org.apache.avalon.framework.activity.Disposable;
23 import org.apache.avalon.framework.logger.AbstractLogEnabled;
24 import org.apache.avalon.framework.logger.Logger;
25 import org.apache.avalon.framework.logger.LogEnabled;
26 import org.apache.james.Constants;
27 import org.apache.james.imapserver.commands.ImapCommand;
28 import org.apache.james.imapserver.commands.ImapCommandFactory;
29 import org.apache.james.imapserver.commands.CommandParser;
30 import org.apache.james.imapserver.store.ImapMailbox;
31 import org.apache.james.services.MailRepository;
32 import org.apache.james.services.User;
33 import org.apache.james.services.UsersRepository;
34 import org.apache.james.util.InternetPrintWriter;
35 import org.apache.james.util.watchdog.Watchdog;
36 import org.apache.james.util.watchdog.WatchdogTarget;
37
38 import java.io.BufferedOutputStream JavaDoc;
39 import java.io.BufferedReader JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.io.InputStreamReader JavaDoc;
42 import java.io.OutputStream JavaDoc;
43 import java.io.PrintWriter JavaDoc;
44 import java.io.Writer JavaDoc;
45 import java.io.Reader JavaDoc;
46 import java.io.InputStream JavaDoc;
47 import java.net.Socket JavaDoc;
48
49 /**
50  * The handler class for IMAP connections.
51  * TODO: This is a quick cut-and-paste hack from POP3Handler. This, and the ImapServer
52  * should probably be rewritten from scratch.
53  *
54  */

55 public class ImapHandler
56         extends AbstractLogEnabled
57         implements ConnectionHandler, Poolable, ImapConstants
58 {
59
60     private String JavaDoc softwaretype = "JAMES IMAP4rev1 Server " + Constants.SOFTWARE_VERSION;
61     private ImapRequestHandler requestHandler = new ImapRequestHandler();
62     private ImapSession session;
63
64     /**
65      * The per-service configuration data that applies to all handlers
66      */

67     private ImapHandlerConfigurationData theConfigData;
68
69     /**
70      * The mail server's copy of the user's inbox
71      */

72     private MailRepository userInbox;
73
74     /**
75      * The thread executing this handler
76      */

77     private Thread JavaDoc handlerThread;
78
79     /**
80      * The TCP/IP socket over which the IMAP interaction
81      * is occurring
82      */

83     private Socket JavaDoc socket;
84
85     /**
86      * The reader associated with incoming characters.
87      */

88     private BufferedReader JavaDoc in;
89
90     /**
91      * The socket's input stream.
92      */

93     private InputStream JavaDoc ins;
94
95     /**
96      * The writer to which outgoing messages are written.
97      */

98     private PrintWriter out;
99
100     /**
101      * The socket's output stream
102      */

103     private OutputStream JavaDoc outs;
104
105     /**
106      * The watchdog being used by this handler to deal with idle timeouts.
107      */

108     private Watchdog theWatchdog;
109
110     /**
111      * The watchdog target that idles out this handler.
112      */

113     private WatchdogTarget theWatchdogTarget = new IMAPWatchdogTarget();
114
115     /**
116      * Set the configuration data for the handler.
117      *
118      * @param theData the configuration data
119      */

120     void setConfigurationData( ImapHandlerConfigurationData theData )
121     {
122         theConfigData = theData;
123     }
124
125     /**
126      * Set the Watchdog for use by this handler.
127      *
128      * @param theWatchdog the watchdog
129      */

130     void setWatchdog( Watchdog theWatchdog )
131     {
132         this.theWatchdog = theWatchdog;
133     }
134
135     /**
136      * Gets the Watchdog Target that should be used by Watchdogs managing
137      * this connection.
138      *
139      * @return the WatchdogTarget
140      */

141     WatchdogTarget getWatchdogTarget()
142     {
143         return theWatchdogTarget;
144     }
145
146     /**
147      * Idle out this connection
148      */

149     void idleClose()
150     {
151         // TODO: Send BYE message before closing.
152
if ( getLogger() != null ) {
153             getLogger().error( "IMAP Connection has idled out." );
154         }
155         try {
156             if ( socket != null ) {
157                 socket.close();
158             }
159         }
160         catch ( Exception JavaDoc e ) {
161             // ignored
162
}
163         finally {
164             socket = null;
165         }
166
167         synchronized ( this ) {
168             // Interrupt the thread to recover from internal hangs
169
if ( handlerThread != null ) {
170                 handlerThread.interrupt();
171                 handlerThread = null;
172             }
173         }
174
175     }
176
177     /**
178      * @see ConnectionHandler#handleConnection(Socket)
179      */

180     public void handleConnection( Socket JavaDoc connection )
181             throws IOException JavaDoc
182     {
183
184         String JavaDoc remoteHost = "";
185         String JavaDoc remoteIP = "";
186
187         try {
188             this.socket = connection;
189             synchronized ( this ) {
190                 handlerThread = Thread.currentThread();
191             }
192             ins = socket.getInputStream();
193             in = new BufferedReader JavaDoc( new InputStreamReader JavaDoc( socket.getInputStream(), "ASCII" ), 512 );
194             remoteIP = socket.getInetAddress().getHostAddress();
195             remoteHost = socket.getInetAddress().getHostName();
196         }
197         catch ( IOException JavaDoc e ) {
198             if ( getLogger().isErrorEnabled() ) {
199                 StringBuffer JavaDoc exceptionBuffer =
200                         new StringBuffer JavaDoc( 256 )
201                         .append( "Cannot open connection from " )
202                         .append( remoteHost )
203                         .append( " (" )
204                         .append( remoteIP )
205                         .append( "): " )
206                         .append( e.getMessage() );
207                 getLogger().error( exceptionBuffer.toString(), e );
208             }
209             throw e;
210         }
211
212         if ( getLogger().isInfoEnabled() ) {
213             StringBuffer JavaDoc logBuffer =
214                     new StringBuffer JavaDoc( 128 )
215                     .append( "Connection from " )
216                     .append( remoteHost )
217                     .append( " (" )
218                     .append( remoteIP )
219                     .append( ") " );
220             getLogger().info( logBuffer.toString() );
221         }
222
223         try {
224             outs = new BufferedOutputStream JavaDoc( socket.getOutputStream(), 1024 );
225             out = new InternetPrintWriter( outs, true );
226             ImapResponse response = new ImapResponse( outs );
227
228             // Write welcome message
229
StringBuffer JavaDoc responseBuffer =
230                     new StringBuffer JavaDoc( 256 )
231                     .append( VERSION )
232                     .append( " Server " )
233                     .append( theConfigData.getHelloName() )
234                     .append( " ready" );
235             response.okResponse( null, responseBuffer.toString() );
236
237             session = new ImapSessionImpl( theConfigData.getImapHost(),
238                                            theConfigData.getUsersRepository(),
239                                            this,
240                                            socket.getInetAddress().getHostName(),
241                                            socket.getInetAddress().getHostAddress());
242
243             theWatchdog.start();
244             while ( requestHandler.handleRequest( ins, outs, session ) ) {
245                 theWatchdog.reset();
246             }
247             theWatchdog.stop();
248
249             //Write BYE message.
250
if ( getLogger().isInfoEnabled() ) {
251                 StringBuffer JavaDoc logBuffer =
252                         new StringBuffer JavaDoc( 128 )
253                         .append( "Connection for " )
254                         .append( session.getUser().getUserName() )
255                         .append( " from " )
256                         .append( remoteHost )
257                         .append( " (" )
258                         .append( remoteIP )
259                         .append( ") closed." );
260                 getLogger().info( logBuffer.toString() );
261             }
262
263         }
264         catch ( Exception JavaDoc e ) {
265             out.println( "Error closing connection." );
266             out.flush();
267             StringBuffer JavaDoc exceptionBuffer =
268                     new StringBuffer JavaDoc( 128 )
269                     .append( "Exception on connection from " )
270                     .append( remoteHost )
271                     .append( " (" )
272                     .append( remoteIP )
273                     .append( ") : " )
274                     .append( e.getMessage() );
275             getLogger().error( exceptionBuffer.toString(), e );
276         }
277         finally {
278             resetHandler();
279         }
280     }
281
282     /**
283      * Resets the handler data to a basic state.
284      */

285     void resetHandler()
286     {
287
288         if ( theWatchdog != null ) {
289             if ( theWatchdog instanceof Disposable ) {
290                 ( ( Disposable ) theWatchdog ).dispose();
291             }
292             theWatchdog = null;
293         }
294
295         // Close and clear streams, sockets
296

297         try {
298             if ( socket != null ) {
299                 socket.close();
300                 socket = null;
301             }
302         }
303         catch ( IOException JavaDoc ioe ) {
304             // Ignoring exception on close
305
}
306         finally {
307             socket = null;
308         }
309
310         try {
311             if ( in != null ) {
312                 in.close();
313             }
314         }
315         catch ( Exception JavaDoc e ) {
316             // Ignored
317
}
318         finally {
319             in = null;
320         }
321
322         try {
323             if ( out != null ) {
324                 out.close();
325             }
326         }
327         catch ( Exception JavaDoc e ) {
328             // Ignored
329
}
330         finally {
331             out = null;
332         }
333
334         try {
335             if ( outs != null ) {
336                 outs.close();
337             }
338         }
339         catch ( Exception JavaDoc e ) {
340             // Ignored
341
}
342         finally {
343             outs = null;
344         }
345
346         synchronized ( this ) {
347             handlerThread = null;
348         }
349
350         // Clear user data
351
session = null;
352
353         // Clear config data
354
theConfigData = null;
355     }
356
357     /**
358      * Implements a "stat". If the handler is currently in
359      * a transaction state, this amounts to a rollback of the
360      * mailbox contents to the beginning of the transaction.
361      * This method is also called when first entering the
362      * transaction state to initialize the handler copies of the
363      * user inbox.
364      *
365      */

366     private void stat()
367     {
368 // userMailbox = new Vector();
369
// userMailbox.addElement(DELETED);
370
// for (Iterator it = userInbox.list(); it.hasNext(); ) {
371
// String key = (String) it.next();
372
// MailImpl mc = userInbox.retrieve(key);
373
// // Retrieve can return null if the mail is no longer in the store.
374
// // In this case we simply continue to the next key
375
// if (mc == null) {
376
// continue;
377
// }
378
// userMailbox.addElement(mc);
379
// }
380
// backupUserMailbox = (Vector) userMailbox.clone();
381
}
382
383     /**
384      * This method logs at a "DEBUG" level the response string that
385      * was sent to the POP3 client. The method is provided largely
386      * as syntactic sugar to neaten up the code base. It is declared
387      * private and final to encourage compiler inlining.
388      *
389      * @param responseString the response string sent to the client
390      */

391     private final void logResponseString( String JavaDoc responseString )
392     {
393         if ( getLogger().isDebugEnabled() ) {
394             getLogger().debug( "Sent: " + responseString );
395         }
396     }
397
398     /**
399      * Write and flush a response string. The response is also logged.
400      * Should be used for the last line of a multi-line response or
401      * for a single line response.
402      *
403      * @param responseString the response string sent to the client
404      */

405     final void writeLoggedFlushedResponse( String JavaDoc responseString )
406     {
407         out.println( responseString );
408         out.flush();
409         logResponseString( responseString );
410     }
411
412     /**
413      * Write a response string. The response is also logged.
414      * Used for multi-line responses.
415      *
416      * @param responseString the response string sent to the client
417      */

418     final void writeLoggedResponse( String JavaDoc responseString )
419     {
420         out.println( responseString );
421         logResponseString( responseString );
422     }
423
424     /**
425      * A private inner class which serves as an adaptor
426      * between the WatchdogTarget interface and this
427      * handler class.
428      */

429     private class IMAPWatchdogTarget
430             implements WatchdogTarget
431     {
432
433         /**
434          * @see WatchdogTarget#execute()
435          */

436         public void execute()
437         {
438             ImapHandler.this.idleClose();
439         }
440
441     }
442
443 }
444
445
Popular Tags