Fix #796 - Correctly escape spaces in generated URLs

This commit is contained in:
James Agnew 2017-11-25 17:52:12 -05:00
parent 584ba1eec4
commit 6afe6804db
46 changed files with 1996 additions and 2038 deletions

View File

@ -59,6 +59,13 @@
<groupId>com.phloc</groupId> <groupId>com.phloc</groupId>
<artifactId>phloc-commons</artifactId> <artifactId>phloc-commons</artifactId>
<optional>true</optional> <optional>true</optional>
<exclusions>
<exclusion>
<!-- Guava brings in a newer replacement for this dependency called com.google.code.findbugs:jsr305 -->
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!-- <dependency> <groupId>xerces</groupId> <artifactId>xercesImpl</artifactId> <!-- <dependency> <groupId>xerces</groupId> <artifactId>xercesImpl</artifactId>
@ -77,6 +84,10 @@
<groupId>commons-io</groupId> <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- Logging --> <!-- Logging -->
<dependency> <dependency>

View File

@ -138,19 +138,6 @@ public class ParameterUtil {
return b.toString(); return b.toString();
} }
/**
* Escapes a string according to the rules for parameter escaping specified in the <a href="http://www.hl7.org/implement/standards/fhir/search.html#escaping">FHIR Specification Escaping
* Section</a>
*/
public static String escapeAndUrlEncode(String theValue) {
if (theValue == null) {
return null;
}
String escaped = escape(theValue);
return UrlUtil.escape(escaped);
}
/** /**
* Escapes a string according to the rules for parameter escaping specified in the <a href="http://www.hl7.org/implement/standards/fhir/search.html#escaping">FHIR Specification Escaping * Escapes a string according to the rules for parameter escaping specified in the <a href="http://www.hl7.org/implement/standards/fhir/search.html#escaping">FHIR Specification Escaping
* Section</a> * Section</a>

View File

@ -1,16 +1,20 @@
package ca.uhn.fhir.util; package ca.uhn.fhir.util;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.util.*;
import java.util.Map.Entry;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import com.google.common.escape.Escaper;
import com.google.common.net.PercentEscaper;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.Map.Entry;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.isBlank;
/* /*
* #%L * #%L
@ -35,6 +39,10 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class UrlUtil { public class UrlUtil {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UrlUtil.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UrlUtil.class);
private static final String URL_FORM_PARAMETER_OTHER_SAFE_CHARS = "-_.*";
private static final Escaper PARAMETER_ESCAPER = new PercentEscaper(URL_FORM_PARAMETER_OTHER_SAFE_CHARS, false);
/** /**
* Resolve a relative URL - THIS METHOD WILL NOT FAIL but will log a warning and return theEndpoint if the input is invalid. * Resolve a relative URL - THIS METHOD WILL NOT FAIL but will log a warning and return theEndpoint if the input is invalid.
*/ */
@ -88,19 +96,24 @@ public class UrlUtil {
} }
/** /**
* URL encode a value * URL encode a value according to RFC 3986
* <p>
* This method is intended to be applied to an individual parameter
* name or value. For example, if you are creating the URL
* <code>http://example.com/fhir/Patient?key=føø</code>
* it would be appropriate to pass the string "føø" to this method,
* but not appropriate to pass the entire URL since characters
* such as "/" and "?" would also be escaped.
* </P>
*/ */
public static String escape(String theValue) { public static String escapeUrlParam(String theUnescaped) {
if (theValue == null) { if (theUnescaped == null) {
return null; return null;
} }
try { return PARAMETER_ESCAPER.escape(theUnescaped);
return URLEncoder.encode(theValue, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new Error("UTF-8 not supported on this platform");
}
} }
public static boolean isAbsolute(String theValue) { public static boolean isAbsolute(String theValue) {
String value = theValue.toLowerCase(); String value = theValue.toLowerCase();
return value.startsWith("http://") || value.startsWith("https://"); return value.startsWith("http://") || value.startsWith("https://");
@ -147,7 +160,7 @@ public class UrlUtil {
} }
public static void main(String[] args) { public static void main(String[] args) {
System.out.println(escape("http://snomed.info/sct?fhir_vs=isa/126851005")); System.out.println(escapeUrlParam("http://snomed.info/sct?fhir_vs=isa/126851005"));
} }
public static Map<String, String[]> parseQueryString(String theQueryString) { public static Map<String, String[]> parseQueryString(String theQueryString) {
@ -156,36 +169,20 @@ public class UrlUtil {
return toQueryStringMap(map); return toQueryStringMap(map);
} }
public static Map<String, String[]> parseQueryStrings(String... theQueryString) {
HashMap<String, List<String>> map = new HashMap<String, List<String>>();
for (String next : theQueryString) {
parseQueryString(next, map);
}
return toQueryStringMap(map);
}
private static Map<String, String[]> toQueryStringMap(HashMap<String, List<String>> map) {
HashMap<String, String[]> retVal = new HashMap<String, String[]>();
for (Entry<String, List<String>> nextEntry : map.entrySet()) {
retVal.put(nextEntry.getKey(), nextEntry.getValue().toArray(new String[nextEntry.getValue().size()]));
}
return retVal;
}
private static void parseQueryString(String theQueryString, HashMap<String, List<String>> map) { private static void parseQueryString(String theQueryString, HashMap<String, List<String>> map) {
String query = theQueryString; String query = theQueryString;
if (query.startsWith("?")) { if (query.startsWith("?")) {
query = query.substring(1); query = query.substring(1);
} }
StringTokenizer tok = new StringTokenizer(query, "&"); StringTokenizer tok = new StringTokenizer(query, "&");
while (tok.hasMoreTokens()) { while (tok.hasMoreTokens()) {
String nextToken = tok.nextToken(); String nextToken = tok.nextToken();
if (isBlank(nextToken)) { if (isBlank(nextToken)) {
continue; continue;
} }
int equalsIndex = nextToken.indexOf('='); int equalsIndex = nextToken.indexOf('=');
String nextValue; String nextValue;
String nextKey; String nextKey;
@ -196,21 +193,28 @@ public class UrlUtil {
nextKey = nextToken.substring(0, equalsIndex); nextKey = nextToken.substring(0, equalsIndex);
nextValue = nextToken.substring(equalsIndex + 1); nextValue = nextToken.substring(equalsIndex + 1);
} }
nextKey = unescape(nextKey); nextKey = unescape(nextKey);
nextValue = unescape(nextValue); nextValue = unescape(nextValue);
List<String> list = map.get(nextKey); List<String> list = map.get(nextKey);
if (list == null) { if (list == null) {
list = new ArrayList<String>(); list = new ArrayList<>();
map.put(nextKey, list); map.put(nextKey, list);
} }
list.add(nextValue); list.add(nextValue);
} }
} }
//@formatter:off public static Map<String, String[]> parseQueryStrings(String... theQueryString) {
/** HashMap<String, List<String>> map = new HashMap<String, List<String>>();
for (String next : theQueryString) {
parseQueryString(next, map);
}
return toQueryStringMap(map);
}
/**
* Parse a URL in one of the following forms: * Parse a URL in one of the following forms:
* <ul> * <ul>
* <li>[Resource Type]?[Search Params] * <li>[Resource Type]?[Search Params]
@ -278,6 +282,16 @@ public class UrlUtil {
} }
//@formatter:off
private static Map<String, String[]> toQueryStringMap(HashMap<String, List<String>> map) {
HashMap<String, String[]> retVal = new HashMap<String, String[]>();
for (Entry<String, List<String>> nextEntry : map.entrySet()) {
retVal.put(nextEntry.getKey(), nextEntry.getValue().toArray(new String[nextEntry.getValue().size()]));
}
return retVal;
}
public static String unescape(String theString) { public static String unescape(String theString) {
if (theString == null) { if (theString == null) {
return null; return null;
@ -305,30 +319,30 @@ public class UrlUtil {
return myParams; return myParams;
} }
public String getResourceId() {
return myResourceId;
}
public String getResourceType() {
return myResourceType;
}
public String getVersionId() {
return myVersionId;
}
public void setParams(String theParams) { public void setParams(String theParams) {
myParams = theParams; myParams = theParams;
} }
public String getResourceId() {
return myResourceId;
}
public void setResourceId(String theResourceId) { public void setResourceId(String theResourceId) {
myResourceId = theResourceId; myResourceId = theResourceId;
} }
public String getResourceType() {
return myResourceType;
}
public void setResourceType(String theResourceType) { public void setResourceType(String theResourceType) {
myResourceType = theResourceType; myResourceType = theResourceType;
} }
public String getVersionId() {
return myVersionId;
}
public void setVersionId(String theVersionId) { public void setVersionId(String theVersionId) {
myVersionId = theVersionId; myVersionId = theVersionId;
} }

View File

@ -1,20 +1,42 @@
package ca.uhn.fhir.util; package ca.uhn.fhir.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
public class UrlUtilTest { public class UrlUtilTest {
@Test
public void testConstructAbsoluteUrl() {
assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl(null, "http://foo/bar/baz"));
assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl("http://foo/bar/", "baz"));
assertEquals("http://foo/bar/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/", "baz/"));
assertEquals("http://foo/bar/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/", "./baz/"));
assertEquals("http://foo/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/", "../baz/"));
assertEquals("http://foo/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/", "/baz/"));
}
@Test
public void testConstructRelativeUrl() {
assertEquals("http://foo/bar/baz", UrlUtil.constructRelativeUrl("http://boo/far/faz", "http://foo/bar/baz"));
assertEquals("http://foo/bar/baz", UrlUtil.constructRelativeUrl("http://foo/far/faz", "http://foo/bar/baz"));
assertEquals("baz", UrlUtil.constructRelativeUrl("http://foo/bar/boo", "http://foo/bar/baz"));
}
@Test
public void testEscape() {
assertEquals("A%20B", UrlUtil.escapeUrlParam("A B"));
assertEquals("A%2BB", UrlUtil.escapeUrlParam("A+B"));
}
@Test @Test
public void testIsValid() { public void testIsValid() {
assertTrue(UrlUtil.isValid("http://foo")); assertTrue(UrlUtil.isValid("http://foo"));
assertTrue(UrlUtil.isValid("https://foo")); assertTrue(UrlUtil.isValid("https://foo"));
assertTrue(UrlUtil.isValid("HTTP://Foo")); assertTrue(UrlUtil.isValid("HTTP://Foo"));
assertTrue(UrlUtil.isValid("HTTPS://Foo")); assertTrue(UrlUtil.isValid("HTTPS://Foo"));
assertFalse(UrlUtil.isValid("file://foo")); assertFalse(UrlUtil.isValid("file://foo"));
assertFalse(UrlUtil.isValid("://foo")); assertFalse(UrlUtil.isValid("://foo"));
assertFalse(UrlUtil.isValid("http:/ss")); assertFalse(UrlUtil.isValid("http:/ss"));
@ -24,7 +46,7 @@ public class UrlUtilTest {
assertFalse(UrlUtil.isValid("")); assertFalse(UrlUtil.isValid(""));
assertFalse(UrlUtil.isValid(null)); assertFalse(UrlUtil.isValid(null));
} }
@Test @Test
public void testParseUrl() { public void testParseUrl() {
assertEquals("ConceptMap", UrlUtil.parseUrl("http://hl7.org/fhir/ConceptMap/ussgfht-loincde").getResourceType()); assertEquals("ConceptMap", UrlUtil.parseUrl("http://hl7.org/fhir/ConceptMap/ussgfht-loincde").getResourceType());
@ -36,25 +58,5 @@ public class UrlUtilTest {
assertEquals("a=b", UrlUtil.parseUrl("ConceptMap/ussgfht-loincde?a=b").getParams()); assertEquals("a=b", UrlUtil.parseUrl("ConceptMap/ussgfht-loincde?a=b").getParams());
} }
@Test
public void testConstructAbsoluteUrl() {
assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl(null, "http://foo/bar/baz"));
assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl("http://foo/bar/","baz"));
assertEquals("http://foo/bar/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","baz/"));
assertEquals("http://foo/bar/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","./baz/"));
assertEquals("http://foo/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","../baz/"));
assertEquals("http://foo/baz/", UrlUtil.constructAbsoluteUrl("http://foo/bar/","/baz/"));
}
@Test
public void testConstructRelativeUrl() {
assertEquals("http://foo/bar/baz", UrlUtil.constructRelativeUrl("http://boo/far/faz", "http://foo/bar/baz"));
assertEquals("http://foo/bar/baz", UrlUtil.constructRelativeUrl("http://foo/far/faz", "http://foo/bar/baz"));
assertEquals("baz", UrlUtil.constructRelativeUrl("http://foo/bar/boo", "http://foo/bar/baz"));
}
} }

View File

@ -20,13 +20,6 @@ package ca.uhn.fhir.rest.client.impl;
* #L% * #L%
*/ */
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
@ -34,6 +27,12 @@ import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.client.api.IHttpClient; import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory; import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
import ca.uhn.fhir.util.UrlUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public abstract class BaseHttpClientInvocation { public abstract class BaseHttpClientInvocation {
@ -115,13 +114,9 @@ public abstract class BaseHttpClientInvocation {
} else { } else {
theUrlBuilder.append('&'); theUrlBuilder.append('&');
} }
try { theUrlBuilder.append(UrlUtil.escapeUrlParam(next.getKey()));
theUrlBuilder.append(URLEncoder.encode(next.getKey(), "UTF-8")); theUrlBuilder.append('=');
theUrlBuilder.append('='); theUrlBuilder.append(UrlUtil.escapeUrlParam(nextValue));
theUrlBuilder.append(URLEncoder.encode(nextValue, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new Error("UTF-8 not supported - This should not happen");
}
} }
} }
} }

View File

@ -354,7 +354,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
case '?': case '?':
case '$': case '$':
case ':': case ':':
b.append(UrlUtil.escape(Character.toString(nextChar))); b.append(UrlUtil.escapeUrlParam(Character.toString(nextChar)));
break; break;
default: default:
b.append(nextChar); b.append(nextChar);

View File

@ -20,21 +20,18 @@ package ca.uhn.fhir.rest.client.method;
* #L% * #L%
*/ */
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.IHttpRequest; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/** /**
* @author James Agnew * @author James Agnew
@ -51,51 +48,40 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
myUrlPath = StringUtils.join(theUrlFragments, '/'); myUrlPath = StringUtils.join(theUrlFragments, '/');
} }
public HttpGetClientInvocation(FhirContext theContext, Map<String, List<String>> theParameters, List<String> theUrlFragments) {
super(theContext);
myParameters = theParameters;
myUrlPath = StringUtils.join(theUrlFragments, '/');
}
public HttpGetClientInvocation(FhirContext theContext, String theUrlPath) { public HttpGetClientInvocation(FhirContext theContext, String theUrlPath) {
super(theContext); super(theContext);
myParameters = new HashMap<String, List<String>>(); myParameters = new HashMap<>();
myUrlPath = theUrlPath; myUrlPath = theUrlPath;
} }
public HttpGetClientInvocation(FhirContext theContext, String... theUrlFragments) {
super(theContext);
myParameters = new HashMap<String, List<String>>();
myUrlPath = StringUtils.join(theUrlFragments, '/');
}
private boolean addQueryParameter(StringBuilder b, boolean first, String nextKey, String nextValue) {
boolean retVal = first;
if (retVal) {
b.append('?');
retVal = false;
} else {
b.append('&');
}
b.append(UrlUtil.escapeUrlParam(nextKey));
b.append('=');
b.append(UrlUtil.escapeUrlParam(nextValue));
public HttpGetClientInvocation(FhirContext theContext, List<String> theUrlFragments) { return retVal;
super(theContext);
myParameters = new HashMap<String, List<String>>();
myUrlPath = StringUtils.join(theUrlFragments, '/');
}
public Map<String, List<String>> getParameters() {
return myParameters;
}
public String getUrlPath() {
return myUrlPath;
} }
@Override @Override
public IHttpRequest asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) { public IHttpRequest asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding, Boolean thePrettyPrint) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
if (!myUrlPath.contains("://")) { if (!myUrlPath.contains("://")) {
b.append(theUrlBase); b.append(theUrlBase);
if (!theUrlBase.endsWith("/") && !myUrlPath.startsWith("/")) { if (!theUrlBase.endsWith("/") && !myUrlPath.startsWith("/")) {
b.append('/'); b.append('/');
} }
} }
b.append(myUrlPath); b.append(myUrlPath);
boolean first = b.indexOf("?") == -1; boolean first = b.indexOf("?") == -1;
for (Entry<String, List<String>> next : myParameters.entrySet()) { for (Entry<String, List<String>> next : myParameters.entrySet()) {
if (next.getValue() == null || next.getValue().isEmpty()) { if (next.getValue() == null || next.getValue().isEmpty()) {
@ -112,22 +98,12 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
return super.createHttpRequest(b.toString(), theEncoding, RequestTypeEnum.GET); return super.createHttpRequest(b.toString(), theEncoding, RequestTypeEnum.GET);
} }
private boolean addQueryParameter(StringBuilder b, boolean first, String nextKey, String nextValue) { public Map<String, List<String>> getParameters() {
boolean retVal = first; return myParameters;
if (retVal) { }
b.append('?');
retVal = false; public String getUrlPath() {
} else { return myUrlPath;
b.append('&');
}
try {
b.append(URLEncoder.encode(nextKey, "UTF-8"));
b.append('=');
b.append(URLEncoder.encode(nextValue, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new ConfigurationException("Could not find UTF-8 encoding. This shouldn't happen.", e);
}
return retVal;
} }
} }

View File

@ -209,9 +209,9 @@ public class MethodUtil {
for (String nextValue : nextEntry.getValue()) { for (String nextValue : nextEntry.getValue()) {
b.append(haveQuestionMark ? '&' : '?'); b.append(haveQuestionMark ? '&' : '?');
haveQuestionMark = true; haveQuestionMark = true;
b.append(UrlUtil.escape(nextEntry.getKey())); b.append(UrlUtil.escapeUrlParam(nextEntry.getKey()));
b.append('='); b.append('=');
b.append(UrlUtil.escape(nextValue)); b.append(UrlUtil.escapeUrlParam(nextValue));
} }
} }
return b; return b;

View File

@ -35,7 +35,6 @@ import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum; import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
@ -229,14 +228,14 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
ArrayList<String> nextChoicesList = new ArrayList<>(); ArrayList<String> nextChoicesList = new ArrayList<>();
partsChoices.add(nextChoicesList); partsChoices.add(nextChoicesList);
String key = UrlUtil.escape(nextCompositeOf.getName()); String key = UrlUtil.escapeUrlParam(nextCompositeOf.getName());
if (paramsListForCompositePart != null) { if (paramsListForCompositePart != null) {
for (BaseResourceIndexedSearchParam nextParam : paramsListForCompositePart) { for (BaseResourceIndexedSearchParam nextParam : paramsListForCompositePart) {
if (nextParam.getParamName().equals(nextCompositeOf.getName())) { if (nextParam.getParamName().equals(nextCompositeOf.getName())) {
IQueryParameterType nextParamAsClientParam = nextParam.toQueryParameterType(); IQueryParameterType nextParamAsClientParam = nextParam.toQueryParameterType();
String value = nextParamAsClientParam.getValueAsQueryToken(getContext()); String value = nextParamAsClientParam.getValueAsQueryToken(getContext());
if (isNotBlank(value)) { if (isNotBlank(value)) {
value = UrlUtil.escape(value); value = UrlUtil.escapeUrlParam(value);
nextChoicesList.add(key + "=" + value); nextChoicesList.add(key + "=" + value);
} }
} }
@ -246,7 +245,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
for (ResourceLink nextLink : linksForCompositePart) { for (ResourceLink nextLink : linksForCompositePart) {
String value = nextLink.getTargetResource().getIdDt().toUnqualifiedVersionless().getValue(); String value = nextLink.getTargetResource().getIdDt().toUnqualifiedVersionless().getValue();
if (isNotBlank(value)) { if (isNotBlank(value)) {
value = UrlUtil.escape(value); value = UrlUtil.escapeUrlParam(value);
nextChoicesList.add(key + "=" + value); nextChoicesList.add(key + "=" + value);
} }
} }

View File

@ -60,7 +60,6 @@ import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hibernate.query.Query; import org.hibernate.query.Query;
import org.hl7.fhir.dstu3.model.BaseResource; import org.hl7.fhir.dstu3.model.BaseResource;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
@ -175,7 +174,7 @@ public class SearchBuilder implements ISearchBuilder {
if (valueBuilder.length() > 0) { if (valueBuilder.length() > 0) {
valueBuilder.append(','); valueBuilder.append(',');
} }
valueBuilder.append(UrlUtil.escape(next.getValueAsQueryToken(myContext))); valueBuilder.append(UrlUtil.escapeUrlParam(next.getValueAsQueryToken(myContext)));
targetResourceType = next.getTargetResourceType(); targetResourceType = next.getTargetResourceType();
owningParameter = next.getOwningFieldName(); owningParameter = next.getOwningFieldName();
parameterName = next.getParameterName(); parameterName = next.getParameterName();
@ -185,7 +184,7 @@ public class SearchBuilder implements ISearchBuilder {
continue; continue;
} }
String matchUrl = targetResourceType + '?' + UrlUtil.escape(parameterName) + '=' + valueBuilder.toString(); String matchUrl = targetResourceType + '?' + UrlUtil.escapeUrlParam(parameterName) + '=' + valueBuilder.toString();
RuntimeResourceDefinition targetResourceDefinition; RuntimeResourceDefinition targetResourceDefinition;
try { try {
targetResourceDefinition = myContext.getResourceDefinition(targetResourceType); targetResourceDefinition = myContext.getResourceDefinition(targetResourceType);
@ -1272,13 +1271,13 @@ public class SearchBuilder implements ISearchBuilder {
List<List<String>> params = new ArrayList<>(); List<List<String>> params = new ArrayList<>();
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamNameToValues : theParams.entrySet()) { for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamNameToValues : theParams.entrySet()) {
String nextParamName = nextParamNameToValues.getKey(); String nextParamName = nextParamNameToValues.getKey();
nextParamName = UrlUtil.escape(nextParamName); nextParamName = UrlUtil.escapeUrlParam(nextParamName);
for (List<? extends IQueryParameterType> nextAnd : nextParamNameToValues.getValue()) { for (List<? extends IQueryParameterType> nextAnd : nextParamNameToValues.getValue()) {
ArrayList<String> nextValueList = new ArrayList<>(); ArrayList<String> nextValueList = new ArrayList<>();
params.add(nextValueList); params.add(nextValueList);
for (IQueryParameterType nextOr : nextAnd) { for (IQueryParameterType nextOr : nextAnd) {
String nextOrValue = nextOr.getValueAsQueryToken(myContext); String nextOrValue = nextOr.getValueAsQueryToken(myContext);
nextOrValue = UrlUtil.escape(nextOrValue); nextOrValue = UrlUtil.escapeUrlParam(nextOrValue);
nextValueList.add(nextParamName + "=" + nextOrValue); nextValueList.add(nextParamName + "=" + nextOrValue);
} }
} }

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.jpa.dao; package ca.uhn.fhir.jpa.dao;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
/* /*
@ -24,7 +23,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
*/ */
import java.util.*; import java.util.*;
import ca.uhn.fhir.rest.param.ReferenceParam;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
@ -138,9 +136,9 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
addUrlParamSeparator(b); addUrlParamSeparator(b);
b.append(paramName); b.append(paramName);
b.append('='); b.append('=');
b.append(UrlUtil.escape(nextInclude.getParamType())); b.append(UrlUtil.escapeUrlParam(nextInclude.getParamType()));
b.append(':'); b.append(':');
b.append(UrlUtil.escape(nextInclude.getParamName())); b.append(UrlUtil.escapeUrlParam(nextInclude.getParamName()));
if (isNotBlank(nextInclude.getParamTargetType())) { if (isNotBlank(nextInclude.getParamTargetType())) {
b.append(':'); b.append(':');
b.append(nextInclude.getParamTargetType()); b.append(nextInclude.getParamTargetType());
@ -314,7 +312,7 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
for (List<IQueryParameterType> nextValuesAnd : nextValuesAndsOut) { for (List<IQueryParameterType> nextValuesAnd : nextValuesAndsOut) {
addUrlParamSeparator(b); addUrlParamSeparator(b);
IQueryParameterType firstValue = nextValuesAnd.get(0); IQueryParameterType firstValue = nextValuesAnd.get(0);
b.append(UrlUtil.escape(nextKey)); b.append(UrlUtil.escapeUrlParam(nextKey));
if (firstValue.getMissing() != null) { if (firstValue.getMissing() != null) {
b.append(Constants.PARAMQUALIFIER_MISSING); b.append(Constants.PARAMQUALIFIER_MISSING);
@ -340,7 +338,7 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
} }
String valueAsQueryToken = nextValueOr.getValueAsQueryToken(theCtx); String valueAsQueryToken = nextValueOr.getValueAsQueryToken(theCtx);
// b.append(ParameterUtil.escapeAndUrlEncode(valueAsQueryToken)); // b.append(ParameterUtil.escapeAndUrlEncode(valueAsQueryToken));
b.append(UrlUtil.escape(valueAsQueryToken)); b.append(UrlUtil.escapeUrlParam(valueAsQueryToken));
} }
} }

View File

@ -676,7 +676,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
String nextReplacementIdPart = nextReplacementId.getValueAsString(); String nextReplacementIdPart = nextReplacementId.getValueAsString();
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) { if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart); matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
matchUrl = matchUrl.replace(UrlUtil.escape(nextTemporaryIdPart), nextReplacementIdPart); matchUrl = matchUrl.replace(UrlUtil.escapeUrlParam(nextTemporaryIdPart), nextReplacementIdPart);
} }
} }
} }

View File

@ -667,7 +667,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
String nextReplacementIdPart = nextReplacementId.getValueAsString(); String nextReplacementIdPart = nextReplacementId.getValueAsString();
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) { if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart); matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
matchUrl = matchUrl.replace(UrlUtil.escape(nextTemporaryIdPart), nextReplacementIdPart); matchUrl = matchUrl.replace(UrlUtil.escapeUrlParam(nextTemporaryIdPart), nextReplacementIdPart);
} }
} }
} }

View File

@ -321,7 +321,7 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
cs.setUrl(theSystem); cs.setUrl(theSystem);
cs.setContent(CodeSystemContentMode.NOTPRESENT); cs.setContent(CodeSystemContentMode.NOTPRESENT);
DaoMethodOutcome createOutcome = myCodeSystemResourceDao.create(cs, "CodeSystem?url=" + UrlUtil.escape(theSystem), theRequestDetails); DaoMethodOutcome createOutcome = myCodeSystemResourceDao.create(cs, "CodeSystem?url=" + UrlUtil.escapeUrlParam(theSystem), theRequestDetails);
IIdType csId = createOutcome.getId().toUnqualifiedVersionless(); IIdType csId = createOutcome.getId().toUnqualifiedVersionless();
if (createOutcome.getCreated() != Boolean.TRUE) { if (createOutcome.getCreated() != Boolean.TRUE) {
CodeSystem existing = myCodeSystemResourceDao.read(csId, theRequestDetails); CodeSystem existing = myCodeSystemResourceDao.read(csId, theRequestDetails);

View File

@ -325,7 +325,7 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvc implements IVal
cs.setUrl(theSystem); cs.setUrl(theSystem);
cs.setContent(CodeSystemContentMode.NOTPRESENT); cs.setContent(CodeSystemContentMode.NOTPRESENT);
DaoMethodOutcome createOutcome = myCodeSystemResourceDao.create(cs, "CodeSystem?url=" + UrlUtil.escape(theSystem), theRequestDetails); DaoMethodOutcome createOutcome = myCodeSystemResourceDao.create(cs, "CodeSystem?url=" + UrlUtil.escapeUrlParam(theSystem), theRequestDetails);
IIdType csId = createOutcome.getId().toUnqualifiedVersionless(); IIdType csId = createOutcome.getId().toUnqualifiedVersionless();
if (createOutcome.getCreated() != Boolean.TRUE) { if (createOutcome.getCreated() != Boolean.TRUE) {
CodeSystem existing = myCodeSystemResourceDao.read(csId, theRequestDetails); CodeSystem existing = myCodeSystemResourceDao.read(csId, theRequestDetails);

View File

@ -30,7 +30,6 @@ import ca.uhn.fhir.model.dstu2.resource.*;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.valueset.*; import ca.uhn.fhir.model.dstu2.valueset.*;
import ca.uhn.fhir.model.primitive.*; import ca.uhn.fhir.model.primitive.*;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.IGenericClient;
@ -528,7 +527,7 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
pt.addName().addFamily("FOO"); pt.addName().addFamily("FOO");
resource = myFhirCtx.newXmlParser().encodeResourceToString(pt); resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escape("|")))); HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escapeUrlParam("|"))));
put.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); put.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
IdDt id2; IdDt id2;

View File

@ -1639,7 +1639,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
myObservationDao.create(obs, mySrd); myObservationDao.create(obs, mySrd);
} }
String uri = ourServerBase + "/Patient?_has:Observation:subject:identifier=" + UrlUtil.escape("urn:system|FOO"); String uri = ourServerBase + "/Patient?_has:Observation:subject:identifier=" + UrlUtil.escapeUrlParam("urn:system|FOO");
List<String> ids = searchAndReturnUnqualifiedVersionlessIdValues(uri); List<String> ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
assertThat(ids, contains(pid0.getValue())); assertThat(ids, contains(pid0.getValue()));
} }
@ -2347,7 +2347,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
myPatientDao.create(p, mySrd); myPatientDao.create(p, mySrd);
} }
String uri = ourServerBase + "/Patient?name=" + URLEncoder.encode("Jernelöv", "UTF-8") + "&_count=5&_pretty=true"; String uri = ourServerBase + "/Patient?name=" + UrlUtil.escapeUrlParam("Jernelöv") + "&_count=5&_pretty=true";
ourLog.info("URI: {}", uri); ourLog.info("URI: {}", uri);
HttpGet get = new HttpGet(uri); HttpGet get = new HttpGet(uri);
CloseableHttpResponse resp = ourHttpClient.execute(get); CloseableHttpResponse resp = ourHttpClient.execute(get);
@ -3792,7 +3792,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
pt.addName().setFamily("FOO"); pt.addName().setFamily("FOO");
resource = myFhirCtx.newXmlParser().encodeResourceToString(pt); resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escape("|")))); HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escapeUrlParam("|"))));
put.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); put.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
IdType id2; IdType id2;

View File

@ -25,7 +25,7 @@ public class GraphQLProviderR4Test extends BaseResourceProviderR4Test {
initTestPatients(); initTestPatients();
String query = "{name{family,given}}"; String query = "{name{family,given}}";
HttpGet httpGet = new HttpGet(ourServerBase + "/Patient/" + myPatientId0.getIdPart() + "/$graphql?query=" + UrlUtil.escape(query)); HttpGet httpGet = new HttpGet(ourServerBase + "/Patient/" + myPatientId0.getIdPart() + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse response = ourHttpClient.execute(httpGet); CloseableHttpResponse response = ourHttpClient.execute(httpGet);
try { try {
@ -50,7 +50,7 @@ public class GraphQLProviderR4Test extends BaseResourceProviderR4Test {
initTestPatients(); initTestPatients();
String query = "{PatientList(given:\"given\"){name{family,given}}}"; String query = "{PatientList(given:\"given\"){name{family,given}}}";
HttpGet httpGet = new HttpGet(ourServerBase + "/$graphql?query=" + UrlUtil.escape(query)); HttpGet httpGet = new HttpGet(ourServerBase + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse response = ourHttpClient.execute(httpGet); CloseableHttpResponse response = ourHttpClient.execute(httpGet);
try { try {

View File

@ -61,7 +61,6 @@ import java.math.BigDecimal;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
@ -1647,7 +1646,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
myObservationDao.create(obs, mySrd); myObservationDao.create(obs, mySrd);
} }
String uri = ourServerBase + "/Patient?_has:Observation:subject:identifier=" + UrlUtil.escape("urn:system|FOO"); String uri = ourServerBase + "/Patient?_has:Observation:subject:identifier=" + UrlUtil.escapeUrlParam("urn:system|FOO");
List<String> ids = searchAndReturnUnqualifiedVersionlessIdValues(uri); List<String> ids = searchAndReturnUnqualifiedVersionlessIdValues(uri);
assertThat(ids, contains(pid0.getValue())); assertThat(ids, contains(pid0.getValue()));
} }
@ -2355,7 +2354,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
myPatientDao.create(p, mySrd); myPatientDao.create(p, mySrd);
} }
String uri = ourServerBase + "/Patient?name=" + URLEncoder.encode("Jernelöv", "UTF-8") + "&_count=5&_pretty=true"; String uri = ourServerBase + "/Patient?name=" + UrlUtil.escapeUrlParam("Jernelöv") + "&_count=5&_pretty=true";
ourLog.info("URI: {}", uri); ourLog.info("URI: {}", uri);
HttpGet get = new HttpGet(uri); HttpGet get = new HttpGet(uri);
CloseableHttpResponse resp = ourHttpClient.execute(get); CloseableHttpResponse resp = ourHttpClient.execute(get);
@ -3938,7 +3937,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
pt.addName().setFamily("FOO"); pt.addName().setFamily("FOO");
resource = myFhirCtx.newXmlParser().encodeResourceToString(pt); resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escape("|")))); HttpPut put = new HttpPut(ourServerBase + "/Patient?identifier=" + ("http://general-hospital.co.uk/Identifiers|09832345234543876876".replace("|", UrlUtil.escapeUrlParam("|"))));
put.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); put.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
IdType id2; IdType id2;

View File

@ -80,13 +80,13 @@ public class AnalyticsInterceptor extends InterceptorAdapter {
b.append("&tid=").append(myAnalyticsTid); b.append("&tid=").append(myAnalyticsTid);
b.append("&t=event"); b.append("&t=event");
b.append("&an=").append(UrlUtil.escape(myHostname)).append('+').append(UrlUtil.escape(next.getApplicationName())); b.append("&an=").append(UrlUtil.escapeUrlParam(myHostname)).append('+').append(UrlUtil.escapeUrlParam(next.getApplicationName()));
b.append("&ec=").append(next.getResourceName()); b.append("&ec=").append(next.getResourceName());
b.append("&ea=").append(next.getRestOperation()); b.append("&ea=").append(next.getRestOperation());
b.append("&cid=").append(next.getClientId()); b.append("&cid=").append(next.getClientId());
b.append("&uip=").append(UrlUtil.escape(next.getSourceIp())); b.append("&uip=").append(UrlUtil.escapeUrlParam(next.getSourceIp()));
b.append("&ua=").append(UrlUtil.escape(next.getUserAgent())); b.append("&ua=").append(UrlUtil.escapeUrlParam(next.getUserAgent()));
b.append("\n"); b.append("\n");
} }

View File

@ -19,34 +19,38 @@ package ca.uhn.fhir.rest.server;
* limitations under the License. * limitations under the License.
* #L% * #L%
*/ */
import static org.apache.commons.lang3.StringUtils.*;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.util.BinaryUtil;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.*; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.server.IRestfulResponse; import ca.uhn.fhir.rest.api.server.IRestfulResponse;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.method.ElementsParameter; import ca.uhn.fhir.rest.server.method.ElementsParameter;
import ca.uhn.fhir.rest.server.method.SummaryEnumParameter; import ca.uhn.fhir.rest.server.method.SummaryEnumParameter;
import ca.uhn.fhir.util.BinaryUtil;
import ca.uhn.fhir.util.DateUtils; import ca.uhn.fhir.util.DateUtils;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import org.hl7.fhir.instance.model.api.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.commons.lang3.StringUtils.*;
public class RestfulServerUtils { 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*)?(,?)"); 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*)?(,?)");
@ -127,74 +131,70 @@ public class RestfulServerUtils {
} }
public static String createPagingLink(Set<Include> theIncludes, String theServerBase, String theSearchId, int theOffset, int theCount, Map<String, String[]> theRequestParameters, boolean thePrettyPrint, public static String createPagingLink(Set<Include> theIncludes, String theServerBase, String theSearchId, int theOffset, int theCount, Map<String, String[]> theRequestParameters, boolean thePrettyPrint,
BundleTypeEnum theBundleType) { BundleTypeEnum theBundleType) {
try { StringBuilder b = new StringBuilder();
StringBuilder b = new StringBuilder(); b.append(theServerBase);
b.append(theServerBase); b.append('?');
b.append('?'); b.append(Constants.PARAM_PAGINGACTION);
b.append(Constants.PARAM_PAGINGACTION); b.append('=');
b.append('='); b.append(UrlUtil.escapeUrlParam(theSearchId));
b.append(URLEncoder.encode(theSearchId, "UTF-8"));
b.append('&');
b.append(Constants.PARAM_PAGINGOFFSET);
b.append('=');
b.append(theOffset);
b.append('&');
b.append(Constants.PARAM_COUNT);
b.append('=');
b.append(theCount);
String[] strings = theRequestParameters.get(Constants.PARAM_FORMAT);
if (strings != null && strings.length > 0) {
b.append('&'); b.append('&');
b.append(Constants.PARAM_PAGINGOFFSET); b.append(Constants.PARAM_FORMAT);
b.append('='); b.append('=');
b.append(theOffset); String format = strings[0];
b.append('&'); format = replace(format, " ", "+");
b.append(Constants.PARAM_COUNT); b.append(UrlUtil.escapeUrlParam(format));
b.append('=');
b.append(theCount);
String[] strings = theRequestParameters.get(Constants.PARAM_FORMAT);
if (strings != null && strings.length > 0) {
b.append('&');
b.append(Constants.PARAM_FORMAT);
b.append('=');
String format = strings[0];
format = replace(format, " ", "+");
b.append(UrlUtil.escape(format));
}
if (thePrettyPrint) {
b.append('&');
b.append(Constants.PARAM_PRETTY);
b.append('=');
b.append(Constants.PARAM_PRETTY_VALUE_TRUE);
}
if (theIncludes != null) {
for (Include nextInclude : theIncludes) {
if (isNotBlank(nextInclude.getValue())) {
b.append('&');
b.append(Constants.PARAM_INCLUDE);
b.append('=');
b.append(URLEncoder.encode(nextInclude.getValue(), "UTF-8"));
}
}
}
if (theBundleType != null) {
b.append('&');
b.append(Constants.PARAM_BUNDLETYPE);
b.append('=');
b.append(theBundleType.getCode());
}
String paramName = Constants.PARAM_ELEMENTS;
String[] params = theRequestParameters.get(paramName);
if (params != null) {
for (String nextValue : params) {
if (isNotBlank(nextValue)) {
b.append('&');
b.append(paramName);
b.append('=');
b.append(UrlUtil.escape(nextValue));
}
}
}
return b.toString();
} catch (UnsupportedEncodingException e) {
throw new Error("UTF-8 not supported", e);// should not happen
} }
if (thePrettyPrint) {
b.append('&');
b.append(Constants.PARAM_PRETTY);
b.append('=');
b.append(Constants.PARAM_PRETTY_VALUE_TRUE);
}
if (theIncludes != null) {
for (Include nextInclude : theIncludes) {
if (isNotBlank(nextInclude.getValue())) {
b.append('&');
b.append(Constants.PARAM_INCLUDE);
b.append('=');
b.append(UrlUtil.escapeUrlParam(nextInclude.getValue()));
}
}
}
if (theBundleType != null) {
b.append('&');
b.append(Constants.PARAM_BUNDLETYPE);
b.append('=');
b.append(theBundleType.getCode());
}
String paramName = Constants.PARAM_ELEMENTS;
String[] params = theRequestParameters.get(paramName);
if (params != null) {
for (String nextValue : params) {
if (isNotBlank(nextValue)) {
b.append('&');
b.append(paramName);
b.append('=');
b.append(UrlUtil.escapeUrlParam(nextValue));
}
}
}
return b.toString();
} }
/** /**
@ -392,15 +392,15 @@ public class RestfulServerUtils {
try { try {
NarrativeModeEnum narrativeMode = NarrativeModeEnum.valueOfCaseInsensitive(narrative[0]); NarrativeModeEnum narrativeMode = NarrativeModeEnum.valueOfCaseInsensitive(narrative[0]);
switch (narrativeMode) { switch (narrativeMode) {
case NORMAL: case NORMAL:
retVal = Collections.singleton(SummaryEnum.FALSE); retVal = Collections.singleton(SummaryEnum.FALSE);
break; break;
case ONLY: case ONLY:
retVal = Collections.singleton(SummaryEnum.TEXT); retVal = Collections.singleton(SummaryEnum.TEXT);
break; break;
case SUPPRESS: case SUPPRESS:
retVal = Collections.singleton(SummaryEnum.DATA); retVal = Collections.singleton(SummaryEnum.DATA);
break; break;
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
ourLog.debug("Invalid {} parameter: {}", Constants.PARAM_NARRATIVE, narrative[0]); ourLog.debug("Invalid {} parameter: {}", Constants.PARAM_NARRATIVE, narrative[0]);
@ -461,13 +461,13 @@ public class RestfulServerUtils {
EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingWithDefault(theRequestDetails).getEncoding(); EncodingEnum responseEncoding = RestfulServerUtils.determineResponseEncodingWithDefault(theRequestDetails).getEncoding();
IParser parser; IParser parser;
switch (responseEncoding) { switch (responseEncoding) {
case JSON: case JSON:
parser = theContext.newJsonParser(); parser = theContext.newJsonParser();
break; break;
case XML: case XML:
default: default:
parser = theContext.newXmlParser(); parser = theContext.newXmlParser();
break; break;
} }
configureResponseParser(theRequestDetails, parser); configureResponseParser(theRequestDetails, parser);
@ -581,13 +581,13 @@ public class RestfulServerUtils {
} }
public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int stausCode, boolean theAddContentLocationHeader, public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int stausCode, boolean theAddContentLocationHeader,
boolean respondGzip, RequestDetails theRequestDetails) throws IOException { boolean respondGzip, RequestDetails theRequestDetails) throws IOException {
return streamResponseAsResource(theServer, theResource, theSummaryMode, stausCode, null, theAddContentLocationHeader, respondGzip, theRequestDetails, null, null); return streamResponseAsResource(theServer, theResource, theSummaryMode, stausCode, null, theAddContentLocationHeader, respondGzip, theRequestDetails, null, null);
} }
public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int theStausCode, String theStatusMessage, public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int theStausCode, String theStatusMessage,
boolean theAddContentLocationHeader, boolean respondGzip, RequestDetails theRequestDetails, IIdType theOperationResourceId, IPrimitiveType<Date> theOperationResourceLastUpdated) boolean theAddContentLocationHeader, boolean respondGzip, RequestDetails theRequestDetails, IIdType theOperationResourceId, IPrimitiveType<Date> theOperationResourceLastUpdated)
throws IOException { throws IOException {
IRestfulResponse response = theRequestDetails.getResponse(); IRestfulResponse response = theRequestDetails.getResponse();
// Determine response encoding // Determine response encoding
@ -706,7 +706,7 @@ public class RestfulServerUtils {
try { try {
return Integer.parseInt(retVal[0]); return Integer.parseInt(retVal[0]);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
ourLog.debug("Failed to parse {} value '{}': {}", new Object[] { theParamName, retVal[0], e }); ourLog.debug("Failed to parse {} value '{}': {}", new Object[]{theParamName, retVal[0], e});
return null; return null;
} }
} }
@ -752,7 +752,7 @@ public class RestfulServerUtils {
if (theContentType.equals(EncodingEnum.JSON_PLAIN_STRING) || theContentType.equals(EncodingEnum.XML_PLAIN_STRING)) { if (theContentType.equals(EncodingEnum.JSON_PLAIN_STRING) || theContentType.equals(EncodingEnum.XML_PLAIN_STRING)) {
FhirVersionEnum ctxtEnum = theCtx.getVersion().getVersion(); FhirVersionEnum ctxtEnum = theCtx.getVersion().getVersion();
myNonLegacy = ctxtEnum.isNewerThan(FhirVersionEnum.DSTU3) myNonLegacy = ctxtEnum.isNewerThan(FhirVersionEnum.DSTU3)
|| (ctxtEnum.isEquivalentTo(FhirVersionEnum.DSTU3) && !"1.4.0".equals(theCtx.getVersion().getVersion().getFhirVersionString())); || (ctxtEnum.isEquivalentTo(FhirVersionEnum.DSTU3) && !"1.4.0".equals(theCtx.getVersion().getVersion().getFhirVersionString()));
} else { } else {
myNonLegacy = EncodingEnum.isNonLegacy(theContentType); myNonLegacy = EncodingEnum.isNonLegacy(theContentType);
} }

View File

@ -25,7 +25,6 @@ import java.io.IOException;
*/ */
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date; import java.util.Date;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -33,6 +32,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.text.StrLookup; import org.apache.commons.lang3.text.StrLookup;
@ -277,13 +277,9 @@ public class LoggingInterceptor extends InterceptorAdapter {
} else { } else {
b.append('&'); b.append('&');
} }
try { b.append(UrlUtil.escapeUrlParam(next.getKey()));
b.append(URLEncoder.encode(next.getKey(), "UTF-8")); b.append('=');
b.append('='); b.append(UrlUtil.escapeUrlParam(nextValue));
b.append(URLEncoder.encode(nextValue, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new ca.uhn.fhir.context.ConfigurationException("UTF-8 not supported", e);
}
} }
} }
return b.toString(); return b.toString();

View File

@ -92,9 +92,9 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
} else { } else {
rawB.append('&'); rawB.append('&');
} }
rawB.append(UrlUtil.escape(next)); rawB.append(UrlUtil.escapeUrlParam(next));
rawB.append('='); rawB.append('=');
rawB.append(UrlUtil.escape(nextValue)); rawB.append(UrlUtil.escapeUrlParam(nextValue));
} }
} }
if (rawB.length() == 0) { if (rawB.length() == 0) {

View File

@ -186,9 +186,9 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
} else { } else {
b.append('&'); b.append('&');
} }
b.append(UrlUtil.escape(nextParamName)); b.append(UrlUtil.escapeUrlParam(nextParamName));
b.append('='); b.append('=');
b.append(UrlUtil.escape(nextParamValue)); b.append(UrlUtil.escapeUrlParam(nextParamValue));
} }
} }
} }

View File

@ -1,12 +1,15 @@
package ca.uhn.fhir.rest.server; package ca.uhn.fhir.rest.server;
import static org.junit.Assert.*; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BundleEntry;
import java.net.URLEncoder; import ca.uhn.fhir.model.api.IResource;
import java.util.ArrayList; import ca.uhn.fhir.model.dstu.resource.Observation;
import java.util.List; import ca.uhn.fhir.model.primitive.DateTimeDt;
import java.util.concurrent.TimeUnit; import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
@ -20,20 +23,11 @@ import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import ca.uhn.fhir.context.FhirContext; import java.util.ArrayList;
import ca.uhn.fhir.model.api.BundleEntry; import java.util.List;
import ca.uhn.fhir.model.api.IResource; import java.util.concurrent.TimeUnit;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.primitive.DateTimeDt; import static org.junit.Assert.*;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.CompositeAndListParam;
import ca.uhn.fhir.rest.param.CompositeOrListParam;
import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
/** /**
* Created by dsotnikov on 2/25/2014. * Created by dsotnikov on 2/25/2014.
@ -48,7 +42,7 @@ public class CompositeParameterTest {
@Test @Test
public void testSearchWithDateValue() throws Exception { public void testSearchWithDateValue() throws Exception {
{ {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?" + Observation.SP_NAME_VALUE_DATE + "=" + URLEncoder.encode("foo\\$bar$2001-01-01", "UTF-8")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?" + Observation.SP_NAME_VALUE_DATE + "=" + UrlUtil.escape("foo\\$bar$2001-01-01"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
@ -66,7 +60,7 @@ public class CompositeParameterTest {
@Test @Test
public void testSearchWithMultipleValue() throws Exception { public void testSearchWithMultipleValue() throws Exception {
{ {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?" + Observation.SP_NAME_VALUE_STRING + "=" + URLEncoder.encode("l1$r1,l2$r2", "UTF-8") + "&" + Observation.SP_NAME_VALUE_STRING + "=" + URLEncoder.encode("l3$r3,l4$r4", "UTF-8")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?" + Observation.SP_NAME_VALUE_STRING + "=" + UrlUtil.escape("l1$r1,l2$r2") + "&" + Observation.SP_NAME_VALUE_STRING + "=" + UrlUtil.escape("l3$r3,l4$r4"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());

View File

@ -1,15 +1,14 @@
package ca.uhn.fhir.rest.server; package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.containsString; import ca.uhn.fhir.context.FhirContext;
import static org.hamcrest.Matchers.not; import ca.uhn.fhir.model.api.IResource;
import static org.hamcrest.Matchers.stringContainsInOrder; import ca.uhn.fhir.model.dstu.resource.Patient;
import static org.junit.Assert.*; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import java.net.URLEncoder; import ca.uhn.fhir.rest.annotation.Read;
import java.util.concurrent.TimeUnit; import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
@ -22,20 +21,11 @@ import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import com.google.common.net.UrlEscapers; import java.util.concurrent.TimeUnit;
import ca.uhn.fhir.context.FhirContext; import static org.hamcrest.Matchers.containsString;
import ca.uhn.fhir.model.api.IResource; import static org.hamcrest.Matchers.not;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt; import static org.junit.Assert.*;
import ca.uhn.fhir.model.dstu.resource.BaseResource;
import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.dstu.resource.Organization;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
public class DefaultEncodingTest { public class DefaultEncodingTest {

View File

@ -1,11 +1,17 @@
package ca.uhn.fhir.rest.server; package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.*; import ca.uhn.fhir.context.FhirContext;
import static org.junit.Assert.*; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import java.net.URLEncoder; import ca.uhn.fhir.model.dstu.resource.BaseResource;
import java.util.concurrent.TimeUnit; import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.dstu.resource.Organization;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
@ -20,18 +26,10 @@ import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import ca.uhn.fhir.context.FhirContext; import java.util.concurrent.TimeUnit;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt; import static org.hamcrest.Matchers.*;
import ca.uhn.fhir.model.dstu.resource.BaseResource; import static org.junit.Assert.*;
import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.dstu.resource.Organization;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
public class ReadDstu1Test { public class ReadDstu1Test {
@ -129,10 +127,10 @@ public class ReadDstu1Test {
@Test @Test
public void testReadWithEscapedCharsInId() throws Exception { public void testReadWithEscapedCharsInId() throws Exception {
String id = "ABC!@#$--DEF"; String id = "ABC!@#$--DEF";
String idEscaped = URLEncoder.encode(id, "UTF-8"); String idEscaped = UrlUtil.escapeid);
String vid = "GHI:/:/JKL"; String vid = "GHI:/:/JKL";
String vidEscaped = URLEncoder.encode(vid, "UTF-8"); String vidEscaped = UrlUtil.escape(vid);
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/" + idEscaped + "/_history/" + vidEscaped); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/" + idEscaped + "/_history/" + vidEscaped);
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);

View File

@ -1,41 +1,12 @@
package ca.uhn.fhir.rest.server; package ca.uhn.fhir.rest.server;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BundleEntry; import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.Conformance; import ca.uhn.fhir.model.dstu.resource.*;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource; import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam; import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam;
import ca.uhn.fhir.model.dstu.resource.Location;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.resource.Organization;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum; import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
@ -47,6 +18,27 @@ import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.PortUtil; import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.*;
/** /**
* Created by dsotnikov on 2/25/2014. * Created by dsotnikov on 2/25/2014.
@ -105,7 +97,7 @@ public class ReferenceParameterTest {
@Test @Test
public void testReferenceParamViewToken() throws Exception { public void testReferenceParamViewToken() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?provider.name=" + URLEncoder.encode("foo|bar", "UTF-8")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?provider.name=" + UrlUtil.escape("foo|bar"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
IOUtils.toString(status.getEntity().getContent()); IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());

View File

@ -105,7 +105,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
@Test @Test
public void testEscapedOperationName() throws Exception { public void testEscapedOperationName() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/%24andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/%24andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -118,7 +118,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
@Test @Test
public void testAndListWithUrl() throws Exception { public void testAndListWithUrl() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -270,7 +270,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
} }
@Test @Test
public void testNonRepeatingWithUrl() throws Exception { public void testNonRepeatingWithUrl() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escape("VALTOKA|VALTOKB")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -290,7 +290,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
@Test @Test
public void testNonRepeatingWithUrlQualified() throws Exception { public void testNonRepeatingWithUrlQualified() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escape("VALTOKA|VALTOKB")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -345,7 +345,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
@Test @Test
public void testOrListWithUrl() throws Exception { public void testOrListWithUrl() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());

View File

@ -110,8 +110,8 @@ public class OperationServerWithSearchParamTypesDstu2Test {
@Test @Test
public void testAndListWithUrl() throws Exception { public void testAndListWithUrl() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok="
+ UrlUtil.escape("VALTOK2A|VALTOK2B")); + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -214,7 +214,7 @@ public class OperationServerWithSearchParamTypesDstu2Test {
@Test @Test
public void testNonRepeatingWithUrl() throws Exception { public void testNonRepeatingWithUrl() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escape("VALTOKA|VALTOKB")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -234,7 +234,7 @@ public class OperationServerWithSearchParamTypesDstu2Test {
@Test @Test
public void testNonRepeatingWithUrlQualified() throws Exception { public void testNonRepeatingWithUrlQualified() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escape("VALTOKA|VALTOKB")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -289,8 +289,8 @@ public class OperationServerWithSearchParamTypesDstu2Test {
@Test @Test
public void testOrListWithUrl() throws Exception { public void testOrListWithUrl() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok="
+ UrlUtil.escape("VALTOK2A|VALTOK2B")); + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());

View File

@ -1,12 +1,14 @@
package ca.uhn.fhir.rest.server; package ca.uhn.fhir.rest.server;
import static org.junit.Assert.assertEquals; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import java.net.URLEncoder; import ca.uhn.fhir.rest.annotation.RequiredParam;
import java.util.ArrayList; import ca.uhn.fhir.rest.annotation.Search;
import java.util.List; import ca.uhn.fhir.rest.param.ReferenceParam;
import java.util.concurrent.TimeUnit; import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
@ -22,14 +24,11 @@ import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import ca.uhn.fhir.context.FhirContext; import java.util.ArrayList;
import ca.uhn.fhir.model.dstu2.resource.Patient; import java.util.List;
import ca.uhn.fhir.rest.annotation.RequiredParam; import java.util.concurrent.TimeUnit;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.ReferenceParam; import static org.junit.Assert.*;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
public class ServerSearchDstu2Test { public class ServerSearchDstu2Test {
@ -106,7 +105,7 @@ public class ServerSearchDstu2Test {
@Test @Test
public void testSearchWithEncodedValue() throws Exception { public void testSearchWithEncodedValue() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/?param1=" + URLEncoder.encode("Jernelöv", "UTF-8")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/?param1=" + UrlUtil.escapeUrlParam("Jernelöv"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());

View File

@ -14,7 +14,6 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -186,7 +185,7 @@ public class ResponseHighlightingInterceptorTest {
@Test @Test
public void testForceApplicationJsonPlusFhir() throws Exception { public void testForceApplicationJsonPlusFhir() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=" + UrlUtil.escape("application/json+fhir")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=" + UrlUtil.escapeUrlParam("application/json+fhir"));
httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"); httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1");
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
@ -225,7 +224,7 @@ public class ResponseHighlightingInterceptorTest {
@Test @Test
public void testForceApplicationXmlPlusFhir() throws Exception { public void testForceApplicationXmlPlusFhir() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=" + UrlUtil.escape("application/xml+fhir")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=" + UrlUtil.escapeUrlParam("application/xml+fhir"));
httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"); httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1");
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);

View File

@ -1,122 +1,122 @@
package org.hl7.fhir.dstu3.model.codesystems; package org.hl7.fhir.dstu3.model.codesystems;
/* /*
Copyright (c) 2011+, HL7, Inc. Copyright (c) 2011+, HL7, Inc.
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to * Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific endorse or promote products derived from this software without specific
prior written permission. prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
*/ */
// Generated on Sat, Mar 25, 2017 21:03-0400 for FHIR v3.0.0 // Generated on Sat, Mar 25, 2017 21:03-0400 for FHIR v3.0.0
import org.hl7.fhir.dstu3.model.EnumFactory; import org.hl7.fhir.dstu3.model.EnumFactory;
public class MapTransformEnumFactory implements EnumFactory<MapTransform> { public class MapTransformEnumFactory implements EnumFactory<MapTransform> {
public MapTransform fromCode(String codeString) throws IllegalArgumentException { public MapTransform fromCode(String codeString) throws IllegalArgumentException {
if (codeString == null || "".equals(codeString)) if (codeString == null || "".equals(codeString))
return null; return null;
if ("create".equals(codeString)) if ("create".equals(codeString))
return MapTransform.CREATE; return MapTransform.CREATE;
if ("copy".equals(codeString)) if ("copy".equals(codeString))
return MapTransform.COPY; return MapTransform.COPY;
if ("truncate".equals(codeString)) if ("truncate".equals(codeString))
return MapTransform.TRUNCATE; return MapTransform.TRUNCATE;
if ("escape".equals(codeString)) if ("escapeUrlParam".equals(codeString))
return MapTransform.ESCAPE; return MapTransform.ESCAPE;
if ("cast".equals(codeString)) if ("cast".equals(codeString))
return MapTransform.CAST; return MapTransform.CAST;
if ("append".equals(codeString)) if ("append".equals(codeString))
return MapTransform.APPEND; return MapTransform.APPEND;
if ("translate".equals(codeString)) if ("translate".equals(codeString))
return MapTransform.TRANSLATE; return MapTransform.TRANSLATE;
if ("reference".equals(codeString)) if ("reference".equals(codeString))
return MapTransform.REFERENCE; return MapTransform.REFERENCE;
if ("dateOp".equals(codeString)) if ("dateOp".equals(codeString))
return MapTransform.DATEOP; return MapTransform.DATEOP;
if ("uuid".equals(codeString)) if ("uuid".equals(codeString))
return MapTransform.UUID; return MapTransform.UUID;
if ("pointer".equals(codeString)) if ("pointer".equals(codeString))
return MapTransform.POINTER; return MapTransform.POINTER;
if ("evaluate".equals(codeString)) if ("evaluate".equals(codeString))
return MapTransform.EVALUATE; return MapTransform.EVALUATE;
if ("cc".equals(codeString)) if ("cc".equals(codeString))
return MapTransform.CC; return MapTransform.CC;
if ("c".equals(codeString)) if ("c".equals(codeString))
return MapTransform.C; return MapTransform.C;
if ("qty".equals(codeString)) if ("qty".equals(codeString))
return MapTransform.QTY; return MapTransform.QTY;
if ("id".equals(codeString)) if ("id".equals(codeString))
return MapTransform.ID; return MapTransform.ID;
if ("cp".equals(codeString)) if ("cp".equals(codeString))
return MapTransform.CP; return MapTransform.CP;
throw new IllegalArgumentException("Unknown MapTransform code '"+codeString+"'"); throw new IllegalArgumentException("Unknown MapTransform code '"+codeString+"'");
} }
public String toCode(MapTransform code) { public String toCode(MapTransform code) {
if (code == MapTransform.CREATE) if (code == MapTransform.CREATE)
return "create"; return "create";
if (code == MapTransform.COPY) if (code == MapTransform.COPY)
return "copy"; return "copy";
if (code == MapTransform.TRUNCATE) if (code == MapTransform.TRUNCATE)
return "truncate"; return "truncate";
if (code == MapTransform.ESCAPE) if (code == MapTransform.ESCAPE)
return "escape"; return "escapeUrlParam";
if (code == MapTransform.CAST) if (code == MapTransform.CAST)
return "cast"; return "cast";
if (code == MapTransform.APPEND) if (code == MapTransform.APPEND)
return "append"; return "append";
if (code == MapTransform.TRANSLATE) if (code == MapTransform.TRANSLATE)
return "translate"; return "translate";
if (code == MapTransform.REFERENCE) if (code == MapTransform.REFERENCE)
return "reference"; return "reference";
if (code == MapTransform.DATEOP) if (code == MapTransform.DATEOP)
return "dateOp"; return "dateOp";
if (code == MapTransform.UUID) if (code == MapTransform.UUID)
return "uuid"; return "uuid";
if (code == MapTransform.POINTER) if (code == MapTransform.POINTER)
return "pointer"; return "pointer";
if (code == MapTransform.EVALUATE) if (code == MapTransform.EVALUATE)
return "evaluate"; return "evaluate";
if (code == MapTransform.CC) if (code == MapTransform.CC)
return "cc"; return "cc";
if (code == MapTransform.C) if (code == MapTransform.C)
return "c"; return "c";
if (code == MapTransform.QTY) if (code == MapTransform.QTY)
return "qty"; return "qty";
if (code == MapTransform.ID) if (code == MapTransform.ID)
return "id"; return "id";
if (code == MapTransform.CP) if (code == MapTransform.CP)
return "cp"; return "cp";
return "?"; return "?";
} }
public String toSystem(MapTransform code) { public String toSystem(MapTransform code) {
return code.getSystem(); return code.getSystem();
} }
} }

View File

@ -105,7 +105,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
@Test @Test
public void testEscapedOperationName() throws Exception { public void testEscapedOperationName() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/%24andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/%24andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -118,7 +118,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
@Test @Test
public void testAndListWithUrl() throws Exception { public void testAndListWithUrl() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$andlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -270,7 +270,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
} }
@Test @Test
public void testNonRepeatingWithUrl() throws Exception { public void testNonRepeatingWithUrl() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escape("VALTOKA|VALTOKB")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr=VALSTR&valtok=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -290,7 +290,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
@Test @Test
public void testNonRepeatingWithUrlQualified() throws Exception { public void testNonRepeatingWithUrlQualified() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escape("VALTOKA|VALTOKB")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$nonrepeating?valstr:exact=VALSTR&valtok:not=" + UrlUtil.escapeUrlParam("VALTOKA|VALTOKB"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
@ -345,7 +345,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
@Test @Test
public void testOrListWithUrl() throws Exception { public void testOrListWithUrl() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escape("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escape("VALTOK2A|VALTOK2B")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$orlist?valstr=VALSTR1A,VALSTR1B&valstr=VALSTR2A,VALSTR2B&valtok=" + UrlUtil.escapeUrlParam("VALTOK1A|VALTOK1B") + "&valtok=" + UrlUtil.escapeUrlParam("VALTOK2A|VALTOK2B"));
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());

View File

@ -137,25 +137,25 @@ public class SearchDstu3Test {
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=" + Constants.CT_FHIR_JSON_NEW); httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=" + Constants.CT_FHIR_JSON_NEW);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
} }

View File

@ -1,406 +1,406 @@
/* /*
Copyright (c) 2011+, HL7, Inc Copyright (c) 2011+, HL7, Inc
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to * Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific endorse or promote products derived from this software without specific
prior written permission. prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
*/ */
package org.hl7.fhir.instance.utilities.xml; package org.hl7.fhir.instance.utilities.xml;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.List; import java.util.List;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import org.hl7.fhir.instance.utilities.Utilities; import org.hl7.fhir.instance.utilities.Utilities;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer; import org.w3c.dom.ls.LSSerializer;
public class XMLUtil { public class XMLUtil {
public static final String SPACE_CHAR = "\u00A0"; public static final String SPACE_CHAR = "\u00A0";
public static boolean isNMToken(String name) { public static boolean isNMToken(String name) {
if (name == null) if (name == null)
return false; return false;
for (int i = 0; i < name.length(); i++) for (int i = 0; i < name.length(); i++)
if (!isNMTokenChar(name.charAt(i))) if (!isNMTokenChar(name.charAt(i)))
return false; return false;
return name.length() > 0; return name.length() > 0;
} }
public static boolean isNMTokenChar(char c) { public static boolean isNMTokenChar(char c) {
return isLetter(c) || isDigit(c) || c == '.' || c == '-' || c == '_' || c == ':' || isCombiningChar(c) || isExtender(c); return isLetter(c) || isDigit(c) || c == '.' || c == '-' || c == '_' || c == ':' || isCombiningChar(c) || isExtender(c);
} }
private static boolean isDigit(char c) { private static boolean isDigit(char c) {
return (c >= '\u0030' && c <= '\u0039') || (c >= '\u0660' && c <= '\u0669') || (c >= '\u06F0' && c <= '\u06F9') || return (c >= '\u0030' && c <= '\u0039') || (c >= '\u0660' && c <= '\u0669') || (c >= '\u06F0' && c <= '\u06F9') ||
(c >= '\u0966' && c <= '\u096F') || (c >= '\u09E6' && c <= '\u09EF') || (c >= '\u0A66' && c <= '\u0A6F') || (c >= '\u0966' && c <= '\u096F') || (c >= '\u09E6' && c <= '\u09EF') || (c >= '\u0A66' && c <= '\u0A6F') ||
(c >= '\u0AE6' && c <= '\u0AEF') || (c >= '\u0B66' && c <= '\u0B6F') || (c >= '\u0BE7' && c <= '\u0BEF') || (c >= '\u0AE6' && c <= '\u0AEF') || (c >= '\u0B66' && c <= '\u0B6F') || (c >= '\u0BE7' && c <= '\u0BEF') ||
(c >= '\u0C66' && c <= '\u0C6F') || (c >= '\u0CE6' && c <= '\u0CEF') || (c >= '\u0D66' && c <= '\u0D6F') || (c >= '\u0C66' && c <= '\u0C6F') || (c >= '\u0CE6' && c <= '\u0CEF') || (c >= '\u0D66' && c <= '\u0D6F') ||
(c >= '\u0E50' && c <= '\u0E59') || (c >= '\u0ED0' && c <= '\u0ED9') || (c >= '\u0F20' && c <= '\u0F29'); (c >= '\u0E50' && c <= '\u0E59') || (c >= '\u0ED0' && c <= '\u0ED9') || (c >= '\u0F20' && c <= '\u0F29');
} }
private static boolean isCombiningChar(char c) { private static boolean isCombiningChar(char c) {
return (c >= '\u0300' && c <= '\u0345') || (c >= '\u0360' && c <= '\u0361') || (c >= '\u0483' && c <= '\u0486') || return (c >= '\u0300' && c <= '\u0345') || (c >= '\u0360' && c <= '\u0361') || (c >= '\u0483' && c <= '\u0486') ||
(c >= '\u0591' && c <= '\u05A1') || (c >= '\u05A3' && c <= '\u05B9') || (c >= '\u05BB' && c <= '\u05BD') || (c >= '\u0591' && c <= '\u05A1') || (c >= '\u05A3' && c <= '\u05B9') || (c >= '\u05BB' && c <= '\u05BD') ||
c == '\u05BF' || (c >= '\u05C1' && c <= '\u05C2') || c == '\u05C4' || (c >= '\u064B' && c <= '\u0652') || c == '\u05BF' || (c >= '\u05C1' && c <= '\u05C2') || c == '\u05C4' || (c >= '\u064B' && c <= '\u0652') ||
c == '\u0670' || (c >= '\u06D6' && c <= '\u06DC') || (c >= '\u06DD' && c <= '\u06DF') || (c >= '\u06E0' && c <= '\u06E4') || c == '\u0670' || (c >= '\u06D6' && c <= '\u06DC') || (c >= '\u06DD' && c <= '\u06DF') || (c >= '\u06E0' && c <= '\u06E4') ||
(c >= '\u06E7' && c <= '\u06E8') || (c >= '\u06EA' && c <= '\u06ED') || (c >= '\u0901' && c <= '\u0903') || c == '\u093C' || (c >= '\u06E7' && c <= '\u06E8') || (c >= '\u06EA' && c <= '\u06ED') || (c >= '\u0901' && c <= '\u0903') || c == '\u093C' ||
(c >= '\u093E' && c <= '\u094C') || c == '\u094D' || (c >= '\u0951' && c <= '\u0954') || (c >= '\u0962' && c <= '\u0963') || (c >= '\u093E' && c <= '\u094C') || c == '\u094D' || (c >= '\u0951' && c <= '\u0954') || (c >= '\u0962' && c <= '\u0963') ||
(c >= '\u0981' && c <= '\u0983') || c == '\u09BC' || c == '\u09BE' || c == '\u09BF' || (c >= '\u09C0' && c <= '\u09C4') || (c >= '\u0981' && c <= '\u0983') || c == '\u09BC' || c == '\u09BE' || c == '\u09BF' || (c >= '\u09C0' && c <= '\u09C4') ||
(c >= '\u09C7' && c <= '\u09C8') || (c >= '\u09CB' && c <= '\u09CD') || c == '\u09D7' || (c >= '\u09E2' && c <= '\u09E3') || (c >= '\u09C7' && c <= '\u09C8') || (c >= '\u09CB' && c <= '\u09CD') || c == '\u09D7' || (c >= '\u09E2' && c <= '\u09E3') ||
c == '\u0A02' || c == '\u0A3C' || c == '\u0A3E' || c == '\u0A3F' || (c >= '\u0A40' && c <= '\u0A42') || c == '\u0A02' || c == '\u0A3C' || c == '\u0A3E' || c == '\u0A3F' || (c >= '\u0A40' && c <= '\u0A42') ||
(c >= '\u0A47' && c <= '\u0A48') || (c >= '\u0A4B' && c <= '\u0A4D') || (c >= '\u0A70' && c <= '\u0A71') || (c >= '\u0A47' && c <= '\u0A48') || (c >= '\u0A4B' && c <= '\u0A4D') || (c >= '\u0A70' && c <= '\u0A71') ||
(c >= '\u0A81' && c <= '\u0A83') || c == '\u0ABC' || (c >= '\u0ABE' && c <= '\u0AC5') || (c >= '\u0AC7' && c <= '\u0AC9') || (c >= '\u0A81' && c <= '\u0A83') || c == '\u0ABC' || (c >= '\u0ABE' && c <= '\u0AC5') || (c >= '\u0AC7' && c <= '\u0AC9') ||
(c >= '\u0ACB' && c <= '\u0ACD') || (c >= '\u0B01' && c <= '\u0B03') || c == '\u0B3C' || (c >= '\u0B3E' && c <= '\u0B43') || (c >= '\u0ACB' && c <= '\u0ACD') || (c >= '\u0B01' && c <= '\u0B03') || c == '\u0B3C' || (c >= '\u0B3E' && c <= '\u0B43') ||
(c >= '\u0B47' && c <= '\u0B48') || (c >= '\u0B4B' && c <= '\u0B4D') || (c >= '\u0B56' && c <= '\u0B57') || (c >= '\u0B47' && c <= '\u0B48') || (c >= '\u0B4B' && c <= '\u0B4D') || (c >= '\u0B56' && c <= '\u0B57') ||
(c >= '\u0B82' && c <= '\u0B83') || (c >= '\u0BBE' && c <= '\u0BC2') || (c >= '\u0BC6' && c <= '\u0BC8') || (c >= '\u0B82' && c <= '\u0B83') || (c >= '\u0BBE' && c <= '\u0BC2') || (c >= '\u0BC6' && c <= '\u0BC8') ||
(c >= '\u0BCA' && c <= '\u0BCD') || c == '\u0BD7' || (c >= '\u0C01' && c <= '\u0C03') || (c >= '\u0C3E' && c <= '\u0C44') || (c >= '\u0BCA' && c <= '\u0BCD') || c == '\u0BD7' || (c >= '\u0C01' && c <= '\u0C03') || (c >= '\u0C3E' && c <= '\u0C44') ||
(c >= '\u0C46' && c <= '\u0C48') || (c >= '\u0C4A' && c <= '\u0C4D') || (c >= '\u0C55' && c <= '\u0C56') || (c >= '\u0C46' && c <= '\u0C48') || (c >= '\u0C4A' && c <= '\u0C4D') || (c >= '\u0C55' && c <= '\u0C56') ||
(c >= '\u0C82' && c <= '\u0C83') || (c >= '\u0CBE' && c <= '\u0CC4') || (c >= '\u0CC6' && c <= '\u0CC8') || (c >= '\u0C82' && c <= '\u0C83') || (c >= '\u0CBE' && c <= '\u0CC4') || (c >= '\u0CC6' && c <= '\u0CC8') ||
(c >= '\u0CCA' && c <= '\u0CCD') || (c >= '\u0CD5' && c <= '\u0CD6') || (c >= '\u0D02' && c <= '\u0D03') || (c >= '\u0CCA' && c <= '\u0CCD') || (c >= '\u0CD5' && c <= '\u0CD6') || (c >= '\u0D02' && c <= '\u0D03') ||
(c >= '\u0D3E' && c <= '\u0D43') || (c >= '\u0D46' && c <= '\u0D48') || (c >= '\u0D4A' && c <= '\u0D4D') || c == '\u0D57' || (c >= '\u0D3E' && c <= '\u0D43') || (c >= '\u0D46' && c <= '\u0D48') || (c >= '\u0D4A' && c <= '\u0D4D') || c == '\u0D57' ||
c == '\u0E31' || (c >= '\u0E34' && c <= '\u0E3A') || (c >= '\u0E47' && c <= '\u0E4E') || c == '\u0EB1' || c == '\u0E31' || (c >= '\u0E34' && c <= '\u0E3A') || (c >= '\u0E47' && c <= '\u0E4E') || c == '\u0EB1' ||
(c >= '\u0EB4' && c <= '\u0EB9') || (c >= '\u0EBB' && c <= '\u0EBC') || (c >= '\u0EC8' && c <= '\u0ECD') || (c >= '\u0EB4' && c <= '\u0EB9') || (c >= '\u0EBB' && c <= '\u0EBC') || (c >= '\u0EC8' && c <= '\u0ECD') ||
(c >= '\u0F18' && c <= '\u0F19') || c == '\u0F35' || c == '\u0F37' || c == '\u0F39' || c == '\u0F3E' || c == '\u0F3F' || (c >= '\u0F18' && c <= '\u0F19') || c == '\u0F35' || c == '\u0F37' || c == '\u0F39' || c == '\u0F3E' || c == '\u0F3F' ||
(c >= '\u0F71' && c <= '\u0F84') || (c >= '\u0F86' && c <= '\u0F8B') || (c >= '\u0F90' && c <= '\u0F95') || c == '\u0F97' || (c >= '\u0F71' && c <= '\u0F84') || (c >= '\u0F86' && c <= '\u0F8B') || (c >= '\u0F90' && c <= '\u0F95') || c == '\u0F97' ||
(c >= '\u0F99' && c <= '\u0FAD') || (c >= '\u0FB1' && c <= '\u0FB7') || c == '\u0FB9' || (c >= '\u20D0' && c <= '\u20DC') || (c >= '\u0F99' && c <= '\u0FAD') || (c >= '\u0FB1' && c <= '\u0FB7') || c == '\u0FB9' || (c >= '\u20D0' && c <= '\u20DC') ||
c == '\u20E1' || (c >= '\u302A' && c <= '\u302F') || c == '\u3099' || c == '\u309A'; c == '\u20E1' || (c >= '\u302A' && c <= '\u302F') || c == '\u3099' || c == '\u309A';
} }
private static boolean isExtender(char c) { private static boolean isExtender(char c) {
return c == '\u00B7' || c == '\u02D0' || c == '\u02D1' || c == '\u0387' || c == '\u0640' || c == '\u0E46' || return c == '\u00B7' || c == '\u02D0' || c == '\u02D1' || c == '\u0387' || c == '\u0640' || c == '\u0E46' ||
c == '\u0EC6' || c == '\u3005' || (c >= '\u3031' && c <= '\u3035') || (c >= '\u309D' && c <= '\u309E') || c == '\u0EC6' || c == '\u3005' || (c >= '\u3031' && c <= '\u3035') || (c >= '\u309D' && c <= '\u309E') ||
(c >= '\u30FC' && c <= '\u30FE'); (c >= '\u30FC' && c <= '\u30FE');
} }
private static boolean isLetter(char c) { private static boolean isLetter(char c) {
return isBaseChar(c) || isIdeographic(c); return isBaseChar(c) || isIdeographic(c);
} }
private static boolean isBaseChar(char c) { private static boolean isBaseChar(char c) {
return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A') || (c >= '\u00C0' && c <= '\u00D6') || return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A') || (c >= '\u00C0' && c <= '\u00D6') ||
(c >= '\u00D8' && c <= '\u00F6') || (c >= '\u00F8' && c <= '\u00FF') || (c >= '\u0100' && c <= '\u0131') || (c >= '\u00D8' && c <= '\u00F6') || (c >= '\u00F8' && c <= '\u00FF') || (c >= '\u0100' && c <= '\u0131') ||
(c >= '\u0134' && c <= '\u013E') || (c >= '\u0141' && c <= '\u0148') || (c >= '\u014A' && c <= '\u017E') || (c >= '\u0134' && c <= '\u013E') || (c >= '\u0141' && c <= '\u0148') || (c >= '\u014A' && c <= '\u017E') ||
(c >= '\u0180' && c <= '\u01C3') || (c >= '\u01CD' && c <= '\u01F0') || (c >= '\u01F4' && c <= '\u01F5') || (c >= '\u0180' && c <= '\u01C3') || (c >= '\u01CD' && c <= '\u01F0') || (c >= '\u01F4' && c <= '\u01F5') ||
(c >= '\u01FA' && c <= '\u0217') || (c >= '\u0250' && c <= '\u02A8') || (c >= '\u02BB' && c <= '\u02C1') || (c >= '\u01FA' && c <= '\u0217') || (c >= '\u0250' && c <= '\u02A8') || (c >= '\u02BB' && c <= '\u02C1') ||
c == '\u0386' || (c >= '\u0388' && c <= '\u038A') || c == '\u038C' || (c >= '\u038E' && c <= '\u03A1') || c == '\u0386' || (c >= '\u0388' && c <= '\u038A') || c == '\u038C' || (c >= '\u038E' && c <= '\u03A1') ||
(c >= '\u03A3' && c <= '\u03CE') || (c >= '\u03D0' && c <= '\u03D6') || c == '\u03DA' || c == '\u03DC' || c == '\u03DE' || (c >= '\u03A3' && c <= '\u03CE') || (c >= '\u03D0' && c <= '\u03D6') || c == '\u03DA' || c == '\u03DC' || c == '\u03DE' ||
c == '\u03E0' || (c >= '\u03E2' && c <= '\u03F3') || (c >= '\u0401' && c <= '\u040C') || (c >= '\u040E' && c <= '\u044F') || c == '\u03E0' || (c >= '\u03E2' && c <= '\u03F3') || (c >= '\u0401' && c <= '\u040C') || (c >= '\u040E' && c <= '\u044F') ||
(c >= '\u0451' && c <= '\u045C') || (c >= '\u045E' && c <= '\u0481') || (c >= '\u0490' && c <= '\u04C4') || (c >= '\u0451' && c <= '\u045C') || (c >= '\u045E' && c <= '\u0481') || (c >= '\u0490' && c <= '\u04C4') ||
(c >= '\u04C7' && c <= '\u04C8') || (c >= '\u04CB' && c <= '\u04CC') || (c >= '\u04D0' && c <= '\u04EB') || (c >= '\u04C7' && c <= '\u04C8') || (c >= '\u04CB' && c <= '\u04CC') || (c >= '\u04D0' && c <= '\u04EB') ||
(c >= '\u04EE' && c <= '\u04F5') || (c >= '\u04F8' && c <= '\u04F9') || (c >= '\u0531' && c <= '\u0556') || (c >= '\u04EE' && c <= '\u04F5') || (c >= '\u04F8' && c <= '\u04F9') || (c >= '\u0531' && c <= '\u0556') ||
c == '\u0559' || (c >= '\u0561' && c <= '\u0586') || (c >= '\u05D0' && c <= '\u05EA') || (c >= '\u05F0' && c <= '\u05F2') || c == '\u0559' || (c >= '\u0561' && c <= '\u0586') || (c >= '\u05D0' && c <= '\u05EA') || (c >= '\u05F0' && c <= '\u05F2') ||
(c >= '\u0621' && c <= '\u063A') || (c >= '\u0641' && c <= '\u064A') || (c >= '\u0671' && c <= '\u06B7') || (c >= '\u0621' && c <= '\u063A') || (c >= '\u0641' && c <= '\u064A') || (c >= '\u0671' && c <= '\u06B7') ||
(c >= '\u06BA' && c <= '\u06BE') || (c >= '\u06C0' && c <= '\u06CE') || (c >= '\u06D0' && c <= '\u06D3') || (c >= '\u06BA' && c <= '\u06BE') || (c >= '\u06C0' && c <= '\u06CE') || (c >= '\u06D0' && c <= '\u06D3') ||
c == '\u06D5' || (c >= '\u06E5' && c <= '\u06E6') || (c >= '\u0905' && c <= '\u0939') || c == '\u093D' || c == '\u06D5' || (c >= '\u06E5' && c <= '\u06E6') || (c >= '\u0905' && c <= '\u0939') || c == '\u093D' ||
(c >= '\u0958' && c <= '\u0961') || (c >= '\u0985' && c <= '\u098C') || (c >= '\u098F' && c <= '\u0990') || (c >= '\u0958' && c <= '\u0961') || (c >= '\u0985' && c <= '\u098C') || (c >= '\u098F' && c <= '\u0990') ||
(c >= '\u0993' && c <= '\u09A8') || (c >= '\u09AA' && c <= '\u09B0') || c == '\u09B2' || (c >= '\u0993' && c <= '\u09A8') || (c >= '\u09AA' && c <= '\u09B0') || c == '\u09B2' ||
(c >= '\u09B6' && c <= '\u09B9') || (c >= '\u09DC' && c <= '\u09DD') || (c >= '\u09DF' && c <= '\u09E1') || (c >= '\u09B6' && c <= '\u09B9') || (c >= '\u09DC' && c <= '\u09DD') || (c >= '\u09DF' && c <= '\u09E1') ||
(c >= '\u09F0' && c <= '\u09F1') || (c >= '\u0A05' && c <= '\u0A0A') || (c >= '\u0A0F' && c <= '\u0A10') || (c >= '\u09F0' && c <= '\u09F1') || (c >= '\u0A05' && c <= '\u0A0A') || (c >= '\u0A0F' && c <= '\u0A10') ||
(c >= '\u0A13' && c <= '\u0A28') || (c >= '\u0A2A' && c <= '\u0A30') || (c >= '\u0A32' && c <= '\u0A33') || (c >= '\u0A13' && c <= '\u0A28') || (c >= '\u0A2A' && c <= '\u0A30') || (c >= '\u0A32' && c <= '\u0A33') ||
(c >= '\u0A35' && c <= '\u0A36') || (c >= '\u0A38' && c <= '\u0A39') || (c >= '\u0A59' && c <= '\u0A5C') || (c >= '\u0A35' && c <= '\u0A36') || (c >= '\u0A38' && c <= '\u0A39') || (c >= '\u0A59' && c <= '\u0A5C') ||
c == '\u0A5E' || (c >= '\u0A72' && c <= '\u0A74') || (c >= '\u0A85' && c <= '\u0A8B') || c == '\u0A8D' || c == '\u0A5E' || (c >= '\u0A72' && c <= '\u0A74') || (c >= '\u0A85' && c <= '\u0A8B') || c == '\u0A8D' ||
(c >= '\u0A8F' && c <= '\u0A91') || (c >= '\u0A93' && c <= '\u0AA8') || (c >= '\u0AAA' && c <= '\u0AB0') || (c >= '\u0A8F' && c <= '\u0A91') || (c >= '\u0A93' && c <= '\u0AA8') || (c >= '\u0AAA' && c <= '\u0AB0') ||
(c >= '\u0AB2' && c <= '\u0AB3') || (c >= '\u0AB5' && c <= '\u0AB9') || c == '\u0ABD' || c == '\u0AE0' || (c >= '\u0AB2' && c <= '\u0AB3') || (c >= '\u0AB5' && c <= '\u0AB9') || c == '\u0ABD' || c == '\u0AE0' ||
(c >= '\u0B05' && c <= '\u0B0C') || (c >= '\u0B0F' && c <= '\u0B10') || (c >= '\u0B13' && c <= '\u0B28') || (c >= '\u0B05' && c <= '\u0B0C') || (c >= '\u0B0F' && c <= '\u0B10') || (c >= '\u0B13' && c <= '\u0B28') ||
(c >= '\u0B2A' && c <= '\u0B30') || (c >= '\u0B32' && c <= '\u0B33') || (c >= '\u0B36' && c <= '\u0B39') || (c >= '\u0B2A' && c <= '\u0B30') || (c >= '\u0B32' && c <= '\u0B33') || (c >= '\u0B36' && c <= '\u0B39') ||
c == '\u0B3D' || (c >= '\u0B5C' && c <= '\u0B5D') || (c >= '\u0B5F' && c <= '\u0B61') || c == '\u0B3D' || (c >= '\u0B5C' && c <= '\u0B5D') || (c >= '\u0B5F' && c <= '\u0B61') ||
(c >= '\u0B85' && c <= '\u0B8A') || (c >= '\u0B8E' && c <= '\u0B90') || (c >= '\u0B92' && c <= '\u0B95') || (c >= '\u0B85' && c <= '\u0B8A') || (c >= '\u0B8E' && c <= '\u0B90') || (c >= '\u0B92' && c <= '\u0B95') ||
(c >= '\u0B99' && c <= '\u0B9A') || c == '\u0B9C' || (c >= '\u0B9E' && c <= '\u0B9F') || (c >= '\u0B99' && c <= '\u0B9A') || c == '\u0B9C' || (c >= '\u0B9E' && c <= '\u0B9F') ||
(c >= '\u0BA3' && c <= '\u0BA4') || (c >= '\u0BA8' && c <= '\u0BAA') || (c >= '\u0BAE' && c <= '\u0BB5') || (c >= '\u0BA3' && c <= '\u0BA4') || (c >= '\u0BA8' && c <= '\u0BAA') || (c >= '\u0BAE' && c <= '\u0BB5') ||
(c >= '\u0BB7' && c <= '\u0BB9') || (c >= '\u0C05' && c <= '\u0C0C') || (c >= '\u0C0E' && c <= '\u0C10') || (c >= '\u0BB7' && c <= '\u0BB9') || (c >= '\u0C05' && c <= '\u0C0C') || (c >= '\u0C0E' && c <= '\u0C10') ||
(c >= '\u0C12' && c <= '\u0C28') || (c >= '\u0C2A' && c <= '\u0C33') || (c >= '\u0C35' && c <= '\u0C39') || (c >= '\u0C12' && c <= '\u0C28') || (c >= '\u0C2A' && c <= '\u0C33') || (c >= '\u0C35' && c <= '\u0C39') ||
(c >= '\u0C60' && c <= '\u0C61') || (c >= '\u0C85' && c <= '\u0C8C') || (c >= '\u0C8E' && c <= '\u0C90') || (c >= '\u0C60' && c <= '\u0C61') || (c >= '\u0C85' && c <= '\u0C8C') || (c >= '\u0C8E' && c <= '\u0C90') ||
(c >= '\u0C92' && c <= '\u0CA8') || (c >= '\u0CAA' && c <= '\u0CB3') || (c >= '\u0CB5' && c <= '\u0CB9') || (c >= '\u0C92' && c <= '\u0CA8') || (c >= '\u0CAA' && c <= '\u0CB3') || (c >= '\u0CB5' && c <= '\u0CB9') ||
c == '\u0CDE' || (c >= '\u0CE0' && c <= '\u0CE1') || (c >= '\u0D05' && c <= '\u0D0C') || c == '\u0CDE' || (c >= '\u0CE0' && c <= '\u0CE1') || (c >= '\u0D05' && c <= '\u0D0C') ||
(c >= '\u0D0E' && c <= '\u0D10') || (c >= '\u0D12' && c <= '\u0D28') || (c >= '\u0D2A' && c <= '\u0D39') || (c >= '\u0D0E' && c <= '\u0D10') || (c >= '\u0D12' && c <= '\u0D28') || (c >= '\u0D2A' && c <= '\u0D39') ||
(c >= '\u0D60' && c <= '\u0D61') || (c >= '\u0E01' && c <= '\u0E2E') || c == '\u0E30' || (c >= '\u0D60' && c <= '\u0D61') || (c >= '\u0E01' && c <= '\u0E2E') || c == '\u0E30' ||
(c >= '\u0E32' && c <= '\u0E33') || (c >= '\u0E40' && c <= '\u0E45') || (c >= '\u0E81' && c <= '\u0E82') || (c >= '\u0E32' && c <= '\u0E33') || (c >= '\u0E40' && c <= '\u0E45') || (c >= '\u0E81' && c <= '\u0E82') ||
c == '\u0E84' || (c >= '\u0E87' && c <= '\u0E88') || c == '\u0E8A' || c == '\u0E8D' || (c >= '\u0E94' && c <= '\u0E97') || c == '\u0E84' || (c >= '\u0E87' && c <= '\u0E88') || c == '\u0E8A' || c == '\u0E8D' || (c >= '\u0E94' && c <= '\u0E97') ||
(c >= '\u0E99' && c <= '\u0E9F') || (c >= '\u0EA1' && c <= '\u0EA3') || c == '\u0EA5' || c == '\u0EA7' || (c >= '\u0E99' && c <= '\u0E9F') || (c >= '\u0EA1' && c <= '\u0EA3') || c == '\u0EA5' || c == '\u0EA7' ||
(c >= '\u0EAA' && c <= '\u0EAB') || (c >= '\u0EAD' && c <= '\u0EAE') || c == '\u0EB0' || (c >= '\u0EAA' && c <= '\u0EAB') || (c >= '\u0EAD' && c <= '\u0EAE') || c == '\u0EB0' ||
(c >= '\u0EB2' && c <= '\u0EB3') || c == '\u0EBD' || (c >= '\u0EC0' && c <= '\u0EC4') || (c >= '\u0EB2' && c <= '\u0EB3') || c == '\u0EBD' || (c >= '\u0EC0' && c <= '\u0EC4') ||
(c >= '\u0F40' && c <= '\u0F47') || (c >= '\u0F49' && c <= '\u0F69') || (c >= '\u10A0' && c <= '\u10C5') || (c >= '\u0F40' && c <= '\u0F47') || (c >= '\u0F49' && c <= '\u0F69') || (c >= '\u10A0' && c <= '\u10C5') ||
(c >= '\u10D0' && c <= '\u10F6') || c == '\u1100' || (c >= '\u1102' && c <= '\u1103') || (c >= '\u10D0' && c <= '\u10F6') || c == '\u1100' || (c >= '\u1102' && c <= '\u1103') ||
(c >= '\u1105' && c <= '\u1107') || c == '\u1109' || (c >= '\u110B' && c <= '\u110C') || (c >= '\u1105' && c <= '\u1107') || c == '\u1109' || (c >= '\u110B' && c <= '\u110C') ||
(c >= '\u110E' && c <= '\u1112') || c == '\u113C' || c == '\u113E' || c == '\u1140' || c == '\u114C' || (c >= '\u110E' && c <= '\u1112') || c == '\u113C' || c == '\u113E' || c == '\u1140' || c == '\u114C' ||
c == '\u114E' || c == '\u1150' || (c >= '\u1154' && c <= '\u1155') || c == '\u1159' || c == '\u114E' || c == '\u1150' || (c >= '\u1154' && c <= '\u1155') || c == '\u1159' ||
(c >= '\u115F' && c <= '\u1161') || c == '\u1163' || c == '\u1165' || c == '\u1167' || c == '\u1169' || (c >= '\u115F' && c <= '\u1161') || c == '\u1163' || c == '\u1165' || c == '\u1167' || c == '\u1169' ||
(c >= '\u116D' && c <= '\u116E') || (c >= '\u1172' && c <= '\u1173') || c == '\u1175' || (c >= '\u116D' && c <= '\u116E') || (c >= '\u1172' && c <= '\u1173') || c == '\u1175' ||
c == '\u119E' || c == '\u11A8' || c == '\u11AB' || (c >= '\u11AE' && c <= '\u11AF') || c == '\u119E' || c == '\u11A8' || c == '\u11AB' || (c >= '\u11AE' && c <= '\u11AF') ||
(c >= '\u11B7' && c <= '\u11B8') || c == '\u11BA' || (c >= '\u11BC' && c <= '\u11C2') || (c >= '\u11B7' && c <= '\u11B8') || c == '\u11BA' || (c >= '\u11BC' && c <= '\u11C2') ||
c == '\u11EB' || c == '\u11F0' || c == '\u11F9' || (c >= '\u1E00' && c <= '\u1E9B') || (c >= '\u1EA0' && c <= '\u1EF9') || c == '\u11EB' || c == '\u11F0' || c == '\u11F9' || (c >= '\u1E00' && c <= '\u1E9B') || (c >= '\u1EA0' && c <= '\u1EF9') ||
(c >= '\u1F00' && c <= '\u1F15') || (c >= '\u1F18' && c <= '\u1F1D') || (c >= '\u1F20' && c <= '\u1F45') || (c >= '\u1F00' && c <= '\u1F15') || (c >= '\u1F18' && c <= '\u1F1D') || (c >= '\u1F20' && c <= '\u1F45') ||
(c >= '\u1F48' && c <= '\u1F4D') || (c >= '\u1F50' && c <= '\u1F57') || c == '\u1F59' || c == '\u1F5B' || c == '\u1F5D' || (c >= '\u1F48' && c <= '\u1F4D') || (c >= '\u1F50' && c <= '\u1F57') || c == '\u1F59' || c == '\u1F5B' || c == '\u1F5D' ||
(c >= '\u1F5F' && c <= '\u1F7D') || (c >= '\u1F80' && c <= '\u1FB4') || (c >= '\u1FB6' && c <= '\u1FBC') || (c >= '\u1F5F' && c <= '\u1F7D') || (c >= '\u1F80' && c <= '\u1FB4') || (c >= '\u1FB6' && c <= '\u1FBC') ||
c == '\u1FBE' || (c >= '\u1FC2' && c <= '\u1FC4') || (c >= '\u1FC6' && c <= '\u1FCC') || c == '\u1FBE' || (c >= '\u1FC2' && c <= '\u1FC4') || (c >= '\u1FC6' && c <= '\u1FCC') ||
(c >= '\u1FD0' && c <= '\u1FD3') || (c >= '\u1FD6' && c <= '\u1FDB') || (c >= '\u1FE0' && c <= '\u1FEC') || (c >= '\u1FD0' && c <= '\u1FD3') || (c >= '\u1FD6' && c <= '\u1FDB') || (c >= '\u1FE0' && c <= '\u1FEC') ||
(c >= '\u1FF2' && c <= '\u1FF4') || (c >= '\u1FF6' && c <= '\u1FFC') || c == '\u2126' || (c >= '\u1FF2' && c <= '\u1FF4') || (c >= '\u1FF6' && c <= '\u1FFC') || c == '\u2126' ||
(c >= '\u212A' && c <= '\u212B') || c == '\u212E' || (c >= '\u2180' && c <= '\u2182') || (c >= '\u212A' && c <= '\u212B') || c == '\u212E' || (c >= '\u2180' && c <= '\u2182') ||
(c >= '\u3041' && c <= '\u3094') || (c >= '\u30A1' && c <= '\u30FA') || (c >= '\u3105' && c <= '\u312C') || (c >= '\u3041' && c <= '\u3094') || (c >= '\u30A1' && c <= '\u30FA') || (c >= '\u3105' && c <= '\u312C') ||
(c >= '\uAC00' && c <= '\uD7A3'); (c >= '\uAC00' && c <= '\uD7A3');
} }
private static boolean isIdeographic(char c) { private static boolean isIdeographic(char c) {
return (c >= '\u4E00' && c <= '\u9FA5') || c == '\u3007' || (c >= '\u3021' && c <= '\u3029'); return (c >= '\u4E00' && c <= '\u9FA5') || c == '\u3007' || (c >= '\u3021' && c <= '\u3029');
} }
public static String determineEncoding(InputStream stream) throws IOException { public static String determineEncoding(InputStream stream) throws IOException {
stream.mark(20000); stream.mark(20000);
try { try {
int b0 = stream.read(); int b0 = stream.read();
int b1 = stream.read(); int b1 = stream.read();
int b2 = stream.read(); int b2 = stream.read();
int b3 = stream.read(); int b3 = stream.read();
if (b0 == 0xFE && b1 == 0xFF) if (b0 == 0xFE && b1 == 0xFF)
return "UTF-16BE"; return "UTF-16BE";
else if (b0 == 0xFF && b1 == 0xFE) else if (b0 == 0xFF && b1 == 0xFE)
return "UTF-16LE"; return "UTF-16LE";
else if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF ) else if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF )
return "UTF-8"; return "UTF-8";
else if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) else if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F)
return "UTF-16BE"; return "UTF-16BE";
else if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) else if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00)
return "UTF-16LE"; return "UTF-16LE";
else if (b0 == 0x3C && b1 == 0x3F && b2 == 0x78 && b3 == 0x6D) { else if (b0 == 0x3C && b1 == 0x3F && b2 == 0x78 && b3 == 0x6D) {
// UTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC, or any other 7-bit, 8-bit, or mixed-width encoding // UTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC, or any other 7-bit, 8-bit, or mixed-width encoding
// which ensures that the characters of ASCII have their normal positions, width, and values; the actual encoding // which ensures that the characters of ASCII have their normal positions, width, and values; the actual encoding
// declaration must be read to detect which of these applies, but since all of these encodings use the same bit patterns // declaration must be read to detect which of these applies, but since all of these encodings use the same bit patterns
// for the relevant ASCII characters, the encoding declaration itself may be read reliably // for the relevant ASCII characters, the encoding declaration itself may be read reliably
InputStreamReader rdr = new InputStreamReader(stream, "US-ASCII"); InputStreamReader rdr = new InputStreamReader(stream, "US-ASCII");
String hdr = readFirstLine(rdr); String hdr = readFirstLine(rdr);
return extractEncoding(hdr); return extractEncoding(hdr);
} else } else
return null; return null;
} finally { } finally {
stream.reset(); stream.reset();
} }
} }
private static String extractEncoding(String hdr) { private static String extractEncoding(String hdr) {
int i = hdr.indexOf("encoding="); int i = hdr.indexOf("encoding=");
if (i == -1) if (i == -1)
return null; return null;
hdr = hdr.substring(i+9); hdr = hdr.substring(i+9);
char sep = hdr.charAt(0); char sep = hdr.charAt(0);
hdr = hdr.substring(1); hdr = hdr.substring(1);
i = hdr.indexOf(sep); i = hdr.indexOf(sep);
if (i == -1) if (i == -1)
return null; return null;
return hdr.substring(0, i); return hdr.substring(0, i);
} }
private static String readFirstLine(InputStreamReader rdr) throws IOException { private static String readFirstLine(InputStreamReader rdr) throws IOException {
char[] buf = new char[1]; char[] buf = new char[1];
StringBuffer bldr = new StringBuffer(); StringBuffer bldr = new StringBuffer();
rdr.read(buf); rdr.read(buf);
while (buf[0] != '>') { while (buf[0] != '>') {
bldr.append(buf[0]); bldr.append(buf[0]);
rdr.read(buf); rdr.read(buf);
} }
return bldr.toString(); return bldr.toString();
} }
public static boolean charSetImpliesAscii(String charset) { public static boolean charSetImpliesAscii(String charset) {
return charset.equals("ISO-8859-1") || charset.equals("US-ASCII"); return charset.equals("ISO-8859-1") || charset.equals("US-ASCII");
} }
/** /**
* Converts the raw characters to XML escape characters. * Converts the raw characters to XML escapeUrlParam characters.
* *
* @param rawContent * @param rawContent
* @param charset Null when charset is not known, so we assume it's unicode * @param charset Null when charset is not known, so we assume it's unicode
* @param isNoLines * @param isNoLines
* @return escape string * @return escapeUrlParam string
*/ */
public static String escapeXML(String rawContent, String charset, boolean isNoLines) { public static String escapeXML(String rawContent, String charset, boolean isNoLines) {
if (rawContent == null) if (rawContent == null)
return ""; return "";
else { else {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
for (int i = 0; i < rawContent.length(); i++) { for (int i = 0; i < rawContent.length(); i++) {
char ch = rawContent.charAt(i); char ch = rawContent.charAt(i);
if (ch == '\'') if (ch == '\'')
sb.append("&#39;"); sb.append("&#39;");
else if (ch == '&') else if (ch == '&')
sb.append("&amp;"); sb.append("&amp;");
else if (ch == '"') else if (ch == '"')
sb.append("&quot;"); sb.append("&quot;");
else if (ch == '<') else if (ch == '<')
sb.append("&lt;"); sb.append("&lt;");
else if (ch == '>') else if (ch == '>')
sb.append("&gt;"); sb.append("&gt;");
else if (ch > '~' && charset != null && charSetImpliesAscii(charset)) else if (ch > '~' && charset != null && charSetImpliesAscii(charset))
// TODO - why is hashcode the only way to get the unicode number for the character // TODO - why is hashcode the only way to get the unicode number for the character
// in jre 5.0? // in jre 5.0?
sb.append("&#x"+Integer.toHexString(new Character(ch).hashCode()).toUpperCase()+";"); sb.append("&#x"+Integer.toHexString(new Character(ch).hashCode()).toUpperCase()+";");
else if (isNoLines) { else if (isNoLines) {
if (ch == '\r') if (ch == '\r')
sb.append("&#xA;"); sb.append("&#xA;");
else if (ch != '\n') else if (ch != '\n')
sb.append(ch); sb.append(ch);
} }
else else
sb.append(ch); sb.append(ch);
} }
return sb.toString(); return sb.toString();
} }
} }
public static Element getFirstChild(Element e) { public static Element getFirstChild(Element e) {
if (e == null) if (e == null)
return null; return null;
Node n = e.getFirstChild(); Node n = e.getFirstChild();
while (n != null && n.getNodeType() != Node.ELEMENT_NODE) while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
n = n.getNextSibling(); n = n.getNextSibling();
return (Element) n; return (Element) n;
} }
public static Element getNamedChild(Element e, String name) { public static Element getNamedChild(Element e, String name) {
Element c = getFirstChild(e); Element c = getFirstChild(e);
while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName())) while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
c = getNextSibling(c); c = getNextSibling(c);
return c; return c;
} }
public static Element getNextSibling(Element e) { public static Element getNextSibling(Element e) {
Node n = e.getNextSibling(); Node n = e.getNextSibling();
while (n != null && n.getNodeType() != Node.ELEMENT_NODE) while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
n = n.getNextSibling(); n = n.getNextSibling();
return (Element) n; return (Element) n;
} }
public static void getNamedChildren(Element e, String name, List<Element> set) { public static void getNamedChildren(Element e, String name, List<Element> set) {
Element c = getFirstChild(e); Element c = getFirstChild(e);
while (c != null) { while (c != null) {
if (name.equals(c.getLocalName()) || name.equals(c.getNodeName()) ) if (name.equals(c.getLocalName()) || name.equals(c.getNodeName()) )
set.add(c); set.add(c);
c = getNextSibling(c); c = getNextSibling(c);
} }
} }
public static String htmlToXmlEscapedPlainText(Element r) { public static String htmlToXmlEscapedPlainText(Element r) {
StringBuilder s = new StringBuilder(); StringBuilder s = new StringBuilder();
Node n = r.getFirstChild(); Node n = r.getFirstChild();
boolean ws = false; boolean ws = false;
while (n != null) { while (n != null) {
if (n.getNodeType() == Node.TEXT_NODE) { if (n.getNodeType() == Node.TEXT_NODE) {
String t = n.getTextContent().trim(); String t = n.getTextContent().trim();
if (Utilities.noString(t)) if (Utilities.noString(t))
ws = true; ws = true;
else { else {
if (ws) if (ws)
s.append(" "); s.append(" ");
ws = false; ws = false;
s.append(t); s.append(t);
} }
} }
if (n.getNodeType() == Node.ELEMENT_NODE) { if (n.getNodeType() == Node.ELEMENT_NODE) {
if (ws) if (ws)
s.append(" "); s.append(" ");
ws = false; ws = false;
s.append(htmlToXmlEscapedPlainText((Element) n)); s.append(htmlToXmlEscapedPlainText((Element) n));
if (r.getNodeName().equals("br") || r.getNodeName().equals("p")) if (r.getNodeName().equals("br") || r.getNodeName().equals("p"))
s.append("\r\n"); s.append("\r\n");
} }
n = n.getNextSibling(); n = n.getNextSibling();
} }
return s.toString(); return s.toString();
} }
public static String htmlToXmlEscapedPlainText(String definition) throws Exception { public static String htmlToXmlEscapedPlainText(String definition) throws Exception {
return htmlToXmlEscapedPlainText(parseToDom("<div>"+definition+"</div>").getDocumentElement()); return htmlToXmlEscapedPlainText(parseToDom("<div>"+definition+"</div>").getDocumentElement());
} }
public static String elementToString(Element el) { public static String elementToString(Element el) {
if (el == null) if (el == null)
return ""; return "";
Document document = el.getOwnerDocument(); Document document = el.getOwnerDocument();
DOMImplementationLS domImplLS = (DOMImplementationLS) document DOMImplementationLS domImplLS = (DOMImplementationLS) document
.getImplementation(); .getImplementation();
LSSerializer serializer = domImplLS.createLSSerializer(); LSSerializer serializer = domImplLS.createLSSerializer();
return serializer.writeToString(el); return serializer.writeToString(el);
} }
public static String getNamedChildValue(Element element, String name) { public static String getNamedChildValue(Element element, String name) {
Element e = getNamedChild(element, name); Element e = getNamedChild(element, name);
return e == null ? null : e.getAttribute("value"); return e == null ? null : e.getAttribute("value");
} }
public static void getNamedChildrenWithWildcard(Element focus, String name, List<Element> children) { public static void getNamedChildrenWithWildcard(Element focus, String name, List<Element> children) {
Element c = getFirstChild(focus); Element c = getFirstChild(focus);
while (c != null) { while (c != null) {
String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName(); String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName();
if (name.equals(n) || (name.endsWith("[x]") && n.startsWith(name.substring(0, name.length()-3)))) if (name.equals(n) || (name.endsWith("[x]") && n.startsWith(name.substring(0, name.length()-3))))
children.add(c); children.add(c);
c = getNextSibling(c); c = getNextSibling(c);
} }
} }
public static boolean hasNamedChild(Element e, String name) { public static boolean hasNamedChild(Element e, String name) {
Element c = getFirstChild(e); Element c = getFirstChild(e);
while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName())) while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
c = getNextSibling(c); c = getNextSibling(c);
return c != null; return c != null;
} }
public static Document parseToDom(String content) throws Exception { public static Document parseToDom(String content) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false); factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder(); DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(content.getBytes())); return builder.parse(new ByteArrayInputStream(content.getBytes()));
} }
public static Element getLastChild(Element e) { public static Element getLastChild(Element e) {
if (e == null) if (e == null)
return null; return null;
Node n = e.getLastChild(); Node n = e.getLastChild();
while (n != null && n.getNodeType() != Node.ELEMENT_NODE) while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
n = n.getPreviousSibling(); n = n.getPreviousSibling();
return (Element) n; return (Element) n;
} }
public static Element getPrevSibling(Element e) { public static Element getPrevSibling(Element e) {
Node n = e.getPreviousSibling(); Node n = e.getPreviousSibling();
while (n != null && n.getNodeType() != Node.ELEMENT_NODE) while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
n = n.getPreviousSibling(); n = n.getPreviousSibling();
return (Element) n; return (Element) n;
} }
} }

View File

@ -1,493 +1,493 @@
package org.hl7.fhir.r4.elementmodel; package org.hl7.fhir.r4.elementmodel;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import org.hl7.fhir.r4.context.IWorkerContext; import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.formats.IParser.OutputStyle; import org.hl7.fhir.r4.formats.IParser.OutputStyle;
import org.hl7.fhir.r4.model.StructureDefinition; import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
/** /**
* This class provides special support for parsing v2 by the v2 logical model * This class provides special support for parsing v2 by the v2 logical model
* For the logical model, see the FHIRPath spec * For the logical model, see the FHIRPath spec
* *
* @author Grahame Grieve * @author Grahame Grieve
* *
*/ */
public class VerticalBarParser extends ParserBase { public class VerticalBarParser extends ParserBase {
/** /**
* Delimiters for a message. Note that the application rarely needs to concern * Delimiters for a message. Note that the application rarely needs to concern
* itself with this information; it mainly exists for internal use. However if * itself with this information; it mainly exists for internal use. However if
* a message is being written to a spec that calls for non-standard delimiters, * a message is being written to a spec that calls for non-standard delimiters,
* the application can set them here. * the application can set them here.
* *
* @author Grahame * @author Grahame
* *
*/ */
public class Delimiters { public class Delimiters {
/** /**
* Hl7 defined default delimiter for a field * Hl7 defined default delimiter for a field
*/ */
public final static char DEFAULT_DELIMITER_FIELD = '|'; public final static char DEFAULT_DELIMITER_FIELD = '|';
/** /**
* Hl7 defined default delimiter for a component * Hl7 defined default delimiter for a component
*/ */
public final static char DEFAULT_DELIMITER_COMPONENT = '^'; public final static char DEFAULT_DELIMITER_COMPONENT = '^';
/** /**
* Hl7 defined default delimiter for a subcomponent * Hl7 defined default delimiter for a subcomponent
*/ */
public final static char DEFAULT_DELIMITER_SUBCOMPONENT = '&'; public final static char DEFAULT_DELIMITER_SUBCOMPONENT = '&';
/** /**
* Hl7 defined default delimiter for a repeat * Hl7 defined default delimiter for a repeat
*/ */
public final static char DEFAULT_DELIMITER_REPETITION = '~'; public final static char DEFAULT_DELIMITER_REPETITION = '~';
/** /**
* Hl7 defined default delimiter for an escape * Hl7 defined default delimiter for an escapeUrlParam
*/ */
public final static char DEFAULT_CHARACTER_ESCAPE = '\\'; public final static char DEFAULT_CHARACTER_ESCAPE = '\\';
/** /**
* defined escape character for this message * defined escapeUrlParam character for this message
*/ */
private char escapeCharacter; private char escapeCharacter;
/** /**
* defined repetition character for this message * defined repetition character for this message
*/ */
private char repetitionDelimiter; private char repetitionDelimiter;
/** /**
* defined field character for this message * defined field character for this message
*/ */
private char fieldDelimiter; private char fieldDelimiter;
/** /**
* defined subComponent character for this message * defined subComponent character for this message
*/ */
private char subComponentDelimiter; private char subComponentDelimiter;
/** /**
* defined component character for this message * defined component character for this message
*/ */
private char componentDelimiter; private char componentDelimiter;
/** /**
* create * create
* *
*/ */
public Delimiters() { public Delimiters() {
super(); super();
reset(); reset();
} }
public boolean matches(Delimiters other) { public boolean matches(Delimiters other) {
return escapeCharacter == other.escapeCharacter && return escapeCharacter == other.escapeCharacter &&
repetitionDelimiter == other.repetitionDelimiter && repetitionDelimiter == other.repetitionDelimiter &&
fieldDelimiter == other.fieldDelimiter && fieldDelimiter == other.fieldDelimiter &&
subComponentDelimiter == other.subComponentDelimiter && subComponentDelimiter == other.subComponentDelimiter &&
componentDelimiter == other.componentDelimiter; componentDelimiter == other.componentDelimiter;
} }
/** /**
* get defined component character for this message * get defined component character for this message
* @return * @return
*/ */
public char getComponentDelimiter() { public char getComponentDelimiter() {
return componentDelimiter; return componentDelimiter;
} }
/** /**
* set defined component character for this message * set defined component character for this message
* @param componentDelimiter * @param componentDelimiter
*/ */
public void setComponentDelimiter(char componentDelimiter) { public void setComponentDelimiter(char componentDelimiter) {
this.componentDelimiter = componentDelimiter; this.componentDelimiter = componentDelimiter;
} }
/** /**
* get defined escape character for this message * get defined escapeUrlParam character for this message
* @return * @return
*/ */
public char getEscapeCharacter() { public char getEscapeCharacter() {
return escapeCharacter; return escapeCharacter;
} }
/** /**
* set defined escape character for this message * set defined escapeUrlParam character for this message
* @param escapeCharacter * @param escapeCharacter
*/ */
public void setEscapeCharacter(char escapeCharacter) { public void setEscapeCharacter(char escapeCharacter) {
this.escapeCharacter = escapeCharacter; this.escapeCharacter = escapeCharacter;
} }
/** /**
* get defined field character for this message * get defined field character for this message
* @return * @return
*/ */
public char getFieldDelimiter() { public char getFieldDelimiter() {
return fieldDelimiter; return fieldDelimiter;
} }
/** /**
* set defined field character for this message * set defined field character for this message
* @param fieldDelimiter * @param fieldDelimiter
*/ */
public void setFieldDelimiter(char fieldDelimiter) { public void setFieldDelimiter(char fieldDelimiter) {
this.fieldDelimiter = fieldDelimiter; this.fieldDelimiter = fieldDelimiter;
} }
/** /**
* get repeat field character for this message * get repeat field character for this message
* @return * @return
*/ */
public char getRepetitionDelimiter() { public char getRepetitionDelimiter() {
return repetitionDelimiter; return repetitionDelimiter;
} }
/** /**
* set repeat field character for this message * set repeat field character for this message
* @param repetitionDelimiter * @param repetitionDelimiter
*/ */
public void setRepetitionDelimiter(char repetitionDelimiter) { public void setRepetitionDelimiter(char repetitionDelimiter) {
this.repetitionDelimiter = repetitionDelimiter; this.repetitionDelimiter = repetitionDelimiter;
} }
/** /**
* get sub-component field character for this message * get sub-component field character for this message
* @return * @return
*/ */
public char getSubComponentDelimiter() { public char getSubComponentDelimiter() {
return subComponentDelimiter; return subComponentDelimiter;
} }
/** /**
* set sub-component field character for this message * set sub-component field character for this message
* @param subComponentDelimiter * @param subComponentDelimiter
*/ */
public void setSubComponentDelimiter(char subComponentDelimiter) { public void setSubComponentDelimiter(char subComponentDelimiter) {
this.subComponentDelimiter = subComponentDelimiter; this.subComponentDelimiter = subComponentDelimiter;
} }
/** /**
* reset to default HL7 values * reset to default HL7 values
* *
*/ */
public void reset () { public void reset () {
fieldDelimiter = DEFAULT_DELIMITER_FIELD; fieldDelimiter = DEFAULT_DELIMITER_FIELD;
componentDelimiter = DEFAULT_DELIMITER_COMPONENT; componentDelimiter = DEFAULT_DELIMITER_COMPONENT;
subComponentDelimiter = DEFAULT_DELIMITER_SUBCOMPONENT; subComponentDelimiter = DEFAULT_DELIMITER_SUBCOMPONENT;
repetitionDelimiter = DEFAULT_DELIMITER_REPETITION; repetitionDelimiter = DEFAULT_DELIMITER_REPETITION;
escapeCharacter = DEFAULT_CHARACTER_ESCAPE; escapeCharacter = DEFAULT_CHARACTER_ESCAPE;
} }
/** /**
* check that the delimiters are valid * check that the delimiters are valid
* *
* @throws FHIRException * @throws FHIRException
*/ */
public void check() throws FHIRException { public void check() throws FHIRException {
rule(componentDelimiter != fieldDelimiter, "Delimiter Error: \""+componentDelimiter+"\" is used for both CPComponent and CPField"); rule(componentDelimiter != fieldDelimiter, "Delimiter Error: \""+componentDelimiter+"\" is used for both CPComponent and CPField");
rule(subComponentDelimiter != fieldDelimiter, "Delimiter Error: \""+subComponentDelimiter+"\" is used for both CPSubComponent and CPField"); rule(subComponentDelimiter != fieldDelimiter, "Delimiter Error: \""+subComponentDelimiter+"\" is used for both CPSubComponent and CPField");
rule(subComponentDelimiter != componentDelimiter, "Delimiter Error: \""+subComponentDelimiter+"\" is used for both CPSubComponent and CPComponent"); rule(subComponentDelimiter != componentDelimiter, "Delimiter Error: \""+subComponentDelimiter+"\" is used for both CPSubComponent and CPComponent");
rule(repetitionDelimiter != fieldDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPField"); rule(repetitionDelimiter != fieldDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPField");
rule(repetitionDelimiter != componentDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPComponent"); rule(repetitionDelimiter != componentDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPComponent");
rule(repetitionDelimiter != subComponentDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPSubComponent"); rule(repetitionDelimiter != subComponentDelimiter, "Delimiter Error: \""+repetitionDelimiter+"\" is used for both Repetition and CPSubComponent");
rule(escapeCharacter != fieldDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPField"); rule(escapeCharacter != fieldDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPField");
rule(escapeCharacter != componentDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPComponent"); rule(escapeCharacter != componentDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPComponent");
rule(escapeCharacter != subComponentDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPSubComponent"); rule(escapeCharacter != subComponentDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and CPSubComponent");
rule(escapeCharacter != repetitionDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and Repetition"); rule(escapeCharacter != repetitionDelimiter, "Delimiter Error: \""+escapeCharacter+"\" is used for both Escape and Repetition");
} }
/** /**
* check to see whether ch is a delimiter character (vertical bar parser support) * check to see whether ch is a delimiter character (vertical bar parser support)
* @param ch * @param ch
* @return * @return
*/ */
public boolean isDelimiter(char ch) { public boolean isDelimiter(char ch) {
return ch == escapeCharacter || ch == repetitionDelimiter || ch == fieldDelimiter || ch == subComponentDelimiter || ch == componentDelimiter; return ch == escapeCharacter || ch == repetitionDelimiter || ch == fieldDelimiter || ch == subComponentDelimiter || ch == componentDelimiter;
} }
/** /**
* check to see whether ch is a cell delimiter char (vertical bar parser support) * check to see whether ch is a cell delimiter char (vertical bar parser support)
* @param ch * @param ch
* @return * @return
*/ */
public boolean isCellDelimiter(char ch) { public boolean isCellDelimiter(char ch) {
return ch == repetitionDelimiter || ch == fieldDelimiter || ch == subComponentDelimiter || ch == componentDelimiter; return ch == repetitionDelimiter || ch == fieldDelimiter || ch == subComponentDelimiter || ch == componentDelimiter;
} }
/** /**
* get the escape for a character * get the escapeUrlParam for a character
* @param ch * @param ch
* @return * @return
*/ */
public String getEscape(char ch) { public String getEscape(char ch) {
if (ch == escapeCharacter) if (ch == escapeCharacter)
return escapeCharacter + "E" + escapeCharacter; return escapeCharacter + "E" + escapeCharacter;
else if (ch == fieldDelimiter) else if (ch == fieldDelimiter)
return escapeCharacter + "F" + escapeCharacter; return escapeCharacter + "F" + escapeCharacter;
else if (ch == componentDelimiter) else if (ch == componentDelimiter)
return escapeCharacter + "S" + escapeCharacter; return escapeCharacter + "S" + escapeCharacter;
else if (ch == subComponentDelimiter) else if (ch == subComponentDelimiter)
return escapeCharacter + "T" + escapeCharacter; return escapeCharacter + "T" + escapeCharacter;
else if (ch == repetitionDelimiter) else if (ch == repetitionDelimiter)
return escapeCharacter + "R" + escapeCharacter; return escapeCharacter + "R" + escapeCharacter;
else else
return null; return null;
} }
/** /**
* build the MSH-2 content * build the MSH-2 content
* @return * @return
*/ */
public String forMSH2() { public String forMSH2() {
return "" + componentDelimiter + repetitionDelimiter + escapeCharacter + subComponentDelimiter; return "" + componentDelimiter + repetitionDelimiter + escapeCharacter + subComponentDelimiter;
} }
/** /**
* check to see whether ch represents a delimiter escape * check to see whether ch represents a delimiter escapeUrlParam
* @param ch * @param ch
* @return * @return
*/ */
public boolean isDelimiterEscape(char ch) { public boolean isDelimiterEscape(char ch) {
return ch == 'F' || ch == 'S' || ch == 'E' || ch == 'T' || ch == 'R'; return ch == 'F' || ch == 'S' || ch == 'E' || ch == 'T' || ch == 'R';
} }
/** /**
* get escape for ch in an escape * get escapeUrlParam for ch in an escapeUrlParam
* @param ch * @param ch
* @return * @return
* @throws DefinitionException * @throws DefinitionException
* @throws FHIRException * @throws FHIRException
*/ */
public char getDelimiterEscapeChar(char ch) throws DefinitionException { public char getDelimiterEscapeChar(char ch) throws DefinitionException {
if (ch == 'E') if (ch == 'E')
return escapeCharacter; return escapeCharacter;
else if (ch == 'F') else if (ch == 'F')
return fieldDelimiter; return fieldDelimiter;
else if (ch == 'S') else if (ch == 'S')
return componentDelimiter; return componentDelimiter;
else if (ch == 'T') else if (ch == 'T')
return subComponentDelimiter; return subComponentDelimiter;
else if (ch == 'R') else if (ch == 'R')
return repetitionDelimiter; return repetitionDelimiter;
else else
throw new DefinitionException("internal error in getDelimiterEscapeChar"); throw new DefinitionException("internal error in getDelimiterEscapeChar");
} }
} }
public class VerticalBarParserReader { public class VerticalBarParserReader {
private BufferedInputStream stream; private BufferedInputStream stream;
private String charsetName; private String charsetName;
private InputStreamReader reader = null; private InputStreamReader reader = null;
private boolean finished; private boolean finished;
private char peeked; private char peeked;
private char lastValue; private char lastValue;
private int offset; private int offset;
private int lineNumber; private int lineNumber;
public VerticalBarParserReader(BufferedInputStream stream, String charsetName) throws FHIRException { public VerticalBarParserReader(BufferedInputStream stream, String charsetName) throws FHIRException {
super(); super();
setStream(stream); setStream(stream);
setCharsetName(charsetName); setCharsetName(charsetName);
open(); open();
} }
public String getCharsetName() { public String getCharsetName() {
return charsetName; return charsetName;
} }
public void setCharsetName(String charsetName) { public void setCharsetName(String charsetName) {
this.charsetName = charsetName; this.charsetName = charsetName;
} }
public BufferedInputStream getStream() { public BufferedInputStream getStream() {
return stream; return stream;
} }
public void setStream(BufferedInputStream stream) { public void setStream(BufferedInputStream stream) {
this.stream = stream; this.stream = stream;
} }
private void open() throws FHIRException { private void open() throws FHIRException {
try { try {
stream.mark(2048); stream.mark(2048);
reader = new InputStreamReader(stream, charsetName); reader = new InputStreamReader(stream, charsetName);
offset = 0; offset = 0;
lineNumber = 0; lineNumber = 0;
lastValue = ' '; lastValue = ' ';
next(); next();
} catch (Exception e) { } catch (Exception e) {
throw new FHIRException(e); throw new FHIRException(e);
} }
} }
private void next() throws IOException, FHIRException { private void next() throws IOException, FHIRException {
finished = !reader.ready(); finished = !reader.ready();
if (!finished) { if (!finished) {
char[] temp = new char[1]; char[] temp = new char[1];
rule(reader.read(temp, 0, 1) == 1, "unable to read 1 character from the stream"); rule(reader.read(temp, 0, 1) == 1, "unable to read 1 character from the stream");
peeked = temp[0]; peeked = temp[0];
} }
} }
public String read(int charCount) throws FHIRException { public String read(int charCount) throws FHIRException {
String value = ""; String value = "";
for (int i = 0; i < charCount; i++) for (int i = 0; i < charCount; i++)
value = value + read(); value = value + read();
return value; return value;
} }
public void skipEOL () throws FHIRException { public void skipEOL () throws FHIRException {
while (!finished && (peek() == '\r' || peek() == '\n')) while (!finished && (peek() == '\r' || peek() == '\n'))
read(); read();
} }
public char read () throws FHIRException { public char read () throws FHIRException {
rule(!finished, "No more content to read"); rule(!finished, "No more content to read");
char value = peek(); char value = peek();
offset++; offset++;
if (value == '\r' || value == '\n') { if (value == '\r' || value == '\n') {
if (lastValue != '\r' || value != '\n') if (lastValue != '\r' || value != '\n')
lineNumber++; lineNumber++;
} }
lastValue = value; lastValue = value;
try { try {
next(); next();
} catch (Exception e) { } catch (Exception e) {
throw new FHIRException(e); throw new FHIRException(e);
} }
return value; return value;
} }
public boolean isFinished () { public boolean isFinished () {
return finished; return finished;
} }
public char peek() throws FHIRException { public char peek() throws FHIRException {
rule(!finished, "Cannot peek"); rule(!finished, "Cannot peek");
return peeked; return peeked;
} }
public void mark() { public void mark() {
stream.mark(2048); stream.mark(2048);
} }
public void reset() throws FHIRException { public void reset() throws FHIRException {
try { try {
stream.reset(); stream.reset();
} catch (IOException e) { } catch (IOException e) {
throw new FHIRException(e); throw new FHIRException(e);
} }
open(); open();
} }
public boolean IsEOL() throws FHIRException { public boolean IsEOL() throws FHIRException {
return peek() == '\r' || peek() == '\n'; return peek() == '\r' || peek() == '\n';
} }
public int getLineNumber() { public int getLineNumber() {
return lineNumber; return lineNumber;
} }
public int getOffset() { public int getOffset() {
return offset; return offset;
} }
} }
public VerticalBarParser(IWorkerContext context) { public VerticalBarParser(IWorkerContext context) {
super(context); super(context);
} }
private String charset = "ASCII"; private String charset = "ASCII";
private Delimiters delimiters = new Delimiters(); private Delimiters delimiters = new Delimiters();
@Override @Override
public Element parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { public Element parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException {
StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/v2/StructureDefinition/Message"); StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/v2/StructureDefinition/Message");
Element message = new Element("Message", new Property(context, sd.getSnapshot().getElementFirstRep(), sd)); Element message = new Element("Message", new Property(context, sd.getSnapshot().getElementFirstRep(), sd));
VerticalBarParserReader reader = new VerticalBarParserReader(new BufferedInputStream(stream), charset); VerticalBarParserReader reader = new VerticalBarParserReader(new BufferedInputStream(stream), charset);
preDecode(reader); preDecode(reader);
while (!reader.isFinished()) // && (getOptions().getSegmentLimit() == 0 || getOptions().getSegmentLimit() > message.getSegments().size())) while (!reader.isFinished()) // && (getOptions().getSegmentLimit() == 0 || getOptions().getSegmentLimit() > message.getSegments().size()))
readSegment(message, reader); readSegment(message, reader);
return message; return message;
} }
private void preDecode(VerticalBarParserReader reader) throws FHIRException { private void preDecode(VerticalBarParserReader reader) throws FHIRException {
reader.skipEOL(); reader.skipEOL();
String temp = reader.read(3); String temp = reader.read(3);
rule(temp.equals("MSH") || temp.equals("FHS"), "Found '" + temp + "' looking for 'MSH' or 'FHS'"); rule(temp.equals("MSH") || temp.equals("FHS"), "Found '" + temp + "' looking for 'MSH' or 'FHS'");
readDelimiters(reader); readDelimiters(reader);
// readVersion(message); - probably don't need to do that? // readVersion(message); - probably don't need to do that?
// readCharacterSet(); // readCharacterSet();
reader.reset(); // ready to read message now reader.reset(); // ready to read message now
} }
private void rule(boolean test, String msg) throws FHIRException { private void rule(boolean test, String msg) throws FHIRException {
if (!test) if (!test)
throw new FHIRException(msg); throw new FHIRException(msg);
} }
private void readDelimiters(VerticalBarParserReader reader) throws FHIRException { private void readDelimiters(VerticalBarParserReader reader) throws FHIRException {
delimiters.setFieldDelimiter(reader.read()); delimiters.setFieldDelimiter(reader.read());
if (!(reader.peek() == delimiters.getFieldDelimiter())) if (!(reader.peek() == delimiters.getFieldDelimiter()))
delimiters.setComponentDelimiter(reader.read()); delimiters.setComponentDelimiter(reader.read());
if (!(reader.peek() == delimiters.getFieldDelimiter())) if (!(reader.peek() == delimiters.getFieldDelimiter()))
delimiters.setRepetitionDelimiter(reader.read()); delimiters.setRepetitionDelimiter(reader.read());
if (!(reader.peek() == delimiters.getFieldDelimiter())) if (!(reader.peek() == delimiters.getFieldDelimiter()))
delimiters.setEscapeCharacter(reader.read()); delimiters.setEscapeCharacter(reader.read());
if (!(reader.peek() == delimiters.getFieldDelimiter())) if (!(reader.peek() == delimiters.getFieldDelimiter()))
delimiters.setSubComponentDelimiter(reader.read()); delimiters.setSubComponentDelimiter(reader.read());
delimiters.check(); delimiters.check();
} }
private void readSegment(Element message, VerticalBarParserReader reader) throws FHIRException { private void readSegment(Element message, VerticalBarParserReader reader) throws FHIRException {
Element segment = new Element("segment", message.getProperty().getChild("segment")); Element segment = new Element("segment", message.getProperty().getChild("segment"));
message.getChildren().add(segment); message.getChildren().add(segment);
Element segmentCode = new Element("code", segment.getProperty().getChild("code")); Element segmentCode = new Element("code", segment.getProperty().getChild("code"));
segment.getChildren().add(segmentCode); segment.getChildren().add(segmentCode);
segmentCode.setValue(reader.read(3)); segmentCode.setValue(reader.read(3));
int index = 0; int index = 0;
while (!reader.isFinished() && !reader.IsEOL()) { while (!reader.isFinished() && !reader.IsEOL()) {
index++; index++;
readField(reader, segment, index); readField(reader, segment, index);
if (!reader.isFinished() && !reader.IsEOL()) if (!reader.isFinished() && !reader.IsEOL())
rule(reader.read() == delimiters.getFieldDelimiter(), "Expected to find field delimiter"); rule(reader.read() == delimiters.getFieldDelimiter(), "Expected to find field delimiter");
} }
if (!reader.isFinished()) if (!reader.isFinished())
reader.skipEOL(); reader.skipEOL();
} }
private void readField(VerticalBarParserReader reader, Element segment, int index) { private void readField(VerticalBarParserReader reader, Element segment, int index) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override @Override
public void compose(Element e, OutputStream destination, OutputStyle style, String base) { public void compose(Element e, OutputStream destination, OutputStyle style, String base) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
} }

View File

@ -1,21 +1,35 @@
package ca.uhn.fhir.rest.client; package ca.uhn.fhir.rest.client;
import static org.hamcrest.Matchers.*; import ca.uhn.fhir.context.FhirContext;
import static org.junit.Assert.*; import ca.uhn.fhir.model.api.Include;
import static org.mockito.Mockito.mock; import ca.uhn.fhir.model.api.annotation.ResourceDef;
import static org.mockito.Mockito.when; import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.Constants;
import java.io.InputStream; import ca.uhn.fhir.rest.api.EncodingEnum;
import java.io.StringReader; import ca.uhn.fhir.rest.api.MethodOutcome;
import java.net.URLEncoder; import ca.uhn.fhir.rest.api.SummaryEnum;
import java.nio.charset.Charset; import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest;
import java.util.*; import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.UrlUtil;
import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream; import org.apache.commons.io.input.ReaderInputStream;
import org.apache.http.*; import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.*; import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine; import org.apache.http.message.BasicStatusLine;
import org.hamcrest.core.StringContains; import org.hamcrest.core.StringContains;
@ -23,29 +37,23 @@ import org.hamcrest.core.StringEndsWith;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
import org.junit.*; import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import com.google.common.base.Charsets; import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.*;
import ca.uhn.fhir.context.FhirContext; import static org.hamcrest.Matchers.*;
import ca.uhn.fhir.model.api.Include; import static org.junit.Assert.*;
import ca.uhn.fhir.model.api.annotation.ResourceDef; import static org.mockito.Mockito.mock;
import ca.uhn.fhir.model.base.resource.BaseConformance; import static org.mockito.Mockito.when;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest;
import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.exceptions.*;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.UrlUtil;
public class ClientR4Test { public class ClientR4Test {
@ -569,7 +577,7 @@ public class ClientR4Test {
DateParam date = new DateParam("2001-01-01"); DateParam date = new DateParam("2001-01-01");
client.getObservationByNameValueDate(new CompositeParam<StringParam, DateParam>(str, date)); client.getObservationByNameValueDate(new CompositeParam<StringParam, DateParam>(str, date));
assertEquals("http://foo/Observation?" + Observation.SP_CODE_VALUE_DATE + "=" + URLEncoder.encode("FOO\\$BAR$2001-01-01", "UTF-8"), capt.getValue().getURI().toString()); assertEquals("http://foo/Observation?" + Observation.SP_CODE_VALUE_DATE + "=" + UrlUtil.escapeUrlParam("FOO\\$BAR$2001-01-01"), capt.getValue().getURI().toString());
} }

View File

@ -1,45 +1,6 @@
package ca.uhn.fhir.rest.client; package ca.uhn.fhir.rest.client;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.*;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Bundle.BundleType;
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
import org.junit.*;
import org.mockito.ArgumentCaptor;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.IGenericClient;
@ -49,7 +10,43 @@ import ca.uhn.fhir.rest.client.impl.BaseClient;
import ca.uhn.fhir.rest.client.impl.GenericClient; import ca.uhn.fhir.rest.client.impl.GenericClient;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.*; import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Bundle.BundleType;
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
import org.junit.*;
import org.mockito.ArgumentCaptor;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.Charset;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class GenericClientTest { public class GenericClientTest {
@ -782,7 +779,7 @@ public class GenericClientTest {
.returnBundle(Bundle.class) .returnBundle(Bundle.class)
.execute(); .execute();
assertEquals("http://foo/Observation?" + Observation.SP_CODE_VALUE_DATE + "=" + URLEncoder.encode("FOO\\$BAR$2001-01-01", "UTF-8"), capt.getValue().getURI().toString()); assertEquals("http://foo/Observation?" + Observation.SP_CODE_VALUE_DATE + "=" + UrlUtil.escapeUrlParam("FOO\\$BAR$2001-01-01"), capt.getValue().getURI().toString());
} }
@ -1025,7 +1022,7 @@ public class GenericClientTest {
.returnBundle(Bundle.class) .returnBundle(Bundle.class)
.execute(); .execute();
assertEquals("http://example.com/fhir/Patient?name=" + URLEncoder.encode("AAA,BBB,C\\,C", "UTF-8"), capt.getAllValues().get(1).getURI().toString()); assertEquals("http://example.com/fhir/Patient?name=" + UrlUtil.escapeUrlParam("AAA,BBB,C\\,C"), capt.getAllValues().get(1).getURI().toString());
} }
@ -1116,7 +1113,7 @@ public class GenericClientTest {
.returnBundle(Bundle.class) .returnBundle(Bundle.class)
.execute(); .execute();
assertEquals("http://example.com/fhir/Patient?identifier=" + URLEncoder.encode("A|B,C|D", "UTF-8"), capt.getAllValues().get(2).getURI().toString()); assertEquals("http://example.com/fhir/Patient?identifier=" + UrlUtil.escapeUrlParam("A|B,C|D"), capt.getAllValues().get(2).getURI().toString());
} }
@ -1152,7 +1149,7 @@ public class GenericClientTest {
String url = capt.getAllValues().get(index).getURI().toString(); String url = capt.getAllValues().get(index).getURI().toString();
assertThat(url, Matchers.startsWith(wantPrefix)); assertThat(url, Matchers.startsWith(wantPrefix));
assertEquals(wantValue, UrlUtil.unescape(url.substring(wantPrefix.length()))); assertEquals(wantValue, UrlUtil.unescape(url.substring(wantPrefix.length())));
assertEquals(UrlUtil.escape(wantValue), url.substring(wantPrefix.length())); assertEquals(UrlUtil.escapeUrlParam(wantValue), url.substring(wantPrefix.length()));
index++; index++;
response = client.search() response = client.search()
@ -1164,7 +1161,7 @@ public class GenericClientTest {
url = capt.getAllValues().get(index).getURI().toString(); url = capt.getAllValues().get(index).getURI().toString();
assertThat(url, Matchers.startsWith(wantPrefix)); assertThat(url, Matchers.startsWith(wantPrefix));
assertEquals(wantValue, UrlUtil.unescape(url.substring(wantPrefix.length()))); assertEquals(wantValue, UrlUtil.unescape(url.substring(wantPrefix.length())));
assertEquals(UrlUtil.escape(wantValue), url.substring(wantPrefix.length())); assertEquals(UrlUtil.escapeUrlParam(wantValue), url.substring(wantPrefix.length()));
index++; index++;
} }
@ -1234,8 +1231,8 @@ public class GenericClientTest {
.execute(); .execute();
assertThat(capt.getValue().getURI().toString(), containsString("http://example.com/fhir/Patient?")); assertThat(capt.getValue().getURI().toString(), containsString("http://example.com/fhir/Patient?"));
assertThat(capt.getValue().getURI().toString(), containsString("_include=" + UrlUtil.escape(Patient.INCLUDE_ORGANIZATION.getValue()))); assertThat(capt.getValue().getURI().toString(), containsString("_include=" + UrlUtil.escapeUrlParam(Patient.INCLUDE_ORGANIZATION.getValue())));
assertThat(capt.getValue().getURI().toString(), containsString("_include%3Arecurse=" + UrlUtil.escape(Patient.INCLUDE_LINK.getValue()))); assertThat(capt.getValue().getURI().toString(), containsString("_include%3Arecurse=" + UrlUtil.escapeUrlParam(Patient.INCLUDE_LINK.getValue())));
assertThat(capt.getValue().getURI().toString(), containsString("_include=*")); assertThat(capt.getValue().getURI().toString(), containsString("_include=*"));
} }

View File

@ -54,7 +54,7 @@ public class GraphQLR4ProviderTest {
@Test @Test
public void testGraphInstance() throws Exception { public void testGraphInstance() throws Exception {
String query = "{name{family,given}}"; String query = "{name{family,given}}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escape(query)); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -80,7 +80,7 @@ public class GraphQLR4ProviderTest {
@Test @Test
public void testGraphInstanceWithFhirpath() throws Exception { public void testGraphInstanceWithFhirpath() throws Exception {
String query = "{name(fhirpath:\"family.exists()\"){text,given,family}}"; String query = "{name(fhirpath:\"family.exists()\"){text,given,family}}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escape(query)); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -104,7 +104,7 @@ public class GraphQLR4ProviderTest {
@Test @Test
public void testGraphSystemInstance() throws Exception { public void testGraphSystemInstance() throws Exception {
String query = "{Patient(id:123){id,name{given,family}}}"; String query = "{Patient(id:123){id,name{given,family}}}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escape(query)); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -132,7 +132,7 @@ public class GraphQLR4ProviderTest {
@Test @Test
public void testGraphSystemList() throws Exception { public void testGraphSystemList() throws Exception {
String query = "{PatientList(name:\"pet\"){name{family,given}}}"; String query = "{PatientList(name:\"pet\"){name{family,given}}}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escape(query)); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);

View File

@ -91,7 +91,7 @@ public class GraphQLR4RawTest {
ourNextRetVal = "{\"foo\"}"; ourNextRetVal = "{\"foo\"}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escape("{name{family,given}}")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -114,7 +114,7 @@ public class GraphQLR4RawTest {
ourNextRetVal = "{\"foo\"}"; ourNextRetVal = "{\"foo\"}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Condition/123/$graphql?query=" + UrlUtil.escape("{name{family,given}}")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Condition/123/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -132,7 +132,7 @@ public class GraphQLR4RawTest {
ourNextRetVal = "{\"foo\"}"; ourNextRetVal = "{\"foo\"}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escape("{name{family,given}}")); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);

View File

@ -131,25 +131,25 @@ public class SearchR4Test {
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=" + Constants.CT_FHIR_JSON_NEW); httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=" + Constants.CT_FHIR_JSON_NEW);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escape(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
} }

View File

@ -1,6 +1,6 @@
package ca.uhn.fhir.rest.server; package ca.uhn.fhir.rest.server;
import static ca.uhn.fhir.util.UrlUtil.escape; import static ca.uhn.fhir.util.UrlUtil.escapeUrlParam;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.empty;
@ -110,10 +110,10 @@ public class SearchSearchServerDstu1Test {
b.append("http://localhost:"); b.append("http://localhost:");
b.append(ourPort); b.append(ourPort);
b.append("/Patient?"); b.append("/Patient?");
b.append(escape("findPatientWithAndList")).append('=').append(escape("NE\\,NE,NE\\,NE")).append('&'); b.append(escapeUrlParam("findPatientWithAndList")).append('=').append(escapeUrlParam("NE\\,NE,NE\\,NE")).append('&');
b.append(escape("findPatientWithAndList")).append('=').append(escape("NE\\\\NE")).append('&'); b.append(escapeUrlParam("findPatientWithAndList")).append('=').append(escapeUrlParam("NE\\\\NE")).append('&');
b.append(escape("findPatientWithAndList:exact")).append('=').append(escape("E\\$E")).append('&'); b.append(escapeUrlParam("findPatientWithAndList:exact")).append('=').append(escapeUrlParam("E\\$E")).append('&');
b.append(escape("findPatientWithAndList:exact")).append('=').append(escape("E\\|E")).append('&'); b.append(escapeUrlParam("findPatientWithAndList:exact")).append('=').append(escapeUrlParam("E\\|E")).append('&');
HttpGet httpGet = new HttpGet(b.toString()); HttpGet httpGet = new HttpGet(b.toString());
@ -416,7 +416,7 @@ public class SearchSearchServerDstu1Test {
@Test @Test
public void testSearchWithTokenParameter() throws Exception { public void testSearchWithTokenParameter() throws Exception {
String token = UrlUtil.escape("http://www.dmix.gov/vista/2957|301"); String token = UrlUtil.escapeUrlParam("http://www.dmix.gov/vista/2957|301");
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?tokenParam=" + token); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?tokenParam=" + token);
HttpResponse status = ourClient.execute(httpGet); HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent()); String responseContent = IOUtils.toString(status.getEntity().getContent());

View File

@ -1,472 +1,472 @@
/* /*
Copyright (c) 2011+, HL7, Inc Copyright (c) 2011+, HL7, Inc
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to * Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific endorse or promote products derived from this software without specific
prior written permission. prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
*/ */
package org.hl7.fhir.utilities.xml; package org.hl7.fhir.utilities.xml;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer; import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource; import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamResult;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.w3c.dom.Attr; import org.w3c.dom.Attr;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer; import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
public class XMLUtil { public class XMLUtil {
public static final String SPACE_CHAR = "\u00A0"; public static final String SPACE_CHAR = "\u00A0";
public static boolean isNMToken(String name) { public static boolean isNMToken(String name) {
if (name == null) if (name == null)
return false; return false;
for (int i = 0; i < name.length(); i++) for (int i = 0; i < name.length(); i++)
if (!isNMTokenChar(name.charAt(i))) if (!isNMTokenChar(name.charAt(i)))
return false; return false;
return name.length() > 0; return name.length() > 0;
} }
public static boolean isNMTokenChar(char c) { public static boolean isNMTokenChar(char c) {
return isLetter(c) || isDigit(c) || c == '.' || c == '-' || c == '_' || c == ':' || isCombiningChar(c) || isExtender(c); return isLetter(c) || isDigit(c) || c == '.' || c == '-' || c == '_' || c == ':' || isCombiningChar(c) || isExtender(c);
} }
private static boolean isDigit(char c) { private static boolean isDigit(char c) {
return (c >= '\u0030' && c <= '\u0039') || (c >= '\u0660' && c <= '\u0669') || (c >= '\u06F0' && c <= '\u06F9') || return (c >= '\u0030' && c <= '\u0039') || (c >= '\u0660' && c <= '\u0669') || (c >= '\u06F0' && c <= '\u06F9') ||
(c >= '\u0966' && c <= '\u096F') || (c >= '\u09E6' && c <= '\u09EF') || (c >= '\u0A66' && c <= '\u0A6F') || (c >= '\u0966' && c <= '\u096F') || (c >= '\u09E6' && c <= '\u09EF') || (c >= '\u0A66' && c <= '\u0A6F') ||
(c >= '\u0AE6' && c <= '\u0AEF') || (c >= '\u0B66' && c <= '\u0B6F') || (c >= '\u0BE7' && c <= '\u0BEF') || (c >= '\u0AE6' && c <= '\u0AEF') || (c >= '\u0B66' && c <= '\u0B6F') || (c >= '\u0BE7' && c <= '\u0BEF') ||
(c >= '\u0C66' && c <= '\u0C6F') || (c >= '\u0CE6' && c <= '\u0CEF') || (c >= '\u0D66' && c <= '\u0D6F') || (c >= '\u0C66' && c <= '\u0C6F') || (c >= '\u0CE6' && c <= '\u0CEF') || (c >= '\u0D66' && c <= '\u0D6F') ||
(c >= '\u0E50' && c <= '\u0E59') || (c >= '\u0ED0' && c <= '\u0ED9') || (c >= '\u0F20' && c <= '\u0F29'); (c >= '\u0E50' && c <= '\u0E59') || (c >= '\u0ED0' && c <= '\u0ED9') || (c >= '\u0F20' && c <= '\u0F29');
} }
private static boolean isCombiningChar(char c) { private static boolean isCombiningChar(char c) {
return (c >= '\u0300' && c <= '\u0345') || (c >= '\u0360' && c <= '\u0361') || (c >= '\u0483' && c <= '\u0486') || return (c >= '\u0300' && c <= '\u0345') || (c >= '\u0360' && c <= '\u0361') || (c >= '\u0483' && c <= '\u0486') ||
(c >= '\u0591' && c <= '\u05A1') || (c >= '\u05A3' && c <= '\u05B9') || (c >= '\u05BB' && c <= '\u05BD') || (c >= '\u0591' && c <= '\u05A1') || (c >= '\u05A3' && c <= '\u05B9') || (c >= '\u05BB' && c <= '\u05BD') ||
c == '\u05BF' || (c >= '\u05C1' && c <= '\u05C2') || c == '\u05C4' || (c >= '\u064B' && c <= '\u0652') || c == '\u05BF' || (c >= '\u05C1' && c <= '\u05C2') || c == '\u05C4' || (c >= '\u064B' && c <= '\u0652') ||
c == '\u0670' || (c >= '\u06D6' && c <= '\u06DC') || (c >= '\u06DD' && c <= '\u06DF') || (c >= '\u06E0' && c <= '\u06E4') || c == '\u0670' || (c >= '\u06D6' && c <= '\u06DC') || (c >= '\u06DD' && c <= '\u06DF') || (c >= '\u06E0' && c <= '\u06E4') ||
(c >= '\u06E7' && c <= '\u06E8') || (c >= '\u06EA' && c <= '\u06ED') || (c >= '\u0901' && c <= '\u0903') || c == '\u093C' || (c >= '\u06E7' && c <= '\u06E8') || (c >= '\u06EA' && c <= '\u06ED') || (c >= '\u0901' && c <= '\u0903') || c == '\u093C' ||
(c >= '\u093E' && c <= '\u094C') || c == '\u094D' || (c >= '\u0951' && c <= '\u0954') || (c >= '\u0962' && c <= '\u0963') || (c >= '\u093E' && c <= '\u094C') || c == '\u094D' || (c >= '\u0951' && c <= '\u0954') || (c >= '\u0962' && c <= '\u0963') ||
(c >= '\u0981' && c <= '\u0983') || c == '\u09BC' || c == '\u09BE' || c == '\u09BF' || (c >= '\u09C0' && c <= '\u09C4') || (c >= '\u0981' && c <= '\u0983') || c == '\u09BC' || c == '\u09BE' || c == '\u09BF' || (c >= '\u09C0' && c <= '\u09C4') ||
(c >= '\u09C7' && c <= '\u09C8') || (c >= '\u09CB' && c <= '\u09CD') || c == '\u09D7' || (c >= '\u09E2' && c <= '\u09E3') || (c >= '\u09C7' && c <= '\u09C8') || (c >= '\u09CB' && c <= '\u09CD') || c == '\u09D7' || (c >= '\u09E2' && c <= '\u09E3') ||
c == '\u0A02' || c == '\u0A3C' || c == '\u0A3E' || c == '\u0A3F' || (c >= '\u0A40' && c <= '\u0A42') || c == '\u0A02' || c == '\u0A3C' || c == '\u0A3E' || c == '\u0A3F' || (c >= '\u0A40' && c <= '\u0A42') ||
(c >= '\u0A47' && c <= '\u0A48') || (c >= '\u0A4B' && c <= '\u0A4D') || (c >= '\u0A70' && c <= '\u0A71') || (c >= '\u0A47' && c <= '\u0A48') || (c >= '\u0A4B' && c <= '\u0A4D') || (c >= '\u0A70' && c <= '\u0A71') ||
(c >= '\u0A81' && c <= '\u0A83') || c == '\u0ABC' || (c >= '\u0ABE' && c <= '\u0AC5') || (c >= '\u0AC7' && c <= '\u0AC9') || (c >= '\u0A81' && c <= '\u0A83') || c == '\u0ABC' || (c >= '\u0ABE' && c <= '\u0AC5') || (c >= '\u0AC7' && c <= '\u0AC9') ||
(c >= '\u0ACB' && c <= '\u0ACD') || (c >= '\u0B01' && c <= '\u0B03') || c == '\u0B3C' || (c >= '\u0B3E' && c <= '\u0B43') || (c >= '\u0ACB' && c <= '\u0ACD') || (c >= '\u0B01' && c <= '\u0B03') || c == '\u0B3C' || (c >= '\u0B3E' && c <= '\u0B43') ||
(c >= '\u0B47' && c <= '\u0B48') || (c >= '\u0B4B' && c <= '\u0B4D') || (c >= '\u0B56' && c <= '\u0B57') || (c >= '\u0B47' && c <= '\u0B48') || (c >= '\u0B4B' && c <= '\u0B4D') || (c >= '\u0B56' && c <= '\u0B57') ||
(c >= '\u0B82' && c <= '\u0B83') || (c >= '\u0BBE' && c <= '\u0BC2') || (c >= '\u0BC6' && c <= '\u0BC8') || (c >= '\u0B82' && c <= '\u0B83') || (c >= '\u0BBE' && c <= '\u0BC2') || (c >= '\u0BC6' && c <= '\u0BC8') ||
(c >= '\u0BCA' && c <= '\u0BCD') || c == '\u0BD7' || (c >= '\u0C01' && c <= '\u0C03') || (c >= '\u0C3E' && c <= '\u0C44') || (c >= '\u0BCA' && c <= '\u0BCD') || c == '\u0BD7' || (c >= '\u0C01' && c <= '\u0C03') || (c >= '\u0C3E' && c <= '\u0C44') ||
(c >= '\u0C46' && c <= '\u0C48') || (c >= '\u0C4A' && c <= '\u0C4D') || (c >= '\u0C55' && c <= '\u0C56') || (c >= '\u0C46' && c <= '\u0C48') || (c >= '\u0C4A' && c <= '\u0C4D') || (c >= '\u0C55' && c <= '\u0C56') ||
(c >= '\u0C82' && c <= '\u0C83') || (c >= '\u0CBE' && c <= '\u0CC4') || (c >= '\u0CC6' && c <= '\u0CC8') || (c >= '\u0C82' && c <= '\u0C83') || (c >= '\u0CBE' && c <= '\u0CC4') || (c >= '\u0CC6' && c <= '\u0CC8') ||
(c >= '\u0CCA' && c <= '\u0CCD') || (c >= '\u0CD5' && c <= '\u0CD6') || (c >= '\u0D02' && c <= '\u0D03') || (c >= '\u0CCA' && c <= '\u0CCD') || (c >= '\u0CD5' && c <= '\u0CD6') || (c >= '\u0D02' && c <= '\u0D03') ||
(c >= '\u0D3E' && c <= '\u0D43') || (c >= '\u0D46' && c <= '\u0D48') || (c >= '\u0D4A' && c <= '\u0D4D') || c == '\u0D57' || (c >= '\u0D3E' && c <= '\u0D43') || (c >= '\u0D46' && c <= '\u0D48') || (c >= '\u0D4A' && c <= '\u0D4D') || c == '\u0D57' ||
c == '\u0E31' || (c >= '\u0E34' && c <= '\u0E3A') || (c >= '\u0E47' && c <= '\u0E4E') || c == '\u0EB1' || c == '\u0E31' || (c >= '\u0E34' && c <= '\u0E3A') || (c >= '\u0E47' && c <= '\u0E4E') || c == '\u0EB1' ||
(c >= '\u0EB4' && c <= '\u0EB9') || (c >= '\u0EBB' && c <= '\u0EBC') || (c >= '\u0EC8' && c <= '\u0ECD') || (c >= '\u0EB4' && c <= '\u0EB9') || (c >= '\u0EBB' && c <= '\u0EBC') || (c >= '\u0EC8' && c <= '\u0ECD') ||
(c >= '\u0F18' && c <= '\u0F19') || c == '\u0F35' || c == '\u0F37' || c == '\u0F39' || c == '\u0F3E' || c == '\u0F3F' || (c >= '\u0F18' && c <= '\u0F19') || c == '\u0F35' || c == '\u0F37' || c == '\u0F39' || c == '\u0F3E' || c == '\u0F3F' ||
(c >= '\u0F71' && c <= '\u0F84') || (c >= '\u0F86' && c <= '\u0F8B') || (c >= '\u0F90' && c <= '\u0F95') || c == '\u0F97' || (c >= '\u0F71' && c <= '\u0F84') || (c >= '\u0F86' && c <= '\u0F8B') || (c >= '\u0F90' && c <= '\u0F95') || c == '\u0F97' ||
(c >= '\u0F99' && c <= '\u0FAD') || (c >= '\u0FB1' && c <= '\u0FB7') || c == '\u0FB9' || (c >= '\u20D0' && c <= '\u20DC') || (c >= '\u0F99' && c <= '\u0FAD') || (c >= '\u0FB1' && c <= '\u0FB7') || c == '\u0FB9' || (c >= '\u20D0' && c <= '\u20DC') ||
c == '\u20E1' || (c >= '\u302A' && c <= '\u302F') || c == '\u3099' || c == '\u309A'; c == '\u20E1' || (c >= '\u302A' && c <= '\u302F') || c == '\u3099' || c == '\u309A';
} }
private static boolean isExtender(char c) { private static boolean isExtender(char c) {
return c == '\u00B7' || c == '\u02D0' || c == '\u02D1' || c == '\u0387' || c == '\u0640' || c == '\u0E46' || return c == '\u00B7' || c == '\u02D0' || c == '\u02D1' || c == '\u0387' || c == '\u0640' || c == '\u0E46' ||
c == '\u0EC6' || c == '\u3005' || (c >= '\u3031' && c <= '\u3035') || (c >= '\u309D' && c <= '\u309E') || c == '\u0EC6' || c == '\u3005' || (c >= '\u3031' && c <= '\u3035') || (c >= '\u309D' && c <= '\u309E') ||
(c >= '\u30FC' && c <= '\u30FE'); (c >= '\u30FC' && c <= '\u30FE');
} }
private static boolean isLetter(char c) { private static boolean isLetter(char c) {
return isBaseChar(c) || isIdeographic(c); return isBaseChar(c) || isIdeographic(c);
} }
private static boolean isBaseChar(char c) { private static boolean isBaseChar(char c) {
return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A') || (c >= '\u00C0' && c <= '\u00D6') || return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A') || (c >= '\u00C0' && c <= '\u00D6') ||
(c >= '\u00D8' && c <= '\u00F6') || (c >= '\u00F8' && c <= '\u00FF') || (c >= '\u0100' && c <= '\u0131') || (c >= '\u00D8' && c <= '\u00F6') || (c >= '\u00F8' && c <= '\u00FF') || (c >= '\u0100' && c <= '\u0131') ||
(c >= '\u0134' && c <= '\u013E') || (c >= '\u0141' && c <= '\u0148') || (c >= '\u014A' && c <= '\u017E') || (c >= '\u0134' && c <= '\u013E') || (c >= '\u0141' && c <= '\u0148') || (c >= '\u014A' && c <= '\u017E') ||
(c >= '\u0180' && c <= '\u01C3') || (c >= '\u01CD' && c <= '\u01F0') || (c >= '\u01F4' && c <= '\u01F5') || (c >= '\u0180' && c <= '\u01C3') || (c >= '\u01CD' && c <= '\u01F0') || (c >= '\u01F4' && c <= '\u01F5') ||
(c >= '\u01FA' && c <= '\u0217') || (c >= '\u0250' && c <= '\u02A8') || (c >= '\u02BB' && c <= '\u02C1') || (c >= '\u01FA' && c <= '\u0217') || (c >= '\u0250' && c <= '\u02A8') || (c >= '\u02BB' && c <= '\u02C1') ||
c == '\u0386' || (c >= '\u0388' && c <= '\u038A') || c == '\u038C' || (c >= '\u038E' && c <= '\u03A1') || c == '\u0386' || (c >= '\u0388' && c <= '\u038A') || c == '\u038C' || (c >= '\u038E' && c <= '\u03A1') ||
(c >= '\u03A3' && c <= '\u03CE') || (c >= '\u03D0' && c <= '\u03D6') || c == '\u03DA' || c == '\u03DC' || c == '\u03DE' || (c >= '\u03A3' && c <= '\u03CE') || (c >= '\u03D0' && c <= '\u03D6') || c == '\u03DA' || c == '\u03DC' || c == '\u03DE' ||
c == '\u03E0' || (c >= '\u03E2' && c <= '\u03F3') || (c >= '\u0401' && c <= '\u040C') || (c >= '\u040E' && c <= '\u044F') || c == '\u03E0' || (c >= '\u03E2' && c <= '\u03F3') || (c >= '\u0401' && c <= '\u040C') || (c >= '\u040E' && c <= '\u044F') ||
(c >= '\u0451' && c <= '\u045C') || (c >= '\u045E' && c <= '\u0481') || (c >= '\u0490' && c <= '\u04C4') || (c >= '\u0451' && c <= '\u045C') || (c >= '\u045E' && c <= '\u0481') || (c >= '\u0490' && c <= '\u04C4') ||
(c >= '\u04C7' && c <= '\u04C8') || (c >= '\u04CB' && c <= '\u04CC') || (c >= '\u04D0' && c <= '\u04EB') || (c >= '\u04C7' && c <= '\u04C8') || (c >= '\u04CB' && c <= '\u04CC') || (c >= '\u04D0' && c <= '\u04EB') ||
(c >= '\u04EE' && c <= '\u04F5') || (c >= '\u04F8' && c <= '\u04F9') || (c >= '\u0531' && c <= '\u0556') || (c >= '\u04EE' && c <= '\u04F5') || (c >= '\u04F8' && c <= '\u04F9') || (c >= '\u0531' && c <= '\u0556') ||
c == '\u0559' || (c >= '\u0561' && c <= '\u0586') || (c >= '\u05D0' && c <= '\u05EA') || (c >= '\u05F0' && c <= '\u05F2') || c == '\u0559' || (c >= '\u0561' && c <= '\u0586') || (c >= '\u05D0' && c <= '\u05EA') || (c >= '\u05F0' && c <= '\u05F2') ||
(c >= '\u0621' && c <= '\u063A') || (c >= '\u0641' && c <= '\u064A') || (c >= '\u0671' && c <= '\u06B7') || (c >= '\u0621' && c <= '\u063A') || (c >= '\u0641' && c <= '\u064A') || (c >= '\u0671' && c <= '\u06B7') ||
(c >= '\u06BA' && c <= '\u06BE') || (c >= '\u06C0' && c <= '\u06CE') || (c >= '\u06D0' && c <= '\u06D3') || (c >= '\u06BA' && c <= '\u06BE') || (c >= '\u06C0' && c <= '\u06CE') || (c >= '\u06D0' && c <= '\u06D3') ||
c == '\u06D5' || (c >= '\u06E5' && c <= '\u06E6') || (c >= '\u0905' && c <= '\u0939') || c == '\u093D' || c == '\u06D5' || (c >= '\u06E5' && c <= '\u06E6') || (c >= '\u0905' && c <= '\u0939') || c == '\u093D' ||
(c >= '\u0958' && c <= '\u0961') || (c >= '\u0985' && c <= '\u098C') || (c >= '\u098F' && c <= '\u0990') || (c >= '\u0958' && c <= '\u0961') || (c >= '\u0985' && c <= '\u098C') || (c >= '\u098F' && c <= '\u0990') ||
(c >= '\u0993' && c <= '\u09A8') || (c >= '\u09AA' && c <= '\u09B0') || c == '\u09B2' || (c >= '\u0993' && c <= '\u09A8') || (c >= '\u09AA' && c <= '\u09B0') || c == '\u09B2' ||
(c >= '\u09B6' && c <= '\u09B9') || (c >= '\u09DC' && c <= '\u09DD') || (c >= '\u09DF' && c <= '\u09E1') || (c >= '\u09B6' && c <= '\u09B9') || (c >= '\u09DC' && c <= '\u09DD') || (c >= '\u09DF' && c <= '\u09E1') ||
(c >= '\u09F0' && c <= '\u09F1') || (c >= '\u0A05' && c <= '\u0A0A') || (c >= '\u0A0F' && c <= '\u0A10') || (c >= '\u09F0' && c <= '\u09F1') || (c >= '\u0A05' && c <= '\u0A0A') || (c >= '\u0A0F' && c <= '\u0A10') ||
(c >= '\u0A13' && c <= '\u0A28') || (c >= '\u0A2A' && c <= '\u0A30') || (c >= '\u0A32' && c <= '\u0A33') || (c >= '\u0A13' && c <= '\u0A28') || (c >= '\u0A2A' && c <= '\u0A30') || (c >= '\u0A32' && c <= '\u0A33') ||
(c >= '\u0A35' && c <= '\u0A36') || (c >= '\u0A38' && c <= '\u0A39') || (c >= '\u0A59' && c <= '\u0A5C') || (c >= '\u0A35' && c <= '\u0A36') || (c >= '\u0A38' && c <= '\u0A39') || (c >= '\u0A59' && c <= '\u0A5C') ||
c == '\u0A5E' || (c >= '\u0A72' && c <= '\u0A74') || (c >= '\u0A85' && c <= '\u0A8B') || c == '\u0A8D' || c == '\u0A5E' || (c >= '\u0A72' && c <= '\u0A74') || (c >= '\u0A85' && c <= '\u0A8B') || c == '\u0A8D' ||
(c >= '\u0A8F' && c <= '\u0A91') || (c >= '\u0A93' && c <= '\u0AA8') || (c >= '\u0AAA' && c <= '\u0AB0') || (c >= '\u0A8F' && c <= '\u0A91') || (c >= '\u0A93' && c <= '\u0AA8') || (c >= '\u0AAA' && c <= '\u0AB0') ||
(c >= '\u0AB2' && c <= '\u0AB3') || (c >= '\u0AB5' && c <= '\u0AB9') || c == '\u0ABD' || c == '\u0AE0' || (c >= '\u0AB2' && c <= '\u0AB3') || (c >= '\u0AB5' && c <= '\u0AB9') || c == '\u0ABD' || c == '\u0AE0' ||
(c >= '\u0B05' && c <= '\u0B0C') || (c >= '\u0B0F' && c <= '\u0B10') || (c >= '\u0B13' && c <= '\u0B28') || (c >= '\u0B05' && c <= '\u0B0C') || (c >= '\u0B0F' && c <= '\u0B10') || (c >= '\u0B13' && c <= '\u0B28') ||
(c >= '\u0B2A' && c <= '\u0B30') || (c >= '\u0B32' && c <= '\u0B33') || (c >= '\u0B36' && c <= '\u0B39') || (c >= '\u0B2A' && c <= '\u0B30') || (c >= '\u0B32' && c <= '\u0B33') || (c >= '\u0B36' && c <= '\u0B39') ||
c == '\u0B3D' || (c >= '\u0B5C' && c <= '\u0B5D') || (c >= '\u0B5F' && c <= '\u0B61') || c == '\u0B3D' || (c >= '\u0B5C' && c <= '\u0B5D') || (c >= '\u0B5F' && c <= '\u0B61') ||
(c >= '\u0B85' && c <= '\u0B8A') || (c >= '\u0B8E' && c <= '\u0B90') || (c >= '\u0B92' && c <= '\u0B95') || (c >= '\u0B85' && c <= '\u0B8A') || (c >= '\u0B8E' && c <= '\u0B90') || (c >= '\u0B92' && c <= '\u0B95') ||
(c >= '\u0B99' && c <= '\u0B9A') || c == '\u0B9C' || (c >= '\u0B9E' && c <= '\u0B9F') || (c >= '\u0B99' && c <= '\u0B9A') || c == '\u0B9C' || (c >= '\u0B9E' && c <= '\u0B9F') ||
(c >= '\u0BA3' && c <= '\u0BA4') || (c >= '\u0BA8' && c <= '\u0BAA') || (c >= '\u0BAE' && c <= '\u0BB5') || (c >= '\u0BA3' && c <= '\u0BA4') || (c >= '\u0BA8' && c <= '\u0BAA') || (c >= '\u0BAE' && c <= '\u0BB5') ||
(c >= '\u0BB7' && c <= '\u0BB9') || (c >= '\u0C05' && c <= '\u0C0C') || (c >= '\u0C0E' && c <= '\u0C10') || (c >= '\u0BB7' && c <= '\u0BB9') || (c >= '\u0C05' && c <= '\u0C0C') || (c >= '\u0C0E' && c <= '\u0C10') ||
(c >= '\u0C12' && c <= '\u0C28') || (c >= '\u0C2A' && c <= '\u0C33') || (c >= '\u0C35' && c <= '\u0C39') || (c >= '\u0C12' && c <= '\u0C28') || (c >= '\u0C2A' && c <= '\u0C33') || (c >= '\u0C35' && c <= '\u0C39') ||
(c >= '\u0C60' && c <= '\u0C61') || (c >= '\u0C85' && c <= '\u0C8C') || (c >= '\u0C8E' && c <= '\u0C90') || (c >= '\u0C60' && c <= '\u0C61') || (c >= '\u0C85' && c <= '\u0C8C') || (c >= '\u0C8E' && c <= '\u0C90') ||
(c >= '\u0C92' && c <= '\u0CA8') || (c >= '\u0CAA' && c <= '\u0CB3') || (c >= '\u0CB5' && c <= '\u0CB9') || (c >= '\u0C92' && c <= '\u0CA8') || (c >= '\u0CAA' && c <= '\u0CB3') || (c >= '\u0CB5' && c <= '\u0CB9') ||
c == '\u0CDE' || (c >= '\u0CE0' && c <= '\u0CE1') || (c >= '\u0D05' && c <= '\u0D0C') || c == '\u0CDE' || (c >= '\u0CE0' && c <= '\u0CE1') || (c >= '\u0D05' && c <= '\u0D0C') ||
(c >= '\u0D0E' && c <= '\u0D10') || (c >= '\u0D12' && c <= '\u0D28') || (c >= '\u0D2A' && c <= '\u0D39') || (c >= '\u0D0E' && c <= '\u0D10') || (c >= '\u0D12' && c <= '\u0D28') || (c >= '\u0D2A' && c <= '\u0D39') ||
(c >= '\u0D60' && c <= '\u0D61') || (c >= '\u0E01' && c <= '\u0E2E') || c == '\u0E30' || (c >= '\u0D60' && c <= '\u0D61') || (c >= '\u0E01' && c <= '\u0E2E') || c == '\u0E30' ||
(c >= '\u0E32' && c <= '\u0E33') || (c >= '\u0E40' && c <= '\u0E45') || (c >= '\u0E81' && c <= '\u0E82') || (c >= '\u0E32' && c <= '\u0E33') || (c >= '\u0E40' && c <= '\u0E45') || (c >= '\u0E81' && c <= '\u0E82') ||
c == '\u0E84' || (c >= '\u0E87' && c <= '\u0E88') || c == '\u0E8A' || c == '\u0E8D' || (c >= '\u0E94' && c <= '\u0E97') || c == '\u0E84' || (c >= '\u0E87' && c <= '\u0E88') || c == '\u0E8A' || c == '\u0E8D' || (c >= '\u0E94' && c <= '\u0E97') ||
(c >= '\u0E99' && c <= '\u0E9F') || (c >= '\u0EA1' && c <= '\u0EA3') || c == '\u0EA5' || c == '\u0EA7' || (c >= '\u0E99' && c <= '\u0E9F') || (c >= '\u0EA1' && c <= '\u0EA3') || c == '\u0EA5' || c == '\u0EA7' ||
(c >= '\u0EAA' && c <= '\u0EAB') || (c >= '\u0EAD' && c <= '\u0EAE') || c == '\u0EB0' || (c >= '\u0EAA' && c <= '\u0EAB') || (c >= '\u0EAD' && c <= '\u0EAE') || c == '\u0EB0' ||
(c >= '\u0EB2' && c <= '\u0EB3') || c == '\u0EBD' || (c >= '\u0EC0' && c <= '\u0EC4') || (c >= '\u0EB2' && c <= '\u0EB3') || c == '\u0EBD' || (c >= '\u0EC0' && c <= '\u0EC4') ||
(c >= '\u0F40' && c <= '\u0F47') || (c >= '\u0F49' && c <= '\u0F69') || (c >= '\u10A0' && c <= '\u10C5') || (c >= '\u0F40' && c <= '\u0F47') || (c >= '\u0F49' && c <= '\u0F69') || (c >= '\u10A0' && c <= '\u10C5') ||
(c >= '\u10D0' && c <= '\u10F6') || c == '\u1100' || (c >= '\u1102' && c <= '\u1103') || (c >= '\u10D0' && c <= '\u10F6') || c == '\u1100' || (c >= '\u1102' && c <= '\u1103') ||
(c >= '\u1105' && c <= '\u1107') || c == '\u1109' || (c >= '\u110B' && c <= '\u110C') || (c >= '\u1105' && c <= '\u1107') || c == '\u1109' || (c >= '\u110B' && c <= '\u110C') ||
(c >= '\u110E' && c <= '\u1112') || c == '\u113C' || c == '\u113E' || c == '\u1140' || c == '\u114C' || (c >= '\u110E' && c <= '\u1112') || c == '\u113C' || c == '\u113E' || c == '\u1140' || c == '\u114C' ||
c == '\u114E' || c == '\u1150' || (c >= '\u1154' && c <= '\u1155') || c == '\u1159' || c == '\u114E' || c == '\u1150' || (c >= '\u1154' && c <= '\u1155') || c == '\u1159' ||
(c >= '\u115F' && c <= '\u1161') || c == '\u1163' || c == '\u1165' || c == '\u1167' || c == '\u1169' || (c >= '\u115F' && c <= '\u1161') || c == '\u1163' || c == '\u1165' || c == '\u1167' || c == '\u1169' ||
(c >= '\u116D' && c <= '\u116E') || (c >= '\u1172' && c <= '\u1173') || c == '\u1175' || (c >= '\u116D' && c <= '\u116E') || (c >= '\u1172' && c <= '\u1173') || c == '\u1175' ||
c == '\u119E' || c == '\u11A8' || c == '\u11AB' || (c >= '\u11AE' && c <= '\u11AF') || c == '\u119E' || c == '\u11A8' || c == '\u11AB' || (c >= '\u11AE' && c <= '\u11AF') ||
(c >= '\u11B7' && c <= '\u11B8') || c == '\u11BA' || (c >= '\u11BC' && c <= '\u11C2') || (c >= '\u11B7' && c <= '\u11B8') || c == '\u11BA' || (c >= '\u11BC' && c <= '\u11C2') ||
c == '\u11EB' || c == '\u11F0' || c == '\u11F9' || (c >= '\u1E00' && c <= '\u1E9B') || (c >= '\u1EA0' && c <= '\u1EF9') || c == '\u11EB' || c == '\u11F0' || c == '\u11F9' || (c >= '\u1E00' && c <= '\u1E9B') || (c >= '\u1EA0' && c <= '\u1EF9') ||
(c >= '\u1F00' && c <= '\u1F15') || (c >= '\u1F18' && c <= '\u1F1D') || (c >= '\u1F20' && c <= '\u1F45') || (c >= '\u1F00' && c <= '\u1F15') || (c >= '\u1F18' && c <= '\u1F1D') || (c >= '\u1F20' && c <= '\u1F45') ||
(c >= '\u1F48' && c <= '\u1F4D') || (c >= '\u1F50' && c <= '\u1F57') || c == '\u1F59' || c == '\u1F5B' || c == '\u1F5D' || (c >= '\u1F48' && c <= '\u1F4D') || (c >= '\u1F50' && c <= '\u1F57') || c == '\u1F59' || c == '\u1F5B' || c == '\u1F5D' ||
(c >= '\u1F5F' && c <= '\u1F7D') || (c >= '\u1F80' && c <= '\u1FB4') || (c >= '\u1FB6' && c <= '\u1FBC') || (c >= '\u1F5F' && c <= '\u1F7D') || (c >= '\u1F80' && c <= '\u1FB4') || (c >= '\u1FB6' && c <= '\u1FBC') ||
c == '\u1FBE' || (c >= '\u1FC2' && c <= '\u1FC4') || (c >= '\u1FC6' && c <= '\u1FCC') || c == '\u1FBE' || (c >= '\u1FC2' && c <= '\u1FC4') || (c >= '\u1FC6' && c <= '\u1FCC') ||
(c >= '\u1FD0' && c <= '\u1FD3') || (c >= '\u1FD6' && c <= '\u1FDB') || (c >= '\u1FE0' && c <= '\u1FEC') || (c >= '\u1FD0' && c <= '\u1FD3') || (c >= '\u1FD6' && c <= '\u1FDB') || (c >= '\u1FE0' && c <= '\u1FEC') ||
(c >= '\u1FF2' && c <= '\u1FF4') || (c >= '\u1FF6' && c <= '\u1FFC') || c == '\u2126' || (c >= '\u1FF2' && c <= '\u1FF4') || (c >= '\u1FF6' && c <= '\u1FFC') || c == '\u2126' ||
(c >= '\u212A' && c <= '\u212B') || c == '\u212E' || (c >= '\u2180' && c <= '\u2182') || (c >= '\u212A' && c <= '\u212B') || c == '\u212E' || (c >= '\u2180' && c <= '\u2182') ||
(c >= '\u3041' && c <= '\u3094') || (c >= '\u30A1' && c <= '\u30FA') || (c >= '\u3105' && c <= '\u312C') || (c >= '\u3041' && c <= '\u3094') || (c >= '\u30A1' && c <= '\u30FA') || (c >= '\u3105' && c <= '\u312C') ||
(c >= '\uAC00' && c <= '\uD7A3'); (c >= '\uAC00' && c <= '\uD7A3');
} }
private static boolean isIdeographic(char c) { private static boolean isIdeographic(char c) {
return (c >= '\u4E00' && c <= '\u9FA5') || c == '\u3007' || (c >= '\u3021' && c <= '\u3029'); return (c >= '\u4E00' && c <= '\u9FA5') || c == '\u3007' || (c >= '\u3021' && c <= '\u3029');
} }
public static String determineEncoding(InputStream stream) throws IOException { public static String determineEncoding(InputStream stream) throws IOException {
stream.mark(20000); stream.mark(20000);
try { try {
int b0 = stream.read(); int b0 = stream.read();
int b1 = stream.read(); int b1 = stream.read();
int b2 = stream.read(); int b2 = stream.read();
int b3 = stream.read(); int b3 = stream.read();
if (b0 == 0xFE && b1 == 0xFF) if (b0 == 0xFE && b1 == 0xFF)
return "UTF-16BE"; return "UTF-16BE";
else if (b0 == 0xFF && b1 == 0xFE) else if (b0 == 0xFF && b1 == 0xFE)
return "UTF-16LE"; return "UTF-16LE";
else if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF ) else if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF )
return "UTF-8"; return "UTF-8";
else if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) else if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F)
return "UTF-16BE"; return "UTF-16BE";
else if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) else if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00)
return "UTF-16LE"; return "UTF-16LE";
else if (b0 == 0x3C && b1 == 0x3F && b2 == 0x78 && b3 == 0x6D) { else if (b0 == 0x3C && b1 == 0x3F && b2 == 0x78 && b3 == 0x6D) {
// UTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC, or any other 7-bit, 8-bit, or mixed-width encoding // UTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC, or any other 7-bit, 8-bit, or mixed-width encoding
// which ensures that the characters of ASCII have their normal positions, width, and values; the actual encoding // which ensures that the characters of ASCII have their normal positions, width, and values; the actual encoding
// declaration must be read to detect which of these applies, but since all of these encodings use the same bit patterns // declaration must be read to detect which of these applies, but since all of these encodings use the same bit patterns
// for the relevant ASCII characters, the encoding declaration itself may be read reliably // for the relevant ASCII characters, the encoding declaration itself may be read reliably
InputStreamReader rdr = new InputStreamReader(stream, "US-ASCII"); InputStreamReader rdr = new InputStreamReader(stream, "US-ASCII");
String hdr = readFirstLine(rdr); String hdr = readFirstLine(rdr);
return extractEncoding(hdr); return extractEncoding(hdr);
} else } else
return null; return null;
} finally { } finally {
stream.reset(); stream.reset();
} }
} }
private static String extractEncoding(String hdr) { private static String extractEncoding(String hdr) {
int i = hdr.indexOf("encoding="); int i = hdr.indexOf("encoding=");
if (i == -1) if (i == -1)
return null; return null;
hdr = hdr.substring(i+9); hdr = hdr.substring(i+9);
char sep = hdr.charAt(0); char sep = hdr.charAt(0);
hdr = hdr.substring(1); hdr = hdr.substring(1);
i = hdr.indexOf(sep); i = hdr.indexOf(sep);
if (i == -1) if (i == -1)
return null; return null;
return hdr.substring(0, i); return hdr.substring(0, i);
} }
private static String readFirstLine(InputStreamReader rdr) throws IOException { private static String readFirstLine(InputStreamReader rdr) throws IOException {
char[] buf = new char[1]; char[] buf = new char[1];
StringBuffer bldr = new StringBuffer(); StringBuffer bldr = new StringBuffer();
rdr.read(buf); rdr.read(buf);
while (buf[0] != '>') { while (buf[0] != '>') {
bldr.append(buf[0]); bldr.append(buf[0]);
rdr.read(buf); rdr.read(buf);
} }
return bldr.toString(); return bldr.toString();
} }
public static boolean charSetImpliesAscii(String charset) { public static boolean charSetImpliesAscii(String charset) {
return charset.equals("ISO-8859-1") || charset.equals("US-ASCII"); return charset.equals("ISO-8859-1") || charset.equals("US-ASCII");
} }
/** /**
* Converts the raw characters to XML escape characters. * Converts the raw characters to XML escapeUrlParam characters.
* *
* @param rawContent * @param rawContent
* @param charset Null when charset is not known, so we assume it's unicode * @param charset Null when charset is not known, so we assume it's unicode
* @param isNoLines * @param isNoLines
* @return escape string * @return escapeUrlParam string
*/ */
public static String escapeXML(String rawContent, String charset, boolean isNoLines) { public static String escapeXML(String rawContent, String charset, boolean isNoLines) {
if (rawContent == null) if (rawContent == null)
return ""; return "";
else { else {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
for (int i = 0; i < rawContent.length(); i++) { for (int i = 0; i < rawContent.length(); i++) {
char ch = rawContent.charAt(i); char ch = rawContent.charAt(i);
if (ch == '\'') if (ch == '\'')
sb.append("&#39;"); sb.append("&#39;");
else if (ch == '&') else if (ch == '&')
sb.append("&amp;"); sb.append("&amp;");
else if (ch == '"') else if (ch == '"')
sb.append("&quot;"); sb.append("&quot;");
else if (ch == '<') else if (ch == '<')
sb.append("&lt;"); sb.append("&lt;");
else if (ch == '>') else if (ch == '>')
sb.append("&gt;"); sb.append("&gt;");
else if (ch > '~' && charset != null && charSetImpliesAscii(charset)) else if (ch > '~' && charset != null && charSetImpliesAscii(charset))
// TODO - why is hashcode the only way to get the unicode number for the character // TODO - why is hashcode the only way to get the unicode number for the character
// in jre 5.0? // in jre 5.0?
sb.append("&#x"+Integer.toHexString(ch).toUpperCase()+";"); sb.append("&#x"+Integer.toHexString(ch).toUpperCase()+";");
else if (isNoLines) { else if (isNoLines) {
if (ch == '\r') if (ch == '\r')
sb.append("&#xA;"); sb.append("&#xA;");
else if (ch != '\n') else if (ch != '\n')
sb.append(ch); sb.append(ch);
} }
else else
sb.append(ch); sb.append(ch);
} }
return sb.toString(); return sb.toString();
} }
} }
public static Element getFirstChild(Element e) { public static Element getFirstChild(Element e) {
if (e == null) if (e == null)
return null; return null;
Node n = e.getFirstChild(); Node n = e.getFirstChild();
while (n != null && n.getNodeType() != Node.ELEMENT_NODE) while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
n = n.getNextSibling(); n = n.getNextSibling();
return (Element) n; return (Element) n;
} }
public static Element getNamedChild(Element e, String name) { public static Element getNamedChild(Element e, String name) {
Element c = getFirstChild(e); Element c = getFirstChild(e);
while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName())) while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
c = getNextSibling(c); c = getNextSibling(c);
return c; return c;
} }
public static Element getNextSibling(Element e) { public static Element getNextSibling(Element e) {
Node n = e.getNextSibling(); Node n = e.getNextSibling();
while (n != null && n.getNodeType() != Node.ELEMENT_NODE) while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
n = n.getNextSibling(); n = n.getNextSibling();
return (Element) n; return (Element) n;
} }
public static void getNamedChildren(Element e, String name, List<Element> set) { public static void getNamedChildren(Element e, String name, List<Element> set) {
Element c = getFirstChild(e); Element c = getFirstChild(e);
while (c != null) { while (c != null) {
if (name.equals(c.getLocalName()) || name.equals(c.getNodeName()) ) if (name.equals(c.getLocalName()) || name.equals(c.getNodeName()) )
set.add(c); set.add(c);
c = getNextSibling(c); c = getNextSibling(c);
} }
} }
public static String htmlToXmlEscapedPlainText(Element r) { public static String htmlToXmlEscapedPlainText(Element r) {
StringBuilder s = new StringBuilder(); StringBuilder s = new StringBuilder();
Node n = r.getFirstChild(); Node n = r.getFirstChild();
boolean ws = false; boolean ws = false;
while (n != null) { while (n != null) {
if (n.getNodeType() == Node.TEXT_NODE) { if (n.getNodeType() == Node.TEXT_NODE) {
String t = n.getTextContent().trim(); String t = n.getTextContent().trim();
if (Utilities.noString(t)) if (Utilities.noString(t))
ws = true; ws = true;
else { else {
if (ws) if (ws)
s.append(" "); s.append(" ");
ws = false; ws = false;
s.append(t); s.append(t);
} }
} }
if (n.getNodeType() == Node.ELEMENT_NODE) { if (n.getNodeType() == Node.ELEMENT_NODE) {
if (ws) if (ws)
s.append(" "); s.append(" ");
ws = false; ws = false;
s.append(htmlToXmlEscapedPlainText((Element) n)); s.append(htmlToXmlEscapedPlainText((Element) n));
if (r.getNodeName().equals("br") || r.getNodeName().equals("p")) if (r.getNodeName().equals("br") || r.getNodeName().equals("p"))
s.append("\r\n"); s.append("\r\n");
} }
n = n.getNextSibling(); n = n.getNextSibling();
} }
return s.toString(); return s.toString();
} }
public static String htmlToXmlEscapedPlainText(String definition) throws ParserConfigurationException, SAXException, IOException { public static String htmlToXmlEscapedPlainText(String definition) throws ParserConfigurationException, SAXException, IOException {
return htmlToXmlEscapedPlainText(parseToDom("<div>"+definition+"</div>").getDocumentElement()); return htmlToXmlEscapedPlainText(parseToDom("<div>"+definition+"</div>").getDocumentElement());
} }
public static String elementToString(Element el) { public static String elementToString(Element el) {
if (el == null) if (el == null)
return ""; return "";
Document document = el.getOwnerDocument(); Document document = el.getOwnerDocument();
DOMImplementationLS domImplLS = (DOMImplementationLS) document DOMImplementationLS domImplLS = (DOMImplementationLS) document
.getImplementation(); .getImplementation();
LSSerializer serializer = domImplLS.createLSSerializer(); LSSerializer serializer = domImplLS.createLSSerializer();
return serializer.writeToString(el); return serializer.writeToString(el);
} }
public static String getNamedChildValue(Element element, String name) { public static String getNamedChildValue(Element element, String name) {
Element e = getNamedChild(element, name); Element e = getNamedChild(element, name);
return e == null ? null : e.getAttribute("value"); return e == null ? null : e.getAttribute("value");
} }
public static void setNamedChildValue(Element element, String name, String value) throws FHIRException { public static void setNamedChildValue(Element element, String name, String value) throws FHIRException {
Element e = getNamedChild(element, name); Element e = getNamedChild(element, name);
if (e == null) if (e == null)
throw new FHIRException("unable to find element "+name); throw new FHIRException("unable to find element "+name);
e.setAttribute("value", value); e.setAttribute("value", value);
} }
public static void getNamedChildrenWithWildcard(Element focus, String name, List<Element> children) { public static void getNamedChildrenWithWildcard(Element focus, String name, List<Element> children) {
Element c = getFirstChild(focus); Element c = getFirstChild(focus);
while (c != null) { while (c != null) {
String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName(); String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName();
if (name.equals(n) || (name.endsWith("[x]") && n.startsWith(name.substring(0, name.length()-3)))) if (name.equals(n) || (name.endsWith("[x]") && n.startsWith(name.substring(0, name.length()-3))))
children.add(c); children.add(c);
c = getNextSibling(c); c = getNextSibling(c);
} }
} }
public static void getNamedChildrenWithTails(Element focus, String name, List<Element> children, Set<String> typeTails) { public static void getNamedChildrenWithTails(Element focus, String name, List<Element> children, Set<String> typeTails) {
Element c = getFirstChild(focus); Element c = getFirstChild(focus);
while (c != null) { while (c != null) {
String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName(); String n = c.getLocalName() != null ? c.getLocalName() : c.getNodeName();
if (n.equals(name) || (!n.equals("responseCode") && (n.startsWith(name) && typeTails.contains(n.substring(name.length()))))) if (n.equals(name) || (!n.equals("responseCode") && (n.startsWith(name) && typeTails.contains(n.substring(name.length())))))
children.add(c); children.add(c);
c = getNextSibling(c); c = getNextSibling(c);
} }
} }
public static boolean hasNamedChild(Element e, String name) { public static boolean hasNamedChild(Element e, String name) {
Element c = getFirstChild(e); Element c = getFirstChild(e);
while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName())) while (c != null && !name.equals(c.getLocalName()) && !name.equals(c.getNodeName()))
c = getNextSibling(c); c = getNextSibling(c);
return c != null; return c != null;
} }
public static Document parseToDom(String content) throws ParserConfigurationException, SAXException, IOException { public static Document parseToDom(String content) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false); factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder(); DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(content.getBytes())); return builder.parse(new ByteArrayInputStream(content.getBytes()));
} }
public static Document parseFileToDom(String filename) throws ParserConfigurationException, SAXException, IOException { public static Document parseFileToDom(String filename) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false); factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder(); DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new FileInputStream(filename)); return builder.parse(new FileInputStream(filename));
} }
public static Element getLastChild(Element e) { public static Element getLastChild(Element e) {
if (e == null) if (e == null)
return null; return null;
Node n = e.getLastChild(); Node n = e.getLastChild();
while (n != null && n.getNodeType() != Node.ELEMENT_NODE) while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
n = n.getPreviousSibling(); n = n.getPreviousSibling();
return (Element) n; return (Element) n;
} }
public static Element getPrevSibling(Element e) { public static Element getPrevSibling(Element e) {
Node n = e.getPreviousSibling(); Node n = e.getPreviousSibling();
while (n != null && n.getNodeType() != Node.ELEMENT_NODE) while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
n = n.getPreviousSibling(); n = n.getPreviousSibling();
return (Element) n; return (Element) n;
} }
public static String getNamedChildAttribute(Element element, String name, String aname) { public static String getNamedChildAttribute(Element element, String name, String aname) {
Element e = getNamedChild(element, name); Element e = getNamedChild(element, name);
return e == null ? null : e.getAttribute(aname); return e == null ? null : e.getAttribute(aname);
} }
public static void writeDomToFile(Document doc, String filename) throws TransformerException { public static void writeDomToFile(Document doc, String filename) throws TransformerException {
TransformerFactory transformerFactory = TransformerFactory.newInstance(); TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(); Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc); DOMSource source = new DOMSource(doc);
StreamResult streamResult = new StreamResult(new File(filename)); StreamResult streamResult = new StreamResult(new File(filename));
transformer.transform(source, streamResult); transformer.transform(source, streamResult);
} }
public static String getXsiType(org.w3c.dom.Element element) { public static String getXsiType(org.w3c.dom.Element element) {
Attr a = element.getAttributeNodeNS("http://www.w3.org/2001/XMLSchema-instance", "type"); Attr a = element.getAttributeNodeNS("http://www.w3.org/2001/XMLSchema-instance", "type");
return (a == null ? null : a.getTextContent()); return (a == null ? null : a.getTextContent());
} }
public static String getDirectText(org.w3c.dom.Element node) { public static String getDirectText(org.w3c.dom.Element node) {
Node n = node.getFirstChild(); Node n = node.getFirstChild();
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
while (n != null) { while (n != null) {
if (n.getNodeType() == Node.TEXT_NODE) if (n.getNodeType() == Node.TEXT_NODE)
b.append(n.getTextContent()); b.append(n.getTextContent());
n = n.getNextSibling(); n = n.getNextSibling();
} }
return b.toString().trim(); return b.toString().trim();
} }
} }

View File

@ -57,7 +57,7 @@ public class GraphQLDstu3ProviderTest {
@Ignore @Ignore
public void testGraphInstance() throws Exception { public void testGraphInstance() throws Exception {
String query = "{name{family,given}}"; String query = "{name{family,given}}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escape(query)); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -84,7 +84,7 @@ public class GraphQLDstu3ProviderTest {
@Ignore @Ignore
public void testGraphInstanceWithFhirpath() throws Exception { public void testGraphInstanceWithFhirpath() throws Exception {
String query = "{name(fhirpath:\"family.exists()\"){text,given,family}}"; String query = "{name(fhirpath:\"family.exists()\"){text,given,family}}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escape(query)); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -109,7 +109,7 @@ public class GraphQLDstu3ProviderTest {
@org.junit.Ignore @org.junit.Ignore
public void testGraphSystemInstance() throws Exception { public void testGraphSystemInstance() throws Exception {
String query = "{Patient(id:123){id,name{given,family}}}"; String query = "{Patient(id:123){id,name{given,family}}}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escape(query)); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -138,7 +138,7 @@ public class GraphQLDstu3ProviderTest {
@Ignore @Ignore
public void testGraphSystemList() throws Exception { public void testGraphSystemList() throws Exception {
String query = "{PatientList(name:\"pet\"){name{family,given}}}"; String query = "{PatientList(name:\"pet\"){name{family,given}}}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escape(query)); HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet); CloseableHttpResponse status = ourClient.execute(httpGet);
try { try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);

View File

@ -11,6 +11,12 @@
Fix a crash in JPA server when performing a recursive Fix a crash in JPA server when performing a recursive
<![CDATA[<code>_include</code>]]> which doesn't actually find any matches. <![CDATA[<code>_include</code>]]> which doesn't actually find any matches.
</action> </action>
<action type="fix" issue="796">
When encoding URL parameter values, HAPI FHIR would incorrectly escape
a space (" ") as a plus ("+") insetad of as "%20" as required by
RFC 3986. This affects client calls, as well as URLs generated by
the server (e.g. REST HOOK calls). Thanks to James Daily for reporting!
</action>
</release> </release>
<release version="3.1.0" date="2017-11-23"> <release version="3.1.0" date="2017-11-23">
<action type="add"> <action type="add">