diff --git a/.gitignore b/.gitignore
index 2a64f04d425..3f1190ec6c7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,7 @@ Servers/
*.log*
nohup.out
.DS_Store
+*.orig
# Vagrant stuff.
.vagrant
diff --git a/examples/src/main/java/example/AuthorizingTesterUiClientFactory.java b/examples/src/main/java/example/AuthorizingTesterUiClientFactory.java
new file mode 100644
index 00000000000..996d28f66d5
--- /dev/null
+++ b/examples/src/main/java/example/AuthorizingTesterUiClientFactory.java
@@ -0,0 +1,23 @@
+package example;
+
+import javax.servlet.http.HttpServletRequest;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.client.IGenericClient;
+import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor;
+import ca.uhn.fhir.util.ITestingUiClientFactory;
+
+public class AuthorizingTesterUiClientFactory implements ITestingUiClientFactory {
+
+ @Override
+ public IGenericClient newClient(FhirContext theFhirContext, HttpServletRequest theRequest, String theServerBaseUrl) {
+ // Create a client
+ IGenericClient client = theFhirContext.newRestfulGenericClient(theServerBaseUrl);
+
+ // Register an interceptor which adds credentials
+ client.registerInterceptor(new BasicAuthInterceptor("someusername", "somepassword"));
+
+ return client;
+ }
+
+}
diff --git a/examples/src/main/java/example/ClientExamples.java b/examples/src/main/java/example/ClientExamples.java
index fcbec0495f6..7631f07c514 100644
--- a/examples/src/main/java/example/ClientExamples.java
+++ b/examples/src/main/java/example/ClientExamples.java
@@ -33,6 +33,22 @@ public class ClientExamples {
// END SNIPPET: proxy
}
+ @SuppressWarnings("unused")
+ public void createTimeouts() {
+ // START SNIPPET: timeouts
+ FhirContext ctx = new FhirContext();
+
+ // Set how long to try and establish the initial TCP connection (in ms)
+ ctx.getRestfulClientFactory().setConnectTimeout(20 * 1000);
+
+ // Set how long to block for individual read/write operations (in ms)
+ ctx.getRestfulClientFactory().setSocketTimeout(20 * 1000);
+
+ // Create the client
+ IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
+ // END SNIPPET: timeouts
+ }
+
@SuppressWarnings("unused")
public void createSecurity() {
// START SNIPPET: security
diff --git a/examples/src/main/java/example/GenericClientExample.java b/examples/src/main/java/example/GenericClientExample.java
index 1c0b4de6569..9b3ad44a95d 100644
--- a/examples/src/main/java/example/GenericClientExample.java
+++ b/examples/src/main/java/example/GenericClientExample.java
@@ -3,6 +3,8 @@ package example;
import java.util.ArrayList;
import java.util.List;
+import org.hl7.fhir.instance.model.IBaseResource;
+
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
@@ -74,30 +76,30 @@ public class GenericClientExample {
// END SNIPPET: create
}
{
- Patient patient = new Patient();
- // START SNIPPET: createConditional
- // One form
- MethodOutcome outcome = client.create()
- .resource(patient)
- .conditionalByUrl("Patient?identifier=system%7C00001")
- .execute();
+ Patient patient = new Patient();
+ // START SNIPPET: createConditional
+ // One form
+ MethodOutcome outcome = client.create()
+ .resource(patient)
+ .conditionalByUrl("Patient?identifier=system%7C00001")
+ .execute();
- // Another form
- MethodOutcome outcome2 = client.create()
- .resource(patient)
- .conditional()
- .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
- .execute();
-
- // This will return true if the server responded with an HTTP 201 created,
- // otherwise it will return null.
- Boolean created = outcome.getCreated();
-
- // The ID of the created, or the pre-existing resource
- IdDt id = outcome.getId();
- // END SNIPPET: createConditional
+ // Another form
+ MethodOutcome outcome2 = client.create()
+ .resource(patient)
+ .conditional()
+ .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
+ .execute();
+
+ // This will return true if the server responded with an HTTP 201 created,
+ // otherwise it will return null.
+ Boolean created = outcome.getCreated();
+
+ // The ID of the created, or the pre-existing resource
+ IdDt id = outcome.getId();
+ // END SNIPPET: createConditional
}
- {
+ {
// START SNIPPET: update
Patient patient = new Patient();
// ..populate the patient object..
@@ -125,21 +127,21 @@ public class GenericClientExample {
// END SNIPPET: update
}
{
- Patient patient = new Patient();
- // START SNIPPET: updateConditional
- client.update()
- .resource(patient)
- .conditionalByUrl("Patient?identifier=system%7C00001")
- .execute();
-
- client.update()
- .resource(patient)
- .conditional()
- .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
- .execute();
- // END SNIPPET: updateConditional
+ Patient patient = new Patient();
+ // START SNIPPET: updateConditional
+ client.update()
+ .resource(patient)
+ .conditionalByUrl("Patient?identifier=system%7C00001")
+ .execute();
+
+ client.update()
+ .resource(patient)
+ .conditional()
+ .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
+ .execute();
+ // END SNIPPET: updateConditional
}
- {
+ {
// START SNIPPET: etagupdate
// First, let's retrive the latest version of a resource
// from the server
@@ -176,26 +178,26 @@ public class GenericClientExample {
}
{
// START SNIPPET: delete
- BaseOperationOutcome resp = client.delete().resourceById(new IdDt("Patient", "1234")).execute();
+ BaseOperationOutcome resp = client.delete().resourceById(new IdDt("Patient", "1234")).execute();
// outcome may be null if the server didn't return one
- if (resp != null) {
- OperationOutcome outcome = (OperationOutcome) resp;
+ if (resp != null) {
+ OperationOutcome outcome = (OperationOutcome) resp;
System.out.println(outcome.getIssueFirstRep().getDetailsElement().getValue());
}
// END SNIPPET: delete
}
- {
- // START SNIPPET: deleteConditional
- client.delete()
- .resourceConditionalByUrl("Patient?identifier=system%7C00001")
- .execute();
-
- client.delete()
- .resourceConditionalByType("Patient")
- .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
- .execute();
- // END SNIPPET: deleteConditional
+ {
+ // START SNIPPET: deleteConditional
+ client.delete()
+ .resourceConditionalByUrl("Patient?identifier=system%7C00001")
+ .execute();
+
+ client.delete()
+ .resourceConditionalByType("Patient")
+ .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
+ .execute();
+ // END SNIPPET: deleteConditional
}
{
// START SNIPPET: search
@@ -273,7 +275,7 @@ public class GenericClientExample {
// .. populate this list - note that you can also pass in a populated
// Bundle if you want to create one manually ..
- List response = client.transaction().withResources(resources).execute();
+ List response = client.transaction().withResources(resources).execute();
// END SNIPPET: transaction
}
diff --git a/examples/src/main/java/example/PagingPatientProvider.java b/examples/src/main/java/example/PagingPatientProvider.java
index 665fd43652d..b106e9f1f28 100644
--- a/examples/src/main/java/example/PagingPatientProvider.java
+++ b/examples/src/main/java/example/PagingPatientProvider.java
@@ -2,6 +2,8 @@ package example;
import java.util.List;
+import org.hl7.fhir.instance.model.IBaseResource;
+
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.InstantDt;
@@ -43,7 +45,7 @@ public class PagingPatientProvider implements IResourceProvider {
}
@Override
- public List getResources(int theFromIndex, int theToIndex) {
+ public List getResources(int theFromIndex, int theToIndex) {
int end = Math.max(theToIndex, matchingResourceIds.size() - 1);
List idsToReturn = matchingResourceIds.subList(theFromIndex, end);
return loadResourcesByIds(idsToReturn);
@@ -65,7 +67,7 @@ public class PagingPatientProvider implements IResourceProvider {
/**
* Load a list of patient resources given their IDs
*/
- private List loadResourcesByIds(List theIdsToReturn) {
+ private List loadResourcesByIds(List theIdsToReturn) {
// .. implement this search against the database ..
return null;
}
diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml
index 5ec4621fa18..906337f3cd4 100644
--- a/hapi-fhir-android/pom.xml
+++ b/hapi-fhir-android/pom.xml
@@ -63,20 +63,22 @@
org.slf4jslf4j-android${slf4j_version}
- provided
-
-
+
+ org.slf4j
+ slf4j-api
+ ${slf4j_version}
+ test
+ commons-iocommons-io${commons_io_version}
+ test
-
+
javax.servletjavax.servlet-api
@@ -135,11 +137,10 @@
true
-
+
commons-codec:commons-codec
- commons-io:commons-ioca.uhn.hapi.fhir:hapi-fhir-baseca.uhn.hapi.fhir:hapi-fhir-structures-dstuca.uhn.hapi.fhir:hapi-fhir-structures-dstu2
@@ -148,7 +149,7 @@
javax.xml.stream:stax-apijavax.servlet:javax.servlet-apiorg.codehaus.woodstox:stax2-api
-
+
org.apache.commons:*org.apache.httpcomponents:*org.glassfish:javax.json
@@ -179,7 +180,7 @@
-
+
DIST
@@ -208,5 +209,5 @@
-
+
diff --git a/hapi-fhir-android/src/main/java/ca/uhn/fhir/android/AndroidLoader.java b/hapi-fhir-android/src/main/java/ca/uhn/fhir/android/AndroidLoader.java
new file mode 100644
index 00000000000..f7e1b685601
--- /dev/null
+++ b/hapi-fhir-android/src/main/java/ca/uhn/fhir/android/AndroidLoader.java
@@ -0,0 +1,14 @@
+package ca.uhn.fhir.android;
+
+import ca.uhn.fhir.context.FhirContext;
+
+public class AndroidLoader {
+
+ public static void main(String[] theArgs) {
+ FhirContext ctx = FhirContext.forDstu2();
+ ctx.newJsonParser();
+ ctx.newXmlParser();
+ ctx.newRestfulGenericClient("");
+ }
+
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
index 391be6b0157..afbf7c983be 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
@@ -368,6 +368,13 @@ public class FhirContext {
return new FhirTerser(this);
}
+ /**
+ * Create a new validator instance.
+ *
+ * Note on thread safety: Validators are thread safe, you may use a single validator
+ * in multiple threads. (This is in contrast to parsers)
+ *
+ */
public FhirValidator newValidator() {
return new FhirValidator(this);
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/BaseElement.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/BaseElement.java
index c86d26bf293..57acdcd8d8c 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/BaseElement.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/BaseElement.java
@@ -91,7 +91,7 @@ public abstract class BaseElement implements IElement, ISupportsUndeclaredExtens
if (myUndeclaredExtensions == null) {
myUndeclaredExtensions = new ArrayList();
}
- return Collections.unmodifiableList(myUndeclaredExtensions);
+ return (myUndeclaredExtensions);
}
@Override
@@ -111,7 +111,7 @@ public abstract class BaseElement implements IElement, ISupportsUndeclaredExtens
if (myUndeclaredModifierExtensions == null) {
myUndeclaredModifierExtensions = new ArrayList();
}
- return Collections.unmodifiableList(myUndeclaredModifierExtensions);
+ return (myUndeclaredModifierExtensions);
}
/**
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java
index a57b1f79c96..285307e5adc 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java
@@ -293,6 +293,7 @@ public class Bundle extends BaseBundle /* implements IElement */{
return myLinkSelf;
}
+ /*
public InstantDt getPublished() {
InstantDt retVal = (InstantDt) getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED);
if (retVal == null) {
@@ -301,6 +302,7 @@ public class Bundle extends BaseBundle /* implements IElement */{
}
return retVal;
}
+ */
/**
* Retrieves a resource from a bundle given its logical ID.
@@ -394,9 +396,11 @@ public class Bundle extends BaseBundle /* implements IElement */{
myCategories = theCategories;
}
+ /*
public void setPublished(InstantDt thePublished) {
getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, thePublished);
}
+ /*
public void setType(BoundCodeDt theType) {
myType = theType;
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ISupportsUndeclaredExtensions.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ISupportsUndeclaredExtensions.java
index 1c34760264b..73817e4e2cb 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ISupportsUndeclaredExtensions.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ISupportsUndeclaredExtensions.java
@@ -27,22 +27,28 @@ import org.hl7.fhir.instance.model.api.IBaseDatatype;
public interface ISupportsUndeclaredExtensions extends IElement {
/**
- * Returns a list containing all undeclared non-modifier extensions
+ * Returns a list containing all undeclared non-modifier extensions. The returned list
+ * is mutable, so it may be modified (e.g. to add or remove an extension).
*/
List getUndeclaredExtensions();
/**
- * Returns a list containing all undeclared extensions (modifier and non-modifier) by extension URL
+ * Returns an immutable list containing all undeclared extensions (modifier and non-modifier) by extension URL
+ *
+ * @see #getUndeclaredExtensions() To return a mutable list which may be used to remove extensions
*/
List getUndeclaredExtensionsByUrl(String theUrl);
/**
- * Returns an immutable list containing all extensions (modifier and non-modifier)
+ * Returns an immutable list containing all extensions (modifier and non-modifier).
+ *
+ * @see #getUndeclaredExtensions() To return a mutable list which may be used to remove extensions
*/
List getAllUndeclaredExtensions();
/**
- * Returns a list containing all undeclared modifier extensions
+ * Returns a list containing all undeclared modifier extensions. The returned list
+ * is mutable, so it may be modified (e.g. to add or remove an extension).
*/
List getUndeclaredModifierExtensions();
@@ -65,6 +71,8 @@ public interface ISupportsUndeclaredExtensions extends IElement {
/**
* Adds an extension to this object
+ *
+ * @see #getUndeclaredExtensions() To return a mutable list which may be used to remove extensions
*/
ExtensionDt addUndeclaredExtension(boolean theIsModifier, String theUrl, IBaseDatatype theValue);
@@ -72,6 +80,8 @@ public interface ISupportsUndeclaredExtensions extends IElement {
* Adds an extension to this object. This method is intended for use when
* an extension is being added which will contain child extensions, as opposed to
* a datatype.
+ *
+ * @see #getUndeclaredExtensions() To return a mutable list which may be used to remove extensions
*/
ExtensionDt addUndeclaredExtension(boolean theIsModifier, String theUrl);
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/BaseDateTimeDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/BaseDateTimeDt.java
index ea3a7b463b0..bc44b064bf6 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/BaseDateTimeDt.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/BaseDateTimeDt.java
@@ -28,6 +28,7 @@ import static ca.uhn.fhir.model.api.TemporalPrecisionEnum.YEAR;
import java.text.ParseException;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
@@ -64,7 +65,9 @@ public abstract class BaseDateTimeDt extends BasePrimitive {
private static final FastDateFormat ourYearMonthDayTimeZoneFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ");
private static final FastDateFormat ourYearMonthFormat = FastDateFormat.getInstance("yyyy-MM");
private static final FastDateFormat ourYearMonthNoDashesFormat = FastDateFormat.getInstance("yyyyMM");
- private static final Pattern ourYearMonthPattern = Pattern.compile("[0-9]{4}[0-9]{2}");
+ private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM);
+ private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM);
+ private static final Pattern ourYearMonthPattern = Pattern.compile("[0-9]{4}[0-9]{2}");
private static final Pattern ourYearPattern = Pattern.compile("[0-9]{4}");
static {
@@ -89,7 +92,55 @@ public abstract class BaseDateTimeDt extends BasePrimitive {
private boolean myTimeZoneZulu = false;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseDateTimeDt.class);
- /**
+ /**
+ * Returns a human readable version of this date/time using the system local format.
+ *
+ * Note on time zones: This method renders the value using the time zone
+ * that is contained within the value. For example, if this date object contains the
+ * value "2012-01-05T12:00:00-08:00", the human display will be rendered as "12:00:00"
+ * even if the application is being executed on a system in a different time zone. If
+ * this behaviour is not what you want, use {@link #toHumanDisplayLocalTimezone()}
+ * instead.
+ *
+ */
+ public String toHumanDisplay() {
+ TimeZone tz = getTimeZone();
+ Calendar value = tz != null ? Calendar.getInstance(tz) : Calendar.getInstance();
+ value.setTime(getValue());
+
+ switch (getPrecision()) {
+ case YEAR:
+ case MONTH:
+ case DAY:
+ return ourHumanDateFormat.format(value);
+ case MILLI:
+ case SECOND:
+ default:
+ return ourHumanDateTimeFormat.format(value);
+ }
+ }
+
+ /**
+ * Returns a human readable version of this date/time using the system local format,
+ * converted to the local timezone if neccesary.
+ *
+ * @see #toHumanDisplay() for a method which does not convert the time to the local
+ * timezone before rendering it.
+ */
+ public String toHumanDisplayLocalTimezone() {
+ switch (getPrecision()) {
+ case YEAR:
+ case MONTH:
+ case DAY:
+ return ourHumanDateFormat.format(getValue());
+ case MILLI:
+ case SECOND:
+ default:
+ return ourHumanDateTimeFormat.format(getValue());
+ }
+ }
+
+ /**
* Constructor
*/
public BaseDateTimeDt() {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/CodeDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/CodeDt.java
index 089e1117df6..c006b57f9ec 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/CodeDt.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/CodeDt.java
@@ -24,7 +24,6 @@ import static org.apache.commons.lang3.StringUtils.*;
import ca.uhn.fhir.model.api.BasePrimitive;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
-import ca.uhn.fhir.parser.DataFormatException;
@DatatypeDef(name = "code")
public class CodeDt extends BasePrimitive implements ICodedDatatype, Comparable {
@@ -44,6 +43,11 @@ public class CodeDt extends BasePrimitive implements ICodedDatatype, Com
setValue(theCode);
}
+ @Override
+ public boolean isEmpty() {
+ return super.isBaseEmpty() && isBlank(getValueAsString());
+ }
+
@Override
public int compareTo(CodeDt theCode) {
if (theCode == null) {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/XhtmlDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/XhtmlDt.java
index 5ec2f7a4bb1..acd0aae6b95 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/XhtmlDt.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/XhtmlDt.java
@@ -48,6 +48,11 @@ public class XhtmlDt extends BasePrimitive> {
// nothing
}
+ @Override
+ public boolean isEmpty() {
+ return super.isBaseEmpty() && (getValue() == null || getValue().isEmpty());
+ }
+
/**
* Constructor which accepts a string code
*
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
index a5ac3b2a5ca..79c3a32dcec 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
@@ -95,19 +95,20 @@ import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.base.composite.BaseNarrativeDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
+import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.model.primitive.StringDt;
+import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.util.ElementUtil;
import ca.uhn.fhir.util.UrlUtil;
/**
- * This class is the FHIR JSON parser/encoder. Users should not interact with this class directly, but should use
- * {@link FhirContext#newJsonParser()} to get an instance.
+ * This class is the FHIR JSON parser/encoder. Users should not interact with this class directly, but should use {@link FhirContext#newJsonParser()} to get an instance.
*/
public class JsonParser extends BaseParser implements IParser {
@@ -196,7 +197,6 @@ public class JsonParser extends BaseParser implements IParser {
writeTagWithTextNode(eventWriter, "title", theBundle.getTitle());
writeTagWithTextNode(eventWriter, "id", theBundle.getBundleId());
writeOptionalTagWithTextNode(eventWriter, "updated", theBundle.getUpdated());
- writeOptionalTagWithTextNode(eventWriter, "published", theBundle.getPublished());
boolean linkStarted = false;
linkStarted = writeAtomLinkInDstu1Format(eventWriter, "self", theBundle.getLinkSelf(), linkStarted);
@@ -353,7 +353,8 @@ public class JsonParser extends BaseParser implements IParser {
theEventWriter.writeEnd();
}
- private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theWriter, IBase theNextValue, BaseRuntimeElementDefinition> theChildDef, String theChildName, boolean theIsSubElementWithinResource) throws IOException {
+ private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theWriter, IBase theNextValue,
+ BaseRuntimeElementDefinition> theChildDef, String theChildName, boolean theContainedResource) throws IOException {
switch (theChildDef.getChildType()) {
case ID_DATATYPE: {
@@ -414,7 +415,7 @@ public class JsonParser extends BaseParser implements IParser {
if (theNextValue instanceof IBaseExtension) {
theWriter.write("url", ((IBaseExtension>) theNextValue).getUrl());
}
- encodeCompositeElementToStreamWriter(theResDef, theResource, theNextValue, theWriter, childCompositeDef, theIsSubElementWithinResource);
+ encodeCompositeElementToStreamWriter(theResDef, theResource, theNextValue, theWriter, childCompositeDef, theContainedResource);
theWriter.writeEnd();
break;
}
@@ -488,7 +489,8 @@ public class JsonParser extends BaseParser implements IParser {
}
- private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, List extends BaseRuntimeChildDefinition> theChildren, boolean theIsSubElementWithinResource) throws IOException {
+ private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter,
+ List extends BaseRuntimeChildDefinition> theChildren, boolean theContainedResource) throws IOException {
for (BaseRuntimeChildDefinition nextChild : theChildren) {
if (nextChild.getElementName().equals("extension") || nextChild.getElementName().equals("modifierExtension")) {
continue;
@@ -503,19 +505,19 @@ public class JsonParser extends BaseParser implements IParser {
if (gen != null) {
BaseNarrativeDt> narr = ((IResource) theResource).getText();
gen.generateNarrative(theResDef.getResourceProfile(), theResource, narr);
- if (narr != null) {
+ if (narr != null && !narr.isEmpty()) {
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
BaseRuntimeElementDefinition> type = child.getChildByName(childName);
- encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, type, childName, theIsSubElementWithinResource);
+ encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, type, childName, theContainedResource);
continue;
}
}
} else if (nextChild instanceof RuntimeChildContainedResources) {
- if (theIsSubElementWithinResource == false) {
+ if (theContainedResource == false) {
String childName = nextChild.getValidChildNames().iterator().next();
BaseRuntimeElementDefinition> child = nextChild.getChildByName(childName);
- encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, null, child, childName, theIsSubElementWithinResource);
+ encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, null, child, childName, theContainedResource);
}
continue;
}
@@ -535,7 +537,7 @@ public class JsonParser extends BaseParser implements IParser {
for (IBase nextValue : values) {
if (nextValue == null || nextValue.isEmpty()) {
if (nextValue instanceof BaseContainedDt) {
- if (theIsSubElementWithinResource || getContainedResources().isEmpty()) {
+ if (theContainedResource || getContainedResources().isEmpty()) {
continue;
}
} else {
@@ -551,7 +553,7 @@ public class JsonParser extends BaseParser implements IParser {
}
boolean primitive = childDef.getChildType() == ChildTypeEnum.PRIMITIVE_DATATYPE;
- if ((childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES||childDef.getChildType()==ChildTypeEnum.CONTAINED_RESOURCE_LIST) && theIsSubElementWithinResource) {
+ if (childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES && theContainedResource) {
continue;
}
@@ -573,15 +575,15 @@ public class JsonParser extends BaseParser implements IParser {
if (nextChild.getMax() > 1 || nextChild.getMax() == Child.MAX_UNLIMITED) {
theEventWriter.writeStartArray(childName);
inArray = true;
- encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theIsSubElementWithinResource);
- } else if (nextChild instanceof RuntimeChildNarrativeDefinition && theIsSubElementWithinResource) {
+ encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource);
+ } else if (nextChild instanceof RuntimeChildNarrativeDefinition && theContainedResource) {
// suppress narratives from contained resources
} else {
- encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theIsSubElementWithinResource);
+ encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theContainedResource);
}
currentChildName = childName;
} else {
- encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theIsSubElementWithinResource);
+ encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource);
}
if (primitive) {
@@ -655,13 +657,15 @@ public class JsonParser extends BaseParser implements IParser {
}
}
- private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, BaseRuntimeElementCompositeDefinition> resDef, boolean theIsSubElementWithinResource) throws IOException, DataFormatException {
+ private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter,
+ BaseRuntimeElementCompositeDefinition> resDef, boolean theContainedResource) throws IOException, DataFormatException {
extractAndWriteExtensionsAsDirectChild(theNextValue, theEventWriter, resDef, theResDef, theResource, null);
- encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getExtensions(), theIsSubElementWithinResource);
- encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getChildren(), theIsSubElementWithinResource);
+ encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getExtensions(), theContainedResource);
+ encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getChildren(), theContainedResource);
}
- private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theContainedResource) throws IOException {
+ private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theContainedResource)
+ throws IOException {
String resourceId = null;
if (theResource instanceof IResource) {
IResource res = (IResource) theResource;
@@ -674,7 +678,7 @@ public class JsonParser extends BaseParser implements IParser {
}
} else if (theResource instanceof IAnyResource) {
IAnyResource res = (IAnyResource) theResource;
- if (StringUtils.isNotBlank(res.getId().getIdPart())) {
+ if (theContainedResource && StringUtils.isNotBlank(res.getId().getIdPart())) {
resourceId = res.getId().getIdPart();
}
}
@@ -702,20 +706,22 @@ public class JsonParser extends BaseParser implements IParser {
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1) && theResource instanceof IResource) {
IResource resource = (IResource) theResource;
+ // Object securityLabelRawObj =
+ List securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
+ List profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
+ TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(resource);
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
IdDt resourceId = resource.getId();
String versionIdPart = resourceId.getVersionIdPart();
if (isBlank(versionIdPart)) {
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
}
- List securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
- List profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
- TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(resource);
+
if (ElementUtil.isEmpty(versionIdPart, updated, securityLabels, profiles) == false) {
theEventWriter.writeStartObject("meta");
- writeOptionalTagWithTextNode(theEventWriter, "versionId", resource.getId().getVersionIdPart());
- writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", ResourceMetadataKeyEnum.UPDATED.get(resource));
+ writeOptionalTagWithTextNode(theEventWriter, "versionId", versionIdPart);
+ writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", updated);
if (profiles != null && profiles.isEmpty() == false) {
theEventWriter.writeStartArray("profile");
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java
index 9e6fd5ef497..a2b83d03ab7 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java
@@ -683,8 +683,6 @@ class ParserState {
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
if ("entry".equals(theLocalPart) && verifyNamespace(XmlParser.ATOM_NS, theNamespaceURI)) {
push(new AtomEntryState(myInstance, myResourceType));
- } else if (theLocalPart.equals("published")) {
- push(new AtomPrimitiveState(myInstance.getPublished()));
} else if (theLocalPart.equals("title")) {
push(new AtomPrimitiveState(myInstance.getTitle()));
} else if ("id".equals(theLocalPart)) {
@@ -1619,12 +1617,12 @@ class ParserState {
return;
}
case RESOURCE: {
- if (myInstance instanceof IResource) {
+ if (myInstance instanceof IResource || myInstance instanceof IElement) {
ParserState.PreResourceStateHapi state = new PreResourceStateHapi(myInstance, child.getMutator(), null);
push(state);
} else {
- ParserState.PreResourceStateHl7Org state = new PreResourceStateHl7Org(myInstance, child.getMutator(), null);
- push(state);
+ ParserState.PreResourceStateHl7Org state = new PreResourceStateHl7Org(myInstance, child.getMutator(), null);
+ push(state);
}
return;
}
@@ -1732,7 +1730,7 @@ class ParserState {
private class SecurityLabelElementStateHapi extends ElementCompositeState {
- public SecurityLabelElementStateHapi(ParserState.PreResourceState thePreResourceState,BaseRuntimeElementCompositeDefinition> theDef, BaseCodingDt codingDt) {
+ public SecurityLabelElementStateHapi(ParserState.PreResourceState thePreResourceState, BaseRuntimeElementCompositeDefinition> theDef, BaseCodingDt codingDt) {
super(thePreResourceState, theDef, codingDt);
}
@@ -1774,7 +1772,7 @@ class ParserState {
securityLabels = new ArrayList();
myMap.put(ResourceMetadataKeyEnum.SECURITY_LABELS, securityLabels);
}
- BaseCodingDt securityLabel= myContext.getVersion().newCodingDt();
+ BaseCodingDt securityLabel = myContext.getVersion().newCodingDt();
BaseRuntimeElementCompositeDefinition> codinfDef = (BaseRuntimeElementCompositeDefinition>) myContext.getElementDefinition(securityLabel.getClass());
push(new SecurityLabelElementStateHapi(getPreResourceState(), codinfDef, securityLabel));
securityLabels.add(securityLabel);
@@ -1900,7 +1898,7 @@ class ParserState {
@Override
public void wereBack() {
super.wereBack();
- if (myEntry == null) {
+ if (myEntry == null && myMutator == null) {
myObject = (T) getCurrentElement();
}
@@ -2068,7 +2066,7 @@ class ParserState {
terser.visit(myInstance, new IModelVisitor() {
@Override
- public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition) {
+ public void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition) {
if (theElement instanceof BaseResourceReferenceDt) {
BaseResourceReferenceDt nextRef = (BaseResourceReferenceDt) theElement;
String ref = nextRef.getReference().getValue();
@@ -2099,8 +2097,8 @@ class ParserState {
}
@Override
- public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition, ExtensionDt theNextExt) {
- acceptElement(theNextExt.getValue(), null, null);
+ public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition, ExtensionDt theNextExt) {
+ acceptElement(theNextExt.getValue(), null, null, null);
}
});
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java
index e513f6035f9..7f304958395 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java
@@ -271,7 +271,6 @@ public class XmlParser extends BaseParser implements IParser {
}
writeOptionalTagWithTextNode(eventWriter, "updated", theBundle.getUpdated());
- writeOptionalTagWithTextNode(eventWriter, "published", theBundle.getPublished());
if (StringUtils.isNotBlank(theBundle.getAuthorName().getValue())) {
eventWriter.writeStartElement("author");
@@ -804,6 +803,7 @@ public class XmlParser extends BaseParser implements IParser {
if (updated != null) {
writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString());
}
+
for (IdDt profile : profiles) {
theEventWriter.writeStartElement("profile");
theEventWriter.writeAttribute("value", profile.getValue());
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java
index 63e58755f95..70cf63a0f84 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java
@@ -135,7 +135,7 @@ public class MethodOutcome {
}
/**
- * This will be set to {@link Boolean#TRUE} for instance of MethodOutcome which are
+ * This will be set to {@link Boolean#TRUE} for instance of MethodOutcome which are
* returned to client instances, if the server has responded with an HTTP 201 Created.
*/
public Boolean getCreated() {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java
index 1dd36b03c4b..a7b20c73c5d 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java
@@ -153,10 +153,14 @@ public abstract class BaseClient implements IRestfulClient {
return invokeClient(theContext, binding, clientInvocation, null, null, theLogRequestAndResponse);
}
+ void forceConformanceCheck() {
+ myFactory.validateServerBase(myUrlBase, myClient, this);
+ }
+
T invokeClient(FhirContext theContext, IClientResponseHandler binding, BaseHttpClientInvocation clientInvocation, EncodingEnum theEncoding, Boolean thePrettyPrint, boolean theLogRequestAndResponse) {
if (!myDontValidateConformance) {
- myFactory.validateServerBaseIfConfiguredToDoSo(myUrlBase, myClient);
+ myFactory.validateServerBaseIfConfiguredToDoSo(myUrlBase, myClient, this);
}
// TODO: handle non 2xx status codes by throwing the correct exception,
@@ -369,7 +373,7 @@ public abstract class BaseClient implements IRestfulClient {
}
/**
- * This method is an internal part of the HAPI API andmay change, use with caution. If you
+ * This method is an internal part of the HAPI API and may change, use with caution. If you
* want to disable the loading of conformance statements, use {@link IRestfulClientFactory#setServerValidationModeEnum(ServerValidationModeEnum)}
*/
public void setDontValidateConformance(boolean theDontValidateConformance) {
@@ -441,4 +445,8 @@ public abstract class BaseClient implements IRestfulClient {
return reader;
}
+ public List getInterceptors() {
+ return Collections.unmodifiableList(myInterceptors);
+ }
+
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java
index c2a595f64b6..aa43b5def18 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java
@@ -33,6 +33,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.http.client.HttpClient;
@@ -144,7 +145,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
super(theHttpClient, theServerBase, theFactory);
myContext = theContext;
}
-
@Override
public BaseConformance conformance() {
@@ -165,6 +165,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
return resp;
}
+ @Override
+ public void forceConformanceCheck() {
+ super.forceConformanceCheck();
+ }
+
@Override
public ICreate create() {
return new CreateInternal();
@@ -590,23 +595,14 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
protected IBaseResource parseResourceBody(String theResourceBody) {
- EncodingEnum encoding = null;
- for (int i = 0; i < theResourceBody.length() && encoding == null; i++) {
- switch (theResourceBody.charAt(i)) {
- case '<':
- encoding = EncodingEnum.XML;
- break;
- case '{':
- encoding = EncodingEnum.JSON;
- break;
- }
- }
+ EncodingEnum encoding = MethodUtil.detectEncodingNoDefault(theResourceBody);
if (encoding == null) {
throw new InvalidRequestException("FHIR client can't determine resource encoding");
}
return encoding.newParser(myContext).parseResource(theResourceBody);
}
+
@SuppressWarnings("unchecked")
@Override
public T prettyPrint() {
@@ -615,7 +611,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
}
-
+
private final class BundleResponseHandler implements IClientResponseHandler {
private Class extends IBaseResource> myType;
@@ -636,6 +632,15 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
}
+ private final class StringResponseHandler implements IClientResponseHandler {
+
+ @Override
+ public String invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException,
+ BaseServerResponseException {
+ return IOUtils.toString(theResponseReader);
+ }
+ }
+
private class CreateInternal extends BaseClientExecutable implements ICreate, ICreateTyped, ICreateWithQuery, ICreateWithQueryTyped {
private CriterionList myCriterionList;
@@ -1574,14 +1579,16 @@ public class GenericClient extends BaseClient implements IGenericClient {
private final class TransactionExecutable extends BaseClientExecutable, T> implements ITransactionTyped {
private Bundle myBundle;
- private List myResources;
+ private List extends IBaseResource> myResources;
private IBaseBundle myBaseBundle;
+ private String myRawBundle;
+ private EncodingEnum myRawBundleEncoding;
public TransactionExecutable(Bundle theResources) {
myBundle = theResources;
}
- public TransactionExecutable(List theResources) {
+ public TransactionExecutable(List extends IBaseResource> theResources) {
myResources = theResources;
}
@@ -1589,6 +1596,14 @@ public class GenericClient extends BaseClient implements IGenericClient {
myBaseBundle = theBundle;
}
+ public TransactionExecutable(String theBundle) {
+ myRawBundle = theBundle;
+ myRawBundleEncoding = MethodUtil.detectEncodingNoDefault(myRawBundle);
+ if (myRawBundleEncoding == null) {
+ throw new IllegalArgumentException("Can not determine encoding of raw resource body");
+ }
+ }
+
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public T execute() {
@@ -1601,6 +1616,19 @@ public class GenericClient extends BaseClient implements IGenericClient {
ResourceResponseHandler binding = new ResourceResponseHandler(myBaseBundle.getClass(), null);
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myBaseBundle, myContext);
return (T) invoke(params, binding, invocation);
+ } else if (myRawBundle != null) {
+ StringResponseHandler binding = new StringResponseHandler();
+ /*
+ * If the user has explicitly requested a given encoding, we may need to reencode the raw string
+ */
+ if (getParamEncoding() != null) {
+ if (MethodUtil.detectEncodingNoDefault(myRawBundle) != getParamEncoding()) {
+ IBaseResource parsed = parseResourceBody(myRawBundle);
+ myRawBundle = getParamEncoding().newParser(getFhirContext()).encodeResourceToString(parsed);
+ }
+ }
+ BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myRawBundle, myContext);
+ return (T) invoke(params, binding, invocation);
} else {
BundleResponseHandler binding = new BundleResponseHandler(null);
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myBundle, myContext);
@@ -1619,7 +1647,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
@Override
- public ITransactionTyped> withResources(List theResources) {
+ public ITransactionTyped> withResources(List extends IBaseResource> theResources) {
Validate.notNull(theResources, "theResources must not be null");
return new TransactionExecutable>(theResources);
}
@@ -1630,6 +1658,12 @@ public class GenericClient extends BaseClient implements IGenericClient {
return new TransactionExecutable(theBundle);
}
+ @Override
+ public ITransactionTyped withBundle(String theBundle) {
+ Validate.notBlank(theBundle, "theBundle must not be null");
+ return new TransactionExecutable(theBundle);
+ }
+
}
private class UpdateInternal extends BaseClientExecutable implements IUpdate, IUpdateTyped, IUpdateExecutable, IUpdateWithQuery, IUpdateWithQueryTyped {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java
index ae7f01030b3..996e6f7dfb3 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java
@@ -34,6 +34,8 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.api.IRestfulClient;
+import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
+import ca.uhn.fhir.rest.client.exceptions.FhirClientInnapropriateForServerException;
import ca.uhn.fhir.rest.gclient.ICreate;
import ca.uhn.fhir.rest.gclient.IDelete;
import ca.uhn.fhir.rest.gclient.IFetchConformanceUntyped;
@@ -109,6 +111,16 @@ public interface IGenericClient extends IRestfulClient {
@Deprecated
MethodOutcome delete(Class extends IResource> theType, String theId);
+ /**
+ * Force the client to fetch the server's conformance statement and validate that it is appropriate for this client.
+ *
+ * @throws FhirClientConnectionException
+ * if the conformance statement cannot be read, or if the client
+ * @throws FhirClientInnapropriateForServerException
+ * If the conformance statement indicates that the server is inappropriate for this client (e.g. it implements the wrong version of FHIR)
+ */
+ void forceConformanceCheck() throws FhirClientConnectionException;
+
/**
* Fluent method for the "get tags" operation
*/
@@ -123,17 +135,15 @@ public interface IGenericClient extends IRestfulClient {
* Implementation of the "history instance" method.
*
* @param theType
- * The type of resource to return the history for, or
- * null to search for history across all resources
+ * The type of resource to return the history for, or null to search for history across all resources
* @param theId
- * The ID of the resource to return the history for, or null to search for all resource
- * instances. Note that if this param is not null, theType must also not be null
+ * The ID of the resource to return the history for, or null to search for all resource instances. Note that if this param is not null, theType must also not
+ * be null
* @param theSince
* If not null, request that the server only return resources updated since this time
* @param theLimit
- * If not null, request that the server return no more than this number of resources. Note that the
- * server may return less even if more are available, but should not return more according to the FHIR
- * specification.
+ * If not null, request that the server return no more than this number of resources. Note that the server may return less even if more are available, but should not return more
+ * according to the FHIR specification.
* @return A bundle containing returned resources
* @deprecated As of 0.9, use the fluent {@link #history()} method instead
*/
@@ -144,49 +154,46 @@ public interface IGenericClient extends IRestfulClient {
* Implementation of the "history instance" method.
*
* @param theType
- * The type of resource to return the history for, or
- * null to search for history across all resources
+ * The type of resource to return the history for, or null to search for history across all resources
* @param theId
- * The ID of the resource to return the history for, or null to search for all resource
- * instances. Note that if this param is not null, theType must also not be null
+ * The ID of the resource to return the history for, or null to search for all resource instances. Note that if this param is not null, theType must also not
+ * be null
* @param theSince
* If not null, request that the server only return resources updated since this time
* @param theLimit
- * If not null, request that the server return no more than this number of resources. Note that the
- * server may return less even if more are available, but should not return more according to the FHIR
- * specification.
+ * If not null, request that the server return no more than this number of resources. Note that the server may return less even if more are available, but should not return more
+ * according to the FHIR specification.
* @return A bundle containing returned resources
* @deprecated As of 0.9, use the fluent {@link #history()} method instead
*/
@Deprecated
Bundle history(Class theType, String theId, DateTimeDt theSince, Integer theLimit);
+ // /**
+ // * Implementation of the "instance read" method. This method will only ever do a "read" for the latest version of a
+ // * given resource instance, even if the ID passed in contains a version. If you wish to request a specific version
+ // * of a resource (the "vread" operation), use {@link #vread(Class, IdDt)} instead.
+ // *
+ // * Note that if an absolute resource ID is passed in (i.e. a URL containing a protocol and host as well as the
+ // * resource type and ID) the server base for the client will be ignored, and the URL passed in will be queried.
+ // *
+ // *
+ // * @param theType
+ // * The type of resource to load
+ // * @param theId
+ // * The ID to load, including the resource ID and the resource version ID. Valid values include
+ // * "Patient/123/_history/222", or "http://example.com/fhir/Patient/123/_history/222"
+ // * @return The resource
+ // */
+ // T read(Class theType, IdDt theId);
+
/**
- * Loads the previous/next bundle of resources from a paged set, using the link specified in the "link type=next"
- * tag within the atom bundle.
+ * Loads the previous/next bundle of resources from a paged set, using the link specified in the "link type=next" tag within the atom bundle.
*
* @see Bundle#getLinkNext()
*/
IGetPage loadPage();
-// /**
-// * Implementation of the "instance read" method. This method will only ever do a "read" for the latest version of a
-// * given resource instance, even if the ID passed in contains a version. If you wish to request a specific version
-// * of a resource (the "vread" operation), use {@link #vread(Class, IdDt)} instead.
-// *
-// * Note that if an absolute resource ID is passed in (i.e. a URL containing a protocol and host as well as the
-// * resource type and ID) the server base for the client will be ignored, and the URL passed in will be queried.
-// *
-// *
-// * @param theType
-// * The type of resource to load
-// * @param theId
-// * The ID to load, including the resource ID and the resource version ID. Valid values include
-// * "Patient/123/_history/222", or "http://example.com/fhir/Patient/123/_history/222"
-// * @return The resource
-// */
-// T read(Class theType, IdDt theId);
-
/**
* Implementation of the FHIR "extended operations" action
*/
@@ -229,8 +236,7 @@ public interface IGenericClient extends IRestfulClient {
IBaseResource read(UriDt theUrl);
/**
- * Register a new interceptor for this client. An interceptor can be used to add additional logging, or add security
- * headers, or pre-process responses, etc.
+ * Register a new interceptor for this client. An interceptor can be used to add additional logging, or add security headers, or pre-process responses, etc.
*/
void registerInterceptor(IClientInterceptor theInterceptor);
@@ -259,8 +265,8 @@ public interface IGenericClient extends IRestfulClient {
Bundle search(UriDt theUrl);
/**
- * If set to true, the client will log all requests and all responses. This is probably not a good
- * production setting since it will result in a lot of extra logging, but it can be useful for troubleshooting.
+ * If set to true, the client will log all requests and all responses. This is probably not a good production setting since it will result in a lot of extra logging, but it can be
+ * useful for troubleshooting.
*
* @param theLogRequestAndResponse
* Should requests and responses be logged
@@ -277,8 +283,7 @@ public interface IGenericClient extends IRestfulClient {
*
* @param theResources
* The resources to create/update in a single transaction
- * @return A list of resource stubs (these will not be fully populated) containing IDs and other
- * {@link IResource#getResourceMetadata() metadata}
+ * @return A list of resource stubs (these will not be fully populated) containing IDs and other {@link IResource#getResourceMetadata() metadata}
* @deprecated Use {@link #transaction()}
*
*/
@@ -286,8 +291,7 @@ public interface IGenericClient extends IRestfulClient {
List transaction(List theResources);
/**
- * Remove an intercaptor that was previously registered using
- * {@link IRestfulClient#registerInterceptor(IClientInterceptor)}
+ * Remove an intercaptor that was previously registered using {@link IRestfulClient#registerInterceptor(IClientInterceptor)}
*/
void unregisterInterceptor(IClientInterceptor theInterceptor);
@@ -328,18 +332,16 @@ public interface IGenericClient extends IRestfulClient {
MethodOutcome validate(IResource theResource);
/**
- * Implementation of the "instance vread" method. Note that this method expects theId to contain a
- * resource ID as well as a version ID, and will fail if it does not.
+ * Implementation of the "instance vread" method. Note that this method expects theId to contain a resource ID as well as a version ID, and will fail if it does not.
*
- * Note that if an absolute resource ID is passed in (i.e. a URL containing a protocol and host as well as the
- * resource type and ID) the server base for the client will be ignored, and the URL passed in will be queried.
+ * Note that if an absolute resource ID is passed in (i.e. a URL containing a protocol and host as well as the resource type and ID) the server base for the client will be ignored, and the URL
+ * passed in will be queried.
*
*
* @param theType
* The type of resource to load
* @param theId
- * The ID to load, including the resource ID and the resource version ID. Valid values include
- * "Patient/123/_history/222", or "http://example.com/fhir/Patient/123/_history/222"
+ * The ID to load, including the resource ID and the resource version ID. Valid values include "Patient/123/_history/222", or "http://example.com/fhir/Patient/123/_history/222"
* @return The resource
*/
T vread(Class theType, IdDt theId);
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IRestfulClientFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IRestfulClientFactory.java
index 35bb74541a0..6af4fed94a9 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IRestfulClientFactory.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IRestfulClientFactory.java
@@ -72,6 +72,12 @@ public interface IRestfulClientFactory {
*/
HttpClient getHttpClient();
+ /**
+ * @deprecated Use {@link #getServerValidationMode()} instead
+ */
+ @Deprecated
+ ServerValidationModeEnum getServerValidationModeEnum();
+
/**
* Gets the server validation mode for any clients created from this factory. Server
* validation involves the client requesting the server's conformance statement
@@ -79,8 +85,10 @@ public interface IRestfulClientFactory {
*
* The default value for this setting is defined by {@link #DEFAULT_SERVER_VALIDATION_MODE}
*
+ *
+ * @since 1.0
*/
- ServerValidationModeEnum getServerValidationModeEnum();
+ ServerValidationModeEnum getServerValidationMode();
/**
* Gets the socket timeout, in milliseconds. This is the SO_TIMEOUT time, which is the amount of time that a
@@ -158,6 +166,12 @@ public interface IRestfulClientFactory {
*/
void setProxyCredentials(String theUsername, String thePassword);
+ /**
+ * @deprecated Use {@link #setServerValidationMode(ServerValidationModeEnum)} instead. This method was incorrectly named.
+ */
+ @Deprecated
+ void setServerValidationModeEnum(ServerValidationModeEnum theServerValidationMode);
+
/**
* Sets the server validation mode for any clients created from this factory. Server
* validation involves the client requesting the server's conformance statement
@@ -165,8 +179,10 @@ public interface IRestfulClientFactory {
*
* The default value for this setting is defined by {@link #DEFAULT_SERVER_VALIDATION_MODE}
*
+ *
+ * @since 1.0
*/
- void setServerValidationModeEnum(ServerValidationModeEnum theServerValidationMode);
+ void setServerValidationMode(ServerValidationModeEnum theServerValidationMode);
/**
* Sets the socket timeout, in milliseconds. This is the SO_TIMEOUT time, which is the amount of time that a
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java
index 021816d07a9..d113e2f16ec 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/RestfulClientFactory.java
@@ -51,6 +51,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
+import ca.uhn.fhir.rest.client.exceptions.FhirClientInnapropriateForServerException;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.FhirTerser;
@@ -137,7 +138,7 @@ public class RestfulClientFactory implements IRestfulClientFactory {
}
@Override
- public ServerValidationModeEnum getServerValidationModeEnum() {
+ public ServerValidationModeEnum getServerValidationMode() {
return myServerValidationMode;
}
@@ -195,25 +196,29 @@ public class RestfulClientFactory implements IRestfulClientFactory {
/**
* This method is internal to HAPI - It may change in future versions, use with caution.
*/
- public void validateServerBaseIfConfiguredToDoSo(String theServerBase, HttpClient theHttpClient) {
- String serverBase = theServerBase;
- if (!serverBase.endsWith("/")) {
- serverBase = serverBase + "/";
- }
+ public void validateServerBaseIfConfiguredToDoSo(String theServerBase, HttpClient theHttpClient, BaseClient theClient) {
+ String serverBase = normalizeBaseUrlForMap(theServerBase);
switch (myServerValidationMode) {
case NEVER:
break;
case ONCE:
if (!myValidatedServerBaseUrls.contains(serverBase)) {
- validateServerBase(serverBase, theHttpClient);
- myValidatedServerBaseUrls.add(serverBase);
+ validateServerBase(serverBase, theHttpClient, theClient);
}
break;
}
}
+ private String normalizeBaseUrlForMap(String theServerBase) {
+ String serverBase = theServerBase;
+ if (!serverBase.endsWith("/")) {
+ serverBase = serverBase + "/";
+ }
+ return serverBase;
+ }
+
@Override
public synchronized void setConnectionRequestTimeout(int theConnectionRequestTimeout) {
myConnectionRequestTimeout = theConnectionRequestTimeout;
@@ -258,7 +263,7 @@ public class RestfulClientFactory implements IRestfulClientFactory {
}
@Override
- public void setServerValidationModeEnum(ServerValidationModeEnum theServerValidationMode) {
+ public void setServerValidationMode(ServerValidationModeEnum theServerValidationMode) {
Validate.notNull(theServerValidationMode, "theServerValidationMode may not be null");
myServerValidationMode = theServerValidationMode;
}
@@ -269,10 +274,12 @@ public class RestfulClientFactory implements IRestfulClientFactory {
myHttpClient = null;
}
- @SuppressWarnings("unchecked")
- private void validateServerBase(String theServerBase, HttpClient theHttpClient) {
+ void validateServerBase(String theServerBase, HttpClient theHttpClient, BaseClient theClient) {
GenericClient client = new GenericClient(myContext, theHttpClient, theServerBase, this);
+ for (IClientInterceptor interceptor : theClient.getInterceptors()) {
+ client.registerInterceptor(interceptor);
+ }
client.setDontValidateConformance(true);
IBaseResource conformance;
@@ -296,7 +303,9 @@ public class RestfulClientFactory implements IRestfulClientFactory {
} else {
if (serverFhirVersionString.startsWith("0.80") || serverFhirVersionString.startsWith("0.0.8")) {
serverFhirVersionEnum = FhirVersionEnum.DSTU1;
- } else if (serverFhirVersionString.startsWith("0.4") || serverFhirVersionString.startsWith("0.5")) {
+ } else if (serverFhirVersionString.startsWith("0.4")) {
+ serverFhirVersionEnum = FhirVersionEnum.DSTU2;
+ } else if (serverFhirVersionString.startsWith("0.5")) {
serverFhirVersionEnum = FhirVersionEnum.DSTU2;
} else {
// we'll be lenient and accept this
@@ -307,9 +316,22 @@ public class RestfulClientFactory implements IRestfulClientFactory {
if (serverFhirVersionEnum != null) {
FhirVersionEnum contextFhirVersion = myContext.getVersion().getVersion();
if (!contextFhirVersion.isEquivalentTo(serverFhirVersionEnum)) {
- throw new FhirClientConnectionException(myContext.getLocalizer().getMessage(RestfulClientFactory.class, "wrongVersionInConformance", theServerBase + Constants.URL_TOKEN_METADATA, serverFhirVersionString, serverFhirVersionEnum, contextFhirVersion));
+ throw new FhirClientInnapropriateForServerException(myContext.getLocalizer().getMessage(RestfulClientFactory.class, "wrongVersionInConformance", theServerBase + Constants.URL_TOKEN_METADATA, serverFhirVersionString, serverFhirVersionEnum, contextFhirVersion));
}
}
+
+ myValidatedServerBaseUrls.add(normalizeBaseUrlForMap(theServerBase));
+
+ }
+
+ @Override
+ public ServerValidationModeEnum getServerValidationModeEnum() {
+ return getServerValidationMode();
+ }
+
+ @Override
+ public void setServerValidationModeEnum(ServerValidationModeEnum theServerValidationMode) {
+ setServerValidationMode(theServerValidationMode);
}
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/exceptions/FhirClientInnapropriateForServerException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/exceptions/FhirClientInnapropriateForServerException.java
new file mode 100644
index 00000000000..1e59d6dc0d9
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/exceptions/FhirClientInnapropriateForServerException.java
@@ -0,0 +1,46 @@
+package ca.uhn.fhir.rest.client.exceptions;
+
+/*
+ * #%L
+ * HAPI FHIR - Core Library
+ * %%
+ * Copyright (C) 2014 - 2015 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.rest.server.exceptions.BaseServerResponseException;
+
+/**
+ * This exception will be thrown by FHIR clients if the client attempts to
+ * communicate with a server which is a valid FHIR server but is incompatible
+ * with this client for some reason.
+ */
+public class FhirClientInnapropriateForServerException extends BaseServerResponseException {
+
+ private static final long serialVersionUID = 1L;
+
+ public FhirClientInnapropriateForServerException(Throwable theCause) {
+ super(0, theCause);
+ }
+
+ public FhirClientInnapropriateForServerException(String theMessage, Throwable theCause) {
+ super(0, theMessage, theCause);
+ }
+
+ public FhirClientInnapropriateForServerException(String theMessage) {
+ super(0, theMessage);
+ }
+
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java
index cbed783919a..584230acd39 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java
@@ -32,7 +32,7 @@ public interface ITransaction {
/**
* Use a list of resources as the transaction input
*/
- ITransactionTyped> withResources(List theResources);
+ ITransactionTyped> withResources(List extends IBaseResource> theResources);
/**
* Use a DSTU1 Bundle (Atom) as the transaction input
@@ -44,9 +44,9 @@ public interface ITransaction {
*/
ITransactionTyped withBundle(T theBundleResource);
- // *****
- // TODO: add withString version
- // If we add a withString version, make sure to auto-detect content type!
- // *****
-
+ /**
+ * Use the given raw text (should be a Bundle resource) as the transaction input
+ */
+ ITransactionTyped withBundle(String theBundle);
+
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java
index 475709fdf1e..f0b4c16e4c0 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseHttpClientInvocationWithContents.java
@@ -37,6 +37,7 @@ import org.hl7.fhir.instance.model.IBaseResource;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
@@ -47,6 +48,7 @@ import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
+import ca.uhn.fhir.validation.FhirValidator;
/**
* @author James Agnew
@@ -63,7 +65,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
private String myIfNoneExistString;
private Map> myParams;
private final IBaseResource myResource;
- private final List myResources;
+ private final List extends IBaseResource> myResources;
private final TagList myTagList;
private final String myUrlPath;
@@ -103,7 +105,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myBundleType = null;
}
- public BaseHttpClientInvocationWithContents(FhirContext theContext, List theResources, BundleTypeEnum theBundleType) {
+ public BaseHttpClientInvocationWithContents(FhirContext theContext, List extends IBaseResource> theResources, BundleTypeEnum theBundleType) {
myContext = theContext;
myResource = null;
myTagList = null;
@@ -270,7 +272,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
}
} else if (myContents != null) {
contents = myContents;
- if (myContentsIsBundle) {
+ if (myContentsIsBundle && myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) {
contentType = encoding.getBundleContentType();
} else {
contentType = encoding.getResourceContentType();
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java
index 5013174f13d..7e157aed3ac 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java
@@ -173,6 +173,25 @@ public abstract class BaseMethodBinding implements IClientResponseHandler
*/
public abstract String getResourceName();
+ /**
+ * Returns the value of {@link #getResourceOperationType()} or {@link #getSystemOperationType()} or {@link #getOtherOperationType()}
+ */
+ public String getResourceOrSystemOperationType() {
+ Enum> retVal = getResourceOperationType();
+ if (retVal != null) {
+ return retVal.name();
+ }
+ retVal = getSystemOperationType();
+ if (retVal != null) {
+ return retVal.name();
+ }
+ retVal = getOtherOperationType();
+ if (retVal != null) {
+ return retVal.name();
+ }
+ return null;
+ }
+
public abstract RestfulOperationTypeEnum getResourceOperationType();
public abstract RestfulOperationSystemEnum getSystemOperationType();
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java
index 73a1db2f730..15631b9e6f3 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java
@@ -20,9 +20,12 @@ package ca.uhn.fhir.rest.method;
* #L%
*/
+import static org.apache.commons.lang3.StringUtils.isBlank;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
+import java.io.StringReader;
import java.io.Writer;
import java.lang.reflect.Method;
import java.util.Enumeration;
@@ -32,6 +35,7 @@ import java.util.Set;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.IBaseResource;
@@ -53,6 +57,7 @@ import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.RestfulServerUtils;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
+import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding {
@@ -65,7 +70,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding> theHeaders) throws IOException, BaseServerResponseException {
+ public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException,
+ BaseServerResponseException {
switch (theResponseStatusCode) {
case Constants.STATUS_HTTP_200_OK:
case Constants.STATUS_HTTP_201_CREATED:
@@ -198,7 +204,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding wantedResourceType = requestContainsResourceType();
IBaseResource retVal;
@@ -305,7 +342,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding includes = getRequestIncludesFromParams(params);
@@ -312,7 +312,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding theResources, BundleTypeEnum theBundleType) {
+ public HttpPostClientInvocation(FhirContext theContext, List extends IBaseResource> theResources, BundleTypeEnum theBundleType) {
super(theContext, theResources, theBundleType);
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java
index ecbcc898831..a78eceab910 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/MethodUtil.java
@@ -249,15 +249,26 @@ public class MethodUtil {
}
public static EncodingEnum detectEncoding(String theBody) {
- for (int i = 0; i < theBody.length(); i++) {
+ EncodingEnum retVal = detectEncodingNoDefault(theBody);
+ if (retVal == null) {
+ retVal = EncodingEnum.XML;
+ }
+ return retVal;
+ }
+
+ public static EncodingEnum detectEncodingNoDefault(String theBody) {
+ EncodingEnum retVal = null;
+ for (int i = 0; i < theBody.length() && retVal == null; i++) {
switch (theBody.charAt(i)) {
- case '<':
- return EncodingEnum.XML;
- case '{':
- return EncodingEnum.JSON;
+ case '<':
+ retVal = EncodingEnum.XML;
+ break;
+ case '{':
+ retVal = EncodingEnum.JSON;
+ break;
}
}
- return EncodingEnum.XML;
+ return retVal;
}
public static void extractDescription(SearchParameter theParameter, Annotation[] theAnnotations) {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java
index 5240981738e..dd84b803b3d 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java
@@ -132,6 +132,11 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
return RestfulOperationTypeEnum.SEARCH_TYPE;
}
+ @Override
+ protected BundleTypeEnum getResponseBundleType() {
+ return BundleTypeEnum.SEARCHSET;
+ }
+
@Override
public ReturnTypeEnum getReturnType() {
return ReturnTypeEnum.BUNDLE;
@@ -289,13 +294,9 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
}
- public void setResourceType(Class extends IResource> resourceType) {
- this.myDeclaredResourceType = resourceType;
- }
-
@Override
- public String toString() {
- return getMethod().toString();
+ protected boolean isAddContentLocationHeader() {
+ return false;
}
private List processWhitelistAndBlacklist(List theQualifiedNames, Set theQualifierWhitelist, Set theQualifierBlacklist) {
@@ -313,6 +314,15 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
return retVal;
}
+ public void setResourceType(Class extends IResource> resourceType) {
+ this.myDeclaredResourceType = resourceType;
+ }
+
+ @Override
+ public String toString() {
+ return getMethod().toString();
+ }
+
public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theResourceName, Map> theParameters, IdDt theId, String theCompartmentName,
SearchStyleEnum theSearchStyle) {
SearchStyleEnum searchStyle = theSearchStyle;
@@ -473,9 +483,4 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
}
- @Override
- protected BundleTypeEnum getResponseBundleType() {
- return BundleTypeEnum.SEARCHSET;
- }
-
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionMethodBinding.java
index 83fa8dfe9fa..6f08e795d0c 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionMethodBinding.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/TransactionMethodBinding.java
@@ -195,8 +195,12 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
return new HttpPostClientInvocation(theContext, theBundle);
}
- public static BaseHttpClientInvocation createTransactionInvocation(List theResources, FhirContext theContext) {
+ public static BaseHttpClientInvocation createTransactionInvocation(List extends IBaseResource> theResources, FhirContext theContext) {
return new HttpPostClientInvocation(theContext, theResources, BundleTypeEnum.TRANSACTION);
}
+ public static BaseHttpClientInvocation createTransactionInvocation(String theRawBundle, FhirContext theContext) {
+ return new HttpPostClientInvocation(theContext, theRawBundle, true, "");
+ }
+
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java
index f27e6c5bc39..b27618874a9 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java
@@ -203,8 +203,6 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
addResourcesToBundle(new ArrayList(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType);
- myBundle.setPublished(theResult.getPublished());
-
if (theServer.getPagingProvider() != null) {
int limit;
limit = theLimit != null ? theLimit : theServer.getPagingProvider().getDefaultPageSize();
@@ -232,10 +230,6 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
myBundle.getBundleId().setValue(UUID.randomUUID().toString());
}
- if (myBundle.getPublished().isEmpty()) {
- myBundle.getPublished().setToCurrentTimeInLocalTimeZone();
- }
-
if (myBundle.getLinkBase().isEmpty()) {
myBundle.getLinkBase().setValue(theServerBase);
}
@@ -264,12 +258,11 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
}
@Override
- public void initializeBundleFromResourceList(String theAuthor, List theResult, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType) {
+ public void initializeBundleFromResourceList(String theAuthor, List extends IBaseResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType) {
myBundle = new Bundle();
myBundle.getAuthorName().setValue(theAuthor);
myBundle.getBundleId().setValue(UUID.randomUUID().toString());
- myBundle.getPublished().setToCurrentTimeInLocalTimeZone();
myBundle.getLinkBase().setValue(theServerBase);
myBundle.getLinkSelf().setValue(theCompleteUrl);
myBundle.getType().setValueAsEnum(theBundleType);
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IVersionSpecificBundleFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IVersionSpecificBundleFactory.java
index 77f379bc75f..9537ef033d9 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IVersionSpecificBundleFactory.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IVersionSpecificBundleFactory.java
@@ -46,7 +46,7 @@ public interface IVersionSpecificBundleFactory {
IBaseResource getResourceBundle();
- void initializeBundleFromResourceList(String theAuthor, List theResult, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType);
+ void initializeBundleFromResourceList(String theAuthor, List extends IBaseResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType);
void initializeWithBundleResource(IBaseResource theResource);
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategy.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategy.java
index 6bcdacd5b22..793e80e23bd 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategy.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategy.java
@@ -30,10 +30,19 @@ import org.apache.commons.lang3.StringUtils;
*/
public class IncomingRequestAddressStrategy implements IServerAddressStrategy {
+ private String myServletPath;
+
@Override
public String determineServerBase(ServletContext theServletContext, HttpServletRequest theRequest) {
String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI());
- String servletPath = StringUtils.defaultString(theRequest.getServletPath());
+
+ String servletPath;
+ if (myServletPath != null) {
+ servletPath = myServletPath;
+ } else {
+ servletPath = StringUtils.defaultString(theRequest.getServletPath());
+ }
+
StringBuffer requestUrl = theRequest.getRequestURL();
String servletContextPath = "";
if (theServletContext != null) {
@@ -48,7 +57,9 @@ public class IncomingRequestAddressStrategy implements IServerAddressStrategy {
}
int startOfPath = requestUrl.indexOf("//");
- if (startOfPath != -1 && (startOfPath + 2) < requestUrl.length()) {
+ int requestUrlLength = requestUrl.length();
+
+ if (startOfPath != -1 && (startOfPath + 2) < requestUrlLength) {
startOfPath = requestUrl.indexOf("/", startOfPath + 2);
}
if (startOfPath == -1) {
@@ -56,9 +67,9 @@ public class IncomingRequestAddressStrategy implements IServerAddressStrategy {
}
int contextIndex;
- if (servletPath.length() == 0) {
+ if (servletPath.length() == 0 || servletPath.equals("/")) {
if (requestPath.length() == 0) {
- contextIndex = requestUrl.length();
+ contextIndex = requestUrlLength;
} else {
contextIndex = requestUrl.indexOf(requestPath, startOfPath);
}
@@ -68,8 +79,30 @@ public class IncomingRequestAddressStrategy implements IServerAddressStrategy {
String fhirServerBase;
int length = contextIndex + servletPath.length();
+ if (length > requestUrlLength) {
+ length = requestUrlLength;
+ }
fhirServerBase = requestUrl.substring(0, length);
return fhirServerBase;
}
+ /**
+ * If set to a non-null value (default is null), this address strategy assumes that the FHIR endpoint is deployed to the given servlet path within the context. This is useful in some
+ * deployments where it isn't obvious to the servlet which part of the path is actually the root path to reach the servlet.
+ *
+ * Example values could be:
+ *
+ *
null
+ *
/
+ *
/base
+ *
+ *
+ *
+ * Wildcards are not supported!
+ *
+ */
+ public void setServletPath(String theServletPath) {
+ myServletPath = theServletPath;
+ }
+
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/ResponseResourceList.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/ResponseResourceList.java
index 3e52314ae25..926d3b55873 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/ResponseResourceList.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/ResponseResourceList.java
@@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.server;
+/*
+ * #%L
+ * HAPI FHIR - Core Library
+ * %%
+ * Copyright (C) 2014 - 2015 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
import java.util.ArrayList;
import java.util.List;
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java
index 557a2d10b3e..5580492d90f 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java
@@ -490,7 +490,7 @@ public class RestfulServer extends HttpServlet {
return;
}
}
- RestfulServerUtils.streamResponseAsResource(this, theResponse, (IResource) resBundle, responseEncoding, prettyPrint, requestIsBrowser, narrativeMode, Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), theRequest.getFhirServerBase());
+ RestfulServerUtils.streamResponseAsResource(this, theResponse, (IResource) resBundle, responseEncoding, prettyPrint, requestIsBrowser, narrativeMode, Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), theRequest.getFhirServerBase(), false);
}
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java
index 26daa5255cd..8c777eab3aa 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java
@@ -76,10 +76,10 @@ public class RestfulServerUtils {
}
public static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IBaseResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint,
- boolean theRequestIsBrowser, RestfulServer.NarrativeModeEnum theNarrativeMode, int stausCode, boolean theRespondGzip, String theServerBase) throws IOException {
+ boolean theRequestIsBrowser, RestfulServer.NarrativeModeEnum theNarrativeMode, int stausCode, boolean theRespondGzip, String theServerBase, boolean theAddContentLocationHeader) throws IOException {
theHttpResponse.setStatus(stausCode);
- if (theResource.getId() != null && theResource.getId().hasIdPart() && isNotBlank(theServerBase)) {
+ if (theAddContentLocationHeader && theResource.getId() != null && theResource.getId().hasIdPart() && isNotBlank(theServerBase)) {
String resName = theServer.getFhirContext().getResourceDefinition(theResource).getName();
IIdType fullId = theResource.getId().withServerBase(theServerBase, resName);
theHttpResponse.addHeader(Constants.HEADER_CONTENT_LOCATION, fullId.getValue());
@@ -205,9 +205,18 @@ public class RestfulServerUtils {
}
public static EncodingEnum determineRequestEncoding(Request theReq) {
+ EncodingEnum retVal = determineRequestEncodingNoDefault(theReq);
+ if (retVal != null) {
+ return retVal;
+ }
+ return EncodingEnum.XML;
+ }
+
+ public static EncodingEnum determineRequestEncodingNoDefault(Request theReq) {
+ EncodingEnum retVal = null;
Enumeration acceptValues = theReq.getServletRequest().getHeaders(Constants.HEADER_CONTENT_TYPE);
if (acceptValues != null) {
- while (acceptValues.hasMoreElements()) {
+ while (acceptValues.hasMoreElements() && retVal == null) {
String nextAcceptHeaderValue = acceptValues.nextElement();
if (nextAcceptHeaderValue != null && isNotBlank(nextAcceptHeaderValue)) {
for (String nextPart : nextAcceptHeaderValue.split(",")) {
@@ -219,15 +228,15 @@ public class RestfulServerUtils {
nextPart = nextPart.substring(0, scIdx);
}
nextPart = nextPart.trim();
- EncodingEnum retVal = Constants.FORMAT_VAL_TO_ENCODING.get(nextPart);
+ retVal = Constants.FORMAT_VAL_TO_ENCODING.get(nextPart);
if (retVal != null) {
- return retVal;
+ break;
}
}
}
}
}
- return EncodingEnum.XML;
+ return retVal;
}
public static String createPagingLink(Set theIncludes, String theServerBase, String theSearchId, int theOffset, int theCount, EncodingEnum theResponseEncoding, boolean thePrettyPrint) {
@@ -413,12 +422,12 @@ public class RestfulServerUtils {
}
}
- public static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IBaseResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint,
- boolean theRequestIsBrowser, RestfulServer.NarrativeModeEnum theNarrativeMode, boolean theRespondGzip, String theServerBase) throws IOException {
- int stausCode = 200;
- RestfulServerUtils.streamResponseAsResource(theServer, theHttpResponse, theResource, theResponseEncoding, thePrettyPrint, theRequestIsBrowser, theNarrativeMode, stausCode, theRespondGzip,
- theServerBase);
- }
+// public static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint,
+// boolean theRequestIsBrowser, RestfulServer.NarrativeModeEnum theNarrativeMode, boolean theRespondGzip, String theServerBase) throws IOException {
+// int stausCode = 200;
+// RestfulServerUtils.streamResponseAsResource(theServer, theHttpResponse, theResource, theResponseEncoding, thePrettyPrint, theRequestIsBrowser, theNarrativeMode, stausCode, theRespondGzip,
+// theServerBase);
+// }
public static void validateResourceListNotNull(List extends IBaseResource> theResourceList) {
if (theResourceList == null) {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceNotFoundException.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceNotFoundException.java
index 600cdd4d0c0..2d89461d86d 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceNotFoundException.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/ResourceNotFoundException.java
@@ -20,6 +20,8 @@ package ca.uhn.fhir.rest.server.exceptions;
* #L%
*/
+import org.hl7.fhir.instance.model.api.IIdType;
+
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
@@ -43,6 +45,14 @@ public class ResourceNotFoundException extends BaseServerResponseException {
super(STATUS_CODE, createErrorMessage(theClass, theId), theOperationOutcome);
}
+ public ResourceNotFoundException(Class extends IResource> theClass, IIdType theId) {
+ super(STATUS_CODE, createErrorMessage(theClass, theId));
+ }
+
+ public ResourceNotFoundException(Class extends IResource> theClass, IIdType theId, BaseOperationOutcome theOperationOutcome) {
+ super(STATUS_CODE, createErrorMessage(theClass, theId), theOperationOutcome);
+ }
+
/**
* Constructor
*
@@ -66,6 +76,10 @@ public class ResourceNotFoundException extends BaseServerResponseException {
super(STATUS_CODE, createErrorMessage(theId));
}
+ public ResourceNotFoundException(IIdType theId) {
+ super(STATUS_CODE, createErrorMessage(theId));
+ }
+
public ResourceNotFoundException(IdDt theId, BaseOperationOutcome theOperationOutcome) {
super(STATUS_CODE, createErrorMessage(theId), theOperationOutcome);
}
@@ -74,11 +88,11 @@ public class ResourceNotFoundException extends BaseServerResponseException {
super(STATUS_CODE, theMessage);
}
- private static String createErrorMessage(Class extends IResource> theClass, IdDt theId) {
+ private static String createErrorMessage(Class extends IResource> theClass, IIdType theId) {
return "Resource of type " + theClass.getSimpleName() + " with ID " + theId + " is not known";
}
- private static String createErrorMessage(IdDt theId) {
+ private static String createErrorMessage(IIdType theId) {
return "Resource " + (theId != null ? theId.getValue() : "") + " is not known";
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java
index a8987477d3c..8737104ff11 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java
@@ -129,7 +129,7 @@ public class ExceptionHandlingInterceptor extends InterceptorAdapter {
boolean requestIsBrowser = RestfulServer.requestIsBrowser(theRequest);
String fhirServerBase = ((Request) theRequestDetails).getFhirServerBase();
RestfulServerUtils.streamResponseAsResource(theRequestDetails.getServer(), theResponse, oo, RestfulServerUtils.determineResponseEncodingNoDefault(theRequest), true, requestIsBrowser,
- NarrativeModeEnum.NORMAL, statusCode, false, fhirServerBase);
+ NarrativeModeEnum.NORMAL, statusCode, false, fhirServerBase, false);
// theResponse.setStatus(statusCode);
// theRequestDetails.getServer().addHeadersToResponse(theResponse);
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java.orig b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java.orig
deleted file mode 100644
index 9e81a04ae44..00000000000
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java.orig
+++ /dev/null
@@ -1,172 +0,0 @@
-package ca.uhn.fhir.rest.server.interceptor;
-
-/*
- * #%L
- * HAPI FHIR - Core Library
- * %%
- * Copyright (C) 2014 - 2015 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 static org.apache.commons.lang3.StringUtils.isNotBlank;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.lang3.exception.ExceptionUtils;
-
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
-import ca.uhn.fhir.model.base.resource.BaseOperationOutcome.BaseIssue;
-import ca.uhn.fhir.rest.method.Request;
-import ca.uhn.fhir.rest.method.RequestDetails;
-import ca.uhn.fhir.rest.server.Constants;
-import ca.uhn.fhir.rest.server.RestfulServer;
-import ca.uhn.fhir.rest.server.RestfulServer.NarrativeModeEnum;
-import ca.uhn.fhir.rest.server.RestfulServerUtils;
-import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
-import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
-
-public class ExceptionHandlingInterceptor extends InterceptorAdapter {
-
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExceptionHandlingInterceptor.class);
- private Class>[] myReturnStackTracesForExceptionTypes;
-
- /**
- * If any server methods throw an exception which extends any of the given exception types, the exception
- * stack trace will be returned to the user. This can be useful for helping to diagnose issues, but may
- * not be desirable for production situations.
- *
- * @param theExceptionTypes The exception types for which to return the stack trace to the user.
- * @return Returns an instance of this interceptor, to allow for easy method chaining.
- */
- public ExceptionHandlingInterceptor setReturnStackTracesForExceptionTypes(Class>... theExceptionTypes) {
- myReturnStackTracesForExceptionTypes = theExceptionTypes;
- return this;
- }
-
- @Override
-<<<<<<< HEAD
- public boolean handleException(RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException {
-=======
- public boolean handleException(RestfulServer theRestfulServer, RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException {
- ourLog.error("AA", theException);
->>>>>>> 5956ab75fd9186ccc8b9836b60bc421b19d3d288
- BaseOperationOutcome oo = null;
- int statusCode = Constants.STATUS_HTTP_500_INTERNAL_ERROR;
-
- FhirContext ctx = theRestfulServer.getFhirContext();
-
- if (theException instanceof BaseServerResponseException) {
- oo = ((BaseServerResponseException) theException).getOperationOutcome();
- statusCode = ((BaseServerResponseException) theException).getStatusCode();
- }
-
- /*
- * Generate an OperationOutcome to return, unless the exception throw by the resource provider had one
- */
- if (oo == null) {
- try {
- oo = (BaseOperationOutcome) ctx.getResourceDefinition("OperationOutcome").getImplementingClass().newInstance();
- } catch (Exception e1) {
- ourLog.error("Failed to instantiate OperationOutcome resource instance", e1);
- throw new ServletException("Failed to instantiate OperationOutcome resource instance", e1);
- }
-
- BaseIssue issue = oo.addIssue();
- issue.getSeverityElement().setValue("error");
- if (theException instanceof InternalErrorException) {
- ourLog.error("Failure during REST processing", theException);
- populateDetails(theException, issue);
- } else if (theException instanceof BaseServerResponseException) {
- ourLog.warn("Failure during REST processing: {}", theException);
- BaseServerResponseException baseServerResponseException = (BaseServerResponseException) theException;
- statusCode = baseServerResponseException.getStatusCode();
- populateDetails(theException, issue);
- if (baseServerResponseException.getAdditionalMessages() != null) {
- for (String next : baseServerResponseException.getAdditionalMessages()) {
- BaseIssue issue2 = oo.addIssue();
- issue2.getSeverityElement().setValue("error");
- issue2.setDetails(next);
- }
- }
- } else {
- ourLog.error("Failure during REST processing: " + theException.toString(), theException);
- populateDetails(theException, issue);
- statusCode = Constants.STATUS_HTTP_500_INTERNAL_ERROR;
- }
- } else {
- ourLog.error("Unknown error during processing", theException);
- }
-
- // Add headers associated with the specific error code
- if (theException instanceof BaseServerResponseException) {
- Map additional = ((BaseServerResponseException) theException).getAssociatedHeaders();
- if (additional != null) {
- for (Entry next : additional.entrySet()) {
- if (isNotBlank(next.getKey()) && next.getValue() != null) {
- String nextKey = next.getKey();
- for (String nextValue : next.getValue()) {
- theResponse.addHeader(nextKey, nextValue);
- }
- }
- }
- }
- }
-
- boolean requestIsBrowser = RestfulServer.requestIsBrowser(theRequest);
- String fhirServerBase = theRestfulServer.getServerBaseForRequest(theRequest);
-
- RestfulServerUtils.streamResponseAsResource(theRestfulServer, theResponse, oo, RestfulServerUtils.determineResponseEncodingNoDefault(theRequest), true, requestIsBrowser,
- NarrativeModeEnum.NORMAL, statusCode, false, fhirServerBase);
-
-<<<<<<< HEAD
-// theResponse.setStatus(statusCode);
-// theRequestDetails.getServer().addHeadersToResponse(theResponse);
-// theResponse.setContentType("text/plain");
-// theResponse.setCharacterEncoding("UTF-8");
-// theResponse.getWriter().append(theException.getMessage());
-// theResponse.getWriter().close();
-=======
- theResponse.setStatus(statusCode);
- theRestfulServer.addHeadersToResponse(theResponse);
- theResponse.setContentType("text/plain");
- theResponse.setCharacterEncoding("UTF-8");
- theResponse.getWriter().append(theException.getMessage());
- theResponse.getWriter().close();
->>>>>>> 5956ab75fd9186ccc8b9836b60bc421b19d3d288
-
- return false;
- }
-
- private void populateDetails(Throwable theException, BaseIssue issue) {
- if (myReturnStackTracesForExceptionTypes != null) {
- for (Class> next : myReturnStackTracesForExceptionTypes) {
- if (next.isAssignableFrom(theException.getClass())) {
- issue.getDetailsElement().setValue(theException.getMessage() + "\n\n" + ExceptionUtils.getStackTrace(theException));
- return;
- }
- }
- }
-
- issue.getDetailsElement().setValue(theException.getMessage());
- }
-
-}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java
index f3d5a40984c..8e401dbe271 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java
@@ -61,7 +61,7 @@ public class FhirTerser {
if (theElement instanceof ISupportsUndeclaredExtensions) {
ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement;
for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) {
- theCallback.acceptUndeclaredExtension(containingElement, theChildDefinition, theDefinition, nextExt);
+ theCallback.acceptUndeclaredExtension(containingElement, null, theChildDefinition, theDefinition, nextExt);
addUndeclaredExtensions(nextExt, theDefinition, theChildDefinition, theCallback);
}
}
@@ -90,10 +90,10 @@ public class FhirTerser {
public List getAllPopulatedChildElementsOfType(IBaseResource theResource, final Class theType) {
final ArrayList retVal = new ArrayList();
BaseRuntimeElementCompositeDefinition> def = myContext.getResourceDefinition(theResource);
- visit(theResource, null, def, new IModelVisitor() {
+ visit(theResource, null, null, def, new IModelVisitor() {
@SuppressWarnings("unchecked")
@Override
- public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition) {
+ public void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition) {
if (theElement == null || theElement.isEmpty()) {
return;
}
@@ -105,7 +105,8 @@ public class FhirTerser {
@SuppressWarnings("unchecked")
@Override
- public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition, ExtensionDt theNextExt) {
+ public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition,
+ ExtensionDt theNextExt) {
if (theType.isAssignableFrom(theNextExt.getClass())) {
retVal.add((T) theNextExt);
}
@@ -117,39 +118,32 @@ public class FhirTerser {
return retVal;
}
- public List getAllResourceReferences(final IBaseResource theResource) {
- final ArrayList retVal = new ArrayList();
- BaseRuntimeElementCompositeDefinition> def = myContext.getResourceDefinition(theResource);
- visit(theResource, null, def, new IModelVisitor() {
- @Override
- public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition) {
- if (theElement == null || theElement.isEmpty()) {
- return;
- }
- String name = null;
- if (theChildDefinition != null) {
- name = theChildDefinition.getElementName();
- }
- if (BaseResourceReferenceDt.class.isAssignableFrom(theElement.getClass())) {
- retVal.add(new ResourceReferenceInfo(theResource, name, (BaseResourceReferenceDt) theElement));
- }
- }
+ public List getAllResourceReferences(final IBaseResource theResource) {
+ final ArrayList retVal = new ArrayList();
+ BaseRuntimeElementCompositeDefinition> def = myContext.getResourceDefinition(theResource);
+ visit(theResource, null, null, def, new IModelVisitor() {
+ @Override
+ public void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition) {
+ if (theElement == null || theElement.isEmpty()) {
+ return;
+ }
+ if (BaseResourceReferenceDt.class.isAssignableFrom(theElement.getClass())) {
+ retVal.add(new ResourceReferenceInfo(theResource, thePathToElement, (BaseResourceReferenceDt)theElement));
+ }
+ }
- @Override
- public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition, ExtensionDt theNextExt) {
- String name = null;
- if (theChildDefinition != null) {
- name = theChildDefinition.getElementName();
- }
- if (theNextExt.getValue() != null && BaseResourceReferenceDt.class.isAssignableFrom(theNextExt.getValue().getClass())) {
- retVal.add(new ResourceReferenceInfo(theResource, name, (BaseResourceReferenceDt) theNextExt.getValue()));
- }
- }
- });
- return retVal;
- }
+ @Override
+ public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition,
+ ExtensionDt theNextExt) {
+ if (theNextExt.getValue() != null && BaseResourceReferenceDt.class.isAssignableFrom(theNextExt.getValue().getClass())) {
+ retVal.add(new ResourceReferenceInfo(theResource, thePathToElement, (BaseResourceReferenceDt)theNextExt.getValue()));
+ }
+ }
+ });
+ return retVal;
+ }
- private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition> theCurrentDef, List theSubList) {
+ private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition> theCurrentDef, List theSubList) {
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));
if (theSubList.size() == 1) {
@@ -222,8 +216,19 @@ public class FhirTerser {
}
- private void visit(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition, IModelVisitor theCallback) {
- theCallback.acceptElement(theElement, theChildDefinition, theDefinition);
+ private List addNameToList(List theCurrentList, BaseRuntimeChildDefinition theChildDefinition) {
+ if (theChildDefinition == null)
+ return null;
+ if (theCurrentList== null || theCurrentList.isEmpty())
+ return new ArrayList(Arrays.asList(theChildDefinition.getElementName()));
+ List newList = new ArrayList(theCurrentList);
+ newList.add(theChildDefinition.getElementName());
+ return newList;
+ }
+
+ private void visit(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition, IModelVisitor theCallback) {
+ List pathToElement = addNameToList(thePathToElement, theChildDefinition);
+ theCallback.acceptElement(theElement, pathToElement, theChildDefinition, theDefinition);
addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback);
// if (theElement.isEmpty()) {
@@ -243,7 +248,7 @@ public class FhirTerser {
IBaseResource theResource = resRefDt.getResource();
if (theResource.getId() == null || theResource.getId().isEmpty() || theResource.getId().isLocal()) {
BaseRuntimeElementCompositeDefinition> def = myContext.getResourceDefinition(theResource);
- visit(theResource, null, def, theCallback);
+ visit(theResource, pathToElement, null, def, theCallback);
}
}
break;
@@ -285,9 +290,9 @@ public class FhirTerser {
if (nextChild instanceof RuntimeChildDirectResource) {
// Don't descend into embedded resources
- theCallback.acceptElement(nextValue, nextChild, childElementDef);
+ theCallback.acceptElement(nextValue, null, nextChild, childElementDef);
} else {
- visit(nextValue, nextChild, childElementDef, theCallback);
+ visit(nextValue, pathToElement, nextChild, childElementDef, theCallback);
}
}
}
@@ -298,7 +303,7 @@ public class FhirTerser {
BaseContainedDt value = (BaseContainedDt) theElement;
for (IResource next : value.getContainedResources()) {
BaseRuntimeElementCompositeDefinition> def = myContext.getResourceDefinition(next);
- visit(next, null, def, theCallback);
+ visit(next, pathToElement, null, def, theCallback);
}
break;
}
@@ -309,7 +314,7 @@ public class FhirTerser {
case CONTAINED_RESOURCE_LIST:
if (theElement != null) {
BaseRuntimeElementDefinition> def = myContext.getElementDefinition(theElement.getClass());
- visit(theElement, null, def, theCallback);
+ visit(theElement, null, theChildDefinition, def, theCallback);
}
break;
}
@@ -454,7 +459,7 @@ public class FhirTerser {
*/
public void visit(IBaseResource theResource, IModelVisitor theVisitor) {
BaseRuntimeElementCompositeDefinition> def = myContext.getResourceDefinition(theResource);
- visit(theResource, null, def, theVisitor);
+ visit(theResource, null, null, def, theVisitor);
}
/**
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java
index f183f8ee4d4..518080aab93 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java
@@ -28,6 +28,8 @@ import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
+import java.util.List;
+
/**
* @see FhirTerser#visit(IBaseResource, IModelVisitor)
*/
@@ -39,7 +41,7 @@ public interface IModelVisitor {
* @param theChildDefinition May be null if this is a root element
* @param theDefinition
*/
- void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition);
+ void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition);
/**
*
@@ -48,7 +50,7 @@ public interface IModelVisitor {
* @param theDefinition
* @param theNextExt
*/
- void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition, ExtensionDt theNextExt);
+ void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition> theDefinition, ExtensionDt theNextExt);
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ITestingUiClientFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ITestingUiClientFactory.java
new file mode 100644
index 00000000000..2ef7b1e6b08
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ITestingUiClientFactory.java
@@ -0,0 +1,39 @@
+package ca.uhn.fhir.util;
+
+/*
+ * #%L
+ * HAPI FHIR - Core Library
+ * %%
+ * Copyright (C) 2014 - 2015 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 javax.servlet.http.HttpServletRequest;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.client.IGenericClient;
+
+/**
+ * This interface isn't used by hapi-fhir-base, but is used by the
+ * Web Testing UI
+ */
+public interface ITestingUiClientFactory {
+
+ /**
+ * Instantiate a new client
+ */
+ IGenericClient newClient(FhirContext theFhirContext, HttpServletRequest theRequest, String theServerBaseUrl);
+
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java
index 1c634d695fa..fd50f9f5a81 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java
@@ -28,58 +28,71 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hl7.fhir.instance.model.IBaseResource;
+import java.util.Iterator;
+import java.util.List;
import java.util.Set;
/**
* Created by Bill de Beaubien on 2/26/2015.
*/
public class ResourceReferenceInfo {
- private String myOwningResource;
- private String myName;
- private BaseResourceReferenceDt myResource;
+ private String myOwningResource;
+ private String myName;
+ private BaseResourceReferenceDt myResource;
- public ResourceReferenceInfo(IBaseResource theOwningResource, String theName, BaseResourceReferenceDt theResource) {
- myOwningResource = theOwningResource.getClass().getAnnotation(ResourceDef.class).name();
- myName = theName;
- myResource = theResource;
- }
+ public ResourceReferenceInfo(IBaseResource theOwningResource, List thePathToElement, BaseResourceReferenceDt theResource) {
+ myOwningResource = theOwningResource.getClass().getAnnotation(ResourceDef.class).name();
+ myResource = theResource;
+ if (thePathToElement != null && !thePathToElement.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+ thePathToElement.iterator();
+ for (Iterator iterator = thePathToElement.iterator(); iterator.hasNext(); ) {
+ sb.append(iterator.next());
+ if (iterator.hasNext())
+ sb.append(".");
+ }
+ myName = sb.toString();
+ } else {
+ myName = null;
+ }
+ }
- @Override
- public String toString() {
- ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
- b.append("name", myName);
- b.append("resource", myResource.getReference());
- return b.build();
- }
+ @Override
+ public String toString() {
+ ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ b.append("name", myName);
+ b.append("resource", myResource.getReference());
+ return b.build();
+ }
- public String getName() {
- return myName;
- }
+ public String getName() {
+ return myName;
+ }
- public BaseResourceReferenceDt getResourceReference() {
- return myResource;
- }
+ public BaseResourceReferenceDt getResourceReference() {
+ return myResource;
+ }
- public boolean matchesIncludeSet(Set theIncludes) {
- if (theIncludes == null)
- return false;
- for (Include include : theIncludes) {
- if (matchesInclude(include))
- return true;
- }
- return false;
- }
+ public boolean matchesIncludeSet(Set theIncludes) {
+ if (theIncludes == null)
+ return false;
+ for (Include include : theIncludes) {
+ if (matchesInclude(include))
+ return true;
+ }
+ return false;
+ }
- public boolean matchesInclude(Include theInclude) {
- if (theInclude.getValue().equals("*")) {
- return true;
- }
- if (theInclude.getValue().indexOf(':') != -1) {
- // DSTU2 style
- return (theInclude.getValue().equals(myOwningResource + ':' + myName));
- } else {
- // DSTU1 style
- return (theInclude.getValue().equals(myOwningResource + '.' + myName));
- }
- }
+ public boolean matchesInclude(Include theInclude) {
+ if (theInclude.getValue().equals("*")) {
+ return true;
+ }
+ if (theInclude.getValue().indexOf(':') != -1) {
+ // DSTU2 style
+ return (theInclude.getValue().equals(myOwningResource + ':' + myName));
+ } else {
+ // DSTU1 style
+ return (theInclude.getValue().equals(myOwningResource + '.' + myName));
+ }
+ }
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java
index 133f7357c1d..258b4e61a03 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java
@@ -25,6 +25,7 @@ import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang3.Validate;
+import org.hl7.fhir.instance.model.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
@@ -199,10 +200,10 @@ public class FhirValidator {
* @return the results of validation
* @since 0.7
*/
- public ValidationResult validateWithResult(IResource theResource) {
+ public ValidationResult validateWithResult(IBaseResource theResource) {
Validate.notNull(theResource, "theResource must not be null");
- ValidationContext ctx = ValidationContext.forResource(myContext, theResource);
+ ValidationContext ctx = ValidationContext.forResource(myContext, (IResource) theResource);
for (IValidator next : myValidators) {
next.validateResource(ctx);
diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java
index de8b50555c6..97eb992b832 100644
--- a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java
+++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java
@@ -1,6 +1,5 @@
package org.hl7.fhir.instance.model.api;
-import ca.uhn.fhir.model.primitive.IdDt;
/*
* #%L
@@ -69,4 +68,8 @@ public interface IIdType {
boolean isAbsolute();
+ boolean isIdPartValidLong();
+
+ Long getIdPartAsLong();
+
}
diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
index ed11a144c98..3be62aef4ce 100644
--- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
+++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
@@ -12,6 +12,9 @@ ca.uhn.fhir.rest.client.GenericClient.cannotDetermineResourceTypeFromUri=Unable
ca.uhn.fhir.rest.client.RestfulClientFactory.failedToRetrieveConformance=Failed to retrieve the server's metadata statement during client initialization. URL used was: {0}
ca.uhn.fhir.rest.client.RestfulClientFactory.wrongVersionInConformance=The server at base URL "{0}" returned a conformance statement indicating that it supports FHIR version "{1}" which corresponds to {2}, but this client is configured to use {3} (via the FhirContext).
+ca.uhn.fhir.rest.method.BaseOutcomeReturningMethodBinding.noContentTypeInRequest=No Content-Type header was provided in the request. This is required for "{0}" operation
+ca.uhn.fhir.rest.method.BaseOutcomeReturningMethodBinding.invalidContentTypeInRequest=Incorrect Content-Type header value of "{0}" was provided in the request. A FHIR Content-Type is required for "{1}" operation
+
ca.uhn.fhir.rest.method.OperationMethodBinding.methodNotSupported=HTTP Method {0} is not allowed for this operation. Allowed method(s): {1}
ca.uhn.fhir.rest.method.OperationParamBinder.urlParamNotPrimitive=Can not invoke operation {0} using HTTP GET because parameter {1} is not a primitive datatype
ca.uhn.fhir.rest.method.IncludeParameter.invalidIncludeNameInRequest=Invalid {2} parameter value: "{0}". Valid values are: {1}
diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml
index 69f149a2f48..f47ef7a4829 100644
--- a/hapi-fhir-jpaserver-base/pom.xml
+++ b/hapi-fhir-jpaserver-base/pom.xml
@@ -43,11 +43,13 @@
ca.uhn.hapi.fhirhapi-fhir-structures-dstu1.0-SNAPSHOT
+ trueca.uhn.hapi.fhirhapi-fhir-structures-dstu21.0-SNAPSHOT
+ true
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java
index 6f9b45405c2..b8d08abbf78 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java
@@ -54,6 +54,7 @@ import org.apache.commons.lang3.Validate;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.hl7.fhir.instance.model.IBaseResource;
+import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
@@ -444,12 +445,12 @@ public abstract class BaseFhirDao implements IDao {
}
@Override
- public List getResources(final int theFromIndex, final int theToIndex) {
+ public List getResources(final int theFromIndex, final int theToIndex) {
final StopWatch timer = new StopWatch();
TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager);
- return template.execute(new TransactionCallback>() {
+ return template.execute(new TransactionCallback>() {
@Override
- public List doInTransaction(TransactionStatus theStatus) {
+ public List doInTransaction(TransactionStatus theStatus) {
List resEntities = Lists.newArrayList();
List tupleSubList = tuples.subList(theFromIndex, theToIndex);
@@ -471,7 +472,7 @@ public abstract class BaseFhirDao implements IDao {
resEntities = resEntities.subList(0, limit);
}
- ArrayList retVal = new ArrayList();
+ ArrayList retVal = new ArrayList();
for (BaseHasResource next : resEntities) {
RuntimeResourceDefinition type;
try {
@@ -503,7 +504,7 @@ public abstract class BaseFhirDao implements IDao {
};
}
- protected boolean isValidPid(IdDt theId) {
+ protected boolean isValidPid(IIdType theId) {
String idPart = theId.getIdPart();
for (int i = 0; i < idPart.length(); i++) {
char nextChar = idPart.charAt(i);
@@ -514,9 +515,9 @@ public abstract class BaseFhirDao implements IDao {
return true;
}
- protected List loadResourcesById(Set theIncludePids) {
+ protected List loadResourcesById(Set extends IIdType> theIncludePids) {
Set pids = new HashSet();
- for (IdDt next : theIncludePids) {
+ for (IIdType next : theIncludePids) {
if (next.isIdPartValidLong()) {
pids.add(next.getIdPartAsLong());
} else {
@@ -538,7 +539,7 @@ public abstract class BaseFhirDao implements IDao {
// }
TypedQuery q = myEntityManager.createQuery(cq);
- ArrayList retVal = new ArrayList();
+ ArrayList retVal = new ArrayList();
for (ResourceTable next : q.getResultList()) {
IResource resource = (IResource) toResource(next);
retVal.add(resource);
@@ -956,7 +957,7 @@ public abstract class BaseFhirDao implements IDao {
return myContext.getResourceDefinition(theResource).getName();
}
- protected Long translateForcedIdToPid(IdDt theId) {
+ protected Long translateForcedIdToPid(IIdType theId) {
if (isValidPid(theId)) {
return theId.getIdPartAsLong();
} else {
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirResourceDao.java
index 935df209c6d..bb4c2f05977 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirResourceDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirResourceDao.java
@@ -56,6 +56,7 @@ import javax.persistence.criteria.Root;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.IBaseResource;
+import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.PlatformTransactionManager;
@@ -660,12 +661,12 @@ public abstract class BaseFhirResourceDao extends BaseFhirD
return new HashSet(q.getResultList());
}
- private List addResourcesAsIncludesById(List theListToPopulate, Set includePids, List resources) {
+ private List addResourcesAsIncludesById(List theListToPopulate, Set extends IIdType> includePids, List resources) {
if (!includePids.isEmpty()) {
ourLog.info("Loading {} included resources", includePids.size());
resources = loadResourcesById(includePids);
- for (IResource next : resources) {
- ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(next, BundleEntrySearchModeEnum.INCLUDE);
+ for (IBaseResource next : resources) {
+ ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put((IResource) next, BundleEntrySearchModeEnum.INCLUDE);
}
theListToPopulate.addAll(resources);
}
@@ -1000,7 +1001,7 @@ public abstract class BaseFhirResourceDao extends BaseFhirD
return tags;
}
- protected abstract List