Add profile and security params for generic search

This commit is contained in:
James Agnew 2015-08-24 15:23:28 -04:00
parent bec43b3fdc
commit df4d371edc
28 changed files with 896 additions and 404 deletions

View File

@ -23,6 +23,7 @@ import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.method.SearchStyleEnum;
@ -259,10 +260,28 @@ public class GenericClientExample {
.forResource(Patient.class)
.withIdAndCompartment("123", "condition")
.where(Patient.ADDRESS.matches().values("Toronto"))
.returnBundle(Bundle.class)
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
// END SNIPPET: searchCompartment
// START SNIPPET: searchSubsetSummary
response = client.search()
.forResource(Patient.class)
.where(Patient.ADDRESS.matches().values("Toronto"))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.summaryMode(SummaryEnum.TRUE)
.execute();
// END SNIPPET: searchSubsetSummary
// START SNIPPET: searchSubsetElements
response = client.search()
.forResource(Patient.class)
.where(Patient.ADDRESS.matches().values("Toronto"))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.elementsSubset("identifier", "name") // only include the identifier and name
.execute();
// END SNIPPET: searchSubsetElements
// START SNIPPET: searchAdv
response = client.search()
.forResource(Patient.class)

View File

@ -32,6 +32,7 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.rest.server.EncodingEnum;
/**
* A parser, which can be used to convert between HAPI FHIR model/structure objects, and their respective String wire
@ -294,4 +295,9 @@ public interface IParser {
*/
IParser setSuppressNarratives(boolean theSuppressNarratives);
/**
* Which encoding does this parser instance produce?
*/
EncodingEnum getEncoding();
}

View File

@ -60,14 +60,12 @@ import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
import org.hl7.fhir.instance.model.api.IBaseIntegerDatatype;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
@ -100,7 +98,7 @@ import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.util.ElementUtil;
/**
@ -923,6 +921,11 @@ public class JsonParser extends BaseParser implements IParser {
}
}
@Override
public EncodingEnum getEncoding() {
return EncodingEnum.JSON;
}
private void parseAlternates(JsonValue theAlternateVal, ParserState<?> theState, String theElementName) {
if (theAlternateVal == null || theAlternateVal.getValueType() == ValueType.NULL) {
return;
@ -1207,25 +1210,6 @@ public class JsonParser extends BaseParser implements IParser {
}
}
@Override
public TagList parseTagList(Reader theReader) {
JsonReader reader = Json.createReader(theReader);
JsonObject object = reader.readObject();
JsonValue resourceTypeObj = object.get("resourceType");
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
String resourceType = ((JsonString) resourceTypeObj).getString();
ParserState<TagList> state = ParserState.getPreTagListInstance(myContext, true, getErrorHandler());
state.enteringNewElement(null, resourceType);
parseChildren(object, state);
state.endingElement();
return state.getObject();
}
// private void parseExtensionInDstu2Style(boolean theModifier, ParserState<?> theState, String
// theParentExtensionUrl, String theExtensionUrl, JsonArray theValues) {
// String extUrl = UrlUtil.constructAbsoluteUrl(theParentExtensionUrl, theExtensionUrl);
@ -1253,6 +1237,25 @@ public class JsonParser extends BaseParser implements IParser {
// }
@Override
public TagList parseTagList(Reader theReader) {
JsonReader reader = Json.createReader(theReader);
JsonObject object = reader.readObject();
JsonValue resourceTypeObj = object.get("resourceType");
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
String resourceType = ((JsonString) resourceTypeObj).getString();
ParserState<TagList> state = ParserState.getPreTagListInstance(myContext, true, getErrorHandler());
state.enteringNewElement(null, resourceType);
parseChildren(object, state);
state.endingElement();
return state.getObject();
}
@Override
public IParser setPrettyPrint(boolean thePrettyPrint) {
myPrettyPrint = thePrettyPrint;

View File

@ -19,8 +19,9 @@ package ca.uhn.fhir.parser;
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.io.Reader;
@ -83,8 +84,8 @@ import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.parser.BaseParser.CompositeChildElement;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.ElementUtil;
import ca.uhn.fhir.util.NonPrettyPrintWriterWrapper;
@ -92,8 +93,7 @@ import ca.uhn.fhir.util.PrettyPrintWriterWrapper;
import ca.uhn.fhir.util.XmlUtil;
/**
* This class is the FHIR XML parser/encoder. Users should not interact with this class directly, but should use
* {@link FhirContext#newXmlParser()} to get an instance.
* This class is the FHIR XML parser/encoder. Users should not interact with this class directly, but should use {@link FhirContext#newXmlParser()} to get an instance.
*/
public class XmlParser extends BaseParser implements IParser {
@ -112,8 +112,7 @@ public class XmlParser extends BaseParser implements IParser {
private boolean myPrettyPrint;
/**
* Do not use this constructor, the recommended way to obtain a new instance of the XML parser is to invoke
* {@link FhirContext#newXmlParser()}.
* Do not use this constructor, the recommended way to obtain a new instance of the XML parser is to invoke {@link FhirContext#newXmlParser()}.
*
* @param theParserErrorHandler
*/
@ -159,6 +158,39 @@ public class XmlParser extends BaseParser implements IParser {
}
}
@Override
public void doEncodeBundleToWriter(Bundle theBundle, Writer theWriter) throws DataFormatException {
try {
XMLStreamWriter eventWriter = createXmlWriter(theWriter);
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
encodeBundleToWriterDstu2(theBundle, eventWriter);
} else {
encodeBundleToWriterDstu1(theBundle, eventWriter);
}
} catch (XMLStreamException e) {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
}
@Override
public void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws DataFormatException {
XMLStreamWriter eventWriter;
try {
eventWriter = createXmlWriter(theWriter);
encodeResourceToXmlStreamWriter(theResource, eventWriter, false);
eventWriter.flush();
} catch (XMLStreamException e) {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
}
@Override
public <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) {
XMLEventReader streamReader = createStreamReader(theReader);
return parseResource(theResourceType, streamReader);
}
private <T> T doXmlLoop(XMLEventReader streamReader, ParserState<T> parserState) {
ourLog.trace("Entering XML parsing loop with state: {}", parserState);
@ -234,20 +266,6 @@ public class XmlParser extends BaseParser implements IParser {
return stringWriter.toString();
}
@Override
public void doEncodeBundleToWriter(Bundle theBundle, Writer theWriter) throws DataFormatException {
try {
XMLStreamWriter eventWriter = createXmlWriter(theWriter);
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
encodeBundleToWriterDstu2(theBundle, eventWriter);
} else {
encodeBundleToWriterDstu1(theBundle, eventWriter);
}
} catch (XMLStreamException e) {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
}
private void encodeBundleToWriterDstu1(Bundle theBundle, XMLStreamWriter eventWriter) throws XMLStreamException {
eventWriter.writeStartElement("feed");
eventWriter.writeDefaultNamespace(ATOM_NS);
@ -448,7 +466,8 @@ public class XmlParser extends BaseParser implements IParser {
theEventWriter.close();
}
private void encodeChildElementToStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, IBase nextValue, String childName, BaseRuntimeElementDefinition<?> childDef, String theExtensionUrl, boolean theIncludedResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException {
private void encodeChildElementToStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, IBase nextValue, String childName, BaseRuntimeElementDefinition<?> childDef,
String theExtensionUrl, boolean theIncludedResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException {
if (nextValue == null || nextValue.isEmpty()) {
if (isChildContained(childDef, theIncludedResource)) {
// We still want to go in..
@ -503,10 +522,9 @@ public class XmlParser extends BaseParser implements IParser {
case CONTAINED_RESOURCE_LIST:
case CONTAINED_RESOURCES: {
/*
* Disable per #103 for (IResource next : value.getContainedResources()) { if
* (getContainedResources().getResourceId(next) != null) { continue; }
* theEventWriter.writeStartElement("contained"); encodeResourceToXmlStreamWriter(next, theEventWriter, true,
* fixContainedResourceId(next.getId().getValue())); theEventWriter.writeEndElement(); }
* Disable per #103 for (IResource next : value.getContainedResources()) { if (getContainedResources().getResourceId(next) != null) { continue; }
* theEventWriter.writeStartElement("contained"); encodeResourceToXmlStreamWriter(next, theEventWriter, true, fixContainedResourceId(next.getId().getValue()));
* theEventWriter.writeEndElement(); }
*/
for (IBaseResource next : getContainedResources().getContainedResources()) {
IIdType resourceId = getContainedResources().getResourceId(next);
@ -550,7 +568,8 @@ public class XmlParser extends BaseParser implements IParser {
}
private void encodeCompositeElementChildrenToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, List<? extends BaseRuntimeChildDefinition> theChildren, boolean theContainedResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException {
private void encodeCompositeElementChildrenToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, List<? extends BaseRuntimeChildDefinition> theChildren,
boolean theContainedResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException {
for (CompositeChildElement nextChildElem : super.compositeChildIterator(theChildren, theContainedResource, theParent)) {
BaseRuntimeChildDefinition nextChild = nextChildElem.getDef();
@ -576,12 +595,13 @@ public class XmlParser extends BaseParser implements IParser {
}
if (nextChild instanceof RuntimeChildContainedResources) {
encodeChildElementToStreamWriter(theResource, theEventWriter, null, nextChild.getChildNameByDatatype(null), nextChild.getChildElementDefinitionByDatatype(null), null, theContainedResource, nextChildElem);
encodeChildElementToStreamWriter(theResource, theEventWriter, null, nextChild.getChildNameByDatatype(null), nextChild.getChildElementDefinitionByDatatype(null), null, theContainedResource,
nextChildElem);
} else {
List<? extends IBase> values = nextChild.getAccessor().getValues(theElement);
values = super.preProcessValues(nextChild, values);
if (values == null || values.isEmpty()) {
continue;
}
@ -623,7 +643,8 @@ public class XmlParser extends BaseParser implements IParser {
}
}
private void encodeCompositeElementToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> theElementDefinition, boolean theIncludedResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException {
private void encodeCompositeElementToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> theElementDefinition,
boolean theIncludedResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException {
encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, theElementDefinition.getExtensions(), theIncludedResource, theParent);
encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, theElementDefinition.getChildren(), theIncludedResource, theParent);
@ -645,17 +666,6 @@ public class XmlParser extends BaseParser implements IParser {
}
}
/**
* This is just to work around the fact that casting java.util.List<ca.uhn.fhir.model.api.ExtensionDt> to
* java.util.List<? extends org.hl7.fhir.instance.model.api.IBaseExtension<?, ?>> seems to be rejected by the
* compiler some of the time.
*/
private <Q extends IBaseExtension<?, ?>> List<IBaseExtension<?, ?>> toBaseExtensionList(final List<Q> theList) {
List<IBaseExtension<?, ?>> retVal = new ArrayList<IBaseExtension<?, ?>>(theList.size());
retVal.addAll(theList);
return retVal;
}
private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, IBaseReference theRef, IBaseResource theResource, boolean theIncludedResource) throws XMLStreamException {
String reference = determineReferenceText(theRef);
@ -673,10 +683,11 @@ public class XmlParser extends BaseParser implements IParser {
}
}
private void encodeResourceToStreamWriterInDstu2Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
private void encodeResourceToStreamWriterInDstu2Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter,
BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
/*
* DSTU2 requires extensions to come in a specific spot within the encoded content - This is a bit of a messy way
* to make that happen, but hopefully this won't matter as much once we use the HL7 structures
* DSTU2 requires extensions to come in a specific spot within the encoded content - This is a bit of a messy way to make that happen, but hopefully this won't matter as much once we use the HL7
* structures
*/
List<BaseRuntimeChildDefinition> preExtensionChildren = new ArrayList<BaseRuntimeChildDefinition>();
@ -691,9 +702,9 @@ public class XmlParser extends BaseParser implements IParser {
postExtensionChildren.add(next);
}
}
CompositeChildElement parent = new CompositeChildElement(theResDef);
encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, preExtensionChildren, theIncludedResource, parent);
encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource);
@ -703,19 +714,6 @@ public class XmlParser extends BaseParser implements IParser {
}
@Override
public void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws DataFormatException {
XMLStreamWriter eventWriter;
try {
eventWriter = createXmlWriter(theWriter);
encodeResourceToXmlStreamWriter(theResource, eventWriter, false);
eventWriter.flush();
} catch (XMLStreamException e) {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
}
private void encodeResourceToXmlStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
String resourceId = null;
if (theResource instanceof IResource) {
@ -873,7 +871,8 @@ public class XmlParser extends BaseParser implements IParser {
}
}
private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theWriter, List<? extends IBaseExtension<?, ?>> theExtensions, String tagName, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theWriter, List<? extends IBaseExtension<?, ?>> theExtensions, String tagName, boolean theIncludedResource)
throws XMLStreamException, DataFormatException {
for (IBaseExtension<?, ?> next : theExtensions) {
if (next == null || (ElementUtil.isEmpty(next.getValue()) && next.getExtension().isEmpty())) {
continue;
@ -1005,6 +1004,11 @@ public class XmlParser extends BaseParser implements IParser {
}
}
@Override
public EncodingEnum getEncoding() {
return EncodingEnum.XML;
}
@Override
public <T extends IBaseResource> Bundle parseBundle(Class<T> theResourceType, Reader theReader) {
XMLEventReader streamReader = createStreamReader(theReader);
@ -1017,12 +1021,6 @@ public class XmlParser extends BaseParser implements IParser {
return doXmlLoop(theStreamReader, parserState);
}
@Override
public <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) {
XMLEventReader streamReader = createStreamReader(theReader);
return parseResource(theResourceType, streamReader);
}
private <T extends IBaseResource> T parseResource(Class<T> theResourceType, XMLEventReader theStreamReader) {
ParserState<T> parserState = ParserState.getPreResourceInstance(theResourceType, myContext, false, getErrorHandler());
return doXmlLoop(theStreamReader, parserState);
@ -1042,6 +1040,16 @@ public class XmlParser extends BaseParser implements IParser {
return this;
}
/**
* This is just to work around the fact that casting java.util.List<ca.uhn.fhir.model.api.ExtensionDt> to java.util.List<? extends org.hl7.fhir.instance.model.api.IBaseExtension<?, ?>> seems to be
* rejected by the compiler some of the time.
*/
private <Q extends IBaseExtension<?, ?>> List<IBaseExtension<?, ?>> toBaseExtensionList(final List<Q> theList) {
List<IBaseExtension<?, ?>> retVal = new ArrayList<IBaseExtension<?, ?>>(theList.size());
retVal.addAll(theList);
return retVal;
}
private void writeAtomLink(XMLStreamWriter theEventWriter, String theRel, StringDt theStringDt) throws XMLStreamException {
if (StringUtils.isNotBlank(theStringDt.getValue())) {
theEventWriter.writeStartElement("link");

View File

@ -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;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.api;
/*
* #%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.HashMap;
import java.util.Map;

View File

@ -33,6 +33,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@ -164,11 +165,11 @@ public abstract class BaseClient implements IRestfulClient {
}
<T> T invokeClient(FhirContext theContext, IClientResponseHandler<T> binding, BaseHttpClientInvocation clientInvocation, boolean theLogRequestAndResponse) {
return invokeClient(theContext, binding, clientInvocation, null, null, theLogRequestAndResponse, null);
return invokeClient(theContext, binding, clientInvocation, null, null, theLogRequestAndResponse, null, null);
}
<T> T invokeClient(FhirContext theContext, IClientResponseHandler<T> binding, BaseHttpClientInvocation clientInvocation, EncodingEnum theEncoding, Boolean thePrettyPrint,
boolean theLogRequestAndResponse, SummaryEnum theSummaryMode) {
boolean theLogRequestAndResponse, SummaryEnum theSummaryMode, Set<String> theSubsetElements) {
if (!myDontValidateConformance) {
myFactory.validateServerBaseIfConfiguredToDoSo(myUrlBase, myClient, this);
@ -196,6 +197,10 @@ public abstract class BaseClient implements IRestfulClient {
if (thePrettyPrint == Boolean.TRUE) {
params.put(Constants.PARAM_PRETTY, Collections.singletonList(Constants.PARAM_PRETTY_VALUE_TRUE));
}
if (theSubsetElements != null && theSubsetElements.isEmpty()== false) {
params.put(Constants.PARAM_ELEMENTS, Collections.singletonList(StringUtils.join(theSubsetElements, ',')));
}
EncodingEnum encoding = getEncoding();
if (theEncoding != null) {

View File

@ -24,12 +24,15 @@ import static org.apache.commons.lang3.StringUtils.*;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@ -226,7 +229,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
return delete(theType, new IdDt(theId));
}
private <T extends IBaseResource> T doReadOrVRead(final Class<T> theType, IIdType theId, boolean theVRead, ICallable<T> theNotModifiedHandler, String theIfVersionMatches, Boolean thePrettyPrint, SummaryEnum theSummary, EncodingEnum theEncoding) {
private <T extends IBaseResource> T doReadOrVRead(final Class<T> theType, IIdType theId, boolean theVRead, ICallable<T> theNotModifiedHandler, String theIfVersionMatches, Boolean thePrettyPrint, SummaryEnum theSummary, EncodingEnum theEncoding, Set<String> theSubsetElements) {
String resName = toResourceName(theType);
IIdType id = theId;
if (!id.hasBaseUrl()) {
@ -259,10 +262,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theType, id, allowHtmlResponse);
if (theNotModifiedHandler == null) {
return invokeClient(myContext, binding, invocation, theEncoding, thePrettyPrint, myLogRequestAndResponse, theSummary);
return invokeClient(myContext, binding, invocation, theEncoding, thePrettyPrint, myLogRequestAndResponse, theSummary, theSubsetElements);
} else {
try {
return invokeClient(myContext, binding, invocation, theEncoding, thePrettyPrint, myLogRequestAndResponse, theSummary);
return invokeClient(myContext, binding, invocation, theEncoding, thePrettyPrint, myLogRequestAndResponse, theSummary, theSubsetElements);
} catch (NotModifiedException e) {
return theNotModifiedHandler.call();
}
@ -413,7 +416,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
@Override
public <T extends IBaseResource> T read(final Class<T> theType, UriDt theUrl) {
IdDt id = theUrl instanceof IdDt ? ((IdDt) theUrl) : new IdDt(theUrl);
return doReadOrVRead(theType, id, false, null, null, false, null, null);
return doReadOrVRead(theType, id, false, null, null, false, null, null, null);
}
@Override
@ -559,7 +562,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
if (theId.hasVersionIdPart() == false) {
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(I18N_NO_VERSION_ID_FOR_VREAD, theId.getValue()));
}
return doReadOrVRead(theType, theId, true, null, null, false, null, null);
return doReadOrVRead(theType, theId, true, null, null, false, null, null, null);
}
/* also deprecated in interface */
@ -592,15 +595,9 @@ public class GenericClient extends BaseClient implements IGenericClient {
protected EncodingEnum myParamEncoding;
protected Boolean myPrettyPrint;
private boolean myQueryLogRequestAndResponse;
private HashSet<String> mySubsetElements;
protected SummaryEnum mySummaryMode;
@SuppressWarnings("unchecked")
@Override
public T summaryMode(SummaryEnum theSummary) {
mySummaryMode = theSummary;
return ((T) this);
}
@SuppressWarnings("unchecked")
@Override
public T andLogRequestAndResponse(boolean theLogRequestAndResponse) {
@ -626,6 +623,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
return myParamEncoding;
}
protected HashSet<String> getSubsetElements() {
return mySubsetElements;
}
protected <Z> Z invoke(Map<String, List<String>> theParams, IClientResponseHandler<Z> theHandler, BaseHttpClientInvocation theInvocation) {
// if (myParamEncoding != null) {
// theParams.put(Constants.PARAM_FORMAT, Collections.singletonList(myParamEncoding.getFormatContentType()));
@ -639,7 +640,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
myLastRequest = theInvocation.asHttpRequest(getServerBase(), theParams, getEncoding(), myPrettyPrint);
}
Z resp = invokeClient(myContext, theHandler, theInvocation, myParamEncoding, myPrettyPrint, myQueryLogRequestAndResponse || myLogRequestAndResponse, mySummaryMode);
Z resp = invokeClient(myContext, theHandler, theInvocation, myParamEncoding, myPrettyPrint, myQueryLogRequestAndResponse || myLogRequestAndResponse, mySummaryMode, mySubsetElements);
return resp;
}
@ -658,6 +659,24 @@ public class GenericClient extends BaseClient implements IGenericClient {
return (T) this;
}
@SuppressWarnings("unchecked")
@Override
public T elementsSubset(String... theElements) {
if (theElements != null && theElements.length > 0) {
mySubsetElements = new HashSet<String>(Arrays.asList(theElements));
} else {
mySubsetElements = null;
}
return (T) this;
}
@SuppressWarnings("unchecked")
@Override
public T summaryMode(SummaryEnum theSummary) {
mySummaryMode = theSummary;
return ((T) this);
}
}
private final class BundleResponseHandler implements IClientResponseHandler<Bundle> {
@ -1489,9 +1508,9 @@ public class GenericClient extends BaseClient implements IGenericClient {
@Override
public Object execute() {//AAA
if (myId.hasVersionIdPart()) {
return doReadOrVRead(myType.getImplementingClass(), myId, true, myNotModifiedHandler, myIfVersionMatches, myPrettyPrint, mySummaryMode, myParamEncoding);
return doReadOrVRead(myType.getImplementingClass(), myId, true, myNotModifiedHandler, myIfVersionMatches, myPrettyPrint, mySummaryMode, myParamEncoding, getSubsetElements());
} else {
return doReadOrVRead(myType.getImplementingClass(), myId, false, myNotModifiedHandler, myIfVersionMatches, myPrettyPrint, mySummaryMode, myParamEncoding);
return doReadOrVRead(myType.getImplementingClass(), myId, false, myNotModifiedHandler, myIfVersionMatches, myPrettyPrint, mySummaryMode, myParamEncoding, getSubsetElements());
}
}
@ -1634,9 +1653,9 @@ public class GenericClient extends BaseClient implements IGenericClient {
private final class ResourceResponseHandler<T extends IBaseResource> implements IClientResponseHandler<T> {
private boolean myAllowHtmlResponse;
private IIdType myId;
private Class<T> myType;
private boolean myAllowHtmlResponse;
public ResourceResponseHandler(Class<T> theType, IIdType theId) {
myType = theType;
@ -1698,14 +1717,15 @@ public class GenericClient extends BaseClient implements IGenericClient {
private List<Include> myInclude = new ArrayList<Include>();
private DateRangeParam myLastUpdated;
private Integer myParamLimit;
private List<String> myProfile = new ArrayList<String>();
private String myResourceId;
private String myResourceName;
private Class<? extends IBaseResource> myResourceType;
private Class<? extends IBaseBundle> myReturnBundleType;
private List<Include> myRevInclude = new ArrayList<Include>();
private SearchStyleEnum mySearchStyle;
private List<TokenParam> mySecurity = new ArrayList<TokenParam>();
private List<SortInternal> mySort = new ArrayList<SortInternal>();
private List<TokenParam> myTags = new ArrayList<TokenParam>();
public SearchInternal() {
@ -1734,6 +1754,14 @@ public class GenericClient extends BaseClient implements IGenericClient {
addParam(params, Constants.PARAM_TAG, next.getValueAsQueryToken());
}
for (TokenParam next : mySecurity) {
addParam(params, Constants.PARAM_SECURITY, next.getValueAsQueryToken());
}
for (String next : myProfile) {
addParam(params, Constants.PARAM_PROFILE, next);
}
for (Include next : myInclude) {
addParam(params, Constants.PARAM_INCLUDE, next.getValue());
}
@ -1867,6 +1895,20 @@ public class GenericClient extends BaseClient implements IGenericClient {
return this;
}
@Override
public IQuery<Object> withProfile(String theProfileUri) {
Validate.notBlank(theProfileUri, "theProfileUri must not be null or empty");
myProfile.add(theProfileUri);
return this;
}
@Override
public IQuery<Object> withSecurity(String theSystem, String theCode) {
Validate.notBlank(theCode, "theCode must not be null or empty");
mySecurity.add(new TokenParam(theSystem, theCode));
return this;
}
@Override
public IQuery<Object> withTag(String theSystem, String theCode) {
Validate.notBlank(theCode, "theCode must not be null or empty");

View File

@ -34,6 +34,13 @@ public interface IClientExecutable<T extends IClientExecutable<?,?>, Y> {
@Deprecated
T andLogRequestAndResponse(boolean theLogRequestAndResponse);
/**
* Request that the server return subsetted resources, containing only the elements specified in the given parameters.
* For example: <code>subsetElements("name", "identifier")</code> requests that the server only return
* the "name" and "identifier" fields in the returned resource, and omit any others.
*/
T elementsSubset(String... theElements);
T encodedJson();
T encodedXml();
@ -46,5 +53,5 @@ public interface IClientExecutable<T extends IClientExecutable<?,?>, Y> {
* Request that the server modify the response using the <code>_summary</code> param
*/
T summaryMode(SummaryEnum theSummary);
}

View File

@ -45,6 +45,22 @@ public interface IQuery<T> extends IClientExecutable<IQuery<T>, T>, IBaseQuery<I
*/
IQuery<T> withTag(String theSystem, String theCode);
/**
* Match only resources where the resource has the given security tag. This parameter corresponds to
* the <code>_security</code> URL parameter.
* @param theSystem The tag code system, or <code>null</code> to match any code system (this may not be supported on all servers)
* @param theCode The tag code. Must not be <code>null</code> or empty.
*/
IQuery<T> withSecurity(String theSystem, String theCode);
/**
* Match only resources where the resource has the given profile declaration. This parameter corresponds to
* the <code>_profile</code> URL parameter.
* @param theSystem The tag code system, or <code>null</code> to match any code system (this may not be supported on all servers)
* @param theCode The tag code. Must not be <code>null</code> or empty.
*/
IQuery<T> withProfile(String theProfileUri);
/**
* Forces the query to perform the search using the given method (allowable methods are described in the
* <a href="http://www.hl7.org/implement/standards/fhir/http.html#search">FHIR Specification Section 2.1.11</a>)

View File

@ -246,16 +246,6 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest.getServletRequest());
// _elements
Set<String> elements = ElementsParameter.getElementsValueOrNull(theRequest);
if (elements != null && summaryMode != null && !summaryMode.equals(Collections.singleton(SummaryEnum.FALSE))) {
throw new InvalidRequestException("Cannot combine the " + Constants.PARAM_SUMMARY + " and " + Constants.PARAM_ELEMENTS + " parameters");
}
Set<String> elementsAppliesTo = null;
if (elements != null && isNotBlank(myResourceName)) {
elementsAppliesTo = Collections.singleton(myResourceName);
}
// Is this request coming from a browser
String uaHeader = theRequest.getServletRequest().getHeader("user-agent");
boolean requestIsBrowser = false;
@ -341,8 +331,8 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
}
}
RestfulServerUtils.streamResponseAsResource(theServer, response, resource, responseEncoding, prettyPrint, requestIsBrowser, summaryMode, Constants.STATUS_HTTP_200_OK, respondGzip,
theRequest.getFhirServerBase(), isAddContentLocationHeader(), elements, elementsAppliesTo);
RestfulServerUtils.streamResponseAsResource(theServer, response, resource, prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, respondGzip,
isAddContentLocationHeader(), theRequest);
break;
} else {
Set<Include> includes = getRequestIncludesFromParams(params);
@ -365,7 +355,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
return;
}
}
RestfulServerUtils.streamResponseAsBundle(theServer, response, bundle, responseEncoding, theRequest.getFhirServerBase(), prettyPrint, summaryMode, respondGzip, requestIsBrowser);
RestfulServerUtils.streamResponseAsBundle(theServer, response, bundle, theRequest.getFhirServerBase(), summaryMode, respondGzip, requestIsBrowser, theRequest);
} else {
IBaseResource resBundle = bundleFactory.getResourceBundle();
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
@ -376,8 +366,8 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
return;
}
}
RestfulServerUtils.streamResponseAsResource(theServer, response, resBundle, responseEncoding, prettyPrint, requestIsBrowser, summaryMode,
Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), theRequest.getFhirServerBase(), isAddContentLocationHeader(), elements, elementsAppliesTo);
RestfulServerUtils.streamResponseAsResource(theServer, response, resBundle, prettyPrint, summaryMode,
Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), isAddContentLocationHeader(), theRequest);
}
break;
@ -401,8 +391,8 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
}
}
RestfulServerUtils.streamResponseAsResource(theServer, response, resource, responseEncoding, prettyPrint, requestIsBrowser, summaryMode, Constants.STATUS_HTTP_200_OK, respondGzip,
theRequest.getFhirServerBase(), isAddContentLocationHeader(), elements, elementsAppliesTo);
RestfulServerUtils.streamResponseAsResource(theServer, response, resource, prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, respondGzip,
isAddContentLocationHeader(), theRequest);
break;
}
}

View File

@ -40,8 +40,8 @@ public interface IVersionSpecificBundleFactory {
void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType, IPrimitiveType<Date> theLastUpdated);
void initializeBundleFromBundleProvider(RestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint, int theOffset, Integer theCount, String theSearchId, BundleTypeEnum theBundleType,
Set<Include> theIncludes);
void initializeBundleFromBundleProvider(RestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint,
int theOffset, Integer theCount, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes);
Bundle getDstu1Bundle();

View File

@ -19,7 +19,8 @@ package ca.uhn.fhir.rest.server;
* limitations under the License.
* #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.lang.annotation.Annotation;
@ -62,7 +63,6 @@ import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.method.ConformanceMethodBinding;
import ca.uhn.fhir.rest.method.ElementsParameter;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
@ -452,9 +452,7 @@ public class RestfulServer extends HttpServlet {
boolean requestIsBrowser = requestIsBrowser(theRequest.getServletRequest());
Set<SummaryEnum> summaryMode = RestfulServerUtils.determineSummaryMode(theRequest);
boolean respondGzip = theRequest.isRespondGzip();
Set<String> elements = ElementsParameter.getElementsValueOrNull(theRequest);
Set<String> elementsAppliesTo = null; // TODO: persist this across pages
IVersionSpecificBundleFactory bundleFactory = getFhirContext().newBundleFactory();
Set<Include> includes = new HashSet<Include>();
@ -480,7 +478,7 @@ public class RestfulServer extends HttpServlet {
return;
}
}
RestfulServerUtils.streamResponseAsBundle(this, theResponse, bundle, responseEncoding, theRequest.getFhirServerBase(), prettyPrint, summaryMode, respondGzip, requestIsBrowser);
RestfulServerUtils.streamResponseAsBundle(this, theResponse, bundle, theRequest.getFhirServerBase(), summaryMode, respondGzip, requestIsBrowser, theRequest);
} else {
IBaseResource resBundle = bundleFactory.getResourceBundle();
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
@ -491,8 +489,7 @@ public class RestfulServer extends HttpServlet {
return;
}
}
RestfulServerUtils.streamResponseAsResource(this, theResponse, resBundle, responseEncoding, prettyPrint, requestIsBrowser, summaryMode, Constants.STATUS_HTTP_200_OK,
theRequest.isRespondGzip(), theRequest.getFhirServerBase(), false, elements, elementsAppliesTo);
RestfulServerUtils.streamResponseAsResource(this, theResponse, resBundle, prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), false, theRequest);
}
}
@ -678,14 +675,12 @@ public class RestfulServer extends HttpServlet {
return;
}
}
/*
* Actualy invoke the server method. This call is to a HAPI method
* binding, which is an object that wraps a specific implementing (user-supplied)
* method, but handles its input and provides its output back to the client.
* Actualy invoke the server method. This call is to a HAPI method binding, which is an object that wraps a specific implementing (user-supplied) method, but handles its input and provides
* its output back to the client.
*
* This is basically the end of processing for a successful request,
* since the method binding replies to the client and closes the response.
* This is basically the end of processing for a successful request, since the method binding replies to the client and closes the response.
*/
resourceMethod.invokeServer(this, requestDetails);
@ -719,13 +714,10 @@ public class RestfulServer extends HttpServlet {
} catch (Throwable e) {
/*
* We have caught an exception during request processing. This might be
* because a handling method threw something they wanted to throw (e.g.
* UnprocessableEntityException because the request had business requirement
* problems) or it could be due to bugs (e.g. NullPointerException).
* We have caught an exception during request processing. This might be because a handling method threw something they wanted to throw (e.g. UnprocessableEntityException because the request
* had business requirement problems) or it could be due to bugs (e.g. NullPointerException).
*
* First we let the interceptors have a crack at converting the exception
* into something HAPI can use (BaseServerResponseException)
* First we let the interceptors have a crack at converting the exception into something HAPI can use (BaseServerResponseException)
*/
BaseServerResponseException exception = null;
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
@ -738,9 +730,8 @@ public class RestfulServer extends HttpServlet {
}
/*
* If none of the interceptors converted the exception, default behaviour is to
* keep the exception as-is if it extends BaseServerResponseException, otherwise
* wrap it in an InternalErrorException.
* If none of the interceptors converted the exception, default behaviour is to keep the exception as-is if it extends BaseServerResponseException, otherwise wrap it in an
* InternalErrorException.
*/
if (exception == null) {
exception = DEFAULT_EXCEPTION_HANDLER.preProcessOutgoingException(requestDetails, e, theRequest);
@ -758,8 +749,13 @@ public class RestfulServer extends HttpServlet {
}
/*
* If nobody handles it, default behaviour is to stream back the
* OperationOutcome to the client.
* If we're handling an exception, no summary mode should be applied
*/
requestDetails.getParameters().remove(Constants.PARAM_SUMMARY);
requestDetails.getParameters().remove(Constants.PARAM_ELEMENTS);
/*
* If nobody handles it, default behaviour is to stream back the OperationOutcome to the client.
*/
DEFAULT_EXCEPTION_HANDLER.handleException(requestDetails, exception, theRequest, theResponse);

View File

@ -63,9 +63,11 @@ import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.method.ElementsParameter;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.method.SummaryEnumParameter;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class RestfulServerUtils {
static final Pattern ACCEPT_HEADER_PATTERN = Pattern.compile("\\s*([a-zA-Z0-9+.*/-]+)\\s*(;\\s*([a-zA-Z]+)\\s*=\\s*([a-zA-Z0-9.]+)\\s*)?(,?)");
@ -285,9 +287,19 @@ public class RestfulServerUtils {
return RestfulServerUtils.tryToExtractNamedParameter(theRequest, Constants.PARAM_COUNT);
}
public static IParser getNewParser(FhirContext theContext, EncodingEnum theResponseEncoding, boolean thePrettyPrint, Set<SummaryEnum> theSummaryMode) {
public static IParser getNewParser(FhirContext theContext, RequestDetails theRequestDetails) {
// Pretty print
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theRequestDetails.getServer(), theRequestDetails);
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest());
if (responseEncoding == null) {
responseEncoding = theRequestDetails.getServer().getDefaultResponseEncoding();
}
IParser parser;
switch (theResponseEncoding) {
switch (responseEncoding) {
case JSON:
parser = theContext.newJsonParser();
break;
@ -296,17 +308,41 @@ public class RestfulServerUtils {
parser = theContext.newXmlParser();
break;
}
parser.setPrettyPrint(thePrettyPrint);
if (theSummaryMode != null) {
if (theSummaryMode.contains(SummaryEnum.COUNT)) {
parser.setPrettyPrint(prettyPrint);
parser.setServerBaseUrl(theRequestDetails.getFhirServerBase());
// Summary mode
Set<SummaryEnum> summaryMode = RestfulServerUtils.determineSummaryMode(theRequestDetails);
// _elements
Set<String> elements = ElementsParameter.getElementsValueOrNull(theRequestDetails);
if (elements != null && summaryMode != null && !summaryMode.equals(Collections.singleton(SummaryEnum.FALSE))) {
throw new InvalidRequestException("Cannot combine the " + Constants.PARAM_SUMMARY + " and " + Constants.PARAM_ELEMENTS + " parameters");
}
Set<String> elementsAppliesTo = null;
if (elements != null && isNotBlank(theRequestDetails.getResourceName())) {
elementsAppliesTo = Collections.singleton(theRequestDetails.getResourceName());
}
if (summaryMode != null) {
if (summaryMode.contains(SummaryEnum.COUNT)) {
parser.setEncodeElements(Collections.singleton("Bundle.total"));
} else if (theSummaryMode.contains(SummaryEnum.TEXT)) {
} else if (summaryMode.contains(SummaryEnum.TEXT)) {
parser.setEncodeElements(TEXT_ENCODE_ELEMENTS);
} else {
parser.setSuppressNarratives(theSummaryMode.contains(SummaryEnum.DATA));
parser.setSummaryMode(theSummaryMode.contains(SummaryEnum.TRUE));
parser.setSuppressNarratives(summaryMode.contains(SummaryEnum.DATA));
parser.setSummaryMode(summaryMode.contains(SummaryEnum.TRUE));
}
}
if (elements != null && elements.size() > 0) {
Set<String> newElements = new HashSet<String>();
for (String next : elements) {
newElements.add("*." + next);
}
parser.setEncodeElements(newElements);
parser.setEncodeElementsAppliesToResourceTypes(elementsAppliesTo);
}
return parser;
}
@ -378,13 +414,15 @@ public class RestfulServerUtils {
return prettyPrint;
}
public static void streamResponseAsBundle(RestfulServer theServer, HttpServletResponse theHttpResponse, Bundle bundle, EncodingEnum theResponseEncoding, String theServerBase, boolean thePrettyPrint, Set<SummaryEnum> theSummaryMode, boolean theRespondGzip, boolean theRequestIsBrowser)
public static void streamResponseAsBundle(RestfulServer theServer, HttpServletResponse theHttpResponse, Bundle bundle, String theServerBase, Set<SummaryEnum> theSummaryMode, boolean theRespondGzip, boolean theRequestIsBrowser, RequestDetails theRequestDetails)
throws IOException {
assert!theServerBase.endsWith("/");
theHttpResponse.setStatus(200);
EncodingEnum responseEncoding = theResponseEncoding != null ? theResponseEncoding : theServer.getDefaultResponseEncoding();
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest());
responseEncoding = responseEncoding != null ? responseEncoding : theServer.getDefaultResponseEncoding();
if (theRequestIsBrowser && theServer.isUseBrowserFriendlyContentTypes()) {
theHttpResponse.setContentType(responseEncoding.getBrowserFriendlyBundleContentType());
@ -398,8 +436,7 @@ public class RestfulServerUtils {
Writer writer = RestfulServerUtils.getWriter(theHttpResponse, theRespondGzip);
try {
IParser parser = RestfulServerUtils.getNewParser(theServer.getFhirContext(), responseEncoding, thePrettyPrint, theSummaryMode);
parser.setServerBaseUrl(theServerBase);
IParser parser = RestfulServerUtils.getNewParser(theServer.getFhirContext(), theRequestDetails);
if (theSummaryMode.contains(SummaryEnum.TEXT)) {
parser.setEncodeElements(TEXT_ENCODE_ELEMENTS);
}
@ -409,13 +446,17 @@ public class RestfulServerUtils {
}
}
public static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IBaseResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint, boolean theRequestIsBrowser, Set<SummaryEnum> theNarrativeMode, int stausCode, boolean theRespondGzip,
String theServerBase, boolean theAddContentLocationHeader, Set<String> theElements, Set<String> theElementsAppliesTo) throws IOException {
public static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IBaseResource theResource, boolean theRequestIsBrowser, Set<SummaryEnum> theSummaryMode, int stausCode, boolean theRespondGzip,
boolean theAddContentLocationHeader, RequestDetails theRequestDetails) throws IOException {
theHttpResponse.setStatus(stausCode);
if (theAddContentLocationHeader && theResource.getIdElement() != null && theResource.getIdElement().hasIdPart() && isNotBlank(theServerBase)) {
// Determine response encoding
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequestDetails.getServletRequest());
String serverBase = theRequestDetails.getFhirServerBase();
if (theAddContentLocationHeader && theResource.getIdElement() != null && theResource.getIdElement().hasIdPart() && isNotBlank(serverBase)) {
String resName = theServer.getFhirContext().getResourceDefinition(theResource).getName();
IIdType fullId = theResource.getIdElement().withServerBase(theServerBase, resName);
IIdType fullId = theResource.getIdElement().withServerBase(serverBase, resName);
theHttpResponse.addHeader(Constants.HEADER_CONTENT_LOCATION, fullId.getValue());
}
@ -428,11 +469,11 @@ public class RestfulServerUtils {
if (theServer.getAddProfileTag() != AddProfileTagEnum.NEVER) {
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(theResource);
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardProfile()) {
addProfileToBundleEntry(theServer.getFhirContext(), theResource, theServerBase);
addProfileToBundleEntry(theServer.getFhirContext(), theResource, serverBase);
}
}
if (theResource instanceof IBaseBinary && theResponseEncoding == null) {
if (theResource instanceof IBaseBinary && responseEncoding == null) {
IBaseBinary bin = (IBaseBinary) theResource;
if (isNotBlank(bin.getContentType())) {
theHttpResponse.setContentType(bin.getContentType());
@ -454,9 +495,10 @@ public class RestfulServerUtils {
return;
}
EncodingEnum responseEncoding = theResponseEncoding != null ? theResponseEncoding : theServer.getDefaultResponseEncoding();
boolean encodingDomainResourceAsText = theNarrativeMode.contains(SummaryEnum.TEXT);
// Ok, we're not serving a binary resource, so apply default encoding
responseEncoding = responseEncoding != null ? responseEncoding : theServer.getDefaultResponseEncoding();
boolean encodingDomainResourceAsText = theSummaryMode.contains(SummaryEnum.TEXT);
if (encodingDomainResourceAsText) {
/*
* If the user requests "text" for a bundle, only suppress the non text elements in the Element.entry.resource
@ -504,16 +546,7 @@ public class RestfulServerUtils {
if (encodingDomainResourceAsText && theResource instanceof IResource) {
writer.append(((IResource) theResource).getText().getDiv().getValueAsString());
} else {
IParser parser = getNewParser(theServer.getFhirContext(), responseEncoding, thePrettyPrint, theNarrativeMode);
parser.setServerBaseUrl(theServerBase);
if (theElements != null && theElements.size() > 0) {
Set<String> elements = new HashSet<String>();
for (String next : theElements) {
elements.add("*." + next);
}
parser.setEncodeElements(elements);
parser.setEncodeElementsAppliesToResourceTypes(theElementsAppliesTo);
}
IParser parser = getNewParser(theServer.getFhirContext(), theRequestDetails);
parser.encodeResourceToWriter(theResource, writer);
}
} finally {

View File

@ -19,8 +19,7 @@ package ca.uhn.fhir.rest.server.interceptor;
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.util.Collections;
@ -37,7 +36,6 @@ import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.RestfulServerUtils;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -73,9 +71,7 @@ public class ExceptionHandlingInterceptor extends InterceptorAdapter {
}
}
boolean requestIsBrowser = RestfulServer.requestIsBrowser(theRequest);
String fhirServerBase = theRequestDetails.getFhirServerBase();
RestfulServerUtils.streamResponseAsResource(theRequestDetails.getServer(), theResponse, oo, RestfulServerUtils.determineResponseEncodingNoDefault(theRequest), true, requestIsBrowser, Collections.singleton(SummaryEnum.FALSE), statusCode, false, fhirServerBase, false, null, null);
RestfulServerUtils.streamResponseAsResource(theRequestDetails.getServer(), theResponse, oo, true, Collections.singleton(SummaryEnum.FALSE), statusCode, false, false, theRequestDetails);
// theResponse.setStatus(statusCode);
// theRequestDetails.getServer().addHeadersToResponse(theResponse);

View File

@ -186,29 +186,17 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
return super.outgoingResponse(theRequestDetails, theResponseObject, theServletRequest, theServletResponse);
}
streamResponse(theRequestDetails, theServletRequest, theServletResponse, theResponseObject);
streamResponse(theRequestDetails, theServletResponse, theResponseObject);
return false;
}
private void streamResponse(RequestDetails theRequestDetails, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse, IBaseResource resource) {
// Pretty print
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theRequestDetails.getServer(), theRequestDetails);
// Determine response encoding
EncodingEnum responseEncoding = null;
if (theRequestDetails.getParameters().containsKey(Constants.PARAM_FORMAT)) {
// Browsers often state that they accept XML but we won't take that as being the user's preference
// unless they explicitly request it
responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theServletRequest);
}
if (responseEncoding == null) {
responseEncoding = theRequestDetails.getServer().getDefaultResponseEncoding();
}
IParser p = responseEncoding.newParser(theRequestDetails.getServer().getFhirContext());
p.setPrettyPrint(prettyPrint);
private void streamResponse(RequestDetails theRequestDetails, HttpServletResponse theServletResponse, IBaseResource resource) {
IParser p = RestfulServerUtils.getNewParser(theRequestDetails.getServer().getFhirContext(), theRequestDetails);
EncodingEnum encoding = p.getEncoding();
String encoded = p.encodeResourceToString(resource);
theServletResponse.setContentType(Constants.CT_HTML_WITH_UTF8);
@ -239,7 +227,7 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
" </head>\n" +
"\n" +
" <body>" +
"<pre>" + format(encoded, responseEncoding) + "</pre>" +
"<pre>" + format(encoded, encoding) + "</pre>" +
" </body>" +
"</html>";
//@formatter:off
@ -277,16 +265,11 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
return super.handleException(theRequestDetails, theException, theServletRequest, theServletResponse);
}
if (!(theException instanceof BaseServerResponseException)) {
if (theException.getOperationOutcome() == null) {
return super.handleException(theRequestDetails, theException, theServletRequest, theServletResponse);
}
BaseServerResponseException bsre = (BaseServerResponseException)theException;
if (bsre.getOperationOutcome() == null) {
return super.handleException(theRequestDetails, theException, theServletRequest, theServletResponse);
}
streamResponse(theRequestDetails, theServletRequest, theServletResponse, bsre.getOperationOutcome());
streamResponse(theRequestDetails, theServletResponse, theException.getOperationOutcome());
return false;
}

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%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 static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%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.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;

View File

@ -1,5 +1,25 @@
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 static org.apache.commons.lang3.StringUtils.isNotBlank;
import javax.servlet.http.HttpServletRequest;

View File

@ -656,6 +656,24 @@ public class FhirSystemDaoDstu2Test extends BaseJpaTest {
assertEquals("Patient/temp6789", p.getLink().get(0).getOther().getReference().getValue());
}
@Test
public void testTransactionFromBundleJosh() throws Exception {
InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/josh-bundle.json");
String bundleStr = IOUtils.toString(bundleRes);
Bundle bundle = ourFhirContext.newJsonParser().parseResource(Bundle.class, bundleStr);
Bundle resp = ourSystemDao.transaction(bundle);
ourLog.info(ourFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp));
OperationOutcome oo = (OperationOutcome) resp.getEntry().get(0).getResource();
assertThat(oo.getIssue().get(0).getDiagnostics(), containsString("Transaction completed"));
assertEquals("201 Created", resp.getEntry().get(1).getResponse().getStatus());
assertEquals("201 Created", resp.getEntry().get(2).getResponse().getStatus());
}
@Test
public void testTransactionReadAndSearch() {
String methodName = "testTransactionReadAndSearch";

View File

@ -0,0 +1,39 @@
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"fullUrl": "urn:oid:1",
"request": {
"method": "POST",
"url": "Patient"
},
"resource": {
"resourceType": "Patient",
"gender": "female",
"birthDate": "1960-09-13"
}
},
{
"fullUrl": "urn:oid:2",
"request": {
"method": "POST",
"url": "Appointment"
},
"resource": {
"resourceType": "Appointment",
"status": "booked",
"start": "2015-08-01T09:00:00Z",
"end": "2015-08-01T09:20:00Z",
"participant": [
{
"actor": {
"reference": "urn:oid:1"
},
"status": "accepted"
}
]
}
}
]
}

View File

@ -133,7 +133,7 @@ public class GenericClientTest {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") });
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
@ -149,30 +149,6 @@ public class GenericClientTest {
}
@Test
public void testMissing() throws Exception {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return (new ReaderInputStream(new StringReader(getPatientFeedWithOneResult()), Charset.forName("UTF-8")));
}});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
client.search().forResource("Patient").where(Patient.NAME.isMissing(true)).execute();
assertEquals("http://example.com/fhir/Patient?name%3Amissing=true", capt.getValue().getRequestLine().getUri());
client.search().forResource("Patient").where(Patient.NAME.isMissing(false)).execute();
assertEquals("http://example.com/fhir/Patient?name%3Amissing=false", capt.getValue().getRequestLine().getUri());
}
@Test
public void testCreateWithStringAutoDetectsEncoding() throws Exception {
@ -400,6 +376,86 @@ public class GenericClientTest {
}
@Test
public void testHistory() throws Exception {
final String msg = getPatientFeedWithOneResult();
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<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
Bundle response;
//@formatter:off
response = client
.history()
.onServer()
.andReturnDstu1Bundle()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/_history", capt.getAllValues().get(idx).getURI().toString());
assertEquals(1, response.size());
idx++;
//@formatter:off
response = client
.history()
.onType(Patient.class)
.andReturnDstu1Bundle()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/_history", capt.getAllValues().get(idx).getURI().toString());
assertEquals(1, response.size());
idx++;
//@formatter:off
response = client
.history()
.onInstance(new IdDt("Patient", "123"))
.andReturnDstu1Bundle()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/123/_history", capt.getAllValues().get(idx).getURI().toString());
assertEquals(1, response.size());
idx++;
}
@Test
public void testMissing() throws Exception {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") });
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return (new ReaderInputStream(new StringReader(getPatientFeedWithOneResult()), Charset.forName("UTF-8")));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
client.search().forResource("Patient").where(Patient.NAME.isMissing(true)).execute();
assertEquals("http://example.com/fhir/Patient?name%3Amissing=true", capt.getValue().getRequestLine().getUri());
client.search().forResource("Patient").where(Patient.NAME.isMissing(false)).execute();
assertEquals("http://example.com/fhir/Patient?name%3Amissing=false", capt.getValue().getRequestLine().getUri());
}
@Test
public void testRead() throws Exception {
@ -438,32 +494,6 @@ public class GenericClientTest {
}
@Test
public void testSetDefaultEncoding() throws Exception {
String msg = ourCtx.newJsonParser().encodeResourceToString(new Patient());
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_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
// Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"),
// new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
// new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") };
// when(myHttpResponse.getAllHeaders()).thenReturn(headers);
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
(client).setEncoding(EncodingEnum.JSON);
int count = 0;
client.read(Patient.class, new IdDt("Patient/1234"));
assertEquals("http://example.com/fhir/Patient/1234?_format=json", capt.getAllValues().get(count).getURI().toString());
count++;
}
@Test
public void testReadFluent() throws Exception {
@ -482,7 +512,7 @@ public class GenericClientTest {
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int count = 0;
Patient response = client.read().resource(Patient.class).withId(new IdDt("Patient/1234")).execute();
assertThat(response.getNameFirstRep().getFamilyAsSingleString(), StringContains.containsString("Cardinal"));
assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count++).getURI().toString());
@ -509,7 +539,6 @@ public class GenericClientTest {
}
@Test
public void testReadWithAbsoluteUrl() throws Exception {
@ -698,117 +727,6 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchByTag() throws Exception {
String msg = getPatientFeedWithOneResult();
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource(Patient.class)
.withTag("urn:foo", "123")
.withTag("urn:bar", "456")
.execute();
//@formatter:on
assertEquals(
"http://example.com/fhir/Patient?_tag=urn%3Afoo%7C123&_tag=urn%3Abar%7C456",
capt.getValue().getURI().toString());
}
@SuppressWarnings("unused")
@Test
public void testSearchWithReverseInclude() throws Exception {
String msg = getPatientFeedWithOneResult();
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource(Patient.class)
.encodedJson()
.revInclude(Provenance.INCLUDE_TARGET)
.execute();
//@formatter:on
assertEquals(
"http://example.com/fhir/Patient?_revinclude=Provenance.target&_format=json",
capt.getValue().getURI().toString());
}
@Test
public void testHistory() throws Exception {
final String msg = getPatientFeedWithOneResult();
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<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
}});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
Bundle response;
//@formatter:off
response = client
.history()
.onServer()
.andReturnDstu1Bundle()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/_history", capt.getAllValues().get(idx).getURI().toString());
assertEquals(1, response.size());
idx++;
//@formatter:off
response = client
.history()
.onType(Patient.class)
.andReturnDstu1Bundle()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/_history", capt.getAllValues().get(idx).getURI().toString());
assertEquals(1, response.size());
idx++;
//@formatter:off
response = client
.history()
.onInstance(new IdDt("Patient", "123"))
.andReturnDstu1Bundle()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/123/_history", capt.getAllValues().get(idx).getURI().toString());
assertEquals(1, response.size());
idx++;
}
@SuppressWarnings("unused")
@Test
public void testSearchByNumberExact() throws Exception {
@ -834,6 +752,32 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchByProfile() throws Exception {
String msg = getPatientFeedWithOneResult();
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource(Patient.class)
.withProfile("http://1")
.withProfile("http://2")
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?_profile=http%3A%2F%2F1&_profile=http%3A%2F%2F2", capt.getValue().getURI().toString());
}
@SuppressWarnings("unused")
@Test
public void testSearchByQuantity() throws Exception {
@ -909,6 +853,32 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchBySecurity() throws Exception {
String msg = getPatientFeedWithOneResult();
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource(Patient.class)
.withSecurity("urn:foo", "123")
.withSecurity("urn:bar", "456")
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?_security=urn%3Afoo%7C123&_security=urn%3Abar%7C456", capt.getValue().getURI().toString());
}
@SuppressWarnings("unused")
@Test
public void testSearchByString() throws Exception {
@ -969,6 +939,32 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchByTag() throws Exception {
String msg = getPatientFeedWithOneResult();
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource(Patient.class)
.withTag("urn:foo", "123")
.withTag("urn:bar", "456")
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?_tag=urn%3Afoo%7C123&_tag=urn%3Abar%7C456", capt.getValue().getURI().toString());
}
@SuppressWarnings("unused")
@Test
public void testSearchByToken() throws Exception {
@ -1030,7 +1026,8 @@ public class GenericClientTest {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
}});
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://foo");
int index = 0;
@ -1133,9 +1130,8 @@ public class GenericClientTest {
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
Bundle response = client
.search(new UriDt(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json"));
Bundle response = client.search(new UriDt(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json"));
assertEquals(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json",
@ -1157,10 +1153,8 @@ public class GenericClientTest {
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
Bundle response = client
.search(Patient.class,
new UriDt(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json"));
Bundle response = client.search(Patient.class, new UriDt(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json"));
assertEquals(
"http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json",
@ -1242,6 +1236,58 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchWithReverseInclude() throws Exception {
String msg = getPatientFeedWithOneResult();
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource(Patient.class)
.encodedJson()
.revInclude(Provenance.INCLUDE_TARGET)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?_revinclude=Provenance.target&_format=json", capt.getValue().getURI().toString());
}
@Test
public void testSetDefaultEncoding() throws Exception {
String msg = ourCtx.newJsonParser().encodeResourceToString(new Patient());
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_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
// Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"),
// new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
// new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") };
// when(myHttpResponse.getAllHeaders()).thenReturn(headers);
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
(client).setEncoding(EncodingEnum.JSON);
int count = 0;
client.read(Patient.class, new IdDt("Patient/1234"));
assertEquals("http://example.com/fhir/Patient/1234?_format=json", capt.getAllValues().get(count).getURI().toString());
count++;
}
@Test
public void testTransaction() throws Exception {
String bundleStr = IOUtils.toString(getClass().getResourceAsStream("/bundle.json"));
@ -1333,7 +1379,7 @@ public class GenericClientTest {
assertEquals(1, capt.getAllValues().size());
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType()+Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
count++;
MethodOutcome outcome = client.update().resource(p1).execute();
@ -1348,7 +1394,7 @@ public class GenericClientTest {
assertNotNull(Arrays.asList(capt.getValue().getAllHeaders()).toString(), catH);
assertEquals("urn:happytag; label=\"This is a happy resource\"; scheme=\"http://hl7.org/fhir/tag\"", catH.getValue());
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType()+Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
/*
* Try fluent options

View File

@ -1,17 +1,15 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.security.sasl.AuthorizeCallback;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.AssertionFailedError;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
@ -46,6 +44,7 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
import ca.uhn.fhir.util.PortUtil;
import junit.framework.AssertionFailedError;
/**
* Created by dsotnikov on 2/25/2014.

View File

@ -1,6 +1,8 @@
package ca.uhn.fhir.rest.client;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.either;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@ -1053,6 +1055,35 @@ public class GenericClientDstu2Test {
}
@Test
public void testSearchWithProfileAndSecurity() throws Exception {
String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
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_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.withProfile("http://foo1")
.withProfile("http://foo2")
.withSecurity("system1", "code1")
.withSecurity("system2", "code2")
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?_security=system1%7Ccode1&_security=system2%7Ccode2&_profile=http%3A%2F%2Ffoo1&_profile=http%3A%2F%2Ffoo2", capt.getValue().getURI().toString());
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@Test
public void testSearchWithSummaryParam() throws Exception {
String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
@ -1078,6 +1109,57 @@ public class GenericClientDstu2Test {
}
@Test
public void testSearchWithElementsParam() throws Exception {
String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
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_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.elementsSubset("name", "identifier")
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(), either(equalTo("http://example.com/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://example.com/fhir/Patient?name=james&_elements=identifier%2Cname")));
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@Test
public void testReadWithElementsParam() throws Exception {
String msg = "{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}";
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_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
IBaseResource response = client.read()
.resource("Patient")
.withId("123")
.elementsSubset("name", "identifier")
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(), either(equalTo("http://example.com/fhir/Patient/123?_elements=name%2Cidentifier")).or(equalTo("http://example.com/fhir/Patient/123?_elements=identifier%2Cname")));
assertEquals(Patient.class, response.getClass());
}
@Test
public void testReadWithSummaryParamHtml() throws Exception {
String msg = "<div>HELP IM A DIV</div>";

View File

@ -134,6 +134,19 @@ public class ResponseHighlightingInterceptorTest {
}
@Test
public void testSearchWithSummaryParam() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWithWildcardRetVal&_summary=count");
httpGet.addHeader("Accept", "html");
CloseableHttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info("Resp: {}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, not(containsString("entry")));
}
@Test
public void testGetInvalidResource() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Foobar/123");

80
pom.xml
View File

@ -251,6 +251,11 @@
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>lt.velykis.maven.skins</groupId>
<artifactId>reflow-velocity-tools</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
@ -281,6 +286,36 @@
<artifactId>httpcore</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>org.apache.maven.doxia</groupId>
<artifactId>doxia-module-markdown</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-api</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-manager-plexus</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-provider-gitexe</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-scm</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
@ -463,38 +498,30 @@
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-scm</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-manager-plexus</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-provider-gitexe</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-api</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.doxia</groupId>
<artifactId>doxia-module-markdown</artifactId>
<version>1.6</version>
</dependency>
<!-- -->
<dependency>
<groupId>lt.velykis.maven.skins</groupId>
<artifactId>reflow-velocity-tools</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
</dependencies>
</plugin>
@ -866,6 +893,43 @@
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-scm</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-manager-plexus</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-provider-gitexe</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-api</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.doxia</groupId>
<artifactId>doxia-module-markdown</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>lt.velykis.maven.skins</groupId>
<artifactId>reflow-velocity-tools</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View File

@ -223,6 +223,33 @@
<param name="file"
value="examples/src/main/java/example/GenericClientExample.java" />
</macro>
<h4>Search - Subsetting (_summary and _elements)</h4>
<p>
Sometimes you may want to only ask the server to include some parts of returned
resources (instead of the whole resource). Typically this is for performance or
optimization reasons, but there may also be privacy reasons for doing this.
</p>
<p>
To request that the server return only "summary" elements (those elements
defined in the specification with the "Σ" flag), you can use the
<code>summaryMode(SummaryEnum)</code> qualifier:
</p>
<macro name="snippet">
<param name="id" value="searchSubsetSummary" />
<param name="file"
value="examples/src/main/java/example/GenericClientExample.java" />
</macro>
<p>
To request that the server return only elements from a custom list
provided by the client, you can use the <code>elementsSubset(String...)</code>
qualifier:
</p>
<macro name="snippet">
<param name="id" value="searchSubsetElements" />
<param name="file"
value="examples/src/main/java/example/GenericClientExample.java" />
</macro>
</subsection>

View File

@ -379,8 +379,8 @@
<table>
<thead>
<tr>
<td>Parameter</td>
<td>Description</td>
<td><b>Parameter</b></td>
<td><b>Description</b></td>
</tr>
</thead>
<tbody>