diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Parameter.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Parameter.java new file mode 100644 index 00000000000..37bf0c983dd --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Parameter.java @@ -0,0 +1,41 @@ +package ca.uhn.fhir.ws; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class Parameter { + private String name; + private boolean required; + private Class type; + + public Parameter(){} + + public Parameter(String name, boolean required) { + this.name = name; + this.required = required; + } + + public Class getType() { + return type; + } + + public void setType(Class type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isRequired() { + return required; + } + + public void setRequired(boolean required) { + this.required = required; + } +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Resource.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Resource.java new file mode 100644 index 00000000000..ec2bfa510af --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Resource.java @@ -0,0 +1,71 @@ +package ca.uhn.fhir.ws; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class Resource { + + private String resourceName; + private Class resourceClass; + private List methods = new ArrayList(); + + public Resource() {} + + public Resource(String resourceName, Class resourceClass, List methods) { + this.resourceName = resourceName; + this.methods = methods; + } + + public ResourceMethod getMethod(Set parameters) throws Exception { + if (null == methods) return null; + + for (ResourceMethod rm : methods) { + if (rm.matches(parameters)) return rm; + } + return null; + } + + public Class getResourceClass() { + return resourceClass; + } + + public void setResourceClass(Class resourceClass) { + this.resourceClass = resourceClass; + } + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public List getMethods() { + return methods; + } + + public void setMethods(List methods) { + this.methods = methods; + } + + public void addMethod(ResourceMethod method) { + this.methods.add(method); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Resource)) return false; + return resourceName.equals(((Resource)o).getResourceName()); + } + + @Override + public int hashCode() { + return 0; + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/ResourceMethod.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/ResourceMethod.java new file mode 100644 index 00000000000..6e0d01ef95e --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/ResourceMethod.java @@ -0,0 +1,94 @@ +package ca.uhn.fhir.ws; + +import ca.uhn.fhir.model.api.IResource; + +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class ResourceMethod { + private Class resourceType; + + public static enum RequestType { + GET, + POST, + PUT, + DELETE + } + + RequestType requestType; + List parameters; + Method method; + + public ResourceMethod() {} + + public ResourceMethod(Method method, List parameters) { + this.method = method; + this.parameters = parameters; + } + + public void setResourceType(Class resourceType) { + this.resourceType = resourceType; + } + + public IResource getResourceType() throws IllegalAccessException, InstantiationException { + return (IResource)resourceType.newInstance(); + } + + public RequestType getRequestType() { + return requestType; + } + + public void setRequestType(RequestType requestType) { + this.requestType = requestType; + } + + public List getParameters() { + return parameters; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public Method getMethod() { + return method; + } + + public void setMethod(Method method) { + this.method = method; + } + + public boolean matches(Set parameterNames) { + Set methodParamsTemp = new HashSet(); + for (int i = 0; i < this.parameters.size(); i++){ + Parameter temp = this.parameters.get(i); + methodParamsTemp.add(temp.getName()); + if (temp.isRequired() && !parameterNames.contains(temp.getName())){ + return false; + } + } + return methodParamsTemp.containsAll(parameterNames); + } + + public IResource invoke(Map parameterValues) { + Object[] params = new Object[parameters.size()]; + for (int i = 0; i < parameters.size(); i++) { + Parameter param = parameters.get(i); + String value = parameterValues.get(param.getName()); + if (null != value) { + //TODO + //param.getType().newInstance().getClass(); + } + else { + params[i] = null; + } + } + return null; + } +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/ResourceName.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/ResourceName.java new file mode 100644 index 00000000000..649ae4e08be --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/ResourceName.java @@ -0,0 +1,10 @@ +package ca.uhn.fhir.ws; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) + +public @interface ResourceName { + String value(); +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Service.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Service.java new file mode 100644 index 00000000000..9f358bfb297 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Service.java @@ -0,0 +1,224 @@ +package ca.uhn.fhir.ws; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.parser.XmlParser; +import ca.uhn.fhir.ws.exceptions.MethodNotFoundException; +import ca.uhn.fhir.ws.operations.DELETE; +import ca.uhn.fhir.ws.operations.GET; +import ca.uhn.fhir.ws.operations.POST; +import ca.uhn.fhir.ws.operations.PUT; +import org.apache.log4j.Logger; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.*; + +public class Service extends HttpServlet { + + private static final Logger log = Logger.getLogger(Service.class); + private static final String handlerPackage = "ca.uhn.rest.handlers"; + + //map of request handler resources keyed by resource name + private static Map resources = new HashMap(); + + /** + * looks up all the methods from the classes specified in jsonHandlerPackage environment variable, and puts them in a map, + * keyed on the method name. + * The handlers for incoming requests will be looked up based on the name. + * Method names must be public, static, unique, and must be annotated with JsonOperation. + */ + + private List findRESTHanlderPackages(Context env) throws Exception { + + List packages = new ArrayList(); + + int i = 1; + String origName = handlerPackage; + String name = origName; + + while (true) { + String handlerPackage = null; + try { + log.debug("Looking up:: " + name); + handlerPackage = (String) env.lookup(name); + } catch (NamingException ne) { + log.debug(ne); + } + if (handlerPackage != null) { + log.debug("Found:: " + name); + packages.add(handlerPackage); + name = origName + i; + i++; + } else { + log.debug("Not Found:: " + name); + break; + } + } + if (packages.isEmpty()) { + throw new Exception("No packages defined as '" + handlerPackage + "' in web.xml"); + } + return packages; + } + + private void addResourceMethod(Resource resource, Method method) throws Exception { + + Class[] params = method.getParameterTypes(); + ResourceMethod rm = new ResourceMethod(); + rm.setResourceType(method.getReturnType()); + + //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); + } + rm.setParameters(Util.getResourceParameters(method)); + resource.addMethod(rm); + } + + private void findResourceMethods(Class handler) throws Exception { + for (Method m : handler.getDeclaredMethods()) { + //only static methods are valid request handlers + if (Modifier.isStatic(m.getModifiers()) && Modifier.isPublic(m.getModifiers())) { + + String resourceName = Util.getResourceName(m); + Resource r = resources.get(resourceName); + if (null == r) { + r = new Resource(); + r.setResourceName(resourceName); + resources.put(resourceName, r); + } + addResourceMethod(r, m); + + log.debug("found handler: " + m.getName()); + } + } + } + + public void init() { + try { + Context env = (Context) new InitialContext().lookup("java:comp/env"); + List packages = findRESTHanlderPackages(env); + + for (String packagePath : packages) { + log.info("searching for JSON operation handlers in package: " + packagePath); + List> handlers = getClasses(packagePath); + for (Class handler : handlers) { + log.info("found class: " + handler.getName()); + findResourceMethods(handler); + } + } + } catch (Exception ex) { + log.error("An error occurred while loading request handlers!", ex); + } + } + + @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); + } + + @Override + protected void doDelete(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + handleRequest(ResourceMethod.RequestType.DELETE, request, response); + } + + protected void handleRequest(ResourceMethod.RequestType requestType, HttpServletRequest request, HttpServletResponse response) { + try { + + response.setContentType(request.getHeader("Accept")); + String resourceName = request.getRequestURI(); + Map params = Util.getQueryParams(request.getQueryString()); + + Resource resource = resources.get(resourceName); + if (null == resource) throw new MethodNotFoundException("No resource available for " + resourceName); + + ResourceMethod resourceMethod = resource.getMethod(params.keySet()); + if (null == resourceMethod) throw new MethodNotFoundException("No resource method available for the supplied parameters " + params); + + FhirContext ctx = new FhirContext(resourceMethod.getResourceType().getClass()); + XmlParser p = new XmlParser(ctx); + response.getWriter().write(p.encodeResourceToString(resourceMethod.invoke(params))); + } catch (Throwable t) { + //TODO: handle errors + } + + + } + + 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; + } + + /** + * 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; + } +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Util.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Util.java new file mode 100644 index 00000000000..c55f8b86bb4 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/Util.java @@ -0,0 +1,67 @@ +package ca.uhn.fhir.ws; + +import ca.uhn.fhir.ws.parameters.Optional; +import ca.uhn.fhir.ws.parameters.Required; + +import java.io.UnsupportedEncodingException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class Util { + public static Map getQueryParams(String query) throws UnsupportedEncodingException { + try { + + Map params = new HashMap(); + for (String param : query.split("&")) { + String[] pair = param.split("="); + String key = URLDecoder.decode(pair[0], "UTF-8"); + String value = URLDecoder.decode(pair[1], "UTF-8"); + + params.put(key, value); + } + return params; + } catch (UnsupportedEncodingException ex) { + throw new AssertionError(ex); + } + } + + public static String getResourceName(Method method) { + ResourceName resourceNameAnnotation = method.getAnnotation(ResourceName.class); + if (null != resourceNameAnnotation) { + return resourceNameAnnotation.value(); + } + return null; + } + + public static List getResourceParameters(Method method) { + List parameters = new ArrayList(); + + Class[] parameterTypes = method.getParameterTypes(); + for (Annotation[] annotations : method.getParameterAnnotations()) { + for (int i = 0; i < annotations.length; i++) { + Annotation a = annotations[i]; + Parameter parameter = new Parameter(); + if (a instanceof Required) { + parameter.setName(((Required) a).name()); + parameter.setRequired(true); + parameter.setType(parameterTypes[i]); + + } else if (a instanceof Optional) { + parameter.setName(((Optional) a).name()); + parameter.setRequired(false); + parameter.setType(parameterTypes[i]); + } + parameters.add(parameter); + } + } + return parameters; + } +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/exceptions/MethodNotFoundException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/exceptions/MethodNotFoundException.java new file mode 100644 index 00000000000..e96444389cd --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/exceptions/MethodNotFoundException.java @@ -0,0 +1,8 @@ +package ca.uhn.fhir.ws.exceptions; + +/** + * Created by dsotnikov on 2/27/2014. + */ +public class MethodNotFoundException extends Exception { + public MethodNotFoundException(String error) { super(error); } +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/DELETE.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/DELETE.java new file mode 100644 index 00000000000..4fbbfa25981 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/DELETE.java @@ -0,0 +1,10 @@ +package ca.uhn.fhir.ws.operations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) + +public @interface DELETE { + +} \ No newline at end of file diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/GET.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/GET.java new file mode 100644 index 00000000000..e138944ac3c --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/GET.java @@ -0,0 +1,10 @@ +package ca.uhn.fhir.ws.operations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) + +public @interface GET { + +} \ No newline at end of file diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/POST.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/POST.java new file mode 100644 index 00000000000..69eb1725590 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/POST.java @@ -0,0 +1,10 @@ +package ca.uhn.fhir.ws.operations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) + +public @interface POST { + +} \ No newline at end of file diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/PUT.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/PUT.java new file mode 100644 index 00000000000..6a6962f9cec --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/operations/PUT.java @@ -0,0 +1,10 @@ +package ca.uhn.fhir.ws.operations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) + +public @interface PUT { + +} \ No newline at end of file diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/parameters/Optional.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/parameters/Optional.java new file mode 100644 index 00000000000..53fd051fea8 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/parameters/Optional.java @@ -0,0 +1,10 @@ +package ca.uhn.fhir.ws.parameters; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) + +public @interface Optional { + String name(); +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/parameters/Required.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/parameters/Required.java new file mode 100644 index 00000000000..abbf736219a --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/ws/parameters/Required.java @@ -0,0 +1,10 @@ +package ca.uhn.fhir.ws.parameters; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) + +public @interface Required { + String name(); +} diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/ws/PatientResource.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/ws/PatientResource.java new file mode 100644 index 00000000000..9fdbdc09f9c --- /dev/null +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/ws/PatientResource.java @@ -0,0 +1,18 @@ +package ca.uhn.fhir.ws; + +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.ws.operations.GET; +import ca.uhn.fhir.ws.parameters.Required; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class PatientResource { + + @GET + @ResourceName(value="Patient") + public static Patient getPatient(@Required(name="mrn") String mrn) { + return null; + } +} diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/ws/ResourceTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/ws/ResourceTest.java new file mode 100644 index 00000000000..e42ff720cad --- /dev/null +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/ws/ResourceTest.java @@ -0,0 +1,171 @@ +package ca.uhn.fhir.ws; + +import junit.framework.TestCase; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class ResourceTest extends TestCase { + + + @Before + public void setUp() throws Exception { + /* + System.setProperty("java.naming.factory.initial", "org.apache.naming.java.javaURLContextFactory"); + System.setProperty("java.naming.factory.url.pkgs", "org.apache.naming"); + InitialContext context = new InitialContext(); + //context.bind("java:comp", "env"); + context.bind(context.composeName("java:comp", "env"), "ca.uhn.rest.handlers"); + + //Context subcontext = context.createSubcontext("java:comp/env"); + //context.bind("java:comp/env/ca.uhn.rest.handlers", "ca.uhn.test"); + + Context env = (Context) new InitialContext().lookup("java:comp/env"); + + //System.out.println((String) env.lookup("ca.uhn.rest.handlers")); + */ + } + + @Test + public void testServlet() throws Exception { + + Server server = new Server(3000); + + ServletHandler proxyHandler = new ServletHandler(); + ServletHolder servletHolder = new ServletHolder(new Service()); + proxyHandler.addServletWithMapping(servletHolder, "/"); + server.setHandler(proxyHandler); + server.start(); + + MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager(); + HttpClient client = new HttpClient(connectionManager); + + + PostMethod httpPost = new PostMethod("http://localhost:3000/foo/bar?bar=123&more=params"); + httpPost.setRequestEntity(new StringRequestEntity("test", "application/json", "UTF-8")); + int status = client.executeMethod(httpPost); + System.out.println(status); + +// server.join(); + } + + @Test + public void testResource() throws Exception { + + //TODO: better params handling + for (Method m : PatientResource.class.getDeclaredMethods()) { + Util.getResourceParameters(m); + + Integer i = 0; + Class c = i.getClass(); + System.out.println(c.getCanonicalName()); + } + } + + @Test + public void testRequiredParamsMissing() { + ResourceMethod rm = new ResourceMethod(); + List methodParams = new ArrayList(); + + methodParams.add(new Parameter("firstName", false)); + methodParams.add(new Parameter("lastName", false)); + methodParams.add(new Parameter("mrn", true)); + + rm.setParameters(methodParams); + + Set inputParams = new HashSet(); + inputParams.add("firstName"); + inputParams.add("lastName"); + + assertEquals(false, rm.matches(inputParams)); //False + } + + @Test + public void testRequiredParamsOnly() { + ResourceMethod rm = new ResourceMethod(); + List methodParams = new ArrayList(); + + methodParams.add(new Parameter("firstName", false)); + methodParams.add(new Parameter("lastName", false)); + methodParams.add(new Parameter("mrn", true)); + + rm.setParameters(methodParams); + + Set inputParams = new HashSet(); + inputParams.add("mrn"); + assertEquals(true, rm.matches(inputParams)); //True + } + + @Test + public void testMixedParams() { + ResourceMethod rm = new ResourceMethod(); + List methodParams = new ArrayList(); + + methodParams.add(new Parameter("firstName", false)); + methodParams.add(new Parameter("lastName", false)); + methodParams.add(new Parameter("mrn", true)); + + rm.setParameters(methodParams); + + Set inputParams = new HashSet(); + inputParams.add("firstName"); + inputParams.add("mrn"); + + assertEquals(true, rm.matches(inputParams)); //True + } + + @Test + public void testAllParams() { + ResourceMethod rm = new ResourceMethod(); + List methodParams = new ArrayList(); + + methodParams.add(new Parameter("firstName", false)); + methodParams.add(new Parameter("lastName", false)); + methodParams.add(new Parameter("mrn", true)); + + rm.setParameters(methodParams); + + Set inputParams = new HashSet(); + inputParams.add("firstName"); + inputParams.add("lastName"); + inputParams.add("mrn"); + + assertEquals(true, rm.matches(inputParams)); //True + } + + @Test + public void testAllParamsWithExtra() { + ResourceMethod rm = new ResourceMethod(); + List methodParams = new ArrayList(); + + methodParams.add(new Parameter("firstName", false)); + methodParams.add(new Parameter("lastName", false)); + methodParams.add(new Parameter("mrn", true)); + + rm.setParameters(methodParams); + + Set inputParams = new HashSet(); + inputParams.add("firstName"); + inputParams.add("lastName"); + inputParams.add("mrn"); + inputParams.add("foo"); + + assertEquals(false, rm.matches(inputParams)); //False + } + +}