From e29e10450cee2d2d4a3ad9f4dfd1c289d8b4ab47 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Wed, 7 Oct 2015 18:12:38 -0400 Subject: [PATCH] Add validation --- .../src/main/java/ca/uhn/fhir/cli/App.java | 1 + .../ca/uhn/fhir/cli/RunServerCommand.java | 4 + .../uhn/fhir/cli/ValidationDataUploader.java | 179 ++++++++++-------- .../src/main/resources/logback-cli-on.xml | 31 +-- .../dao/FhirResourceDaoSubscriptionDstu2.java | 8 +- .../jpa/dao/data/ISubscriptionTableDao.java | 3 + .../fhir/jpa/entity/SubscriptionTable.java | 1 - .../jpa/provider/SubscriptionsDstu2Test.java | 4 + 8 files changed, 118 insertions(+), 113 deletions(-) diff --git a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/App.java b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/App.java index a514fe3e854..00b366d6fe4 100644 --- a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/App.java +++ b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/App.java @@ -35,6 +35,7 @@ public class App { ourCommands.add(new RunServerCommand()); ourCommands.add(new ExampleDataUploader()); ourCommands.add(new ValidateCommand()); + ourCommands.add(new ValidationDataUploader()); Collections.sort(ourCommands); } diff --git a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/RunServerCommand.java b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/RunServerCommand.java index 44250273331..d3f7e42bfa1 100644 --- a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/RunServerCommand.java +++ b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/RunServerCommand.java @@ -48,6 +48,8 @@ public class RunServerCommand extends BaseCommand { public void run(CommandLine theCommandLine) throws ParseException { myPort = parseOptionInteger(theCommandLine, OPTION_P, DEFAULT_PORT); +// ((ch.qos.logback.classic.Logger)LoggerFactory.getLogger("/")).setLevel(Level.ERROR); + ourLog.info("Preparing HAPI FHIR JPA server"); File tempWarFile; try { @@ -81,6 +83,8 @@ public class RunServerCommand extends BaseCommand { ourLog.info("Server started on port {}", myPort); ourLog.info("Web Testing UI : http://localhost:{}/", myPort); ourLog.info("Server Base URL: http://localhost:{}/baseDstu2/", myPort); + + } public void run(String[] theArgs) { diff --git a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ValidationDataUploader.java b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ValidationDataUploader.java index 1487ee46486..6bcbb6b5086 100644 --- a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ValidationDataUploader.java +++ b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ValidationDataUploader.java @@ -1,134 +1,157 @@ package ca.uhn.fhir.cli; +import static org.apache.commons.lang3.StringUtils.isBlank; + import java.io.IOException; -import java.io.UnsupportedEncodingException; import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.io.IOUtils; -import org.apache.http.client.ClientProtocolException; -import org.hl7.fhir.instance.model.Bundle; -import org.hl7.fhir.instance.model.Bundle.BundleEntryComponent; -import org.hl7.fhir.instance.model.StructureDefinition; -import org.hl7.fhir.instance.model.ValueSet; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu2.resource.Bundle; +import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; +import ca.uhn.fhir.model.dstu2.resource.StructureDefinition; +import ca.uhn.fhir.model.dstu2.resource.ValueSet; +import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.rest.client.IGenericClient; public class ValidationDataUploader extends BaseCommand { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidationDataUploader.class); - public static void main(String[] args) throws Exception { - new ValidationDataUploader().execute(); + @Override + public String getCommandDescription() { + return "Uploads the conformance resources (StructureDefinition and ValueSet) from the official FHIR definitions."; } - private void execute() throws IOException, ClientProtocolException, UnsupportedEncodingException { - ourLog.info("Starting..."); + @Override + public String getCommandName() { + return "upload-definitions"; + } - FhirContext ctx = FhirContext.forDstu2Hl7Org(); + @Override + public Options getOptions() { + Options options = new Options(); + Option opt; - IGenericClient client = newClient(ctx,""); + opt = new Option("t", "target", true, "Base URL for the target server (e.g. \"http://example.com/fhir\")"); + opt.setRequired(true); + options.addOption(opt); - int total; - int count; - - // String vsContents = - // IOUtils.toString(ValidationDataUploader.class.getResourceAsStream("/org/hl7/fhir/instance/model/valueset/valuesets.xml"), - // "UTF-8"); - // Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, vsContents); - // - // int total = bundle.getEntry().size(); - // int count = 1; - // for (BundleEntryComponent i : bundle.getEntry()) { - // ValueSet next = (ValueSet) i.getResource(); - // next.setId(next.getIdElement().toUnqualifiedVersionless()); - // - // ourLog.info("Uploading ValueSet {}/{} : {}", new Object[] {count,total,next.getIdElement().getValue()}); - // client.update().resource(next).execute(); - // - // count++; - // } - // - // ourLog.info("Finished uploading ValueSets"); + return options; + } -// String vsContents = IOUtils.toString(ValidationDataUploader.class.getResourceAsStream("/org/hl7/fhir/instance/model/valueset/v3-codesystems.xml"), "UTF-8"); -// Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, vsContents); -// total = bundle.getEntry().size(); -// count = 1; -// for (BundleEntryComponent i : bundle.getEntry()) { -// ValueSet next = (ValueSet) i.getResource(); -// next.setId(next.getIdElement().toUnqualifiedVersionless()); -// -// ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[] { count, total, next.getIdElement().getValue() }); -// client.update().resource(next).execute(); -// -// count++; -// } + @Override + public void run(CommandLine theCommandLine) throws ParseException { + String targetServer = theCommandLine.getOptionValue("t"); + if (isBlank(targetServer)) { + throw new ParseException("No target server (-t) specified"); + } else if (targetServer.startsWith("http") == false) { + throw new ParseException("Invalid target server specified, must begin with 'http'"); + } - - String vsContents = IOUtils.toString(ValidationDataUploader.class.getResourceAsStream("/org/hl7/fhir/instance/model/valueset/v2-tables.xml"), "UTF-8"); + FhirContext ctx = FhirContext.forDstu2(); + ourLog.info("Uploading definitions to server: " + targetServer); + + IGenericClient client = newClient(ctx, targetServer); + long start = System.currentTimeMillis(); + + String vsContents; + try { + vsContents = IOUtils.toString(ValidationDataUploader.class.getResourceAsStream("/org/hl7/fhir/instance/model/valueset/valuesets.xml"), "UTF-8"); + } catch (IOException e) { + throw new CommandFailureException(e.toString()); + } Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, vsContents); + + int total = bundle.getEntry().size(); + int count = 1; + for (Entry i : bundle.getEntry()) { + ValueSet next = (ValueSet) i.getResource(); + next.setId(next.getIdElement().toUnqualifiedVersionless()); + + ourLog.info("Uploading ValueSet {}/{} : {}", new Object[] { count, total, next.getIdElement().getValue() }); + client.update().resource(next).execute(); + + count++; + } + + try { + vsContents = IOUtils.toString(ValidationDataUploader.class.getResourceAsStream("/org/hl7/fhir/instance/model/valueset/v3-codesystems.xml"), "UTF-8"); + } catch (IOException e) { + throw new CommandFailureException(e.toString()); + } + + bundle = ctx.newXmlParser().parseResource(Bundle.class, vsContents); total = bundle.getEntry().size(); count = 1; - for (BundleEntryComponent i : bundle.getEntry()) { - if (count > 1900) { + for (Entry i : bundle.getEntry()) { + ValueSet next = (ValueSet) i.getResource(); + next.setId(next.getIdElement().toUnqualifiedVersionless()); + + ourLog.info("Uploading v3-codesystems ValueSet {}/{} : {}", new Object[] { count, total, next.getIdElement().getValue() }); + client.update().resource(next).execute(); + + count++; + } + + try { + vsContents = IOUtils.toString(ValidationDataUploader.class.getResourceAsStream("/org/hl7/fhir/instance/model/valueset/v2-tables.xml"), "UTF-8"); + } catch (IOException e) { + throw new CommandFailureException(e.toString()); + } + bundle = ctx.newXmlParser().parseResource(Bundle.class, vsContents); + total = bundle.getEntry().size(); + count = 1; + for (Entry i : bundle.getEntry()) { ValueSet next = (ValueSet) i.getResource(); next.setId(next.getIdElement().toUnqualifiedVersionless()); ourLog.info("Uploading v2-tables ValueSet {}/{} : {}", new Object[] { count, total, next.getIdElement().getValue() }); client.update().resource(next).execute(); - } count++; } ourLog.info("Finished uploading ValueSets"); ResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver(); - Resource[] mappingLocations = patternResolver.getResources("classpath*:org/hl7/fhir/instance/model/profile/*.profile.xml"); + Resource[] mappingLocations; + try { + mappingLocations = patternResolver.getResources("classpath*:org/hl7/fhir/instance/model/profile/*.profile.xml"); + } catch (IOException e) { + throw new CommandFailureException(e.toString()); + } total = mappingLocations.length; count = 1; for (Resource i : mappingLocations) { - if (count > 140) { - StructureDefinition next = ctx.newXmlParser().parseResource(StructureDefinition.class, IOUtils.toString(i.getInputStream(), "UTF-8")); + StructureDefinition next; + try { + next = ctx.newXmlParser().parseResource(StructureDefinition.class, IOUtils.toString(i.getInputStream(), "UTF-8")); + } catch (DataFormatException | IOException e) { + throw new CommandFailureException(e.toString()); + } next.setId(next.getIdElement().toUnqualifiedVersionless()); ourLog.info("Uploading StructureDefinition {}/{} : {}", new Object[] { count, total, next.getIdElement().getValue() }); - client.update().resource(next).execute(); + try { + client.update().resource(next).execute(); + } catch (Exception e) { + ourLog.warn("Failed to upload {} - {}", next.getIdElement().getValue(), e.getMessage()); } count++; } ourLog.info("Finished uploading ValueSets"); - } + long delay = System.currentTimeMillis() - start; - @Override - public String getCommandDescription() { - // TODO Auto-generated method stub - return null; - } - - @Override - public String getCommandName() { - // TODO Auto-generated method stub - return null; - } - - @Override - public Options getOptions() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void run(CommandLine theCommandLine) throws ParseException { - // TODO Auto-generated method stub - + ourLog.info("Finished uploading definitions to server (took {} ms)", delay); } } diff --git a/hapi-fhir-cli/src/main/resources/logback-cli-on.xml b/hapi-fhir-cli/src/main/resources/logback-cli-on.xml index 4d118ba4a37..e549923a08b 100644 --- a/hapi-fhir-cli/src/main/resources/logback-cli-on.xml +++ b/hapi-fhir-cli/src/main/resources/logback-cli-on.xml @@ -8,38 +8,11 @@ - - - - - - - - - - - - - - - - - - - - - - + - - - + diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java index 95b18ef766e..0b5096f55e4 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java @@ -101,17 +101,15 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2 q = myEntityManager.createNamedQuery("Q_HFJ_SUBSCRIPTION_NEXT_CHECK", SubscriptionTable.class); - q.setParameter("next_check", new Date()); - q.setParameter("status", SubscriptionStatusEnum.ACTIVE); - List subscriptions = q.getResultList(); + Collection subscriptions = mySubscriptionTableDao.finsSubscriptionsWhichNeedToBeChecked(SubscriptionStatusEnum.ACTIVE, new Date()); TransactionTemplate txTemplate = new TransactionTemplate(myTxManager); txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); - for (final SubscriptionTable nextSubscriptionTable : subscriptions) { + for (final Long nextSubscriptionTablePid : subscriptions) { txTemplate.execute(new TransactionCallback() { @Override public Void doInTransaction(TransactionStatus theStatus) { + SubscriptionTable nextSubscriptionTable = mySubscriptionTableDao.findOne(nextSubscriptionTablePid); pollForNewUndeliveredResources(nextSubscriptionTable); return null; } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISubscriptionTableDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISubscriptionTableDao.java index 364815b35d9..e6ee2588323 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISubscriptionTableDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISubscriptionTableDao.java @@ -29,6 +29,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import ca.uhn.fhir.jpa.entity.SubscriptionTable; +import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum; public interface ISubscriptionTableDao extends JpaRepository { @@ -46,4 +47,6 @@ public interface ISubscriptionTableDao extends JpaRepository findInactiveBeforeCutoff(@Param("cutoff") Date theCutoff); + @Query("SELECT t.myId FROM SubscriptionTable t WHERE t.myStatus = :status AND t.myNextCheck <= :next_check") + public Collection finsSubscriptionsWhichNeedToBeChecked(@Param("status") SubscriptionStatusEnum theStatus, @Param("next_check") Date theNextCheck); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SubscriptionTable.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SubscriptionTable.java index ead69ac6e1f..762dc6ceef7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SubscriptionTable.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SubscriptionTable.java @@ -52,7 +52,6 @@ import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum; }) @NamedQueries({ @NamedQuery(name="Q_HFJ_SUBSCRIPTION_SET_STATUS", query="UPDATE SubscriptionTable t SET t.myStatus = :status WHERE t.myResId = :res_id"), - @NamedQuery(name="Q_HFJ_SUBSCRIPTION_NEXT_CHECK", query="SELECT t FROM SubscriptionTable t WHERE t.myStatus = :status AND t.myNextCheck <= :next_check"), @NamedQuery(name="Q_HFJ_SUBSCRIPTION_GET_BY_RES", query="SELECT t FROM SubscriptionTable t WHERE t.myResId = :res_id") }) //@formatter:on diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SubscriptionsDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SubscriptionsDstu2Test.java index aceac69f4b9..012b524e294 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SubscriptionsDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SubscriptionsDstu2Test.java @@ -6,6 +6,7 @@ import static org.junit.Assert.fail; import java.net.URI; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.eclipse.jetty.websocket.api.Session; @@ -19,6 +20,7 @@ import org.hl7.fhir.instance.model.api.IIdType; import org.junit.Test; import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptor; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.dstu2.resource.Observation; import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.model.dstu2.resource.Subscription; @@ -250,6 +252,7 @@ public class SubscriptionsDstu2Test extends BaseResourceProviderDstu2Test { mySubscriptionDao.read(new IdDt("Subscription", socket.mySubsId)); Observation obs = new Observation(); + ResourceMetadataKeyEnum.PROFILES.put(obs, Collections.singletonList(new IdDt("http://foo"))); obs.getSubject().setReference(pId); obs.setStatus(ObservationStatusEnum.FINAL); IIdType afterId1 = myObservationDao.create(obs).getId().toUnqualifiedVersionless(); @@ -301,6 +304,7 @@ public class SubscriptionsDstu2Test extends BaseResourceProviderDstu2Test { IIdType pId = myPatientDao.create(p).getId().toUnqualifiedVersionless(); Subscription subs = new Subscription(); + ResourceMetadataKeyEnum.PROFILES.put(subs, Collections.singletonList(new IdDt("http://foo"))); subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET); subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart()); subs.setStatus(SubscriptionStatusEnum.ACTIVE);