More work on getting conditional updates working
This commit is contained in:
parent
ecd3620e27
commit
0f2eb230e7
|
@ -694,6 +694,29 @@ public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
|
|||
//END SNIPPET: create
|
||||
|
||||
|
||||
//START SNIPPET: createConditional
|
||||
@Create
|
||||
public MethodOutcome createPatientConditional(
|
||||
@ResourceParam Patient thePatient,
|
||||
@ConditionalOperationParam String theConditionalUrl) {
|
||||
|
||||
if (theConditionalUrl != null) {
|
||||
// We are doing a conditional create
|
||||
|
||||
// populate this with the ID of the existing resource which
|
||||
// matches the conditional URL
|
||||
return new MethodOutcome();
|
||||
} else {
|
||||
// We are doing a normal create
|
||||
|
||||
// populate this with the ID of the newly created resource
|
||||
return new MethodOutcome();
|
||||
}
|
||||
|
||||
}
|
||||
//END SNIPPET: createConditional
|
||||
|
||||
|
||||
//START SNIPPET: createClient
|
||||
@Create
|
||||
public abstract MethodOutcome createNewPatient(@ResourceParam Patient thePatient);
|
||||
|
|
|
@ -92,7 +92,7 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
myMethod = theMethod;
|
||||
myContext = theContext;
|
||||
myProvider = theProvider;
|
||||
myParameters = MethodUtil.getResourceParameters(theContext, theMethod, theProvider);
|
||||
myParameters = MethodUtil.getResourceParameters(theContext, theMethod, theProvider, getResourceOperationType());
|
||||
}
|
||||
|
||||
public List<Class<?>> getAllowableParamAnnotations() {
|
||||
|
|
|
@ -43,6 +43,7 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
|
|||
private String myResourceName;
|
||||
private boolean myBinary;
|
||||
private Class<? extends IBaseResource> myResourceType;
|
||||
private Integer myIdParamIndex;
|
||||
|
||||
public BaseOutcomeReturningMethodBindingWithResourceParam(Method theMethod, FhirContext theContext, Class<?> theMethodAnnotation, Object theProvider) {
|
||||
super(theMethod, theContext, theMethodAnnotation, theProvider);
|
||||
|
@ -79,6 +80,8 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
|
|||
index++;
|
||||
}
|
||||
|
||||
myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod);
|
||||
|
||||
if (resourceParameter == null) {
|
||||
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " does not have a parameter annotated with @" + ResourceParam.class.getSimpleName());
|
||||
}
|
||||
|
@ -106,12 +109,11 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For subclasses to override
|
||||
*/
|
||||
@Override
|
||||
protected void addParametersForServerRequest(Request theRequest, Object[] theParams) {
|
||||
// nothing
|
||||
if (myIdParamIndex != null) {
|
||||
theParams[myIdParamIndex] = theRequest.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,19 +20,28 @@ package ca.uhn.fhir.rest.method;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
class ConditionalParamBinder implements IParameter {
|
||||
|
||||
ConditionalParamBinder() {
|
||||
super();
|
||||
private RestfulOperationTypeEnum myOperationType;
|
||||
|
||||
ConditionalParamBinder(RestfulOperationTypeEnum theOperationType) {
|
||||
Validate.notNull(theOperationType, "theOperationType can not be null");
|
||||
myOperationType = theOperationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,9 +51,34 @@ class ConditionalParamBinder implements IParameter {
|
|||
|
||||
@Override
|
||||
public Object translateQueryParametersIntoServerArgument(Request theRequest, Object theRequestContents) throws InternalErrorException, InvalidRequestException {
|
||||
|
||||
if (myOperationType == RestfulOperationTypeEnum.CREATE) {
|
||||
String retVal = theRequest.getServletRequest().getHeader(Constants.HEADER_IF_NONE_EXIST);
|
||||
if (isBlank(retVal)) {
|
||||
return null;
|
||||
}
|
||||
if (retVal.startsWith(theRequest.getFhirServerBase())) {
|
||||
retVal = retVal.substring(theRequest.getFhirServerBase().length());
|
||||
}
|
||||
return retVal;
|
||||
} else if (myOperationType != RestfulOperationTypeEnum.DELETE && myOperationType != RestfulOperationTypeEnum.UPDATE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (theRequest.getId() != null && theRequest.getId().hasIdPart()) {
|
||||
return null;
|
||||
}
|
||||
boolean haveParam = false;
|
||||
for (String next : theRequest.getParameters().keySet()) {
|
||||
if (!next.startsWith("_")) {
|
||||
haveParam=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!haveParam) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int questionMarkIndex = theRequest.getCompleteUrl().indexOf('?');
|
||||
return theRequest.getResourceName() + theRequest.getCompleteUrl().substring(questionMarkIndex);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import ca.uhn.fhir.model.api.Tag;
|
|||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
|
@ -300,7 +301,7 @@ public class MethodUtil {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<IParameter> getResourceParameters(FhirContext theContext, Method theMethod, Object theProvider) {
|
||||
public static List<IParameter> getResourceParameters(FhirContext theContext, Method theMethod, Object theProvider, RestfulOperationTypeEnum theRestfulOperationTypeEnum) {
|
||||
List<IParameter> parameters = new ArrayList<IParameter>();
|
||||
|
||||
Class<?>[] parameterTypes = theMethod.getParameterTypes();
|
||||
|
@ -396,7 +397,7 @@ public class MethodUtil {
|
|||
} else if (nextAnnotation instanceof TransactionParam) {
|
||||
param = new TransactionParamBinder(theContext);
|
||||
} else if (nextAnnotation instanceof ConditionalOperationParam) {
|
||||
param = new ConditionalParamBinder();
|
||||
param = new ConditionalParamBinder(theRestfulOperationTypeEnum);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.util.Map;
|
|||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.UnavailableException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -814,6 +815,10 @@ public class RestfulServer extends HttpServlet {
|
|||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.entity;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* 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.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
public class FhirPersister {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
new ClassPathXmlApplicationContext("fhir-spring-config.xml");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -50,42 +50,22 @@ import ca.uhn.fhir.rest.server.IBundleProvider;
|
|||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
|
||||
public class JpaResourceProvider<T extends IResource> extends BaseJpaProvider implements IResourceProvider {
|
||||
public abstract class BaseJpaResourceProvider<T extends IResource> extends BaseJpaProvider implements IResourceProvider {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JpaResourceProvider.class);
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseJpaResourceProvider.class);
|
||||
|
||||
private FhirContext myContext;
|
||||
|
||||
private IFhirResourceDao<T> myDao;
|
||||
|
||||
public JpaResourceProvider() {
|
||||
public BaseJpaResourceProvider() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
public JpaResourceProvider(IFhirResourceDao<T> theDao) {
|
||||
public BaseJpaResourceProvider(IFhirResourceDao<T> theDao) {
|
||||
myDao = theDao;
|
||||
}
|
||||
|
||||
@Create
|
||||
public MethodOutcome create(HttpServletRequest theRequest, @ResourceParam T theResource) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
return myDao.create(theResource);
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Delete
|
||||
public MethodOutcome delete(HttpServletRequest theRequest, @IdParam IdDt theResource) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
return myDao.delete(theResource);
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
public FhirContext getContext() {
|
||||
return myContext;
|
||||
}
|
||||
|
@ -158,21 +138,6 @@ public class JpaResourceProvider<T extends IResource> extends BaseJpaProvider im
|
|||
myDao = theDao;
|
||||
}
|
||||
|
||||
@Update
|
||||
public MethodOutcome update(HttpServletRequest theRequest, @ResourceParam T theResource, @IdParam IdDt theId) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
theResource.setId(theId);
|
||||
return myDao.update(theResource);
|
||||
} catch (ResourceNotFoundException e) {
|
||||
ourLog.info("Can't update resource with ID[" + theId.getValue() + "] because it doesn't exist, going to create it instead");
|
||||
theResource.setId(theId);
|
||||
return myDao.create(theResource);
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Validate
|
||||
public MethodOutcome validate(HttpServletRequest theRequest, @ResourceParam T theResource) {
|
||||
startRequest(theRequest);
|
|
@ -0,0 +1,83 @@
|
|||
package ca.uhn.fhir.jpa.provider;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.Delete;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
|
||||
public class JpaResourceProviderDstu1<T extends IResource> extends BaseJpaResourceProvider<T> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JpaResourceProviderDstu1.class);
|
||||
|
||||
public JpaResourceProviderDstu1() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
public JpaResourceProviderDstu1(IFhirResourceDao<T> theDao) {
|
||||
super(theDao);
|
||||
}
|
||||
|
||||
@Create
|
||||
public MethodOutcome create(HttpServletRequest theRequest, @ResourceParam T theResource) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
return getDao().create(theResource);
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Delete
|
||||
public MethodOutcome delete(HttpServletRequest theRequest, @IdParam IdDt theResource) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
return getDao().delete(theResource);
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Update
|
||||
public MethodOutcome update(HttpServletRequest theRequest, @ResourceParam T theResource, @IdParam IdDt theId) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
theResource.setId(theId);
|
||||
return getDao().update(theResource);
|
||||
} catch (ResourceNotFoundException e) {
|
||||
ourLog.info("Can't update resource with ID[" + theId.getValue() + "] because it doesn't exist, going to create it instead");
|
||||
theResource.setId(theId);
|
||||
return getDao().create(theResource);
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package ca.uhn.fhir.jpa.provider;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalOperationParam;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.Delete;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
|
||||
public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResourceProvider<T> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JpaResourceProviderDstu2.class);
|
||||
|
||||
public JpaResourceProviderDstu2() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
public JpaResourceProviderDstu2(IFhirResourceDao<T> theDao) {
|
||||
super(theDao);
|
||||
}
|
||||
|
||||
@Create
|
||||
public MethodOutcome create(HttpServletRequest theRequest, @ResourceParam T theResource, @ConditionalOperationParam String theConditional) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
if (theConditional != null) {
|
||||
return getDao().create(theResource, theConditional);
|
||||
} else {
|
||||
return getDao().create(theResource);
|
||||
}
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Delete
|
||||
public MethodOutcome delete(HttpServletRequest theRequest, @IdParam IdDt theResource, @ConditionalOperationParam String theConditional) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
if (theConditional != null) {
|
||||
return getDao().deleteByUrl(theConditional);
|
||||
} else {
|
||||
return getDao().delete(theResource);
|
||||
}
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Update
|
||||
public MethodOutcome update(HttpServletRequest theRequest, @ResourceParam T theResource, @IdParam IdDt theId, @ConditionalOperationParam String theConditional) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
if (theConditional != null) {
|
||||
return getDao().update(theResource, theConditional);
|
||||
} else {
|
||||
theResource.setId(theId);
|
||||
return getDao().update(theResource);
|
||||
}
|
||||
} catch (ResourceNotFoundException e) {
|
||||
ourLog.info("Can't update resource with ID[" + theId.getValue() + "] because it doesn't exist, going to create it instead");
|
||||
theResource.setId(theId);
|
||||
return getDao().create(theResource);
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
package ca.uhn.fhir.jpa.provider;
|
||||
|
||||
import ca.uhn.fhir.jpa.provider.JpaResourceProvider;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.resource.Questionnaire;
|
||||
|
||||
public class QuestionnaireResourceProvider extends JpaResourceProvider<Questionnaire> {
|
||||
public class QuestionnaireResourceProvider extends JpaResourceProviderDstu1<Questionnaire> {
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
package ca.uhn.fhir.jpa.provider;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
|
@ -45,6 +61,7 @@ import ca.uhn.fhir.rest.client.IGenericClient;
|
|||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.rest.gclient.TokenClientParam;
|
||||
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;
|
||||
|
@ -63,6 +80,8 @@ public class ResourceProviderDstu2Test {
|
|||
private static Server ourServer;
|
||||
private static IFhirResourceDao<Organization> ourOrganizationDao;
|
||||
private static DaoConfig ourDaoConfig;
|
||||
private static CloseableHttpClient ourHttpClient;
|
||||
private static String ourServerBase;
|
||||
|
||||
// private static JpaConformanceProvider ourConfProvider;
|
||||
|
||||
|
@ -92,9 +111,24 @@ public class ResourceProviderDstu2Test {
|
|||
}
|
||||
}
|
||||
|
||||
public void testTryToCreateResourceWithNumericId() {
|
||||
@Test
|
||||
public void testCreateResourceWithNumericId() throws IOException {
|
||||
String resource = "<Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1777\"/><meta><versionId value=\"1\"/><lastUpdated value=\"2015-02-25T15:47:48Z\"/></meta></Patient>";
|
||||
|
||||
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
|
||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
||||
assertThat(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(), startsWith(ourServerBase + "/Patient/"));
|
||||
assertThat(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(), endsWith("/_history/1"));
|
||||
assertThat(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(), not(containsString("1777")));
|
||||
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -523,6 +557,7 @@ public class ResourceProviderDstu2Test {
|
|||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
ourAppCtx.stop();
|
||||
ourHttpClient.close();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -534,7 +569,7 @@ public class ResourceProviderDstu2Test {
|
|||
ourFhirCtx = FhirContext.forDstu2();
|
||||
restServer.setFhirContext(ourFhirCtx);
|
||||
|
||||
String serverBase = "http://localhost:" + port + "/fhir/context";
|
||||
ourServerBase = "http://localhost:" + port + "/fhir/context";
|
||||
|
||||
ourAppCtx = new ClassPathXmlApplicationContext("hapi-fhir-server-resourceproviders-dstu2.xml", "fhir-jpabase-spring-test-config.xml");
|
||||
|
||||
|
@ -565,9 +600,13 @@ public class ResourceProviderDstu2Test {
|
|||
ourServer.start();
|
||||
|
||||
ourFhirCtx.getRestfulClientFactory().setSocketTimeout(600 * 1000);
|
||||
ourClient = ourFhirCtx.newRestfulGenericClient(serverBase);
|
||||
ourClient = ourFhirCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourHttpClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -145,9 +145,9 @@ public class PagingTest {
|
|||
assertEquals(2, bundle.getEntries().size());
|
||||
assertEquals("2", bundle.getEntries().get(0).getId().getIdPart());
|
||||
assertEquals("3", bundle.getEntries().get(1).getId().getIdPart());
|
||||
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2", bundle.getLinkNext().getValue());
|
||||
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2", bundle.getLinkSelf().getValue());
|
||||
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2", bundle.getLinkPrevious().getValue());
|
||||
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue());
|
||||
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkSelf().getValue());
|
||||
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkPrevious().getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
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.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.dstu2.resource.DiagnosticOrder;
|
||||
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
||||
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Organization;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalOperationParam;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public class CreateConditionalTest {
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static String ourLastConditionalUrl;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CreateConditionalTest.class);
|
||||
private static int ourPort;
|
||||
|
||||
private static Server ourServer;
|
||||
private static IdDt ourLastId;
|
||||
private static IdDt ourLastIdParam;
|
||||
private static boolean ourLastRequestWasSearch;
|
||||
|
||||
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastId = null;
|
||||
ourLastConditionalUrl = null;
|
||||
ourLastIdParam = null;
|
||||
ourLastRequestWasSearch = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithConditionalUrl() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?identifier=system%7C001");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("content-location").getValue());
|
||||
|
||||
assertNull(ourLastId.getValue());
|
||||
assertNull(ourLastIdParam);
|
||||
assertEquals("Patient?identifier=system%7C001", ourLastConditionalUrl);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithoutConditionalUrl() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/2?_format=true&_pretty=true");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("content-location").getValue());
|
||||
|
||||
assertEquals("Patient/2", ourLastId.toUnqualified().getValue());
|
||||
assertEquals("Patient/2", ourLastIdParam.toUnqualified().getValue());
|
||||
assertNull(ourLastConditionalUrl);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchStillWorks() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_pretty=true");
|
||||
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertTrue(ourLastRequestWasSearch);
|
||||
assertNull(ourLastId);
|
||||
assertNull(ourLastIdParam);
|
||||
assertNull(ourLastConditionalUrl);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
PatientProvider patientProvider = new PatientProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer();
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<IResource> search(@OptionalParam(name="foo") StringDt theString) {
|
||||
ourLastRequestWasSearch = true;
|
||||
return new ArrayList<IResource>();
|
||||
}
|
||||
|
||||
@Create()
|
||||
public MethodOutcome createPatient(@ResourceParam Patient thePatient, @ConditionalOperationParam String theConditional, @IdParam IdDt theIdParam) {
|
||||
ourLastConditionalUrl = theConditional;
|
||||
ourLastId = thePatient.getId();
|
||||
ourLastIdParam = theIdParam;
|
||||
return new MethodOutcome(new IdDt("Patient/001/_history/002"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -2,10 +2,13 @@ package ca.uhn.fhir.rest.server;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
|
@ -31,9 +34,12 @@ import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
|||
import ca.uhn.fhir.model.dstu2.resource.Organization;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalOperationParam;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
|
@ -50,6 +56,7 @@ public class UpdateConditionalTest {
|
|||
private static Server ourServer;
|
||||
private static IdDt ourLastId;
|
||||
private static IdDt ourLastIdParam;
|
||||
private static boolean ourLastRequestWasSearch;
|
||||
|
||||
|
||||
|
||||
|
@ -58,6 +65,7 @@ public class UpdateConditionalTest {
|
|||
ourLastId = null;
|
||||
ourLastConditionalUrl = null;
|
||||
ourLastIdParam = null;
|
||||
ourLastRequestWasSearch = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -112,6 +120,29 @@ public class UpdateConditionalTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchStillWorks() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_pretty=true");
|
||||
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertTrue(ourLastRequestWasSearch);
|
||||
assertNull(ourLastId);
|
||||
assertNull(ourLastIdParam);
|
||||
assertNull(ourLastConditionalUrl);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
|
@ -147,6 +178,11 @@ public class UpdateConditionalTest {
|
|||
return Patient.class;
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<IResource> search(@OptionalParam(name="foo") StringDt theString) {
|
||||
ourLastRequestWasSearch = true;
|
||||
return new ArrayList<IResource>();
|
||||
}
|
||||
|
||||
@Update()
|
||||
public MethodOutcome updatePatient(@ResourceParam Patient thePatient, @ConditionalOperationParam String theConditional, @IdParam IdDt theIdParam) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Set;
|
|||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
|
@ -444,6 +445,12 @@ public abstract class BaseStructureParser {
|
|||
ctx.put("includes", (theResource.getIncludes()));
|
||||
ctx.put("esc", new EscapeTool());
|
||||
|
||||
String capitalize = WordUtils.capitalize(myVersion);
|
||||
if ("Dstu".equals(capitalize)) {
|
||||
capitalize="Dstu1";
|
||||
}
|
||||
ctx.put("versionCapitalized", capitalize);
|
||||
|
||||
VelocityEngine v = new VelocityEngine();
|
||||
v.setProperty("resource.loader", "cp");
|
||||
v.setProperty("cp.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
|
||||
|
@ -526,6 +533,13 @@ public abstract class BaseStructureParser {
|
|||
ctx.put("versionEnumName", determineVersionEnum().name());
|
||||
ctx.put("esc", new EscapeTool());
|
||||
|
||||
String capitalize = WordUtils.capitalize(myVersion);
|
||||
if ("Dstu".equals(capitalize)) {
|
||||
capitalize="Dstu1";
|
||||
}
|
||||
ctx.put("versionCapitalized", capitalize);
|
||||
|
||||
|
||||
VelocityEngine v = new VelocityEngine();
|
||||
v.setProperty("resource.loader", "cp");
|
||||
v.setProperty("cp.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.util.*;
|
|||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.jpa.provider.JpaResourceProvider;
|
||||
import ca.uhn.fhir.jpa.provider.JpaResourceProvider${versionCapitalized};
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.api.annotation.*;
|
||||
|
@ -18,7 +18,7 @@ import ca.uhn.fhir.model.dstu.resource.Binary;
|
|||
// import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
|
||||
public class ${className}ResourceProvider extends JpaResourceProvider<${className}> {
|
||||
public class ${className}ResourceProvider extends JpaResourceProvider${versionCapitalized}<${className}> {
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
|
|
|
@ -474,6 +474,35 @@
|
|||
<param name="file" value="examples/src/main/java/example/RestfulPatientResourceProviderMore.java" />
|
||||
</macro>
|
||||
|
||||
<h4>Conditional Creates</h4>
|
||||
|
||||
<p>
|
||||
The FHIR specification also allows "conditional creates". A conditional
|
||||
create has an additional header called <code>If-None-Exist</code>
|
||||
which the client will supply on the HTTP request. The client will
|
||||
populate this header with a search URL such as <code>Patient?identifier=foo</code>.
|
||||
See the FHIR specification for details on the semantics for correctly
|
||||
implementing conditional create.
|
||||
</p>
|
||||
<p>
|
||||
When a conditional create is detected (i.e. when the create request contains
|
||||
a populated <code>If-None-Exist</code> header), if a method parameter annotated
|
||||
with the
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/annotation/ConditionalOperationParam.html">@ConditionalOperationParam</a>
|
||||
is detected, it will be populated with the value of this header.
|
||||
</p>
|
||||
|
||||
<macro name="snippet">
|
||||
<param name="id" value="createConditional" />
|
||||
<param name="file" value="examples/src/main/java/example/RestfulPatientResourceProviderMore.java" />
|
||||
</macro>
|
||||
|
||||
<p>
|
||||
Example URL and HTTP header to perform a conditional create:
|
||||
<br />
|
||||
<code>http://fhir.example.com/Patient<br/>If-None-Exist: Patient?identifier=system%7C0001</code>
|
||||
</p>
|
||||
|
||||
<a name="type_search" />
|
||||
</section>
|
||||
|
||||
|
@ -535,9 +564,9 @@
|
|||
|
||||
<p>
|
||||
Parameters which take a string as their format should use the
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/param/StringParam.html">StringParam</a>
|
||||
type. They may also use normal java Strings, although it is
|
||||
not possible to use the ":exact" qualifier in that case.
|
||||
<code><a href="./apidocs/ca/uhn/fhir/rest/param/StringParam.html">StringParam</a></code>
|
||||
type. They may also use normal java <code>String</code>, although it is
|
||||
not possible to use the <code>:exact</code> qualifier in that case.
|
||||
</p>
|
||||
|
||||
<macro name="snippet">
|
||||
|
@ -971,7 +1000,7 @@
|
|||
<p>
|
||||
To accept a composite parameter, use a parameter type which implements the
|
||||
<a href="./apidocs/ca/uhn/fhir/model/api/IQueryParameterAnd.html">IQueryParameterAnd</a>
|
||||
interface.
|
||||
interface (which in turn encapsulates the corresponding IQueryParameterOr types).
|
||||
</p>
|
||||
<p>
|
||||
An example follows which shows a search for Patients by address, where multiple string
|
||||
|
@ -992,6 +1021,17 @@
|
|||
<param name="file" value="examples/src/main/java/example/RestfulPatientResourceProviderMore.java" />
|
||||
</macro>
|
||||
|
||||
<p>
|
||||
Note that AND parameters join multiple OR parameters together, but
|
||||
the inverse is not true. In other words, it is possible in FHIR
|
||||
to use AND search parameters to specify a search criteria of
|
||||
<code>(A=1 OR A=2) AND (B=1 OR B=2)</code>
|
||||
but it is not possible to specify
|
||||
<code>(A=1 AND B=1) OR (A=2 AND B=2)</code> (aside from
|
||||
in very specific cases where a composite parameter has been
|
||||
specifically defined).
|
||||
</p>
|
||||
|
||||
<h4>AND Relationship Query Parameters for Dates</h4>
|
||||
|
||||
<p>
|
||||
|
|
Loading…
Reference in New Issue