From d94d2719d963752d6a6f42b3837fff354f057696 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Wed, 5 Mar 2014 09:33:29 -0500 Subject: [PATCH] Fix some merge issues --- .../ca/uhn/fhir/context/ModelScanner.java | 4 - .../ca/uhn/fhir/server/RestfulServer.java | 76 ++-- .../uhn/fhir/server/RestfulServer.java.orig | 331 ++++++++++++++++++ 3 files changed, 357 insertions(+), 54 deletions(-) create mode 100644 hapi-fhir-base/src/main/java/ca/uhn/fhir/server/RestfulServer.java.orig diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java index 40320bbdcfd..7f00f4aab41 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/ModelScanner.java @@ -96,10 +96,6 @@ class ModelScanner { ourLog.info("Done scanning FHIR library, found {} model entries", myClassToElementDefinitions.size()); } - public ModelScanner(Class theClass) { - // TODO Auto-generated constructor stub - } - public RuntimeChildUndeclaredExtensionDefinition getRuntimeChildUndeclaredExtensionDefinition() { return myRuntimeChildUndeclaredExtensionDefinition; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/server/RestfulServer.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/server/RestfulServer.java index eca171410d3..44e77804c3b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/server/RestfulServer.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/server/RestfulServer.java @@ -41,31 +41,9 @@ public abstract class RestfulServer extends HttpServlet { private static final long serialVersionUID = 1L; - private Map, IResourceProvider> myTypeToProvider = new HashMap, IResourceProvider>(); - private FhirContext myFhirContext; - public abstract Collection> getResourceProviders(); - - @Override - public void init() throws ServletException { - try { - ourLog.info("Initializing HAPI FHIR restful server"); - - Collection> resourceProvider = getResourceProviders(); - for (IResourceProvider nextProvider : resourceProvider) { - if (myTypeToProvider.containsKey(nextProvider.getResourceType())) { - throw new ServletException("Multiple providers for type: " + nextProvider.getResourceType().getCanonicalName()); - } - myTypeToProvider.put(nextProvider.getResourceType(), nextProvider); - } - - ourLog.info("Got {} resource providers",myTypeToProvider.size()); - - myFhirContext = new FhirContext(myTypeToProvider.keySet()); - -// findResourceMethods(nextProvider.getClass()); ->>>>>>> b15504ab6af00727419d4888cd3a1c5215f5b5e3:hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/RestfulServer.java + private Map, IResourceProvider> myTypeToProvider = new HashMap, IResourceProvider>(); // map of request handler resources keyed by resource name private Map resources = new HashMap(); @@ -90,7 +68,7 @@ public abstract class RestfulServer extends HttpServlet { rm.setMethod(method); rm.setResourceType(method.getReturnType()); rm.setParameters(Util.getResourceParameters(method)); - + resource.addMethod(rm); return true; } @@ -126,11 +104,11 @@ public abstract class RestfulServer extends HttpServlet { Class resourceType = theProvider.getResourceType(); RuntimeResourceDefinition definition = myFhirContext.getResourceDefinition(resourceType); - - Resource r = new Resource(); - r.setResourceProvider(theProvider); - r.setResourceName(definition.getName()); - resources.put(definition.getName(), r); + + Resource r = new Resource(); + r.setResourceProvider(theProvider); + r.setResourceName(definition.getName()); + resources.put(definition.getName(), r); Class clazz = theProvider.getClass(); for (Method m : clazz.getDeclaredMethods()) { @@ -153,7 +131,7 @@ public abstract class RestfulServer extends HttpServlet { Map params = new HashMap(request.getParameterMap()); EncodingUtil responseEncoding = determineResponseEncoding(params); - + StringTokenizer tok = new StringTokenizer(request.getRequestURI(), "/"); if (!tok.hasMoreTokens()) { throw new MethodNotFoundException("No resource name specified"); @@ -164,7 +142,7 @@ public abstract class RestfulServer extends HttpServlet { if (resourceBinding == null) { throw new MethodNotFoundException("Unknown resource type: " + resourceBinding); } - + if (tok.hasMoreTokens()) { String identityString = tok.nextToken(); try { @@ -173,7 +151,7 @@ public abstract class RestfulServer extends HttpServlet { throw new NumberFormatException("Invalid identity token: " + identity); } } - + if (identity != null && !tok.hasMoreTokens()) { if (params == null || params.isEmpty()) { IResource resource = resourceBinding.getResourceProvider().getResourceById(identity); @@ -184,24 +162,24 @@ public abstract class RestfulServer extends HttpServlet { return; } } - + ResourceMethod resourceMethod = resourceBinding.getMethod(params.keySet()); if (null == resourceMethod) { throw new MethodNotFoundException("No resource method available for the supplied parameters " + params); } - + List result = resourceMethod.invoke(resourceBinding.getResourceProvider(), params); streamResponseAsBundle(response, result, responseEncoding); -// resourceMethod.get - + // resourceMethod.get + } catch (AbstractResponseException e) { - + response.setStatus(e.getStatusCode()); response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); response.getWriter().append(e.getMessage()); response.getWriter().close(); - + } catch (Throwable t) { // TODO: handle this better ourLog.error("Failed to process invocation", t); @@ -223,15 +201,14 @@ public abstract class RestfulServer extends HttpServlet { myTypeToProvider.put(nextProvider.getResourceType(), nextProvider); } - ourLog.info("Got {} resource providers",myTypeToProvider.size()); - + ourLog.info("Got {} resource providers", myTypeToProvider.size()); + myFhirContext = new FhirContext(myTypeToProvider.keySet()); for (IResourceProvider provider : myTypeToProvider.values()) { findResourceMethods(provider); } - } catch (Exception ex) { ourLog.error("An error occurred while loading request handlers!", ex); throw new ServletException("Failed to initialize FHIR Restful server", ex); @@ -242,21 +219,21 @@ public abstract class RestfulServer extends HttpServlet { theHttpResponse.setStatus(200); theHttpResponse.setContentType(Constants.CT_FHIR_XML); theHttpResponse.setCharacterEncoding("UTF-8"); - + Bundle bundle = new Bundle(); bundle.getAuthorName().setValue(getClass().getCanonicalName()); bundle.getId().setValue(UUID.randomUUID().toString()); bundle.getPublished().setToCurrentTimeInLocalTimeZone(); - + for (IResource next : theResult) { BundleEntry entry = new BundleEntry(); bundle.getEntries().add(entry); - + entry.setResource(next); } - + bundle.getTotalResults().setValue(theResult.size()); - + PrintWriter writer = theHttpResponse.getWriter(); myFhirContext.newXmlParser().encodeBundleToWriter(bundle, writer); writer.close(); @@ -267,16 +244,15 @@ public abstract class RestfulServer extends HttpServlet { theHttpResponse.setStatus(200); theHttpResponse.setContentType(Constants.CT_FHIR_XML); theHttpResponse.setCharacterEncoding("UTF-8"); - + PrintWriter writer = theHttpResponse.getWriter(); myFhirContext.newXmlParser().encodeResourceToWriter(theResource, writer); writer.close(); - + } /** - * Recursive method used to find all classes in a given directory and - * subdirs. + * Recursive method used to find all classes in a given directory and subdirs. * * @param directory * The base directory diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/server/RestfulServer.java.orig b/hapi-fhir-base/src/main/java/ca/uhn/fhir/server/RestfulServer.java.orig new file mode 100644 index 00000000000..55e899d66f6 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/server/RestfulServer.java.orig @@ -0,0 +1,331 @@ +package ca.uhn.fhir.server; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.UUID; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.parser.XmlParser; +import ca.uhn.fhir.server.exceptions.AbstractResponseException; +import ca.uhn.fhir.server.exceptions.InternalErrorException; +import ca.uhn.fhir.server.exceptions.MethodNotFoundException; +import ca.uhn.fhir.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.server.operations.DELETE; +import ca.uhn.fhir.server.operations.GET; +import ca.uhn.fhir.server.operations.POST; +import ca.uhn.fhir.server.operations.PUT; + +public abstract class RestfulServer extends HttpServlet { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServer.class); + + private static final long serialVersionUID = 1L; + +<<<<<<< HEAD:hapi-fhir-base/src/main/java/ca/uhn/fhir/server/RestfulServer.java + private FhirContext myFhirContext; + + private Map, IResourceProvider> myTypeToProvider = new HashMap, IResourceProvider>(); +======= + private Map, IResourceProvider> myTypeToProvider = new HashMap, IResourceProvider>(); + + private FhirContext myFhirContext; + + public abstract Collection> getResourceProviders(); + + @Override + public void init() throws ServletException { + try { + ourLog.info("Initializing HAPI FHIR restful server"); + + Collection> resourceProvider = getResourceProviders(); + for (IResourceProvider nextProvider : resourceProvider) { + if (myTypeToProvider.containsKey(nextProvider.getResourceType())) { + throw new ServletException("Multiple providers for type: " + nextProvider.getResourceType().getCanonicalName()); + } + myTypeToProvider.put(nextProvider.getResourceType(), nextProvider); + } + + ourLog.info("Got {} resource providers",myTypeToProvider.size()); + + myFhirContext = new FhirContext(myTypeToProvider.keySet()); + +// findResourceMethods(nextProvider.getClass()); +>>>>>>> b15504ab6af00727419d4888cd3a1c5215f5b5e3:hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/RestfulServer.java + + // map of request handler resources keyed by resource name + private Map resources = new HashMap(); + + private boolean addResourceMethod(Resource resource, Method method) throws Exception { + + ResourceMethod rm = new ResourceMethod(); + + // each operation name must have a request type annotation and be unique + if (null != method.getAnnotation(GET.class)) { + rm.setRequestType(ResourceMethod.RequestType.GET); + } else if (null != method.getAnnotation(PUT.class)) { + rm.setRequestType(ResourceMethod.RequestType.PUT); + } else if (null != method.getAnnotation(POST.class)) { + rm.setRequestType(ResourceMethod.RequestType.POST); + } else if (null != method.getAnnotation(DELETE.class)) { + rm.setRequestType(ResourceMethod.RequestType.DELETE); + } else { + return false; + } + + rm.setMethod(method); + rm.setResourceType(method.getReturnType()); + rm.setParameters(Util.getResourceParameters(method)); + + resource.addMethod(rm); + return true; + } + + @SuppressWarnings("unused") + private EncodingUtil determineResponseEncoding(Map theParams) { + String[] format = theParams.remove(Constants.PARAM_FORMAT); + // TODO: handle this once we support JSON + return EncodingUtil.XML; + } + + @Override + protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + handleRequest(ResourceMethod.RequestType.DELETE, request, response); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + handleRequest(ResourceMethod.RequestType.GET, request, response); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + handleRequest(ResourceMethod.RequestType.POST, request, response); + } + + @Override + protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + handleRequest(ResourceMethod.RequestType.PUT, request, response); + } + + private void findResourceMethods(IResourceProvider theProvider) throws Exception { + + Class resourceType = theProvider.getResourceType(); + RuntimeResourceDefinition definition = myFhirContext.getResourceDefinition(resourceType); + + Resource r = new Resource(); + r.setResourceProvider(theProvider); + r.setResourceName(definition.getName()); + resources.put(definition.getName(), r); + + Class clazz = theProvider.getClass(); + for (Method m : clazz.getDeclaredMethods()) { + if (Modifier.isPublic(m.getModifiers())) { + + boolean foundMethod = addResourceMethod(r, m); + if (foundMethod) { + ourLog.debug("found handler: " + m.getName()); + } + } + } + } + + public abstract Collection> getResourceProviders(); + + protected void handleRequest(ResourceMethod.RequestType requestType, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + try { + String resourceName = null; + Long identity = null; + + Map params = new HashMap(request.getParameterMap()); + EncodingUtil responseEncoding = determineResponseEncoding(params); + + StringTokenizer tok = new StringTokenizer(request.getRequestURI(), "/"); + if (!tok.hasMoreTokens()) { + throw new MethodNotFoundException("No resource name specified"); + } + resourceName = tok.nextToken(); + + Resource resourceBinding = resources.get(resourceName); + if (resourceBinding == null) { + throw new MethodNotFoundException("Unknown resource type: " + resourceBinding); + } + + if (tok.hasMoreTokens()) { + String identityString = tok.nextToken(); + try { + identity = Long.parseLong(identityString); + } catch (NumberFormatException e) { + throw new NumberFormatException("Invalid identity token: " + identity); + } + } + + if (identity != null && !tok.hasMoreTokens()) { + if (params == null || params.isEmpty()) { + IResource resource = resourceBinding.getResourceProvider().getResourceById(identity); + if (resource == null) { + throw new ResourceNotFoundException(identity); + } + streamResponseAsResource(response, resource, resourceBinding, responseEncoding); + return; + } + } + + ResourceMethod resourceMethod = resourceBinding.getMethod(params.keySet()); + if (null == resourceMethod) { + throw new MethodNotFoundException("No resource method available for the supplied parameters " + params); + } + + List result = resourceMethod.invoke(resourceBinding.getResourceProvider(), params); + streamResponseAsBundle(response, result, responseEncoding); +// resourceMethod.get + + } catch (AbstractResponseException e) { + + response.setStatus(e.getStatusCode()); + response.setContentType("text/plain"); + response.setCharacterEncoding("UTF-8"); + response.getWriter().append(e.getMessage()); + response.getWriter().close(); + + } catch (Throwable t) { + // TODO: handle this better + ourLog.error("Failed to process invocation", t); + throw new ServletException(t); + } + + } + + @Override + public void init() throws ServletException { + try { + ourLog.info("Initializing HAPI FHIR restful server"); + + Collection> resourceProvider = getResourceProviders(); + for (IResourceProvider nextProvider : resourceProvider) { + if (myTypeToProvider.containsKey(nextProvider.getResourceType())) { + throw new ServletException("Multiple providers for type: " + nextProvider.getResourceType().getCanonicalName()); + } + myTypeToProvider.put(nextProvider.getResourceType(), nextProvider); + } + + ourLog.info("Got {} resource providers",myTypeToProvider.size()); + + myFhirContext = new FhirContext(myTypeToProvider.keySet()); + + for (IResourceProvider provider : myTypeToProvider.values()) { + findResourceMethods(provider); + } + + + } catch (Exception ex) { + ourLog.error("An error occurred while loading request handlers!", ex); + throw new ServletException("Failed to initialize FHIR Restful server", ex); + } + } + + private void streamResponseAsBundle(HttpServletResponse theHttpResponse, List theResult, EncodingUtil theResponseEncoding) throws IOException { + theHttpResponse.setStatus(200); + theHttpResponse.setContentType(Constants.CT_FHIR_XML); + theHttpResponse.setCharacterEncoding("UTF-8"); + + Bundle bundle = new Bundle(); + bundle.getAuthorName().setValue(getClass().getCanonicalName()); + bundle.getId().setValue(UUID.randomUUID().toString()); + bundle.getPublished().setToCurrentTimeInLocalTimeZone(); + + for (IResource next : theResult) { + BundleEntry entry = new BundleEntry(); + bundle.getEntries().add(entry); + + entry.setResource(next); + } + + bundle.getTotalResults().setValue(theResult.size()); + + PrintWriter writer = theHttpResponse.getWriter(); + myFhirContext.newXmlParser().encodeBundleToWriter(bundle, writer); + writer.close(); + } + + private void streamResponseAsResource(HttpServletResponse theHttpResponse, IResource theResource, Resource theResourceBinding, EncodingUtil theResponseEncoding) throws IOException { + + theHttpResponse.setStatus(200); + theHttpResponse.setContentType(Constants.CT_FHIR_XML); + theHttpResponse.setCharacterEncoding("UTF-8"); + + PrintWriter writer = theHttpResponse.getWriter(); + myFhirContext.newXmlParser().encodeResourceToWriter(theResource, writer); + writer.close(); + + } + + /** + * Recursive method used to find all classes in a given directory and + * subdirs. + * + * @param directory + * The base directory + * @param packageName + * The package name for classes found inside the base directory + * @return The classes + * @throws ClassNotFoundException + */ + private static List> findClasses(File directory, String packageName) throws ClassNotFoundException { + List> classes = new ArrayList>(); + if (!directory.exists()) { + return classes; + } + File[] files = directory.listFiles(); + for (File file : files) { + if (file.isDirectory()) { + assert !file.getName().contains("."); + classes.addAll(findClasses(file, packageName + "." + file.getName())); + } else if (file.getName().endsWith(".class")) { + classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); + } + } + return classes; + } + + private static List> getClasses(String packageName) throws ClassNotFoundException, IOException { + + if (null == packageName) + throw new ClassNotFoundException("package name must be specified for JSON operations"); + + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + assert classLoader != null; + String path = packageName.replace('.', '/'); + Enumeration resources = classLoader.getResources(path); + List dirs = new ArrayList(); + while (resources.hasMoreElements()) { + URL resource = resources.nextElement(); + dirs.add(new File(resource.getFile())); + } + + ArrayList> classes = new ArrayList>(); + for (File directory : dirs) { + classes.addAll(findClasses(directory, packageName)); + } + return classes; + } +}