More client work
This commit is contained in:
parent
b05ea01b45
commit
82193017d8
|
@ -3,7 +3,7 @@
|
|||
<classpathentry including="**/*.java" kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**/*.java" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry including="**/*.java" kind="src" path="src/main/java"/>
|
||||
<classpathentry kind="var" path="M2_REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar" sourcepath="M2_REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0-sources.jar">
|
||||
<classpathentry kind="var" path="M2_REPO/javax/servlet/javax.servlet-api/3.0.1/javax.servlet-api-3.0.1.jar" sourcepath="M2_REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0-sources.jar">
|
||||
<attributes>
|
||||
<attribute name="javadoc_location" value="jar:file:/Users/james/.m2/repository/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0-javadoc.jar!/"/>
|
||||
</attributes>
|
||||
|
@ -80,8 +80,7 @@
|
|||
<attribute name="javadoc_location" value="jar:file:/Users/james/.m2/repository/xmlunit/xmlunit/1.5/xmlunit-1.5-javadoc.jar!/"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/mockito/mockito-all/1.9.5/mockito-all-1.9.5.jar"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/hapi-fhir-structures-dstu"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
|
|
@ -5,10 +5,18 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Read {
|
||||
|
||||
/**
|
||||
* Returns the resource type that is returned by the method annotated
|
||||
* with this annotation
|
||||
*/
|
||||
Class<? extends IResource> value();
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface IdParam {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
public class ClientInvocation {
|
||||
|
||||
}
|
|
@ -2,21 +2,34 @@ package ca.uhn.fhir.rest.client;
|
|||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.common.BaseMethodBinding;
|
||||
|
||||
public class ClientInvocationHandler implements InvocationHandler {
|
||||
|
||||
private HttpClient myClient;
|
||||
private Map<Method, BaseMethodBinding> myBindings = new HashMap<Method, BaseMethodBinding>();
|
||||
private FhirContext myContext;
|
||||
|
||||
public ClientInvocationHandler(HttpClient theClient) {
|
||||
public ClientInvocationHandler(HttpClient theClient, FhirContext theContext) {
|
||||
myClient = theClient;
|
||||
myContext = theContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object theProxy, Method theMethod, Object[] theArgs) throws Throwable {
|
||||
// TODO Auto-generated method stub
|
||||
BaseMethodBinding binding = myBindings.get(theMethod);
|
||||
ClientInvocation clientInvocation = binding.invokeClient(theArgs);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addBinding(Method theMethod, BaseMethodBinding theBinding) {
|
||||
myBindings.put(theMethod, theBinding);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -11,7 +12,9 @@ import org.apache.http.impl.conn.SchemeRegistryFactory;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.common.BaseMethodBinding;
|
||||
|
||||
public class RestfulClientFactory {
|
||||
|
||||
|
@ -20,20 +23,23 @@ public class RestfulClientFactory {
|
|||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theContext The context
|
||||
* @param theContext
|
||||
* The context
|
||||
*/
|
||||
public RestfulClientFactory(FhirContext theContext) {
|
||||
myContext = theContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new client instance
|
||||
*
|
||||
* @param theClientType The client type, which is an interface type to be instantiated
|
||||
* @param theServerBase The URL of the base for the restful FHIR server to connect to
|
||||
* @param theClientType
|
||||
* The client type, which is an interface type to be instantiated
|
||||
* @param theServerBase
|
||||
* The URL of the base for the restful FHIR server to connect to
|
||||
* @return A newly created client
|
||||
* @throws ConfigurationException If the interface type is not an interface
|
||||
* @throws ConfigurationException
|
||||
* If the interface type is not an interface
|
||||
*/
|
||||
public <T extends IRestfulClient> T newClient(Class<T> theClientType, String theServerBase){
|
||||
if (!theClientType.isInterface()) {
|
||||
|
@ -43,7 +49,12 @@ public class RestfulClientFactory {
|
|||
PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager(SchemeRegistryFactory.createDefault(), 5000, TimeUnit.MILLISECONDS);
|
||||
HttpClient client = new DefaultHttpClient(connectionManager);
|
||||
|
||||
ClientInvocationHandler theInvocationHandler = new ClientInvocationHandler(client);
|
||||
ClientInvocationHandler theInvocationHandler = new ClientInvocationHandler(client, myContext);
|
||||
|
||||
for (Method nextMethod : theClientType.getMethods()) {
|
||||
BaseMethodBinding binding = BaseMethodBinding.bindMethod(nextMethod);
|
||||
theInvocationHandler.addBinding(nextMethod, binding);
|
||||
}
|
||||
|
||||
T proxy = instantiateProxy(theClientType, theInvocationHandler);
|
||||
|
||||
|
@ -51,6 +62,7 @@ public class RestfulClientFactory {
|
|||
}
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends IRestfulClient> T instantiateProxy(Class<T> theClientType, InvocationHandler theInvocationHandler) {
|
||||
T proxy = (T) Proxy.newProxyInstance(RestfulClientFactory.class.getClassLoader(), new Class[] { theClientType }, theInvocationHandler);
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
package ca.uhn.fhir.rest.common;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.client.ClientInvocation;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.Resource;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.operations.Search;
|
||||
|
||||
public abstract class BaseMethodBinding {
|
||||
|
||||
private String myResourceName;
|
||||
|
||||
public BaseMethodBinding(Class<? extends IResource> theAnnotatedResourceType) {
|
||||
ResourceDef resourceDefAnnotation = theAnnotatedResourceType.getAnnotation(ResourceDef.class);
|
||||
if (resourceDefAnnotation == null) {
|
||||
throw new ConfigurationException(theAnnotatedResourceType.getCanonicalName() + " has no @" + ResourceDef.class.getSimpleName()+ " annotation");
|
||||
}
|
||||
myResourceName = resourceDefAnnotation.name();
|
||||
}
|
||||
|
||||
public abstract ReturnTypeEnum getReturnType();
|
||||
|
||||
public ClientInvocation invokeClient(Object[] theArgs) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract List<IResource> invokeServer(IResourceProvider theResourceProvider, IdDt theId, IdDt theVersionId, Map<String, String[]> theParameterValues) throws InvalidRequestException, InternalErrorException;
|
||||
|
||||
public abstract boolean matches(String theResourceName, IdDt theId, IdDt theVersion, Set<String> theParameterNames);
|
||||
|
||||
public String getResourceName() {
|
||||
return myResourceName;
|
||||
}
|
||||
|
||||
public static BaseMethodBinding bindMethod(Method theMethod) {
|
||||
Read read = theMethod.getAnnotation(Read.class);
|
||||
Search search = theMethod.getAnnotation(Search.class);
|
||||
verifyExactlyOneValued(theMethod, read, search);
|
||||
|
||||
Class<? extends IResource> annotatedResourceType;
|
||||
if (read != null) {
|
||||
annotatedResourceType = read.value();
|
||||
} else {
|
||||
annotatedResourceType = search.value();
|
||||
}
|
||||
|
||||
Class<?> methodReturnType = theMethod.getReturnType();
|
||||
|
||||
if (read != null) {
|
||||
return new ReadMethodBinding(annotatedResourceType, theMethod);
|
||||
} else if (search != null) {
|
||||
return new SearchMethodBinding(annotatedResourceType, theMethod);
|
||||
} else {
|
||||
throw new ConfigurationException("Did not detect any FHIR annotations on method '" + theMethod.getName() + "' on type: " + theMethod.getDeclaringClass().getCanonicalName());
|
||||
}
|
||||
|
||||
// // each operation name must have a request type annotation and be
|
||||
// unique
|
||||
// if (null != read) {
|
||||
// return rm;
|
||||
// }
|
||||
//
|
||||
// SearchMethodBinding sm = new SearchMethodBinding();
|
||||
// if (null != search) {
|
||||
// sm.setRequestType(SearchMethodBinding.RequestType.GET);
|
||||
// } else if (null != theMethod.getAnnotation(PUT.class)) {
|
||||
// sm.setRequestType(SearchMethodBinding.RequestType.PUT);
|
||||
// } else if (null != theMethod.getAnnotation(POST.class)) {
|
||||
// sm.setRequestType(SearchMethodBinding.RequestType.POST);
|
||||
// } else if (null != theMethod.getAnnotation(DELETE.class)) {
|
||||
// sm.setRequestType(SearchMethodBinding.RequestType.DELETE);
|
||||
// } else {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// return sm;
|
||||
}
|
||||
|
||||
public static void verifyExactlyOneValued(Method theNextMethod, Object... theAnnotations) {
|
||||
Object obj1 = null;
|
||||
for (Object object : theAnnotations) {
|
||||
if (object != null) {
|
||||
if (obj1 == null) {
|
||||
obj1 = object;
|
||||
} else {
|
||||
throw new ConfigurationException("Method " + theNextMethod.getName() + " on type '" + theNextMethod.getDeclaringClass().getSimpleName() + " has annotations @" + obj1.getClass().getSimpleName() + " and @" + object.getClass().getSimpleName()
|
||||
+ ". Can not have both.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (obj1 == null) {
|
||||
throw new ConfigurationException("Method " + theNextMethod.getName() + " on type '" + theNextMethod.getDeclaringClass().getSimpleName() + " has no FHIR method annotations.");
|
||||
}
|
||||
}
|
||||
|
||||
protected static List<IResource> toResourceList(Object response) throws InternalErrorException {
|
||||
if (response == null) {
|
||||
return Collections.emptyList();
|
||||
} else if (response instanceof IResource) {
|
||||
return Collections.singletonList((IResource) response);
|
||||
} else if (response instanceof Collection) {
|
||||
List<IResource> retVal = new ArrayList<IResource>();
|
||||
for (Object next : ((Collection<?>) response)) {
|
||||
retVal.add((IResource) next);
|
||||
}
|
||||
return retVal;
|
||||
} else {
|
||||
throw new InternalErrorException("Unexpected return type: " + response.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
public enum ReturnTypeEnum {
|
||||
BUNDLE, RESOURCE
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
package ca.uhn.fhir.rest.common;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
@ -10,23 +10,29 @@ import org.apache.commons.lang3.Validate;
|
|||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.Util;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
class ReadMethod extends BaseMethod {
|
||||
public class ReadMethodBinding extends BaseMethodBinding {
|
||||
|
||||
private Method myMethod;
|
||||
private Integer myIdIndex;
|
||||
private Integer myVersionIdIndex;
|
||||
private int myParameterCount;
|
||||
|
||||
ReadMethod(Method theMethod, Integer theIdIndex, Integer theVersionIdIndex) {
|
||||
public ReadMethodBinding(Class<? extends IResource> theAnnotatedResourceType, Method theMethod) {
|
||||
super(theAnnotatedResourceType);
|
||||
|
||||
Validate.notNull(theMethod, "Method must not be null");
|
||||
Validate.notNull(theIdIndex, "ID Index must not be null");
|
||||
|
||||
Integer idIndex = Util.findReadIdParameterIndex(theMethod);
|
||||
Integer versionIdIndex = Util.findReadVersionIdParameterIndex(theMethod);
|
||||
|
||||
myMethod = theMethod;
|
||||
myIdIndex = theIdIndex;
|
||||
myVersionIdIndex = theVersionIdIndex;
|
||||
myIdIndex = idIndex;
|
||||
myVersionIdIndex = versionIdIndex;
|
||||
myParameterCount = myMethod.getParameterTypes().length;
|
||||
|
||||
Class<?>[] parameterTypes = theMethod.getParameterTypes();
|
||||
|
@ -41,7 +47,7 @@ class ReadMethod extends BaseMethod {
|
|||
|
||||
@Override
|
||||
public boolean matches(String theResourceName, IdDt theId, IdDt theVersion, Set<String> theParameterNames) {
|
||||
if (!theResourceName.equals(getResource().getResourceName())) {
|
||||
if (!theResourceName.equals(getResourceName())) {
|
||||
return false;
|
||||
}
|
||||
if (theParameterNames.isEmpty() == false) {
|
||||
|
@ -62,7 +68,7 @@ class ReadMethod extends BaseMethod {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<IResource> invoke(IResourceProvider theResourceProvider, IdDt theId, IdDt theVersionId, Map<String, String[]> theParameterValues) throws InvalidRequestException,
|
||||
public List<IResource> invokeServer(IResourceProvider theResourceProvider, IdDt theId, IdDt theVersionId, Map<String, String[]> theParameterValues) throws InvalidRequestException,
|
||||
InternalErrorException {
|
||||
Object[] params = new Object[myParameterCount];
|
||||
params[myIdIndex] = theId;
|
|
@ -1,41 +1,41 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
package ca.uhn.fhir.rest.common;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.internal.MethodSorter;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.Parameter;
|
||||
import ca.uhn.fhir.rest.server.Util;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public class SearchMethod extends BaseMethod {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchMethod.class);
|
||||
public class SearchMethodBinding extends BaseMethodBinding {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchMethodBinding.class);
|
||||
|
||||
private Method method;
|
||||
|
||||
private List<Parameter> parameters;
|
||||
private RequestType requestType;
|
||||
private Class<?> resourceType;
|
||||
private Class<?> myDeclaredResourceType;
|
||||
|
||||
public SearchMethod() {
|
||||
}
|
||||
public SearchMethodBinding(Class<? extends IResource> theAnnotatedResourceType, Method theMethod) {
|
||||
super(theAnnotatedResourceType);
|
||||
this.method = theMethod;
|
||||
this.parameters = Util.getResourceParameters(theMethod);
|
||||
|
||||
public SearchMethod(Method method, List<Parameter> parameters) {
|
||||
this.method = method;
|
||||
this.parameters = parameters;
|
||||
this.myDeclaredResourceType = theMethod.getReturnType();
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
|
@ -50,8 +50,8 @@ public class SearchMethod extends BaseMethod {
|
|||
return requestType;
|
||||
}
|
||||
|
||||
public Class getResourceType() {
|
||||
return resourceType.getClass();
|
||||
public Class getDeclaredResourceType() {
|
||||
return myDeclaredResourceType.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,7 +60,7 @@ public class SearchMethod extends BaseMethod {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<IResource> invoke(IResourceProvider theResourceProvider, IdDt theId, IdDt theVersionId, Map<String, String[]> parameterValues) throws InvalidRequestException, InternalErrorException {
|
||||
public List<IResource> invokeServer(IResourceProvider theResourceProvider, IdDt theId, IdDt theVersionId, Map<String, String[]> parameterValues) throws InvalidRequestException, InternalErrorException {
|
||||
assert theId == null;
|
||||
assert theVersionId == null;
|
||||
|
||||
|
@ -94,12 +94,12 @@ public class SearchMethod extends BaseMethod {
|
|||
|
||||
@Override
|
||||
public boolean matches(String theResourceName, IdDt theId, IdDt theVersion, Set<String> theParameterNames) {
|
||||
if (!theResourceName.equals(getResource().getResourceName())) {
|
||||
ourLog.info("Method {} doesn't match because resource name {} != {}", method.getName(), theResourceName, getResource().getResourceName());
|
||||
if (!theResourceName.equals(getResourceName())) {
|
||||
ourLog.trace("Method {} doesn't match because resource name {} != {}", method.getName(), theResourceName, getResourceName());
|
||||
return false;
|
||||
}
|
||||
if (theId != null || theVersion != null) {
|
||||
ourLog.info("Method {} doesn't match because ID or Version are not null: {} - {}", theId, theVersion);
|
||||
ourLog.trace("Method {} doesn't match because ID or Version are not null: {} - {}", theId, theVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -108,13 +108,13 @@ public class SearchMethod extends BaseMethod {
|
|||
Parameter temp = this.parameters.get(i);
|
||||
methodParamsTemp.add(temp.getName());
|
||||
if (temp.isRequired() && !theParameterNames.contains(temp.getName())) {
|
||||
ourLog.info("Method {} doesn't match param '{}' is not present", temp.getName());
|
||||
ourLog.trace("Method {} doesn't match param '{}' is not present", method.getName(), temp.getName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean retVal = methodParamsTemp.containsAll(theParameterNames);
|
||||
|
||||
ourLog.info("Method {} matches: {}", method.getName(), retVal);
|
||||
ourLog.trace("Method {} matches: {}", method.getName(), retVal);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ public class SearchMethod extends BaseMethod {
|
|||
}
|
||||
|
||||
public void setResourceType(Class<?> resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
this.myDeclaredResourceType = resourceType;
|
||||
}
|
||||
|
||||
public static enum RequestType {
|
|
@ -1,53 +0,0 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
abstract class BaseMethod {
|
||||
|
||||
public enum ReturnTypeEnum {
|
||||
RESOURCE, BUNDLE
|
||||
}
|
||||
|
||||
private Resource resource;
|
||||
|
||||
public Resource getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public abstract ReturnTypeEnum getReturnType();
|
||||
|
||||
public abstract boolean matches(String theResourceName, IdDt theId, IdDt theVersion, Set<String> theParameterNames);
|
||||
|
||||
public void setResource(Resource theResource) {
|
||||
this.resource = theResource;
|
||||
}
|
||||
|
||||
public abstract List<IResource> invoke(IResourceProvider theResourceProvider, IdDt theId, IdDt theVersionId, Map<String, String[]> theParameterValues) throws InvalidRequestException,
|
||||
InternalErrorException;
|
||||
|
||||
protected static List<IResource> toResourceList(Object response) throws InternalErrorException {
|
||||
if (response == null) {
|
||||
return Collections.emptyList();
|
||||
} else if (response instanceof IResource) {
|
||||
return Collections.singletonList((IResource) response);
|
||||
} else if (response instanceof Collection) {
|
||||
List<IResource> retVal = new ArrayList<IResource>();
|
||||
for (Object next : ((Collection<?>) response)) {
|
||||
retVal.add((IResource) next);
|
||||
}
|
||||
return retVal;
|
||||
} else {
|
||||
throw new InternalErrorException("Unexpected return type: " + response.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.common.BaseMethodBinding;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
|
@ -14,25 +15,25 @@ public class Resource {
|
|||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Resource.class);
|
||||
|
||||
private String resourceName;
|
||||
private List<BaseMethod> methods = new ArrayList<BaseMethod>();
|
||||
private List<BaseMethodBinding> methods = new ArrayList<BaseMethodBinding>();
|
||||
private IResourceProvider resourceProvider;
|
||||
|
||||
public Resource() {
|
||||
}
|
||||
|
||||
public Resource(String resourceName, List<BaseMethod> methods) {
|
||||
public Resource(String resourceName, List<BaseMethodBinding> methods) {
|
||||
this.resourceName = resourceName;
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
public BaseMethod getMethod(String theResourceName, IdDt theId, IdDt theVersionId, Set<String> theParameters) throws Exception {
|
||||
public BaseMethodBinding getMethod(String theResourceName, IdDt theId, IdDt theVersionId, Set<String> theParameters) throws Exception {
|
||||
if (null == methods) {
|
||||
ourLog.warn("No methods exist for resource provider: {}", resourceProvider.getClass());
|
||||
return null;
|
||||
}
|
||||
|
||||
ourLog.info("Looking for a handler for {} / {} / {} / {}", new Object[] {theResourceName,theId, theVersionId, theParameters});
|
||||
for (BaseMethod rm : methods) {
|
||||
for (BaseMethodBinding rm : methods) {
|
||||
if (rm.matches(theResourceName, theId, theVersionId, theParameters)) {
|
||||
ourLog.info("Handler {} matches", rm);
|
||||
return rm;
|
||||
|
@ -51,17 +52,16 @@ public class Resource {
|
|||
this.resourceName = resourceName;
|
||||
}
|
||||
|
||||
public List<BaseMethod> getMethods() {
|
||||
public List<BaseMethodBinding> getMethods() {
|
||||
return methods;
|
||||
}
|
||||
|
||||
public void setMethods(List<BaseMethod> methods) {
|
||||
public void setMethods(List<BaseMethodBinding> methods) {
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
public void addMethod(BaseMethod method) {
|
||||
public void addMethod(BaseMethodBinding method) {
|
||||
this.methods.add(method);
|
||||
method.setResource(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
package ca.uhn.fhir.rest.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;
|
||||
|
@ -20,22 +16,20 @@ import javax.servlet.http.HttpServlet;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
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.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.parser.XmlParser;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.common.BaseMethodBinding;
|
||||
import ca.uhn.fhir.rest.common.SearchMethodBinding;
|
||||
import ca.uhn.fhir.rest.server.exceptions.AbstractResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.operations.DELETE;
|
||||
import ca.uhn.fhir.rest.server.operations.Search;
|
||||
import ca.uhn.fhir.rest.server.operations.POST;
|
||||
import ca.uhn.fhir.rest.server.operations.PUT;
|
||||
|
||||
public abstract class RestfulServer extends HttpServlet {
|
||||
|
||||
|
@ -50,38 +44,6 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
// map of request handler resources keyed by resource name
|
||||
private Map<String, Resource> resources = new HashMap<String, Resource>();
|
||||
|
||||
private boolean addResourceMethod(Resource resource, Method method) throws Exception {
|
||||
|
||||
// each operation name must have a request type annotation and be unique
|
||||
if (null != method.getAnnotation(Read.class)) {
|
||||
Integer idIndex = Util.findReadIdParameterIndex(method);
|
||||
Integer versionIdIndex = Util.findReadVersionIdParameterIndex(method);
|
||||
ReadMethod rm = new ReadMethod(method, idIndex, versionIdIndex);
|
||||
resource.addMethod(rm);
|
||||
return true;
|
||||
}
|
||||
|
||||
SearchMethod sm = new SearchMethod();
|
||||
if (null != method.getAnnotation(Search.class)) {
|
||||
sm.setRequestType(SearchMethod.RequestType.GET);
|
||||
} else if (null != method.getAnnotation(PUT.class)) {
|
||||
sm.setRequestType(SearchMethod.RequestType.PUT);
|
||||
} else if (null != method.getAnnotation(POST.class)) {
|
||||
sm.setRequestType(SearchMethod.RequestType.POST);
|
||||
} else if (null != method.getAnnotation(DELETE.class)) {
|
||||
sm.setRequestType(SearchMethod.RequestType.DELETE);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
sm.setMethod(method);
|
||||
sm.setResourceType(method.getReturnType());
|
||||
sm.setParameters(Util.getResourceParameters(method));
|
||||
|
||||
resource.addMethod(sm);
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private EncodingUtil determineResponseEncoding(Map<String, String[]> theParams) {
|
||||
String[] format = theParams.remove(Constants.PARAM_FORMAT);
|
||||
|
@ -91,22 +53,22 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
|
||||
@Override
|
||||
protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
handleRequest(SearchMethod.RequestType.DELETE, request, response);
|
||||
handleRequest(SearchMethodBinding.RequestType.DELETE, request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
handleRequest(SearchMethod.RequestType.GET, request, response);
|
||||
handleRequest(SearchMethodBinding.RequestType.GET, request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
handleRequest(SearchMethod.RequestType.POST, request, response);
|
||||
handleRequest(SearchMethodBinding.RequestType.POST, request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
handleRequest(SearchMethod.RequestType.PUT, request, response);
|
||||
handleRequest(SearchMethodBinding.RequestType.PUT, request, response);
|
||||
}
|
||||
|
||||
private void findResourceMethods(IResourceProvider theProvider) throws Exception {
|
||||
|
@ -126,8 +88,9 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
if (Modifier.isPublic(m.getModifiers())) {
|
||||
ourLog.info("Scanning public method: {}#{}", theProvider.getClass(), m.getName());
|
||||
|
||||
boolean foundMethod = addResourceMethod(r, m);
|
||||
if (foundMethod) {
|
||||
BaseMethodBinding foundMethodBinding = BaseMethodBinding.bindMethod(m);
|
||||
if (foundMethodBinding != null) {
|
||||
r.addMethod(foundMethodBinding);
|
||||
ourLog.info(" * Method: {}#{} is a handler", theProvider.getClass(), m.getName());
|
||||
} else {
|
||||
ourLog.info(" * Method: {}#{} is not a handler", theProvider.getClass(), m.getName());
|
||||
|
@ -138,13 +101,14 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
|
||||
public abstract Collection<IResourceProvider> getResourceProviders();
|
||||
|
||||
protected void handleRequest(SearchMethod.RequestType requestType, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
protected void handleRequest(SearchMethodBinding.RequestType requestType, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
try {
|
||||
String resourceName = null;
|
||||
Long identity = null;
|
||||
|
||||
String requestPath = request.getRequestURI();
|
||||
requestPath = requestPath.substring(request.getContextPath().length());
|
||||
String requestPath = StringUtils.defaultString(request.getRequestURI());
|
||||
String contextPath = StringUtils.defaultString(request.getContextPath());
|
||||
requestPath = requestPath.substring(contextPath.length());
|
||||
if (requestPath.charAt(0) == '/') {
|
||||
requestPath = requestPath.substring(1);
|
||||
}
|
||||
|
@ -178,21 +142,23 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
//
|
||||
// if (identity != null && !tok.hasMoreTokens()) {
|
||||
// if (params == null || params.isEmpty()) {
|
||||
// IResource resource = resourceBinding.getResourceProvider().getResourceById(identity);
|
||||
// IResource resource =
|
||||
// resourceBinding.getResourceProvider().getResourceById(identity);
|
||||
// if (resource == null) {
|
||||
// throw new ResourceNotFoundException(identity);
|
||||
// }
|
||||
// streamResponseAsResource(response, resource, resourceBinding, responseEncoding);
|
||||
// streamResponseAsResource(response, resource, resourceBinding,
|
||||
// responseEncoding);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
BaseMethod resourceMethod = resourceBinding.getMethod(resourceName, id, versionId, params.keySet());
|
||||
BaseMethodBinding resourceMethod = resourceBinding.getMethod(resourceName, id, versionId, params.keySet());
|
||||
if (null == resourceMethod) {
|
||||
throw new MethodNotFoundException("No resource method available for the supplied parameters " + params);
|
||||
}
|
||||
|
||||
List<IResource> result = resourceMethod.invoke(resourceBinding.getResourceProvider(), id, versionId, params);
|
||||
List<IResource> result = resourceMethod.invokeServer(resourceBinding.getResourceProvider(), id, versionId, params);
|
||||
switch (resourceMethod.getReturnType()) {
|
||||
case BUNDLE:
|
||||
streamResponseAsBundle(response, result, responseEncoding);
|
||||
|
@ -293,6 +259,4 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -3,8 +3,16 @@ package ca.uhn.fhir.rest.server.operations;
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
public @interface Search {
|
||||
|
||||
/**
|
||||
* Returns the resource type that is returned by the method annotated
|
||||
* with this annotation
|
||||
*/
|
||||
Class<? extends IResource> value();
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.server.operations.Search;
|
||||
import ca.uhn.fhir.rest.server.parameters.Required;
|
||||
|
||||
public interface ITestClient extends IRestfulClient {
|
||||
|
||||
@Read(value=Patient.class)
|
||||
Patient getPatientById(@Read.IdParam IdDt theId);
|
||||
|
||||
@Search(value=Patient.class)
|
||||
Patient findPatientByMrn(@Required(name = Patient.SP_IDENTIFIER) IdentifierDt theId);
|
||||
|
||||
@Search(value=Patient.class)
|
||||
Bundle findPatientByLastName(@Required(name = Patient.SP_FAMILY) IdentifierDt theId);
|
||||
}
|
|
@ -51,7 +51,7 @@ public class DummyPatientResourceProvider implements IResourceProvider {
|
|||
}
|
||||
}
|
||||
|
||||
@Search
|
||||
@Search(Patient.class)
|
||||
public Patient getPatient(@Required(name = "identifier") IdentifierDt theIdentifier) {
|
||||
for (Patient next : myIdToPatient.values()) {
|
||||
for (IdentifierDt nextId : next.getIdentifier()) {
|
||||
|
@ -75,7 +75,7 @@ public class DummyPatientResourceProvider implements IResourceProvider {
|
|||
* The resource identity
|
||||
* @return The resource
|
||||
*/
|
||||
@Read
|
||||
@Read(Patient.class)
|
||||
public Patient getResourceById(@Read.IdParam IdDt theId) {
|
||||
return myIdToPatient.get(theId.getValue());
|
||||
}
|
||||
|
|
|
@ -10,20 +10,17 @@ import java.util.Set;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.rest.common.SearchMethodBinding;
|
||||
import ca.uhn.fhir.rest.server.Parameter;
|
||||
import ca.uhn.fhir.rest.server.SearchMethod;
|
||||
|
||||
public class ResourceMethodTest {
|
||||
|
||||
private SearchMethod rm;
|
||||
private SearchMethodBinding rm;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
Resource resource = new Resource();
|
||||
resource.setResourceName("ResName");
|
||||
|
||||
rm = new SearchMethod();
|
||||
rm.setResource(resource);
|
||||
public void before() throws NoSuchMethodException, SecurityException {
|
||||
rm = new SearchMethodBinding(Patient.class, ResourceMethodTest.class.getMethod("before"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue