More work on transaction method

This commit is contained in:
jamesagnew 2014-05-22 10:20:51 -04:00
parent 62b909ff22
commit 30065fdfae
9 changed files with 371 additions and 102 deletions

View File

@ -0,0 +1,41 @@
package ca.uhn.fhir.rest.annotation;
/*
* #%L
* HAPI FHIR Library
* %%
* Copyright (C) 2014 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import ca.uhn.fhir.model.api.Bundle;
/**
* RESTful method annotation to be used for the FHIR <a href="http://hl7.org/implement/standards/fhir/http.html#transaction">transaction</a> method.
*
* <p>
* This method should have a parameter of type {@link Bundle} annotated with the {@link TransactionParam} annotation.
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Transaction {
// nothing
}

View File

@ -0,0 +1,32 @@
package ca.uhn.fhir.rest.annotation;
/*
* #%L
* HAPI FHIR Library
* %%
* Copyright (C) 2014 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value=ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface TransactionParam {
}

View File

@ -56,6 +56,7 @@ import ca.uhn.fhir.rest.annotation.History;
import ca.uhn.fhir.rest.annotation.Metadata;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Transaction;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.MethodOutcome;
@ -172,8 +173,9 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
GetTags getTags = theMethod.getAnnotation(GetTags.class);
AddTags addTags = theMethod.getAnnotation(AddTags.class);
DeleteTags deleteTags = theMethod.getAnnotation(DeleteTags.class);
Transaction transaction = theMethod.getAnnotation(Transaction.class);
// ** if you add another annotation above, also add it to the next line:
if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance, create, update, delete, history, validate, getTags, addTags, deleteTags)) {
if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance, create, update, delete, history, validate, getTags, addTags, deleteTags,transaction)) {
return null;
}
@ -283,6 +285,8 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
return new AddTagsMethodBinding(theMethod, theContext, theProvider, addTags);
} else if (deleteTags != null) {
return new DeleteTagsMethodBinding(theMethod, theContext, theProvider, deleteTags);
} else if (transaction != null) {
return new TransactionMethodBinding(theMethod, theContext, theProvider);
} else {
throw new ConfigurationException("Did not detect any FHIR annotations on method '" + theMethod.getName() + "' on type: " + theMethod.getDeclaringClass().getCanonicalName());
}

View File

@ -210,12 +210,14 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
requestIsBrowser = true;
}
Object requestObject = parseRequestObject(theRequest);
// Method params
Object[] params = new Object[getParameters().size()];
for (int i = 0; i < getParameters().size(); i++) {
IParameter param = getParameters().get(i);
if (param != null) {
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, null);
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, requestObject);
}
}
@ -235,6 +237,13 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
}
}
/**
* Subclasses may override
*/
protected Object parseRequestObject(@SuppressWarnings("unused") Request theRequest) {
return null;
}
protected static IdDt getIdFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum, Object> theResourceMetadata, ResourceMetadataKeyEnum theKey) {
Object retValObj = theResourceMetadata.get(theKey);
if (retValObj == null) {

View File

@ -1,45 +1,45 @@
package ca.uhn.fhir.rest.method;
import java.io.IOException;
import java.io.Reader;
import static org.apache.commons.lang3.StringUtils.*;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.client.BaseClientInvocation;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
import ca.uhn.fhir.rest.param.TransactionParameter;
import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class TransactionMethodBinding extends BaseResourceReturningMethodBinding {
private int myResourceParameterIndex;
public TransactionMethodBinding(Method theMethod, FhirContext theConetxt, Object theProvider) {
super(null, theMethod, theConetxt, theProvider);
}
@Override
public Bundle invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
// TODO Auto-generated method stub
return null;
}
myResourceParameterIndex = -1;
int index=0;
for (IParameter next : getParameters()) {
if (next instanceof TransactionParameter) {
myResourceParameterIndex = index;
}
index++;
}
@Override
public String getResourceName() {
return null;
}
@Override
public RestfulOperationTypeEnum getResourceOperationType() {
return null;
if (myResourceParameterIndex==-1) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type " + theMethod.getDeclaringClass().getCanonicalName() + " does not have a parameter annotated with the @" + TransactionParam.class + " annotation");
}
}
@Override
@ -47,22 +47,19 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
return RestfulOperationSystemEnum.TRANSACTION;
}
@Override
public BaseClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
// TODO Auto-generated method stub
return null;
}
@Override
public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException {
// TODO Auto-generated method stub
}
@Override
public boolean incomingServerRequestMatchesMethod(Request theRequest) {
// TODO Auto-generated method stub
return false;
if (theRequest.getRequestType() != RequestType.POST) {
return false;
}
if (isNotBlank(theRequest.getOperation())) {
return false;
}
if (isNotBlank(theRequest.getResourceName())) {
return false;
}
return true;
}
@Override
@ -72,6 +69,26 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
@Override
public List<IResource> invokeServer(Request theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
@SuppressWarnings("unchecked")
List<IResource> retVal=(List<IResource>) invokeServerMethod(theMethodParams);
return retVal;
}
@Override
protected Object parseRequestObject(Request theRequest) {
EncodingEnum encoding = determineResponseEncoding(theRequest);
IParser parser = encoding.newParser(getContext());
Bundle bundle = parser.parseBundle(theRequest.getInputReader());
return bundle;
}
@Override
public RestfulOperationTypeEnum getResourceOperationType() {
return null;
}
@Override
public BaseClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
// TODO Auto-generated method stub
return null;
}

View File

@ -50,6 +50,7 @@ import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.TagListParam;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.annotation.Count;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.IncludeParam;
@ -225,6 +226,8 @@ public class ParameterUtil {
param = new CountParameter();
} else if (nextAnnotation instanceof Sort) {
param = new SortParameter();
} else if (nextAnnotation instanceof TransactionParam) {
param = new TransactionParameter();
} else {
continue;
}

View File

@ -0,0 +1,68 @@
package ca.uhn.fhir.rest.param;
/*
* #%L
* HAPI FHIR Library
* %%
* Copyright (C) 2014 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.client.BaseClientInvocation;
import ca.uhn.fhir.rest.method.Request;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class TransactionParameter implements IParameter {
public TransactionParameter() {
}
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, BaseClientInvocation theClientInvocation) throws InternalErrorException {
// TODO Auto-generated method stub
}
@Override
public Object translateQueryParametersIntoServerArgument(Request theRequest, Object theRequestContents) throws InternalErrorException, InvalidRequestException {
Bundle resource = (Bundle) theRequestContents;
return resource;
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
if (theOuterCollectionType != null) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" +theMethod.getDeclaringClass().getCanonicalName()+ "' is annotated with @" + TransactionParam.class.getName() + " but can not be a collection of collections");
}
if (theInnerCollectionType.equals(List.class)==false) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" +theMethod.getDeclaringClass().getCanonicalName()+ "' is annotated with @" + TransactionParam.class.getName() + " but is not of type List<" + IResource.class.getCanonicalName()+">");
}
if (theParameterType.equals(IResource.class)==false) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" +theMethod.getDeclaringClass().getCanonicalName()+ "' is annotated with @" + TransactionParam.class.getName() + " but is not of type List<" + IResource.class.getCanonicalName()+">");
}
}
}

View File

@ -89,12 +89,10 @@ public class RestfulServer extends HttpServlet {
}
/**
* This method is called prior to sending a response to incoming requests.
* It is used to add custom headers.
* This method is called prior to sending a response to incoming requests. It is used to add custom headers.
* <p>
* Use caution if overriding this method: it is recommended to call
* <code>super.addHeadersToResponse</code> to avoid inadvertantly disabling
* functionality.
* Use caution if overriding this method: it is recommended to call <code>super.addHeadersToResponse</code> to avoid
* inadvertantly disabling functionality.
* </p>
*/
public void addHeadersToResponse(HttpServletResponse theHttpResponse) {
@ -102,17 +100,15 @@ public class RestfulServer extends HttpServlet {
}
/**
* Gets the {@link FhirContext} associated with this server. For efficient
* processing, resource providers and plain providers should generally use
* this context if one is needed, as opposed to creating their own.
* Gets the {@link FhirContext} associated with this server. For efficient processing, resource providers and plain
* providers should generally use this context if one is needed, as opposed to creating their own.
*/
public FhirContext getFhirContext() {
return myFhirContext;
}
/**
* Provides the non-resource specific providers which implement method calls
* on this server
* Provides the non-resource specific providers which implement method calls on this server
*
* @see #getResourceProviders()
*/
@ -139,12 +135,11 @@ public class RestfulServer extends HttpServlet {
}
/**
* Returns the server conformance provider, which is the provider that is
* used to generate the server's conformance (metadata) statement.
* Returns the server conformance provider, which is the provider that is used to generate the server's conformance
* (metadata) statement.
* <p>
* By default, the {@link ServerConformanceProvider} is used, but this can
* be changed, or set to <code>null</code> if you do not wish to export a
* conformance statement.
* By default, the {@link ServerConformanceProvider} is used, but this can be changed, or set to <code>null</code>
* if you do not wish to export a conformance statement.
* </p>
*/
public Object getServerConformanceProvider() {
@ -152,9 +147,8 @@ public class RestfulServer extends HttpServlet {
}
/**
* Gets the server's name, as exported in conformance profiles exported by
* the server. This is informational only, but can be helpful to set with
* something appropriate.
* Gets the server's name, as exported in conformance profiles exported by the server. This is informational only,
* but can be helpful to set with something appropriate.
*
* @see RestfulServer#setServerName(StringDt)
*/
@ -167,19 +161,17 @@ public class RestfulServer extends HttpServlet {
}
/**
* Gets the server's version, as exported in conformance profiles exported
* by the server. This is informational only, but can be helpful to set with
* something appropriate.
* Gets the server's version, as exported in conformance profiles exported by the server. This is informational
* only, but can be helpful to set with something appropriate.
*/
public String getServerVersion() {
return myServerVersion;
}
/**
* Initializes the server. Note that this method is final to avoid
* accidentally introducing bugs in implementations, but subclasses may put
* initialization code in {@link #initialize()}, which is called immediately
* before beginning initialization of the restful server's internal init.
* Initializes the server. Note that this method is final to avoid accidentally introducing bugs in implementations,
* but subclasses may put initialization code in {@link #initialize()}, which is called immediately before beginning
* initialization of the restful server's internal init.
*/
@Override
public final void init() throws ServletException {
@ -237,8 +229,7 @@ public class RestfulServer extends HttpServlet {
}
/**
* Sets the non-resource specific providers which implement method calls on
* this server.
* Sets the non-resource specific providers which implement method calls on this server.
*
* @see #setResourceProviders(Collection)
*/
@ -247,8 +238,7 @@ public class RestfulServer extends HttpServlet {
}
/**
* Sets the non-resource specific providers which implement method calls on
* this server.
* Sets the non-resource specific providers which implement method calls on this server.
*
* @see #setResourceProviders(Collection)
*/
@ -257,8 +247,7 @@ public class RestfulServer extends HttpServlet {
}
/**
* Sets the non-resource specific providers which implement method calls on
* this server
* Sets the non-resource specific providers which implement method calls on this server
*
* @see #setResourceProviders(Collection)
*/
@ -288,19 +277,16 @@ public class RestfulServer extends HttpServlet {
}
/**
* Returns the server conformance provider, which is the provider that is
* used to generate the server's conformance (metadata) statement.
* Returns the server conformance provider, which is the provider that is used to generate the server's conformance
* (metadata) statement.
* <p>
* By default, the {@link ServerConformanceProvider} is used, but this can
* be changed, or set to <code>null</code> if you do not wish to export a
* conformance statement.
* By default, the {@link ServerConformanceProvider} is used, but this can be changed, or set to <code>null</code>
* if you do not wish to export a conformance statement.
* </p>
* Note that this method can only be called before the server is
* initialized.
* Note that this method can only be called before the server is initialized.
*
* @throws IllegalStateException
* Note that this method can only be called prior to
* {@link #init() initialization} and will throw an
* Note that this method can only be called prior to {@link #init() initialization} and will throw an
* {@link IllegalStateException} if called after that.
*/
public void setServerConformanceProvider(Object theServerConformanceProvider) {
@ -311,9 +297,8 @@ public class RestfulServer extends HttpServlet {
}
/**
* Gets the server's name, as exported in conformance profiles exported by
* the server. This is informational only, but can be helpful to set with
* something appropriate.
* Gets the server's name, as exported in conformance profiles exported by the server. This is informational only,
* but can be helpful to set with something appropriate.
*
* @see RestfulServer#setServerName(StringDt)
*/
@ -322,18 +307,16 @@ public class RestfulServer extends HttpServlet {
}
/**
* Gets the server's version, as exported in conformance profiles exported
* by the server. This is informational only, but can be helpful to set with
* something appropriate.
* Gets the server's version, as exported in conformance profiles exported by the server. This is informational
* only, but can be helpful to set with something appropriate.
*/
public void setServerVersion(String theServerVersion) {
myServerVersion = theServerVersion;
}
/**
* If set to <code>true</code> (default is false), the server will use
* browser friendly content-types (instead of standard FHIR ones) when it
* detects that the request is coming from a browser instead of a FHIR
* If set to <code>true</code> (default is false), the server will use browser friendly content-types (instead of
* standard FHIR ones) when it detects that the request is coming from a browser instead of a FHIR
*/
public void setUseBrowserFriendlyContentTypes(boolean theUseBrowserFriendlyContentTypes) {
myUseBrowserFriendlyContentTypes = theUseBrowserFriendlyContentTypes;
@ -361,7 +344,7 @@ public class RestfulServer extends HttpServlet {
private void findResourceMethods(Object theProvider, Class<?> clazz) {
for (Method m : clazz.getDeclaredMethods()) {
if (!Modifier.isPublic(m.getModifiers())) {
ourLog.debug("Ignoring non-public method: {}",m);
ourLog.debug("Ignoring non-public method: {}", m);
} else {
if (!Modifier.isStatic(m.getModifiers())) {
ourLog.debug("Scanning public method: {}#{}", theProvider.getClass(), m.getName());
@ -521,13 +504,12 @@ public class RestfulServer extends HttpServlet {
Map<String, String[]> params = new HashMap<String, String[]>(theRequest.getParameterMap());
StringTokenizer tok = new StringTokenizer(requestPath, "/");
if (!tok.hasMoreTokens()) {
throw new ResourceNotFoundException("No resource name specified");
}
resourceName = tok.nextToken();
if (resourceName.startsWith("_")) {
operation = resourceName;
resourceName = null;
if (tok.hasMoreTokens()) {
resourceName = tok.nextToken();
if (resourceName.startsWith("_")) {
operation = resourceName;
resourceName = null;
}
}
ResourceBinding resourceBinding = null;
@ -570,16 +552,16 @@ public class RestfulServer extends HttpServlet {
}
// Secondary is for things like ..../_tags/_delete
String secondaryOperation=null;
String secondaryOperation = null;
while (tok.hasMoreTokens()) {
String nextString = tok.nextToken();
if (operation == null) {
operation = nextString;
}else if (secondaryOperation==null) {
secondaryOperation=nextString;
}else {
throw new InvalidRequestException("URL path has unexpected token '"+nextString + "' at the end: " + requestPath);
} else if (secondaryOperation == null) {
secondaryOperation = nextString;
} else {
throw new InvalidRequestException("URL path has unexpected token '" + nextString + "' at the end: " + requestPath);
}
}
@ -653,8 +635,8 @@ public class RestfulServer extends HttpServlet {
}
/**
* This method may be overridden by subclasses to do perform initialization
* that needs to be performed prior to the server being used.
* This method may be overridden by subclasses to do perform initialization that needs to be performed prior to the
* server being used.
*/
protected void initialize() {
// nothing by default

View File

@ -0,0 +1,113 @@
package ca.uhn.fhir.rest.server;
import static org.junit.Assert.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
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.dstu.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.annotation.Transaction;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.testutil.RandomServerPortProvider;
/**
* Created by dsotnikov on 2/25/2014.
*/
public class TransactionTest {
private static CloseableHttpClient ourClient;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TransactionTest.class);
private static int ourPort;
private static Server ourServer;
private static FhirContext ourCtx = new FhirContext();
@Test
public void testTransaction() throws Exception {
Bundle b= new Bundle();
Patient p1 = new Patient();
p1.getId().setValue("1");
b.addEntry().setResource(p1);
Patient p2 = new Patient();
p2.getId().setValue("2");
b.addEntry().setResource(p2);
BundleEntry deletedEntry = b.addEntry();
deletedEntry.setId(new IdDt("3"));
deletedEntry.setDeleted(new InstantDt());
String bundleString = ourCtx.newXmlParser().encodeBundleToString(b);
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/");
httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8")));
HttpResponse status = ourClient.execute(httpPost);
String responseContent = IOUtils.toString(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent);
assertEquals(3, bundle.size());
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = RandomServerPortProvider.findFreePort();
ourServer = new Server(ourPort);
DummyProvider patientProvider = new DummyProvider();
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer();
servlet.setProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
/**
* Created by dsotnikov on 2/25/2014.
*/
public static class DummyProvider {
@Transaction
public List<IResource> transaction(@TransactionParam List<IResource> theResources) {
return theResources;
}
}
}