More qwork on the tester
This commit is contained in:
parent
c20e7e450a
commit
7736e201e2
|
@ -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<? extends IElement> 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<? extends IResource> theResourceType) {
|
||||
RuntimeResourceDefinition retVal = (RuntimeResourceDefinition) myClassToElementDefinition.get(theResourceType);
|
||||
|
@ -106,16 +106,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 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) {
|
||||
|
@ -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<RuntimeResourceDefinition> getResourceDefinitions() {
|
||||
return myIdToResourceDefinition.values();
|
||||
|
@ -169,8 +165,7 @@ public class FhirContext {
|
|||
* Create and return a new JSON parser.
|
||||
*
|
||||
* <p>
|
||||
* Performance Note: <b>This class is cheap</b> to create, and may be called once for
|
||||
* every message being processed without incurring any performance penalty
|
||||
* Performance Note: <b>This class is cheap</b> to create, and may be called once for every message being processed without incurring any performance penalty
|
||||
* </p>
|
||||
*/
|
||||
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 <a
|
||||
* href="http://hl7api.sourceforge.net/hapi-fhir/doc_rest_client.html">RESTful Client</a> documentation for more information on how to define this interface.
|
||||
*
|
||||
* <p>
|
||||
* Performance Note: <b>This class is cheap</b> to create, and may be called once for
|
||||
* every message being processed without incurring any performance penalty
|
||||
* Performance Note: <b>This class is cheap</b> to create, and may be called once for every message being processed without incurring any performance penalty
|
||||
* </p>
|
||||
*
|
||||
* @param theClientType
|
||||
|
@ -197,12 +193,26 @@ public class FhirContext {
|
|||
return getRestfulClientFactory().newClient(theClientType, theServerBase);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}).
|
||||
* <p>
|
||||
* In most cases it is preferable to use the non-generic clients instead of this mechanism, but not always.
|
||||
* </p>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>
|
||||
* Performance Note: <b>This class is cheap</b> to create, and may be called once for
|
||||
* every message being processed without incurring any performance penalty
|
||||
* Performance Note: <b>This class is cheap</b> to create, and may be called once for every message being processed without incurring any performance penalty
|
||||
* </p>
|
||||
*/
|
||||
public IParser newXmlParser() {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<String, List<String>> headers = new HashMap<String, List<String>>();
|
||||
if (response.getAllHeaders() != null) {
|
||||
for (Header next : response.getAllHeaders()) {
|
||||
String name = next.getName().toLowerCase();
|
||||
List<String> list = headers.get(name);
|
||||
if (list == null) {
|
||||
list = new ArrayList<String>();
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -20,43 +20,25 @@ 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<Method, BaseMethodBinding> myBindings = new HashMap<Method, BaseMethodBinding>();
|
||||
private final HttpClient myClient;
|
||||
private final String myUrlBase;
|
||||
private final Map<Method, Object> myMethodToReturnValue = new HashMap<Method, Object>();
|
||||
|
||||
public ClientInvocationHandler(HttpClient theClient, FhirContext theContext, String theUrlBase, Class<? extends IRestfulClient> theClientType) {
|
||||
myClient = theClient;
|
||||
myUrlBase = theUrlBase;
|
||||
super(theClient, theUrlBase);
|
||||
|
||||
try {
|
||||
myMethodToReturnValue.put(theClientType.getMethod("getFhirContext"), theContext);
|
||||
|
@ -83,61 +65,9 @@ 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);
|
||||
return invokeClient(binding, clientInvocation);
|
||||
}
|
||||
|
||||
ContentType ct = ContentType.get(response.getEntity());
|
||||
|
||||
String mimeType = ct.getMimeType();
|
||||
|
||||
Map<String, List<String>> headers = new HashMap<String, List<String>>();
|
||||
if (response.getAllHeaders() != null) {
|
||||
for (Header next : response.getAllHeaders()) {
|
||||
String name = next.getName().toLowerCase();
|
||||
List<String> list = headers.get(name);
|
||||
if (list == null) {
|
||||
list = new ArrayList<String>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 extends IResource> T read(final Class<T> 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<String, List<String>> 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<? extends IResource> theType) {
|
||||
return myContext.getResourceDefinition(theType).getName();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T extends IResource> T vread(final Class<T> 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<String, List<String>> 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;
|
||||
}
|
||||
}
|
|
@ -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 extends IResource> T read(Class<T> 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 extends IResource> T vread(Class<T> theType, IdDt theId, IdDt theVersionId);
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public class RestfulClientFactory implements IRestfulClientFactory {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends IRestfulClient> T instantiateProxy(Class<T> theClientType, InvocationHandler theInvocationHandler) {
|
||||
T proxy = (T) Proxy.newProxyInstance(RestfulClientFactory.class.getClassLoader(), new Class[] { theClientType }, theInvocationHandler);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<String, List<String>> theHeaders) throws IOException, BaseServerResponseException;
|
||||
|
||||
public abstract void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException;
|
||||
|
||||
public abstract boolean matches(Request theRequest);
|
||||
|
|
|
@ -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<String, List<String>> theHeaders) throws IOException, BaseServerResponseException;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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<String, EncodingUtil> valToEncoding = new HashMap<String, EncodingUtil>();
|
||||
|
|
|
@ -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 {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Integer, Class<? extends BaseServerResponseException>> ourStatusCodeToExceptionType = new HashMap<Integer, Class<? extends BaseServerResponseException>>();
|
||||
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
|
||||
*
|
||||
|
@ -64,7 +80,8 @@ 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);
|
||||
|
@ -86,6 +103,13 @@ public abstract class BaseServerResponseException extends RuntimeException {
|
|||
myOperationOutcome = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link OperationOutcome} resource if any which was supplied in the response, or <code>null</code>
|
||||
*/
|
||||
public OperationOutcome getOperationOutcome() {
|
||||
return myOperationOutcome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP status code corresponding to this problem
|
||||
*/
|
||||
|
@ -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 <code>null</code>
|
||||
*/
|
||||
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<? extends BaseServerResponseException> theType) {
|
||||
if (ourStatusCodeToExceptionType.containsKey(theStatusCode)) {
|
||||
throw new Error("Can not register " + theType + " to status code " + theStatusCode + " because " + ourStatusCodeToExceptionType.get(theStatusCode) + " already registers that code");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <b>HTTP 404 Resource Not Found</b> 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<? extends IResource> 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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <b>HTTP 422 Unprocessable Entity</b> 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) {
|
||||
|
|
|
@ -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<String, String> myStaticResources;
|
||||
private String myServerBase;
|
||||
|
@ -43,13 +54,112 @@ 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 doGet(HttpServletRequest theReq, HttpServletResponse theResp) throws ServletException, IOException {
|
||||
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());
|
||||
|
||||
|
@ -65,12 +175,12 @@ public class PublicTesterServlet extends HttpServlet {
|
|||
WebContext ctx = new WebContext(theReq, theResp, theReq.getServletContext(), theReq.getLocale());
|
||||
ctx.setVariable("conf", conformance);
|
||||
ctx.setVariable("base", myServerBase);
|
||||
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();
|
||||
}
|
||||
|
@ -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,10 +207,13 @@ 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;
|
||||
}
|
||||
|
|
|
@ -20,3 +20,7 @@ TD.testerNameCell {
|
|||
border-radius: 3px;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.syntaxhighlighter {
|
||||
font-size: 0.85em !important;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ This file is a Thymeleaf template for the
|
|||
<script type="text/javascript" src="PublicTester.js"></script>
|
||||
<script type="text/javascript">
|
||||
var serverBase = "<th:block th:text="${base}"/>";
|
||||
var conformance = <th:block th:text="${jsonEncodedConf}"/>;
|
||||
</script>
|
||||
<link rel="stylesheet" type="text/css" href="PublicTester.css"/>
|
||||
</head>
|
||||
|
@ -62,7 +63,8 @@ This file is a Thymeleaf template for the
|
|||
<td valign="top">
|
||||
<th:span th:each="operation : ${resource.operation}">
|
||||
<th:block th:switch="${operation.code.value}">
|
||||
<a th:case="'read'" th:href="'javascript:displayRead(\'' + ${expandoId} + '\');'">read</a>
|
||||
<a th:case="'read'" th:href="'javascript:displayRead(\'' + ${expandoId} + '\', \'' + ${resource.type.valueAsString} + '\');'">read</a>
|
||||
<a th:case="'vread'" th:href="'javascript:displayVRead(\'' + ${expandoId} + '\', \'' + ${resource.type.valueAsString} + '\');'">vread</a>
|
||||
<span th:case="*" th:text="${operation.code.value}"/>
|
||||
</th:block>
|
||||
</th:span>
|
||||
|
|
|
@ -1,20 +1,60 @@
|
|||
|
||||
var currentForm;
|
||||
|
||||
/** Create a tester form for the 'read' method */
|
||||
function displayRead(expandoTr) {
|
||||
/** 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();
|
||||
}
|
||||
}
|
||||
|
||||
$('#' + expandoTr).show();
|
||||
/** Create a tester form for the 'read' method */
|
||||
function displayRead(expandoTr, resourceName) {
|
||||
var postCompleteFunction = function() {
|
||||
//$('#' + expandoTr).show();
|
||||
currentForm = $('#' + expandoTr).append(
|
||||
$('<td class="testerNameCell">Read</td>'),
|
||||
$('<td />').append(
|
||||
$('<form />', { action: '', method: 'POST' }).append(
|
||||
$('<form/>', { id: 'testerform', action: 'PublicTesterResult.html', method: 'POST' }).append(
|
||||
$('<input />', { name: 'method', value: 'read', type: 'hidden' }),
|
||||
$('<input />', { name: 'resourceName', value: resourceName, type: 'hidden' }),
|
||||
$('<input />', { name: 'id', placeholder: 'Resource ID', type: 'text' }),
|
||||
$('<br />'),
|
||||
$('<input />', { 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(
|
||||
$('<td class="testerNameCell">VRead</td>'),
|
||||
$('<td />').append(
|
||||
$('<form/>', { id: 'testerform', action: 'PublicTesterResult.html', method: 'POST' }).append(
|
||||
$('<input />', { name: 'method', value: 'vread', type: 'hidden' }),
|
||||
$('<input />', { name: 'resourceName', value: resourceName, type: 'hidden' }),
|
||||
$('<input />', { name: 'id', placeholder: 'Resource ID', type: 'text' }),
|
||||
$('<input />', { name: 'versionid', placeholder: 'Version ID', type: 'text' }),
|
||||
$('<br />'),
|
||||
$('<input />', { type: 'submit', value: 'Submit' })
|
||||
)
|
||||
)
|
||||
);
|
||||
$('#' + expandoTr).fadeIn(500);
|
||||
}
|
||||
clearCurrentForm(postCompleteFunction);
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<!DOCTYPE html>
|
||||
<!--/*
|
||||
************************************************************
|
||||
This file is a Thymeleaf template for the
|
||||
************************************************************
|
||||
*/-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<script src="shCore.js" type="text/javascript"></script>
|
||||
<script src="shBrushJScript.js" type="text/javascript"></script>
|
||||
<script src="shBrushXml.js" type="text/javascript"></script>
|
||||
<script src="shBrushPlain.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" type="text/css" href="shCore.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="shThemeDefault.css"/>
|
||||
<script type="text/javascript" src="jquery-2.1.0.min.js"></script>
|
||||
<script type="text/javascript" src="PublicTester.js"></script>
|
||||
<script type="text/javascript">
|
||||
var serverBase = "<th:block th:utext="${base}"/>";
|
||||
</script>
|
||||
<link rel="stylesheet" type="text/css" href="PublicTester.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<table border="0" width="100%">
|
||||
<tr>
|
||||
<td align="left"><img src="hapi_fhir_banner.png"/></td>
|
||||
<td align="right"><img src="hapi_fhir_banner_right.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="bodyHeaderBlock">
|
||||
Executed invocation:<br/>
|
||||
<th:block th:text="${action}">GET</th:block>
|
||||
<a href="http://foo.com/fhir" th:href="${requestUrl}"><th:block th:text="${requestUrl}">http://foo.com/fhir</th:block></a>
|
||||
</div>
|
||||
|
||||
<table border="0" width="100%" cellpadding="0" cellspacing="0" style="margin-top: 4px;">
|
||||
<tr>
|
||||
<td width="29%" valign="top">
|
||||
|
||||
<div class="bodyHeaderBlock">
|
||||
Actions
|
||||
</div>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td class="propertyKeyCell">Something</td>
|
||||
<td>Something</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
|
||||
<td width="1%"/>
|
||||
|
||||
<td width="70%" valign="top">
|
||||
|
||||
<div class="bodyHeaderBlock">
|
||||
Response
|
||||
</div>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td valign="top" class="propertyKeyCell">Status</td>
|
||||
<td valign="top" th:text="${resultStatus}">HTTP 200 OK</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" class="propertyKeyCell">Result</td>
|
||||
<td valign="top"><pre th:text="${resultBody}" th:class="${resultSyntaxHighlighterClass}">{}</pre></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript">
|
||||
SyntaxHighlighter.all();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
52
hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushJScript.js
vendored
Normal file
52
hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushJScript.js
vendored
Normal file
|
@ -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;
|
||||
})();
|
33
hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushPlain.js
vendored
Normal file
33
hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushPlain.js
vendored
Normal file
|
@ -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;
|
||||
})();
|
69
hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushXml.js
vendored
Normal file
69
hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/shBrushXml.js
vendored
Normal file
|
@ -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\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg').exec(code),
|
||||
result = []
|
||||
;
|
||||
|
||||
if (match.attributes != null)
|
||||
{
|
||||
var attributes,
|
||||
regex = new XRegExp('(?<name> [\\w:\\-\\.]+)' +
|
||||
'\\s*=\\s*' +
|
||||
'(?<value> ".*?"|\'.*?\'|\\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+)(?<attributes>.*?)[\\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;
|
||||
})();
|
|
@ -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;
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue