f8c5441016f8aa596b4bacd156327ab3b830194f
[jalview.git] / src / jalview / httpserver / AbstractRequestHandler.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.httpserver;
22
23 import java.io.IOException;
24 import java.net.BindException;
25 import java.util.Collections;
26
27 import javax.servlet.ServletException;
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.http.HttpServletResponse;
30
31 import org.eclipse.jetty.server.Request;
32 import org.eclipse.jetty.server.handler.AbstractHandler;
33
34 import jalview.bin.Console;
35
36 /**
37  * 
38  * @author gmcarstairs
39  *
40  */
41 public abstract class AbstractRequestHandler extends AbstractHandler
42 {
43
44   /*
45    * The relative path (below context root) of this handler (without /
46    * separators)
47    */
48   private String path;
49
50   /*
51    * The full URI on which this handler listens
52    */
53   private String uri;
54
55   /**
56    * Handle an incoming Http request.
57    */
58   @Override
59   public void handle(String target, Request baseRequest,
60           HttpServletRequest request, HttpServletResponse response)
61           throws IOException, ServletException
62   {
63     try
64     {
65       // dumpRequest(request); // debug
66       processRequest(request, response);
67     } catch (Throwable t)
68     {
69       /*
70        * Set server error status on response
71        */
72       Console.error("Exception handling request " + request.getRequestURI(),
73               t);
74       if (response.isCommitted())
75       {
76         /*
77          * Can't write an HTTP header once any response content has been written
78          */
79         System.err.println(
80                 "Unable to return HTTP 500 as response already committed");
81       }
82       else
83       {
84         response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
85       }
86     } finally
87     {
88       response.getWriter().flush();
89       baseRequest.setHandled(true);
90     }
91   }
92
93   /**
94    * Subclasses should override this method to perform request processing
95    * 
96    * @param request
97    * @param response
98    * @throws IOException
99    */
100   protected abstract void processRequest(HttpServletRequest request,
101           HttpServletResponse response) throws IOException;
102
103   /**
104    * For debug - writes HTTP request details to stdout
105    * 
106    * @param request
107    */
108   protected void dumpRequest(HttpServletRequest request)
109   {
110     System.out.println(request.getMethod());
111     System.out.println(request.getRequestURL());
112     for (String hdr : Collections.list(request.getHeaderNames()))
113     {
114       for (String val : Collections.list(request.getHeaders(hdr)))
115       {
116         System.out.println(hdr + ": " + val);
117       }
118     }
119     for (String param : Collections.list(request.getParameterNames()))
120     {
121       for (String val : request.getParameterValues(param))
122       {
123         System.out.println(param + "=" + val);
124       }
125     }
126   }
127
128   /**
129    * Returns a display name for the handler
130    * 
131    * @return
132    */
133   public abstract String getName();
134
135   /**
136    * Deregister this listener and close it down
137    * 
138    * @throws Exception
139    */
140   public void shutdown()
141   {
142     try
143     {
144       HttpServer.getInstance().removeHandler(this);
145       stop();
146     } catch (Exception e)
147     {
148       System.err.println(
149               "Error stopping " + getName() + ": " + e.getMessage());
150     }
151   }
152
153   /**
154    * Returns the URI on which we are listening
155    * 
156    * @return
157    */
158   public String getUri()
159   {
160     return this.uri;
161   }
162
163   /**
164    * Set the URI to this handler
165    * 
166    * @param u
167    */
168   protected void setUri(String u)
169   {
170     this.uri = u;
171   }
172
173   /**
174    * Sets the relative path to this handler - do this before registering the
175    * handler.
176    * 
177    * @param p
178    */
179   protected void setPath(String p)
180   {
181     this.path = p;
182   }
183
184   /**
185    * Returns the relative path to this handler below the context root (without /
186    * separators)
187    * 
188    * @return
189    */
190   public String getPath()
191   {
192     return this.path;
193   }
194
195   /**
196    * Registers the handler with the HttpServer and reports its URI on stdout
197    * 
198    * @throws BindException
199    *           if no port could be allocated
200    * @throws IllegalStateException
201    *           if this method is called before {@link #setPath}
202    */
203   protected void registerHandler() throws BindException
204   {
205     HttpServer.getInstance().registerHandler(this);
206   }
207 }