Implement meta operations in client

This commit is contained in:
James Agnew 2015-07-10 17:36:55 -04:00
parent c22aa14d29
commit 350028be73
14 changed files with 523 additions and 55 deletions

View File

@ -20,7 +20,8 @@ package ca.uhn.fhir.rest.client;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.io.Reader;
@ -40,6 +41,7 @@ import org.apache.http.client.methods.HttpRequestBase;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseConformance;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
@ -86,6 +88,10 @@ import ca.uhn.fhir.rest.gclient.IGetTags;
import ca.uhn.fhir.rest.gclient.IHistory;
import ca.uhn.fhir.rest.gclient.IHistoryTyped;
import ca.uhn.fhir.rest.gclient.IHistoryUntyped;
import ca.uhn.fhir.rest.gclient.IMeta;
import ca.uhn.fhir.rest.gclient.IMetaAddOrDeleteSourced;
import ca.uhn.fhir.rest.gclient.IMetaAddOrDeleteUnsourced;
import ca.uhn.fhir.rest.gclient.IMetaGetUnsourced;
import ca.uhn.fhir.rest.gclient.IOperation;
import ca.uhn.fhir.rest.gclient.IOperationUnnamed;
import ca.uhn.fhir.rest.gclient.IOperationUntyped;
@ -130,6 +136,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.NotModifiedException;
import ca.uhn.fhir.util.ICallable;
import ca.uhn.fhir.util.ParametersUtil;
/**
* @author James Agnew
@ -702,7 +709,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
addPreferHeader(myPrefer, invocation);
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
final String resourceName = def.getName();
@ -1247,7 +1254,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
throw new IllegalArgumentException("theOutputParameterType must refer to a HAPI FHIR Resource type: " + theOutputParameterType.getName());
}
if (!"Parameters".equals(def.getName())) {
throw new IllegalArgumentException("theOutputParameterType must refer to a HAPI FHIR Resource type for a resource named " + "Parameters" + " - " + theOutputParameterType.getName() + " is a resource named: " + def.getName());
throw new IllegalArgumentException("theOutputParameterType must refer to a HAPI FHIR Resource type for a resource named " + "Parameters" + " - " + theOutputParameterType.getName()
+ " is a resource named: " + def.getName());
}
myParameters = (IBaseParameters) def.newInstance();
return this;
@ -1266,7 +1274,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
private final class OperationOutcomeResponseHandler implements IClientResponseHandler<BaseOperationOutcome> {
@Override
public BaseOperationOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws BaseServerResponseException {
public BaseOperationOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders)
throws BaseServerResponseException {
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
if (respType == null) {
return null;
@ -1473,6 +1482,42 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
}
private final class MetaParametersResponseHandler<T extends IBaseMetaType> implements IClientResponseHandler<T> {
private Class<T> myType;
public MetaParametersResponseHandler(Class<T> theMetaType) {
myType = theMetaType;
}
@SuppressWarnings("unchecked")
@Override
public T invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws BaseServerResponseException {
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
if (respType == null) {
throw NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader);
}
IParser parser = respType.newParser(myContext);
RuntimeResourceDefinition type = myContext.getResourceDefinition("Parameters");
IBaseResource retVal = parser.parseResource(type.getImplementingClass(), theResponseReader);
BaseRuntimeChildDefinition paramChild = type.getChildByName("parameter");
BaseRuntimeElementCompositeDefinition<?> paramChildElem = (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter");
List<IBase> parameter = paramChild.getAccessor().getValues(retVal);
if (parameter == null || parameter.isEmpty()) {
return (T) myContext.getElementDefinition(myType).newInstance();
}
IBase param = parameter.get(0);
List<IBase> meta = paramChildElem.getChildByName("value[x]").getAccessor().getValues(param);
if (meta.isEmpty()) {
return (T) myContext.getElementDefinition(myType).newInstance();
}
return (T) meta.get(0);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private class SearchInternal extends BaseClientExecutable<IQuery<Object>, Object> implements IQuery<Object>, IUntypedQuery {
@ -1526,7 +1571,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
if (myParamLimit != null) {
addParam(params, Constants.PARAM_COUNT, Integer.toString(myParamLimit));
}
if (myLastUpdated != null) {
for (DateParam next : myLastUpdated.getValuesAsQueryTokens()) {
addParam(params, Constants.PARAM_LASTUPDATED, next.getValueAsQueryToken());
@ -1534,7 +1579,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
if (myReturnBundleType == null && myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) {
throw new IllegalArgumentException("When using the client with HL7.org structures, you must specify " + "the bundle return type for the client by adding \".returnBundle(org.hl7.fhir.instance.model.Bundle.class)\" to your search method call before the \".execute()\" method");
throw new IllegalArgumentException("When using the client with HL7.org structures, you must specify "
+ "the bundle return type for the client by adding \".returnBundle(org.hl7.fhir.instance.model.Bundle.class)\" to your search method call before the \".execute()\" method");
}
IClientResponseHandler<? extends IBase> binding;
@ -1852,7 +1898,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
addPreferHeader(myPrefer, invocation);
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
final String resourceName = def.getName();
@ -1939,9 +1985,9 @@ public class GenericClient extends BaseClient implements IGenericClient {
public IValidateUntyped resource(String theResourceRaw) {
Validate.notBlank(theResourceRaw, "theResourceRaw must not be null or blank");
myResource = parseResourceBody(theResourceRaw);
EncodingEnum enc = MethodUtil.detectEncodingNoDefault(theResourceRaw);
if (enc==null) {
if (enc == null) {
throw new IllegalArgumentException("Could not detect encoding (XML/JSON) in string. Is this a valid FHIR resource?");
}
switch (enc) {
@ -1957,4 +2003,124 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
@SuppressWarnings("rawtypes")
private class MetaInternal extends BaseClientExecutable implements IMeta, IMetaAddOrDeleteUnsourced, IMetaGetUnsourced, IMetaAddOrDeleteSourced {
private MetaOperation myOperation;
private String myOnType;
private IIdType myId;
private Class<? extends IBaseMetaType> myMetaType;
private IBaseMetaType myMeta;
@SuppressWarnings("unchecked")
@Override
public Object execute() {
BaseHttpClientInvocation invocation = null;
IBaseParameters parameters = ParametersUtil.newInstance(myContext);
switch (myOperation) {
case ADD:
ParametersUtil.addParameterToParameters(myContext, parameters, myMeta, "meta");
invocation = OperationMethodBinding.createOperationInvocation(myContext, myId.getResourceType(), myId.getIdPart(), "$meta-add", parameters, false);
break;
case DELETE:
ParametersUtil.addParameterToParameters(myContext, parameters, myMeta, "meta");
invocation = OperationMethodBinding.createOperationInvocation(myContext, myId.getResourceType(), myId.getIdPart(), "$meta-delete", parameters, false);
break;
case GET:
if (myId != null) {
invocation = OperationMethodBinding.createOperationInvocation(myContext, myOnType, myId.getIdPart(), "$meta", parameters, true);
} else if (myOnType != null) {
invocation = OperationMethodBinding.createOperationInvocation(myContext, myOnType, null, "$meta", parameters, true);
} else {
invocation = OperationMethodBinding.createOperationInvocation(myContext, null, null, "$meta", parameters, true);
}
break;
}
// Should not happen
if (invocation == null) {
throw new IllegalStateException();
}
IClientResponseHandler handler;
handler = new MetaParametersResponseHandler(myMetaType);
return invoke(null, handler, invocation);
}
@SuppressWarnings("unchecked")
@Override
public <T extends IBaseMetaType> IMetaGetUnsourced<T> get(Class<T> theType) {
myMetaType = theType;
myOperation = MetaOperation.GET;
return this;
}
@Override
public IMetaAddOrDeleteUnsourced add() {
myOperation = MetaOperation.ADD;
return this;
}
@Override
public IMetaAddOrDeleteUnsourced delete() {
myOperation = MetaOperation.DELETE;
return this;
}
@Override
public IClientExecutable fromServer() {
return this;
}
@Override
public IClientExecutable fromType(String theResourceName) {
Validate.notBlank(theResourceName, "theResourceName must not be blank");
myOnType = theResourceName;
return this;
}
@Override
public IClientExecutable fromResource(IIdType theId) {
setIdInternal(theId);
return this;
}
@Override
public IMetaAddOrDeleteSourced onResource(IIdType theId) {
setIdInternal(theId);
return this;
}
private void setIdInternal(IIdType theId) {
Validate.notBlank(theId.getResourceType(), "theId must contain a resource type");
Validate.notBlank(theId.getIdPart(), "theId must contain an ID part");
myOnType = theId.getResourceType();
myId = theId;
}
@SuppressWarnings("unchecked")
@Override
public <T extends IBaseMetaType> IClientExecutable<IClientExecutable<?, ?>, T> meta(T theMeta) {
Validate.notNull(theMeta, "theMeta must not be null");
myMeta = theMeta;
myMetaType = myMeta.getClass();
return this;
}
}
private enum MetaOperation {
DELETE, ADD, GET
}
@Override
public IMeta meta() {
if (myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) {
throw new IllegalStateException("Can not call $meta operations on a DSTU1 client");
}
return new MetaInternal();
}
}

View File

@ -42,6 +42,7 @@ import ca.uhn.fhir.rest.gclient.IFetchConformanceUntyped;
import ca.uhn.fhir.rest.gclient.IGetPage;
import ca.uhn.fhir.rest.gclient.IGetTags;
import ca.uhn.fhir.rest.gclient.IHistory;
import ca.uhn.fhir.rest.gclient.IMeta;
import ca.uhn.fhir.rest.gclient.IOperation;
import ca.uhn.fhir.rest.gclient.IRead;
import ca.uhn.fhir.rest.gclient.ITransaction;
@ -69,6 +70,14 @@ public interface IGenericClient extends IRestfulClient {
*/
ICreate create();
/**
* Fluent method for the "meta" operations, which can be used to get, add and remove tags and other
* Meta elements from a resource or across the server.
*
* @since 1.1
*/
IMeta meta();
/**
* Implementation of the "type create" method.
*

View File

@ -0,0 +1,44 @@
package ca.uhn.fhir.rest.gclient;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
/*
* #%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 IMeta {
/**
* Fetch the current metadata
*
* @param theMetaType The type of the meta datatype for the given FHIR model version (should be <code>MetaDt.class</code> or <code>MetaType.class</code>)
*/
<T extends IBaseMetaType> IMetaGetUnsourced<T> get(Class<T> theMetaType);
/**
* Add the elements in the given metadata to the already existing set (do not remove any)
*/
IMetaAddOrDeleteUnsourced add();
/**
* Delete the elements in the given metadata to the
*/
IMetaAddOrDeleteUnsourced delete();
}

View File

@ -0,0 +1,8 @@
package ca.uhn.fhir.rest.gclient;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
public interface IMetaAddOrDeleteSourced {
<T extends IBaseMetaType> IClientExecutable<IClientExecutable<?, ?>, T> meta(T theMeta);
}

View File

@ -0,0 +1,9 @@
package ca.uhn.fhir.rest.gclient;
import org.hl7.fhir.instance.model.api.IIdType;
public interface IMetaAddOrDeleteUnsourced {
IMetaAddOrDeleteSourced onResource(IIdType theId);
}

View File

@ -0,0 +1,20 @@
package ca.uhn.fhir.rest.gclient;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IIdType;
public interface IMetaGetUnsourced<T extends IBaseMetaType> {
IClientExecutable<IClientExecutable<?,?>, T> fromServer();
IClientExecutable<IClientExecutable<?,?>, T> fromType(String theResourceName);
/**
* Get the meta from a resource instance by ID.
*
* @param theId The ID. Must contain both a resource type and an ID part
*/
IClientExecutable<IClientExecutable<?,?>, T> fromResource(IIdType theId);
}

View File

@ -27,7 +27,6 @@ import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -35,12 +34,10 @@ import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IAccessor;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeChildPrimitiveDatatypeDefinition;
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.i18n.HapiLocalizer;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.param.CollectionBinder;
@ -48,6 +45,7 @@ import ca.uhn.fhir.rest.param.ResourceParameter;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.util.ParametersUtil;
public class OperationParameter implements IParameter {
@ -72,35 +70,7 @@ public class OperationParameter implements IParameter {
myMax = theMax;
}
private static void addClientParameter(FhirContext theContext, Object theSourceClientArgument, IBaseResource theTargetResource, BaseRuntimeChildDefinition paramChild, BaseRuntimeElementCompositeDefinition<?> paramChildElem, String theName) {
if (theSourceClientArgument instanceof IBaseResource) {
IBase parameter = createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName);
paramChildElem.getChildByName("resource").getMutator().addValue(parameter, (IBaseResource) theSourceClientArgument);
} else if (theSourceClientArgument instanceof IBaseDatatype) {
IBase parameter = createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName);
paramChildElem.getChildByName("value[x]").getMutator().addValue(parameter, (IBaseDatatype) theSourceClientArgument);
} else if (theSourceClientArgument instanceof Collection) {
Collection<?> collection = (Collection<?>) theSourceClientArgument;
for (Object next : collection) {
addClientParameter(theContext, next, theTargetResource, paramChild, paramChildElem, theName);
}
} else {
throw new IllegalArgumentException("Don't know how to handle value of type " + theSourceClientArgument.getClass() + " for paramater " + theName);
}
}
private static IBase createParameterRepetition(FhirContext theContext, IBaseResource theTargetResource, BaseRuntimeChildDefinition paramChild, BaseRuntimeElementCompositeDefinition<?> paramChildElem, String theName) {
IBase parameter = paramChildElem.newInstance();
paramChild.getMutator().addValue(theTargetResource, parameter);
IPrimitiveType<?> value;
if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) {
value = (IPrimitiveType<?>) theContext.getElementDefinition("string").newInstance(theName);
} else {
value = new StringDt(theName);
}
paramChildElem.getChildByName("name").getMutator().addValue(parameter, value);
return parameter;
}
public int getMax() {
return myMax;
@ -145,15 +115,7 @@ public class OperationParameter implements IParameter {
sourceClientArgument = myConverter.outgoingClient(sourceClientArgument);
}
addParameterToParameters(theContext, theTargetResource, sourceClientArgument, myName);
}
public static void addParameterToParameters(FhirContext theContext, IBaseResource theTargetResource, Object sourceClientArgument, String theName) {
RuntimeResourceDefinition def = theContext.getResourceDefinition(theTargetResource);
BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter");
BaseRuntimeElementCompositeDefinition<?> paramChildElem = (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter");
addClientParameter(theContext, sourceClientArgument, theTargetResource, paramChild, paramChildElem, theName);
ParametersUtil.addParameterToParameters(theContext, theTargetResource, sourceClientArgument, myName);
}
@SuppressWarnings("unchecked")

View File

@ -33,6 +33,7 @@ import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.param.ResourceParameter;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.util.ParametersUtil;
public class ValidateMethodBindingDstu2 extends OperationMethodBinding {
@ -68,7 +69,7 @@ public class ValidateMethodBindingDstu2 extends OperationMethodBinding {
public static BaseHttpClientInvocation createValidateInvocation(FhirContext theContext, IBaseResource theResource) {
IBaseParameters parameters = (IBaseParameters) theContext.getResourceDefinition("Parameters").newInstance();
OperationParameter.addParameterToParameters(theContext, parameters, theResource, "resource");
ParametersUtil.addParameterToParameters(theContext, parameters, theResource, "resource");
String resourceName = theContext.getResourceDefinition(theResource).getName();
String resourceId = theResource.getIdElement().getIdPart();

View File

@ -0,0 +1,64 @@
package ca.uhn.fhir.util;
import java.util.Collection;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.primitive.StringDt;
/**
* Utilities for dealing with parameters resources
*/
public class ParametersUtil {
public static void addParameterToParameters(FhirContext theContext, IBaseResource theTargetResource, Object sourceClientArgument, String theName) {
RuntimeResourceDefinition def = theContext.getResourceDefinition(theTargetResource);
BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter");
BaseRuntimeElementCompositeDefinition<?> paramChildElem = (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter");
addClientParameter(theContext, sourceClientArgument, theTargetResource, paramChild, paramChildElem, theName);
}
private static void addClientParameter(FhirContext theContext, Object theSourceClientArgument, IBaseResource theTargetResource, BaseRuntimeChildDefinition paramChild, BaseRuntimeElementCompositeDefinition<?> paramChildElem, String theName) {
if (theSourceClientArgument instanceof IBaseResource) {
IBase parameter = createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName);
paramChildElem.getChildByName("resource").getMutator().addValue(parameter, (IBaseResource) theSourceClientArgument);
} else if (theSourceClientArgument instanceof IBaseDatatype) {
IBase parameter = createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName);
paramChildElem.getChildByName("value[x]").getMutator().addValue(parameter, (IBaseDatatype) theSourceClientArgument);
} else if (theSourceClientArgument instanceof Collection) {
Collection<?> collection = (Collection<?>) theSourceClientArgument;
for (Object next : collection) {
addClientParameter(theContext, next, theTargetResource, paramChild, paramChildElem, theName);
}
} else {
throw new IllegalArgumentException("Don't know how to handle value of type " + theSourceClientArgument.getClass() + " for paramater " + theName);
}
}
private static IBase createParameterRepetition(FhirContext theContext, IBaseResource theTargetResource, BaseRuntimeChildDefinition paramChild, BaseRuntimeElementCompositeDefinition<?> paramChildElem, String theName) {
IBase parameter = paramChildElem.newInstance();
paramChild.getMutator().addValue(theTargetResource, parameter);
IPrimitiveType<?> value;
if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) {
value = (IPrimitiveType<?>) theContext.getElementDefinition("string").newInstance(theName);
} else {
value = new StringDt(theName);
}
paramChildElem.getChildByName("name").getMutator().addValue(parameter, value);
return parameter;
}
public static IBaseParameters newInstance(FhirContext theContext) {
return (IBaseParameters) theContext.getResourceDefinition("Parameters").newInstance();
}
}

View File

@ -97,7 +97,8 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
//@formatter:on
public Parameters meta() {
Parameters parameters = new Parameters();
parameters.addParameter().setName("return").setValue(getDao().metaGetOperation());
MetaDt metaGetOperation = getDao().metaGetOperation();
parameters.addParameter().setName("return").setValue(metaGetOperation);
return parameters;
}
@ -108,7 +109,8 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
//@formatter:on
public Parameters meta(@IdParam IdDt theId) {
Parameters parameters = new Parameters();
parameters.addParameter().setName("return").setValue(getDao().metaGetOperation(theId));
MetaDt metaGetOperation = getDao().metaGetOperation(theId);
parameters.addParameter().setName("return").setValue(metaGetOperation);
return parameters;
}
@ -119,7 +121,8 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
//@formatter:on
public Parameters metaAdd(@IdParam IdDt theId, @OperationParam(name = "meta") MetaDt theMeta) {
Parameters parameters = new Parameters();
parameters.addParameter().setName("return").setValue(getDao().metaAddOperation(theId, theMeta));
MetaDt metaAddOperation = getDao().metaAddOperation(theId, theMeta);
parameters.addParameter().setName("return").setValue(metaAddOperation);
return parameters;
}

View File

@ -50,6 +50,7 @@ import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.dstu.resource.Device;
import ca.uhn.fhir.model.dstu.resource.Practitioner;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
@ -184,6 +185,30 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
}
@Test
public void testMetaOperations() throws Exception {
String methodName = "testMetaOperations";
Patient pt = new Patient();
pt.addName().addFamily(methodName);
IIdType id = ourClient.create().resource(pt).execute().getId().toUnqualifiedVersionless();
MetaDt meta = ourClient.meta().get(MetaDt.class).fromResource(id).execute();
assertEquals(0, meta.getTag().size());
MetaDt inMeta = new MetaDt();
inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
meta = ourClient.meta().add().onResource(id).meta(inMeta).execute();
assertEquals(1, meta.getTag().size());
inMeta = new MetaDt();
inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
meta = ourClient.meta().delete().onResource(id).meta(inMeta).execute();
assertEquals(0, meta.getTag().size());
}
@Test
public void testCreateResourceConditional() throws IOException {
String methodName = "testCreateResourceConditional";

View File

@ -41,6 +41,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
@ -328,6 +329,152 @@ public class GenericClientDstu2Test {
idx++;
}
@Test
public void testMetaAdd() throws Exception {
IParser p = ourCtx.newXmlParser();
MetaDt inMeta = new MetaDt().addProfile("urn:profile:in");
Parameters outParams = new Parameters();
outParams.addParameter().setName("meta").setValue(new MetaDt().addProfile("urn:profile:out"));
final String respString = p.encodeResourceToString(outParams);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
//@formatter:off
MetaDt resp = client
.meta()
.add()
.onResource(new IdDt("Patient/123"))
.meta(inMeta)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/123/$meta-add", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"meta\"/><valueMeta><profile value=\"urn:profile:in\"/></valueMeta></parameter></Parameters>", extractBody(capt, idx));
idx++;
}
@Test
public void testMetaDelete() throws Exception {
IParser p = ourCtx.newXmlParser();
MetaDt inMeta = new MetaDt().addProfile("urn:profile:in");
Parameters outParams = new Parameters();
outParams.addParameter().setName("meta").setValue(new MetaDt().addProfile("urn:profile:out"));
final String respString = p.encodeResourceToString(outParams);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
//@formatter:off
MetaDt resp = client
.meta()
.delete()
.onResource(new IdDt("Patient/123"))
.meta(inMeta)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/123/$meta-delete", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"meta\"/><valueMeta><profile value=\"urn:profile:in\"/></valueMeta></parameter></Parameters>", extractBody(capt, idx));
idx++;
}
@Test
public void testMetaGet() throws Exception {
IParser p = ourCtx.newXmlParser();
Parameters inParams = new Parameters();
inParams.addParameter().setName("meta").setValue(new MetaDt().addProfile("urn:profile:in"));
Parameters outParams = new Parameters();
outParams.addParameter().setName("meta").setValue(new MetaDt().addProfile("urn:profile:out"));
final String respString = p.encodeResourceToString(outParams);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
//@formatter:off
MetaDt resp = client
.meta()
.get(MetaDt.class)
.fromServer()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/$meta", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
assertEquals("GET", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
//@formatter:off
resp = client
.meta()
.get(MetaDt.class)
.fromType("Patient")
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/$meta", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
assertEquals("GET", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
//@formatter:off
resp = client
.meta()
.get(MetaDt.class)
.fromResource(new IdDt("Patient/123"))
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/123/$meta", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
assertEquals("GET", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
}
@Test
public void testOperationAsGetWithInParameters() throws Exception {
IParser p = ourCtx.newXmlParser();
@ -1357,7 +1504,7 @@ public class GenericClientDstu2Test {
private OperationOutcome toOo(IBaseOperationOutcome theOperationOutcome) {
return (OperationOutcome) theOperationOutcome;
}
@BeforeClass
public static void beforeClass() {
ourCtx = FhirContext.forDstu2();

View File

@ -32,7 +32,7 @@ import ${import};
@DatatypeDef(name="${className}")
public class ${className}
extends #{if}( ${className}=="ResourceReferenceDt" || ${className}=="IdentifierDt" || ${className}=="CodingDt" || ${className}=='QuantityDt' || ${className}=='HumanNameDt') Base${className} #{else} BaseIdentifiableElement #{end}
implements ICompositeDatatype
implements ICompositeDatatype#{if}(${className}=="MetaDt"), org.hl7.fhir.instance.model.api.IBaseMetaType #{end}#{if}(${className}=="CodingDt"), org.hl7.fhir.instance.model.api.IBaseCoding #{end}
{
/**
@ -167,6 +167,13 @@ public class ${className}
setUnits(theUnits);
}
#end
#if ( ${className} == "MetaDt" )
@Override
public MetaDt setLastUpdated(Date theHeaderDateValue) {
return setLastUpdated(theHeaderDateValue, TemporalPrecisionEnum.SECOND);
}
#end
#if ( ${className} == "ResourceReferenceDt" )
/**

View File

@ -150,6 +150,9 @@
Prevent crash when encoding resources with contained resources
if the contained resources contained a circular reference to each other
</action>
<action type="add">
Add $meta, $meta-add, and $meta-delete operations to generic client
</action>
</release>
<release version="1.0" date="2015-May-8">
<action type="add">