Merge branch 'subscription_cleanup' of github.com:jamesagnew/hapi-fhir into subscription_cleanup
This commit is contained in:
commit
ea70683604
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
|
|||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.provider.AbstractHashMapResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.provider.HashMapResourceProvider;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
|
@ -42,7 +42,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
|
||||
/**
|
||||
* This is a subclass to implement FHIR operations specific to DSTU3 ConceptMap
|
||||
* resources. Its superclass, {@link AbstractHashMapResourceProvider}, is a simple
|
||||
* resources. Its superclass, {@link HashMapResourceProvider}, is a simple
|
||||
* implementation of the resource provider interface that uses a HashMap to
|
||||
* store all resources in memory.
|
||||
* <p>
|
||||
|
@ -53,7 +53,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
* <li>Conditional update for DSTU3 ConceptMap resources by ConceptMap.url</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class HashMapResourceProviderConceptMapDstu3 extends AbstractHashMapResourceProvider<ConceptMap> {
|
||||
public class HashMapResourceProviderConceptMapDstu3 extends HashMapResourceProvider<ConceptMap> {
|
||||
@SuppressWarnings("unchecked")
|
||||
public HashMapResourceProviderConceptMapDstu3(FhirContext theFhirContext) {
|
||||
super(theFhirContext, ConceptMap.class);
|
||||
|
@ -84,10 +84,10 @@ public class HashMapResourceProviderConceptMapDstu3 extends AbstractHashMapResou
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Update
|
||||
public MethodOutcome updateConceptMapConditional(
|
||||
public MethodOutcome update(
|
||||
@ResourceParam ConceptMap theConceptMap,
|
||||
@IdParam IdType theId,
|
||||
@ConditionalUrlParam String theConditional) {
|
||||
|
||||
MethodOutcome methodOutcome = new MethodOutcome();
|
||||
|
@ -112,14 +112,14 @@ public class HashMapResourceProviderConceptMapDstu3 extends AbstractHashMapResou
|
|||
List<ConceptMap> conceptMaps = searchByUrl(url);
|
||||
|
||||
if (!conceptMaps.isEmpty()) {
|
||||
methodOutcome = update(conceptMaps.get(0));
|
||||
methodOutcome = super.update(conceptMaps.get(0), null);
|
||||
} else {
|
||||
methodOutcome = create(theConceptMap);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
methodOutcome = update(theConceptMap);
|
||||
methodOutcome = super.update(theConceptMap, null);
|
||||
}
|
||||
|
||||
return methodOutcome;
|
||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
|
|||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.provider.AbstractHashMapResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.provider.HashMapResourceProvider;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
|
@ -42,7 +42,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
|
||||
/**
|
||||
* This is a subclass to implement FHIR operations specific to R4 ConceptMap
|
||||
* resources. Its superclass, {@link AbstractHashMapResourceProvider}, is a simple
|
||||
* resources. Its superclass, {@link HashMapResourceProvider}, is a simple
|
||||
* implementation of the resource provider interface that uses a HashMap to
|
||||
* store all resources in memory.
|
||||
* <p>
|
||||
|
@ -53,7 +53,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
* <li>Conditional update for R4 ConceptMap resources by ConceptMap.url</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class HashMapResourceProviderConceptMapR4 extends AbstractHashMapResourceProvider<ConceptMap> {
|
||||
public class HashMapResourceProviderConceptMapR4 extends HashMapResourceProvider<ConceptMap> {
|
||||
@SuppressWarnings("unchecked")
|
||||
public HashMapResourceProviderConceptMapR4(FhirContext theFhirContext) {
|
||||
super(theFhirContext, ConceptMap.class);
|
||||
|
@ -84,16 +84,15 @@ public class HashMapResourceProviderConceptMapR4 extends AbstractHashMapResource
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Update
|
||||
public MethodOutcome updateConceptMapConditional(
|
||||
public MethodOutcome update(
|
||||
@ResourceParam ConceptMap theConceptMap,
|
||||
@IdParam IdType theId,
|
||||
@ConditionalUrlParam String theConditional) {
|
||||
|
||||
MethodOutcome methodOutcome = new MethodOutcome();
|
||||
|
||||
if (theConditional != null) {
|
||||
|
||||
String url = null;
|
||||
|
||||
try {
|
||||
|
@ -112,14 +111,14 @@ public class HashMapResourceProviderConceptMapR4 extends AbstractHashMapResource
|
|||
List<ConceptMap> conceptMaps = searchByUrl(url);
|
||||
|
||||
if (!conceptMaps.isEmpty()) {
|
||||
methodOutcome = update(conceptMaps.get(0));
|
||||
methodOutcome = super.update(conceptMaps.get(0), null);
|
||||
} else {
|
||||
methodOutcome = create(theConceptMap);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
methodOutcome = update(theConceptMap);
|
||||
methodOutcome = super.update(theConceptMap, null);
|
||||
}
|
||||
|
||||
return methodOutcome;
|
||||
|
|
|
@ -34,7 +34,6 @@ import org.junit.AfterClass;
|
|||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.orm.hibernate5.HibernateTransactionManager;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
|
@ -49,6 +48,7 @@ import java.sql.SQLException;
|
|||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.util.TestUtil.randomizeLocale;
|
||||
import static org.junit.Assert.*;
|
||||
|
@ -77,16 +77,6 @@ public abstract class BaseJpaTest {
|
|||
BaseHapiFhirResourceDao.setDisableIncrementOnUpdateForUnitTest(false);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeCreateSrd() {
|
||||
mySrd = mock(ServletRequestDetails.class, Mockito.RETURNS_DEEP_STUBS);
|
||||
when(mySrd.getRequestOperationCallback()).thenReturn(myRequestOperationCallback);
|
||||
myServerInterceptorList = new ArrayList<>();
|
||||
when(mySrd.getServer().getInterceptors()).thenReturn(myServerInterceptorList);
|
||||
when(mySrd.getUserData()).thenReturn(new HashMap<>());
|
||||
when(mySrd.getHeaders(eq(JpaConstants.HEADER_META_SNAPSHOT_MODE))).thenReturn(new ArrayList<>());
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterValidateNoTransaction() {
|
||||
PlatformTransactionManager txManager = getTxManager();
|
||||
|
@ -103,6 +93,7 @@ public abstract class BaseJpaTest {
|
|||
if (currentSession != null) {
|
||||
currentSession.doWork(new Work() {
|
||||
|
||||
@Override
|
||||
public void execute(Connection connection) throws SQLException {
|
||||
isReadOnly.set(connection.isReadOnly());
|
||||
}
|
||||
|
@ -113,6 +104,16 @@ public abstract class BaseJpaTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeCreateSrd() {
|
||||
mySrd = mock(ServletRequestDetails.class, Mockito.RETURNS_DEEP_STUBS);
|
||||
when(mySrd.getRequestOperationCallback()).thenReturn(myRequestOperationCallback);
|
||||
myServerInterceptorList = new ArrayList<>();
|
||||
when(mySrd.getServer().getInterceptors()).thenReturn(myServerInterceptorList);
|
||||
when(mySrd.getUserData()).thenReturn(new HashMap<>());
|
||||
when(mySrd.getHeaders(eq(JpaConstants.HEADER_META_SNAPSHOT_MODE))).thenReturn(new ArrayList<>());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeRandomizeLocale() {
|
||||
randomizeLocale();
|
||||
|
@ -299,6 +300,7 @@ public abstract class BaseJpaTest {
|
|||
return retVal.toArray(new String[retVal.size()]);
|
||||
}
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
@ -360,7 +362,19 @@ public abstract class BaseJpaTest {
|
|||
}
|
||||
}
|
||||
if (sw.getMillis() >= 15000) {
|
||||
fail("Size " + theList.size() + " is != target " + theTarget + " - Got: " + theList.toString());
|
||||
String describeResults = theList
|
||||
.stream()
|
||||
.map(t -> {
|
||||
if (t == null) {
|
||||
return "null";
|
||||
}
|
||||
if (t instanceof IBaseResource) {
|
||||
return ((IBaseResource)t).getIdElement().getValue();
|
||||
}
|
||||
return t.toString();
|
||||
})
|
||||
.collect(Collectors.joining(", "));
|
||||
fail("Size " + theList.size() + " is != target " + theTarget + " - Got: " + describeResults);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -235,6 +235,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
|
|
@ -150,7 +150,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
|
|||
waitForSize(0, ourCreatedObservations);
|
||||
waitForSize(4, ourUpdatedObservations);
|
||||
|
||||
Observation observation3 = myClient.read(Observation.class, observationTemp3.getId());
|
||||
Observation observation3 = myClient.read().resource(Observation.class).withId(observationTemp3.getId()).execute();
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation3.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
|
@ -223,7 +223,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
|
|||
waitForSize(0, ourCreatedObservations);
|
||||
waitForSize(4, ourUpdatedObservations);
|
||||
|
||||
Observation observation3 = myClient.read(Observation.class, observationTemp3.getId());
|
||||
Observation observation3 = myClient.read().resource(Observation.class).withId(observationTemp3.getId()).execute();
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation3.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
|
@ -236,7 +236,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
|
|||
waitForSize(0, ourCreatedObservations);
|
||||
waitForSize(4, ourUpdatedObservations);
|
||||
|
||||
Observation observation3a = myClient.read(Observation.class, observationTemp3.getId());
|
||||
Observation observation3a = myClient.read().resource(Observation.class).withId(observationTemp3.getId()).execute();
|
||||
|
||||
CodeableConcept codeableConcept1 = new CodeableConcept();
|
||||
observation3a.setCode(codeableConcept1);
|
||||
|
|
|
@ -13,7 +13,9 @@ import ca.uhn.fhir.rest.server.RestfulServerUtils.ResponseEncoding;
|
|||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -440,206 +442,237 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
|
|||
}
|
||||
theServletResponse.setContentType(Constants.CT_HTML_WITH_UTF8);
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<html lang=\"en\">\n");
|
||||
b.append(" <head>\n");
|
||||
b.append(" <meta charset=\"utf-8\" />\n");
|
||||
b.append(" <style>\n");
|
||||
b.append(".httpStatusDiv {");
|
||||
b.append(" font-size: 1.2em;");
|
||||
b.append(" font-weight: bold;");
|
||||
b.append("}");
|
||||
b.append(".hlQuot { color: #88F; }\n");
|
||||
b.append(".hlQuot a { text-decoration: underline; text-decoration-color: #CCC; }\n");
|
||||
b.append(".hlQuot a:HOVER { text-decoration: underline; text-decoration-color: #008; }\n");
|
||||
b.append(".hlQuot .uuid, .hlQuot .dateTime {\n");
|
||||
b.append(" user-select: all;\n");
|
||||
b.append(" -moz-user-select: all;\n");
|
||||
b.append(" -webkit-user-select: all;\n");
|
||||
b.append(" -ms-user-select: element;\n");
|
||||
b.append("}\n");
|
||||
b.append(".hlAttr {\n");
|
||||
b.append(" color: #888;\n");
|
||||
b.append("}\n");
|
||||
b.append(".hlTagName {\n");
|
||||
b.append(" color: #006699;\n");
|
||||
b.append("}\n");
|
||||
b.append(".hlControl {\n");
|
||||
b.append(" color: #660000;\n");
|
||||
b.append("}\n");
|
||||
b.append(".hlText {\n");
|
||||
b.append(" color: #000000;\n");
|
||||
b.append("}\n");
|
||||
b.append(".hlUrlBase {\n");
|
||||
b.append("}");
|
||||
b.append(".headersDiv {\n");
|
||||
b.append(" padding: 10px;");
|
||||
b.append(" margin-left: 10px;");
|
||||
b.append(" border: 1px solid #CCC;");
|
||||
b.append(" border-radius: 10px;");
|
||||
b.append("}");
|
||||
b.append(".headersRow {\n");
|
||||
b.append("}");
|
||||
b.append(".headerName {\n");
|
||||
b.append(" color: #888;\n");
|
||||
b.append(" font-family: monospace;\n");
|
||||
b.append("}");
|
||||
b.append(".headerValue {\n");
|
||||
b.append(" color: #88F;\n");
|
||||
b.append(" font-family: monospace;\n");
|
||||
b.append("}");
|
||||
b.append(".responseBodyTable {");
|
||||
b.append(" width: 100%;\n");
|
||||
b.append(" margin-left: 0px;\n");
|
||||
b.append(" margin-top: -10px;\n");
|
||||
b.append(" position: relative;\n");
|
||||
b.append("}");
|
||||
b.append(".responseBodyTableFirstColumn {");
|
||||
b.append(" position: absolute;\n");
|
||||
b.append(" width: 70px;\n");
|
||||
b.append("}");
|
||||
b.append(".responseBodyTableSecondColumn {");
|
||||
b.append(" position: absolute;\n");
|
||||
b.append(" margin-left: 70px;\n");
|
||||
b.append(" vertical-align: top;\n");
|
||||
b.append(" left: 0px;\n");
|
||||
b.append(" right: 0px;\n");
|
||||
b.append("}");
|
||||
b.append(".lineAnchor A {");
|
||||
b.append(" text-decoration: none;");
|
||||
b.append(" padding-left: 20px;");
|
||||
b.append("}");
|
||||
b.append(".lineAnchor {");
|
||||
b.append(" display: block;");
|
||||
b.append(" padding-right: 20px;");
|
||||
b.append("}");
|
||||
b.append(".selectedLine {");
|
||||
b.append(" background-color: #EEF;");
|
||||
b.append(" font-weight: bold;");
|
||||
b.append("}");
|
||||
b.append("H1 {");
|
||||
b.append(" font-size: 1.1em;");
|
||||
b.append(" color: #666;");
|
||||
b.append("}");
|
||||
b.append("BODY {\n");
|
||||
b.append(" font-family: Arial;\n");
|
||||
b.append("}");
|
||||
b.append(" </style>\n");
|
||||
b.append(" </head>\n");
|
||||
b.append("\n");
|
||||
b.append(" <body>");
|
||||
StringBuilder outputBuffer = new StringBuilder();
|
||||
outputBuffer.append("<html lang=\"en\">\n");
|
||||
outputBuffer.append(" <head>\n");
|
||||
outputBuffer.append(" <meta charset=\"utf-8\" />\n");
|
||||
outputBuffer.append(" <style>\n");
|
||||
outputBuffer.append(".httpStatusDiv {");
|
||||
outputBuffer.append(" font-size: 1.2em;");
|
||||
outputBuffer.append(" font-weight: bold;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".hlQuot { color: #88F; }\n");
|
||||
outputBuffer.append(".hlQuot a { text-decoration: underline; text-decoration-color: #CCC; }\n");
|
||||
outputBuffer.append(".hlQuot a:HOVER { text-decoration: underline; text-decoration-color: #008; }\n");
|
||||
outputBuffer.append(".hlQuot .uuid, .hlQuot .dateTime {\n");
|
||||
outputBuffer.append(" user-select: all;\n");
|
||||
outputBuffer.append(" -moz-user-select: all;\n");
|
||||
outputBuffer.append(" -webkit-user-select: all;\n");
|
||||
outputBuffer.append(" -ms-user-select: element;\n");
|
||||
outputBuffer.append("}\n");
|
||||
outputBuffer.append(".hlAttr {\n");
|
||||
outputBuffer.append(" color: #888;\n");
|
||||
outputBuffer.append("}\n");
|
||||
outputBuffer.append(".hlTagName {\n");
|
||||
outputBuffer.append(" color: #006699;\n");
|
||||
outputBuffer.append("}\n");
|
||||
outputBuffer.append(".hlControl {\n");
|
||||
outputBuffer.append(" color: #660000;\n");
|
||||
outputBuffer.append("}\n");
|
||||
outputBuffer.append(".hlText {\n");
|
||||
outputBuffer.append(" color: #000000;\n");
|
||||
outputBuffer.append("}\n");
|
||||
outputBuffer.append(".hlUrlBase {\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".headersDiv {\n");
|
||||
outputBuffer.append(" padding: 10px;");
|
||||
outputBuffer.append(" margin-left: 10px;");
|
||||
outputBuffer.append(" border: 1px solid #CCC;");
|
||||
outputBuffer.append(" border-radius: 10px;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".headersRow {\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".headerName {\n");
|
||||
outputBuffer.append(" color: #888;\n");
|
||||
outputBuffer.append(" font-family: monospace;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".headerValue {\n");
|
||||
outputBuffer.append(" color: #88F;\n");
|
||||
outputBuffer.append(" font-family: monospace;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".responseBodyTable {");
|
||||
outputBuffer.append(" width: 100%;\n");
|
||||
outputBuffer.append(" margin-left: 0px;\n");
|
||||
outputBuffer.append(" margin-top: -10px;\n");
|
||||
outputBuffer.append(" position: relative;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".responseBodyTableFirstColumn {");
|
||||
// outputBuffer.append(" position: absolute;\n");
|
||||
// outputBuffer.append(" width: 70px;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".responseBodyTableSecondColumn {");
|
||||
outputBuffer.append(" position: absolute;\n");
|
||||
outputBuffer.append(" margin-left: 70px;\n");
|
||||
outputBuffer.append(" vertical-align: top;\n");
|
||||
outputBuffer.append(" left: 0px;\n");
|
||||
outputBuffer.append(" right: 0px;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".responseBodyTableSecondColumn PRE {");
|
||||
outputBuffer.append(" margin: 0px;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".sizeInfo {");
|
||||
outputBuffer.append(" margin-top: 20px;");
|
||||
outputBuffer.append(" font-size: 0.8em;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".lineAnchor A {");
|
||||
outputBuffer.append(" text-decoration: none;");
|
||||
outputBuffer.append(" padding-left: 20px;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".lineAnchor {");
|
||||
outputBuffer.append(" display: block;");
|
||||
outputBuffer.append(" padding-right: 20px;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(".selectedLine {");
|
||||
outputBuffer.append(" background-color: #EEF;");
|
||||
outputBuffer.append(" font-weight: bold;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append("H1 {");
|
||||
outputBuffer.append(" font-size: 1.1em;");
|
||||
outputBuffer.append(" color: #666;");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append("BODY {\n");
|
||||
outputBuffer.append(" font-family: Arial;\n");
|
||||
outputBuffer.append("}");
|
||||
outputBuffer.append(" </style>\n");
|
||||
outputBuffer.append(" </head>\n");
|
||||
outputBuffer.append("\n");
|
||||
outputBuffer.append(" <body>");
|
||||
|
||||
b.append("<p>");
|
||||
b.append("This result is being rendered in HTML for easy viewing. ");
|
||||
b.append("You may access this content as ");
|
||||
outputBuffer.append("<p>");
|
||||
outputBuffer.append("This result is being rendered in HTML for easy viewing. ");
|
||||
outputBuffer.append("You may access this content as ");
|
||||
|
||||
b.append("<a href=\"");
|
||||
b.append(createLinkHref(parameters, Constants.FORMAT_JSON));
|
||||
b.append("\">Raw JSON</a> or ");
|
||||
outputBuffer.append("<a href=\"");
|
||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMAT_JSON));
|
||||
outputBuffer.append("\">Raw JSON</a> or ");
|
||||
|
||||
b.append("<a href=\"");
|
||||
b.append(createLinkHref(parameters, Constants.FORMAT_XML));
|
||||
b.append("\">Raw XML</a>, ");
|
||||
outputBuffer.append("<a href=\"");
|
||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMAT_XML));
|
||||
outputBuffer.append("\">Raw XML</a>, ");
|
||||
|
||||
b.append(" or view this content in ");
|
||||
outputBuffer.append(" or view this content in ");
|
||||
|
||||
b.append("<a href=\"");
|
||||
b.append(createLinkHref(parameters, Constants.FORMATS_HTML_JSON));
|
||||
b.append("\">HTML JSON</a> ");
|
||||
outputBuffer.append("<a href=\"");
|
||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMATS_HTML_JSON));
|
||||
outputBuffer.append("\">HTML JSON</a> ");
|
||||
|
||||
b.append("or ");
|
||||
b.append("<a href=\"");
|
||||
b.append(createLinkHref(parameters, Constants.FORMATS_HTML_XML));
|
||||
b.append("\">HTML XML</a>.");
|
||||
outputBuffer.append("or ");
|
||||
outputBuffer.append("<a href=\"");
|
||||
outputBuffer.append(createLinkHref(parameters, Constants.FORMATS_HTML_XML));
|
||||
outputBuffer.append("\">HTML XML</a>.");
|
||||
|
||||
Date startTime = (Date) theServletRequest.getAttribute(RestfulServer.REQUEST_START_TIME);
|
||||
if (startTime != null) {
|
||||
long time = System.currentTimeMillis() - startTime.getTime();
|
||||
b.append(" Response generated in ");
|
||||
b.append(time);
|
||||
b.append("ms.");
|
||||
outputBuffer.append(" Response generated in ");
|
||||
outputBuffer.append(time);
|
||||
outputBuffer.append("ms.");
|
||||
}
|
||||
|
||||
b.append("</p>");
|
||||
outputBuffer.append("</p>");
|
||||
|
||||
b.append("\n");
|
||||
outputBuffer.append("\n");
|
||||
|
||||
// status (e.g. HTTP 200 OK)
|
||||
String statusName = Constants.HTTP_STATUS_NAMES.get(theServletResponse.getStatus());
|
||||
statusName = defaultString(statusName);
|
||||
b.append("<div class=\"httpStatusDiv\">");
|
||||
b.append("HTTP ");
|
||||
b.append(theServletResponse.getStatus());
|
||||
b.append(" ");
|
||||
b.append(statusName);
|
||||
b.append("</div>");
|
||||
outputBuffer.append("<div class=\"httpStatusDiv\">");
|
||||
outputBuffer.append("HTTP ");
|
||||
outputBuffer.append(theServletResponse.getStatus());
|
||||
outputBuffer.append(" ");
|
||||
outputBuffer.append(statusName);
|
||||
outputBuffer.append("</div>");
|
||||
|
||||
b.append("\n");
|
||||
b.append("\n");
|
||||
outputBuffer.append("\n");
|
||||
outputBuffer.append("\n");
|
||||
|
||||
try {
|
||||
if (isShowRequestHeaders()) {
|
||||
streamRequestHeaders(theServletRequest, b);
|
||||
streamRequestHeaders(theServletRequest, outputBuffer);
|
||||
}
|
||||
if (isShowResponseHeaders()) {
|
||||
streamResponseHeaders(theRequestDetails, theServletResponse, b);
|
||||
streamResponseHeaders(theRequestDetails, theServletResponse, outputBuffer);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore (this will hit if we're running in a servlet 2.5 environment)
|
||||
}
|
||||
|
||||
b.append("<h1>Response Body</h1>");
|
||||
outputBuffer.append("<h1>Response Body</h1>");
|
||||
|
||||
b.append("<div class=\"responseBodyTable\">");
|
||||
outputBuffer.append("<div class=\"responseBodyTable\">");
|
||||
|
||||
// Response Body
|
||||
b.append("<div class=\"responseBodyTableSecondColumn\"><pre>");
|
||||
outputBuffer.append("<div class=\"responseBodyTableSecondColumn\"><pre>");
|
||||
StringBuilder target = new StringBuilder();
|
||||
int linesCount = format(encoded, target, encoding);
|
||||
b.append(target);
|
||||
b.append("</pre></div>");
|
||||
outputBuffer.append(target);
|
||||
outputBuffer.append("</pre></div>");
|
||||
|
||||
// Line Numbers
|
||||
b.append("<div class=\"responseBodyTableFirstColumn\"><pre>");
|
||||
outputBuffer.append("<div class=\"responseBodyTableFirstColumn\"><pre>");
|
||||
for (int i = 1; i <= linesCount; i++) {
|
||||
b.append("<div class=\"lineAnchor\" id=\"anchor");
|
||||
b.append(i);
|
||||
b.append("\">");
|
||||
outputBuffer.append("<div class=\"lineAnchor\" id=\"anchor");
|
||||
outputBuffer.append(i);
|
||||
outputBuffer.append("\">");
|
||||
|
||||
b.append("<a href=\"#L");
|
||||
b.append(i);
|
||||
b.append("\" name=\"L");
|
||||
b.append(i);
|
||||
b.append("\" id=\"L");
|
||||
b.append(i);
|
||||
b.append("\">");
|
||||
b.append(i);
|
||||
b.append("</a></div>");
|
||||
outputBuffer.append("<a href=\"#L");
|
||||
outputBuffer.append(i);
|
||||
outputBuffer.append("\" name=\"L");
|
||||
outputBuffer.append(i);
|
||||
outputBuffer.append("\" id=\"L");
|
||||
outputBuffer.append(i);
|
||||
outputBuffer.append("\">");
|
||||
outputBuffer.append(i);
|
||||
outputBuffer.append("</a></div>");
|
||||
}
|
||||
b.append("</div></td>");
|
||||
outputBuffer.append("</div></td>");
|
||||
|
||||
b.append("</div>");
|
||||
outputBuffer.append("</div>");
|
||||
|
||||
b.append("\n");
|
||||
outputBuffer.append("\n");
|
||||
|
||||
InputStream jsStream = ResponseHighlighterInterceptor.class.getResourceAsStream("ResponseHighlighter.js");
|
||||
String jsStr = jsStream != null ? IOUtils.toString(jsStream, "UTF-8") : "console.log('ResponseHighlighterInterceptor: javascript theResource not found')";
|
||||
jsStr = jsStr.replace("FHIR_BASE", theRequestDetails.getServerBaseForRequest());
|
||||
b.append("<script type=\"text/javascript\">");
|
||||
b.append(jsStr);
|
||||
b.append("</script>\n");
|
||||
outputBuffer.append("<script type=\"text/javascript\">");
|
||||
outputBuffer.append(jsStr);
|
||||
outputBuffer.append("</script>\n");
|
||||
|
||||
b.append("</body>");
|
||||
b.append("</html>");
|
||||
String out = b.toString();
|
||||
StopWatch writeSw = new StopWatch();
|
||||
theServletResponse.getWriter().append(outputBuffer);
|
||||
theServletResponse.getWriter().flush();
|
||||
|
||||
theServletResponse.getWriter().append("<div class=\"sizeInfo\">");
|
||||
theServletResponse.getWriter().append("Wrote ");
|
||||
writeLength(theServletResponse, encoded.length());
|
||||
theServletResponse.getWriter().append(" (");
|
||||
writeLength(theServletResponse, outputBuffer.length());
|
||||
theServletResponse.getWriter().append(" total including HTML)");
|
||||
|
||||
theServletResponse.getWriter().append(" in estimated ");
|
||||
theServletResponse.getWriter().append(writeSw.toString());
|
||||
theServletResponse.getWriter().append("</div>");
|
||||
|
||||
|
||||
theServletResponse.getWriter().append("</body>");
|
||||
theServletResponse.getWriter().append("</html>");
|
||||
|
||||
theServletResponse.getWriter().append(out);
|
||||
theServletResponse.getWriter().close();
|
||||
} catch (IOException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeLength(HttpServletResponse theServletResponse, int theLength) throws IOException {
|
||||
double kb = ((double)theLength) / FileUtils.ONE_KB;
|
||||
if (kb <= 1000) {
|
||||
theServletResponse.getWriter().append(String.format("%.1f", kb)).append(" KB");
|
||||
} else {
|
||||
double mb = kb / 1000;
|
||||
theServletResponse.getWriter().append(String.format("%.1f", mb)).append(" MB");
|
||||
}
|
||||
}
|
||||
|
||||
private void streamResponseHeaders(RequestDetails theRequestDetails, HttpServletResponse theServletResponse, StringBuilder b) {
|
||||
if (theServletResponse.getHeaderNames().isEmpty() == false) {
|
||||
b.append("<h1>Response Headers</h1>");
|
||||
|
|
|
@ -1,198 +0,0 @@
|
|||
package ca.uhn.fhir.rest.server.provider;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Server Framework
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2018 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class is a simple implementation of the resource provider
|
||||
* interface that uses a HashMap to store all resources in memory.
|
||||
* It is essentially a copy of {@link ca.uhn.fhir.rest.server.provider.HashMapResourceProvider}
|
||||
* with the {@link Update} and {@link ResourceParam} annotations removed from method
|
||||
* {@link ca.uhn.fhir.rest.server.provider.HashMapResourceProvider#update(IBaseResource)}.
|
||||
* Non-generic subclasses of this abstract class may implement their own annotated methods (e.g. a conditional
|
||||
* update method specifically for ConceptMap resources).
|
||||
* <p>
|
||||
* This class currently supports the following FHIR operations:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Create</li>
|
||||
* <li>Update existing resource</li>
|
||||
* <li>Update non-existing resource (e.g. create with client-supplied ID)</li>
|
||||
* <li>Delete</li>
|
||||
* <li>Search by resource type with no parameters</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <T> The resource type to support
|
||||
*/
|
||||
public class AbstractHashMapResourceProvider<T extends IBaseResource> implements IResourceProvider {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(AbstractHashMapResourceProvider.class);
|
||||
private final Class<T> myResourceType;
|
||||
private final FhirContext myFhirContext;
|
||||
private final String myResourceName;
|
||||
protected Map<String, TreeMap<Long, T>> myIdToVersionToResourceMap = new HashMap<>();
|
||||
private long myNextId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theFhirContext The FHIR context
|
||||
* @param theResourceType The resource type to support
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public AbstractHashMapResourceProvider(FhirContext theFhirContext, Class<T> theResourceType) {
|
||||
myFhirContext = theFhirContext;
|
||||
myResourceType = theResourceType;
|
||||
myResourceName = myFhirContext.getResourceDefinition(theResourceType).getName();
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all data held in this resource provider
|
||||
*/
|
||||
public void clear() {
|
||||
myNextId = 1;
|
||||
myIdToVersionToResourceMap.clear();
|
||||
}
|
||||
|
||||
@Create
|
||||
public MethodOutcome create(@ResourceParam T theResource) {
|
||||
long idPart = myNextId++;
|
||||
String idPartAsString = Long.toString(idPart);
|
||||
Long versionIdPart = 1L;
|
||||
|
||||
IIdType id = store(theResource, idPartAsString, versionIdPart);
|
||||
|
||||
return new MethodOutcome()
|
||||
.setCreated(true)
|
||||
.setId(id);
|
||||
}
|
||||
|
||||
@Delete
|
||||
public MethodOutcome delete(@IdParam IIdType theId) {
|
||||
TreeMap<Long, T> versions = myIdToVersionToResourceMap.get(theId.getIdPart());
|
||||
if (versions == null || versions.isEmpty()) {
|
||||
throw new ResourceNotFoundException(theId);
|
||||
}
|
||||
|
||||
long nextVersion = versions.lastEntry().getKey() + 1L;
|
||||
IIdType id = store(null, theId.getIdPart(), nextVersion);
|
||||
|
||||
return new MethodOutcome()
|
||||
.setId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return myResourceType;
|
||||
}
|
||||
|
||||
private synchronized TreeMap<Long, T> getVersionToResource(String theIdPart) {
|
||||
if (!myIdToVersionToResourceMap.containsKey(theIdPart)) {
|
||||
myIdToVersionToResourceMap.put(theIdPart, new TreeMap<Long, T>());
|
||||
}
|
||||
return myIdToVersionToResourceMap.get(theIdPart);
|
||||
}
|
||||
|
||||
@Read(version = true)
|
||||
public IBaseResource read(@IdParam IIdType theId) {
|
||||
TreeMap<Long, T> versions = myIdToVersionToResourceMap.get(theId.getIdPart());
|
||||
if (versions == null || versions.isEmpty()) {
|
||||
throw new ResourceNotFoundException(theId);
|
||||
}
|
||||
|
||||
if (theId.hasVersionIdPart()) {
|
||||
Long versionId = theId.getVersionIdPartAsLong();
|
||||
if (!versions.containsKey(versionId)) {
|
||||
throw new ResourceNotFoundException(theId);
|
||||
} else {
|
||||
T resource = versions.get(versionId);
|
||||
if (resource == null) {
|
||||
throw new ResourceGoneException(theId);
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
} else {
|
||||
return versions.lastEntry().getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<IBaseResource> search() {
|
||||
List<IBaseResource> retVal = new ArrayList<>();
|
||||
|
||||
for (TreeMap<Long, T> next : myIdToVersionToResourceMap.values()) {
|
||||
if (next.isEmpty() == false) {
|
||||
retVal.add(next.lastEntry().getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private IIdType store(@ResourceParam T theResource, String theIdPart, Long theVersionIdPart) {
|
||||
IIdType id = myFhirContext.getVersion().newIdType();
|
||||
id.setParts(null, myResourceName, theIdPart, Long.toString(theVersionIdPart));
|
||||
if (theResource != null) {
|
||||
theResource.setId(id);
|
||||
}
|
||||
|
||||
TreeMap<Long, T> versionToResource = getVersionToResource(theIdPart);
|
||||
versionToResource.put(theVersionIdPart, theResource);
|
||||
|
||||
ourLog.info("Storing resource with ID: {}", id.getValue());
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public MethodOutcome update(T theResource) {
|
||||
String idPartAsString = theResource.getIdElement().getIdPart();
|
||||
TreeMap<Long, T> versionToResource = getVersionToResource(idPartAsString);
|
||||
|
||||
Long versionIdPart;
|
||||
Boolean created;
|
||||
if (versionToResource.isEmpty()) {
|
||||
versionIdPart = 1L;
|
||||
created = true;
|
||||
} else {
|
||||
versionIdPart = versionToResource.lastKey() + 1L;
|
||||
created = false;
|
||||
}
|
||||
|
||||
IIdType id = store(theResource, idPartAsString, versionIdPart);
|
||||
|
||||
return new MethodOutcome()
|
||||
.setCreated(created)
|
||||
.setId(id);
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ import ca.uhn.fhir.rest.param.TokenParam;
|
|||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.util.ValidateUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
@ -44,6 +45,8 @@ import org.slf4j.LoggerFactory;
|
|||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
/**
|
||||
* This class is a simple implementation of the resource provider
|
||||
* interface that uses a HashMap to store all resources in memory.
|
||||
|
@ -338,8 +341,15 @@ public class HashMapResourceProvider<T extends IBaseResource> implements IResour
|
|||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theConditional This is provided only so that subclasses can implement if they want
|
||||
*/
|
||||
@Update
|
||||
public MethodOutcome update(@ResourceParam T theResource) {
|
||||
public MethodOutcome update(
|
||||
@ResourceParam T theResource,
|
||||
@ConditionalUrlParam String theConditional) {
|
||||
|
||||
ValidateUtil.isTrueOrThrowInvalidRequest(isBlank(theConditional), "This server doesn't support conditional update");
|
||||
|
||||
String idPartAsString = theResource.getIdElement().getIdPart();
|
||||
TreeMap<Long, T> versionToResource = getVersionToResource(idPartAsString);
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
<properties>
|
||||
<features.file>features.xml</features.file>
|
||||
<pax-logging-version>1.10.1</pax-logging-version>
|
||||
<felix-framework-version>6.0.0</felix-framework-version>
|
||||
<pax-logging-version>1.8.6</pax-logging-version>
|
||||
<felix-framework-version>3.2.2</felix-framework-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</description>
|
||||
|
||||
<properties>
|
||||
<pax.exam.version>4.12.0</pax.exam.version>
|
||||
<pax.exam.version>4.9.1</pax.exam.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
|
|
@ -262,6 +262,10 @@
|
|||
/ R4 (and future) versions of FHIR. This should greatly improve maintainability
|
||||
and consistency for transaction processing.
|
||||
</action>
|
||||
<action type="add">
|
||||
ResponseHighlighterInterceptor now displays the total size of the output and
|
||||
an estimate of the transfer time at the bottom of the response.
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.4.0" date="2018-05-28">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue