diff --git a/examples/src/main/java/example/ClientExamples.java b/examples/src/main/java/example/ClientExamples.java index 5725e8b161c..5f191520a59 100644 --- a/examples/src/main/java/example/ClientExamples.java +++ b/examples/src/main/java/example/ClientExamples.java @@ -7,6 +7,7 @@ import ca.uhn.fhir.rest.client.api.IBasicClient; import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor; import ca.uhn.fhir.rest.client.interceptor.BearerTokenAuthInterceptor; import ca.uhn.fhir.rest.client.interceptor.CookieInterceptor; +import ca.uhn.fhir.rest.client.interceptor.GZipContentInterceptor; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.server.EncodingEnum; @@ -90,6 +91,18 @@ public class ClientExamples { // END SNIPPET: cookie } + @SuppressWarnings("unused") + public void gzip() { + // START SNIPPET: gzip + // Create a context and get the client factory so it can be configured + FhirContext ctx = FhirContext.forDstu2(); + IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory(); + + // Register the interceptor with your client (either style) + IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir"); + annotationClient.registerInterceptor(new GZipContentInterceptor()); + // END SNIPPET: gzip + } @SuppressWarnings("unused") public void createSecurityBearer() { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/GetPage.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/GetPage.java index b347033d74c..bcf1bd87633 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/GetPage.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/GetPage.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.rest.annotation; +/* + * #%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.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/PageIdParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/PageIdParam.java index ed5a493fd99..4560eeaa648 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/PageIdParam.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/PageIdParam.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.rest.annotation; +/* + * #%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.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/interceptor/GZipContentInterceptor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/interceptor/GZipContentInterceptor.java new file mode 100644 index 00000000000..c4d73341395 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/interceptor/GZipContentInterceptor.java @@ -0,0 +1,56 @@ +package ca.uhn.fhir.rest.client.interceptor; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.GZIPOutputStream; + +import org.apache.http.Header; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.entity.ByteArrayEntity; + +import ca.uhn.fhir.rest.client.IClientInterceptor; +import ca.uhn.fhir.rest.server.Constants; + +/** + * Client interceptor which GZip compresses outgoing (POST/PUT) contents being uploaded + * from the client to the server. This can improve performance by reducing network + * load time. + */ +public class GZipContentInterceptor implements IClientInterceptor { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GZipContentInterceptor.class); + + @Override + public void interceptRequest(HttpRequestBase theRequest) { + if (theRequest instanceof HttpEntityEnclosingRequest) { + Header[] encodingHeaders = theRequest.getHeaders(Constants.HEADER_CONTENT_ENCODING); + if (encodingHeaders == null || encodingHeaders.length == 0) { + HttpEntityEnclosingRequest req = (HttpEntityEnclosingRequest)theRequest; + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + GZIPOutputStream gos; + try { + gos = new GZIPOutputStream(bos); + req.getEntity().writeTo(gos); + gos.finish(); + } catch (IOException e) { + ourLog.warn("Failed to GZip outgoing content", e); + return; + } + + byte[] byteArray = bos.toByteArray(); + ByteArrayEntity newEntity = new ByteArrayEntity(byteArray); + req.setEntity(newEntity); + req.addHeader(Constants.HEADER_CONTENT_ENCODING, "gzip"); + } + } + + } + + @Override + public void interceptResponse(HttpResponse theResponse) throws IOException { + // nothing + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IRestfulHeader.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IRestfulHeader.java index 2abce5282a8..04b94b032b4 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IRestfulHeader.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IRestfulHeader.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.rest.method; +/* + * #%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% + */ + public interface IRestfulHeader { } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/PageMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/PageMethodBinding.java index a19d5459790..2eaa9c97a07 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/PageMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/PageMethodBinding.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.rest.method; +/* + * #%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.isBlank; import java.lang.reflect.Method; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ParseAction.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ParseAction.java index a3b3e29cc14..463c4b3fda8 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ParseAction.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ParseAction.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.rest.method; +/* + * #%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.io.IOException; import java.io.Writer; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetails.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetails.java index 61b00ae6a2d..ff60bbe59f4 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetails.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/RequestDetails.java @@ -39,7 +39,7 @@ import ca.uhn.fhir.rest.server.IRestfulServerDefaults; public abstract class RequestDetails { - private byte[] myRequestContents; + private byte[] myRequestContents; private String myCompartmentName; private String myCompleteUrl; private String myFhirServerBase; @@ -54,7 +54,7 @@ public abstract class RequestDetails { private String mySecondaryOperation; private Map> myUnqualifiedToQualifiedNames; private IRestfulResponse myResponse; - + public String getCompartmentName() { return myCompartmentName; } @@ -65,6 +65,7 @@ public abstract class RequestDetails { /** * The fhir server base url, independant of the query being executed + * * @return the fhir server base url */ public String getFhirServerBase() { @@ -192,66 +193,64 @@ public abstract class RequestDetails { mySecondaryOperation = theSecondaryOperation; } - public IRestfulResponse getResponse() { - return myResponse; - } + public IRestfulResponse getResponse() { + return myResponse; + } - public void setResponse(IRestfulResponse theResponse) { - this.myResponse = theResponse; - } + public void setResponse(IRestfulResponse theResponse) { + this.myResponse = theResponse; + } - public abstract String getHeader(String name); - - public final byte[] loadRequestContents(RequestDetails theRequest) { + public abstract String getHeader(String name); + + public final byte[] loadRequestContents() { if (myRequestContents == null) { myRequestContents = getByteStreamRequestContents(); } return myRequestContents; } - protected abstract byte[] getByteStreamRequestContents(); + protected abstract byte[] getByteStreamRequestContents(); - public abstract List getHeaders(String name); + public abstract List getHeaders(String name); - /** - * Retrieves the body of the request as character data using - * a BufferedReader. The reader translates the character - * data according to the character encoding used on the body. - * Either this method or {@link #getInputStream} may be called to read the - * body, not both. - * - * @return a Reader containing the body of the request - * - * @exception UnsupportedEncodingException if the character set encoding - * used is not supported and the text cannot be decoded - * - * @exception IllegalStateException if {@link #getInputStream} method - * has been called on this request - * - * @exception IOException if an input or output exception occurred - * - * @see javax.servlet.http.HttpServletRequest#getInputStream - */ - public abstract Reader getReader() throws IOException; + /** + * Retrieves the body of the request as character data using a BufferedReader. The reader translates the + * character data according to the character encoding used on the body. Either this method or {@link #getInputStream} + * may be called to read the body, not both. + * + * @return a Reader containing the body of the request + * + * @exception UnsupportedEncodingException + * if the character set encoding used is not supported and the text cannot be decoded + * + * @exception IllegalStateException + * if {@link #getInputStream} method has been called on this request + * + * @exception IOException + * if an input or output exception occurred + * + * @see javax.servlet.http.HttpServletRequest#getInputStream + */ + public abstract Reader getReader() throws IOException; - /** - * Retrieves the body of the request as binary data. - * Either this method or {@link #getReader} may be called to - * read the body, not both. - * - * @return a {@link InputStream} object containing - * the body of the request - * - * @exception IllegalStateException if the {@link #getReader} method - * has already been called for this request - * - * @exception IOException if an input or output exception occurred - */ - public abstract InputStream getInputStream() throws IOException; + /** + * Retrieves the body of the request as binary data. Either this method or {@link #getReader} may be called to read + * the body, not both. + * + * @return a {@link InputStream} object containing the body of the request + * + * @exception IllegalStateException + * if the {@link #getReader} method has already been called for this request + * + * @exception IOException + * if an input or output exception occurred + */ + public abstract InputStream getInputStream() throws IOException; - /** - * Returns the server base URL (with no trailing '/') for a given request - */ - public abstract String getServerBaseForRequest(); + /** + * Returns the server base URL (with no trailing '/') for a given request + */ + public abstract String getServerBaseForRequest(); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java index f626ae783c2..fa86a054849 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ResourceParameter.java @@ -122,7 +122,7 @@ public class ResourceParameter implements IParameter { } public static Reader createRequestReader(RequestDetails theRequest, Charset charset) { - Reader requestReader = new InputStreamReader(new ByteArrayInputStream(theRequest.loadRequestContents(theRequest)), charset); + Reader requestReader = new InputStreamReader(new ByteArrayInputStream(theRequest.loadRequestContents()), charset); return requestReader; } @@ -179,7 +179,7 @@ public class ResourceParameter implements IParameter { String msg = ctx.getLocalizer().getMessage(ResourceParameter.class, "noContentTypeInRequest", restOperationType); throw new InvalidRequestException(msg); } else { - requestReader = new InputStreamReader(new ByteArrayInputStream(theRequest.loadRequestContents(theRequest)), charset); + requestReader = new InputStreamReader(new ByteArrayInputStream(theRequest.loadRequestContents()), charset); } } else { String msg = ctx.getLocalizer().getMessage(ResourceParameter.class, "invalidContentTypeInRequest", ctValue, restOperationType); @@ -219,7 +219,7 @@ public class ResourceParameter implements IParameter { String ct = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE); IBaseBinary binary = (IBaseBinary) ctx.getResourceDefinition("Binary").newInstance(); binary.setContentType(ct); - binary.setContent(theRequest.loadRequestContents(theRequest)); + binary.setContent(theRequest.loadRequestContents()); retVal = binary; } else { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulResponse.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulResponse.java index afbb3000fd3..a88aa73711b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulResponse.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulResponse.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.io.IOException; import java.io.UnsupportedEncodingException; import java.io.Writer; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulServerDefaults.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulServerDefaults.java index 6029f2ebeb5..b97395a69d9 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulServerDefaults.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulServerDefaults.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 ca.uhn.fhir.context.FhirContext; public interface IRestfulServerDefaults { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulServerUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulServerUtil.java index b55330d0836..abe86bbfee8 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulServerUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IRestfulServerUtil.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 org.hl7.fhir.instance.model.api.IBaseResource; import ca.uhn.fhir.rest.method.BaseMethodBinding; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/PageProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/PageProvider.java index e6dc7af9992..3af59f57946 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/PageProvider.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/PageProvider.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 ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.rest.annotation.GetPage; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulResponse.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulResponse.java index 7d30b9f7959..e79840480f2 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulResponse.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulResponse.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.io.IOException; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; 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 9ac8c538d2f..3e2fd30ac04 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 @@ -80,13 +80,13 @@ import ca.uhn.fhir.util.VersionUtil; public class RestfulServer extends HttpServlet implements IRestfulServer { - private static final ExceptionHandlingInterceptor DEFAULT_EXCEPTION_HANDLER = new ExceptionHandlingInterceptor(); - private static final long serialVersionUID = 1L; /** * Default setting for {@link #setETagSupport(ETagSupportEnum) ETag Support}: {@link ETagSupportEnum#ENABLED} */ public static final ETagSupportEnum DEFAULT_ETAG_SUPPORT = ETagSupportEnum.ENABLED; + private static final ExceptionHandlingInterceptor DEFAULT_EXCEPTION_HANDLER = new ExceptionHandlingInterceptor(); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServer.class); + private static final long serialVersionUID = 1L; private AddProfileTagEnum myAddProfileTag; private BundleInclusionRule myBundleInclusionRule = BundleInclusionRule.BASED_ON_INCLUDES; private boolean myDefaultPrettyPrint = false; @@ -97,9 +97,9 @@ public class RestfulServer extends HttpServlet implements IRestfulServer myInterceptors = new ArrayList(); private IPagingProvider myPagingProvider; private final List myPlainProviders = new ArrayList(); + private Lock myProviderRegistrationMutex = new ReentrantLock(); private Map myResourceNameToBinding = new HashMap(); private final List myResourceProviders = new ArrayList(); - private Map myTypeToProvider = new HashMap(); private IServerAddressStrategy myServerAddressStrategy = new IncomingRequestAddressStrategy(); private ResourceBinding myServerBinding = new ResourceBinding(); private BaseMethodBinding myServerConformanceMethod; @@ -108,12 +108,14 @@ public class RestfulServer extends HttpServlet implements IRestfulServer myTypeToProvider = new HashMap(); + private boolean myUncompressIncomingContents = true; private boolean myUseBrowserFriendlyContentTypes; - private Lock myProviderRegistrationMutex = new ReentrantLock(); /** - * Constructor. Note that if no {@link FhirContext} is passed in to the server (either through the constructor, or through {@link #setFhirContext(FhirContext)}) the server will determine which - * version of FHIR to support through classpath scanning. This is brittle, and it is highly recommended to explicitly specify a FHIR version. + * Constructor. Note that if no {@link FhirContext} is passed in to the server (either through the constructor, or + * through {@link #setFhirContext(FhirContext)}) the server will determine which version of FHIR to support through + * classpath scanning. This is brittle, and it is highly recommended to explicitly specify a FHIR version. */ public RestfulServer() { this(null); @@ -126,22 +128,74 @@ public class RestfulServer extends HttpServlet implements IRestfulServer - * Use caution if overriding this method: it is recommended to call super.addHeadersToResponse to avoid inadvertantly disabling functionality. + * Use caution if overriding this method: it is recommended to call super.addHeadersToResponse to avoid + * inadvertantly disabling functionality. *

*/ public void addHeadersToResponse(HttpServletResponse theHttpResponse) { theHttpResponse.addHeader("X-Powered-By", "HAPI FHIR " + VersionUtil.getVersion() + " RESTful Server"); } + private void addLocationHeader(RequestDetails theRequest, HttpServletResponse theResponse, MethodOutcome response, String headerLocation, String resourceName) { + StringBuilder b = new StringBuilder(); + b.append(theRequest.getFhirServerBase()); + b.append('/'); + b.append(resourceName); + b.append('/'); + b.append(response.getId().getIdPart()); + if (response.getId().hasVersionIdPart()) { + b.append("/" + Constants.PARAM_HISTORY + "/"); + b.append(response.getId().getVersionIdPart()); + } else if (response.getVersionId() != null && response.getVersionId().isEmpty() == false) { + b.append("/" + Constants.PARAM_HISTORY + "/"); + b.append(response.getVersionId().getValue()); + } + theResponse.addHeader(headerLocation, b.toString()); + + } + private void assertProviderIsValid(Object theNext) throws ConfigurationException { if (Modifier.isPublic(theNext.getClass().getModifiers()) == false) { throw new ConfigurationException("Can not use provider '" + theNext.getClass() + "' - Class must be public"); } } + public RestulfulServerConfiguration createConfiguration() { + RestulfulServerConfiguration result = new RestulfulServerConfiguration(); + result.setResourceBindings(getResourceBindings()); + result.setServerBindings(getServerBindings()); + result.setImplementationDescription(getImplementationDescription()); + result.setServerVersion(getServerVersion()); + result.setServerName(getServerName()); + result.setFhirContext(getFhirContext()); + result.setServerAddressStrategy(myServerAddressStrategy); + InputStream inputStream = null; + try { + inputStream = getClass().getResourceAsStream("/META-INF/MANIFEST.MF"); + if (inputStream != null) { + Manifest manifest = new Manifest(inputStream); + result.setConformanceDate(manifest.getMainAttributes().getValue("Build-Time")); + } + } catch (IOException e) { + // fall through + } finally { + if (inputStream != null) { + IOUtils.closeQuietly(inputStream); + } + } + return result; + } + @Override public void destroy() { if (getResourceProviders() != null) { @@ -159,6 +213,38 @@ public class RestfulServer extends HttpServlet implements IRestfulServer determineResourceMethod(RequestDetails requestDetails, String requestPath) { + RequestTypeEnum requestType = requestDetails.getRequestType(); + + ResourceBinding resourceBinding = null; + BaseMethodBinding resourceMethod = null; + String resourceName = requestDetails.getResourceName(); + if (Constants.URL_TOKEN_METADATA.equals(resourceName) || requestType == RequestTypeEnum.OPTIONS) { + resourceMethod = myServerConformanceMethod; + } else if (resourceName == null) { + resourceBinding = myServerBinding; + } else { + resourceBinding = myResourceNameToBinding.get(resourceName); + if (resourceBinding == null) { + throw new InvalidRequestException("Unknown resource type '" + resourceName + "' - Server knows how to handle: " + myResourceNameToBinding.keySet()); + } + } + + if (resourceMethod == null) { + if (resourceBinding != null) { + resourceMethod = resourceBinding.getMethod(requestDetails); + } + } + if (resourceMethod == null) { + if (isBlank(requestPath)) { + throw new InvalidRequestException(myFhirContext.getLocalizer().getMessage(RestfulServer.class, "rootRequest")); + } else { + throw new InvalidRequestException(myFhirContext.getLocalizer().getMessage(RestfulServer.class, "unknownMethod", requestType.name(), requestPath, requestDetails.getParameters().keySet())); + } + } + return resourceMethod; + } + @Override protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { handleRequest(RequestTypeEnum.DELETE, request, response); @@ -198,46 +284,6 @@ public class RestfulServer extends HttpServlet implements IRestfulServer clazz = theProvider.getClass(); - Class supertype = clazz.getSuperclass(); - Collection resourceNames = new ArrayList(); - while (!Object.class.equals(supertype)) { - removeResourceMethods(theProvider, supertype, resourceNames); - supertype = supertype.getSuperclass(); - } - removeResourceMethods(theProvider, clazz, resourceNames); - for (String resourceName : resourceNames) { - myResourceNameToBinding.remove(resourceName); - } - } - - /* - * Collect the set of RESTful methods for a single class - * when it is being unregistered - */ - private void removeResourceMethods(Object theProvider, Class clazz, Collection resourceNames) throws ConfigurationException { - for (Method m : ReflectionUtil.getDeclaredMethods(clazz)) { - BaseMethodBinding foundMethodBinding = BaseMethodBinding.bindMethod(m, getFhirContext(), theProvider); - if (foundMethodBinding == null) { - continue; // not a bound method - } - if (foundMethodBinding instanceof ConformanceMethodBinding) { - myServerConformanceMethod = null; - continue; - } - String resourceName = foundMethodBinding.getResourceName(); - if (!resourceNames.contains(resourceName)) { - resourceNames.add(resourceName); - } - } - } - private void findResourceMethods(Object theProvider) throws Exception { ourLog.info("Scanning type for RESTful methods: {}", theProvider.getClass()); @@ -330,8 +376,9 @@ public class RestfulServer extends HttpServlet implements IRestfulServer_format URL parameter, or with an Accept header - * in the request. The default is {@link EncodingEnum#XML}. Will not return null. + * Returns the default encoding to return (XML/JSON) if an incoming request does not specify a preference (either + * with the _format URL parameter, or with an Accept header in the request. The default is + * {@link EncodingEnum#XML}. Will not return null. */ @Override public EncodingEnum getDefaultResponseEncoding() { @@ -344,8 +391,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer> getServerBindings() { return myServerBinding.getMethodBindings(); } /** - * Returns the server conformance provider, which is the provider that is used to generate the server's conformance (metadata) statement if one has been explicitly defined. + * Returns the server conformance provider, which is the provider that is used to generate the server's conformance + * (metadata) statement if one has been explicitly defined. *

- * By default, the ServerConformanceProvider for the declared version of FHIR is used, but this can be changed, or set to null to use the appropriate one for the given FHIR version. + * By default, the ServerConformanceProvider for the declared version of FHIR is used, but this can be changed, or + * set to null to use the appropriate one for the given FHIR version. *

*/ public Object getServerConformanceProvider() { @@ -446,7 +497,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer 0 && requestPath.charAt(0) == '/') { @@ -540,19 +591,21 @@ public class RestfulServer extends HttpServlet implements IRestfulServer resourceMethod = determineResourceMethod(requestDetails, requestPath); @@ -568,10 +621,12 @@ public class RestfulServer extends HttpServlet implements IRestfulServer= 0; i--) { @@ -621,8 +678,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer determineResourceMethod(RequestDetails requestDetails, String requestPath) { - RequestTypeEnum requestType = requestDetails.getRequestType(); - - ResourceBinding resourceBinding = null; - BaseMethodBinding resourceMethod = null; - String resourceName = requestDetails.getResourceName(); - if (Constants.URL_TOKEN_METADATA.equals(resourceName) || requestType == RequestTypeEnum.OPTIONS) { - resourceMethod = myServerConformanceMethod; - } else if (resourceName == null) { - resourceBinding = myServerBinding; - } else { - resourceBinding = myResourceNameToBinding.get(resourceName); - if (resourceBinding == null) { - throw new InvalidRequestException("Unknown resource type '" + resourceName + "' - Server knows how to handle: " + myResourceNameToBinding.keySet()); + /** + * Initializes the server. Note that this method is final to avoid accidentally introducing bugs in implementations, + * but subclasses may put initialization code in {@link #initialize()}, which is called immediately before beginning + * initialization of the restful server's internal init. + */ + @Override + public final void init() throws ServletException { + myProviderRegistrationMutex.lock(); + try { + initialize(); + + Object confProvider; + try { + ourLog.info("Initializing HAPI FHIR restful server running in " + getFhirContext().getVersion().getVersion().name() + " mode"); + + ProvidedResourceScanner providedResourceScanner = new ProvidedResourceScanner(getFhirContext()); + providedResourceScanner.scanForProvidedResources(this); + + Collection resourceProvider = getResourceProviders(); + // 'true' tells registerProviders() that + // this call is part of initialization + registerProviders(resourceProvider, true); + + Collection providers = getPlainProviders(); + // 'true' tells registerProviders() that + // this call is part of initialization + registerProviders(providers, true); + + findResourceMethods(getServerProfilesProvider()); + + confProvider = getServerConformanceProvider(); + if (confProvider == null) { + confProvider = getFhirContext().getVersion().createServerConformanceProvider(this); + } + // findSystemMethods(confProvider); + findResourceMethods(confProvider); + + } catch (Exception ex) { + ourLog.error("An error occurred while loading request handlers!", ex); + throw new ServletException("Failed to initialize FHIR Restful server", ex); + } + + ourLog.trace("Invoking provider initialize methods"); + if (getResourceProviders() != null) { + for (IResourceProvider iResourceProvider : getResourceProviders()) { + invokeInitialize(iResourceProvider); + } + } + if (confProvider != null) { + invokeInitialize(confProvider); + } + if (getPlainProviders() != null) { + for (Object next : getPlainProviders()) { + invokeInitialize(next); + } + } + + try { + findResourceMethods(new PageProvider()); + } catch (Exception ex) { + ourLog.error("An error occurred while loading request handlers!", ex); + throw new ServletException("Failed to initialize FHIR Restful server", ex); + } + + myStarted = true; + ourLog.info("A FHIR has been lit on this server"); + } finally { + myProviderRegistrationMutex.unlock(); + } + } + + /** + * This method may be overridden by subclasses to do perform initialization that needs to be performed prior to the + * server being used. + * + * @throws ServletException + * If the initialization failed. Note that you should consider throwing {@link UnavailableException} + * (which extends {@link ServletException}), as this is a flag to the servlet container that the servlet + * is not usable. + */ + protected void initialize() throws ServletException { + // nothing by default + } + + private void invokeDestroy(Object theProvider) { + invokeDestroy(theProvider, theProvider.getClass()); + } + + private void invokeDestroy(Object theProvider, Class clazz) { + for (Method m : ReflectionUtil.getDeclaredMethods(clazz)) { + Destroy destroy = m.getAnnotation(Destroy.class); + if (destroy != null) { + try { + m.invoke(theProvider); + } catch (IllegalAccessException e) { + ourLog.error("Exception occurred in destroy ", e); + } catch (InvocationTargetException e) { + ourLog.error("Exception occurred in destroy ", e); + } + return; } } - if (resourceMethod == null) { - if (resourceBinding != null) { - resourceMethod = resourceBinding.getMethod(requestDetails); + Class supertype = clazz.getSuperclass(); + if (!Object.class.equals(supertype)) { + invokeDestroy(theProvider, supertype); + } + } + + private void invokeInitialize(Object theProvider) { + invokeInitialize(theProvider, theProvider.getClass()); + } + + private void invokeInitialize(Object theProvider, Class clazz) { + for (Method m : ReflectionUtil.getDeclaredMethods(clazz)) { + Initialize initialize = m.getAnnotation(Initialize.class); + if (initialize != null) { + try { + m.invoke(theProvider); + } catch (IllegalAccessException e) { + ourLog.error("Exception occurred in destroy ", e); + } catch (InvocationTargetException e) { + ourLog.error("Exception occurred in destroy ", e); + } + return; } } - if (resourceMethod == null) { - if (isBlank(requestPath)) { - throw new InvalidRequestException(myFhirContext.getLocalizer().getMessage(RestfulServer.class, "rootRequest")); - } else { - throw new InvalidRequestException(myFhirContext.getLocalizer().getMessage(RestfulServer.class, "unknownMethod", requestType.name(), requestPath, requestDetails.getParameters().keySet())); - } + + Class supertype = clazz.getSuperclass(); + if (!Object.class.equals(supertype)) { + invokeInitialize(theProvider, supertype); } - return resourceMethod; + } + + /** + * Should the server "pretty print" responses by default (requesting clients can always override this default by + * supplying an Accept header in the request, or a _pretty parameter in the request URL. + *

+ * The default is false + *

+ * + * @return Returns the default pretty print setting + */ + @Override + public boolean isDefaultPrettyPrint() { + return myDefaultPrettyPrint; + } + + /** + * Should the server attempt to decompress incoming request contents (default is true). Typically this + * should be set to true unless the server has other configuration to deal with decompressing request + * bodies (e.g. a filter applied to the whole server). + */ + public boolean isUncompressIncomingContents() { + return myUncompressIncomingContents; + } + + @Override + public boolean isUseBrowserFriendlyContentTypes() { + return myUseBrowserFriendlyContentTypes; } public void populateRequestDetailsFromRequestPath(RequestDetails theRequestDetails, String theRequestPath) { StringTokenizer tok = new StringTokenizer(theRequestPath, "/"); String resourceName = null; - + IdDt id = null; String operation = null; String compartment = null; @@ -752,118 +939,41 @@ public class RestfulServer extends HttpServlet implements IRestfulServer resourceProvider = getResourceProviders(); - // 'true' tells registerProviders() that - // this call is part of initialization - registerProviders(resourceProvider, true); - - Collection providers = getPlainProviders(); - // 'true' tells registerProviders() that - // this call is part of initialization - registerProviders(providers, true); - - findResourceMethods(getServerProfilesProvider()); - - confProvider = getServerConformanceProvider(); - if (confProvider == null) { - confProvider = getFhirContext().getVersion().createServerConformanceProvider(this); - } -// findSystemMethods(confProvider); - findResourceMethods(confProvider); - - } catch (Exception ex) { - ourLog.error("An error occurred while loading request handlers!", ex); - throw new ServletException("Failed to initialize FHIR Restful server", ex); - } - - ourLog.trace("Invoking provider initialize methods"); - if (getResourceProviders() != null) { - for (IResourceProvider iResourceProvider : getResourceProviders()) { - invokeInitialize(iResourceProvider); - } - } - if (confProvider != null) { - invokeInitialize(confProvider); - } - if (getPlainProviders() != null) { - for (Object next : getPlainProviders()) { - invokeInitialize(next); - } - } - - try { - findResourceMethods(new PageProvider()); - } catch (Exception ex) { - ourLog.error("An error occurred while loading request handlers!", ex); - throw new ServletException("Failed to initialize FHIR Restful server", ex); - } - - myStarted = true; - ourLog.info("A FHIR has been lit on this server"); - } finally { - myProviderRegistrationMutex.unlock(); - } + public void registerInterceptor(IServerInterceptor theInterceptor) { + Validate.notNull(theInterceptor, "Interceptor can not be null"); + myInterceptors.add(theInterceptor); } /** - * This method may be overridden by subclasses to do perform initialization that needs to be performed prior to the server being used. - * - * @throws ServletException - * If the initialization failed. Note that you should consider throwing {@link UnavailableException} (which extends {@link ServletException}), as this is a flag to the servlet container - * that the servlet is not usable. - */ - protected void initialize() throws ServletException { - // nothing by default - } - - /** - * Register a single provider. This could be a Resource Provider - * or a "plain" provider not associated with any resource. + * Register a single provider. This could be a Resource Provider or a "plain" provider not associated with any + * resource. * * @param provider * @throws Exception */ - public void registerProvider (Object provider) throws Exception { + public void registerProvider(Object provider) throws Exception { if (provider != null) { Collection providerList = new ArrayList(1); providerList.add(provider); registerProviders(providerList); } } - + /** - * Register a group of providers. These could be Resource Providers, - * "plain" providers or a mixture of the two. + * Register a group of providers. These could be Resource Providers, "plain" providers or a mixture of the two. * - * @param providers a {@code Collection} of providers. The parameter - * could be null or an empty {@code Collection} + * @param providers + * a {@code Collection} of providers. The parameter could be null or an empty {@code Collection} * @throws Exception */ - public void registerProviders (Collection providers) throws Exception { + public void registerProviders(Collection providers) throws Exception { myProviderRegistrationMutex.lock(); try { if (!myStarted) { for (Object provider : providers) { - ourLog.info("Registration of provider ["+provider.getClass().getName()+"] will be delayed until FHIR server startup"); + ourLog.info("Registration of provider [" + provider.getClass().getName() + "] will be delayed until FHIR server startup"); if (provider instanceof IResourceProvider) { - myResourceProviders.add((IResourceProvider)provider); + myResourceProviders.add((IResourceProvider) provider); } else { myPlainProviders.add(provider); } @@ -875,11 +985,11 @@ public class RestfulServer extends HttpServlet implements IRestfulServer providers, boolean inInit) throws Exception { + protected void registerProviders(Collection providers, boolean inInit) throws Exception { List newResourceProviders = new ArrayList(); List newPlainProviders = new ArrayList(); ProvidedResourceScanner providedResourceScanner = new ProvidedResourceScanner(getFhirContext()); @@ -887,7 +997,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer resourceType = rsrcProvider.getResourceType(); if (resourceType == null) { throw new NullPointerException("getResourceType() on class '" + rsrcProvider.getClass().getCanonicalName() + "' returned null"); @@ -908,7 +1018,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer providerList = new ArrayList(1); - providerList.add(provider); - unregisterProviders(providerList); - } - } - - /** - * Unregister a {@code Collection} of providers - * - * @param providers - * @throws Exception - */ - public void unregisterProviders (Collection providers) throws Exception { - ProvidedResourceScanner providedResourceScanner = new ProvidedResourceScanner(getFhirContext()); - if (providers != null) { - for (Object provider : providers) { - removeResourceMethods(provider); - if (provider instanceof IResourceProvider) { - myResourceProviders.remove(provider); - IResourceProvider rsrcProvider = (IResourceProvider)provider; - Class resourceType = rsrcProvider.getResourceType(); - String resourceName = getFhirContext().getResourceDefinition(resourceType).getName(); - myTypeToProvider.remove(resourceName); - providedResourceScanner.removeProvidedResources(rsrcProvider); - } else { - myPlainProviders.remove(provider); - } - invokeDestroy(provider); - } - } - } - - private void invokeDestroy(Object theProvider) { - invokeDestroy(theProvider, theProvider.getClass()); - } - - private void invokeInitialize(Object theProvider) { - invokeInitialize(theProvider, theProvider.getClass()); - } - - private void invokeDestroy(Object theProvider, Class clazz) { - for (Method m : ReflectionUtil.getDeclaredMethods(clazz)) { - Destroy destroy = m.getAnnotation(Destroy.class); - if (destroy != null) { - try { - m.invoke(theProvider); - } catch (IllegalAccessException e) { - ourLog.error("Exception occurred in destroy ", e); - } catch (InvocationTargetException e) { - ourLog.error("Exception occurred in destroy ", e); - } - return; - } - } - + private void removeResourceMethods(Object theProvider) throws Exception { + ourLog.info("Removing RESTful methods for: {}", theProvider.getClass()); + Class clazz = theProvider.getClass(); Class supertype = clazz.getSuperclass(); - if (!Object.class.equals(supertype)) { - invokeDestroy(theProvider, supertype); + Collection resourceNames = new ArrayList(); + while (!Object.class.equals(supertype)) { + removeResourceMethods(theProvider, supertype, resourceNames); + supertype = supertype.getSuperclass(); + } + removeResourceMethods(theProvider, clazz, resourceNames); + for (String resourceName : resourceNames) { + myResourceNameToBinding.remove(resourceName); } } - private void invokeInitialize(Object theProvider, Class clazz) { + /* + * Collect the set of RESTful methods for a single class when it is being unregistered + */ + private void removeResourceMethods(Object theProvider, Class clazz, Collection resourceNames) throws ConfigurationException { for (Method m : ReflectionUtil.getDeclaredMethods(clazz)) { - Initialize initialize = m.getAnnotation(Initialize.class); - if (initialize != null) { - try { - m.invoke(theProvider); - } catch (IllegalAccessException e) { - ourLog.error("Exception occurred in destroy ", e); - } catch (InvocationTargetException e) { - ourLog.error("Exception occurred in destroy ", e); - } - return; + BaseMethodBinding foundMethodBinding = BaseMethodBinding.bindMethod(m, getFhirContext(), theProvider); + if (foundMethodBinding == null) { + continue; // not a bound method + } + if (foundMethodBinding instanceof ConformanceMethodBinding) { + myServerConformanceMethod = null; + continue; + } + String resourceName = foundMethodBinding.getResourceName(); + if (!resourceNames.contains(resourceName)) { + resourceNames.add(resourceName); } } + } - Class supertype = clazz.getSuperclass(); - if (!Object.class.equals(supertype)) { - invokeInitialize(theProvider, supertype); + public Object returnResponse(ServletRequestDetails theRequest, ParseAction outcome, int operationStatus, boolean allowPrefer, MethodOutcome response, String resourceName) throws IOException { + HttpServletResponse servletResponse = theRequest.getServletResponse(); + servletResponse.setStatus(operationStatus); + servletResponse.setCharacterEncoding(Constants.CHARSET_NAME_UTF8); + addHeadersToResponse(servletResponse); + if (allowPrefer) { + addContentLocationHeaders(theRequest, servletResponse, response, resourceName); } + if (outcome != null) { + EncodingEnum encoding = RestfulServerUtils.determineResponseEncodingWithDefault(theRequest); + servletResponse.setContentType(encoding.getResourceContentType()); + Writer writer = servletResponse.getWriter(); + IParser parser = encoding.newParser(getFhirContext()); + parser.setPrettyPrint(RestfulServerUtils.prettyPrintResponse(this, theRequest)); + try { + outcome.execute(parser, writer); + } finally { + writer.close(); + } + } else { + servletResponse.setContentType(Constants.CT_TEXT_WITH_UTF8); + Writer writer = servletResponse.getWriter(); + writer.close(); + } + // getMethod().in + return null; } /** - * Should the server "pretty print" responses by default (requesting clients can always override this default by supplying an Accept header in the request, or a _pretty - * parameter in the request URL. - *

- * The default is false - *

- * - * @return Returns the default pretty print setting - */ - @Override - public boolean isDefaultPrettyPrint() { - return myDefaultPrettyPrint; - } - - @Override - public boolean isUseBrowserFriendlyContentTypes() { - return myUseBrowserFriendlyContentTypes; - } - - public void registerInterceptor(IServerInterceptor theInterceptor) { - Validate.notNull(theInterceptor, "Interceptor can not be null"); - myInterceptors.add(theInterceptor); - } - - /** - * Sets the profile tagging behaviour for the server. When set to a value other than {@link AddProfileTagEnum#NEVER} (which is the default), the server will automatically add a profile tag based on - * the class of the resource(s) being returned. + * Sets the profile tagging behaviour for the server. When set to a value other than {@link AddProfileTagEnum#NEVER} + * (which is the default), the server will automatically add a profile tag based on the class of the resource(s) + * being returned. * * @param theAddProfileTag * The behaviour enum (must not be null) @@ -1077,8 +1140,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServerAccept header in the request, or a _pretty - * parameter in the request URL. + * Should the server "pretty print" responses by default (requesting clients can always override this default by + * supplying an Accept header in the request, or a _pretty parameter in the request URL. *

* The default is false *

@@ -1091,10 +1154,12 @@ public class RestfulServer extends HttpServlet implements IRestfulServer_format URL parameter, or with an Accept header in - * the request. The default is {@link EncodingEnum#XML}. + * Sets the default encoding to return (XML/JSON) if an incoming request does not specify a preference (either with + * the _format URL parameter, or with an Accept header in the request. The default is + * {@link EncodingEnum#XML}. *

- * Note when testing this feature: Some browsers will include "application/xml" in their Accept header, which means that the + * Note when testing this feature: Some browsers will include "application/xml" in their Accept header, which means + * that the *

*/ public void setDefaultResponseEncoding(EncodingEnum theDefaultResponseEncoding) { @@ -1103,7 +1168,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServernull. Default is {@link #DEFAULT_ETAG_SUPPORT} + * Sets (enables/disables) the server support for ETags. Must not be null. Default is + * {@link #DEFAULT_ETAG_SUPPORT} * * @param theETagSupport * The ETag support mode @@ -1211,7 +1277,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer - * By default, the ServerConformanceProvider implementation for the declared version of FHIR is used, but this can be changed, or set to null if you do not wish to export a conformance - * statement. + * By default, the ServerConformanceProvider implementation for the declared version of FHIR is used, but this can be + * changed, or set to null if you do not wish to export a conformance statement. *

* Note that this method can only be called before the server is initialized. * * @throws IllegalStateException - * Note that this method can only be called prior to {@link #init() initialization} and will throw an {@link IllegalStateException} if called after that. + * Note that this method can only be called prior to {@link #init() initialization} and will throw an + * {@link IllegalStateException} if called after that. */ public void setServerConformanceProvider(Object theServerConformanceProvider) { if (myStarted) { @@ -1237,35 +1306,46 @@ public class RestfulServer extends HttpServlet implements IRestfulServertrue (default is false), the server will use browser friendly content-types (instead of standard FHIR ones) when it detects that the request is coming from a browser - * instead of a FHIR + * Should the server attempt to decompress incoming request contents (default is true). Typically this + * should be set to true unless the server has other configuration to deal with decompressing request + * bodies (e.g. a filter applied to the whole server). + */ + public void setUncompressIncomingContents(boolean theUncompressIncomingContents) { + myUncompressIncomingContents = theUncompressIncomingContents; + } + + /** + * If set to true (default is false), the server will use browser friendly content-types (instead of + * standard FHIR ones) when it detects that the request is coming from a browser instead of a FHIR */ public void setUseBrowserFriendlyContentTypes(boolean theUseBrowserFriendlyContentTypes) { myUseBrowserFriendlyContentTypes = theUseBrowserFriendlyContentTypes; @@ -1276,6 +1356,46 @@ public class RestfulServer extends HttpServlet implements IRestfulServer providerList = new ArrayList(1); + providerList.add(provider); + unregisterProviders(providerList); + } + } + + /** + * Unregister a {@code Collection} of providers + * + * @param providers + * @throws Exception + */ + public void unregisterProviders(Collection providers) throws Exception { + ProvidedResourceScanner providedResourceScanner = new ProvidedResourceScanner(getFhirContext()); + if (providers != null) { + for (Object provider : providers) { + removeResourceMethods(provider); + if (provider instanceof IResourceProvider) { + myResourceProviders.remove(provider); + IResourceProvider rsrcProvider = (IResourceProvider) provider; + Class resourceType = rsrcProvider.getResourceType(); + String resourceName = getFhirContext().getResourceDefinition(resourceType).getName(); + myTypeToProvider.remove(resourceName); + providedResourceScanner.removeProvidedResources(rsrcProvider); + } else { + myPlainProviders.remove(provider); + } + invokeDestroy(provider); + } + } + } + private void writeExceptionToResponse(HttpServletResponse theResponse, BaseServerResponseException theException) throws IOException { theResponse.setStatus(theException.getStatusCode()); addHeadersToResponse(theResponse); @@ -1293,86 +1413,4 @@ public class RestfulServer extends HttpServlet implements IRestfulServer outcome, int operationStatus, boolean allowPrefer, MethodOutcome response, - String resourceName) throws IOException { - HttpServletResponse servletResponse = theRequest.getServletResponse(); - servletResponse.setStatus(operationStatus); - servletResponse.setCharacterEncoding(Constants.CHARSET_NAME_UTF8); - addHeadersToResponse(servletResponse); - if(allowPrefer) { - addContentLocationHeaders(theRequest, servletResponse, response, resourceName); - } - if (outcome != null) { - EncodingEnum encoding = RestfulServerUtils.determineResponseEncodingWithDefault(theRequest); - servletResponse.setContentType(encoding.getResourceContentType()); - Writer writer = servletResponse.getWriter(); - IParser parser = encoding.newParser(getFhirContext()); - parser.setPrettyPrint(RestfulServerUtils.prettyPrintResponse(this, theRequest)); - try { - outcome.execute(parser, writer); - } finally { - writer.close(); - } - } else { - servletResponse.setContentType(Constants.CT_TEXT_WITH_UTF8); - Writer writer = servletResponse.getWriter(); - writer.close(); - } - // getMethod().in - return null; - } - - private void addContentLocationHeaders(RequestDetails theRequest, HttpServletResponse servletResponse, MethodOutcome response, String resourceName) { - if (response != null && response.getId() != null) { - addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_LOCATION, resourceName); - addLocationHeader(theRequest, servletResponse, response, Constants.HEADER_CONTENT_LOCATION, resourceName); - } - } - - private void addLocationHeader(RequestDetails theRequest, HttpServletResponse theResponse, MethodOutcome response, String headerLocation, String resourceName) { - StringBuilder b = new StringBuilder(); - b.append(theRequest.getFhirServerBase()); - b.append('/'); - b.append(resourceName); - b.append('/'); - b.append(response.getId().getIdPart()); - if (response.getId().hasVersionIdPart()) { - b.append("/" + Constants.PARAM_HISTORY + "/"); - b.append(response.getId().getVersionIdPart()); - } else if (response.getVersionId() != null && response.getVersionId().isEmpty() == false) { - b.append("/" + Constants.PARAM_HISTORY + "/"); - b.append(response.getVersionId().getValue()); - } - theResponse.addHeader(headerLocation, b.toString()); - - } - - public RestulfulServerConfiguration createConfiguration() { - RestulfulServerConfiguration result = new RestulfulServerConfiguration(); - result.setResourceBindings(getResourceBindings()); - result.setServerBindings(getServerBindings()); - result.setImplementationDescription(getImplementationDescription()); - result.setServerVersion(getServerVersion()); - result.setServerName(getServerName()); - result.setFhirContext(getFhirContext()); - result.setServerAddressStrategy(myServerAddressStrategy); - InputStream inputStream = null; - try { - inputStream = getClass().getResourceAsStream("/META-INF/MANIFEST.MF"); - if (inputStream != null) { - Manifest manifest = new Manifest(inputStream); - result.setConformanceDate(manifest.getMainAttributes().getValue("Build-Time")); - } - } - catch (IOException e) { - // fall through - } - finally { - if (inputStream != null) { - IOUtils.closeQuietly(inputStream); - } - } - return result; - } - } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestulfulServerConfiguration.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestulfulServerConfiguration.java index 195a77b62fe..909ee90b844 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestulfulServerConfiguration.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestulfulServerConfiguration.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.Collection; import java.util.List; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java index 86d4e83e765..9f30c592882 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java @@ -1,5 +1,28 @@ package ca.uhn.fhir.rest.server.servlet; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +/* + * #%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.io.IOException; import java.io.InputStream; import java.io.Reader; @@ -9,17 +32,21 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; +import org.apache.tools.ant.taskdefs.GUnzip; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.method.BaseMethodBinding; import ca.uhn.fhir.rest.method.BaseMethodBinding.IRequestReader; 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.exceptions.InvalidRequestException; @@ -72,6 +99,16 @@ public class ServletRequestDetails extends RequestDetails { try { InputStream inputStream = reader.getInputStream(this); requestContents = IOUtils.toByteArray(inputStream); + + if (myServer.isUncompressIncomingContents()) { + String contentEncoding = myServletRequest.getHeader(Constants.HEADER_CONTENT_ENCODING); + if ("gzip".equals(contentEncoding)) { + ourLog.debug("Uncompressing (GZip) incoming content"); + GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(requestContents)); + requestContents = IOUtils.toByteArray(gis); + } + } + return requestContents; } catch (IOException e) { ourLog.error("Could not load request resource", e); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRestfulResponse.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRestfulResponse.java index 97ce9f5ebfb..c5fecb39235 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRestfulResponse.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRestfulResponse.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.rest.server.servlet; +/* + * #%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.io.IOException; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; diff --git a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ExampleDataUploader.java b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ExampleDataUploader.java index d771b94e514..a8d27f67973 100644 --- a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ExampleDataUploader.java +++ b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ExampleDataUploader.java @@ -7,7 +7,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileWriter; -import java.net.URL; +import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -25,21 +25,24 @@ import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; +import org.fusesource.jansi.Ansi; +import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseResource; import com.phloc.commons.io.file.FileUtils; +import ca.uhn.fhir.context.BaseRuntimeChildDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.dstu2.resource.Bundle; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryRequest; -import ca.uhn.fhir.model.dstu2.resource.SearchParameter; -import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum; import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.rest.client.IGenericClient; +import ca.uhn.fhir.rest.client.interceptor.GZipContentInterceptor; import ca.uhn.fhir.util.ResourceReferenceInfo; public class ExampleDataUploader extends BaseCommand { @@ -75,6 +78,10 @@ public class ExampleDataUploader extends BaseCommand { opt.setRequired(false); options.addOption(opt); + opt = new Option("c", "cache", true, "Store a copy of the downloaded example pack on the local disk using a file of the given name. Use this file instead of fetching it from the internet if the file already exists."); + opt.setRequired(false); + options.addOption(opt); + return options; } @@ -121,8 +128,8 @@ public class ExampleDataUploader extends BaseCommand { } Bundle bundle = new Bundle(); { - - byte[] inputBytes = IOUtils.toByteArray(result.getEntity().getContent()); + byte[] inputBytes = readStreamFromInternet(result); + IOUtils.closeQuietly(result.getEntity().getContent()); ourLog.info("Successfully Loaded example pack ({} bytes)", inputBytes.length); @@ -163,26 +170,23 @@ public class ExampleDataUploader extends BaseCommand { } ourLog.info("Found example {} - {} - {} chars", nextEntry.getName(), parsed.getClass().getSimpleName(), exampleString.length()); - if (parsed instanceof Bundle) { - Bundle b = (Bundle) parsed; - if (b.getTypeElement().getValueAsEnum() != BundleTypeEnum.DOCUMENT) { - continue; - } + if (ctx.getResourceDefinition(parsed).getName().equals("Bundle")) { + BaseRuntimeChildDefinition entryChildDef = ctx.getResourceDefinition(parsed).getChildByName("entry"); + BaseRuntimeElementCompositeDefinition entryDef = (BaseRuntimeElementCompositeDefinition) entryChildDef.getChildByName("entry"); - for (Entry nextEntry1 : b.getEntry()) { - if (nextEntry1.getResource() == null) { + for (IBase nextEntry1 : entryChildDef.getAccessor().getValues(parsed)) { + List resources = entryDef.getChildByName("resource").getAccessor().getValues(nextEntry1); + if (resources == null) { continue; } - if (nextEntry1.getResource() instanceof Bundle) { - continue; + for (IBase nextResource : resources) { + if (!ctx.getResourceDefinition(parsed).getName().equals("Bundle") && ctx.getResourceDefinition(parsed).getName().equals("SearchParameter")) { + bundle.addEntry().setRequest(new EntryRequest().setMethod(HTTPVerbEnum.POST)).setResource((IResource) nextResource); + } } - if (nextEntry1.getResource() instanceof SearchParameter) { - continue; - } - bundle.addEntry().setRequest(new EntryRequest().setMethod(HTTPVerbEnum.POST)).setResource(nextEntry1.getResource()); } } else { - if (parsed instanceof SearchParameter) { + if (ctx.getResourceDefinition(parsed).getName().equals("SearchParameter")) { continue; } bundle.addEntry().setRequest(new EntryRequest().setMethod(HTTPVerbEnum.POST)).setResource((IResource) parsed); @@ -242,6 +246,7 @@ public class ExampleDataUploader extends BaseCommand { } next.getRequest().setMethod(HTTPVerbEnum.PUT); next.getRequest().setUrl(nextId); + next.getResource().setId(""); renames.put(originalId, nextId); } } @@ -302,6 +307,7 @@ public class ExampleDataUploader extends BaseCommand { ourLog.info("Uploading bundle to server: " + targetServer); IGenericClient fhirClient = newClient(ctx, targetServer); + fhirClient.registerInterceptor(new GZipContentInterceptor()); long start = System.currentTimeMillis(); ; @@ -312,4 +318,40 @@ public class ExampleDataUploader extends BaseCommand { } } + private byte[] readStreamFromInternet(CloseableHttpResponse result) throws IOException { + byte[] inputBytes; + { + long maxLength = result.getEntity().getContentLength(); + int nextLog = -1; + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[16384]; + while ((nRead = result.getEntity().getContent().read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + if (buffer.size() > nextLog) { + System.err.print("\r" + Ansi.ansi().eraseLine()); + System.err.print(FileUtils.getFileSizeDisplay(buffer.size(), 1)); + if (maxLength > 0) { + System.err.print(" ["); + int stars = (int)(50.0f * ((float)buffer.size() / (float)maxLength)); + for (int i = 0; i < stars; i++) { + System.err.print("*"); + } + for (int i = stars; i < 50; i++) { + System.err.print(" "); + } + System.err.print("]"); + } + System.err.flush(); + nextLog += 100000; + } + } + buffer.flush(); + inputBytes = buffer.toByteArray(); + } + System.err.println(); + System.err.flush(); + return inputBytes; + } + } diff --git a/hapi-fhir-cli/tmp.txt.gz b/hapi-fhir-cli/tmp.txt.gz new file mode 100644 index 00000000000..773d5921a0e Binary files /dev/null and b/hapi-fhir-cli/tmp.txt.gz differ diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/interceptor/CompressOutgoingContentInterceptorTest.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/interceptor/CompressOutgoingContentInterceptorTest.java new file mode 100644 index 00000000000..44134c4b3c1 --- /dev/null +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/interceptor/CompressOutgoingContentInterceptorTest.java @@ -0,0 +1,99 @@ +package ca.uhn.fhir.rest.client.interceptor; + +import static org.junit.Assert.*; + +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.client.IGenericClient; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.util.PortUtil; + +public class CompressOutgoingContentInterceptorTest { + + private static IGenericClient ourClient; + private static FhirContext ourCtx = FhirContext.forDstu2(); + private static Patient ourLastPatient; + private static String ourLastReq; + private static String ourLastResponseEncoding; + private static int ourPort; + private static Server ourServer; + + @Before + public void before() { + ourClient = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort); + } + + @Test + public void testCreate() throws Exception { + ourClient.registerInterceptor(new GZipContentInterceptor()); + + Patient p = new Patient(); + p.addName().addFamily("FAMILY"); + + ourClient.create().resource(p).execute(); + + assertEquals("FAMILY", p.getName().get(0).getFamily().get(0).getValue()); + assertEquals("gzip", ourLastReq); + assertEquals("gzip", ourLastResponseEncoding); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(ourCtx); + servlet.setPagingProvider(new FifoMemoryPagingProvider(10)); + + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + } + + public static class DummyPatientResourceProvider implements IResourceProvider { + + @Create + public MethodOutcome create(HttpServletRequest theReq, @ResourceParam Patient thePatient) { + ourLastReq = theReq.getHeader(Constants.HEADER_CONTENT_ENCODING.toLowerCase()); + ourLastResponseEncoding = theReq.getHeader(Constants.HEADER_ACCEPT_ENCODING.toLowerCase()); + ourLastPatient = thePatient; + return new MethodOutcome(new IdDt("Patient", "1")); + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index 307922cf5b9..0402b6e12cd 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 1.4-SNAPSHOT + 1.3 ../pom.xml @@ -19,7 +19,7 @@ ca.uhn.hapi.fhir hapi-fhir-base - 1.4-SNAPSHOT + 1.3 ca.uhn.hapi.fhir hapi-fhir-structures-hl7org-dstu2 - 1.4-SNAPSHOT + 1.3 ca.uhn.hapi.fhir hapi-fhir-validation-resources-dstu2 - 1.4-SNAPSHOT + 1.3 + org.apache.velocity velocity diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/AgeDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/AgeDt.java new file mode 100644 index 00000000000..57d830f0985 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/AgeDt.java @@ -0,0 +1,30 @@ +package ca.uhn.fhir.model.dstu21.composite; + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.dstu21.composite.QuantityDt; +import ca.uhn.fhir.model.primitive.IntegerDt; + +/* + * #%L + * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) + * %% + * 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% + */ + +@DatatypeDef(name="AgeDt") +public class AgeDt extends QuantityDt { + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/BoundCodeableConceptDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/BoundCodeableConceptDt.java new file mode 100644 index 00000000000..e0f5f671a8e --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/BoundCodeableConceptDt.java @@ -0,0 +1,141 @@ +package ca.uhn.fhir.model.dstu21.composite; + +/* + * #%L + * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) + * %% + * 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.defaultString; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.lang3.Validate; + +import ca.uhn.fhir.model.api.IBoundCodeableConcept; +import ca.uhn.fhir.model.api.IValueSetEnumBinder; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.dstu21.composite.CodeableConceptDt; +import ca.uhn.fhir.model.dstu21.composite.CodingDt; + +@DatatypeDef(name = "CodeableConcept", isSpecialization = true) +public class BoundCodeableConceptDt> extends CodeableConceptDt implements IBoundCodeableConcept { + + private IValueSetEnumBinder myBinder; + + /** + * @deprecated This constructor is provided only for serialization support. Do not call it directly! + */ + @Deprecated + public BoundCodeableConceptDt() { + // nothing + } + + /** + * Constructor + */ + public BoundCodeableConceptDt(IValueSetEnumBinder theBinder) { + Validate.notNull(theBinder, "theBinder must not be null"); + myBinder = theBinder; + } + + /** + * Constructor + */ + public BoundCodeableConceptDt(IValueSetEnumBinder theBinder, T theValue) { + Validate.notNull(theBinder, "theBinder must not be null"); + myBinder = theBinder; + setValueAsEnum(theValue); + } + + /** + * Constructor + */ + public BoundCodeableConceptDt(IValueSetEnumBinder theBinder, Collection theValues) { + Validate.notNull(theBinder, "theBinder must not be null"); + myBinder = theBinder; + setValueAsEnum(theValues); + } + + /** + * Sets the {@link #getCoding()} to contain a coding with the code and + * system defined by the given enumerated types, AND clearing any existing + * codings first. If theValue is null, existing codings are cleared and no + * codings are added. + * + * @param theValues + * The value to add, or null + */ + public void setValueAsEnum(Collection theValues) { + Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeableConceptDt() should not be called!"); + getCoding().clear(); + if (theValues != null) { + for (T next : theValues) { + getCoding().add(new CodingDt(myBinder.toSystemString(next), myBinder.toCodeString(next))); + } + } + } + + /** + * Sets the {@link #getCoding()} to contain a coding with the code and + * system defined by the given enumerated type, AND clearing any existing + * codings first. If theValue is null, existing codings are cleared and no + * codings are added. + * + * @param theValue + * The value to add, or null + */ + public void setValueAsEnum(T theValue) { + Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeableConceptDt() should not be called!"); + getCoding().clear(); + if (theValue == null) { + return; + } + getCoding().add(new CodingDt(myBinder.toSystemString(theValue), myBinder.toCodeString(theValue))); + } + + /** + * Loops through the {@link #getCoding() codings} in this codeable concept + * and returns the first bound enumerated type that matches. Use + * caution using this method, see the return description for more + * information. + * + * @return Returns the bound enumerated type, or null if none + * are found. Note that a null return value doesn't neccesarily + * imply that this Codeable Concept has no codes, only that it has + * no codes that match the enum. + */ + public Set getValueAsEnum() { + Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeableConceptDt() should not be called!"); + Set retVal = new HashSet(); + for (CodingDt next : getCoding()) { + if (next == null) { + continue; + } + T nextT = myBinder.fromCodeString(defaultString(next.getCodeElement().getValue()), defaultString(next.getSystemElement().getValueAsString())); + if (nextT != null) { + retVal.add(nextT); + } else { + // TODO: throw special exception type? + } + } + return retVal; + } + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/CodeableConceptDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/CodeableConceptDt.java new file mode 100644 index 00000000000..97746c08fa0 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/CodeableConceptDt.java @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu21.composite; + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.primitive.StringDt; + +/** + * HAPI/FHIR CodeableConceptDt Datatype + * () + * + *

+ * Definition: + * A concept that may be defined by a formal reference to a terminology or ontology or may be provided by text + *

+ * + *

+ * Requirements: + * This is a common pattern in healthcare - a concept that may be defined by one or more codes from formal definitions including LOINC and SNOMED CT, and/or defined by the provision of text that captures a human sense of the concept + *

+ */ +@DatatypeDef(name="CodeableConceptDt") +public class CodeableConceptDt + extends BaseIdentifiableElement implements ICompositeDatatype{ + + /** + * Constructor + */ + public CodeableConceptDt() { + // nothing + } + + /** + * Constructor which creates a CodeableConceptDt with one coding repetition, containing + * the given system and code + */ + public CodeableConceptDt(String theSystem, String theCode) { + addCoding().setSystem(theSystem).setCode(theCode); + } + + @Child(name="coding", type=CodingDt.class, order=0, min=0, max=Child.MAX_UNLIMITED, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="A reference to a code defined by a terminology system" + ) + private java.util.List myCoding; + + @Child(name="text", type=StringDt.class, order=1, min=0, max=1, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user" + ) + private StringDt myText; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myCoding, myText); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myCoding, myText); + } + + /** + * Gets the value(s) for coding (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ */ + public java.util.List getCoding() { + if (myCoding == null) { + myCoding = new java.util.ArrayList(); + } + return myCoding; + } + + /** + * Sets the value(s) for coding () + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ */ + public CodeableConceptDt setCoding(java.util.List theValue) { + myCoding = theValue; + return this; + } + + + + /** + * Adds and returns a new value for coding () + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ */ + public CodingDt addCoding() { + CodingDt newType = new CodingDt(); + getCoding().add(newType); + return newType; + } + + /** + * Adds a given new value for coding () + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ * @param theValue The coding to add (must not be null) + */ + public CodeableConceptDt addCoding(CodingDt theValue) { + if (theValue == null) { + throw new NullPointerException("theValue must not be null"); + } + getCoding().add(theValue); + return this; + } + + /** + * Gets the first repetition for coding (), + * creating it if it does not already exist. + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ */ + public CodingDt getCodingFirstRep() { + if (getCoding().isEmpty()) { + return addCoding(); + } + return getCoding().get(0); + } + + /** + * Gets the value(s) for text (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user + *

+ */ + public StringDt getTextElement() { + if (myText == null) { + myText = new StringDt(); + } + return myText; + } + + + /** + * Gets the value(s) for text (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user + *

+ */ + public String getText() { + return getTextElement().getValue(); + } + + /** + * Sets the value(s) for text () + * + *

+ * Definition: + * A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user + *

+ */ + public CodeableConceptDt setText(StringDt theValue) { + myText = theValue; + return this; + } + + + + /** + * Sets the value for text () + * + *

+ * Definition: + * A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user + *

+ */ + public CodeableConceptDt setText( String theString) { + myText = new StringDt(theString); + return this; + } + + + + +} \ No newline at end of file diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/CodingDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/CodingDt.java new file mode 100644 index 00000000000..254eb32b01e --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/CodingDt.java @@ -0,0 +1,426 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu21.composite; + +import java.util.List; + +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.base.composite.BaseCodingDt; +import ca.uhn.fhir.model.primitive.BooleanDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; + +/** + * HAPI/FHIR CodingDt Datatype + * () + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ * + *

+ * Requirements: + * References to codes are very common in healthcare models + *

+ */ +@DatatypeDef(name="CodingDt") +public class CodingDt + extends BaseCodingDt implements ICompositeDatatype, org.hl7.fhir.instance.model.api.IBaseCoding { + + /** + * Constructor + */ + public CodingDt() { + // nothing + } + + /** + * Creates a new Coding with the given system and code + */ + public CodingDt(String theSystem, String theCode) { + setSystem(theSystem); + setCode(theCode); + } + + /** + * Copy constructor: Creates a new Coding with the system and code copied out of the given coding + */ + public CodingDt(BaseCodingDt theCoding) { + this(theCoding.getSystemElement().getValueAsString(), theCoding.getCodeElement().getValue()); + } + + + @Child(name="system", type=UriDt.class, order=0, min=0, max=1, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="The identification of the code system that defines the meaning of the symbol in the code." + ) + private UriDt mySystem; + + @Child(name="version", type=StringDt.class, order=1, min=0, max=1, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="The version of the code system which was used when choosing this code. Note that a well-maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured. and when the meaning is not guaranteed to be consistent, the version SHOULD be exchanged" + ) + private StringDt myVersion; + + @Child(name="code", type=CodeDt.class, order=2, min=0, max=1, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination)" + ) + private CodeDt myCode; + + @Child(name="display", type=StringDt.class, order=3, min=0, max=1, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="A representation of the meaning of the code in the system, following the rules of the system" + ) + private StringDt myDisplay; + + @Child(name="userSelected", type=BooleanDt.class, order=4, min=0, max=1, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="Indicates that this coding was chosen by a user directly - i.e. off a pick list of available items (codes or displays)" + ) + private BooleanDt myUserSelected; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( mySystem, myVersion, myCode, myDisplay, myUserSelected); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, mySystem, myVersion, myCode, myDisplay, myUserSelected); + } + + /** + * Gets the value(s) for system (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identification of the code system that defines the meaning of the symbol in the code. + *

+ */ + public UriDt getSystemElement() { + if (mySystem == null) { + mySystem = new UriDt(); + } + return mySystem; + } + + + /** + * Gets the value(s) for system (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identification of the code system that defines the meaning of the symbol in the code. + *

+ */ + public String getSystem() { + return getSystemElement().getValue(); + } + + /** + * Sets the value(s) for system () + * + *

+ * Definition: + * The identification of the code system that defines the meaning of the symbol in the code. + *

+ */ + public CodingDt setSystem(UriDt theValue) { + mySystem = theValue; + return this; + } + + + + /** + * Sets the value for system () + * + *

+ * Definition: + * The identification of the code system that defines the meaning of the symbol in the code. + *

+ */ + public CodingDt setSystem( String theUri) { + mySystem = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for version (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The version of the code system which was used when choosing this code. Note that a well-maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured. and when the meaning is not guaranteed to be consistent, the version SHOULD be exchanged + *

+ */ + public StringDt getVersionElement() { + if (myVersion == null) { + myVersion = new StringDt(); + } + return myVersion; + } + + + /** + * Gets the value(s) for version (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The version of the code system which was used when choosing this code. Note that a well-maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured. and when the meaning is not guaranteed to be consistent, the version SHOULD be exchanged + *

+ */ + public String getVersion() { + return getVersionElement().getValue(); + } + + /** + * Sets the value(s) for version () + * + *

+ * Definition: + * The version of the code system which was used when choosing this code. Note that a well-maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured. and when the meaning is not guaranteed to be consistent, the version SHOULD be exchanged + *

+ */ + public CodingDt setVersion(StringDt theValue) { + myVersion = theValue; + return this; + } + + + + /** + * Sets the value for version () + * + *

+ * Definition: + * The version of the code system which was used when choosing this code. Note that a well-maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured. and when the meaning is not guaranteed to be consistent, the version SHOULD be exchanged + *

+ */ + public CodingDt setVersion( String theString) { + myVersion = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for code (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination) + *

+ */ + public CodeDt getCodeElement() { + if (myCode == null) { + myCode = new CodeDt(); + } + return myCode; + } + + + /** + * Gets the value(s) for code (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination) + *

+ */ + public String getCode() { + return getCodeElement().getValue(); + } + + /** + * Sets the value(s) for code () + * + *

+ * Definition: + * A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination) + *

+ */ + public CodingDt setCode(CodeDt theValue) { + myCode = theValue; + return this; + } + + + + /** + * Sets the value for code () + * + *

+ * Definition: + * A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination) + *

+ */ + public CodingDt setCode( String theCode) { + myCode = new CodeDt(theCode); + return this; + } + + + /** + * Gets the value(s) for display (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A representation of the meaning of the code in the system, following the rules of the system + *

+ */ + public StringDt getDisplayElement() { + if (myDisplay == null) { + myDisplay = new StringDt(); + } + return myDisplay; + } + + + /** + * Gets the value(s) for display (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A representation of the meaning of the code in the system, following the rules of the system + *

+ */ + public String getDisplay() { + return getDisplayElement().getValue(); + } + + /** + * Sets the value(s) for display () + * + *

+ * Definition: + * A representation of the meaning of the code in the system, following the rules of the system + *

+ */ + public CodingDt setDisplay(StringDt theValue) { + myDisplay = theValue; + return this; + } + + + + /** + * Sets the value for display () + * + *

+ * Definition: + * A representation of the meaning of the code in the system, following the rules of the system + *

+ */ + public CodingDt setDisplay( String theString) { + myDisplay = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for userSelected (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Indicates that this coding was chosen by a user directly - i.e. off a pick list of available items (codes or displays) + *

+ */ + public BooleanDt getUserSelectedElement() { + if (myUserSelected == null) { + myUserSelected = new BooleanDt(); + } + return myUserSelected; + } + + + /** + * Gets the value(s) for userSelected (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Indicates that this coding was chosen by a user directly - i.e. off a pick list of available items (codes or displays) + *

+ */ + public Boolean getUserSelected() { + return getUserSelectedElement().getValue(); + } + + /** + * Sets the value(s) for userSelected () + * + *

+ * Definition: + * Indicates that this coding was chosen by a user directly - i.e. off a pick list of available items (codes or displays) + *

+ */ + public CodingDt setUserSelected(BooleanDt theValue) { + myUserSelected = theValue; + return this; + } + + + + /** + * Sets the value for userSelected () + * + *

+ * Definition: + * Indicates that this coding was chosen by a user directly - i.e. off a pick list of available items (codes or displays) + *

+ */ + public CodingDt setUserSelected( boolean theBoolean) { + myUserSelected = new BooleanDt(theBoolean); + return this; + } + + + + +} \ No newline at end of file diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/ContainedDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/ContainedDt.java new file mode 100644 index 00000000000..3f3f2f2322d --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/ContainedDt.java @@ -0,0 +1,54 @@ +package ca.uhn.fhir.model.dstu21.composite; + +/* + * #%L + * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) + * %% + * 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; + +import ca.uhn.fhir.model.api.IDatatype; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.base.composite.BaseContainedDt; + +@DatatypeDef(name = "contained") +public class ContainedDt extends BaseContainedDt { + + @Child(name = "resource", type = IResource.class, order = 0, min = 0, max = Child.MAX_UNLIMITED) + private List myContainedResources; + + public List getContainedResources() { + if (myContainedResources == null) { + myContainedResources = new ArrayList(); + } + return myContainedResources; + } + + public void setContainedResources(List theContainedResources) { + myContainedResources = theContainedResources; + } + + @Override + public boolean isEmpty() { + return myContainedResources == null || myContainedResources.size() == 0; + } + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/CountDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/CountDt.java new file mode 100644 index 00000000000..4b279ecbd58 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/CountDt.java @@ -0,0 +1,29 @@ +package ca.uhn.fhir.model.dstu21.composite; + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.dstu21.composite.QuantityDt; + +/* + * #%L + * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) + * %% + * 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% + */ + +@DatatypeDef(name="CountDt") +public class CountDt extends QuantityDt { + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/DistanceDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/DistanceDt.java new file mode 100644 index 00000000000..398f71ca1f1 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/DistanceDt.java @@ -0,0 +1,30 @@ +package ca.uhn.fhir.model.dstu21.composite; + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.dstu21.composite.QuantityDt; +import ca.uhn.fhir.model.primitive.IntegerDt; + +/* + * #%L + * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) + * %% + * 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% + */ + +@DatatypeDef(name="DistanceDt") +public class DistanceDt extends QuantityDt { + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/DurationDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/DurationDt.java new file mode 100644 index 00000000000..6d261f2e7d2 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/DurationDt.java @@ -0,0 +1,29 @@ +package ca.uhn.fhir.model.dstu21.composite; + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.dstu21.composite.QuantityDt; + +/* + * #%L + * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) + * %% + * 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% + */ + +@DatatypeDef(name="DurationDt") +public class DurationDt extends QuantityDt { + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/MoneyDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/MoneyDt.java new file mode 100644 index 00000000000..d04b8404913 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/MoneyDt.java @@ -0,0 +1,29 @@ +package ca.uhn.fhir.model.dstu21.composite; + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.dstu21.composite.QuantityDt; + +/* + * #%L + * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) + * %% + * 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% + */ + +@DatatypeDef(name="Money") +public class MoneyDt extends QuantityDt { + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/NarrativeDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/NarrativeDt.java new file mode 100644 index 00000000000..81cc8f121eb --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/NarrativeDt.java @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu21.composite; + +/* + * #%L + * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) + * %% + * 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.List; + +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.base.composite.BaseNarrativeDt; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.XhtmlDt; + +/** + * HAPI/FHIR Narrative Datatype + * (A human-readable formatted text, including images) + * + *

+ * Definition: + * A human-readable formatted text, including images + *

+ * + *

+ * Requirements: + * + *

+ */ +@DatatypeDef(name="Narrative") +public class NarrativeDt extends BaseNarrativeDt { + + @Child(name="div", type=XhtmlDt.class, order=1, min=1, max=1) + private XhtmlDt myDiv; + + public NarrativeDt() { + // nothing + } + + @Override + public boolean isEmpty() { + return ca.uhn.fhir.util.ElementUtil.isEmpty( myDiv ); + } + + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements( theType, myDiv ); + } + + /** + * Gets the value(s) for div (Limited xhtml content). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The actual narrative content, a stripped down version of XHTML + *

+ */ + public XhtmlDt getDivElement() { + return getDiv(); + } + + /** + * Gets the value(s) for div (Limited xhtml content). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The actual narrative content, a stripped down version of XHTML + *

+ */ + public XhtmlDt getDiv() { + if (myDiv == null) { + myDiv = new XhtmlDt(); + } + return myDiv; + } + + /** + * Sets the value(s) for div (Limited xhtml content) + * + *

+ * Definition: + * The actual narrative content, a stripped down version of XHTML + *

+ */ + public void setDiv(XhtmlDt theValue) { + myDiv = theValue; + } + + /** + * Sets the value using a textual DIV (or simple text block which will be + * converted to XHTML) + */ + public void setDiv(String theTextDiv) { + myDiv = new XhtmlDt(theTextDiv); + } + + @Override + public BoundCodeDt getStatus() { + return null; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/QuantityDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/QuantityDt.java new file mode 100644 index 00000000000..7c6b173144d --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/QuantityDt.java @@ -0,0 +1,523 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu21.composite; + +import java.math.BigDecimal; +import java.util.List; + +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.SimpleSetter; +import ca.uhn.fhir.model.base.composite.BaseQuantityDt; +import ca.uhn.fhir.model.dstu2.valueset.QuantityComparatorEnum; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.DecimalDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; + +/** + * HAPI/FHIR QuantityDt Datatype + * () + * + *

+ * Definition: + * A measured amount (or an amount that can potentially be measured). Note that measured amounts include amounts that are not precisely quantified, including amounts involving arbitrary units and floating currencies + *

+ * + *

+ * Requirements: + * Need to able to capture all sorts of measured values, even if the measured value are not precisely quantified. Values include exact measures such as 3.51g, customary units such as 3 tablets, and currencies such as $100.32USD + *

+ */ +@DatatypeDef(name="QuantityDt") +public class QuantityDt + extends BaseQuantityDt implements ICompositeDatatype{ + + /** + * Constructor + */ + public QuantityDt() { + // nothing + } + + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name="theValue") double theValue) { + setValue(theValue); + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name="theValue") long theValue) { + setValue(theValue); + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name = "theComparator") QuantityComparatorEnum theComparator, @SimpleSetter.Parameter(name = "theValue") double theValue, + @SimpleSetter.Parameter(name = "theUnits") String theUnits) { + setValue(theValue); + setComparator(theComparator); + setUnits(theUnits); + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name = "theComparator") QuantityComparatorEnum theComparator, @SimpleSetter.Parameter(name = "theValue") long theValue, + @SimpleSetter.Parameter(name = "theUnits") String theUnits) { + setValue(theValue); + setComparator(theComparator); + setUnits(theUnits); + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name="theComparator") QuantityComparatorEnum theComparator, @SimpleSetter.Parameter(name="theValue") double theValue, @SimpleSetter.Parameter(name="theSystem") String theSystem, @SimpleSetter.Parameter(name="theUnits") String theUnits) { + setValue(theValue); + setComparator(theComparator); + setSystem(theSystem); + setUnits(theUnits); + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name="theComparator") QuantityComparatorEnum theComparator, @SimpleSetter.Parameter(name="theValue") long theValue, @SimpleSetter.Parameter(name="theSystem") String theSystem, @SimpleSetter.Parameter(name="theUnits") String theUnits) { + setValue(theValue); + setComparator(theComparator); + setSystem(theSystem); + setUnits(theUnits); + } + + /** + * @deprecated Use {@link #setUnit(String)} instead - Quantity.units was renamed to Quantity.unit in DSTU2 + */ + @Deprecated + @Override + public BaseQuantityDt setUnits(String theString) { + return setUnit(theString); + } + + /** + * @deprecated Use {@link #getUnitElement()} - Quantity.units was renamed to Quantity.unit in DSTU2 + */ + @Deprecated + @Override + public StringDt getUnitsElement() { + return getUnitElement(); + } + + @Child(name="value", type=DecimalDt.class, order=0, min=0, max=1, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="The value of the measured amount. The value includes an implicit precision in the presentation of the value" + ) + private DecimalDt myValue; + + @Child(name="comparator", type=CodeDt.class, order=1, min=0, max=1, summary=true, modifier=true) + @Description( + shortDefinition="", + formalDefinition="How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues; e.g. if the comparator is \"<\" , then the real value is < stated value" + ) + private BoundCodeDt myComparator; + + @Child(name="unit", type=StringDt.class, order=2, min=0, max=1, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="A human-readable form of the unit" + ) + private StringDt myUnit; + + @Child(name="system", type=UriDt.class, order=3, min=0, max=1, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="The identification of the system that provides the coded form of the unit" + ) + private UriDt mySystem; + + @Child(name="code", type=CodeDt.class, order=4, min=0, max=1, summary=true, modifier=false) + @Description( + shortDefinition="", + formalDefinition="A computer processable form of the unit in some unit representation system" + ) + private CodeDt myCode; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myValue, myComparator, myUnit, mySystem, myCode); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myValue, myComparator, myUnit, mySystem, myCode); + } + + /** + * Gets the value(s) for value (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public DecimalDt getValueElement() { + if (myValue == null) { + myValue = new DecimalDt(); + } + return myValue; + } + + + /** + * Gets the value(s) for value (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public BigDecimal getValue() { + return getValueElement().getValue(); + } + + /** + * Sets the value(s) for value () + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public QuantityDt setValue(DecimalDt theValue) { + myValue = theValue; + return this; + } + + + + /** + * Sets the value for value () + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public QuantityDt setValue( long theValue) { + myValue = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for value () + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public QuantityDt setValue( double theValue) { + myValue = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for value () + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public QuantityDt setValue( java.math.BigDecimal theValue) { + myValue = new DecimalDt(theValue); + return this; + } + + + /** + * Gets the value(s) for comparator (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues; e.g. if the comparator is \"<\" , then the real value is < stated value + *

+ */ + public BoundCodeDt getComparatorElement() { + if (myComparator == null) { + myComparator = new BoundCodeDt(QuantityComparatorEnum.VALUESET_BINDER); + } + return myComparator; + } + + + /** + * Gets the value(s) for comparator (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues; e.g. if the comparator is \"<\" , then the real value is < stated value + *

+ */ + public String getComparator() { + return getComparatorElement().getValue(); + } + + /** + * Sets the value(s) for comparator () + * + *

+ * Definition: + * How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues; e.g. if the comparator is \"<\" , then the real value is < stated value + *

+ */ + public QuantityDt setComparator(BoundCodeDt theValue) { + myComparator = theValue; + return this; + } + + + + /** + * Sets the value(s) for comparator () + * + *

+ * Definition: + * How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues; e.g. if the comparator is \"<\" , then the real value is < stated value + *

+ */ + public QuantityDt setComparator(QuantityComparatorEnum theValue) { + setComparator(new BoundCodeDt(QuantityComparatorEnum.VALUESET_BINDER, theValue)); + +/* + getComparatorElement().setValueAsEnum(theValue); +*/ + return this; + } + + + /** + * Gets the value(s) for unit (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A human-readable form of the unit + *

+ */ + public StringDt getUnitElement() { + if (myUnit == null) { + myUnit = new StringDt(); + } + return myUnit; + } + + + /** + * Gets the value(s) for unit (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A human-readable form of the unit + *

+ */ + public String getUnit() { + return getUnitElement().getValue(); + } + + /** + * Sets the value(s) for unit () + * + *

+ * Definition: + * A human-readable form of the unit + *

+ */ + public QuantityDt setUnit(StringDt theValue) { + myUnit = theValue; + return this; + } + + + + /** + * Sets the value for unit () + * + *

+ * Definition: + * A human-readable form of the unit + *

+ */ + public QuantityDt setUnit( String theString) { + myUnit = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for system (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identification of the system that provides the coded form of the unit + *

+ */ + public UriDt getSystemElement() { + if (mySystem == null) { + mySystem = new UriDt(); + } + return mySystem; + } + + + /** + * Gets the value(s) for system (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identification of the system that provides the coded form of the unit + *

+ */ + public String getSystem() { + return getSystemElement().getValue(); + } + + /** + * Sets the value(s) for system () + * + *

+ * Definition: + * The identification of the system that provides the coded form of the unit + *

+ */ + public QuantityDt setSystem(UriDt theValue) { + mySystem = theValue; + return this; + } + + + + /** + * Sets the value for system () + * + *

+ * Definition: + * The identification of the system that provides the coded form of the unit + *

+ */ + public QuantityDt setSystem( String theUri) { + mySystem = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for code (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A computer processable form of the unit in some unit representation system + *

+ */ + public CodeDt getCodeElement() { + if (myCode == null) { + myCode = new CodeDt(); + } + return myCode; + } + + + /** + * Gets the value(s) for code (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A computer processable form of the unit in some unit representation system + *

+ */ + public String getCode() { + return getCodeElement().getValue(); + } + + /** + * Sets the value(s) for code () + * + *

+ * Definition: + * A computer processable form of the unit in some unit representation system + *

+ */ + public QuantityDt setCode(CodeDt theValue) { + myCode = theValue; + return this; + } + + + + /** + * Sets the value for code () + * + *

+ * Definition: + * A computer processable form of the unit in some unit representation system + *

+ */ + public QuantityDt setCode( String theCode) { + myCode = new CodeDt(theCode); + return this; + } + + + + +} \ No newline at end of file diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/ResourceReferenceDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/ResourceReferenceDt.java new file mode 100644 index 00000000000..54ce5c234da --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/ResourceReferenceDt.java @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu21.composite; + +/* + * #%L + * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) + * %% + * 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.List; + +import org.hl7.fhir.instance.model.api.IIdType; + +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.SimpleSetter; +import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.StringDt; + +/** + * HAPI/FHIR ResourceReferenceDt Datatype + * (A reference from one resource to another) + * + *

+ * Definition: + * A reference from one resource to another + *

+ * + *

+ * Requirements: + * + *

+ */ +@DatatypeDef(name="ResourceReferenceDt") +public class ResourceReferenceDt + extends BaseResourceReferenceDt implements ICompositeDatatype +{ + + /** + * Constructor + */ + public ResourceReferenceDt() { + // nothing + } + + /** + * Constructor which creates a resource reference containing the actual resource in question. + *

+ * When using this in a server: Generally if this is serialized, it will be serialized as a contained + * resource, so this should not be used if the intent is not to actually supply the referenced resource. This is not + * a hard-and-fast rule however, as the server can be configured to not serialized this resource, or to load an ID + * and contain even if this constructor is not used. + *

+ * + * @param theResource + * The resource instance + */ + @SimpleSetter() + public ResourceReferenceDt(IResource theResource) { + super(theResource); + } + + /** + * Constructor which accepts a reference directly (this can be an ID, a partial/relative URL or a complete/absolute + * URL) + * + * @param theId + * The reference itself + */ + public ResourceReferenceDt(String theId) { + setReference(new IdDt(theId)); + } + + /** + * Constructor which accepts a reference directly (this can be an ID, a partial/relative URL or a complete/absolute + * URL) + * + * @param theResourceId + * The reference itself + */ + public ResourceReferenceDt(IdDt theResourceId) { + setReference(theResourceId); + } + + /** + * Constructor which accepts a reference directly (this can be an ID, a partial/relative URL or a complete/absolute + * URL) + * + * @param theResourceId + * The reference itself + */ + public ResourceReferenceDt(IIdType theResourceId) { + setReference(theResourceId); + } + + @Child(name="reference", type=IdDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Relative, internal or absolute URL reference", + formalDefinition="A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources" + ) + private IdDt myReference; + + @Child(name="display", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Text alternative for the resource", + formalDefinition="Plain text narrative that identifies the resource in addition to the resource reference" + ) + private StringDt myDisplay; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myReference, myDisplay); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myReference, myDisplay); + } + + /** + * Gets the value(s) for reference (Relative, internal or absolute URL reference). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources + *

+ */ + public IdDt getReference() { + if (myReference == null) { + myReference = new IdDt(); + } + return myReference; + } + + @Override + public IdDt getReferenceElement() { + return getReference(); + } + + + /** + * Sets the value(s) for reference (Relative, internal or absolute URL reference) + * + *

+ * Definition: + * A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources + *

+ */ + public ResourceReferenceDt setReference(IdDt theValue) { + myReference = theValue; + return this; + } + + /** + * Sets the value for reference (Relative, internal or absolute URL reference) + * + *

+ * Definition: + * A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources + *

+ */ + public ResourceReferenceDt setReference( String theId) { + myReference = new IdDt(theId); + return this; + } + + + /** + * Gets the value(s) for display (Text alternative for the resource). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Plain text narrative that identifies the resource in addition to the resource reference + *

+ */ + public StringDt getDisplay() { + if (myDisplay == null) { + myDisplay = new StringDt(); + } + return myDisplay; + } + + /** + * Sets the value(s) for display (Text alternative for the resource) + * + *

+ * Definition: + * Plain text narrative that identifies the resource in addition to the resource reference + *

+ */ + public ResourceReferenceDt setDisplay(StringDt theValue) { + myDisplay = theValue; + return this; + } + + /** + * Sets the value for display (Text alternative for the resource) + * + *

+ * Definition: + * Plain text narrative that identifies the resource in addition to the resource reference + *

+ */ + public ResourceReferenceDt setDisplay( String theString) { + myDisplay = new StringDt(theString); + return this; + } + + @Override + public StringDt getDisplayElement() { + return getDisplay(); + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/SimpleQuantityDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/SimpleQuantityDt.java new file mode 100644 index 00000000000..5e26b311014 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu21/composite/SimpleQuantityDt.java @@ -0,0 +1,98 @@ +package ca.uhn.fhir.model.dstu21.composite; + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.SimpleSetter; +import ca.uhn.fhir.model.dstu2.valueset.QuantityComparatorEnum; + +/* + * #%L + * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) + * %% + * 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% + */ + +@DatatypeDef(name="SimpleQuantity") +public class SimpleQuantityDt extends QuantityDt { + + private static final long serialVersionUID = 1L; + + /** + * Constructor + */ + public SimpleQuantityDt() { + // nothing + } + + + /** + * Constructor + */ + @SimpleSetter + public SimpleQuantityDt(@SimpleSetter.Parameter(name="theValue") double theValue) { + setValue(theValue); + } + + /** + * Constructor + */ + @SimpleSetter + public SimpleQuantityDt(@SimpleSetter.Parameter(name="theValue") long theValue) { + setValue(theValue); + } + + /** + * Constructor + */ + @SimpleSetter + public SimpleQuantityDt(@SimpleSetter.Parameter(name = "theComparator") QuantityComparatorEnum theComparator, @SimpleSetter.Parameter(name = "theValue") double theValue, + @SimpleSetter.Parameter(name = "theUnits") String theUnits) { + setValue(theValue); + setComparator(theComparator); + setUnit(theUnits); + } + + /** + * Constructor + */ + @SimpleSetter + public SimpleQuantityDt(@SimpleSetter.Parameter(name = "theComparator") QuantityComparatorEnum theComparator, @SimpleSetter.Parameter(name = "theValue") long theValue, + @SimpleSetter.Parameter(name = "theUnits") String theUnits) { + setValue(theValue); + setComparator(theComparator); + setUnit(theUnits); + } + + /** + * Constructor + */ + @SimpleSetter + public SimpleQuantityDt(@SimpleSetter.Parameter(name="theValue") double theValue, @SimpleSetter.Parameter(name="theSystem") String theSystem, @SimpleSetter.Parameter(name="theUnits") String theUnits) { + setValue(theValue); + setSystem(theSystem); + setUnit(theUnits); + } + + /** + * Constructor + */ + @SimpleSetter + public SimpleQuantityDt(@SimpleSetter.Parameter(name="theValue") long theValue, @SimpleSetter.Parameter(name="theSystem") String theSystem, @SimpleSetter.Parameter(name="theUnits") String theUnits) { + setValue(theValue); + setSystem(theSystem); + setUnit(theUnits); + } + +} diff --git a/src/changes/changes.xml b/src/changes/changes.xml index b0f260d22f0..04899c57d74 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -27,6 +27,12 @@ CLI now supports writing to file:// URL for 'upload-examples' command + + GZipped content is now supported for client-to-server uploads (create, update, transaction, etc.). + The server will not automatically detect compressed incoming content and decompress it (this can be + disabled using a RestfulServer configuration setting). A new client interceptor has been added + which compresses outgoing content from the client. + diff --git a/src/site/xdoc/doc_rest_client_interceptor.xml b/src/site/xdoc/doc_rest_client_interceptor.xml index 48361874ef0..eecdbeaa4b2 100644 --- a/src/site/xdoc/doc_rest_client_interceptor.xml +++ b/src/site/xdoc/doc_rest_client_interceptor.xml @@ -82,6 +82,22 @@ + + +

+ The GZipContentInterceptor compresses outgoing contents. + With this interceptor, if the client is transmitting resources to the server + (e.g. for a create, update, transaction, etc.) the content will be GZipped + before transmission to the server. +

+ + + + + + +
+