bcee1c7c336eb5110da43a83f804d3a479efa882
[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 (Exception e)
68     {
69       Console.debug("Exception.", e);
70     } catch (Throwable t)
71     {
72       /*
73        * Set server error status on response
74        */
75       Console.error("Exception handling request " + request.getRequestURI(),
76               t);
77       if (response.isCommitted())
78       {
79         /*
80          * Can't write an HTTP header once any response content has been written
81          */
82         System.err.println(
83                 "Unable to return HTTP 500 as response already committed");
84       }
85       else
86       {
87         response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
88       }
89     } finally
90     {
91       response.getWriter().flush();
92       baseRequest.setHandled(true);
93     }
94   }
95
96   /**
97    * Subclasses should override this method to perform request processing
98    * 
99    * @param request
100    * @param response
101    * @throws IOException
102    */
103   protected abstract void processRequest(HttpServletRequest request,
104           HttpServletResponse response) throws IOException;
105
106   /**
107    * For debug - writes HTTP request details to stdout
108    * 
109    * @param request
110    */
111   protected void dumpRequest(HttpServletRequest request)
112   {
113     System.out.println(request.getMethod());
114     System.out.println(request.getRequestURL());
115     for (String hdr : Collections.list(request.getHeaderNames()))
116     {
117       for (String val : Collections.list(request.getHeaders(hdr)))
118       {
119         System.out.println(hdr + ": " + val);
120       }
121     }
122     for (String param : Collections.list(request.getParameterNames()))
123     {
124       for (String val : request.getParameterValues(param))
125       {
126         System.out.println(param + "=" + val);
127       }
128     }
129   }
130
131   /**
132    * Returns a display name for the handler
133    * 
134    * @return
135    */
136   public abstract String getName();
137
138   /**
139    * Deregister this listener and close it down
140    * 
141    * @throws Exception
142    */
143   public void shutdown()
144   {
145     try
146     {
147       HttpServer.getInstance().removeHandler(this);
148       stop();
149     } catch (Exception e)
150     {
151       System.err.println(
152               "Error stopping " + getName() + ": " + e.getMessage());
153     }
154   }
155
156   /**
157    * Returns the URI on which we are listening
158    * 
159    * @return
160    */
161   public String getUri()
162   {
163     return this.uri;
164   }
165
166   /**
167    * Set the URI to this handler
168    * 
169    * @param u
170    */
171   protected void setUri(String u)
172   {
173     this.uri = u;
174   }
175
176   /**
177    * Sets the relative path to this handler - do this before registering the
178    * handler.
179    * 
180    * @param p
181    */
182   protected void setPath(String p)
183   {
184     this.path = p;
185   }
186
187   /**
188    * Returns the relative path to this handler below the context root (without /
189    * separators)
190    * 
191    * @return
192    */
193   public String getPath()
194   {
195     return this.path;
196   }
197
198   /**
199    * Registers the handler with the HttpServer and reports its URI on stdout
200    * 
201    * @throws BindException
202    *           if no port could be allocated
203    * @throws IllegalStateException
204    *           if this method is called before {@link #setPath}
205    */
206   protected void registerHandler() throws BindException
207   {
208     HttpServer.getInstance().registerHandler(this);
209   }
210 }