diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java index 7e15ad5811d..180c260dc69 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java @@ -36,8 +36,10 @@ import ca.uhn.fhir.narrative.INarrativeGenerator; import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.JsonParser; import ca.uhn.fhir.parser.XmlParser; +import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.client.IRestfulClientFactory; import ca.uhn.fhir.rest.client.RestfulClientFactory; +import ca.uhn.fhir.rest.client.api.IBasicClient; import ca.uhn.fhir.rest.client.api.IRestfulClient; /** @@ -82,8 +84,7 @@ public class FhirContext { } /** - * Returns the scanned runtime model for the given type. This is an advanced feature - * which is generally only needed for extending the core library. + * Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed for extending the core library. */ public BaseRuntimeElementDefinition getElementDefinition(Class theElementType) { return myClassToElementDefinition.get(theElementType); @@ -94,8 +95,7 @@ public class FhirContext { } /** - * Returns the scanned runtime model for the given type. This is an advanced feature - * which is generally only needed for extending the core library. + * Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed for extending the core library. */ public RuntimeResourceDefinition getResourceDefinition(Class theResourceType) { RuntimeResourceDefinition retVal = (RuntimeResourceDefinition) myClassToElementDefinition.get(theResourceType); @@ -106,21 +106,19 @@ public class FhirContext { } /** - * Returns the scanned runtime model for the given type. This is an advanced feature - * which is generally only needed for extending the core library. + * Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed for extending the core library. */ public RuntimeResourceDefinition getResourceDefinition(IResource theResource) { return getResourceDefinition(theResource.getClass()); } /** - * Returns the scanned runtime model for the given type. This is an advanced feature - * which is generally only needed for extending the core library. + * Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed for extending the core library. */ @SuppressWarnings("unchecked") public RuntimeResourceDefinition getResourceDefinition(String theResourceName) { Validate.notBlank(theResourceName, "Resource name must not be blank"); - + RuntimeResourceDefinition retVal = myNameToElementDefinition.get(theResourceName); if (retVal == null) { @@ -139,16 +137,14 @@ public class FhirContext { } /** - * Returns the scanned runtime model for the given type. This is an advanced feature - * which is generally only needed for extending the core library. + * Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed for extending the core library. */ public RuntimeResourceDefinition getResourceDefinitionById(String theId) { return myIdToResourceDefinition.get(theId); } /** - * Returns the scanned runtime models. This is an advanced feature - * which is generally only needed for extending the core library. + * Returns the scanned runtime models. This is an advanced feature which is generally only needed for extending the core library. */ public Collection getResourceDefinitions() { return myIdToResourceDefinition.values(); @@ -166,11 +162,10 @@ public class FhirContext { } /** - * Create and return a new JSON parser. + * Create and return a new JSON parser. * *

- * Performance Note: This class is cheap to create, and may be called once for - * every message being processed without incurring any performance penalty + * Performance Note: This class is cheap to create, and may be called once for every message being processed without incurring any performance penalty *

*/ public IParser newJsonParser() { @@ -178,11 +173,12 @@ public class FhirContext { } /** - * Instantiates a new client instance. + * Instantiates a new client instance. This method requires an interface which is defined specifically for your use cases to contain methods for each of the RESTful operations you wish to + * implement (e.g. "read ImagingStudy", "search Patient by identifier", etc.). This interface must extend {@link IRestfulClient} (or commonly its sub-interface {@link IBasicClient}). See the RESTful Client documentation for more information on how to define this interface. * *

- * Performance Note: This class is cheap to create, and may be called once for - * every message being processed without incurring any performance penalty + * Performance Note: This class is cheap to create, and may be called once for every message being processed without incurring any performance penalty *

* * @param theClientType @@ -198,11 +194,25 @@ public class FhirContext { } /** - * Create and return a new JSON parser. + * Instantiates a new generic client. A generic client is able to perform any of the FHIR RESTful operations against a compliant server, but does not have methods defining the specific + * functionality required (as is the case with {@link #newRestfulClient(Class, String) non-generic clients}). + *

+ * In most cases it is preferable to use the non-generic clients instead of this mechanism, but not always. + *

+ * + * @param theServerBase + * The URL of the base for the restful FHIR server to connect to + * @return + */ + public IGenericClient newRestfulGenericClient(String theServerBase) { + return getRestfulClientFactory().newGenericClient(theServerBase); + } + + /** + * Create and return a new JSON parser. * *

- * Performance Note: This class is cheap to create, and may be called once for - * every message being processed without incurring any performance penalty + * Performance Note: This class is cheap to create, and may be called once for every message being processed without incurring any performance penalty *

*/ public IParser newXmlParser() { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/BaseResourceReference.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/BaseResourceReference.java index 5f2b7fc1c11..dcb81b5ea54 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/BaseResourceReference.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/BaseResourceReference.java @@ -32,7 +32,7 @@ import org.apache.http.client.methods.HttpGet; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.parser.IParser; -import ca.uhn.fhir.rest.client.ClientInvocationHandler; +import ca.uhn.fhir.rest.client.BaseClient; import ca.uhn.fhir.rest.client.api.IRestfulClient; public abstract class BaseResourceReference extends BaseElement { @@ -127,7 +127,7 @@ public abstract class BaseResourceReference extends BaseElement { // TODO: choose appropriate parser based on response CT IParser parser = context.newXmlParser(); - Reader responseReader = ClientInvocationHandler.createReaderFromResponse(response); + Reader responseReader = BaseClient.createReaderFromResponse(response); myResource = parser.parseResource(responseReader); } finally { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java new file mode 100644 index 00000000000..0f1faa0efa3 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java @@ -0,0 +1,171 @@ +package ca.uhn.fhir.rest.client; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.entity.ContentType; + +import ca.uhn.fhir.parser.DataFormatException; +import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException; +import ca.uhn.fhir.rest.method.IClientResponseHandler; +import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; + +public abstract class BaseClient { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseClient.class); + + private final HttpClient myClient; + private boolean myKeepResponses = false; + private HttpResponse myLastResponse; + private String myLastResponseBody; + private final String myUrlBase; + + BaseClient(HttpClient theClient, String theUrlBase) { + super(); + myClient = theClient; + myUrlBase = theUrlBase; + } + + /** + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! + */ + public HttpResponse getLastResponse() { + return myLastResponse; + } + + /** + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! + */ + public String getLastResponseBody() { + return myLastResponseBody; + } + + String getServerBase() { + return myUrlBase; + } + + Object invokeClient(IClientResponseHandler binding, BaseClientInvocation clientInvocation) { + // TODO: handle non 2xx status codes by throwing the correct exception, + // and ensure it's passed upwards + HttpRequestBase httpRequest; + HttpResponse response; + try { + httpRequest = clientInvocation.asHttpRequest(myUrlBase); + response = myClient.execute(httpRequest); + } catch (DataFormatException e) { + throw new FhirClientConnectionException(e); + } catch (IOException e) { + throw new FhirClientConnectionException(e); + } + + if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() > 299) { + throw BaseServerResponseException.newInstance(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase()); + } + + try { + + Reader reader = createReaderFromResponse(response); + + if (ourLog.isTraceEnabled() || myKeepResponses) { + String responseString = IOUtils.toString(reader); + if (myKeepResponses) { + myLastResponse = response; + myLastResponseBody = responseString; + } + ourLog.trace("FHIR response:\n{}\n{}", response, responseString); + reader = new StringReader(responseString); + } + + ContentType ct = ContentType.get(response.getEntity()); + String mimeType = ct.getMimeType(); + + Map> headers = new HashMap>(); + if (response.getAllHeaders() != null) { + for (Header next : response.getAllHeaders()) { + String name = next.getName().toLowerCase(); + List list = headers.get(name); + if (list == null) { + list = new ArrayList(); + headers.put(name, list); + } + list.add(next.getValue()); + } + } + + return binding.invokeClient(mimeType, reader, response.getStatusLine().getStatusCode(), headers); + + } catch (IllegalStateException e) { + throw new FhirClientConnectionException(e); + } catch (IOException e) { + throw new FhirClientConnectionException(e); + } finally { + if (response instanceof CloseableHttpResponse) { + try { + ((CloseableHttpResponse) response).close(); + } catch (IOException e) { + ourLog.debug("Failed to close response", e); + } + } + } + } + /** + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! + */ + public boolean isKeepResponses() { + return myKeepResponses; + } + + /** + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! + */ + public void setKeepResponses(boolean theKeepResponses) { + myKeepResponses = theKeepResponses; + } + + /** + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! + */ + public void setLastResponse(HttpResponse theLastResponse) { + myLastResponse = theLastResponse; + } + + /** + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! + */ + public void setLastResponseBody(String theLastResponseBody) { + myLastResponseBody = theLastResponseBody; + } + + public static Reader createReaderFromResponse(HttpResponse theResponse) throws IllegalStateException, IOException { + HttpEntity entity = theResponse.getEntity(); + if (entity == null) { + return new StringReader(""); + } + Charset charset = null; + if (entity.getContentType().getElements() != null) { + ContentType ct = ContentType.get(entity); + charset = ct.getCharset(); + } + if (charset == null) { + ourLog.warn("Response did not specify a charset."); + charset = Charset.forName("UTF-8"); + } + + Reader reader = new InputStreamReader(theResponse.getEntity().getContent(), charset); + return reader; + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/ClientInvocationHandler.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/ClientInvocationHandler.java index 578f9ef893e..b2a5a7f01de 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/ClientInvocationHandler.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/ClientInvocationHandler.java @@ -20,44 +20,26 @@ package ca.uhn.fhir.rest.client; * #L% */ -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; -import java.nio.charset.Charset; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; -import org.apache.commons.io.IOUtils; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.entity.ContentType; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.client.api.IRestfulClient; import ca.uhn.fhir.rest.method.BaseMethodBinding; -public class ClientInvocationHandler implements InvocationHandler { +public class ClientInvocationHandler extends BaseClient implements InvocationHandler { - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ClientInvocationHandler.class); private final Map myBindings = new HashMap(); - private final HttpClient myClient; - private final String myUrlBase; private final Map myMethodToReturnValue = new HashMap(); public ClientInvocationHandler(HttpClient theClient, FhirContext theContext, String theUrlBase, Class theClientType) { - myClient = theClient; - myUrlBase = theUrlBase; - + super(theClient, theUrlBase); + try { myMethodToReturnValue.put(theClientType.getMethod("getFhirContext"), theContext); myMethodToReturnValue.put(theClientType.getMethod("getHttpClient"), theClient); @@ -82,62 +64,10 @@ public class ClientInvocationHandler implements InvocationHandler { BaseMethodBinding binding = myBindings.get(theMethod); BaseClientInvocation clientInvocation = binding.invokeClient(theArgs); - - HttpRequestBase httpRequest = clientInvocation.asHttpRequest(myUrlBase); - HttpResponse response = myClient.execute(httpRequest); - try { - - Reader reader = createReaderFromResponse(response); - - if (ourLog.isTraceEnabled()) { - String responseString = IOUtils.toString(reader); - ourLog.trace("FHIR response:\n{}\n{}", response, responseString); - reader = new StringReader(responseString); - } - - ContentType ct = ContentType.get(response.getEntity()); - - String mimeType = ct.getMimeType(); - - Map> headers = new HashMap>(); - if (response.getAllHeaders() != null) { - for (Header next : response.getAllHeaders()) { - String name = next.getName().toLowerCase(); - List list = headers.get(name); - if (list == null) { - list = new ArrayList(); - headers.put(name, list); - } - list.add(next.getValue()); - } - } - - return binding.invokeClient(mimeType, reader, response.getStatusLine().getStatusCode(), headers); - - } finally { - if (response instanceof CloseableHttpResponse) { - ((CloseableHttpResponse) response).close(); - } - } + + return invokeClient(binding, clientInvocation); } - public static Reader createReaderFromResponse(HttpResponse theResponse) throws IllegalStateException, IOException { - HttpEntity entity = theResponse.getEntity(); - if (entity == null) { - return new StringReader(""); - } - Charset charset = null; - if (entity.getContentType().getElements() != null) { - ContentType ct = ContentType.get(entity); - charset = ct.getCharset(); - } - if (charset == null) { - ourLog.warn("Response did not specify a charset."); - charset = Charset.forName("UTF-8"); - } - Reader reader = new InputStreamReader(theResponse.getEntity().getContent(), charset); - return reader; - } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java new file mode 100644 index 00000000000..4ef499f992a --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java @@ -0,0 +1,92 @@ +package ca.uhn.fhir.rest.client; + +import java.io.IOException; +import java.io.Reader; +import java.util.List; +import java.util.Map; + +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpRequestBase; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.parser.IParser; +import ca.uhn.fhir.rest.method.IClientResponseHandler; +import ca.uhn.fhir.rest.method.ReadMethodBinding; +import ca.uhn.fhir.rest.server.EncodingUtil; +import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; + +public class GenericClient extends BaseClient implements IGenericClient { + + private FhirContext myContext; + private HttpRequestBase myLastRequest; + + /** + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! + */ + public GenericClient(FhirContext theContext, HttpClient theHttpClient, String theServerBase) { + super(theHttpClient, theServerBase); + myContext = theContext; + } + + public HttpRequestBase getLastRequest() { + return myLastRequest; + } + + @Override + public T read(final Class theType, IdDt theId) { + GetClientInvocation invocation = ReadMethodBinding.createReadInvocation(theId, toResourceName(theType)); + if (isKeepResponses()) { + myLastRequest = invocation.asHttpRequest(getServerBase()); + } + + IClientResponseHandler binding = new IClientResponseHandler() { + @Override + public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, + BaseServerResponseException { + EncodingUtil respType = EncodingUtil.forContentType(theResponseMimeType); + IParser parser = respType.newParser(myContext); + return parser.parseResource(theType, theResponseReader); + } + }; + + @SuppressWarnings("unchecked") + T resp = (T) invokeClient(binding, invocation); + return resp; + } + + /** + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! + */ + public void setLastRequest(HttpRequestBase theLastRequest) { + myLastRequest = theLastRequest; + } + + private String toResourceName(Class theType) { + return myContext.getResourceDefinition(theType).getName(); + } + + + @Override + public T vread(final Class theType, IdDt theId, IdDt theVersionId) { + GetClientInvocation invocation = ReadMethodBinding.createVReadInvocation(theId, theVersionId, toResourceName(theType)); + if (isKeepResponses()) { + myLastRequest = invocation.asHttpRequest(getServerBase()); + } + + IClientResponseHandler binding = new IClientResponseHandler() { + @Override + public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, + BaseServerResponseException { + EncodingUtil respType = EncodingUtil.forContentType(theResponseMimeType); + IParser parser = respType.newParser(myContext); + return parser.parseResource(theType, theResponseReader); + } + }; + + @SuppressWarnings("unchecked") + T resp = (T) invokeClient(binding, invocation); + return resp; + } +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java new file mode 100644 index 00000000000..2a401aae748 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java @@ -0,0 +1,27 @@ +package ca.uhn.fhir.rest.client; + +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.primitive.IdDt; + +public interface IGenericClient { + + /** + * Implementation of the "read" method. + * + * @param theType The type of resource to load + * @param theId The ID to load + * @return The resource + */ + T read(Class theType, IdDt theId); + + /** + * Implementation of the "vread" method. + * + * @param theType The type of resource to load + * @param theId The ID to load + * @param theVersionId The version ID + * @return The resource + */ + T vread(Class theType, IdDt theId, IdDt theVersionId); + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IRestfulClientFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IRestfulClientFactory.java index 6b43718d65c..80dfdc92716 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IRestfulClientFactory.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IRestfulClientFactory.java @@ -57,4 +57,13 @@ public interface IRestfulClientFactory { */ HttpClient getHttpClient(); + /** + * Instantiates a new generic client instance + * + * @param theServerBase + * The URL of the base for the restful FHIR server to connect to + * @return A newly created client + */ + IGenericClient newGenericClient(String theServerBase); + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java index 4e4d380e61a..a0ce83d7e63 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java @@ -54,7 +54,7 @@ public class RestfulClientFactory implements IRestfulClientFactory { @SuppressWarnings("unchecked") private T instantiateProxy(Class theClientType, InvocationHandler theInvocationHandler) { - T proxy = (T) Proxy.newProxyInstance(RestfulClientFactory.class.getClassLoader(), new Class[] { theClientType }, theInvocationHandler); + T proxy = (T) Proxy.newProxyInstance(theClientType.getClassLoader(), new Class[] { theClientType }, theInvocationHandler); return proxy; } @@ -120,4 +120,9 @@ public class RestfulClientFactory implements IRestfulClientFactory { myHttpClient = theHttpClient; } + @Override + public IGenericClient newGenericClient(String theServerBase) { + return new GenericClient(myContext, getHttpClient(), theServerBase); + } + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/exceptions/FhirClientConnectionException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/exceptions/FhirClientConnectionException.java new file mode 100644 index 00000000000..82640be603e --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/exceptions/FhirClientConnectionException.java @@ -0,0 +1,14 @@ +package ca.uhn.fhir.rest.client.exceptions; + +import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; + + +public class FhirClientConnectionException extends BaseServerResponseException { + + private static final long serialVersionUID = 1L; + + public FhirClientConnectionException(Throwable theE) { + super(0, theE); + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java index a94ae765775..1e8529f00d2 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java @@ -65,7 +65,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.util.ReflectionUtil; -public abstract class BaseMethodBinding { +public abstract class BaseMethodBinding implements IClientResponseHandler { private FhirContext myContext; private Method myMethod; @@ -106,8 +106,6 @@ public abstract class BaseMethodBinding { public abstract BaseClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException; - public abstract Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException; - public abstract void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException; public abstract boolean matches(Request theRequest); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IClientResponseHandler.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IClientResponseHandler.java new file mode 100644 index 00000000000..97cabb109ae --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IClientResponseHandler.java @@ -0,0 +1,14 @@ +package ca.uhn.fhir.rest.method; + +import java.io.IOException; +import java.io.Reader; +import java.util.List; +import java.util.Map; + +import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; + +public interface IClientResponseHandler { + + Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException; + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ReadMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ReadMethodBinding.java index 91a094a0364..1ba3848bdc5 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ReadMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ReadMethodBinding.java @@ -118,15 +118,25 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding { @Override public GetClientInvocation invokeClient(Object[] theArgs) { - String id = ((IdDt) theArgs[myIdIndex]).getValue(); + IdDt id = ((IdDt) theArgs[myIdIndex]); if (myVersionIdIndex == null) { - return new GetClientInvocation(getResourceName(), id); + String resourceName = getResourceName(); + return createReadInvocation(id, resourceName); } else { - String vid = ((IdDt) theArgs[myVersionIdIndex]).getValue(); - return new GetClientInvocation(getResourceName(), id, Constants.URL_TOKEN_HISTORY, vid); + IdDt vid = ((IdDt) theArgs[myVersionIdIndex]); + String resourceName = getResourceName(); + return createVReadInvocation(id, vid, resourceName); } } + public static GetClientInvocation createVReadInvocation(IdDt theId, IdDt vid, String resourceName) { + return new GetClientInvocation(resourceName, theId.getValue(), Constants.URL_TOKEN_HISTORY, vid.getValue()); + } + + public static GetClientInvocation createReadInvocation(IdDt theId, String resourceName) { + return new GetClientInvocation(resourceName, theId.getValue()); + } + @Override public RestfulOperationTypeEnum getResourceOperationType() { return isVread() ? RestfulOperationTypeEnum.VREAD : RestfulOperationTypeEnum.READ; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java index 70e52d86a58..c29c9af43f8 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Constants.java @@ -60,6 +60,8 @@ public class Constants { public static final String HEADER_LAST_MODIFIED = "Last-Modified"; public static final String HEADER_LAST_MODIFIED_LOWERCASE = HEADER_LAST_MODIFIED.toLowerCase(); public static final String PARAM_VALIDATE = "_validate"; + public static final int STATUS_HTTP_401_CLIENT_UNAUTHORIZED = 401; + public static final int STATUS_HTTP_500_INTERNAL_ERROR = 500; static { Map valToEncoding = new HashMap(); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/AuthenticationException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/AuthenticationException.java index 23d0e31434c..f1199a1388e 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/AuthenticationException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/AuthenticationException.java @@ -1,6 +1,6 @@ package ca.uhn.fhir.rest.server.exceptions; -import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.rest.server.Constants; /* * #%L @@ -29,14 +29,16 @@ import ca.uhn.fhir.model.dstu.resource.OperationOutcome; */ public class AuthenticationException extends BaseServerResponseException { - private static final long serialVersionUID = 1L; + public static final int STATUS_CODE = Constants.STATUS_HTTP_401_CLIENT_UNAUTHORIZED; + + private static final long serialVersionUID = 1L; public AuthenticationException() { - super(401, "Client unauthorized"); + super(STATUS_CODE, "Client unauthorized"); } public AuthenticationException(String theMessage) { - super(401, theMessage); + super(STATUS_CODE, theMessage); } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.java index 0bcc944347c..f1734e8ff31 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.java @@ -1,5 +1,9 @@ package ca.uhn.fhir.rest.server.exceptions; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + import ca.uhn.fhir.model.dstu.resource.OperationOutcome; /* @@ -24,11 +28,23 @@ import ca.uhn.fhir.model.dstu.resource.OperationOutcome; public abstract class BaseServerResponseException extends RuntimeException { + private static final Map> ourStatusCodeToExceptionType = new HashMap>(); private static final long serialVersionUID = 1L; - private int myStatusCode; + static { + registerExceptionType(AuthenticationException.STATUS_CODE, AuthenticationException.class); + registerExceptionType(InternalErrorException.STATUS_CODE, InternalErrorException.class); + registerExceptionType(InvalidRequestException.STATUS_CODE, InvalidRequestException.class); + registerExceptionType(MethodNotAllowedException.STATUS_CODE, MethodNotAllowedException.class); + registerExceptionType(ResourceNotFoundException.STATUS_CODE, ResourceNotFoundException.class); + registerExceptionType(ResourceVersionNotSpecifiedException.STATUS_CODE, ResourceVersionNotSpecifiedException.class); + registerExceptionType(UnprocessableEntityException.STATUS_CODE, UnprocessableEntityException.class); + } + private final OperationOutcome myOperationOutcome; + private int myStatusCode; + /** * Constructor * @@ -40,7 +56,7 @@ public abstract class BaseServerResponseException extends RuntimeException { public BaseServerResponseException(int theStatusCode, String theMessage) { super(theMessage); myStatusCode = theStatusCode; - myOperationOutcome=null; + myOperationOutcome = null; } /** @@ -54,9 +70,9 @@ public abstract class BaseServerResponseException extends RuntimeException { public BaseServerResponseException(int theStatusCode, String theMessage, OperationOutcome theOperationOutcome) { super(theMessage); myStatusCode = theStatusCode; - myOperationOutcome=theOperationOutcome; + myOperationOutcome = theOperationOutcome; } - + /** * Constructor * @@ -64,12 +80,13 @@ public abstract class BaseServerResponseException extends RuntimeException { * The HTTP status code corresponding to this problem * @param theMessage * The message - * @param theCause The cause + * @param theCause + * The cause */ public BaseServerResponseException(int theStatusCode, String theMessage, Throwable theCause) { super(theMessage, theCause); myStatusCode = theStatusCode; - myOperationOutcome=null; + myOperationOutcome = null; } /** @@ -83,7 +100,14 @@ public abstract class BaseServerResponseException extends RuntimeException { public BaseServerResponseException(int theStatusCode, Throwable theCause) { super(theCause.toString(), theCause); myStatusCode = theStatusCode; - myOperationOutcome=null; + myOperationOutcome = null; + } + + /** + * Returns the {@link OperationOutcome} resource if any which was supplied in the response, or null + */ + public OperationOutcome getOperationOutcome() { + return myOperationOutcome; } /** @@ -93,11 +117,31 @@ public abstract class BaseServerResponseException extends RuntimeException { return myStatusCode; } - /** - * Returns the {@link OperationOutcome} resource if any which was supplied in the response, - * or null - */ - public OperationOutcome getOperationOutcome() { - return myOperationOutcome; + public static BaseServerResponseException newInstance(int theStatusCode, String theMessage) { + if (ourStatusCodeToExceptionType.containsKey(theStatusCode)) { + try { + return ourStatusCodeToExceptionType.get(theStatusCode).getConstructor(new Class[] { String.class }).newInstance(theMessage); + } catch (InstantiationException e) { + throw new InternalErrorException(e); + } catch (IllegalAccessException e) { + throw new InternalErrorException(e); + } catch (IllegalArgumentException e) { + throw new InternalErrorException(e); + } catch (InvocationTargetException e) { + throw new InternalErrorException(e); + } catch (NoSuchMethodException e) { + throw new InternalErrorException(e); + } catch (SecurityException e) { + throw new InternalErrorException(e); + } + } else { + return new UnclassifiedServerFailureException(theStatusCode, theMessage); + } + } + + static void registerExceptionType(int theStatusCode, Class theType) { + if (ourStatusCodeToExceptionType.containsKey(theStatusCode)) { + throw new Error("Can not register " + theType + " to status code " + theStatusCode + " because " + ourStatusCodeToExceptionType.get(theStatusCode) + " already registers that code"); + } } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InternalErrorException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InternalErrorException.java index db3828ab567..cf016004c6a 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InternalErrorException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InternalErrorException.java @@ -1,5 +1,7 @@ package ca.uhn.fhir.rest.server.exceptions; +import ca.uhn.fhir.rest.server.Constants; + /* * #%L * HAPI FHIR Library @@ -25,18 +27,20 @@ package ca.uhn.fhir.rest.server.exceptions; */ public class InternalErrorException extends BaseServerResponseException { + public static final int STATUS_CODE = Constants.STATUS_HTTP_500_INTERNAL_ERROR; + private static final long serialVersionUID = 1L; public InternalErrorException(String theMessage) { - super(500, theMessage); + super(STATUS_CODE, theMessage); } public InternalErrorException(String theMessage, Throwable theCause) { - super(500, theMessage, theCause); + super(STATUS_CODE, theMessage, theCause); } public InternalErrorException(Throwable theCause) { - super(500, theCause); + super(STATUS_CODE, theCause); } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InvalidRequestException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InvalidRequestException.java index 92e7015a2bc..effe55ff457 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InvalidRequestException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/InvalidRequestException.java @@ -1,5 +1,7 @@ package ca.uhn.fhir.rest.server.exceptions; +import ca.uhn.fhir.rest.server.Constants; + /* * #%L * HAPI FHIR Library @@ -30,10 +32,11 @@ package ca.uhn.fhir.rest.server.exceptions; */ public class InvalidRequestException extends BaseServerResponseException { + public static final int STATUS_CODE = Constants.STATUS_HTTP_400_BAD_REQUEST; private static final long serialVersionUID = 1L; public InvalidRequestException(String theMessage) { - super(400, theMessage); + super(STATUS_CODE, theMessage); } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/MethodNotAllowedException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/MethodNotAllowedException.java index b9619a5efe2..df32db5de86 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/MethodNotAllowedException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/MethodNotAllowedException.java @@ -1,5 +1,7 @@ package ca.uhn.fhir.rest.server.exceptions; +import ca.uhn.fhir.rest.server.Constants; + /* * #%L * HAPI FHIR Library @@ -24,9 +26,10 @@ package ca.uhn.fhir.rest.server.exceptions; * TODO: javadoc this */ public class MethodNotAllowedException extends BaseServerResponseException { + public static final int STATUS_CODE = Constants.STATUS_HTTP_405_METHOD_NOT_ALLOWED; private static final long serialVersionUID = 1L; public MethodNotAllowedException(String error) { - super(405, error); + super(STATUS_CODE, error); } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceNotFoundException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceNotFoundException.java index 7ac76521731..94f9f61d63c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceNotFoundException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceNotFoundException.java @@ -23,6 +23,7 @@ package ca.uhn.fhir.rest.server.exceptions; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.dstu.composite.IdentifierDt; import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.server.Constants; /** * Represents an HTTP 404 Resource Not Found response, which means that @@ -30,16 +31,18 @@ import ca.uhn.fhir.model.primitive.IdDt; */ public class ResourceNotFoundException extends BaseServerResponseException { + public static final int STATUS_CODE = Constants.STATUS_HTTP_404_NOT_FOUND; + public ResourceNotFoundException(IdDt theId) { - super(404, "Resource " + (theId != null ? theId.getValue() : "") + " is not known"); + super(STATUS_CODE, "Resource " + (theId != null ? theId.getValue() : "") + " is not known"); } public ResourceNotFoundException(Class theClass, IdentifierDt thePatientId) { - super(404, "Resource of type " + theClass.getSimpleName() + " with ID " + thePatientId + " is not known"); + super(STATUS_CODE, "Resource of type " + theClass.getSimpleName() + " with ID " + thePatientId + " is not known"); } public ResourceNotFoundException(String theMessage) { - super(404, theMessage); + super(STATUS_CODE, theMessage); } private static final long serialVersionUID = 1L; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceVersionConflictException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceVersionConflictException.java index 77bcf2cba62..4aafd54484c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceVersionConflictException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceVersionConflictException.java @@ -30,9 +30,10 @@ import ca.uhn.fhir.rest.server.Constants; * when the operation fails because of a version conflict as specified in the FHIR specification. */ public class ResourceVersionConflictException extends BaseServerResponseException { + public static final int STATUS_CODE = Constants.STATUS_HTTP_409_CONFLICT; private static final long serialVersionUID = 1L; public ResourceVersionConflictException(String error) { - super(Constants.STATUS_HTTP_409_CONFLICT, error); + super(STATUS_CODE, error); } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceVersionNotSpecifiedException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceVersionNotSpecifiedException.java index d221e9149dd..3fa7b849b63 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceVersionNotSpecifiedException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceVersionNotSpecifiedException.java @@ -29,9 +29,10 @@ import ca.uhn.fhir.rest.server.Constants; * be specified in an HTTP header, and none was. */ public class ResourceVersionNotSpecifiedException extends BaseServerResponseException { + public static final int STATUS_CODE = Constants.STATUS_HTTP_412_PRECONDITION_FAILED; private static final long serialVersionUID = 1L; public ResourceVersionNotSpecifiedException(String error) { - super(Constants.STATUS_HTTP_412_PRECONDITION_FAILED, error); + super(STATUS_CODE, error); } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/UnprocessableEntityException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/UnprocessableEntityException.java index ee76f7169c7..bf70f8adce2 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/UnprocessableEntityException.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/UnprocessableEntityException.java @@ -21,6 +21,7 @@ package ca.uhn.fhir.rest.server.exceptions; */ import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.rest.server.Constants; /** * Represents an HTTP 422 Unprocessable Entity response, which means that a resource was rejected by the server because it "violated applicable FHIR profiles or server business rules". @@ -35,26 +36,27 @@ public class UnprocessableEntityException extends BaseServerResponseException { private static final String DEFAULT_MESSAGE = "Unprocessable Entity"; private static final long serialVersionUID = 1L; + public static final int STATUS_CODE = Constants.STATUS_HTTP_422_UNPROCESSABLE_ENTITY; /** * Constructor which accepts an {@link OperationOutcome} resource which will be supplied in the response */ public UnprocessableEntityException(OperationOutcome theOperationOutcome) { - super(422, DEFAULT_MESSAGE, theOperationOutcome == null ? new OperationOutcome() : theOperationOutcome); + super(STATUS_CODE, DEFAULT_MESSAGE, theOperationOutcome == null ? new OperationOutcome() : theOperationOutcome); } /** * Constructor which accepts a String describing the issue. This string will be translated into an {@link OperationOutcome} resource which will be supplied in the response. */ public UnprocessableEntityException(String theMessage) { - super(422, DEFAULT_MESSAGE, toOperationOutcome(theMessage)); + super(STATUS_CODE, DEFAULT_MESSAGE, toOperationOutcome(theMessage)); } /** * Constructor which accepts an array of Strings describing the issue. This strings will be translated into an {@link OperationOutcome} resource which will be supplied in the response. */ public UnprocessableEntityException(String... theMessage) { - super(422, DEFAULT_MESSAGE, toOperationOutcome(theMessage)); + super(STATUS_CODE, DEFAULT_MESSAGE, toOperationOutcome(theMessage)); } private static OperationOutcome toOperationOutcome(String... theMessage) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java index 8171588526d..c2ac752f905 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java @@ -11,6 +11,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.entity.ContentType; import org.thymeleaf.TemplateEngine; import org.thymeleaf.TemplateProcessingParameters; import org.thymeleaf.context.WebContext; @@ -19,14 +23,21 @@ import org.thymeleaf.standard.StandardDialect; import org.thymeleaf.templateresolver.TemplateResolver; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.annotation.Metadata; +import ca.uhn.fhir.rest.client.GenericClient; +import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.EncodingUtil; public class PublicTesterServlet extends HttpServlet { private static final long serialVersionUID = 1L; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PublicTesterServlet.class); + private static final boolean DEBUGMODE = true; private TemplateEngine myTemplateEngine; private HashMap myStaticResources; private String myServerBase; @@ -43,38 +54,137 @@ public class PublicTesterServlet extends HttpServlet { myStaticResources.put("PublicTester.css", "text/css"); myStaticResources.put("hapi_fhir_banner.png", "image/png"); myStaticResources.put("hapi_fhir_banner_right.png", "image/png"); - + myStaticResources.put("shCore.js","text/javascript"); + myStaticResources.put("shBrushJScript.js" ,"text/javascript"); + myStaticResources.put("shBrushXml.js" ,"text/javascript"); + myStaticResources.put("shBrushPlain.js" ,"text/javascript"); + myStaticResources.put("shCore.css", "text/css"); + myStaticResources.put("shThemeDefault.css", "text/css"); + + myCtx = new FhirContext(); } - + + @Override + protected void doPost(HttpServletRequest theReq, HttpServletResponse theResp) throws ServletException, IOException { + if (DEBUGMODE) { + myTemplateEngine.getCacheManager().clearAllCaches(); + } + + try { + GenericClient client = (GenericClient) myCtx.newRestfulGenericClient(myServerBase); + client.setKeepResponses(true); + String method = theReq.getParameter("method"); + + String requestUrl; + String action; + String resultStatus; + String resultBody; + String resultSyntaxHighlighterClass; + + if ("read".equals(method)) { + String resourceName = StringUtils.defaultString(theReq.getParameter("resourceName")); + RuntimeResourceDefinition def = myCtx.getResourceDefinition(resourceName); + if (def == null) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "Invalid resourceName: " + resourceName); + return; + } + String id = StringUtils.defaultString(theReq.getParameter("id")); + if (StringUtils.isBlank(id)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); + } + client.read(def.getImplementingClass(), new IdDt(id)); + + } if ("vread".equals(method)) { + String resourceName = StringUtils.defaultString(theReq.getParameter("resourceName")); + RuntimeResourceDefinition def = myCtx.getResourceDefinition(resourceName); + if (def == null) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "Invalid resourceName: " + resourceName); + return; + } + String id = StringUtils.defaultString(theReq.getParameter("id")); + if (StringUtils.isBlank(id)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); + } + + String versionId = StringUtils.defaultString(theReq.getParameter("versionid")); + if (StringUtils.isBlank(versionId)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No Version ID specified"); + } + client.vread(def.getImplementingClass(), new IdDt(id), new IdDt(versionId)); + + + } else { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "Invalid method: " + method); + return; + } + + HttpRequestBase lastRequest = client.getLastRequest(); + requestUrl = lastRequest.getURI().toASCIIString(); + action = client.getLastRequest().getMethod(); + resultStatus = client.getLastResponse().getStatusLine().toString(); + resultBody = client.getLastResponseBody(); + + ContentType ct = ContentType.get(client.getLastResponse().getEntity()); + String mimeType = ct.getMimeType(); + EncodingUtil ctEnum = EncodingUtil.forContentType(mimeType); + switch (ctEnum) { + case JSON: + resultSyntaxHighlighterClass="brush: jscript"; + break; + case XML: + resultSyntaxHighlighterClass="brush: xml"; + break; + default: + resultSyntaxHighlighterClass="brush: plain"; + break; + } + + WebContext ctx = new WebContext(theReq, theResp, theReq.getServletContext(), theReq.getLocale()); + ctx.setVariable("base", myServerBase); + ctx.setVariable("requestUrl", requestUrl); + ctx.setVariable("action", action); + ctx.setVariable("resultStatus", resultStatus); + ctx.setVariable("resultBody", StringEscapeUtils.escapeHtml(resultBody)); + ctx.setVariable("resultSyntaxHighlighterClass", resultSyntaxHighlighterClass); + + myTemplateEngine.process(PUBLIC_TESTER_RESULT_HTML, ctx, theResp.getWriter()); + } catch (Exception e) { + ourLog.error("Failure during processing", e); + theResp.sendError(500, e.toString()); + } + } + @Override protected void doGet(HttpServletRequest theReq, HttpServletResponse theResp) throws ServletException, IOException { + if (DEBUGMODE) { myTemplateEngine.getCacheManager().clearAllCaches(); - - ourLog.info("RequestURI: {}", theReq.getPathInfo()); + } + ourLog.info("RequestURI: {}", theReq.getPathInfo()); + String resName = theReq.getPathInfo().substring(1); if (myStaticResources.containsKey(resName)) { streamResponse(resName, myStaticResources.get(resName), theResp); return; } - + ConformanceClient client = myCtx.newRestfulClient(ConformanceClient.class, myServerBase); Conformance conformance = client.getConformance(); - + WebContext ctx = new WebContext(theReq, theResp, theReq.getServletContext(), theReq.getLocale()); ctx.setVariable("conf", conformance); ctx.setVariable("base", myServerBase); - myTemplateEngine.process(theReq.getPathInfo(), ctx, theResp.getWriter()); - + ctx.setVariable("jsonEncodedConf", myCtx.newJsonParser().encodeResourceToString(conformance)); + myTemplateEngine.process(theReq.getPathInfo(), ctx, theResp.getWriter()); + } - private interface ConformanceClient extends IBasicClient - { + private interface ConformanceClient extends IBasicClient { @Metadata Conformance getConformance(); } - + @Override public void init(ServletConfig theConfig) throws ServletException { myTemplateEngine = new TemplateEngine(); @@ -86,7 +196,10 @@ public class PublicTesterServlet extends HttpServlet { myTemplateEngine.initialize(); } + private static final String PUBLIC_TESTER_RESULT_HTML = "/PublicTesterResult.html"; + private final class ProfileResourceResolver implements IResourceResolver { + @Override public String getName() { return getClass().getCanonicalName(); @@ -94,12 +207,15 @@ public class PublicTesterServlet extends HttpServlet { @Override public InputStream getResourceAsStream(TemplateProcessingParameters theTemplateProcessingParameters, String theName) { - ourLog.info("Loading template: {}", theName); + ourLog.debug("Loading template: {}", theName); if ("/".equals(theName)) { return PublicTesterServlet.class.getResourceAsStream("/ca/uhn/fhir/rest/server/tester/PublicTester.html"); } + if (PUBLIC_TESTER_RESULT_HTML.equals(theName)) { + return PublicTesterServlet.class.getResourceAsStream("/ca/uhn/fhir/rest/server/tester/PublicTesterResult.html"); + } - return null; + return null; } } diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.css b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.css index 9975a3f458b..3e731644f8f 100644 --- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.css +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.css @@ -19,4 +19,8 @@ TD.testerNameCell { background-color: #E0FFE0; border-radius: 3px; padding: 3px; -} \ No newline at end of file +} + +.syntaxhighlighter { + font-size: 0.85em !important; +} diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.html b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.html index 3f4032a83a3..6d8566d2be7 100644 --- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.html +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.html @@ -10,7 +10,8 @@ This file is a Thymeleaf template for the @@ -62,7 +63,8 @@ This file is a Thymeleaf template for the - read + read + vread diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.js b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.js index 73de56f0fd9..8d1dc2d15f7 100644 --- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.js +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.js @@ -1,20 +1,60 @@ var currentForm; +/** Hide any currently displayed tester form */ +function clearCurrentForm(postCompleteFunction) { + if (currentForm != null) { + var holder = currentForm; + holder.children().fadeOut(500).promise().then(function() { + holder.empty(); + holder.hide(); + postCompleteFunction(); + }); + currentForm = null; + } else { + postCompleteFunction(); + } +} + /** Create a tester form for the 'read' method */ -function displayRead(expandoTr) { - - $('#' + expandoTr).show(); - currentForm = $('#' + expandoTr).append( - $('Read'), - $('').append( - $('
', { action: '', method: 'POST' }).append( - $('', { name: 'method', value: 'read', type: 'hidden' }), - $('', { name: 'id', placeholder: 'Resource ID', type: 'text' }), - $('
'), - $('', { type: 'submit', value: 'Submit' }) - ) - ) - ); - +function displayRead(expandoTr, resourceName) { + var postCompleteFunction = function() { + //$('#' + expandoTr).show(); + currentForm = $('#' + expandoTr).append( + $('Read'), + $('').append( + $('', { id: 'testerform', action: 'PublicTesterResult.html', method: 'POST' }).append( + $('', { name: 'method', value: 'read', type: 'hidden' }), + $('', { name: 'resourceName', value: resourceName, type: 'hidden' }), + $('', { name: 'id', placeholder: 'Resource ID', type: 'text' }), + $('
'), + $('', { type: 'submit', value: 'Submit' }) + ) + ) + ); + $('#' + expandoTr).fadeIn(500); + } + clearCurrentForm(postCompleteFunction); +} + +/** Create a tester form for the 'read' method */ +function displayVRead(expandoTr, resourceName) { + var postCompleteFunction = function() { + //$('#' + expandoTr).show(); + currentForm = $('#' + expandoTr).append( + $('VRead'), + $('').append( + $('', { id: 'testerform', action: 'PublicTesterResult.html', method: 'POST' }).append( + $('', { name: 'method', value: 'vread', type: 'hidden' }), + $('', { name: 'resourceName', value: resourceName, type: 'hidden' }), + $('', { name: 'id', placeholder: 'Resource ID', type: 'text' }), + $('', { name: 'versionid', placeholder: 'Version ID', type: 'text' }), + $('
'), + $('', { type: 'submit', value: 'Submit' }) + ) + ) + ); + $('#' + expandoTr).fadeIn(500); + } + clearCurrentForm(postCompleteFunction); } \ No newline at end of file diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTesterResult.html b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTesterResult.html new file mode 100644 index 00000000000..d2e5b62156b --- /dev/null +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTesterResult.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + +
+
+ Executed invocation:
+ GET + http://foo.com/fhir +
+ + + + + + + +
+ +
+ Actions +
+ + + + + +
SomethingSomething
+ +
+ + + +
+ Response +
+ + + + + + + + + +
StatusHTTP 200 OK
Result
{}
+
+ +
+ +
+ + + + + diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushJScript.js b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushJScript.js new file mode 100644 index 00000000000..ff98daba16e --- /dev/null +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushJScript.js @@ -0,0 +1,52 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +;(function() +{ + // CommonJS + typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; + + function Brush() + { + var keywords = 'break case catch continue ' + + 'default delete do else false ' + + 'for function if in instanceof ' + + 'new null return super switch ' + + 'this throw true try typeof var while with' + ; + + var r = SyntaxHighlighter.regexLib; + + this.regexList = [ + { regex: r.multiLineDoubleQuotedString, css: 'string' }, // double quoted strings + { regex: r.multiLineSingleQuotedString, css: 'string' }, // single quoted strings + { regex: r.singleLineCComments, css: 'comments' }, // one line comments + { regex: r.multiLineCComments, css: 'comments' }, // multiline comments + { regex: /\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion + { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keywords + ]; + + this.forHtmlScript(r.scriptScriptTags); + }; + + Brush.prototype = new SyntaxHighlighter.Highlighter(); + Brush.aliases = ['js', 'jscript', 'javascript']; + + SyntaxHighlighter.brushes.JScript = Brush; + + // CommonJS + typeof(exports) != 'undefined' ? exports.Brush = Brush : null; +})(); diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushPlain.js b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushPlain.js new file mode 100644 index 00000000000..9f7d9e90c32 --- /dev/null +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushPlain.js @@ -0,0 +1,33 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +;(function() +{ + // CommonJS + typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; + + function Brush() + { + }; + + Brush.prototype = new SyntaxHighlighter.Highlighter(); + Brush.aliases = ['text', 'plain']; + + SyntaxHighlighter.brushes.Plain = Brush; + + // CommonJS + typeof(exports) != 'undefined' ? exports.Brush = Brush : null; +})(); diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushXml.js b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushXml.js new file mode 100644 index 00000000000..69d9fd0b1f4 --- /dev/null +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushXml.js @@ -0,0 +1,69 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +;(function() +{ + // CommonJS + typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; + + function Brush() + { + function process(match, regexInfo) + { + var constructor = SyntaxHighlighter.Match, + code = match[0], + tag = new XRegExp('(<|<)[\\s\\/\\?]*(?[:\\w-\\.]+)', 'xg').exec(code), + result = [] + ; + + if (match.attributes != null) + { + var attributes, + regex = new XRegExp('(? [\\w:\\-\\.]+)' + + '\\s*=\\s*' + + '(? ".*?"|\'.*?\'|\\w+)', + 'xg'); + + while ((attributes = regex.exec(code)) != null) + { + result.push(new constructor(attributes.name, match.index + attributes.index, 'color1')); + result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string')); + } + } + + if (tag != null) + result.push( + new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword') + ); + + return result; + } + + this.regexList = [ + { regex: new XRegExp('(\\<|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\>|>)', 'gm'), css: 'color2' }, // + { regex: SyntaxHighlighter.regexLib.xmlComments, css: 'comments' }, // + { regex: new XRegExp('(<|<)[\\s\\/\\?]*(\\w+)(?.*?)[\\s\\/\\?]*(>|>)', 'sg'), func: process } + ]; + }; + + Brush.prototype = new SyntaxHighlighter.Highlighter(); + Brush.aliases = ['xml', 'xhtml', 'xslt', 'html']; + + SyntaxHighlighter.brushes.Xml = Brush; + + // CommonJS + typeof(exports) != 'undefined' ? exports.Brush = Brush : null; +})(); diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shCore.css b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shCore.css new file mode 100644 index 00000000000..34f6864a155 --- /dev/null +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shCore.css @@ -0,0 +1,226 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + -moz-border-radius: 0 0 0 0 !important; + -webkit-border-radius: 0 0 0 0 !important; + background: none !important; + border: 0 !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} + +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .bold { + font-weight: bold !important; +} +.syntaxhighlighter .italic { + font-style: italic !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 0 0.5em 0 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 0 1em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { + padding-left: 0em !important; +} +.syntaxhighlighter.show { + display: block !important; +} +.syntaxhighlighter.collapsed table { + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar { + padding: 0.1em 0.8em 0em 0.8em !important; + font-size: 1em !important; + position: static !important; + width: auto !important; + height: auto !important; +} +.syntaxhighlighter.collapsed .toolbar span { + display: inline !important; + margin-right: 1em !important; +} +.syntaxhighlighter.collapsed .toolbar span a { + padding: 0 !important; + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar span a.expandSource { + display: inline !important; +} +.syntaxhighlighter .toolbar { + position: absolute !important; + right: 1px !important; + top: 1px !important; + width: 11px !important; + height: 11px !important; + font-size: 10px !important; + z-index: 10 !important; +} +.syntaxhighlighter .toolbar span.title { + display: inline !important; +} +.syntaxhighlighter .toolbar a { + display: block !important; + text-align: center !important; + text-decoration: none !important; + padding-top: 1px !important; +} +.syntaxhighlighter .toolbar a.expandSource { + display: none !important; +} +.syntaxhighlighter.ie { + font-size: .9em !important; + padding: 1px 0 1px 0 !important; +} +.syntaxhighlighter.ie .toolbar { + line-height: 8px !important; +} +.syntaxhighlighter.ie .toolbar a { + padding-top: 0px !important; +} +.syntaxhighlighter.printing .line.alt1 .content, +.syntaxhighlighter.printing .line.alt2 .content, +.syntaxhighlighter.printing .line.highlighted .number, +.syntaxhighlighter.printing .line.highlighted.alt1 .content, +.syntaxhighlighter.printing .line.highlighted.alt2 .content { + background: none !important; +} +.syntaxhighlighter.printing .line .number { + color: #bbbbbb !important; +} +.syntaxhighlighter.printing .line .content { + color: black !important; +} +.syntaxhighlighter.printing .toolbar { + display: none !important; +} +.syntaxhighlighter.printing a { + text-decoration: none !important; +} +.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { + color: black !important; +} +.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { + color: #008200 !important; +} +.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { + color: blue !important; +} +.syntaxhighlighter.printing .keyword { + color: #006699 !important; + font-weight: bold !important; +} +.syntaxhighlighter.printing .preprocessor { + color: gray !important; +} +.syntaxhighlighter.printing .variable { + color: #aa7700 !important; +} +.syntaxhighlighter.printing .value { + color: #009900 !important; +} +.syntaxhighlighter.printing .functions { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .constants { + color: #0066cc !important; +} +.syntaxhighlighter.printing .script { + font-weight: bold !important; +} +.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { + color: gray !important; +} +.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { + color: red !important; +} +.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { + color: black !important; +} diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shCore.js b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shCore.js new file mode 100644 index 00000000000..b47b6454721 --- /dev/null +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shCore.js @@ -0,0 +1,17 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('K M;I(M)1S 2U("2a\'t 4k M 4K 2g 3l 4G 4H");(6(){6 r(f,e){I(!M.1R(f))1S 3m("3s 15 4R");K a=f.1w;f=M(f.1m,t(f)+(e||""));I(a)f.1w={1m:a.1m,19:a.19?a.19.1a(0):N};H f}6 t(f){H(f.1J?"g":"")+(f.4s?"i":"")+(f.4p?"m":"")+(f.4v?"x":"")+(f.3n?"y":"")}6 B(f,e,a,b){K c=u.L,d,h,g;v=R;5K{O(;c--;){g=u[c];I(a&g.3r&&(!g.2p||g.2p.W(b))){g.2q.12=e;I((h=g.2q.X(f))&&h.P===e){d={3k:g.2b.W(b,h,a),1C:h};1N}}}}5v(i){1S i}5q{v=11}H d}6 p(f,e,a){I(3b.Z.1i)H f.1i(e,a);O(a=a||0;a-1},3d:6(g){e+=g}};c1&&p(e,"")>-1){a=15(J.1m,n.Q.W(t(J),"g",""));n.Q.W(f.1a(e.P),a,6(){O(K c=1;c<14.L-2;c++)I(14[c]===1d)e[c]=1d})}I(J.1w&&J.1w.19)O(K b=1;be.P&&J.12--}H e};I(!D)15.Z.1A=6(f){(f=n.X.W(J,f))&&J.1J&&!f[0].L&&J.12>f.P&&J.12--;H!!f};1r.Z.1C=6(f){M.1R(f)||(f=15(f));I(f.1J){K e=n.1C.1p(J,14);f.12=0;H e}H f.X(J)};1r.Z.Q=6(f,e){K a=M.1R(f),b,c;I(a&&1j e.58()==="3f"&&e.1i("${")===-1&&y)H n.Q.1p(J,14);I(a){I(f.1w)b=f.1w.19}Y f+="";I(1j e==="6")c=n.Q.W(J,f,6(){I(b){14[0]=1f 1r(14[0]);O(K d=0;dd.L-3;){i=1r.Z.1a.W(g,-1)+i;g=1Q.3i(g/10)}H(g?d[g]||"":"$")+i}Y{g=+i;I(g<=d.L-3)H d[g];g=b?p(b,i):-1;H g>-1?d[g+1]:h}})})}I(a&&f.1J)f.12=0;H c};1r.Z.1e=6(f,e){I(!M.1R(f))H n.1e.1p(J,14);K a=J+"",b=[],c=0,d,h;I(e===1d||+e<0)e=5D;Y{e=1Q.3i(+e);I(!e)H[]}O(f=M.3c(f);d=f.X(a);){I(f.12>c){b.U(a.1a(c,d.P));d.L>1&&d.P=e)1N}f.12===d.P&&f.12++}I(c===a.L){I(!n.1A.W(f,"")||h)b.U("")}Y b.U(a.1a(c));H b.L>e?b.1a(0,e):b};M.1h(/\\(\\?#[^)]*\\)/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"});M.1h(/\\((?!\\?)/,6(){J.19.U(N);H"("});M.1h(/\\(\\?<([$\\w]+)>/,6(f){J.19.U(f[1]);J.2N=R;H"("});M.1h(/\\\\k<([\\w$]+)>/,6(f){K e=p(J.19,f[1]);H e>-1?"\\\\"+(e+1)+(3R(f.2S.3a(f.P+f[0].L))?"":"(?:)"):f[0]});M.1h(/\\[\\^?]/,6(f){H f[0]==="[]"?"\\\\b\\\\B":"[\\\\s\\\\S]"});M.1h(/^\\(\\?([5A]+)\\)/,6(f){J.3d(f[1]);H""});M.1h(/(?:\\s+|#.*)+/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"},M.1B,6(){H J.2K("x")});M.1h(/\\./,6(){H"[\\\\s\\\\S]"},M.1B,6(){H J.2K("s")})})();1j 2e!="1d"&&(2e.M=M);K 1v=6(){6 r(a,b){a.1l.1i(b)!=-1||(a.1l+=" "+b)}6 t(a){H a.1i("3e")==0?a:"3e"+a}6 B(a){H e.1Y.2A[t(a)]}6 p(a,b,c){I(a==N)H N;K d=c!=R?a.3G:[a.2G],h={"#":"1c",".":"1l"}[b.1o(0,1)]||"3h",g,i;g=h!="3h"?b.1o(1):b.5u();I((a[h]||"").1i(g)!=-1)H a;O(a=0;d&&a\'+c+""});H a}6 n(a,b){a.1e("\\n");O(K c="",d=0;d<50;d++)c+=" ";H a=v(a,6(h){I(h.1i("\\t")==-1)H h;O(K g=0;(g=h.1i("\\t"))!=-1;)h=h.1o(0,g)+c.1o(0,b-g%b)+h.1o(g+1,h.L);H h})}6 x(a){H a.Q(/^\\s+|\\s+$/g,"")}6 D(a,b){I(a.Pb.P)H 1;Y I(a.Lb.L)H 1;H 0}6 y(a,b){6 c(k){H k[0]}O(K d=N,h=[],g=b.2D?b.2D:c;(d=b.1I.X(a))!=N;){K i=g(d,b);I(1j i=="3f")i=[1f e.2L(i,d.P,b.23)];h=h.1O(i)}H h}6 E(a){K b=/(.*)((&1G;|&1y;).*)/;H a.Q(e.3A.3M,6(c){K d="",h=N;I(h=b.X(c)){c=h[1];d=h[2]}H\'\'+c+""+d})}6 z(){O(K a=1E.36("1k"),b=[],c=0;c<1z 4I="1Z://2y.3L.3K/4L/5L"><3J><4N 1Z-4M="5G-5M" 6K="2O/1z; 6J=6I-8" /><1t>6L 1v<3B 1L="25-6M:6Q,6P,6O,6N-6F;6y-2f:#6x;2f:#6w;25-22:6v;2O-3D:3C;">1v3v 3.0.76 (72 73 3x)1Z://3u.2w/1v70 17 6U 71.6T 6X-3x 6Y 6D.6t 61 60 J 1k, 5Z 5R 5V <2R/>5U 5T 5S!\'}},1Y:{2j:N,2A:{}},1U:{},3A:{6n:/\\/\\*[\\s\\S]*?\\*\\//2c,6m:/\\/\\/.*$/2c,6l:/#.*$/2c,6k:/"([^\\\\"\\n]|\\\\.)*"/g,6o:/\'([^\\\\\'\\n]|\\\\.)*\'/g,6p:1f M(\'"([^\\\\\\\\"]|\\\\\\\\.)*"\',"3z"),6s:1f M("\'([^\\\\\\\\\']|\\\\\\\\.)*\'","3z"),6q:/(&1y;|<)!--[\\s\\S]*?--(&1G;|>)/2c,3M:/\\w+:\\/\\/[\\w-.\\/?%&=:@;]*/g,6a:{18:/(&1y;|<)\\?=?/g,1b:/\\?(&1G;|>)/g},69:{18:/(&1y;|<)%=?/g,1b:/%(&1G;|>)/g},6d:{18:/(&1y;|<)\\s*1k.*?(&1G;|>)/2T,1b:/(&1y;|<)\\/\\s*1k\\s*(&1G;|>)/2T}},16:{1H:6(a){6 b(i,k){H e.16.2o(i,k,e.13.1x[k])}O(K c=\'\',d=e.16.2x,h=d.2X,g=0;g";H c},2o:6(a,b,c){H\'<2W>\'+c+""},2b:6(a){K b=a.1F,c=b.1l||"";b=B(p(b,".20",R).1c);K d=6(h){H(h=15(h+"6f(\\\\w+)").X(c))?h[1]:N}("6g");b&&d&&e.16.2x[d].2B(b);a.3N()},2x:{2X:["21","2P"],21:{1H:6(a){I(a.V("2l")!=R)H"";K b=a.V("1t");H e.16.2o(a,"21",b?b:e.13.1x.21)},2B:6(a){a=1E.6j(t(a.1c));a.1l=a.1l.Q("47","")}},2P:{2B:6(){K a="68=0";a+=", 18="+(31.30-33)/2+", 32="+(31.2Z-2Y)/2+", 30=33, 2Z=2Y";a=a.Q(/^,/,"");a=1P.6Z("","38",a);a.2C();K b=a.1E;b.6W(e.13.1x.37);b.6V();a.2C()}}}},35:6(a,b){K c;I(b)c=[b];Y{c=1E.36(e.13.34);O(K d=[],h=0;h(.*?))\\\\]$"),s=1f M("(?<27>[\\\\w-]+)\\\\s*:\\\\s*(?<1T>[\\\\w-%#]+|\\\\[.*?\\\\]|\\".*?\\"|\'.*?\')\\\\s*;?","g");(j=s.X(k))!=N;){K o=j.1T.Q(/^[\'"]|[\'"]$/g,"");I(o!=N&&m.1A(o)){o=m.X(o);o=o.2V.L>0?o.2V.1e(/\\s*,\\s*/):[]}l[j.27]=o}g={1F:g,1n:C(i,l)};g.1n.1D!=N&&d.U(g)}H d},1M:6(a,b){K c=J.35(a,b),d=N,h=e.13;I(c.L!==0)O(K g=0;g")==o-3){m=m.4h(0,o-3);s=R}l=s?m:l}I((i.1t||"")!="")k.1t=i.1t;k.1D=j;d.2Q(k);b=d.2F(l);I((i.1c||"")!="")b.1c=i.1c;i.2G.74(b,i)}}},2E:6(a){w(1P,"4k",6(){e.1M(a)})}};e.2E=e.2E;e.1M=e.1M;e.2L=6(a,b,c){J.1T=a;J.P=b;J.L=a.L;J.23=c;J.1V=N};e.2L.Z.1q=6(){H J.1T};e.4l=6(a){6 b(j,l){O(K m=0;md)1N;Y I(g.P==c.P&&g.L>c.L)a[b]=N;Y I(g.P>=c.P&&g.P\'+c+""},3Q:6(a,b){K c="",d=a.1e("\\n").L,h=2u(J.V("2i-1s")),g=J.V("2z-1s-2t");I(g==R)g=(h+d-1).1q().L;Y I(3R(g)==R)g=0;O(K i=0;i\'+j+"":"")+i)}H a},4f:6(a){H a?"<4a>"+a+"":""},4b:6(a,b){6 c(l){H(l=l?l.1V||g:g)?l+" ":""}O(K d=0,h="",g=J.V("1D",""),i=0;i|&1y;2R\\s*\\/?&1G;/2T;I(e.13.46==R)b=b.Q(h,"\\n");I(e.13.44==R)b=b.Q(h,"");b=b.1e("\\n");h=/^\\s*/;g=4Q;O(K i=0;i0;i++){K k=b[i];I(x(k).L!=0){k=h.X(k);I(k==N){a=a;1N a}g=1Q.4q(k[0].L,g)}}I(g>0)O(i=0;i\'+(J.V("16")?e.16.1H(J):"")+\'<3Z 5z="0" 5H="0" 5J="0">\'+J.4f(J.V("1t"))+"<3T><3P>"+(1u?\'<2d 1g="1u">\'+J.3Q(a)+"":"")+\'<2d 1g="17">\'+b+""},2F:6(a){I(a===N)a="";J.17=a;K b=J.3Y("T");b.3X=J.1H(a);J.V("16")&&w(p(b,".16"),"5c",e.16.2b);J.V("3V-17")&&w(p(b,".17"),"56",f);H b},2Q:6(a){J.1c=""+1Q.5d(1Q.5n()*5k).1q();e.1Y.2A[t(J.1c)]=J;J.1n=C(e.2v,a||{});I(J.V("2k")==R)J.1n.16=J.1n.1u=11},5j:6(a){a=a.Q(/^\\s+|\\s+$/g,"").Q(/\\s+/g,"|");H"\\\\b(?:"+a+")\\\\b"},5f:6(a){J.28={18:{1I:a.18,23:"1k"},1b:{1I:a.1b,23:"1k"},17:1f M("(?<18>"+a.18.1m+")(?<17>.*?)(?<1b>"+a.1b.1m+")","5o")}}};H e}();1j 2e!="1d"&&(2e.1v=1v);',62,441,'||||||function|||||||||||||||||||||||||||||||||||||return|if|this|var|length|XRegExp|null|for|index|replace|true||div|push|getParam|call|exec|else|prototype||false|lastIndex|config|arguments|RegExp|toolbar|code|left|captureNames|slice|right|id|undefined|split|new|class|addToken|indexOf|typeof|script|className|source|params|substr|apply|toString|String|line|title|gutter|SyntaxHighlighter|_xregexp|strings|lt|html|test|OUTSIDE_CLASS|match|brush|document|target|gt|getHtml|regex|global|join|style|highlight|break|concat|window|Math|isRegExp|throw|value|brushes|brushName|space|alert|vars|http|syntaxhighlighter|expandSource|size|css|case|font|Fa|name|htmlScript|dA|can|handler|gm|td|exports|color|in|href|first|discoveredBrushes|light|collapse|object|cache|getButtonHtml|trigger|pattern|getLineHtml|nbsp|numbers|parseInt|defaults|com|items|www|pad|highlighters|execute|focus|func|all|getDiv|parentNode|navigator|INSIDE_CLASS|regexList|hasFlag|Match|useScriptTags|hasNamedCapture|text|help|init|br|input|gi|Error|values|span|list|250|height|width|screen|top|500|tagName|findElements|getElementsByTagName|aboutDialog|_blank|appendChild|charAt|Array|copyAsGlobal|setFlag|highlighter_|string|attachEvent|nodeName|floor|backref|output|the|TypeError|sticky|Za|iterate|freezeTokens|scope|type|textarea|alexgorbatchev|version|margin|2010|005896|gs|regexLib|body|center|align|noBrush|require|childNodes|DTD|xhtml1|head|org|w3|url|preventDefault|container|tr|getLineNumbersHtml|isNaN|userAgent|tbody|isLineHighlighted|quick|void|innerHTML|create|table|links|auto|smart|tab|stripBrs|tabs|bloggerMode|collapsed|plain|getCodeLinesHtml|caption|getMatchesHtml|findMatches|figureOutLineNumbers|removeNestedMatches|getTitleHtml|brushNotHtmlScript|substring|createElement|Highlighter|load|HtmlScript|Brush|pre|expand|multiline|min|Can|ignoreCase|find|blur|extended|toLowerCase|aliases|addEventListener|innerText|textContent|wasn|select|createTextNode|removeChild|option|same|frame|xmlns|dtd|twice|1999|equiv|meta|htmlscript|transitional|1E3|expected|PUBLIC|DOCTYPE|on|W3C|XHTML|TR|EN|Transitional||configured|srcElement|Object|after|run|dblclick|matchChain|valueOf|constructor|default|switch|click|round|execAt|forHtmlScript|token|gimy|functions|getKeywords|1E6|escape|within|random|sgi|another|finally|supply|MSIE|ie|toUpperCase|catch|returnValue|definition|event|border|imsx|constructing|one|Infinity|from|when|Content|cellpadding|flags|cellspacing|try|xhtml|Type|spaces|2930402|hosted_button_id|lastIndexOf|donate|active|development|keep|to|xclick|_s|Xml|please|like|you|paypal|cgi|cmd|webscr|bin|highlighted|scrollbars|aspScriptTags|phpScriptTags|sort|max|scriptScriptTags|toolbar_item|_|command|command_|number|getElementById|doubleQuotedString|singleLinePerlComments|singleLineCComments|multiLineCComments|singleQuotedString|multiLineDoubleQuotedString|xmlComments|alt|multiLineSingleQuotedString|If|https|1em|000|fff|background|5em|xx|bottom|75em|Gorbatchev|large|serif|CDATA|continue|utf|charset|content|About|family|sans|Helvetica|Arial|Geneva|3em|nogutter|Copyright|syntax|close|write|2004|Alex|open|JavaScript|highlighter|July|02|replaceChild|offset|83'.split('|'),0,{})) diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shCoreDefault.css b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shCoreDefault.css new file mode 100644 index 00000000000..08f9e10e4ea --- /dev/null +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shCoreDefault.css @@ -0,0 +1,328 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + -moz-border-radius: 0 0 0 0 !important; + -webkit-border-radius: 0 0 0 0 !important; + background: none !important; + border: 0 !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} + +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .bold { + font-weight: bold !important; +} +.syntaxhighlighter .italic { + font-style: italic !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 0 0.5em 0 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 0 1em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { + padding-left: 0em !important; +} +.syntaxhighlighter.show { + display: block !important; +} +.syntaxhighlighter.collapsed table { + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar { + padding: 0.1em 0.8em 0em 0.8em !important; + font-size: 1em !important; + position: static !important; + width: auto !important; + height: auto !important; +} +.syntaxhighlighter.collapsed .toolbar span { + display: inline !important; + margin-right: 1em !important; +} +.syntaxhighlighter.collapsed .toolbar span a { + padding: 0 !important; + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar span a.expandSource { + display: inline !important; +} +.syntaxhighlighter .toolbar { + position: absolute !important; + right: 1px !important; + top: 1px !important; + width: 11px !important; + height: 11px !important; + font-size: 10px !important; + z-index: 10 !important; +} +.syntaxhighlighter .toolbar span.title { + display: inline !important; +} +.syntaxhighlighter .toolbar a { + display: block !important; + text-align: center !important; + text-decoration: none !important; + padding-top: 1px !important; +} +.syntaxhighlighter .toolbar a.expandSource { + display: none !important; +} +.syntaxhighlighter.ie { + font-size: .9em !important; + padding: 1px 0 1px 0 !important; +} +.syntaxhighlighter.ie .toolbar { + line-height: 8px !important; +} +.syntaxhighlighter.ie .toolbar a { + padding-top: 0px !important; +} +.syntaxhighlighter.printing .line.alt1 .content, +.syntaxhighlighter.printing .line.alt2 .content, +.syntaxhighlighter.printing .line.highlighted .number, +.syntaxhighlighter.printing .line.highlighted.alt1 .content, +.syntaxhighlighter.printing .line.highlighted.alt2 .content { + background: none !important; +} +.syntaxhighlighter.printing .line .number { + color: #bbbbbb !important; +} +.syntaxhighlighter.printing .line .content { + color: black !important; +} +.syntaxhighlighter.printing .toolbar { + display: none !important; +} +.syntaxhighlighter.printing a { + text-decoration: none !important; +} +.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { + color: black !important; +} +.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { + color: #008200 !important; +} +.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { + color: blue !important; +} +.syntaxhighlighter.printing .keyword { + color: #006699 !important; + font-weight: bold !important; +} +.syntaxhighlighter.printing .preprocessor { + color: gray !important; +} +.syntaxhighlighter.printing .variable { + color: #aa7700 !important; +} +.syntaxhighlighter.printing .value { + color: #009900 !important; +} +.syntaxhighlighter.printing .functions { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .constants { + color: #0066cc !important; +} +.syntaxhighlighter.printing .script { + font-weight: bold !important; +} +.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { + color: gray !important; +} +.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { + color: red !important; +} +.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { + color: black !important; +} + +.syntaxhighlighter { + background-color: white !important; +} +.syntaxhighlighter .line.alt1 { + background-color: white !important; +} +.syntaxhighlighter .line.alt2 { + background-color: white !important; +} +.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { + background-color: #e0e0e0 !important; +} +.syntaxhighlighter .line.highlighted.number { + color: black !important; +} +.syntaxhighlighter table caption { + color: black !important; +} +.syntaxhighlighter .gutter { + color: #afafaf !important; +} +.syntaxhighlighter .gutter .line { + border-right: 3px solid #6ce26c !important; +} +.syntaxhighlighter .gutter .line.highlighted { + background-color: #6ce26c !important; + color: white !important; +} +.syntaxhighlighter.printing .line .content { + border: none !important; +} +.syntaxhighlighter.collapsed { + overflow: visible !important; +} +.syntaxhighlighter.collapsed .toolbar { + color: blue !important; + background: white !important; + border: 1px solid #6ce26c !important; +} +.syntaxhighlighter.collapsed .toolbar a { + color: blue !important; +} +.syntaxhighlighter.collapsed .toolbar a:hover { + color: red !important; +} +.syntaxhighlighter .toolbar { + color: white !important; + background: #6ce26c !important; + border: none !important; +} +.syntaxhighlighter .toolbar a { + color: white !important; +} +.syntaxhighlighter .toolbar a:hover { + color: black !important; +} +.syntaxhighlighter .plain, .syntaxhighlighter .plain a { + color: black !important; +} +.syntaxhighlighter .comments, .syntaxhighlighter .comments a { + color: #008200 !important; +} +.syntaxhighlighter .string, .syntaxhighlighter .string a { + color: blue !important; +} +.syntaxhighlighter .keyword { + color: #006699 !important; +} +.syntaxhighlighter .preprocessor { + color: gray !important; +} +.syntaxhighlighter .variable { + color: #aa7700 !important; +} +.syntaxhighlighter .value { + color: #009900 !important; +} +.syntaxhighlighter .functions { + color: #ff1493 !important; +} +.syntaxhighlighter .constants { + color: #0066cc !important; +} +.syntaxhighlighter .script { + font-weight: bold !important; + color: #006699 !important; + background-color: none !important; +} +.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { + color: gray !important; +} +.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { + color: red !important; +} + +.syntaxhighlighter .keyword { + font-weight: bold !important; +} diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shThemeDefault.css b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shThemeDefault.css new file mode 100644 index 00000000000..136541172dc --- /dev/null +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shThemeDefault.css @@ -0,0 +1,117 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter { + background-color: white !important; +} +.syntaxhighlighter .line.alt1 { + background-color: white !important; +} +.syntaxhighlighter .line.alt2 { + background-color: white !important; +} +.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { + background-color: #e0e0e0 !important; +} +.syntaxhighlighter .line.highlighted.number { + color: black !important; +} +.syntaxhighlighter table caption { + color: black !important; +} +.syntaxhighlighter .gutter { + color: #afafaf !important; +} +.syntaxhighlighter .gutter .line { + border-right: 3px solid #6ce26c !important; +} +.syntaxhighlighter .gutter .line.highlighted { + background-color: #6ce26c !important; + color: white !important; +} +.syntaxhighlighter.printing .line .content { + border: none !important; +} +.syntaxhighlighter.collapsed { + overflow: visible !important; +} +.syntaxhighlighter.collapsed .toolbar { + color: blue !important; + background: white !important; + border: 1px solid #6ce26c !important; +} +.syntaxhighlighter.collapsed .toolbar a { + color: blue !important; +} +.syntaxhighlighter.collapsed .toolbar a:hover { + color: red !important; +} +.syntaxhighlighter .toolbar { + color: white !important; + background: #6ce26c !important; + border: none !important; +} +.syntaxhighlighter .toolbar a { + color: white !important; +} +.syntaxhighlighter .toolbar a:hover { + color: black !important; +} +.syntaxhighlighter .plain, .syntaxhighlighter .plain a { + color: black !important; +} +.syntaxhighlighter .comments, .syntaxhighlighter .comments a { + color: #008200 !important; +} +.syntaxhighlighter .string, .syntaxhighlighter .string a { + color: blue !important; +} +.syntaxhighlighter .keyword { + color: #006699 !important; +} +.syntaxhighlighter .preprocessor { + color: gray !important; +} +.syntaxhighlighter .variable { + color: #aa7700 !important; +} +.syntaxhighlighter .value { + color: #009900 !important; +} +.syntaxhighlighter .functions { + color: #ff1493 !important; +} +.syntaxhighlighter .constants { + color: #0066cc !important; +} +.syntaxhighlighter .script { + font-weight: bold !important; + color: #006699 !important; + background-color: none !important; +} +.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { + color: gray !important; +} +.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { + color: red !important; +} + +.syntaxhighlighter .keyword { + font-weight: bold !important; +} diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TesterTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TesterTest.java index d29cda7fe6a..78c22e31ad0 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TesterTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TesterTest.java @@ -75,7 +75,7 @@ public class TesterTest { @Test public void testTester() throws Exception { - if (true) return; +// if (true) return; myRestfulServer.setProviders(new SearchProvider(), new GlobalHistoryProvider()); myServer.start();