From 65dc9e85b730b372b223281b803d3b04839c2886 Mon Sep 17 00:00:00 2001 From: jkv Date: Tue, 14 Feb 2017 08:01:44 +0100 Subject: [PATCH 1/3] Work in progress bringing SSE to FHIR --- example-projects/hapi-fhir-jaxrs-sse/pom.xml | 91 ++++++++++++ .../example/JaxRsPatientProvider.java | 122 ++++++++++++++++ .../example/jerseyguice/GuiceHk2Helper.java | 132 ++++++++++++++++++ .../GuiceJersey2ServletContextListener.java | 97 +++++++++++++ .../src/main/webapp/WEB-INF/web.xml | 22 +++ .../src/test/java/test/WarTester.java | 14 ++ 6 files changed, 478 insertions(+) create mode 100644 example-projects/hapi-fhir-jaxrs-sse/pom.xml create mode 100644 example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/JaxRsPatientProvider.java create mode 100644 example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceHk2Helper.java create mode 100644 example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceJersey2ServletContextListener.java create mode 100644 example-projects/hapi-fhir-jaxrs-sse/src/main/webapp/WEB-INF/web.xml create mode 100644 example-projects/hapi-fhir-jaxrs-sse/src/test/java/test/WarTester.java diff --git a/example-projects/hapi-fhir-jaxrs-sse/pom.xml b/example-projects/hapi-fhir-jaxrs-sse/pom.xml new file mode 100644 index 00000000000..c4c26d8e718 --- /dev/null +++ b/example-projects/hapi-fhir-jaxrs-sse/pom.xml @@ -0,0 +1,91 @@ + + 4.0.0 + + ca.uhn.hapi.fhir + hapi-fhir + 2.3-SNAPSHOT + ../hapi-deployable-pom/pom.xml + + hapi-fhir-jaxrs-sse + + + + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + + org.eclipse.jetty + jetty-servlet + + + org.eclipse.jetty + jetty-webapp + + + + org.ebaysf.web + cors-filter + 1.0.1 + + + + org.glassfish.jersey.media + jersey-media-sse + ${jersey_version} + + + org.glassfish.jersey.containers + jersey-container-servlet + ${jersey_version} + + + ca.uhn.hapi.fhir + hapi-fhir-jaxrsserver-base + ${project.version} + + + org.slf4j + slf4j-simple + 1.7.21 + + + org.slf4j + jul-to-slf4j + 1.7.21 + + + org.slf4j + slf4j-api + 1.7.21 + + + + org.glassfish.hk2 + hk2-locator + 2.4.0-b34 + + + org.glassfish.hk2 + guice-bridge + 2.4.0-b34 + + + com.google.guava + guava + 21.0 + + + com.google.inject.extensions + guice-servlet + 4.1.0 + + + + diff --git a/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/JaxRsPatientProvider.java b/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/JaxRsPatientProvider.java new file mode 100644 index 00000000000..7f27f1632a7 --- /dev/null +++ b/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/JaxRsPatientProvider.java @@ -0,0 +1,122 @@ +package embedded.example; + +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.glassfish.jersey.media.sse.EventOutput; +import org.glassfish.jersey.media.sse.OutboundEvent; +import org.glassfish.jersey.media.sse.SseBroadcaster; +import org.glassfish.jersey.media.sse.SseFeature; +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Identifier; +import org.hl7.fhir.dstu3.model.Patient; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider; +import ca.uhn.fhir.rest.annotation.ConditionalUrlParam; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.ETagSupportEnum; +import jersey.repackaged.com.google.common.collect.Maps; + +@Singleton +@Path("Patient") +@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML }) +public class JaxRsPatientProvider extends AbstractJaxRsResourceProvider { + + private final Map patients = Maps.newConcurrentMap(); + private final SseBroadcaster broadcaster = new SseBroadcaster(); + + @Inject + public JaxRsPatientProvider() { + super(FhirContext.forDstu3(), JaxRsPatientProvider.class); + + new Thread() { + @Override + public void run() { + try { + while (true) { + Thread.sleep(1000); + final int id = patients.size() + 1; + final Patient p = new Patient(); + final Identifier i = new Identifier(); + i.setValue(id + ""); + p.addName().setFamily("John " + i); + p.getIdentifier().add(i); + p.setId(new IdType(id)); + patients.put(id + "", p); + + + broadcaster.broadcast(new OutboundEvent.Builder().name("patients").data(String.class, patients.size() + "").build()); + } + + } catch (final InterruptedException e) { + e.printStackTrace(); + } + } + }.start(); + } + + @Search + public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) { + final List result = new LinkedList(); + for (final Patient patient : patients.values()) { + Patient single = null; + if (name == null || patient.getName().get(0).getFamilyElement().getValueNotNull() + .equals(name.getValueNotNull())) { + single = patient; + } + if (single != null) { + result.add(single); + } + } + return result; + } + + @Create + public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam final String theConditional) + throws Exception { + + patients.put(patient.getIdentifierFirstRep().getId(), patient); + final MethodOutcome result = new MethodOutcome().setCreated(true); + result.setResource(patient); + result.setId(new IdType(patient.getId())); + return result; + } + + @Override + public ETagSupportEnum getETagSupport() { + return ETagSupportEnum.DISABLED; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + + @GET + @Path("listen") + @Produces(SseFeature.SERVER_SENT_EVENTS) + public EventOutput listenToBroadcast() throws IOException { + final EventOutput eventOutput = new EventOutput(); + eventOutput.write( + new OutboundEvent.Builder().name("patient count").data(String.class, patients.size() + "").build()); + this.broadcaster.add(eventOutput); + return eventOutput; + } +} diff --git a/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceHk2Helper.java b/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceHk2Helper.java new file mode 100644 index 00000000000..81743ff9242 --- /dev/null +++ b/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceHk2Helper.java @@ -0,0 +1,132 @@ +package embedded.example.jerseyguice; + +import java.net.URL; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.spi.Container; +import org.glassfish.jersey.server.spi.ContainerLifecycleListener; +import org.glassfish.jersey.servlet.ServletContainer; +import org.jvnet.hk2.guice.bridge.api.GuiceBridge; +import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; +import com.google.inject.Injector; +import com.google.inject.Scopes; +import com.google.inject.servlet.ServletModule; + +public abstract class GuiceHk2Helper extends ServletModule { + private static final Logger log = LoggerFactory.getLogger(GuiceHk2Helper.class); + + @Override + abstract protected void configureServlets(); + + public interface RestKeyBindingBuilder { + void packages(String... packages); + + void packages(Package... packages); + + void packages(Class... clazz); + } + + protected RestKeyBindingBuilder rest(final String... urlPatterns) { + return new RestKeyBindingBuilderImpl(Arrays.asList(urlPatterns)); + } + + private class RestKeyBindingBuilderImpl implements RestKeyBindingBuilder { + List paths; + + public RestKeyBindingBuilderImpl(final List paths) { + this.paths = paths; + } + + private boolean checkIfPackageExistsAndLog(final String packge) { + boolean exists = false; + final String resourcePath = packge.replace(".", "/"); + final URL resource = getClass().getClassLoader().getResource(resourcePath); + if (resource != null) { + exists = true; + log.info("rest(" + paths + ").packages(" + packge + ")"); + } else { + log.info("No Beans in '" + packge + "' found. Requests " + paths + " will fail."); + } + return exists; + } + + @Override + public void packages(final String... packages) { + final StringBuilder sb = new StringBuilder(); + + for (final String pkg : packages) { + if (sb.length() > 0) { + sb.append(','); + } + checkIfPackageExistsAndLog(pkg); + sb.append(pkg); + } + final Map params = new HashMap<>(); + params.put("javax.ws.rs.Application", GuiceResourceConfig.class.getCanonicalName()); + if (sb.length() > 0) { + params.put("jersey.config.server.provider.packages", sb.toString()); + } + bind(ServletContainer.class).in(Scopes.SINGLETON); + for (final String path : paths) { + serve(path).with(ServletContainer.class, params); + } + } + + @Override + public void packages(final Package... packages) { + packages(FluentIterable.from(packages).transform(new Function() { + + @Override + public String apply(final Package arg0) { + return arg0.getName(); + } + }).toArray(String.class)); + } + + @Override + public void packages(final Class... clazz) { + packages(FluentIterable.from(clazz).transform(new Function, String>() { + + @Override + public String apply(final Class arg0) { + return arg0.getPackage().getName(); + } + }).toArray(String.class)); + } + } +} + +class GuiceResourceConfig extends ResourceConfig { + public GuiceResourceConfig() { + register(new ContainerLifecycleListener() { + @Override + public void onStartup(final Container container) { + final ServletContainer servletContainer = (ServletContainer) container; + final ServiceLocator serviceLocator = container.getApplicationHandler().getServiceLocator(); + GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator); + final GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class); + final Injector injector = (Injector) servletContainer.getServletContext() + .getAttribute(Injector.class.getName()); + guiceBridge.bridgeGuiceInjector(injector); + } + + @Override + public void onReload(final Container container) { + } + + @Override + public void onShutdown(final Container container) { + } + }); + } +} \ No newline at end of file diff --git a/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceJersey2ServletContextListener.java b/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceJersey2ServletContextListener.java new file mode 100644 index 00000000000..77fe796bf38 --- /dev/null +++ b/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceJersey2ServletContextListener.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016 Aberger Software GmbH. All Rights Reserved. + * http://www.aberger.at + * + * 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. + */ + +package embedded.example.jerseyguice; + +import java.awt.Desktop; +import java.net.URI; +import java.util.EnumSet; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import javax.servlet.DispatcherType; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.hl7.fhir.dstu3.model.HumanName; +import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Patient; +import org.slf4j.bridge.SLF4JBridgeHandler; + +import com.google.common.collect.Lists; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Module; +import com.google.inject.Scopes; +import com.google.inject.Stage; +import com.google.inject.name.Names; +import com.google.inject.servlet.GuiceFilter; +import com.google.inject.servlet.GuiceServletContextListener; + +import embedded.example.JaxRsPatientProvider; + +public class GuiceJersey2ServletContextListener extends GuiceServletContextListener { + + @Override + protected Injector getInjector() { + + final List modules = Lists.newArrayList(); + + modules.add(new AbstractModule() { + + @Override + protected void configure() { + final ConcurrentHashMap> patients = new ConcurrentHashMap>(); + for (int i = 0; i < 20; i++) { + + final Patient patient = new Patient(); + patient.getName().add(new HumanName().setFamily("Random Patient " + i)); + patient.setId(new IdType("Patient", "" + i, "" + 1)); + patients.put(String.valueOf(i), Lists.newArrayList(patient)); + + } + } + }); + + modules.add(new GuiceHk2Helper() { + @Override + protected void configureServlets() { + bind(String.class).annotatedWith(Names.named("1")).toInstance("sad"); + + bind(JaxRsPatientProvider.class).in(Scopes.SINGLETON); + rest("/*").packages(JaxRsPatientProvider.class); + } + }); + return Guice.createInjector(Stage.PRODUCTION, modules); + } + + public static void main(final String[] args) throws Exception { + + SLF4JBridgeHandler.removeHandlersForRootLogger(); + SLF4JBridgeHandler.install(); + + final Server server = new Server(8080); + + final ServletContextHandler sch = new ServletContextHandler(server, "/"); + sch.addEventListener(new GuiceJersey2ServletContextListener()); + sch.addFilter(GuiceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); + server.start(); + + Desktop.getDesktop().browse(new URI("http://localhost:8080/Patient")); + } +} \ No newline at end of file diff --git a/example-projects/hapi-fhir-jaxrs-sse/src/main/webapp/WEB-INF/web.xml b/example-projects/hapi-fhir-jaxrs-sse/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..8c985e61d0c --- /dev/null +++ b/example-projects/hapi-fhir-jaxrs-sse/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,22 @@ + + + + Guice Filter + com.google.inject.servlet.GuiceFilter + + + Guice Filter + /* + + + embedded.example.ContextListener + + + + + serverAddress + http://fhirtest.uhn.ca/baseDstu2 + + \ No newline at end of file diff --git a/example-projects/hapi-fhir-jaxrs-sse/src/test/java/test/WarTester.java b/example-projects/hapi-fhir-jaxrs-sse/src/test/java/test/WarTester.java new file mode 100644 index 00000000000..fffbc626c75 --- /dev/null +++ b/example-projects/hapi-fhir-jaxrs-sse/src/test/java/test/WarTester.java @@ -0,0 +1,14 @@ +package test; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.webapp.WebAppContext; + +public class WarTester { + + public static void main(String[] args) throws Exception { + final Server server = new Server(8080); + server.setHandler(new WebAppContext("target/fhirtester.war", "/")); + server.start(); + } + +} From 2cb3aaa2a16ea59bfcbdf6e0d4a2266f5671c1ac Mon Sep 17 00:00:00 2001 From: jkv Date: Tue, 7 Mar 2017 22:45:49 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=E2=80=98Spring=20cleaning=20=E2=80=A6.=20?= =?UTF-8?q?=E2=80=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/JaxRsPatientProvider.java | 75 ++++++++++--------- .../GuiceJersey2ServletContextListener.java | 28 +------ 2 files changed, 43 insertions(+), 60 deletions(-) diff --git a/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/JaxRsPatientProvider.java b/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/JaxRsPatientProvider.java index 7f27f1632a7..eace4ee0df9 100644 --- a/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/JaxRsPatientProvider.java +++ b/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/JaxRsPatientProvider.java @@ -16,12 +16,13 @@ import org.glassfish.jersey.media.sse.EventOutput; import org.glassfish.jersey.media.sse.OutboundEvent; import org.glassfish.jersey.media.sse.SseBroadcaster; import org.glassfish.jersey.media.sse.SseFeature; +import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; import org.hl7.fhir.dstu3.model.IdType; -import org.hl7.fhir.dstu3.model.Identifier; import org.hl7.fhir.dstu3.model.Patient; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider; +import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.rest.annotation.ConditionalUrlParam; import ca.uhn.fhir.rest.annotation.Create; import ca.uhn.fhir.rest.annotation.RequiredParam; @@ -44,42 +45,17 @@ public class JaxRsPatientProvider extends AbstractJaxRsResourceProvider @Inject public JaxRsPatientProvider() { super(FhirContext.forDstu3(), JaxRsPatientProvider.class); - - new Thread() { - @Override - public void run() { - try { - while (true) { - Thread.sleep(1000); - final int id = patients.size() + 1; - final Patient p = new Patient(); - final Identifier i = new Identifier(); - i.setValue(id + ""); - p.addName().setFamily("John " + i); - p.getIdentifier().add(i); - p.setId(new IdType(id)); - patients.put(id + "", p); - - - broadcaster.broadcast(new OutboundEvent.Builder().name("patients").data(String.class, patients.size() + "").build()); - } - - } catch (final InterruptedException e) { - e.printStackTrace(); - } - } - }.start(); } - + @Search public List search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) { final List result = new LinkedList(); for (final Patient patient : patients.values()) { Patient single = null; - if (name == null || patient.getName().get(0).getFamilyElement().getValueNotNull() - .equals(name.getValueNotNull())) { - single = patient; - } + if (name == null + || patient.getName().get(0).getFamilyElement().getValueNotNull().equals(name.getValueNotNull())) { + single = patient; + } if (single != null) { result.add(single); } @@ -91,13 +67,42 @@ public class JaxRsPatientProvider extends AbstractJaxRsResourceProvider public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam final String theConditional) throws Exception { - patients.put(patient.getIdentifierFirstRep().getId(), patient); + storePatient(patient); + final MethodOutcome result = new MethodOutcome().setCreated(true); result.setResource(patient); result.setId(new IdType(patient.getId())); return result; } + // Conceptual wrapper for storing in a db + private void storePatient(final Patient patient) { + + try { + patients.put(patient.getIdentifierFirstRep().getValue(), patient); + // if storing is successful the notify the listeners that listens on + // any patient => patient/* + + final String bundleToString = currentPatientsAsJsonString(); + + broadcaster + .broadcast(new OutboundEvent.Builder().name("patients").data(String.class, bundleToString).build()); + + } catch (final Exception e) { + e.printStackTrace(); + } + + } + + private String currentPatientsAsJsonString() { + final IParser jsonParser = this.getFhirContext().newJsonParser().setPrettyPrint(true); + final org.hl7.fhir.dstu3.model.Bundle bundle = new org.hl7.fhir.dstu3.model.Bundle(); + for (final Patient p : patients.values()) + bundle.addEntry(new BundleEntryComponent().setResource(p)); + final String bundleToString = jsonParser.encodeResourceToString(bundle); + return bundleToString; + } + @Override public ETagSupportEnum getETagSupport() { return ETagSupportEnum.DISABLED; @@ -108,14 +113,16 @@ public class JaxRsPatientProvider extends AbstractJaxRsResourceProvider return Patient.class; } - @GET @Path("listen") @Produces(SseFeature.SERVER_SENT_EVENTS) public EventOutput listenToBroadcast() throws IOException { final EventOutput eventOutput = new EventOutput(); + + final String bundleToString = currentPatientsAsJsonString(); + eventOutput.write( - new OutboundEvent.Builder().name("patient count").data(String.class, patients.size() + "").build()); + new OutboundEvent.Builder().name("patients").data(String.class, bundleToString).build()); this.broadcaster.add(eventOutput); return eventOutput; } diff --git a/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceJersey2ServletContextListener.java b/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceJersey2ServletContextListener.java index 77fe796bf38..2a2bef0e11e 100644 --- a/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceJersey2ServletContextListener.java +++ b/example-projects/hapi-fhir-jaxrs-sse/src/main/java/embedded/example/jerseyguice/GuiceJersey2ServletContextListener.java @@ -21,25 +21,18 @@ import java.awt.Desktop; import java.net.URI; import java.util.EnumSet; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; import javax.servlet.DispatcherType; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; -import org.hl7.fhir.dstu3.model.HumanName; -import org.hl7.fhir.dstu3.model.IdType; -import org.hl7.fhir.dstu3.model.Patient; import org.slf4j.bridge.SLF4JBridgeHandler; import com.google.common.collect.Lists; -import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; -import com.google.inject.Scopes; import com.google.inject.Stage; -import com.google.inject.name.Names; import com.google.inject.servlet.GuiceFilter; import com.google.inject.servlet.GuiceServletContextListener; @@ -52,28 +45,11 @@ public class GuiceJersey2ServletContextListener extends GuiceServletContextListe final List modules = Lists.newArrayList(); - modules.add(new AbstractModule() { - - @Override - protected void configure() { - final ConcurrentHashMap> patients = new ConcurrentHashMap>(); - for (int i = 0; i < 20; i++) { - - final Patient patient = new Patient(); - patient.getName().add(new HumanName().setFamily("Random Patient " + i)); - patient.setId(new IdType("Patient", "" + i, "" + 1)); - patients.put(String.valueOf(i), Lists.newArrayList(patient)); - - } - } - }); - + modules.add(new GuiceHk2Helper() { @Override protected void configureServlets() { - bind(String.class).annotatedWith(Names.named("1")).toInstance("sad"); - - bind(JaxRsPatientProvider.class).in(Scopes.SINGLETON); +// bind(JaxRsPatientProvider.class).in(Scopes.SINGLETON); rest("/*").packages(JaxRsPatientProvider.class); } }); From 22bda7ff2779b5a5c9b8d0596d49d75e9cc90ac2 Mon Sep 17 00:00:00 2001 From: Jens Kristian Villadsen Date: Tue, 7 Mar 2017 23:00:26 +0100 Subject: [PATCH 3/3] Create README.md --- example-projects/hapi-fhir-jaxrs-sse/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 example-projects/hapi-fhir-jaxrs-sse/README.md diff --git a/example-projects/hapi-fhir-jaxrs-sse/README.md b/example-projects/hapi-fhir-jaxrs-sse/README.md new file mode 100644 index 00000000000..8c5785931a9 --- /dev/null +++ b/example-projects/hapi-fhir-jaxrs-sse/README.md @@ -0,0 +1,5 @@ +This example sets up a FHIR server that can ship out Server-sent events using standard Jersey 2.x components. Start up the server and eg. issue the following curl request 'curl -v -X GET http://localhost:8080/Patient/listen'. The will block curl and once any events are shipped to the server, they will automatically be sent to the curl client. + +Changes can be sent to the server on localhost:8080/Patient which accepts any kind of patients that has at least one identifier. + +Voila