KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mx4j > tools > adaptor > http > HttpAdaptor


1 /*
2  * Copyright (C) The MX4J Contributors.
3  * All rights reserved.
4  *
5  * This software is distributed under the terms of the MX4J License version 1.0.
6  * See the terms of the MX4J License in the documentation provided with this software.
7  */

8
9 package mx4j.tools.adaptor.http;
10
11 import java.io.IOException JavaDoc;
12 import java.io.InputStream JavaDoc;
13 import java.io.InterruptedIOException JavaDoc;
14 import java.io.OutputStream JavaDoc;
15 import java.net.ServerSocket JavaDoc;
16 import java.net.Socket JavaDoc;
17 import java.util.Date JavaDoc;
18 import java.util.HashMap JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.StringTokenizer JavaDoc;
22
23 import javax.management.JMException JavaDoc;
24 import javax.management.MBeanRegistration JavaDoc;
25 import javax.management.MBeanServer JavaDoc;
26 import javax.management.MalformedObjectNameException JavaDoc;
27 import javax.management.ObjectName JavaDoc;
28 import javax.xml.parsers.DocumentBuilder JavaDoc;
29 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
30 import javax.xml.parsers.ParserConfigurationException JavaDoc;
31
32 import mx4j.log.Log;
33 import mx4j.log.Logger;
34 import mx4j.tools.adaptor.AdaptorServerSocketFactory;
35 import mx4j.tools.adaptor.PlainAdaptorServerSocketFactory;
36 import mx4j.util.Base64Codec;
37 import org.w3c.dom.Document JavaDoc;
38
39 /**
40  * HttpAdaptor sets the basic adaptor listening for HTTP requests
41  *
42  * @version $Revision: 1.14 $
43  */

44 public class HttpAdaptor implements HttpAdaptorMBean, MBeanRegistration JavaDoc
45 {
46    private static final String JavaDoc VERSION = "3.0.2";
47
48    /**
49     * Port to listen for connections
50     */

51    private int port = 8080;
52
53    /**
54     * Host where to set the server socket
55     */

56    private String JavaDoc host = "localhost";
57
58    /**
59     * Target server
60     */

61    private MBeanServer JavaDoc server;
62
63    /**
64     * Server socket
65     */

66    private ServerSocket JavaDoc serverSocket;
67
68    /**
69     * Indicates whether the server is running
70     */

71    private boolean alive;
72
73    /**
74     * Map of commands indexed by the request path
75     */

76    private Map JavaDoc commands = new HashMap JavaDoc();
77
78    /**
79     * Target processor
80     */

81    private ProcessorMBean processor = null;
82
83    /**
84     * Target processor name
85     */

86    private ObjectName JavaDoc processorName = null;
87
88    /**
89     * Default processor
90     */

91    private ProcessorMBean defaultProcessor = new DefaultProcessor();
92
93    private String JavaDoc authenticationMethod = "none";
94
95    // Should be dependant on the server?
96
private String JavaDoc realm = "MX4J";
97
98    private Map JavaDoc authorizations = new HashMap JavaDoc();
99
100    private AdaptorServerSocketFactory socketFactory = null;
101
102    private ObjectName JavaDoc factoryName;
103
104    private String JavaDoc processorClass;
105
106    private Date JavaDoc startDate;
107
108    private long requestsCount;
109
110    private String JavaDoc[][] defaultCommandProcessors = {
111       {"server", "mx4j.tools.adaptor.http.ServerCommandProcessor"},
112       {"serverbydomain", "mx4j.tools.adaptor.http.ServerByDomainCommandProcessor"},
113       {"mbean", "mx4j.tools.adaptor.http.MBeanCommandProcessor"},
114       {"setattributes", "mx4j.tools.adaptor.http.SetAttributesCommandProcessor"},
115       {"setattribute", "mx4j.tools.adaptor.http.SetAttributeCommandProcessor"},
116       {"getattribute", "mx4j.tools.adaptor.http.GetAttributeCommandProcessor"},
117       {"delete", "mx4j.tools.adaptor.http.DeleteMBeanCommandProcessor"},
118       {"invoke", "mx4j.tools.adaptor.http.InvokeOperationCommandProcessor"},
119       {"create", "mx4j.tools.adaptor.http.CreateMBeanCommandProcessor"},
120       {"constructors", "mx4j.tools.adaptor.http.ConstructorsCommandProcessor"},
121       {"relation", "mx4j.tools.adaptor.http.RelationCommandProcessor"},
122       {"empty", "mx4j.tools.adaptor.http.EmptyCommandProcessor"}};
123
124    private DocumentBuilder JavaDoc builder;
125
126    /**
127     * Default Constructor added so that we can have some additional
128     * constructors as well.
129     */

130    public HttpAdaptor()
131    {
132    }
133
134    /**
135     * Overloaded constructor to allow the port to be set.
136     * The reason this was added was to allow the loading of this adaptor by
137     * the dynamic loading service of the MBean server and have the port set
138     * from a param in the mlet file. Example: (replaced lt & gt symbol with [])
139     * <br>[mlet code="mx4j.tools.adaptor.http.HttpAdaptor"
140     * <br> archive="mx4j.jar"
141     * <br> name="Server:name=HttpAdaptor"]
142     * <br> [arg type="int" value="12345"]
143     * <br>[/mlet]
144     * <p/>
145     * <p>This constructor uses the default host or the host must be set later.
146     *
147     * @param port The port on which the HttpAdaptor should listen
148     */

149    public HttpAdaptor(int port)
150    {
151       this.port = port;
152    }
153
154
155    /**
156     * Overloaded constructor to allow the host to be set.
157     * The reason this was added was to allow the loading of this adaptor by
158     * the dynamic loading service of the MBean server and have the host set
159     * from a param in the mlet file. Example: (replaced lt & gt symbol with [])
160     * <br>[mlet code="mx4j.tools.adaptor.http.HttpAdaptor"
161     * <br> archive="mx4j.jar"
162     * <br> name="Server:name=HttpAdaptor"]
163     * <br> [arg type="java.lang.String" value="someserver.somehost.com"]
164     * <br>[/mlet]
165     * <p/>
166     * <p>This constructor uses the default port or the port must be set later.
167     *
168     * @param host The host on which the HttpAdaptor should listen
169     */

170    public HttpAdaptor(String JavaDoc host)
171    {
172       this.host = host;
173    }
174
175
176    /**
177     * Overloaded constructor to allow the port to be set.
178     * The reason this was added was to allow the loading of this adaptor by
179     * the dynamic loading service of the MBean server and have the port set
180     * from a param in the mlet file. Example: (replaced lt & gt symbol with [])
181     * NOTE that the port must come before the host in the arg list of the mlet
182     * <br>[mlet code="mx4j.tools.adaptor.http.HttpAdaptor"
183     * <br> archive="mx4j.jar"
184     * <br> name="Server:name=HttpAdaptor"]
185     * <br> [arg type="int" value="12345"]
186     * <br> [arg type="java.lang.String" value="someserver.somehost.com"]
187     * <br>[/mlet]
188     *
189     * @param port The port on which the HttpAdaptor should listen
190     * @param host The host on which the HttpAdaptor should listen
191     */

192    public HttpAdaptor(int port, String JavaDoc host)
193    {
194       this.port = port;
195       this.host = host;
196    }
197
198
199    /**
200     * Sets the value of the server's port
201     *
202     * @param port the new port's value
203     */

204    public void setPort(int port)
205    {
206       if (alive)
207       {
208          throw new IllegalArgumentException JavaDoc("Not possible to change port with the server running");
209       }
210       this.port = port;
211    }
212
213
214    /**
215     * Returns the port where the server is running on. Default is 8080
216     *
217     * @return HTTPServer's port
218     */

219    public int getPort()
220    {
221       return port;
222    }
223
224
225    /**
226     * Sets the host name where the server will be listening
227     *
228     * @param host Server's host
229     */

230    public void setHost(String JavaDoc host)
231    {
232       if (alive)
233       {
234          throw new IllegalArgumentException JavaDoc("Not possible to change port with the server running");
235       }
236       this.host = host;
237    }
238
239
240    /**
241     * Return the host name the server will be listening to. If null the server
242     * listen at the localhost
243     *
244     * @return the current hostname
245     */

246    public String JavaDoc getHost()
247    {
248       return host;
249    }
250
251
252    /**
253     * Sets the Authentication Method.
254     *
255     * @param method none/basic/digest
256     */

257    public void setAuthenticationMethod(String JavaDoc method)
258    {
259       if (alive)
260       {
261          throw new IllegalArgumentException JavaDoc("Not possible to change authentication method with the server running");
262       }
263       if (method == null || !(method.equals("none") || method.equals("basic") || method.equals("digest")))
264       {
265          throw new IllegalArgumentException JavaDoc("Only accept methods none/basic/digest");
266       }
267       this.authenticationMethod = method;
268    }
269
270
271    /**
272     * Authentication Method
273     *
274     * @return authentication method
275     */

276    public String JavaDoc getAuthenticationMethod()
277    {
278       return authenticationMethod;
279    }
280
281
282    /**
283     * Sets the object which will post process the XML results. The last value set
284     * between the setPostProcessor and setPostProcessorName will be the valid one
285     *
286     * @param processor a Post processor object
287     */

288    public void setProcessor(ProcessorMBean processor)
289    {
290       this.processor = processor;
291       this.processorName = null;
292    }
293
294
295    /**
296     * Sets the classname of the object which will post process the XML results. The adaptor
297     * will try to build the object and use the processor name ObjectName to register it
298     * The class name has to implements mx4j.tools.adaptor.http.ProcessorMBean and be MBean
299     * compliant
300     *
301     * @param processorClass a Post processor object
302     */

303    public void setProcessorClass(String JavaDoc processorClass)
304    {
305       this.processorClass = processorClass;
306    }
307
308
309    /**
310     * Sets the object name of the PostProcessor MBean. If ProcessorClass is set the processor
311     * will be created
312     *
313     * @param processorName a Post processor object
314     */

315    public void setProcessorNameString(String JavaDoc processorName) throws MalformedObjectNameException JavaDoc
316    {
317       this.processorName = new ObjectName JavaDoc(processorName);
318    }
319
320
321    /**
322     * Sets the object name which will post process the XML result. The last value
323     * set between the setPostProcessor and setPostProcessorName will be the valid
324     * one. The MBean will be verified to be of instance HttpPostProcessor
325     *
326     * @param processorName The new processorName value
327     */

328    public void setProcessorName(ObjectName JavaDoc processorName)
329    {
330       this.processor = null;
331       this.processorName = processorName;
332    }
333
334    public ProcessorMBean getProcessor()
335    {
336       return this.processor;
337    }
338
339    public ObjectName JavaDoc getProcessorName()
340    {
341       return this.processorName;
342    }
343
344    /**
345     * Sets the object which create the server sockets
346     *
347     * @param factory the socket factory
348     */

349    public void setSocketFactory(AdaptorServerSocketFactory factory)
350    {
351       this.factoryName = null;
352       this.socketFactory = factory;
353    }
354
355
356    /**
357     * Sets the factory's object name which will create the server sockets
358     *
359     * @param factoryName the socket factory
360     */

361    public void setSocketFactoryName(ObjectName JavaDoc factoryName)
362    {
363       this.socketFactory = null;
364       this.factoryName = factoryName;
365    }
366
367
368    /**
369     * Sets the factory's object name which will create the server sockets
370     *
371     * @param factoryName the socket factory
372     */

373    public void setSocketFactoryNameString(String JavaDoc factoryName) throws MalformedObjectNameException JavaDoc
374    {
375       this.socketFactory = null;
376       this.factoryName = new ObjectName JavaDoc(factoryName);
377    }
378
379
380    /**
381     * Indicates whether the server's running
382     *
383     * @return The active value
384     */

385    public boolean isActive()
386    {
387       return alive;
388    }
389
390
391    /**
392     * Starting date
393     *
394     * @return The date when the server was started
395     */

396    public Date JavaDoc getStartDate()
397    {
398       return startDate;
399    }
400
401
402    /**
403     * Requests count
404     *
405     * @return The total of requests served so far
406     */

407    public long getRequestsCount()
408    {
409       return requestsCount;
410    }
411
412
413    /**
414     * Gets the HttpAdaptor version
415     *
416     * @return HttpAdaptor's version
417     */

418    public String JavaDoc getVersion()
419    {
420       return VERSION;
421    }
422
423
424    /**
425     * Adds a command processor object
426     */

427    public void addCommandProcessor(String JavaDoc path, HttpCommandProcessor processor)
428    {
429       commands.put(path, processor);
430       if (alive)
431       {
432          processor.setMBeanServer(server);
433          processor.setDocumentBuilder(builder);
434       }
435    }
436
437
438    /**
439     * Adds a command processor object by class
440     */

441    public void addCommandProcessor(String JavaDoc path, String JavaDoc processorClass)
442    {
443       try
444       {
445          HttpCommandProcessor processor = (HttpCommandProcessor)Class.forName(processorClass).newInstance();
446          addCommandProcessor(path, processor);
447       }
448       catch (Exception JavaDoc e)
449       {
450          Logger log = getLogger();
451          log.error("Exception creating Command Processor of class " + processorClass, e);
452       }
453    }
454
455
456    /**
457     * Removes a command processor object by class
458     */

459    public void removeCommandProcessor(String JavaDoc path)
460    {
461       if (commands.containsKey(path))
462       {
463          commands.remove(path);
464       }
465    }
466
467
468    /**
469     * Starts the server
470     */

471    public void start()
472            throws IOException JavaDoc
473    {
474       final Logger logger = getLogger();
475
476       if (server != null)
477       {
478          serverSocket = createServerSocket();
479
480          if (serverSocket == null)
481          {
482             logger.error("Server socket is null");
483             return;
484          }
485
486          if (processorClass != null && processorName != null)
487          {
488             if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Building processor class of type " + processorClass + " and name " + processorName);
489             try
490             {
491                server.createMBean(processorClass, processorName, null);
492             }
493             catch (JMException JavaDoc e)
494             {
495                logger.error("Exception creating processor class", e);
496             }
497          }
498
499          Iterator JavaDoc i = commands.values().iterator();
500          while (i.hasNext())
501          {
502             HttpCommandProcessor processor = (HttpCommandProcessor)i.next();
503             processor.setMBeanServer(server);
504             processor.setDocumentBuilder(builder);
505          }
506
507          if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("HttpAdaptor server listening on port " + port);
508          alive = true;
509          Thread JavaDoc serverThread = new Thread JavaDoc(new Runnable JavaDoc()
510          {
511             public void run()
512             {
513                if (logger.isEnabledFor(Logger.INFO)) logger.info("HttpAdaptor version " + VERSION + " started on port " + port);
514
515                startDate = new Date JavaDoc();
516                requestsCount = 0;
517
518                while (alive)
519                {
520                   try
521                   {
522                      Socket JavaDoc client = null;
523                      client = serverSocket.accept();
524                      if (!alive)
525                      {
526                         client.close();
527                         break;
528                      }
529                      requestsCount++;
530                      new HttpClient(client).start();
531                   }
532                   catch (InterruptedIOException JavaDoc e)
533                   {
534                      continue;
535                   }
536                   catch (IOException JavaDoc e)
537                   {
538                      continue;
539                   }
540                   catch (Exception JavaDoc e)
541                   {
542                      logger.warn("Exception during request processing", e);
543                      continue;
544                   }
545                   catch (Error JavaDoc e)
546                   {
547                      logger.error("Error during request processing", e);
548                      continue;
549                   }
550                }
551                try
552                {
553                   serverSocket.close();
554                }
555                catch (IOException JavaDoc e)
556                {
557                   logger.warn("Exception closing the server", e);
558                }
559                serverSocket = null;
560                alive = false;
561                if (logger.isEnabledFor(Logger.INFO)) logger.info("HttpAdaptor version " + VERSION + " stopped on port " + port);
562             }
563          });
564          serverThread.start();
565       }
566       else
567       {
568          if (logger.isEnabledFor(Logger.INFO)) logger.info("Start failed, no server target server has been set");
569       }
570    }
571
572
573    /**
574     * Restarts the server. Useful when changing the Server parameters
575     *
576     * @deprecated as of RC 1
577     */

578    public void restart()
579            throws IOException JavaDoc
580    {
581       stop();
582       start();
583    }
584
585
586    /**
587     * Stops the HTTP daemon
588     */

589    public void stop()
590    {
591       try
592       {
593          if (alive)
594          {
595             alive = false;
596             // force the close with a socket call
597
new Socket JavaDoc(host, port);
598          }
599       }
600       catch (IOException JavaDoc e)
601       {
602          getLogger().warn(e.getMessage());
603       }
604       try
605       {
606          if (serverSocket != null)
607          {
608             serverSocket.close();
609          }
610       }
611       catch (IOException JavaDoc e)
612       {
613          getLogger().warn(e.getMessage());
614       }
615    }
616
617
618    /**
619     * Adds an authorization pair as username/password
620     */

621    public void addAuthorization(String JavaDoc username, String JavaDoc password)
622    {
623       if (username == null || password == null)
624       {
625          throw new IllegalArgumentException JavaDoc("username and passwords cannot be null");
626       }
627       authorizations.put(username, password);
628    }
629
630
631    /**
632     * Gathers some basic data
633     */

634    public ObjectName JavaDoc preRegister(MBeanServer JavaDoc server, ObjectName JavaDoc name)
635            throws java.lang.Exception JavaDoc
636    {
637       this.server = server;
638       buildCommands();
639       return name;
640    }
641
642
643    public void postRegister(Boolean JavaDoc registrationDone)
644    {
645    }
646
647
648    public void preDeregister()
649            throws java.lang.Exception JavaDoc
650    {
651       // stop the server
652
stop();
653    }
654
655
656    public void postDeregister()
657    {
658    }
659
660    private Logger getLogger()
661    {
662       return Log.getLogger(getClass().getName());
663    }
664
665    private ServerSocket JavaDoc createServerSocket() throws IOException JavaDoc
666    {
667       if (socketFactory == null)
668       {
669          if (factoryName == null)
670          {
671             socketFactory = new PlainAdaptorServerSocketFactory();
672             return socketFactory.createServerSocket(port, 50, host);
673          }
674          else
675          {
676             try
677             {
678                return (ServerSocket JavaDoc)server.invoke(factoryName, "createServerSocket", new Object JavaDoc[]{new Integer JavaDoc(port), new Integer JavaDoc(50), host}, new String JavaDoc[]{"int", "int", "java.lang.String"});
679             }
680             catch (Exception JavaDoc x)
681             {
682                Logger log = getLogger();
683                log.error("Exception invoking AdaptorServerSocketFactory via MBeanServer", x);
684             }
685          }
686       }
687       else
688       {
689          return socketFactory.createServerSocket(port, 50, host);
690       }
691
692       return null;
693    }
694
695
696    private boolean isUsernameValid(String JavaDoc username, String JavaDoc password)
697    {
698       if (authorizations.containsKey(username))
699       {
700          return password.equals(authorizations.get(username));
701       }
702       return false;
703    }
704
705
706    protected HttpCommandProcessor getProcessor(String JavaDoc path)
707    {
708       return (HttpCommandProcessor)commands.get(path);
709    }
710
711
712    /**
713     * Build the commands
714     */

715    protected void buildCommands()
716    {
717       Logger log = getLogger();
718       try
719       {
720          DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
721          builder = factory.newDocumentBuilder();
722          for (int i = 0; i < defaultCommandProcessors.length; i++)
723          {
724             try
725             {
726                HttpCommandProcessor processor = (HttpCommandProcessor)Class.forName(defaultCommandProcessors[i][1]).newInstance();
727                commands.put(defaultCommandProcessors[i][0], processor);
728             }
729             catch (Exception JavaDoc e)
730             {
731                log.warn("Exception building command procesor", e);
732             }
733          }
734       }
735       catch (ParserConfigurationException JavaDoc e)
736       {
737          log.error("Exception building the Document Factories", e);
738       }
739    }
740
741
742    protected void postProcess(HttpOutputStream out, HttpInputStream in, Document JavaDoc document)
743            throws IOException JavaDoc, JMException JavaDoc
744    {
745       boolean processed = false;
746       // inefficient but handles modifications at runtime
747
if (processorName != null)
748       {
749          if (server.isRegistered(processorName) &&
750                  server.isInstanceOf(processorName, "mx4j.tools.adaptor.http.ProcessorMBean"))
751          {
752             server.invoke(processorName,
753                     "writeResponse",
754                     new Object JavaDoc[]{out, in, document},
755                     new String JavaDoc[]{"mx4j.tools.adaptor.http.HttpOutputStream", "mx4j.tools.adaptor.http.HttpInputStream", "org.w3c.dom.Document"});
756             processed = true;
757          }
758          else
759          {
760             Logger log = getLogger();
761             if (log.isEnabledFor(Logger.TRACE)) log.trace(processorName + " not found");
762          }
763       }
764       if (!processed && processor != null)
765       {
766          processor.writeResponse(out, in, document);
767          processed = true;
768       }
769       if (!processed)
770       {
771          defaultProcessor.writeResponse(out, in, document);
772       }
773    }
774
775
776    protected void findUnknownElement(String JavaDoc path, HttpOutputStream out, HttpInputStream in)
777            throws IOException JavaDoc, JMException JavaDoc
778    {
779       boolean processed = false;
780       // inefficient but handles modifications at runtime
781
if (processorName != null)
782       {
783          if (server.isRegistered(processorName) &&
784                  server.isInstanceOf(processorName, "mx4j.tools.adaptor.http.ProcessorMBean"))
785          {
786             server.invoke(processorName,
787                     "notFoundElement",
788                     new Object JavaDoc[]{path, out, in},
789                     new String JavaDoc[]{"java.lang.String", "mx4j.tools.adaptor.http.HttpOutputStream", "mx4j.tools.adaptor.http.HttpInputStream"});
790             processed = true;
791          }
792          else
793          {
794             Logger log = getLogger();
795             if (log.isEnabledFor(Logger.TRACE)) log.trace(processorName + " not found");
796          }
797       }
798       if (!processed && processor != null)
799       {
800          processor.notFoundElement(path, out, in);
801          processed = true;
802       }
803       if (!processed)
804       {
805          defaultProcessor.notFoundElement(path, out, in);
806       }
807    }
808
809
810    protected String JavaDoc preProcess(String JavaDoc path)
811            throws IOException JavaDoc, JMException JavaDoc
812    {
813       boolean processed = false;
814       // inefficient but handles modifications at runtime
815
if (processorName != null)
816       {
817          Logger log = getLogger();
818          if (log.isEnabledFor(Logger.TRACE)) log.trace("Preprocess using " + processorName);
819          if (server.isRegistered(processorName) &&
820                  server.isInstanceOf(processorName, "mx4j.tools.adaptor.http.ProcessorMBean"))
821          {
822             if (log.isEnabledFor(Logger.TRACE)) log.trace("Preprocessing");
823             path = (String JavaDoc)server.invoke(processorName,
824                     "preProcess",
825                     new Object JavaDoc[]{path},
826                     new String JavaDoc[]{"java.lang.String"});
827             processed = true;
828          }
829          else
830          {
831             if (log.isEnabledFor(Logger.TRACE)) log.trace(processorName + " not found");
832          }
833       }
834       if (!processed && processor != null)
835       {
836          path = processor.preProcess(path);
837          processed = true;
838       }
839       if (!processed)
840       {
841          path = defaultProcessor.preProcess(path);
842       }
843       return path;
844    }
845
846
847    protected void postProcess(HttpOutputStream out, HttpInputStream in, Exception JavaDoc e)
848            throws IOException JavaDoc, JMException JavaDoc
849    {
850       boolean processed = false;
851       // inefficient but handles modifications at runtime
852
if (processorName != null)
853       {
854          if (server.isRegistered(processorName) &&
855                  server.isInstanceOf(processorName, "mx4j.tools.adaptor.http.ProcessorMBean"))
856          {
857             server.invoke(processorName,
858                     "writeError",
859                     new Object JavaDoc[]{out, in, e},
860                     new String JavaDoc[]{"mx4j.tools.adaptor.http.HttpOutputStream", "mx4j.tools.adaptor.http.HttpInputStream", "java.lang.Exception"});
861             processed = true;
862          }
863          else
864          {
865             Logger log = getLogger();
866             if (log.isEnabledFor(Logger.TRACE)) log.trace(processorName + " not found");
867          }
868       }
869       if (!processed && processor != null)
870       {
871          processor.writeError(out, in, e);
872          processed = true;
873       }
874       if (!processed)
875       {
876          defaultProcessor.writeError(out, in, e);
877       }
878    }
879
880
881    private class HttpClient extends Thread JavaDoc
882    {
883       private Socket JavaDoc client;
884
885
886       HttpClient(Socket JavaDoc client)
887       {
888          this.client = client;
889       }
890
891       public boolean isValid(String JavaDoc authorizationString)
892       {
893          if (authenticationMethod.startsWith("basic"))
894          {
895             authorizationString = authorizationString.substring(5, authorizationString.length());
896             String JavaDoc decodeString = new String JavaDoc(Base64Codec.decodeBase64(authorizationString.getBytes()));
897             if (decodeString.indexOf(":") > 0)
898             {
899                try
900                {
901                   StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(decodeString, ":");
902                   String JavaDoc username = tokens.nextToken();
903                   String JavaDoc password = tokens.nextToken();
904                   return isUsernameValid(username, password);
905                }
906                catch (Exception JavaDoc e)
907                {
908                   return false;
909                }
910             }
911          }
912          return false;
913       }
914
915
916       private boolean handleAuthentication(HttpInputStream in, HttpOutputStream out) throws IOException JavaDoc
917       {
918          if (authenticationMethod.equals("basic"))
919          {
920             String JavaDoc result = in.getHeader("authorization");
921             if (result != null)
922             {
923                if (isValid(result))
924                {
925                   return true;
926                }
927                throw new HttpException(HttpConstants.STATUS_FORBIDDEN, "Authentication failed");
928             }
929
930             out.setCode(HttpConstants.STATUS_AUTHENTICATE);
931             out.setHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
932             out.sendHeaders();
933             out.flush();
934             return false;
935          }
936          if (authenticationMethod.equals("digest"))
937          {
938             // not implemented
939
}
940          return true;
941       }
942
943
944       public void run()
945       {
946          Logger log = getLogger();
947          HttpInputStream httpIn = null;
948          HttpOutputStream httpOut = null;
949          try
950          {
951             // get input streams
952
InputStream JavaDoc in = client.getInputStream();
953             httpIn = new HttpInputStream(in);
954             httpIn.readRequest();
955
956             // Find a suitable command processor
957
String JavaDoc path = httpIn.getPath();
958             String JavaDoc queryString = httpIn.getQueryString();
959             if (log.isEnabledFor(Logger.DEBUG)) log.debug("Request " + path + ((queryString == null) ? "" : ("?" + queryString)));
960             String JavaDoc postPath = preProcess(path);
961             if (!postPath.equals(path))
962             {
963                if (log.isEnabledFor(Logger.DEBUG)) log.debug("Processor replaced path " + path + " with the path " + postPath);
964                path = postPath;
965             }
966             OutputStream JavaDoc out = client.getOutputStream();
967             httpOut = new HttpOutputStream(out, httpIn);
968             if (!handleAuthentication(httpIn, httpOut))
969             {
970                return;
971             }
972             HttpCommandProcessor processor = getProcessor(path.substring(1, path.length()));
973             if (processor == null)
974             {
975                if (log.isEnabledFor(Logger.DEBUG)) log.debug("No suitable command processor found, requesting from processor path " + path);
976                findUnknownElement(path, httpOut, httpIn);
977             }
978             else
979             {
980                Document JavaDoc document = processor.executeRequest(httpIn);
981                postProcess(httpOut, httpIn, document);
982             }
983          }
984          catch (Exception JavaDoc ex)
985          {
986             log.warn("Exception during http request", ex);
987             if (httpOut != null)
988             {
989                try
990                {
991                   postProcess(httpOut, httpIn, ex);
992                }
993                catch (IOException JavaDoc e)
994                {
995                   log.warn("IOException during http request", e);
996                }
997                catch (JMException JavaDoc e)
998                {
999                   log.warn("JMException during http request", e);
1000               }
1001               catch (RuntimeException JavaDoc rte)
1002               {
1003                  log.error("RuntimeException during http request", rte);
1004               }
1005               catch (Error JavaDoc er)
1006               {
1007                  log.error("Error during http request ", er);
1008               }
1009               catch (Throwable JavaDoc t)
1010               {
1011                  log.fatal("Throwable during http request ", t);
1012               }
1013            }
1014         }
1015         catch (Error JavaDoc ex)
1016         {
1017            log.error("Error during http request ", ex);
1018         }
1019         finally
1020         {
1021            try
1022            {
1023               if (httpOut != null)
1024               {
1025                  httpOut.flush();
1026               }
1027            }
1028            catch (IOException JavaDoc e)
1029            {
1030               log.warn("Exception during request processing", e);
1031            }
1032            finally
1033            {
1034               try
1035               {
1036// always close the socket
1037
client.close();
1038               }
1039               catch (IOException JavaDoc e)
1040               {
1041                  log.info("Exception during socket close", e);
1042               }
1043            }
1044         }
1045      }
1046   }
1047}
1048
1049
Popular Tags