| 1 |
package org.openmrs.module.restmodule.web; |
|---|
| 2 |
|
|---|
| 3 |
import java.io.IOException; |
|---|
| 4 |
import java.net.URLDecoder; |
|---|
| 5 |
import java.util.Hashtable; |
|---|
| 6 |
|
|---|
| 7 |
import javax.servlet.ServletException; |
|---|
| 8 |
import javax.servlet.http.HttpServlet; |
|---|
| 9 |
import javax.servlet.http.HttpServletRequest; |
|---|
| 10 |
import javax.servlet.http.HttpServletResponse; |
|---|
| 11 |
|
|---|
| 12 |
import org.openmrs.api.APIAuthenticationException; |
|---|
| 13 |
import org.openmrs.module.restmodule.RestUtil; |
|---|
| 14 |
import org.openmrs.module.restmodule.web.RestResource.Operation; |
|---|
| 15 |
|
|---|
| 16 |
/** |
|---|
| 17 |
* Provides a simple RESTful API to the repository. Useful for meeting simple |
|---|
| 18 |
* data needs over HTTP. Authentication is performed using HTTP BASIC |
|---|
| 19 |
* Authentication. Global properties are used to restrict access by client IP |
|---|
| 20 |
* address and to set a maximum number of results to be returned. |
|---|
| 21 |
* |
|---|
| 22 |
* @author Burke Mamlin |
|---|
| 23 |
* @version 1.0 |
|---|
| 24 |
*/ |
|---|
| 25 |
public class RestServlet extends HttpServlet { |
|---|
| 26 |
|
|---|
| 27 |
/** |
|---|
| 28 |
* |
|---|
| 29 |
*/ |
|---|
| 30 |
private static final long serialVersionUID = -6644606499605233047L; |
|---|
| 31 |
|
|---|
| 32 |
/** |
|---|
| 33 |
* Name for servlet within the servlet mapping (follows "/servletModule/" in |
|---|
| 34 |
* URL) |
|---|
| 35 |
*/ |
|---|
| 36 |
public static final String SERVLET_NAME = "api"; |
|---|
| 37 |
|
|---|
| 38 |
/** |
|---|
| 39 |
* Internally held list of resources. Currently hardcoded. |
|---|
| 40 |
*/ |
|---|
| 41 |
private static Hashtable<String, RestResource> resources = new Hashtable<String, RestResource>(); |
|---|
| 42 |
static { |
|---|
| 43 |
resources.put("patient", new PatientResource()); |
|---|
| 44 |
resources.put("findPatient", new FindPatientResource()); |
|---|
| 45 |
} |
|---|
| 46 |
|
|---|
| 47 |
@Override |
|---|
| 48 |
protected void doGet(HttpServletRequest request, |
|---|
| 49 |
HttpServletResponse response) throws ServletException, IOException { |
|---|
| 50 |
handleRequest(Operation.GET, request, response); |
|---|
| 51 |
} |
|---|
| 52 |
|
|---|
| 53 |
@Override |
|---|
| 54 |
protected void doPost(HttpServletRequest request, |
|---|
| 55 |
HttpServletResponse response) throws ServletException, IOException { |
|---|
| 56 |
handleRequest(Operation.POST, request, response); |
|---|
| 57 |
} |
|---|
| 58 |
|
|---|
| 59 |
@Override |
|---|
| 60 |
protected void doPut(HttpServletRequest request, |
|---|
| 61 |
HttpServletResponse response) throws ServletException, IOException { |
|---|
| 62 |
handleRequest(Operation.PUT, request, response); |
|---|
| 63 |
} |
|---|
| 64 |
|
|---|
| 65 |
@Override |
|---|
| 66 |
protected void doDelete(HttpServletRequest request, |
|---|
| 67 |
HttpServletResponse response) throws ServletException, IOException { |
|---|
| 68 |
handleRequest(Operation.DELETE, request, response); |
|---|
| 69 |
} |
|---|
| 70 |
|
|---|
| 71 |
/** |
|---|
| 72 |
* Handle all requests to the API -- i.e., authenticate to the API, restrict |
|---|
| 73 |
* access based on client's IP address, parse the request URL, and pass |
|---|
| 74 |
* control to the appropriate resource. |
|---|
| 75 |
* |
|---|
| 76 |
* @param operation |
|---|
| 77 |
* HTTP operation being performed (e.g., GET, POST, PUT, DELETE) |
|---|
| 78 |
* @param request |
|---|
| 79 |
* HTTP request |
|---|
| 80 |
* @param response |
|---|
| 81 |
* HTTP response |
|---|
| 82 |
* @throws ServletException |
|---|
| 83 |
* @throws IOException |
|---|
| 84 |
*/ |
|---|
| 85 |
private void handleRequest(Operation operation, HttpServletRequest request, |
|---|
| 86 |
HttpServletResponse response) throws ServletException, IOException { |
|---|
| 87 |
|
|---|
| 88 |
// Implement BASIC Authentication and restrict by client IP address |
|---|
| 89 |
String auth = request.getHeader("Authorization"); |
|---|
| 90 |
String remoteAddress = request.getRemoteAddr(); |
|---|
| 91 |
if (!RestUtil.allowUser(auth) |
|---|
| 92 |
|| !RestUtil.allowRemoteAddress(remoteAddress)) { |
|---|
| 93 |
// Not allowed |
|---|
| 94 |
response.setHeader("WWW-Authenticate", |
|---|
| 95 |
"BASIC realm=\"OpenMRS Rest API\""); |
|---|
| 96 |
response.sendError(HttpServletResponse.SC_UNAUTHORIZED); |
|---|
| 97 |
return; |
|---|
| 98 |
} |
|---|
| 99 |
|
|---|
| 100 |
// Parse the request URL, removing the rest module name along with the |
|---|
| 101 |
// mapping to this servlet |
|---|
| 102 |
String url = request.getRequestURI(); |
|---|
| 103 |
int pos = url.indexOf("/" + RestUtil.MODULE_ID + "/") |
|---|
| 104 |
+ RestUtil.MODULE_ID.length() + 2; |
|---|
| 105 |
String target = url.substring(pos); |
|---|
| 106 |
// Remove "api/" from URL (gets us to this servlet) |
|---|
| 107 |
if (target.startsWith(SERVLET_NAME + "/")) |
|---|
| 108 |
target = target.substring(4); |
|---|
| 109 |
|
|---|
| 110 |
// If we have a matching resource, let it handle the request |
|---|
| 111 |
for (String resourceName : resources.keySet()) { |
|---|
| 112 |
if (target.startsWith(resourceName + "/")) { |
|---|
| 113 |
response.setHeader("Content-type", "text/xml"); |
|---|
| 114 |
String restRequest = URLDecoder.decode(target |
|---|
| 115 |
.substring(resourceName.length() + 1), "UTF-8"); |
|---|
| 116 |
try { |
|---|
| 117 |
resources.get(resourceName).handleRequest(operation, |
|---|
| 118 |
restRequest, request, response); |
|---|
| 119 |
} catch (APIAuthenticationException e) { |
|---|
| 120 |
response.sendError(HttpServletResponse.SC_FORBIDDEN); |
|---|
| 121 |
} |
|---|
| 122 |
return; |
|---|
| 123 |
} |
|---|
| 124 |
} |
|---|
| 125 |
|
|---|
| 126 |
// If no matching resources were found, return an error |
|---|
| 127 |
response.sendError(HttpServletResponse.SC_BAD_REQUEST); |
|---|
| 128 |
|
|---|
| 129 |
} |
|---|
| 130 |
|
|---|
| 131 |
} |
|---|