From 4032a2674d7e7aee4463194d3fa7e589f0fa9558 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Fri, 28 Aug 2015 11:35:12 -0400 Subject: [PATCH 1/6] Force UTF-8 on all sources to hopefully avoid compile issues on Windows --- .../fhir/tinder/ResourceMinimizerMojo.java | 12 +- .../ca/uhn/fhir/tinder/TinderClientMojo.java | 6 +- .../fhir/tinder/TinderJpaRestServerMojo.java | 6 +- .../ca/uhn/fhir/tinder/ValueSetGenerator.java | 7 +- .../tinder/parser/BaseStructureParser.java | 3 +- .../ca/uhn/fhir/tinder/util/SyncUtil.java | 7 +- .../ca/uhn/fhir/util/VersionSynchronizer.java | 151 ------------------ pom.xml | 2 +- 8 files changed, 26 insertions(+), 168 deletions(-) delete mode 100644 hapi-tinder-plugin/src/test/java/ca/uhn/fhir/util/VersionSynchronizer.java diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ResourceMinimizerMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ResourceMinimizerMojo.java index 03f13ce0f7b..779ddf698a6 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ResourceMinimizerMojo.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ResourceMinimizerMojo.java @@ -3,8 +3,10 @@ package ca.uhn.fhir.tinder; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; -import java.io.FileWriter; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; import java.net.URL; import java.util.Collection; @@ -120,9 +122,11 @@ public class ResourceMinimizerMojo extends AbstractMojo { if (!inputString.equals(outputString)) { ourLog.info("Trimming contents of resource: {} - From {} to {}", nextFile, FileUtils.byteCountToDisplaySize(inputString.length()), FileUtils.byteCountToDisplaySize(outputString.length())); try { - BufferedWriter writer = new BufferedWriter(new FileWriter(nextFile.getAbsolutePath(), false)); - writer.append(outputString); - writer.close(); + String f = nextFile.getAbsolutePath(); + Writer w = new OutputStreamWriter(new FileOutputStream(f, false), "UTF-8"); + w = new BufferedWriter(w); + w.append(outputString); + w.close(); } catch (IOException e) { throw new MojoFailureException("Failed to write " + nextFile, e); } diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderClientMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderClientMojo.java index b5cde76bd0c..498da723e53 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderClientMojo.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderClientMojo.java @@ -1,10 +1,11 @@ package ca.uhn.fhir.tinder; import java.io.File; -import java.io.FileWriter; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; @@ -154,7 +155,8 @@ public class TinderClientMojo extends AbstractMojo { private void write() throws IOException { File file = new File(myDirectoryBase, myClientClassSimpleName + ".java"); - FileWriter w = new FileWriter(file, false); + OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(file, false), "UTF-8"); + ourLog.debug("Writing file: {}", file.getAbsolutePath()); diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java index 26bbad641c2..b655d5f40d2 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java @@ -1,10 +1,11 @@ package ca.uhn.fhir.tinder; import java.io.File; -import java.io.FileWriter; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; import java.util.Properties; @@ -157,7 +158,8 @@ public class TinderJpaRestServerMojo extends AbstractMojo { InputStreamReader templateReader = new InputStreamReader(templateIs); targetResourceDirectory.mkdirs(); - FileWriter w = new FileWriter(new File(targetResourceDirectory, targetResourceSpringBeansFile)); + File f = new File(targetResourceDirectory, targetResourceSpringBeansFile); + OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(f, false), "UTF-8"); v.evaluate(ctx, w, "", templateReader); w.close(); diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ValueSetGenerator.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ValueSetGenerator.java index 5bf5a8bac08..a05ed623e74 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ValueSetGenerator.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ValueSetGenerator.java @@ -2,11 +2,12 @@ package ca.uhn.fhir.tinder; import java.io.File; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -287,7 +288,7 @@ public class ValueSetGenerator { } File f = new File(theOutputDirectory, theValueSetTm.getClassName() + ".java"); - FileWriter w = new FileWriter(f, false); + OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(f, false), "UTF-8"); ourLog.debug("Writing file: {}", f.getAbsolutePath()); @@ -302,7 +303,7 @@ public class ValueSetGenerator { v.setProperty("runtime.references.strict", Boolean.TRUE); InputStream templateIs = ResourceGeneratorUsingSpreadsheet.class.getResourceAsStream("/vm/valueset.vm"); - InputStreamReader templateReader = new InputStreamReader(templateIs); + InputStreamReader templateReader = new InputStreamReader(templateIs, "UTF-8"); v.evaluate(ctx, w, "", templateReader); w.close(); diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java index cf5ab3f5080..5bbaf59c116 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java @@ -5,7 +5,6 @@ import static org.apache.commons.lang.StringUtils.isNotBlank; import java.io.File; import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -522,7 +521,7 @@ public abstract class BaseStructureParser { try { File versionFile = new File(theResourceOutputDirectory, "fhirversion.properties"); - FileWriter w = new FileWriter(versionFile, false); + OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(versionFile, false), "UTF-8"); ourLog.debug("Writing file: {}", versionFile.getAbsolutePath()); diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/util/SyncUtil.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/util/SyncUtil.java index b8ae5ecbffd..950ce7c1b82 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/util/SyncUtil.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/util/SyncUtil.java @@ -1,9 +1,9 @@ package ca.uhn.fhir.tinder.util; import java.io.File; -import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileReader; -import java.io.FileWriter; +import java.io.OutputStreamWriter; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.dstu2.composite.NarrativeDt; @@ -24,7 +24,8 @@ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger nextRes.setText(new NarrativeDt()); } - FileWriter fw = new FileWriter(new File(fileName), false); + File f = new File(fileName); + OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(f, false), "UTF-8"); ctx.newXmlParser().encodeResourceToWriter(b, fw); fw.close(); diff --git a/hapi-tinder-plugin/src/test/java/ca/uhn/fhir/util/VersionSynchronizer.java b/hapi-tinder-plugin/src/test/java/ca/uhn/fhir/util/VersionSynchronizer.java deleted file mode 100644 index b8f7ee5a1ba..00000000000 --- a/hapi-tinder-plugin/src/test/java/ca/uhn/fhir/util/VersionSynchronizer.java +++ /dev/null @@ -1,151 +0,0 @@ -package ca.uhn.fhir.util; - -import static org.apache.commons.lang3.StringUtils.isBlank; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.ini4j.Ini; -import org.ini4j.Profile.Section; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.model.dstu2.composite.NarrativeDt; -import ca.uhn.fhir.model.dstu2.resource.BaseResource; -import ca.uhn.fhir.model.dstu2.resource.Bundle; -import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; - -public class VersionSynchronizer { - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(VersionSynchronizer.class); - - public static void main(String[] args) throws Exception { - - Set resources = new TreeSet(); - { - String str = IOUtils.toString(new FileReader("../hapi-fhir-structures-dstu2/pom.xml")); - Matcher m = Pattern.compile("baseResourceName.([a-zA-Z]+)..baseResourceName").matcher(str); - while (m.find()) { - String name = m.group(1).toLowerCase(); - resources.add(name); - } - } - - ourLog.info("POM resource names: " + resources); - - String buildDir = "/Users/t3903uhn/workspace/fhirbuild/trunk/build"; - ArrayList lines = new ArrayList(Arrays.asList(IOUtils.toString(new FileReader(new File(buildDir + "/source", "fhir.ini"))).split("\\r?\\n"))); - for (int i = 0; i < lines.size(); i++) { - String next = lines.get(i); - if (next.startsWith("=") || next.startsWith(" ")) { - lines.remove(i); - i--; - continue; - } - - if (isBlank(next)) { - continue; - } - - if (Character.isAlphabetic(next.charAt(0)) && next.indexOf('=') == -1) { - lines.set(i, next + '='); - continue; - } - - } - - Ini ini = new Ini(new StringReader(StringUtils.join(lines, '\n'))); - Section resourceSects = ini.get("resources"); - - ourLog.info("Copying resource spreadsheets"); - - TreeSet resourceNames = new TreeSet(resourceSects.keySet()); - resourceNames.add("parameters"); - - for (String nextResource : new ArrayList(resourceNames)) { - nextResource = nextResource.toLowerCase(); - ourLog.info(" * Resource: {}", nextResource); - - File spreadsheetFile = new File(buildDir + "/source/" + nextResource + "/" + nextResource + "-spreadsheet.xml"); - if (!spreadsheetFile.exists()) { - throw new Exception("Unknown file: " + spreadsheetFile); - } - FileUtils.copyFile(spreadsheetFile, new File("src/main/resources/res/dstu2/" + nextResource + "-spreadsheet.xml")); - - if (!resources.contains(nextResource)) { - throw new Exception("POM needs:\n" + nextResource+""); - } - resources.remove(nextResource); - } - - if (resources.size() > 0) { - throw new Exception("POM has unneeded resources: " + resources); - } - - ourLog.info("Copying datatypes"); - - Collection dtFiles = FileUtils.listFiles(new File(buildDir+"/source/datatypes"), new String[] {"xml"}, false); - for (File file : dtFiles) { - if (file.getName().contains("-")) { - continue; - } - ourLog.info("Datatype: {}", file.getName()); - File destFile = new File("src/main/resources/dt/dstu2/" + file.getName()); - FileUtils.copyFile(file, destFile); -// ourLog.info("Copied to {}", destFile.getAbsolutePath()); - } - - ourLog.info("Copying ValueSets"); - - FileUtils.copyFile(new File(buildDir + "/publish/valuesets.xml"), new File("src/main/resources/vs/dstu2/all-valuesets-bundle.xml")); - - { - ourLog.info("Shrinking valueset file"); - String fileName = "src/main/resources/vs/dstu2/all-valuesets-bundle.xml"; - FileReader fr = new FileReader(fileName); - FhirContext ctx = FhirContext.forDstu2(); - Bundle b = ctx.newXmlParser().parseResource(Bundle.class, fr); - for (Entry nextEntry : b.getEntry()) { - BaseResource nextRes = (BaseResource) nextEntry.getResource(); - nextRes.setText(new NarrativeDt()); - } - - FileWriter fw = new FileWriter(new File(fileName), false); - ctx.newXmlParser().encodeResourceToWriter(b, fw); - fw.close(); - - ourLog.info("Fixed {} valuesets", b.getEntry().size()); - } - - ourLog.info("Copying Schematron files"); - - Collection schFiles = FileUtils.listFiles(new File(buildDir+"/publish"), new String[] {"sch"}, false); - for (File file : schFiles) { - ourLog.info("Schematron: {}", file.getName()); - File destFile = new File("../hapi-fhir-structures-dstu2/src/main/resources/ca/uhn/fhir/model/dstu2/schema/" + file.getName()); - FileUtils.copyFile(file, destFile); -// ourLog.info("Copied to {}", destFile.getAbsolutePath()); - } - - ourLog.info("Copying XSD"); - FileUtils.copyFile(new File(buildDir + "/publish/fhir-single.xsd"), new File("../hapi-fhir-structures-dstu2/src/main/resources/ca/uhn/fhir/model/dstu2/schema/fhir-single.xsd")); - FileUtils.copyFile(new File(buildDir + "/publish/xml.xsd"), new File("../hapi-fhir-structures-dstu2/src/main/resources/ca/uhn/fhir/model/dstu2/schema/xml.xsd")); - FileUtils.copyFile(new File(buildDir + "/publish/fhir-xhtml.xsd"), new File("../hapi-fhir-structures-dstu2/src/main/resources/ca/uhn/fhir/model/dstu2/schema/fhir-xhtml.xsd")); - - } - - - -} diff --git a/pom.xml b/pom.xml index 04776249957..b6f490c01d2 100644 --- a/pom.xml +++ b/pom.xml @@ -231,7 +231,6 @@ 1.1.8 2.7.1 4.3.6 - UTF-8 1.7.10 4.1.5.RELEASE 3.2.4.RELEASE @@ -400,6 +399,7 @@ 1.6 javac-with-errorprone true + UTF-8 From bd13b53099325b7b6ad8d72fddd37e688c101d92 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Fri, 28 Aug 2015 15:36:56 -0400 Subject: [PATCH 2/6] Fix #212 - Dont accept invalid IDs but do accept IDs starting with a number --- .../ca/uhn/fhir/model/primitive/IdDt.java | 102 ++-- .../ca/uhn/fhir/rest/param/TokenParam.java | 26 +- .../hl7/fhir/instance/model/api/IIdType.java | 13 + .../ca/uhn/fhir/i18n/hapi-messages.properties | 3 +- hapi-fhir-examples-uploader/pom.xml | 9 +- .../ca/uhn/fhir/exampleuploader/Uploader.java | 24 +- .../fhir/jpa/dao/BaseHapiFhirResourceDao.java | 10 +- .../jpa/dao/SearchParamExtractorDstu2.java | 142 +++-- .../jpa/dao/FhirResourceDaoDstu1Test.java | 4 +- .../jpa/dao/FhirResourceDaoDstu2Test.java | 571 ++++++++++-------- .../provider/ResourceProviderDstu2Test.java | 490 ++++++++------- .../ca/uhn/fhir/model/primitive/IdDtTest.java | 14 + .../org/hl7/fhir/instance/model/IdType.java | 28 +- src/changes/changes.xml | 9 + 14 files changed, 818 insertions(+), 627 deletions(-) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java index 5bca7c1b121..c1d6fabacf6 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/IdDt.java @@ -199,6 +199,34 @@ public class IdDt extends UriDt implements IPrimitiveDatatype, IIdType { return getIdPartAsBigDecimal(); } + private String determineLocalPrefix(String theValue) { + if (theValue == null || theValue.isEmpty()) { + return null; + } + if (theValue.startsWith("#")) { + return "#"; + } + int lastPrefix = -1; + for (int i = 0; i < theValue.length(); i++) { + char nextChar = theValue.charAt(i); + if (nextChar == ':') { + lastPrefix = i; + } else if (!Character.isLetter(nextChar) || !Character.isLowerCase(nextChar)) { + break; + } + } + if (lastPrefix != -1) { + String candidate = theValue.substring(0, lastPrefix + 1); + if (candidate.startsWith("cid:") || candidate.startsWith("urn:")) { + return candidate; + } else { + return null; + } + } else { + return null; + } + } + @Override public boolean equals(Object theArg0) { if (!(theArg0 instanceof IdDt)) { @@ -383,6 +411,34 @@ public class IdDt extends UriDt implements IPrimitiveDatatype, IIdType { return isBlank(getValue()); } + @Override + public boolean isIdPartValid() { + String id = getIdPart(); + if (StringUtils.isBlank(id)) { + return false; + } + if (id.length() > 64) { + return false; + } + for (int i = 0; i < id.length(); i++) { + char nextChar = id.charAt(i); + if (nextChar >= 'a' && nextChar <= 'z') { + continue; + } + if (nextChar >= 'A' && nextChar <= 'Z') { + continue; + } + if (nextChar >= '0' && nextChar <= '9') { + continue; + } + if (nextChar == '-' || nextChar == '.') { + continue; + } + return false; + } + return true; + } + /** * Returns true if the unqualified ID is a valid {@link Long} value (in other words, it consists only of digits) */ @@ -407,7 +463,7 @@ public class IdDt extends UriDt implements IPrimitiveDatatype, IIdType { public boolean isLocal() { return "#".equals(myBaseUrl); } - + /** * Copies the value from the given IdDt to this IdDt. It is generally not neccesary to use this method but it is provided for consistency with the rest of the API. */ @@ -416,34 +472,6 @@ public class IdDt extends UriDt implements IPrimitiveDatatype, IIdType { setValue(theId.getValue()); } - private String determineLocalPrefix(String theValue) { - if (theValue == null || theValue.isEmpty()) { - return null; - } - if (theValue.startsWith("#")) { - return "#"; - } - int lastPrefix = -1; - for (int i = 0; i < theValue.length(); i++) { - char nextChar = theValue.charAt(i); - if (nextChar == ':') { - lastPrefix = i; - } else if (!Character.isLetter(nextChar) || !Character.isLowerCase(nextChar)) { - break; - } - } - if (lastPrefix != -1) { - String candidate = theValue.substring(0, lastPrefix + 1); - if (candidate.startsWith("cid:") || candidate.startsWith("urn:")) { - return candidate; - } else { - return null; - } - } else { - return null; - } - } - /** * Set the value * @@ -602,6 +630,14 @@ public class IdDt extends UriDt implements IPrimitiveDatatype, IIdType { return new IdDt(value + '/' + Constants.PARAM_HISTORY + '/' + theVersion); } + /** + * Construct a new ID with with form "urn:uuid:[UUID]" where [UUID] is a new, randomly + * created UUID generated by {@link UUID#randomUUID()} + */ + public static IdDt newRandomUuid() { + return new IdDt("urn:uuid:" + UUID.randomUUID().toString()); + } + /** * Retrieves the ID from the given resource instance */ @@ -634,12 +670,4 @@ public class IdDt extends UriDt implements IPrimitiveDatatype, IIdType { return theIdPart.toString(); } - /** - * Construct a new ID with with form "urn:uuid:[UUID]" where [UUID] is a new, randomly - * created UUID generated by {@link UUID#randomUUID()} - */ - public static IdDt newRandomUuid() { - return new IdDt("urn:uuid:" + UUID.randomUUID().toString()); - } - } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/TokenParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/TokenParam.java index b99cb6d4b6c..c137982b48c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/TokenParam.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/TokenParam.java @@ -42,20 +42,22 @@ public class TokenParam extends BaseParam implements IQueryParameterType { } /** - * Constructor which copies the {@link InternalCodingDt#getSystemElement() system} and {@link InternalCodingDt#getCodeElement() code} from a {@link InternalCodingDt} instance and adds it as a parameter + * Constructor which copies the {@link InternalCodingDt#getSystemElement() system} and {@link InternalCodingDt#getCodeElement() code} from a {@link InternalCodingDt} instance and adds it as a + * parameter * * @param theCodingDt - * The coding + * The coding */ public TokenParam(BaseCodingDt theCodingDt) { this(toSystemValue(theCodingDt.getSystemElement()), theCodingDt.getCodeElement().getValue()); } /** - * Constructor which copies the {@link BaseIdentifierDt#getSystemElement() system} and {@link BaseIdentifierDt#getValueElement() value} from a {@link BaseIdentifierDt} instance and adds it as a parameter + * Constructor which copies the {@link BaseIdentifierDt#getSystemElement() system} and {@link BaseIdentifierDt#getValueElement() value} from a {@link BaseIdentifierDt} instance and adds it as a + * parameter * * @param theIdentifierDt - * The identifier + * The identifier */ public TokenParam(BaseIdentifierDt theIdentifierDt) { this(toSystemValue(theIdentifierDt.getSystemElement()), theIdentifierDt.getValueElement().getValue()); @@ -102,12 +104,18 @@ public class TokenParam extends BaseParam implements IQueryParameterType { */ @Override void doSetValueAsQueryToken(String theQualifier, String theParameter) { - int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|'); - if (barIndex != -1) { - setSystem(theParameter.substring(0, barIndex)); - setValue(ParameterUtil.unescape(theParameter.substring(barIndex + 1))); + setText(Constants.PARAMQUALIFIER_TOKEN_TEXT.equals(theQualifier)); + setSystem(null); + if (theParameter == null) { + setValue(null); } else { - setValue(ParameterUtil.unescape(theParameter)); + int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|'); + if (barIndex != -1) { + setSystem(theParameter.substring(0, barIndex)); + setValue(ParameterUtil.unescape(theParameter.substring(barIndex + 1))); + } else { + setValue(ParameterUtil.unescape(theParameter)); + } } } diff --git a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java index 0f677f30e9f..83ee0c179ca 100644 --- a/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java +++ b/hapi-fhir-base/src/main/java/org/hl7/fhir/instance/model/api/IIdType.java @@ -92,6 +92,19 @@ public interface IIdType { */ boolean isAbsolute(); + /** + * Returns true if the {@link #getIdPart() ID part of this object} is valid according to the FHIR rules for valid IDs. + *

+ * The FHIR specification states: + * Any combination of upper or lower case ASCII letters ('A'..'Z', and 'a'..'z', numerals ('0'..'9'), '-' and '.', with a length limit of 64 characters. (This might be an integer, an un-prefixed OID, UUID or any other identifier pattern that meets these constraints.) regex: [A-Za-z0-9\-\.]{1,64} + *

+ */ + boolean isIdPartValid(); + + /** + * Returns true if the {@link #getIdPart() ID part of this object} contains + * only numbers + */ boolean isIdPartValidLong(); Long getIdPartAsLong(); diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties index adf8561ad44..cc8cb51002e 100644 --- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties @@ -52,7 +52,8 @@ ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.transactionMissingUrl=Unable to perfor ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.transactionInvalidUrl=Unable to perform {0}, URL provided is invalid: {1} ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.duplicateCreateForcedId=Can not create entity with ID[{0}], a resource with this ID already exists -ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedNumericId=Can not create resource with ID[{0}], no resource with this ID exists and clients may only assign IDs which begin with a non-numeric character on this server +ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithInvalidId=Can not process entity with ID[{0}], this is not a valid FHIR ID +ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedNumericId=Can not create resource with ID[{0}], no resource with this ID exists and clients may only assign IDs which contain at least one non-numeric character ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.failedToCreateWithClientAssignedId=Can not create resource with ID[{0}], ID must not be supplied on a create (POST) operation ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.invalidParameterChain=Invalid parameter chain: {0} ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.multipleParamsWithSameNameOneIsMissingTrue=This server does not know how to handle multiple "{0}" parameters where one has a value of :missing=true diff --git a/hapi-fhir-examples-uploader/pom.xml b/hapi-fhir-examples-uploader/pom.xml index 459f934e3ad..9816aeb379d 100644 --- a/hapi-fhir-examples-uploader/pom.xml +++ b/hapi-fhir-examples-uploader/pom.xml @@ -18,7 +18,6 @@ ca.uhn.hapi.example hapi-fhir-examples-uploader - 1.1-SNAPSHOT jar HAPI FHIR - Examples Uploader @@ -36,17 +35,19 @@ hapi-fhir-structures-dstu2 1.1-SNAPSHOT
+ + ca.uhn.hapi.fhir + hapi-fhir-structures-hl7org-dstu2 + 1.1-SNAPSHOT + ch.qos.logback logback-classic - 1.1.2 javax.servlet javax.servlet-api - 3.0.1 - provided diff --git a/hapi-fhir-examples-uploader/src/main/java/ca/uhn/fhir/exampleuploader/Uploader.java b/hapi-fhir-examples-uploader/src/main/java/ca/uhn/fhir/exampleuploader/Uploader.java index 37993cd9b90..af23cbec540 100644 --- a/hapi-fhir-examples-uploader/src/main/java/ca/uhn/fhir/exampleuploader/Uploader.java +++ b/hapi-fhir-examples-uploader/src/main/java/ca/uhn/fhir/exampleuploader/Uploader.java @@ -2,7 +2,6 @@ package ca.uhn.fhir.exampleuploader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -10,7 +9,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.commons.io.IOUtils; -import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; @@ -113,10 +111,10 @@ public class Uploader { for (Entry next : bundle.getEntry()) { List refs = ctx.newTerser().getAllResourceReferences(next.getResource()); for (ResourceReferenceInfo nextRef : refs) { -// if (nextRef.getResourceReference().getReferenceElement().isAbsolute()) { -// ourLog.info("Discarding absolute reference: {}", nextRef.getResourceReference().getReferenceElement().getValue()); -// nextRef.getResourceReference().getReferenceElement().setValue(null); -// } + // if (nextRef.getResourceReference().getReferenceElement().isAbsolute()) { + // ourLog.info("Discarding absolute reference: {}", nextRef.getResourceReference().getReferenceElement().getValue()); + // nextRef.getResourceReference().getReferenceElement().setValue(null); + // } nextRef.getResourceReference().getReferenceElement().setValue(nextRef.getResourceReference().getReferenceElement().toUnqualifiedVersionless().getValue()); String value = nextRef.getResourceReference().getReferenceElement().toUnqualifiedVersionless().getValue(); if (!ids.contains(value) && !nextRef.getResourceReference().getReferenceElement().isLocal()) { @@ -127,13 +125,13 @@ public class Uploader { } } } - -// for (Entry next : bundle.getEntry()) { -// if (next.getResource().getId().hasIdPart() && Character.isLetter(next.getResource().getId().getIdPart().charAt(0))) { -// next.getTransaction().setUrl(next.getResource().getResourceName() + '/' + next.getResource().getId().getIdPart()); -// next.getTransaction().setMethod(HTTPVerbEnum.PUT); -// } -// } + + // for (Entry next : bundle.getEntry()) { + // if (next.getResource().getId().hasIdPart() && Character.isLetter(next.getResource().getId().getIdPart().charAt(0))) { + // next.getTransaction().setUrl(next.getResource().getResourceName() + '/' + next.getResource().getId().getIdPart()); + // next.getTransaction().setMethod(HTTPVerbEnum.PUT); + // } + // } ourLog.info("{} good references", goodRefs); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index 116b7ea15f6..fa5a3b2798d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -1696,13 +1696,17 @@ public abstract class BaseHapiFhirResourceDao extends BaseH } /** - * May be implemented by subclasses to validate resources prior to storage + * May be overridden by subclasses to validate resources prior to storage * * @param theResource * The resource that is about to be stored */ protected void preProcessResourceForStorage(T theResource) { - // nothing by default + if (theResource.getId().hasIdPart()) { + if (!theResource.getId().isIdPartValid()) { + throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithInvalidId", theResource.getId().getIdPart())); + } + } } @Override @@ -2296,7 +2300,7 @@ public abstract class BaseHapiFhirResourceDao extends BaseH try { entity = readEntityLatestVersion(resourceId); } catch (ResourceNotFoundException e) { - if (Character.isDigit(theResource.getId().getIdPart().charAt(0))) { + if (resourceId.isIdPartValidLong()) { throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedNumericId", theResource.getId().getIdPart())); } return doCreate(theResource, null, thePerformIndexing); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java index c7cfddfe237..a967c8393f1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java @@ -32,6 +32,7 @@ import javax.measure.quantity.Quantity; import javax.measure.unit.NonSI; import javax.measure.unit.Unit; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import ca.uhn.fhir.context.ConfigurationException; @@ -80,8 +81,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen /* * (non-Javadoc) * - * @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable, - * ca.uhn.fhir.model.api.IResource) + * @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource) */ @Override public List extractSearchParamDates(ResourceTable theEntity, IResource theResource) { @@ -143,8 +143,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen /* * (non-Javadoc) * - * @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable, - * ca.uhn.fhir.model.api.IResource) + * @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource) */ @Override public ArrayList extractSearchParamNumber(ResourceTable theEntity, IResource theResource) { @@ -191,18 +190,12 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen nextValue = newValue; /* - * @SuppressWarnings("unchecked") PhysicsUnit> unit = (PhysicsUnit>) - * UCUMFormat.getCaseInsensitiveInstance().parse(nextValue.getCode().getValue(), null); if - * (unit.isCompatible(UCUM.DAY)) { + * @SuppressWarnings("unchecked") PhysicsUnit> unit = (PhysicsUnit>) + * UCUMFormat.getCaseInsensitiveInstance().parse(nextValue.getCode().getValue(), null); if (unit.isCompatible(UCUM.DAY)) { * - * @SuppressWarnings("unchecked") PhysicsUnit timeUnit - * = (PhysicsUnit