Re-enable errorprone on standard hapi fhir build. woohoo!

This commit is contained in:
James Agnew 2017-10-15 11:27:30 -04:00
parent 2b230d3d9c
commit 9ca85b4cf3
26 changed files with 11002 additions and 11164 deletions

View File

@ -22,4 +22,4 @@ before_script:
script:
# - mvn -e -B clean install && cd hapi-fhir-ra && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID clean test jacoco:report coveralls:report
# - mvn -Dci=true -e -B -P ALLMODULES,NOPARALLEL,ERRORPRONE clean install && cd hapi-fhir-jacoco && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID jacoco:report coveralls:report
- mvn -Dci=true -e -B -P ALLMODULES,MINPARALLEL clean install && cd hapi-fhir-jacoco && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID jacoco:report coveralls:report
- mvn -Dci=true -e -B -P ALLMODULES,MINPARALLEL,ERRORPRONE clean install && cd hapi-fhir-jacoco && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID jacoco:report coveralls:report

View File

@ -63,6 +63,60 @@
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.basepom.maven</groupId>
<artifactId>duplicate-finder-maven-plugin</artifactId>
<executions>
<execution>
<id>default</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
<inherited>true</inherited>
</execution>
</executions>
<configuration>
<printEqualFiles>false</printEqualFiles>
<failBuildInCaseOfDifferentContentConflict>true</failBuildInCaseOfDifferentContentConflict>
<failBuildInCaseOfEqualContentConflict>true</failBuildInCaseOfEqualContentConflict>
<failBuildInCaseOfConflict>true</failBuildInCaseOfConflict>
<checkCompileClasspath>true</checkCompileClasspath>
<checkRuntimeClasspath>false</checkRuntimeClasspath>
<checkTestClasspath>false</checkTestClasspath>
<skip>false</skip>
<quiet>false</quiet>
<preferLocal>true</preferLocal>
<useResultFile>true</useResultFile>
<resultFileMinClasspathCount>2</resultFileMinClasspathCount>
<resultFile>${project.build.directory}/duplicate-finder-result.xml</resultFile>
<ignoredDependencies>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
</dependency>
<dependency>
<groupId>com.phloc</groupId>
<artifactId>phloc-commons</artifactId>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
<dependency>
<groupId>org.jscience</groupId>
<artifactId>jscience</artifactId>
</dependency>
</ignoredDependencies>
<ignoredResources>
<ignoredResource>changelog.txt</ignoredResource>
</ignoredResources>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -152,7 +152,8 @@ public class RuntimeSearchParam {
public enum RuntimeSearchParamStatusEnum {
ACTIVE,
DRAFT,
RETIRED
RETIRED,
UNKNOWN
}
}

View File

@ -1346,7 +1346,7 @@ public class VersionConvertor_14_40 {
org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionSlicingComponent tgt = new org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionSlicingComponent();
copyElement(src, tgt);
for (org.hl7.fhir.dstu2016may.model.StringType t : src.getDiscriminator())
tgt.addDiscriminator(ProfileUtilities.interpretR2Discriminator(t.getValue()));
tgt.addDiscriminator(ProfileUtilities.interpretR2Discriminator(t.getValue(), true));
if (src.hasDescription())
tgt.setDescription(src.getDescription());
if (src.hasOrdered())

View File

@ -1,83 +0,0 @@
package org.hl7.fhir.utilities;
/*
* #%L
* HAPI FHIR - Converter
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public class OIDUtils {
/*
2.16.840.1.113883.3.72.5.2 - NIST owns this
2.16.840.1.113883.4.6 - National Provider Identifier
2.16.840.1.113883.6.21 - UB92
2.16.840.1.113883.6.69 - NDC
*/
public static String getUriForOid(String r) {
if (r.equals("2.16.840.1.113883.6.96"))
return "http://snomed.info/sct";
if (r.equals("2.16.840.1.113883.6.1"))
return "http://loinc.org";
if (r.equals("2.16.840.1.113883.6.8"))
return "http://unitsofmeasure.org";
if (r.equals("2.16.840.1.113883.6.3"))
return "http://hl7.org/fhir/sid/icd-10";
if (r.equals("2.16.840.1.113883.6.42"))
return "http://hl7.org/fhir/sid/icd-9";
if (r.equals("2.16.840.1.113883.6.104"))
return "http://hl7.org/fhir/sid/icd-9";
if (r.equals("2.16.840.1.113883.6.103"))
return "http://hl7.org/fhir/sid/icd-9"; //todo: confirm this
if (r.equals("2.16.840.1.113883.6.73"))
return "http://hl7.org/fhir/sid/atc";
if (r.equals("2.16.840.1.113883.3.26.1.1"))
return "http://ncimeta.nci.nih.gov";
if (r.equals("2.16.840.1.113883.3.26.1.1.1"))
return "http://ncimeta.nci.nih.gov";
if (r.equals("2.16.840.1.113883.6.88"))
return "http://www.nlm.nih.gov/research/umls/rxnorm"; // todo: confirm this
if (r.equals("2.16.840.1.113883.5.1008"))
return "http://hl7.org/fhir/v3/NullFlavor";
if (r.equals("2.16.840.1.113883.5.111"))
return "http://hl7.org/fhir/v3/RoleCode";
if (r.equals("2.16.840.1.113883.5.4"))
return "http://hl7.org/fhir/v3/ActCode";
if (r.equals("2.16.840.1.113883.5.8"))
return "http://hl7.org/fhir/v3/ActReason";
if (r.equals("2.16.840.1.113883.5.83"))
return "http://hl7.org/fhir/v3/ObservationInterpretation";
if (r.equals("2.16.840.1.113883.6.238"))
return "http://hl7.org/fhir/v3/Race";
if (r.equals("2.16.840.1.113883.6.59"))
return "http://hl7.org/fhir/sid/cvx";
if (r.equals("2.16.840.1.113883.12.292"))
return "http://hl7.org/fhir/sid/cvx";
if (r.equals("2.16.840.1.113883.6.12"))
return "http://www.ama-assn.org/go/cpt";
if (r.startsWith("2.16.840.1.113883.12."))
return "http://hl7.org/fhir/sid/v2-"+r.substring(21);
return null;
}
}

View File

@ -1,193 +0,0 @@
package org.hl7.fhir.utilities.ucum;
/*
* #%L
* HAPI FHIR - Converter
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
/*******************************************************************************
* Crown Copyright (c) 2006+, Copyright (c) 2006 - 2014 Kestral Computing & Health Intersections.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Kestral Computing P/L - initial implementation
* Health Intersections - ongoing maintenance
*******************************************************************************/
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.exceptions.UcumException;
/**
* General Ucum Service
*
* UCUM functionality that is useful for applications that make use of UCUM codes
*
* This is a tightly bound interface - consumers use the internal model classes
*
* @author Grahame Grieve
*
*/
public interface UcumService {
public class UcumVersionDetails {
private Date releaseDate;
private String version;
/**
* @param releaseDate
* @param version
*/
public UcumVersionDetails(Date releaseDate, String version) {
super();
this.releaseDate = releaseDate;
this.version = version;
}
/**
* @return the releaseDate
*/
public Date getReleaseDate() {
return releaseDate;
}
/**
* @return the version
*/
public String getVersion() {
return version;
}
}
/**
* return Ucum Identification details for the version in use
*/
public abstract UcumVersionDetails ucumIdentification();
/**
* Check UCUM. Note that this stands as a test of the service
* more than UCUM itself (for version 1.7, there are no known
* semantic errors in UCUM). But you should always run this test at least
* once with the version of UCUM you are using to ensure that
* the service implementation correctly understands the UCUM data
* to which it is bound
*
* @return a list of internal errors in the UCUM spec.
*
*/
public abstract List<String> validateUCUM();
/**
* return a list of the defined types of units in this UCUM version
*
* @return
*/
public abstract Set<String> getProperties();
/**
* validate whether a unit code are valid UCUM units
*
* @param units - the unit code to check
* @return nil if valid, or an error message describing the problem
*/
public abstract String validate(String unit);
/**
* given a unit, return a formal description of what the units stand for using
* full names
* @param units the unit code
* @return formal description
* @throws UcumException
* @throws OHFException
*/
public String analyse(String unit) throws UcumException ;
/**
* validate whether a units are valid UCUM units and additionally require that the
* units from a particular property
*
* @param units - the unit code to check
* @return nil if valid, or an error message describing the problem
*/
public abstract String validateInProperty(String unit, String property);
/**
* validate whether a units are valid UCUM units and additionally require that the
* units match a particular base canonical unit
*
* @param units - the unit code to check
* @return nil if valid, or an error message describing the problem
*/
public abstract String validateCanonicalUnits(String unit, String canonical);
/**
* given a set of units, return their canonical form
* @param unit
* @return the canonical form
* @throws UcumException
* @throws OHFException
*/
public abstract String getCanonicalUnits(String unit) throws UcumException ;
/**
* given two pairs of units, return true if they sahre the same canonical base
*
* @param units1
* @param units2
* @return
* @throws UcumException
* @
*/
public abstract boolean isComparable(String units1, String units2) throws UcumException ;
/**
* given a value and source unit, return the value in the given dest unit
* an exception is thrown if the conversion is not possible
*
* @param value
* @param sourceUnit
* @param destUnit
* @return the value if a conversion is possible
* @throws UcumException
* @throws OHFException
*/
public abstract Decimal convert(Decimal value, String sourceUnit, String destUnit) throws UcumException ;
/**
* given a set of UCUM units, return a likely preferred human dense form
*
* SI units - as is.
* Other units - improved by manual fixes, or the removal of []
*
* @param code
* @return the preferred human display form
*/
public abstract String getCommonDisplay(String code);
}

View File

@ -1,8 +1,13 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- The parent of this project is the deployable POM. This project isn't deployable, but this keeps it before the root pom in the reactor order when building the site. I don't know why this works...
Need to investigate this. -->
<!--
The parent of this project is the deployable POM. This project isn't
deployable, but this keeps it before the root pom in the reactor
order when building the site. I don't know why this works...
Need to investigate this.
-->
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
@ -139,7 +144,7 @@
<artifactId>jetty-util</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
@ -225,14 +230,14 @@
<artifactId>spring-web</artifactId>
</dependency>
<!--
<!--
For some reason JavaDoc crashed during site generation unless we have this dependency
-->
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
@ -253,6 +258,13 @@
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.basepom.maven</groupId>
<artifactId>duplicate-finder-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
@ -285,19 +297,17 @@
</fileSets>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<phase>install</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/jacoco.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco-report</outputDirectory>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<phase>install</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/jacoco.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco-report</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>

View File

@ -163,7 +163,7 @@
<artifactId>thymeleaf-spring4</artifactId>
</dependency>
<!-- For UCUM -->
<!-- For UCUM: TODO we should replace this with org.fhir UCUM -->
<dependency>
<groupId>org.jscience</groupId>
<artifactId>jscience</artifactId>
@ -233,10 +233,12 @@
<!-- <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>2.3.2</version> </dependency> -->
<!-- Spring -->
<!--
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
</dependency>
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
@ -358,6 +360,7 @@
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>

View File

@ -215,6 +215,9 @@ public class SearchParamRegistryDstu3 extends BaseSearchParamRegistry {
case RETIRED:
status = RuntimeSearchParamStatusEnum.RETIRED;
break;
case UNKNOWN:
status = RuntimeSearchParamStatusEnum.UNKNOWN;
break;
case NULL:
break;
}

View File

@ -216,6 +216,9 @@ public class SearchParamRegistryR4 extends BaseSearchParamRegistry {
case RETIRED:
status = RuntimeSearchParamStatusEnum.RETIRED;
break;
case UNKNOWN:
status = RuntimeSearchParamStatusEnum.UNKNOWN;
break;
case NULL:
break;
}

View File

@ -115,6 +115,8 @@ public class JpaStorageServices extends BaseHapiFhirDao<IBaseResource> implement
break;
case URI:
break;
case HAS:
break;
}
params.add(nextArgument.getName(), param);

View File

@ -103,6 +103,8 @@ public class SubscriptionActivatingSubscriber {
}
activateAndRegisterSubscriptionIfRequired(theSubscription);
break;
default:
break;
}
}

View File

@ -77,35 +77,6 @@
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.basepom.maven</groupId>
<artifactId>duplicate-finder-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>default</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<printEqualFiles>false</printEqualFiles>
<failBuildInCaseOfDifferentContentConflict>true</failBuildInCaseOfDifferentContentConflict>
<failBuildInCaseOfEqualContentConflict>true</failBuildInCaseOfEqualContentConflict>
<failBuildInCaseOfConflict>true</failBuildInCaseOfConflict>
<checkCompileClasspath>true</checkCompileClasspath>
<checkRuntimeClasspath>false</checkRuntimeClasspath>
<checkTestClasspath>false</checkTestClasspath>
<skip>false</skip>
<quiet>false</quiet>
<preferLocal>true</preferLocal>
<useResultFile>true</useResultFile>
<resultFileMinClasspathCount>2</resultFileMinClasspathCount>
<resultFile>${project.build.directory}/duplicate-finder-result.xml</resultFile>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -1532,7 +1532,7 @@ public class ProfileUtilities extends TranslatingUtilities {
private boolean hasBindableType(ElementDefinition ed) {
for (TypeRefComponent tr : ed.getType()) {
if (Utilities.existsInList(tr.getCode(), "Coding", "CodeableConcept", "Quantity", "url", "string", "code"))
if (Utilities.existsInList(tr.getCode(), "Coding", "CodeableConcept", "Quantity", "uri", "string", "code"))
return true;
}
return false;
@ -1918,8 +1918,8 @@ public class ProfileUtilities extends TranslatingUtilities {
case BUNDLED : return "b";
case CONTAINED : return "c";
case REFERENCED: return "r";
default: return "?";
}
return "?";
}
@ -2366,7 +2366,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (definition != null && definition.hasShort()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br"));
c.addPiece(checkForNoChange(definition.getShortElement(), gen.new Piece(null, gt(definition.getShortElement()), null)));
} else if (fallback != null && fallback != null && fallback.hasShort()) {
} else if (fallback != null && fallback.hasShort()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br"));
c.addPiece(checkForNoChange(fallback.getShortElement(), gen.new Piece(null, gt(fallback.getShortElement()), null)));
}
@ -2604,6 +2604,13 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
}
if (definition.hasDefinition()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br"));
c.getPieces().add(gen.new Piece(null, "Definition: ", null).addStyle("font-weight:bold"));
c.addPiece(gen.new Piece("br"));
c.addMarkdown(definition.getDefinition());
// c.getPieces().add(checkForNoChange(definition.getCommentElement(), gen.new Piece(null, definition.getComment(), null)));
}
if (definition.getComment()!=null) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br"));
c.getPieces().add(gen.new Piece(null, "Comments: ", null).addStyle("font-weight:bold"));
@ -3734,17 +3741,21 @@ public class ProfileUtilities extends TranslatingUtilities {
}
public static ElementDefinitionSlicingDiscriminatorComponent interpretR2Discriminator(String discriminator) {
public static ElementDefinitionSlicingDiscriminatorComponent interpretR2Discriminator(String discriminator, boolean isExists) {
if (discriminator.endsWith("@profile"))
return makeDiscriminator(DiscriminatorType.PROFILE, discriminator.length() == 8 ? "" : discriminator.substring(discriminator.length()-9));
if (discriminator.endsWith("@type"))
return makeDiscriminator(DiscriminatorType.TYPE, discriminator.length() == 5 ? "" : discriminator.substring(discriminator.length()-6));
return makeDiscriminator(DiscriminatorType.TYPE, discriminator.length() == 5 ? "" : discriminator.substring(discriminator.length()-6));
if (discriminator.endsWith("@exists"))
return makeDiscriminator(DiscriminatorType.EXISTS, discriminator.length() == 7 ? "" : discriminator.substring(discriminator.length()-8));
if (isExists)
return makeDiscriminator(DiscriminatorType.EXISTS, discriminator);
return new ElementDefinitionSlicingDiscriminatorComponent().setType(DiscriminatorType.VALUE).setPath(discriminator);
}
private static ElementDefinitionSlicingDiscriminatorComponent makeDiscriminator(DiscriminatorType profile, String str) {
return new ElementDefinitionSlicingDiscriminatorComponent().setType(DiscriminatorType.VALUE).setPath(Utilities.noString(str)? "$this" : str);
private static ElementDefinitionSlicingDiscriminatorComponent makeDiscriminator(DiscriminatorType dType, String str) {
return new ElementDefinitionSlicingDiscriminatorComponent().setType(dType).setPath(Utilities.noString(str)? "$this" : str);
}

View File

@ -208,14 +208,6 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return getFieldValue(Calendar.DAY_OF_MONTH);
}
/**
* Sets the month with 1-index, e.g. 1=the first day of the month
*/
public BaseDateTimeType setDay(int theDay) {
setFieldValue(Calendar.DAY_OF_MONTH, theDay, null, 0, 31);
return this;
}
/**
* Returns the default precision for the given datatype
*/
@ -236,14 +228,6 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return getFieldValue(Calendar.HOUR_OF_DAY);
}
/**
* Sets the hour of the day in a 24h clock, e.g. 13=1pm
*/
public BaseDateTimeType setHour(int theHour) {
setFieldValue(Calendar.HOUR_OF_DAY, theHour, null, 0, 23);
return this;
}
/**
* Returns the milliseconds within the current second.
* <p>
@ -255,18 +239,6 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return getFieldValue(Calendar.MILLISECOND);
}
/**
* Sets the milliseconds within the current second.
* <p>
* Note that this method sets the
* same value as {@link #setNanos(long)} but with less precision.
* </p>
*/
public BaseDateTimeType setMillis(int theMillis) {
setFieldValue(Calendar.MILLISECOND, theMillis, null, 0, 999);
return this;
}
/**
* Returns the minute of the hour in the range 0-59
*/
@ -274,14 +246,6 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return getFieldValue(Calendar.MINUTE);
}
/**
* Sets the minute of the hour in the range 0-59
*/
public BaseDateTimeType setMinute(int theMinute) {
setFieldValue(Calendar.MINUTE, theMinute, null, 0, 59);
return this;
}
/**
* Returns the month with 0-index, e.g. 0=January
*/
@ -289,14 +253,6 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return getFieldValue(Calendar.MONTH);
}
/**
* Sets the month with 0-index, e.g. 0=January
*/
public BaseDateTimeType setMonth(int theMonth) {
setFieldValue(Calendar.MONTH, theMonth, null, 0, 11);
return this;
}
/**
* Returns the nanoseconds within the current second
* <p>
@ -313,29 +269,6 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return Long.parseLong(retVal);
}
/**
* Sets the nanoseconds within the current second
* <p>
* Note that this method sets the
* same value as {@link #setMillis(int)} but with more precision.
* </p>
*/
public BaseDateTimeType setNanos(long theNanos) {
validateValueInRange(theNanos, 0, NANOS_PER_SECOND - 1);
String fractionalSeconds = StringUtils.leftPad(Long.toString(theNanos), 9, '0');
// Strip trailing 0s
for (int i = fractionalSeconds.length(); i > 0; i--) {
if (fractionalSeconds.charAt(i - 1) != '0') {
fractionalSeconds = fractionalSeconds.substring(0, i);
break;
}
}
int millis = (int) (theNanos / NANOS_PER_MILLIS);
setFieldValue(Calendar.MILLISECOND, millis, fractionalSeconds, 0, 999);
return this;
}
private int getOffsetIndex(String theValueString) {
int plusIndex = theValueString.indexOf('+', 16);
int minusIndex = theValueString.indexOf('-', 16);
@ -352,7 +285,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
/**
* Gets the precision for this datatype (using the default for the given type if not set)
*
*
* @see #setPrecision(TemporalPrecisionEnum)
*/
public TemporalPrecisionEnum getPrecision() {
@ -362,19 +295,6 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return myPrecision;
}
/**
* Sets the precision for this datatype
*
* @throws DataFormatException
*/
public void setPrecision(TemporalPrecisionEnum thePrecision) throws DataFormatException {
if (thePrecision == null) {
throw new NullPointerException("Precision may not be null");
}
myPrecision = thePrecision;
updateStringValue();
}
/**
* Returns the second of the minute in the range 0-59
*/
@ -382,32 +302,17 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return getFieldValue(Calendar.SECOND);
}
/**
* Sets the second of the minute in the range 0-59
*/
public BaseDateTimeType setSecond(int theSecond) {
setFieldValue(Calendar.SECOND, theSecond, null, 0, 59);
return this;
}
/**
* Returns the TimeZone associated with this dateTime's value. May return <code>null</code> if no timezone was
* supplied.
*/
public TimeZone getTimeZone() {
if (myTimeZoneZulu) {
return TimeZone.getTimeZone("Z");
return TimeZone.getTimeZone("GMT");
}
return myTimeZone;
}
public BaseDateTimeType setTimeZone(TimeZone theTimeZone) {
myTimeZone = theTimeZone;
myTimeZoneZulu = false;
updateStringValue();
return this;
}
/**
* Returns the value of this object as a {@link GregorianCalendar}
*/
@ -432,14 +337,6 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return getFieldValue(Calendar.YEAR);
}
/**
* Sets the year, e.g. 2015
*/
public BaseDateTimeType setYear(int theYear) {
setFieldValue(Calendar.YEAR, theYear, null, 0, 9999);
return this;
}
/**
* To be implemented by subclasses to indicate whether the given precision is allowed by this type
*/
@ -452,16 +349,9 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return myTimeZoneZulu;
}
public BaseDateTimeType setTimeZoneZulu(boolean theTimeZoneZulu) {
myTimeZoneZulu = theTimeZoneZulu;
myTimeZone = null;
updateStringValue();
return this;
}
/**
* Returns <code>true</code> if this object represents a date that is today's date
*
*
* @throws NullPointerException
* if {@link #getValue()} returns <code>null</code>
*/
@ -602,6 +492,14 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return retVal;
}
/**
* Sets the month with 1-index, e.g. 1=the first day of the month
*/
public BaseDateTimeType setDay(int theDay) {
setFieldValue(Calendar.DAY_OF_MONTH, theDay, null, 0, 31);
return this;
}
private void setFieldValue(int theField, int theValue, String theFractionalSeconds, int theMinimum, int theMaximum) {
validateValueInRange(theValue, theMinimum, theMaximum);
Calendar cal;
@ -621,6 +519,86 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
super.setValue(cal.getTime());
}
/**
* Sets the hour of the day in a 24h clock, e.g. 13=1pm
*/
public BaseDateTimeType setHour(int theHour) {
setFieldValue(Calendar.HOUR_OF_DAY, theHour, null, 0, 23);
return this;
}
/**
* Sets the milliseconds within the current second.
* <p>
* Note that this method sets the
* same value as {@link #setNanos(long)} but with less precision.
* </p>
*/
public BaseDateTimeType setMillis(int theMillis) {
setFieldValue(Calendar.MILLISECOND, theMillis, null, 0, 999);
return this;
}
/**
* Sets the minute of the hour in the range 0-59
*/
public BaseDateTimeType setMinute(int theMinute) {
setFieldValue(Calendar.MINUTE, theMinute, null, 0, 59);
return this;
}
/**
* Sets the month with 0-index, e.g. 0=January
*/
public BaseDateTimeType setMonth(int theMonth) {
setFieldValue(Calendar.MONTH, theMonth, null, 0, 11);
return this;
}
/**
* Sets the nanoseconds within the current second
* <p>
* Note that this method sets the
* same value as {@link #setMillis(int)} but with more precision.
* </p>
*/
public BaseDateTimeType setNanos(long theNanos) {
validateValueInRange(theNanos, 0, NANOS_PER_SECOND - 1);
String fractionalSeconds = StringUtils.leftPad(Long.toString(theNanos), 9, '0');
// Strip trailing 0s
for (int i = fractionalSeconds.length(); i > 0; i--) {
if (fractionalSeconds.charAt(i - 1) != '0') {
fractionalSeconds = fractionalSeconds.substring(0, i);
break;
}
}
int millis = (int) (theNanos / NANOS_PER_MILLIS);
setFieldValue(Calendar.MILLISECOND, millis, fractionalSeconds, 0, 999);
return this;
}
/**
* Sets the precision for this datatype
*
* @throws DataFormatException
*/
public void setPrecision(TemporalPrecisionEnum thePrecision) throws DataFormatException {
if (thePrecision == null) {
throw new NullPointerException("Precision may not be null");
}
myPrecision = thePrecision;
updateStringValue();
}
/**
* Sets the second of the minute in the range 0-59
*/
public BaseDateTimeType setSecond(int theSecond) {
setFieldValue(Calendar.SECOND, theSecond, null, 0, 59);
return this;
}
private BaseDateTimeType setTimeZone(String theWholeValue, String theValue) {
if (isBlank(theValue)) {
@ -642,6 +620,20 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return this;
}
public BaseDateTimeType setTimeZone(TimeZone theTimeZone) {
myTimeZone = theTimeZone;
myTimeZoneZulu = false;
updateStringValue();
return this;
}
public BaseDateTimeType setTimeZoneZulu(boolean theTimeZoneZulu) {
myTimeZoneZulu = theTimeZoneZulu;
myTimeZone = null;
updateStringValue();
return this;
}
/**
* Sets the value for this type using the given Java Date object as the time, and using the default precision for
* this datatype (unless the precision is already set), as well as the local timezone as determined by the local operating
@ -657,7 +649,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
* Sets the value for this type using the given Java Date object as the time, and using the specified precision, as
* well as the local timezone as determined by the local operating system. Both of
* these properties may be modified in subsequent calls if neccesary.
*
*
* @param theValue
* The date value
* @param thePrecision
@ -729,6 +721,14 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
}
}
/**
* Sets the year, e.g. 2015
*/
public BaseDateTimeType setYear(int theYear) {
setFieldValue(Calendar.YEAR, theYear, null, 0, 9999);
return this;
}
private void throwBadDateFormat(String theValue) {
throw new DataFormatException("Invalid date/time format: \"" + theValue + "\"");
}

View File

@ -1,417 +1,417 @@
package org.hl7.fhir.r4.utils.client;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* 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
prior written permission.
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
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,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
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,
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
POSSIBILITY OF SUCH DAMAGE.
*/
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.ResourceType;
import org.hl7.fhir.utilities.Utilities;
//Make resources address subclass of URI
/**
* Helper class to manage FHIR Resource URIs
*
* @author Claude Nanjo
*
*/
public class ResourceAddress {
public static final String REGEX_ID_WITH_HISTORY = "(.*)(/)([a-zA-Z0-9]*)(/)([a-z0-9\\-\\.]{1,64})(/_history/)([a-z0-9\\-\\.]{1,64})$";
private URI baseServiceUri;
public ResourceAddress(String endpointPath) throws URISyntaxException {//TODO Revisit this exception
this.baseServiceUri = ResourceAddress.buildAbsoluteURI(endpointPath);
}
public ResourceAddress(URI baseServiceUri) {
this.baseServiceUri = baseServiceUri;
}
public URI getBaseServiceUri() {
return this.baseServiceUri;
}
public <T extends Resource> URI resolveOperationURLFromClass(Class<T> resourceClass, String name, String parameters) {
return baseServiceUri.resolve(nameForClassWithSlash(resourceClass) +"$"+name+"?"+ parameters);
}
public <T extends Resource> URI resolveSearchUri(Class<T> resourceClass, Map<String,String> parameters) {
return appendHttpParameters(baseServiceUri.resolve(nameForClassWithSlash(resourceClass) +"_search"), parameters);
}
private <T extends Resource> String nameForClassWithSlash(Class<T> resourceClass) {
String n = nameForClass(resourceClass);
return n == null ? "" : n +"/";
}
public <T extends Resource> URI resolveOperationUri(Class<T> resourceClass, String opName) {
return baseServiceUri.resolve(nameForClassWithSlash(resourceClass) +"/"+opName);
}
public <T extends Resource> URI resolveOperationUri(Class<T> resourceClass, String opName, Map<String,String> parameters) {
return appendHttpParameters(baseServiceUri.resolve(nameForClassWithSlash(resourceClass) +"$"+opName), parameters);
}
public <T extends Resource> URI resolveValidateUri(Class<T> resourceClass, String id) {
return baseServiceUri.resolve(nameForClassWithSlash(resourceClass) +"$validate/"+id);
}
public <T extends Resource> URI resolveGetUriFromResourceClass(Class<T> resourceClass) {
return baseServiceUri.resolve(nameForClass(resourceClass));
}
public <T extends Resource> URI resolveGetUriFromResourceClassAndId(Class<T> resourceClass, String id) {
return baseServiceUri.resolve(nameForClass(resourceClass) +"/"+id);
}
public <T extends Resource> URI resolveGetUriFromResourceClassAndIdAndVersion(Class<T> resourceClass, String id, String version) {
return baseServiceUri.resolve(nameForClass(resourceClass) +"/"+id+"/_history/"+version);
}
public URI resolveGetHistoryForAllResources(int count) {
if(count > 0) {
return appendHttpParameter(baseServiceUri.resolve("_history"), "_count", ""+count);
} else {
return baseServiceUri.resolve("_history");
}
}
public <T extends Resource> URI resolveGetHistoryForResourceId(Class<T> resourceClass, String id, int count) {
return resolveGetHistoryUriForResourceId(resourceClass, id, null, count);
}
protected <T extends Resource> URI resolveGetHistoryUriForResourceId(Class<T> resourceClass, String id, Object since, int count) {
Map<String,String> parameters = getHistoryParameters(since, count);
return appendHttpParameters(baseServiceUri.resolve(nameForClass(resourceClass) + "/" + id + "/_history"), parameters);
}
public <T extends Resource> URI resolveGetHistoryForResourceType(Class<T> resourceClass, int count) {
Map<String,String> parameters = getHistoryParameters(null, count);
return appendHttpParameters(baseServiceUri.resolve(nameForClass(resourceClass) + "/_history"), parameters);
}
public <T extends Resource> URI resolveGetHistoryForResourceType(Class<T> resourceClass, Object since, int count) {
Map<String,String> parameters = getHistoryParameters(since, count);
return appendHttpParameters(baseServiceUri.resolve(nameForClass(resourceClass) + "/_history"), parameters);
}
public URI resolveGetHistoryForAllResources(Calendar since, int count) {
Map<String,String> parameters = getHistoryParameters(since, count);
return appendHttpParameters(baseServiceUri.resolve("_history"), parameters);
}
public URI resolveGetHistoryForAllResources(Date since, int count) {
Map<String,String> parameters = getHistoryParameters(since, count);
return appendHttpParameters(baseServiceUri.resolve("_history"), parameters);
}
public Map<String,String> getHistoryParameters(Object since, int count) {
Map<String,String> parameters = new HashMap<String,String>();
if (since != null) {
parameters.put("_since", since.toString());
}
if(count > 0) {
parameters.put("_count", ""+count);
}
return parameters;
}
public <T extends Resource> URI resolveGetHistoryForResourceId(Class<T> resourceClass, String id, Calendar since, int count) {
return resolveGetHistoryUriForResourceId(resourceClass, id, since, count);
}
public <T extends Resource> URI resolveGetHistoryForResourceId(Class<T> resourceClass, String id, Date since, int count) {
return resolveGetHistoryUriForResourceId(resourceClass, id, since, count);
}
public <T extends Resource> URI resolveGetHistoryForResourceType(Class<T> resourceClass, Calendar since, int count) {
return resolveGetHistoryForResourceType(resourceClass, getCalendarDateInIsoTimeFormat(since), count);
}
public <T extends Resource> URI resolveGetHistoryForResourceType(Class<T> resourceClass, Date since, int count) {
return resolveGetHistoryForResourceType(resourceClass, since.toString(), count);
}
public <T extends Resource> URI resolveGetAllTags() {
return baseServiceUri.resolve("_tags");
}
public <T extends Resource> URI resolveGetAllTagsForResourceType(Class<T> resourceClass) {
return baseServiceUri.resolve(nameForClass(resourceClass) + "/_tags");
}
public <T extends Resource> URI resolveGetTagsForReference(Class<T> resourceClass, String id) {
return baseServiceUri.resolve(nameForClass(resourceClass) + "/" + id + "/_tags");
}
public <T extends Resource> URI resolveGetTagsForResourceVersion(Class<T> resourceClass, String id, String version) {
return baseServiceUri.resolve(nameForClass(resourceClass) +"/"+id+"/_history/"+version + "/_tags");
}
public <T extends Resource> URI resolveDeleteTagsForResourceVersion(Class<T> resourceClass, String id, String version) {
return baseServiceUri.resolve(nameForClass(resourceClass) +"/"+id+"/_history/"+version + "/_tags/_delete");
}
public <T extends Resource> String nameForClass(Class<T> resourceClass) {
if (resourceClass == null)
return null;
String res = resourceClass.getSimpleName();
if (res.equals("List_"))
return "List";
else
return res;
}
public URI resolveMetadataUri(boolean quick) {
return baseServiceUri.resolve(quick ? "metadata?_summary=true" : "metadata");
}
/**
* For now, assume this type of location header structure.
* Generalize later: http://hl7connect.healthintersections.com.au/svc/fhir/318/_history/1
*
* @param serviceBase
* @param locationHeader
*/
public static ResourceAddress.ResourceVersionedIdentifier parseCreateLocation(String locationResponseHeader) {
Pattern pattern = Pattern.compile(REGEX_ID_WITH_HISTORY);
Matcher matcher = pattern.matcher(locationResponseHeader);
ResourceVersionedIdentifier parsedHeader = null;
if(matcher.matches()){
String serviceRoot = matcher.group(1);
String resourceType = matcher.group(3);
String id = matcher.group(5);
String version = matcher.group(7);
parsedHeader = new ResourceVersionedIdentifier(serviceRoot, resourceType, id, version);
}
return parsedHeader;
}
public static URI buildAbsoluteURI(String absoluteURI) {
if(StringUtils.isBlank(absoluteURI)) {
throw new EFhirClientException("Invalid URI", new URISyntaxException(absoluteURI, "URI/URL cannot be blank"));
}
String endpoint = appendForwardSlashToPath(absoluteURI);
return buildEndpointUriFromString(endpoint);
}
public static String appendForwardSlashToPath(String path) {
if(path.lastIndexOf('/') != path.length() - 1) {
path += "/";
}
return path;
}
public static URI buildEndpointUriFromString(String endpointPath) {
URI uri = null;
try {
URIBuilder uriBuilder = new URIBuilder(endpointPath);
uri = uriBuilder.build();
String scheme = uri.getScheme();
String host = uri.getHost();
if(!scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https")) {
throw new EFhirClientException("Scheme must be 'http' or 'https': " + uri);
}
if(StringUtils.isBlank(host)) {
throw new EFhirClientException("host cannot be blank: " + uri);
}
} catch(URISyntaxException e) {
throw new EFhirClientException("Invalid URI", e);
}
return uri;
}
public static URI appendQueryStringToUri(URI uri, String parameterName, String parameterValue) {
URI modifiedUri = null;
try {
URIBuilder uriBuilder = new URIBuilder(uri);
uriBuilder.setQuery(parameterName + "=" + parameterValue);
modifiedUri = uriBuilder.build();
} catch(Exception e) {
throw new EFhirClientException("Unable to append query parameter '" + parameterName + "=" + parameterValue + " to URI " + uri, e);
}
return modifiedUri;
}
public static String buildRelativePathFromResourceType(ResourceType resourceType) {
//return resourceType.toString().toLowerCase()+"/";
return resourceType.toString() + "/";
}
public static String buildRelativePathFromResourceType(ResourceType resourceType, String id) {
return buildRelativePathFromResourceType(resourceType)+ "@" + id;
}
public static String buildRelativePathFromReference(Resource resource) {
return buildRelativePathFromResourceType(resource.getResourceType());
}
public static String buildRelativePathFromReference(Resource resource, String id) {
return buildRelativePathFromResourceType(resource.getResourceType(), id);
}
public static class ResourceVersionedIdentifier {
private String serviceRoot;
private String resourceType;
private String id;
private String version;
private URI resourceLocation;
public ResourceVersionedIdentifier(String serviceRoot, String resourceType, String id, String version, URI resourceLocation) {
this.serviceRoot = serviceRoot;
this.resourceType = resourceType;
this.id = id;
this.version = version;
this.resourceLocation = resourceLocation;
}
public ResourceVersionedIdentifier(String resourceType, String id, String version, URI resourceLocation) {
this(null, resourceType, id, version, resourceLocation);
}
public ResourceVersionedIdentifier(String serviceRoot, String resourceType, String id, String version) {
this(serviceRoot, resourceType, id, version, null);
}
public ResourceVersionedIdentifier(String resourceType, String id, String version) {
this(null, resourceType, id, version, null);
}
public ResourceVersionedIdentifier(String resourceType, String id) {
this.id = id;
}
public String getId() {
return this.id;
}
protected void setId(String id) {
this.id = id;
}
public String getVersionId() {
return this.version;
}
protected void setVersionId(String version) {
this.version = version;
}
public String getResourceType() {
return resourceType;
}
public void setResourceType(String resourceType) {
this.resourceType = resourceType;
}
public String getServiceRoot() {
return serviceRoot;
}
public void setServiceRoot(String serviceRoot) {
this.serviceRoot = serviceRoot;
}
public String getResourcePath() {
return this.serviceRoot + "/" + this.resourceType + "/" + this.id;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public URI getResourceLocation() {
return this.resourceLocation;
}
public void setResourceLocation(URI resourceLocation) {
this.resourceLocation = resourceLocation;
}
}
public static String getCalendarDateInIsoTimeFormat(Calendar calendar) {
SimpleDateFormat format = new SimpleDateFormat("YYYY-MM-dd'T'hh:mm:ss");//TODO Move out
format.setTimeZone(TimeZone.getTimeZone("GMT"));
return format.format(calendar.getTime());
}
public static URI appendHttpParameter(URI basePath, String httpParameterName, String httpParameterValue) {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(httpParameterName, httpParameterValue);
return appendHttpParameters(basePath, parameters);
}
public static URI appendHttpParameters(URI basePath, Map<String,String> parameters) {
try {
Set<String> httpParameterNames = parameters.keySet();
String query = basePath.getQuery();
for(String httpParameterName : httpParameterNames) {
if(query != null) {
query += "&";
} else {
query = "";
}
query += httpParameterName + "=" + Utilities.encodeUri(parameters.get(httpParameterName));
}
return new URI(basePath.getScheme(), basePath.getUserInfo(), basePath.getHost(),basePath.getPort(), basePath.getPath(), query, basePath.getFragment());
} catch(Exception e) {
throw new EFhirClientException("Error appending http parameter", e);
}
}
}
package org.hl7.fhir.r4.utils.client;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* 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
prior written permission.
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
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,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
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,
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
POSSIBILITY OF SUCH DAMAGE.
*/
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.ResourceType;
import org.hl7.fhir.utilities.Utilities;
//Make resources address subclass of URI
/**
* Helper class to manage FHIR Resource URIs
*
* @author Claude Nanjo
*
*/
public class ResourceAddress {
public static final String REGEX_ID_WITH_HISTORY = "(.*)(/)([a-zA-Z0-9]*)(/)([a-z0-9\\-\\.]{1,64})(/_history/)([a-z0-9\\-\\.]{1,64})$";
private URI baseServiceUri;
public ResourceAddress(String endpointPath) throws URISyntaxException {//TODO Revisit this exception
this.baseServiceUri = ResourceAddress.buildAbsoluteURI(endpointPath);
}
public ResourceAddress(URI baseServiceUri) {
this.baseServiceUri = baseServiceUri;
}
public URI getBaseServiceUri() {
return this.baseServiceUri;
}
public <T extends Resource> URI resolveOperationURLFromClass(Class<T> resourceClass, String name, String parameters) {
return baseServiceUri.resolve(nameForClassWithSlash(resourceClass) +"$"+name+"?"+ parameters);
}
public <T extends Resource> URI resolveSearchUri(Class<T> resourceClass, Map<String,String> parameters) {
return appendHttpParameters(baseServiceUri.resolve(nameForClassWithSlash(resourceClass) +"_search"), parameters);
}
private <T extends Resource> String nameForClassWithSlash(Class<T> resourceClass) {
String n = nameForClass(resourceClass);
return n == null ? "" : n +"/";
}
public <T extends Resource> URI resolveOperationUri(Class<T> resourceClass, String opName) {
return baseServiceUri.resolve(nameForClassWithSlash(resourceClass) +"/"+opName);
}
public <T extends Resource> URI resolveOperationUri(Class<T> resourceClass, String opName, Map<String,String> parameters) {
return appendHttpParameters(baseServiceUri.resolve(nameForClassWithSlash(resourceClass) +"$"+opName), parameters);
}
public <T extends Resource> URI resolveValidateUri(Class<T> resourceClass, String id) {
return baseServiceUri.resolve(nameForClassWithSlash(resourceClass) +"$validate/"+id);
}
public <T extends Resource> URI resolveGetUriFromResourceClass(Class<T> resourceClass) {
return baseServiceUri.resolve(nameForClass(resourceClass));
}
public <T extends Resource> URI resolveGetUriFromResourceClassAndId(Class<T> resourceClass, String id) {
return baseServiceUri.resolve(nameForClass(resourceClass) +"/"+id);
}
public <T extends Resource> URI resolveGetUriFromResourceClassAndIdAndVersion(Class<T> resourceClass, String id, String version) {
return baseServiceUri.resolve(nameForClass(resourceClass) +"/"+id+"/_history/"+version);
}
public URI resolveGetHistoryForAllResources(int count) {
if(count > 0) {
return appendHttpParameter(baseServiceUri.resolve("_history"), "_count", ""+count);
} else {
return baseServiceUri.resolve("_history");
}
}
public <T extends Resource> URI resolveGetHistoryForResourceId(Class<T> resourceClass, String id, int count) {
return resolveGetHistoryUriForResourceId(resourceClass, id, null, count);
}
protected <T extends Resource> URI resolveGetHistoryUriForResourceId(Class<T> resourceClass, String id, Object since, int count) {
Map<String,String> parameters = getHistoryParameters(since, count);
return appendHttpParameters(baseServiceUri.resolve(nameForClass(resourceClass) + "/" + id + "/_history"), parameters);
}
public <T extends Resource> URI resolveGetHistoryForResourceType(Class<T> resourceClass, int count) {
Map<String,String> parameters = getHistoryParameters(null, count);
return appendHttpParameters(baseServiceUri.resolve(nameForClass(resourceClass) + "/_history"), parameters);
}
public <T extends Resource> URI resolveGetHistoryForResourceType(Class<T> resourceClass, Object since, int count) {
Map<String,String> parameters = getHistoryParameters(since, count);
return appendHttpParameters(baseServiceUri.resolve(nameForClass(resourceClass) + "/_history"), parameters);
}
public URI resolveGetHistoryForAllResources(Calendar since, int count) {
Map<String,String> parameters = getHistoryParameters(since, count);
return appendHttpParameters(baseServiceUri.resolve("_history"), parameters);
}
public URI resolveGetHistoryForAllResources(Date since, int count) {
Map<String,String> parameters = getHistoryParameters(since, count);
return appendHttpParameters(baseServiceUri.resolve("_history"), parameters);
}
public Map<String,String> getHistoryParameters(Object since, int count) {
Map<String,String> parameters = new HashMap<String,String>();
if (since != null) {
parameters.put("_since", since.toString());
}
if(count > 0) {
parameters.put("_count", ""+count);
}
return parameters;
}
public <T extends Resource> URI resolveGetHistoryForResourceId(Class<T> resourceClass, String id, Calendar since, int count) {
return resolveGetHistoryUriForResourceId(resourceClass, id, since, count);
}
public <T extends Resource> URI resolveGetHistoryForResourceId(Class<T> resourceClass, String id, Date since, int count) {
return resolveGetHistoryUriForResourceId(resourceClass, id, since, count);
}
public <T extends Resource> URI resolveGetHistoryForResourceType(Class<T> resourceClass, Calendar since, int count) {
return resolveGetHistoryForResourceType(resourceClass, getCalendarDateInIsoTimeFormat(since), count);
}
public <T extends Resource> URI resolveGetHistoryForResourceType(Class<T> resourceClass, Date since, int count) {
return resolveGetHistoryForResourceType(resourceClass, since.toString(), count);
}
public <T extends Resource> URI resolveGetAllTags() {
return baseServiceUri.resolve("_tags");
}
public <T extends Resource> URI resolveGetAllTagsForResourceType(Class<T> resourceClass) {
return baseServiceUri.resolve(nameForClass(resourceClass) + "/_tags");
}
public <T extends Resource> URI resolveGetTagsForReference(Class<T> resourceClass, String id) {
return baseServiceUri.resolve(nameForClass(resourceClass) + "/" + id + "/_tags");
}
public <T extends Resource> URI resolveGetTagsForResourceVersion(Class<T> resourceClass, String id, String version) {
return baseServiceUri.resolve(nameForClass(resourceClass) +"/"+id+"/_history/"+version + "/_tags");
}
public <T extends Resource> URI resolveDeleteTagsForResourceVersion(Class<T> resourceClass, String id, String version) {
return baseServiceUri.resolve(nameForClass(resourceClass) +"/"+id+"/_history/"+version + "/_tags/_delete");
}
public <T extends Resource> String nameForClass(Class<T> resourceClass) {
if (resourceClass == null)
return null;
String res = resourceClass.getSimpleName();
if (res.equals("List_"))
return "List";
else
return res;
}
public URI resolveMetadataUri(boolean quick) {
return baseServiceUri.resolve(quick ? "metadata?_summary=true" : "metadata");
}
/**
* For now, assume this type of location header structure.
* Generalize later: http://hl7connect.healthintersections.com.au/svc/fhir/318/_history/1
*
* @param serviceBase
* @param locationHeader
*/
public static ResourceAddress.ResourceVersionedIdentifier parseCreateLocation(String locationResponseHeader) {
Pattern pattern = Pattern.compile(REGEX_ID_WITH_HISTORY);
Matcher matcher = pattern.matcher(locationResponseHeader);
ResourceVersionedIdentifier parsedHeader = null;
if(matcher.matches()){
String serviceRoot = matcher.group(1);
String resourceType = matcher.group(3);
String id = matcher.group(5);
String version = matcher.group(7);
parsedHeader = new ResourceVersionedIdentifier(serviceRoot, resourceType, id, version);
}
return parsedHeader;
}
public static URI buildAbsoluteURI(String absoluteURI) {
if(StringUtils.isBlank(absoluteURI)) {
throw new EFhirClientException("Invalid URI", new URISyntaxException(absoluteURI, "URI/URL cannot be blank"));
}
String endpoint = appendForwardSlashToPath(absoluteURI);
return buildEndpointUriFromString(endpoint);
}
public static String appendForwardSlashToPath(String path) {
if(path.lastIndexOf('/') != path.length() - 1) {
path += "/";
}
return path;
}
public static URI buildEndpointUriFromString(String endpointPath) {
URI uri = null;
try {
URIBuilder uriBuilder = new URIBuilder(endpointPath);
uri = uriBuilder.build();
String scheme = uri.getScheme();
String host = uri.getHost();
if(!scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https")) {
throw new EFhirClientException("Scheme must be 'http' or 'https': " + uri);
}
if(StringUtils.isBlank(host)) {
throw new EFhirClientException("host cannot be blank: " + uri);
}
} catch(URISyntaxException e) {
throw new EFhirClientException("Invalid URI", e);
}
return uri;
}
public static URI appendQueryStringToUri(URI uri, String parameterName, String parameterValue) {
URI modifiedUri = null;
try {
URIBuilder uriBuilder = new URIBuilder(uri);
uriBuilder.setQuery(parameterName + "=" + parameterValue);
modifiedUri = uriBuilder.build();
} catch(Exception e) {
throw new EFhirClientException("Unable to append query parameter '" + parameterName + "=" + parameterValue + " to URI " + uri, e);
}
return modifiedUri;
}
public static String buildRelativePathFromResourceType(ResourceType resourceType) {
//return resourceType.toString().toLowerCase()+"/";
return resourceType.toString() + "/";
}
public static String buildRelativePathFromResourceType(ResourceType resourceType, String id) {
return buildRelativePathFromResourceType(resourceType)+ "@" + id;
}
public static String buildRelativePathFromReference(Resource resource) {
return buildRelativePathFromResourceType(resource.getResourceType());
}
public static String buildRelativePathFromReference(Resource resource, String id) {
return buildRelativePathFromResourceType(resource.getResourceType(), id);
}
public static class ResourceVersionedIdentifier {
private String serviceRoot;
private String resourceType;
private String id;
private String version;
private URI resourceLocation;
public ResourceVersionedIdentifier(String serviceRoot, String resourceType, String id, String version, URI resourceLocation) {
this.serviceRoot = serviceRoot;
this.resourceType = resourceType;
this.id = id;
this.version = version;
this.resourceLocation = resourceLocation;
}
public ResourceVersionedIdentifier(String resourceType, String id, String version, URI resourceLocation) {
this(null, resourceType, id, version, resourceLocation);
}
public ResourceVersionedIdentifier(String serviceRoot, String resourceType, String id, String version) {
this(serviceRoot, resourceType, id, version, null);
}
public ResourceVersionedIdentifier(String resourceType, String id, String version) {
this(null, resourceType, id, version, null);
}
public ResourceVersionedIdentifier(String resourceType, String id) {
this.id = id;
}
public String getId() {
return this.id;
}
protected void setId(String id) {
this.id = id;
}
public String getVersionId() {
return this.version;
}
protected void setVersionId(String version) {
this.version = version;
}
public String getResourceType() {
return resourceType;
}
public void setResourceType(String resourceType) {
this.resourceType = resourceType;
}
public String getServiceRoot() {
return serviceRoot;
}
public void setServiceRoot(String serviceRoot) {
this.serviceRoot = serviceRoot;
}
public String getResourcePath() {
return this.serviceRoot + "/" + this.resourceType + "/" + this.id;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public URI getResourceLocation() {
return this.resourceLocation;
}
public void setResourceLocation(URI resourceLocation) {
this.resourceLocation = resourceLocation;
}
}
public static String getCalendarDateInIsoTimeFormat(Calendar calendar) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss");//TODO Move out
format.setTimeZone(TimeZone.getTimeZone("GMT"));
return format.format(calendar.getTime());
}
public static URI appendHttpParameter(URI basePath, String httpParameterName, String httpParameterValue) {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(httpParameterName, httpParameterValue);
return appendHttpParameters(basePath, parameters);
}
public static URI appendHttpParameters(URI basePath, Map<String,String> parameters) {
try {
Set<String> httpParameterNames = parameters.keySet();
String query = basePath.getQuery();
for(String httpParameterName : httpParameterNames) {
if(query != null) {
query += "&";
} else {
query = "";
}
query += httpParameterName + "=" + Utilities.encodeUri(parameters.get(httpParameterName));
}
return new URI(basePath.getScheme(), basePath.getUserInfo(), basePath.getHost(),basePath.getPort(), basePath.getPath(), query, basePath.getFragment());
} catch(Exception e) {
throw new EFhirClientException("Error appending http parameter", e);
}
}
}

View File

@ -339,10 +339,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
switch (bpWarnings) {
case Error:
rule(errors, invalid, line, col, literalPath, test, message);
break;
case Warning:
warning(errors, invalid, line, col, literalPath, test, message);
break;
case Hint:
hint(errors, invalid, line, col, literalPath, test, message);
break;
default: // do nothing
}
}
@ -2452,6 +2455,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
else if (itemType.equals("integer")) checkOption(errors, answer, ns, qsrc, qItem, "integer");
else if (itemType.equals("string")) checkOption(errors, answer, ns, qsrc, qItem, "string", true);
break;
case QUESTION:
case NULL:
break;
}
validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, answer, stack, inProgress);
}
@ -3050,11 +3056,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (ei.path.endsWith(".extension"))
rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.path, ei.definition != null, "Element is unknown or does not match any slice (url=\"" + ei.element.getNamedChildValue("url") + "\")" + (profile==null ? "" : " for profile " + profile.getUrl()));
else if (!unsupportedSlicing)
if (ei.slice!=null && (ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN) || ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN)))
if (ei.slice!=null && (ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN)))
hint(errors, IssueType.INFORMATIONAL, ei.line(), ei.col(), ei.path, (ei.definition != null),
"Element " + ei.element.getName() + " is unknown or does not match any slice " + sliceInfo + (profile==null ? "" : " for profile " + profile.getUrl()));
else
if (ei.slice!=null && (ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN) || ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN)))
if (ei.slice!=null && (ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN)))
rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.path, (ei.definition != null),
"Element " + ei.element.getName() + " is unknown or does not match any slice " + sliceInfo + (profile==null ? "" : " for profile " + profile.getUrl()));
else
@ -3230,7 +3236,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
goodProfiles.put(typeProfile, profileErrors);
}
if (goodProfiles.size()==1) {
errors.addAll(goodProfiles.get(0));
errors.addAll(goodProfiles.values().iterator().next());
} else if (goodProfiles.size()==0) {
rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.path, false, "Unable to find matching profile among choices: " + StringUtils.join("; ", profiles));
for (List<ValidationMessage> messages : badProfiles) {

View File

@ -379,10 +379,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
switch (bpWarnings) {
case Error:
rule(errors, invalid, line, col, literalPath, test, message);
break;
case Warning:
warning(errors, invalid, line, col, literalPath, test, message);
break;
case Hint:
hint(errors, invalid, line, col, literalPath, test, message);
break;
default: // do nothing
}
}
@ -2419,6 +2422,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
else if (itemType.equals("integer")) checkOption(errors, answer, ns, qsrc, qItem, "integer");
else if (itemType.equals("string")) checkOption(errors, answer, ns, qsrc, qItem, "string", true);
break;
case QUESTION:
// TODO: how to validate this???
break;
case NULL:
// Should not happen
break;
}
validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, answer, stack, inProgress);
}
@ -3019,11 +3028,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (ei.path.endsWith(".extension"))
rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.path, ei.definition != null, "Element is unknown or does not match any slice (url=\"" + ei.element.getNamedChildValue("url") + "\")" + (profile==null ? "" : " for profile " + profile.getUrl()));
else if (!unsupportedSlicing)
if (ei.slice!=null && (ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN) || ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN)))
if (ei.slice!=null && (ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN)))
hint(errors, IssueType.INFORMATIONAL, ei.line(), ei.col(), ei.path, (ei.definition != null),
"Element " + ei.element.getName() + " is unknown or does not match any slice " + sliceInfo + (profile==null ? "" : " for profile " + profile.getUrl()));
else
if (ei.slice!=null && (ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN) || ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN)))
if (ei.slice!=null && (ei.slice.getSlicing().getRules().equals(ElementDefinition.SlicingRules.OPEN)))
rule(errors, IssueType.INVALID, ei.line(), ei.col(), ei.path, (ei.definition != null),
"Element " + ei.element.getName() + " is unknown or does not match any slice " + sliceInfo + (profile==null ? "" : " for profile " + profile.getUrl()));
else
@ -3220,7 +3229,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
goodProfiles.put(typeProfile, profileErrors);
}
if (goodProfiles.size()==1) {
errors.addAll(goodProfiles.get(0));
/* TODO: this was goodProfiless.get(0) which will always
* return null - Is the first value what was wanted? */
errors.addAll(goodProfiles.values().iterator().next());
} else if (goodProfiles.size()==0) {
rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.path, false, "Unable to find matching profile among choices: " + StringUtils.join("; ", profiles));
for (List<ValidationMessage> messages : badProfiles) {

View File

@ -994,6 +994,11 @@
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.basepom.maven</groupId>
<artifactId>duplicate-finder-maven-plugin</artifactId>
<version>1.2.1</version>
</plugin>
<plugin>
<groupId>de.juplo</groupId>
<artifactId>hibernate-maven-plugin</artifactId>
@ -1908,6 +1913,9 @@
</profile>
<profile>
<id>ERRORPRONE</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>