OSGi bundle of FHIR base & structures.. allows for runtime plugging of
providers
This commit is contained in:
parent
9de81a1bd8
commit
353f815cc3
|
@ -0,0 +1,52 @@
|
|||
<project name="HAPI FHIR Core OSGi Bundle" default="all">
|
||||
<property file="project.properties"/>
|
||||
<property name="spring.dir" value="${resources.dir}/META-INF/spring" />
|
||||
<property name="bundle.jar" value="${bundle.file.name}_${major.version}.${minor.version}.${micro.version}.jar" />
|
||||
<property name="bundle.file" value="${target.dir}/${bundle.jar}" />
|
||||
<property name="hapi.fhir.base.jar" value="${hapi.fhir.base.name}-${hapi.fhir.version}.jar" />
|
||||
<property name="hapi.fhir.base.file" value="../${hapi.fhir.base.name}/target/${hapi.fhir.base.jar}" />
|
||||
<property name="hapi.fhir.dstu.jar" value="${hapi.fhir.dstu.name}-${hapi.fhir.version}.jar" />
|
||||
<property name="hapi.fhir.dstu.file" value="../${hapi.fhir.dstu.name}/target/${hapi.fhir.dstu.jar}" />
|
||||
<property name="hapi.fhir.dstu2.jar" value="${hapi.fhir.dstu2.name}-${hapi.fhir.version}.jar" />
|
||||
<property name="hapi.fhir.dstu2.file" value="../${hapi.fhir.dstu2.name}/target/${hapi.fhir.dstu2.jar}" />
|
||||
<property name="hapi.fhir.hl7dstu2.jar" value="${hapi.fhir.hl7dstu2.name}-${hapi.fhir.version}.jar" />
|
||||
<property name="hapi.fhir.hl7dstu2.file" value="../${hapi.fhir.hl7dstu2.name}/target/${hapi.fhir.hl7dstu2.jar}" />
|
||||
|
||||
<target name="all" depends="bundle" />
|
||||
|
||||
<target name="init">
|
||||
<delete dir="${obr.target.dir}" failonerror="false"/>
|
||||
<mkdir dir="${obr.target.dir}" />
|
||||
</target>
|
||||
|
||||
<target name="collect.jars" depends="init">
|
||||
<delete dir="${temp.target.dir}" failonerror="false"/>
|
||||
<mkdir dir="${temp.target.dir}" />
|
||||
<copy todir="${temp.target.dir}">
|
||||
<fileset file="${hapi.fhir.base.file}"/>
|
||||
<fileset file="${hapi.fhir.dstu.file}"/>
|
||||
<fileset file="${hapi.fhir.dstu2.file}"/>
|
||||
<fileset file="${hapi.fhir.hl7dstu2.file}"/>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="bundle" depends="collect.jars">
|
||||
<echo>creating HAPI FHIR Core OSGi Bundle</echo>
|
||||
<concat destfile="${temp.target.dir}/MANIFEST.MF">
|
||||
<fileset dir="${resources.dir}/META-INF" includes="MANIFEST.MF" />
|
||||
<footer>
|
||||
Bundle-Classpath: .,
|
||||
lib/${hapi.fhir.base.jar},
|
||||
lib/${hapi.fhir.dstu.jar},
|
||||
lib/${hapi.fhir.dstu2.jar},
|
||||
lib/${hapi.fhir.hl7dstu2.jar}
|
||||
</footer>
|
||||
</concat>
|
||||
<jar destfile="${bundle.file}" manifest="${temp.target.dir}/MANIFEST.MF">
|
||||
<fileset dir="${classes.dir}" includes="**/*" />
|
||||
<zipfileset dir="${temp.target.dir}" includes="*.jar" prefix="lib"/>
|
||||
<zipfileset dir="${spring.dir}" prefix="META-INF/spring"/>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,18 @@
|
|||
#Fri, 31 Jul 2015 17:06:47 -0700
|
||||
bundle.file.name=hapi-fhir-osgi-core
|
||||
major.version=1
|
||||
minor.version=2
|
||||
micro.version=0.SNAPSHOT
|
||||
|
||||
src.dir=./src/main/java
|
||||
resources.dir=./src/main/resources
|
||||
classes.dir=./target/classes
|
||||
target.dir=./target
|
||||
obr.target.dir=./target/build-obr
|
||||
temp.target.dir=./target/build-temp
|
||||
|
||||
hapi.fhir.version=1.2-SNAPSHOT
|
||||
hapi.fhir.base.name=hapi-fhir-base
|
||||
hapi.fhir.dstu.name=hapi-fhir-structures-dstu
|
||||
hapi.fhir.dstu2.name=hapi-fhir-structures-dstu2
|
||||
hapi.fhir.hl7dstu2.name=hapi-fhir-structures-hl7org-dstu2
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* This software has been produced by Akana, Inc. under a professional services
|
||||
* agreement with our customer. This work may contain material that is confidential
|
||||
* and proprietary information of Akana, Inc. and is subject to copyright
|
||||
* protection under laws of the United States of America and other countries.
|
||||
* Akana, Inc. grants the customer non-exclusive rights to this material without
|
||||
* any warranty expressed or implied.
|
||||
*/
|
||||
|
||||
package ca.uhn.fhir.osgi;
|
||||
|
||||
/**
|
||||
* Exception thrown from the Spring-DM/OSGi wiring. These
|
||||
* exceptions are thrown when an error was encountered
|
||||
* that was caused by incorrect wiring.
|
||||
*
|
||||
* @author Akana, Inc. Professional Services
|
||||
*
|
||||
*/
|
||||
public class FhirConfigurationException extends Exception {
|
||||
|
||||
public FhirConfigurationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public FhirConfigurationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public FhirConfigurationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public FhirConfigurationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* This software has been produced by Akana, Inc. under a professional services
|
||||
* agreement with our customer. This work may contain material that is confidential
|
||||
* and proprietary information of Akana, Inc. and is subject to copyright
|
||||
* protection under laws of the United States of America and other countries.
|
||||
* Akana, Inc. grants the customer non-exclusive rights to this material without
|
||||
* any warranty expressed or implied.
|
||||
*/
|
||||
|
||||
package ca.uhn.fhir.osgi;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* This is an abstraction for adding one or more Providers
|
||||
* ("plain" providers as well as Resource Providers)
|
||||
* to the configuration of a Fhir Server. This approach
|
||||
* is needed versus direct publication of providers as
|
||||
* OSGi services because references to OSGi services are
|
||||
* really proxies that only implement the methods of the
|
||||
* service's interfaces. This means that the introspection
|
||||
* and annotation processing needed for HAPI FHIR provider
|
||||
* processing is not possible on those proxy references..
|
||||
*
|
||||
* To get around this restriction, instances of this interface
|
||||
* will be published as OSGi services and the real providers
|
||||
* will typically be Spring wired into the underlying bean.
|
||||
*
|
||||
* Beans that are decorated with this interface can be
|
||||
* published as OSGi services and will be registered in
|
||||
* the specified FHIR Server. The OSGi service definition
|
||||
* should have the following <service-property> entry:
|
||||
*
|
||||
* <entry key="fhir.server.name" value="a-name"/>
|
||||
*
|
||||
* where the value matches the same <service-property>
|
||||
* assigned to a FhirServer OSGi service.
|
||||
*
|
||||
* @author Akana, Inc. Professional Services
|
||||
*
|
||||
*/
|
||||
public interface FhirProviderBundle {
|
||||
public Collection<Object> getProviders();
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* This software has been produced by Akana, Inc. under a professional services
|
||||
* agreement with our customer. This work may contain material that is confidential
|
||||
* and proprietary information of Akana, Inc. and is subject to copyright
|
||||
* protection under laws of the United States of America and other countries.
|
||||
* Akana, Inc. grants the customer non-exclusive rights to this material without
|
||||
* any warranty expressed or implied.
|
||||
*/
|
||||
|
||||
package ca.uhn.fhir.osgi;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
|
||||
/**
|
||||
* Instances of the FHIR Server must implement this interface
|
||||
* in order to be registered as OSGi services capable of dynamic
|
||||
* provider registration. It expected that implementations of this
|
||||
* interface will also extend RestfulService.
|
||||
*
|
||||
* The OSGi service definition for instances of the FHIR SERver
|
||||
* should have the following <service-property> entry:
|
||||
*
|
||||
* <entry key="fhir.server.name" value="a-name"/>
|
||||
*
|
||||
* where the value matches the same <service-property> specified
|
||||
* on the published "provider" OSGi services that are to be
|
||||
* dynamically registered in the FHIR Server instance.
|
||||
*
|
||||
* @author Akana, Inc. Professional Services
|
||||
*
|
||||
*/
|
||||
public interface FhirServer {
|
||||
public static final String SVCPROP_SERVICE_NAME = "fhir.server.name";
|
||||
|
||||
/**
|
||||
* Dynamically registers a single provider with the RestfulServer
|
||||
*
|
||||
* @param provider the provider to be registered
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
public void registerOsgiProvider(Object provider) throws FhirConfigurationException;
|
||||
|
||||
/**
|
||||
* Dynamically unregisters a single provider with the RestfulServer
|
||||
*
|
||||
* @param provider the provider to be unregistered
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
public void unregisterOsgiProvider(Object provider) throws FhirConfigurationException;
|
||||
|
||||
/**
|
||||
* Dynamically registers a list of providers with the RestfulServer
|
||||
*
|
||||
* @param provider the providers to be registered
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
public void registerOsgiProviders(Collection<Object> provider) throws FhirConfigurationException;
|
||||
|
||||
/**
|
||||
* Dynamically unregisters a list of providers with the RestfulServer
|
||||
*
|
||||
* @param provider the providers to be unregistered
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
public void unregisterOsgiProviders(Collection<Object> provider) throws FhirConfigurationException;
|
||||
|
||||
/**
|
||||
* Dynamically unregisters all of providers currently registered
|
||||
*
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
public void unregisterOsgiProviders() throws FhirConfigurationException;
|
||||
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
/**
|
||||
* This software has been produced by Akana, Inc. under a professional services
|
||||
* agreement with our customer. This work may contain material that is confidential
|
||||
* and proprietary information of Akana, Inc. and is subject to copyright
|
||||
* protection under laws of the United States of America and other countries.
|
||||
* SOA Software grants the customer non-exclusive rights to this material without
|
||||
* any warranty expressed or implied.
|
||||
*/
|
||||
|
||||
package ca.uhn.fhir.osgi.impl;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.osgi.FhirConfigurationException;
|
||||
import ca.uhn.fhir.osgi.FhirServer;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Akana, Inc. Professional Services
|
||||
*
|
||||
*/
|
||||
public class FhirServerImpl extends RestfulServer implements FhirServer {
|
||||
private static Logger log = LoggerFactory.getLogger(FhirServerImpl.class);
|
||||
|
||||
private Collection<Object> serverProviders = Collections.synchronizedCollection(new ArrayList<Object>());
|
||||
|
||||
public FhirServerImpl() {
|
||||
super();
|
||||
}
|
||||
|
||||
public FhirServerImpl(FhirContext theCtx) {
|
||||
super(theCtx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically registers a single provider with the RestfulServer
|
||||
*
|
||||
* @param provider the provider to be registered
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
@Override
|
||||
public void registerOsgiProvider (Object provider) throws FhirConfigurationException {
|
||||
if (null == provider) {
|
||||
throw new NullPointerException("FHIR Provider cannot be null");
|
||||
}
|
||||
try {
|
||||
super.registerProvider(provider);
|
||||
log.trace("registered provider. class ["+provider.getClass().getName()+"]");
|
||||
this.serverProviders.add(provider);
|
||||
} catch (Exception e) {
|
||||
log.error("Error registering FHIR Provider", e);
|
||||
throw new FhirConfigurationException("Error registering FHIR Provider", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically unregisters a single provider with the RestfulServer
|
||||
*
|
||||
* @param provider the provider to be unregistered
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
@Override
|
||||
public void unregisterOsgiProvider (Object provider) throws FhirConfigurationException {
|
||||
if (null == provider) {
|
||||
throw new NullPointerException("FHIR Provider cannot be null");
|
||||
}
|
||||
try {
|
||||
this.serverProviders.remove(provider);
|
||||
log.trace("unregistered provider. class ["+provider.getClass().getName()+"]");
|
||||
super.unregisterProvider(provider);
|
||||
} catch (Exception e) {
|
||||
log.error("Error unregistering FHIR Provider", e);
|
||||
throw new FhirConfigurationException("Error unregistering FHIR Provider", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically registers a list of providers with the RestfulServer
|
||||
*
|
||||
* @param provider the providers to be registered
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
@Override
|
||||
public void registerOsgiProviders (Collection<Object> providers) throws FhirConfigurationException {
|
||||
if (null == providers) {
|
||||
throw new NullPointerException("FHIR Provider list cannot be null");
|
||||
}
|
||||
try {
|
||||
super.registerProviders(providers);
|
||||
for (Object provider : providers) {
|
||||
log.trace("registered provider. class ["+provider.getClass().getName()+"]");
|
||||
this.serverProviders.add(provider);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error registering FHIR Providers", e);
|
||||
throw new FhirConfigurationException("Error registering FHIR Providers", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically unregisters a list of providers with the RestfulServer
|
||||
*
|
||||
* @param provider the providers to be unregistered
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
@Override
|
||||
public void unregisterOsgiProviders (Collection<Object> providers) throws FhirConfigurationException {
|
||||
if (null == providers) {
|
||||
throw new NullPointerException("FHIR Provider list cannot be null");
|
||||
}
|
||||
try {
|
||||
for (Object provider : providers) {
|
||||
log.trace("unregistered provider. class ["+provider.getClass().getName()+"]");
|
||||
this.serverProviders.remove(provider);
|
||||
}
|
||||
super.unregisterProvider(providers);
|
||||
} catch (Exception e) {
|
||||
log.error("Error unregistering FHIR Providers", e);
|
||||
throw new FhirConfigurationException("Error unregistering FHIR Providers", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically unregisters all of providers currently registered
|
||||
*
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
@Override
|
||||
public void unregisterOsgiProviders () throws FhirConfigurationException {
|
||||
// need to make a copy to be able to remove items
|
||||
Collection<Object> providers = new ArrayList<Object>();
|
||||
providers.addAll(this.serverProviders);
|
||||
this.unregisterOsgiProviders(providers);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
/**
|
||||
* This software has been produced by Akana, Inc. under a professional services
|
||||
* agreement with our customer. This work may contain material that is confidential
|
||||
* and proprietary information of Akana, Inc. and is subject to copyright
|
||||
* protection under laws of the United States of America and other countries.
|
||||
* SOA Software grants the customer non-exclusive rights to this material without
|
||||
* any warranty expressed or implied.
|
||||
*/
|
||||
|
||||
package ca.uhn.fhir.osgi.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ca.uhn.fhir.osgi.FhirConfigurationException;
|
||||
import ca.uhn.fhir.osgi.FhirProviderBundle;
|
||||
import ca.uhn.fhir.osgi.FhirServer;
|
||||
|
||||
/**
|
||||
* Manage the dynamic registration of FHIR Servers and FHIR Providers.
|
||||
* Methods on this Spring Bean will be invoked from OSGi Reference
|
||||
* Listeners when OSGi services are published for these interfaces.
|
||||
*
|
||||
* @author Akana, Inc. Professional Services
|
||||
*
|
||||
*/
|
||||
public class FhirServerManager {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(FhirServerManager.class);
|
||||
private static final String FIRST_SERVER = "#first";
|
||||
|
||||
private Map<String,FhirServer> registeredServers = new ConcurrentHashMap<>();
|
||||
private Map<String,Collection<Collection<Object>>> serverProviders = new ConcurrentHashMap<>();
|
||||
private Collection<Collection<Object>> registeredProviders = Collections.synchronizedList(new ArrayList<Collection<Object>>());
|
||||
private Map<String,Collection<Collection<Object>>> pendingProviders = new ConcurrentHashMap<>();
|
||||
private boolean haveDefaultProviders = false;
|
||||
|
||||
/**
|
||||
* Register a new FHIR Server OSGi service.
|
||||
* We need to track these services so we can find the correct
|
||||
* server to use when registering/unregistering providers.
|
||||
* <p>
|
||||
* The OSGi service definition of a FHIR Server should look like:
|
||||
* <code><pre>
|
||||
* <osgi:service ref="<b><i>some.bean</i></b>" interface="ca.uhn.fhir.osgi.FhirServer">
|
||||
* <osgi:service-properties>
|
||||
* <entry key="name" value="<b><i>osgi-service-name</i></b>"/>
|
||||
* <entry key="fhir.server.name" value="<b><i>fhir-server-name</i></b>"/>
|
||||
* </osgi:service-properties>
|
||||
* </osgi:service>
|
||||
* </pre></code>
|
||||
* The <b><i>fhir-server-name</i></b> parameter is also specified for all
|
||||
* of the FHIR Providers that are to be dynamically registered with the
|
||||
* named FHIR Server.
|
||||
*
|
||||
* @param server OSGi service implementing the FhirService interface
|
||||
* @param props the <service-properties> for that service
|
||||
*
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
public void registerFhirServer (FhirServer server, Map<String,Object> props) throws FhirConfigurationException {
|
||||
if (server != null) {
|
||||
String serviceName = (String)props.get("name");
|
||||
if (null == serviceName) {
|
||||
serviceName = "<default>";
|
||||
}
|
||||
String serverName = (String)props.get(FhirServer.SVCPROP_SERVICE_NAME);
|
||||
if (serverName != null) {
|
||||
if (registeredServers.containsKey(serverName)) {
|
||||
throw new FhirConfigurationException("FHIR Server named ["+serverName+"] is already registered. These names must be unique.");
|
||||
}
|
||||
log.trace("Registering FHIR Server ["+serverName+"]. (OSGi service named ["+serviceName+"])");
|
||||
registeredServers.put(serverName, server);
|
||||
if (haveDefaultProviders && registeredServers.size() > 1) {
|
||||
throw new FhirConfigurationException("FHIR Providers are registered without a server name. Only one FHIR Server is allowed.");
|
||||
}
|
||||
Collection<Collection<Object>> providers = pendingProviders.get(serverName);
|
||||
if (providers != null) {
|
||||
log.trace("Registering FHIR providers waiting for this server to be registered.");
|
||||
pendingProviders.remove(serverName);
|
||||
for (Collection<Object> list : providers) {
|
||||
this.registerProviders(list, server, serverName);
|
||||
}
|
||||
}
|
||||
if (registeredServers.size() == 1) {
|
||||
providers = pendingProviders.get(FIRST_SERVER);
|
||||
if (providers != null) {
|
||||
log.trace("Registering FHIR providers waiting for the first/only server to be registered.");
|
||||
pendingProviders.remove(FIRST_SERVER);
|
||||
for (Collection<Object> list : providers) {
|
||||
this.registerProviders(list, server, serverName);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new FhirConfigurationException("FHIR Server registered in OSGi is missing the required ["+FhirServer.SVCPROP_SERVICE_NAME+"] service-property");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when a FHIR Server OSGi service
|
||||
* is being removed from the container. This normally will only
|
||||
* occur when its bundle is stopped because it is being removed
|
||||
* or updated.
|
||||
*
|
||||
* @param server OSGi service implementing the FhirService interface
|
||||
* @param props the <service-properties> for that service
|
||||
*
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
public void unregisterFhirServer (FhirServer server, Map<String,Object> props) throws FhirConfigurationException {
|
||||
if (server != null) {
|
||||
String serverName = (String)props.get(FhirServer.SVCPROP_SERVICE_NAME);
|
||||
if (serverName != null) {
|
||||
FhirServer service = registeredServers.get(serverName);
|
||||
if (service != null) {
|
||||
log.trace("Unregistering FHIR Server ["+serverName+"]");
|
||||
service.unregisterOsgiProviders();
|
||||
registeredServers.remove(serverName);
|
||||
log.trace("Dequeue any FHIR providers waiting for this server");
|
||||
pendingProviders.remove(serverName);
|
||||
if (registeredServers.size() == 0) {
|
||||
log.trace("Dequeue any FHIR providers waiting for the first/only server");
|
||||
pendingProviders.remove(FIRST_SERVER);
|
||||
}
|
||||
Collection<Collection<Object>> providers = serverProviders.get(serverName);
|
||||
if (providers != null) {
|
||||
serverProviders.remove(serverName);
|
||||
registeredProviders.removeAll(providers);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new FhirConfigurationException("FHIR Server registered in OSGi is missing the required ["+FhirServer.SVCPROP_SERVICE_NAME+"] service-property");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new FHIR Provider-Bundle OSGi service.
|
||||
*
|
||||
* This could be a "plain" provider that is published with the
|
||||
* FhirProvider interface or it could be a resource provider that
|
||||
* is published with either that same interface or the IResourceProvider
|
||||
* interface.
|
||||
*
|
||||
* (That check is not made here but is included as usage documentation)
|
||||
*
|
||||
* <p>
|
||||
* The OSGi service definition of a FHIR Provider would look like:
|
||||
* <code><pre>
|
||||
* <osgi:service ref="<b><i>some.bean</i></b>" interface="ca.uhn.fhir.osgi.IResourceProvider">
|
||||
* <osgi:service-properties>
|
||||
* <entry key="name" value="<b><i>osgi-service-name</i></b>"/>
|
||||
* <entry key="fhir.server.name" value="<b><i>fhir-server-name</i></b>"/>
|
||||
* </osgi:service-properties>
|
||||
* </osgi:service>
|
||||
* </pre></code>
|
||||
* The <b><i>fhir-server-name</i></b> parameter is the value assigned to the
|
||||
* <code>fhir.server.name</code> service-property of one of the OSGi-published
|
||||
* FHIR Servers.
|
||||
*
|
||||
* @param server OSGi service implementing a FHIR provider interface
|
||||
* @param props the <service-properties> for that service
|
||||
*
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
public void registerFhirProviders (FhirProviderBundle bundle, Map<String,Object> props) throws FhirConfigurationException {
|
||||
if (bundle != null) {
|
||||
Collection<Object> providers = bundle.getProviders();
|
||||
if (providers != null && !providers.isEmpty()) {
|
||||
try {
|
||||
String serverName = (String)props.get(FhirServer.SVCPROP_SERVICE_NAME);
|
||||
String ourServerName = getServerName(serverName);
|
||||
String bundleName = (String)props.get("name");
|
||||
if (null == bundleName) {
|
||||
bundleName = "<default>";
|
||||
}
|
||||
log.trace("Register FHIR Provider Bundle ["+bundleName+"] on FHIR Server ["+ourServerName+"]");
|
||||
FhirServer server = registeredServers.get(ourServerName);
|
||||
if (server != null) {
|
||||
registerProviders(providers, server, serverName);
|
||||
} else {
|
||||
log.trace("Queue the Provider Bundle waiting for FHIR Server to be registered");
|
||||
Collection<Collection<Object>> pending;
|
||||
synchronized(pendingProviders) {
|
||||
pending = pendingProviders.get(serverName);
|
||||
if (null == pending) {
|
||||
pending = Collections.synchronizedCollection(new ArrayList<Collection<Object>>());
|
||||
pendingProviders.put(serverName, pending);
|
||||
}
|
||||
}
|
||||
pending.add(providers);
|
||||
}
|
||||
|
||||
} catch (BadServerException e) {
|
||||
throw new FhirConfigurationException("Unable to register the OSGi FHIR Provider. Multiple Restful Servers exist. Specify the ["+FhirServer.SVCPROP_SERVICE_NAME+"] service-property");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerProviders (Collection<Object> providers, FhirServer server, String serverName) throws FhirConfigurationException {
|
||||
server.registerOsgiProviders(providers);
|
||||
|
||||
Collection<Collection<Object>> active;
|
||||
synchronized(serverProviders) {
|
||||
active = serverProviders.get(serverName);
|
||||
if (null == active) {
|
||||
active = Collections.synchronizedCollection(new ArrayList<Collection<Object>>());
|
||||
serverProviders.put(serverName, active);
|
||||
}
|
||||
}
|
||||
active.add(providers);
|
||||
registeredProviders.add(providers);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called when a FHIR Provider OSGi service
|
||||
* is being removed from the container. This normally will only
|
||||
* occur when its bundle is stopped because it is being removed
|
||||
* or updated.
|
||||
*
|
||||
* @param server OSGi service implementing one of the provider
|
||||
* interfaces
|
||||
* @param props the <service-properties> for that service
|
||||
*
|
||||
* @throws FhirConfigurationException
|
||||
*/
|
||||
public void unregisterFhirProviders (FhirProviderBundle bundle, Map<String,Object> props) throws FhirConfigurationException {
|
||||
if (bundle != null) {
|
||||
Collection<Object> providers = bundle.getProviders();
|
||||
if (providers != null && !providers.isEmpty()) {
|
||||
try {
|
||||
registeredProviders.remove(providers);
|
||||
String serverName = (String)props.get(FhirServer.SVCPROP_SERVICE_NAME);
|
||||
String ourServerName = getServerName(serverName);
|
||||
FhirServer server = registeredServers.get(ourServerName);
|
||||
if (server != null) {
|
||||
|
||||
server.unregisterOsgiProviders(providers);
|
||||
|
||||
Collection<Collection<Object>> active = serverProviders.get(serverName);
|
||||
if (active != null) {
|
||||
active.remove(providers);
|
||||
}
|
||||
}
|
||||
} catch (BadServerException e) {
|
||||
throw new FhirConfigurationException("Unable to register the OSGi FHIR Provider. Multiple Restful Servers exist. Specify the ["+FhirServer.SVCPROP_SERVICE_NAME+"] service-property");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the FHIR Server name allowing for null which would
|
||||
* indicate that the Provider should be registered with the
|
||||
* only FHIR Server defined.
|
||||
*/
|
||||
private String getServerName (String osgiName) throws BadServerException {
|
||||
String result = osgiName;
|
||||
if (null == result) {
|
||||
if (registeredServers.isEmpty()) { // wait for the first one
|
||||
haveDefaultProviders = true; // only allow one server
|
||||
result = FIRST_SERVER;
|
||||
} else
|
||||
if (registeredServers.size() == 1) { // use the only one
|
||||
haveDefaultProviders = true; // only allow one server
|
||||
result = registeredServers.keySet().iterator().next();
|
||||
} else {
|
||||
throw new BadServerException();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
class BadServerException extends Exception {
|
||||
BadServerException() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* This software has been produced by Akana, Inc. under a professional services
|
||||
* agreement with our customer. This work may contain material that is confidential
|
||||
* and proprietary information of Akana, Inc. and is subject to copyright
|
||||
* protection under laws of the United States of America and other countries.
|
||||
* Akana, Inc. grants the customer non-exclusive rights to this material without
|
||||
* any warranty expressed or implied.
|
||||
*/
|
||||
|
||||
package ca.uhn.fhir.osgi.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import ca.uhn.fhir.osgi.FhirProviderBundle;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Akana, Inc. Professional Services
|
||||
*
|
||||
*/
|
||||
public class SimpleFhirProviderBundle implements FhirProviderBundle {
|
||||
|
||||
// /////////////////////////////////////
|
||||
// //////// Spring Wiring ////////
|
||||
// /////////////////////////////////////
|
||||
|
||||
private Collection<Object> providers;
|
||||
|
||||
public void setProviders (Collection<Object> providers) {
|
||||
this.providers = providers;
|
||||
}
|
||||
|
||||
// /////////////////////////////////////
|
||||
// /////////////////////////////////////
|
||||
// /////////////////////////////////////
|
||||
|
||||
public SimpleFhirProviderBundle () {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> getProviders () {
|
||||
return this.providers;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: HAPI FHIR - Core Library and DSTU/DSTU2 Structures
|
||||
Bundle-SymbolicName: hapi-fhir-osgi-core
|
||||
Bundle-Version: 1.2.0.SNAPSHOT
|
||||
Spring-Context: *;publish-context:=false
|
||||
Export-Package: ca.uhn.fhir;version="1.2.0",
|
||||
ca.uhn.fhir.context;version="1.2.0",
|
||||
ca.uhn.fhir.i18n;version="1.2.0",
|
||||
ca.uhn.fhir.model.api;version="1.2.0",
|
||||
ca.uhn.fhir.model.api.annotation;version="1.2.0",
|
||||
ca.uhn.fhir.model.base.composite;version="1.2.0",
|
||||
ca.uhn.fhir.model.base.resource;version="1.2.0",
|
||||
ca.uhn.fhir.model.dstu;version="1.2.0",
|
||||
ca.uhn.fhir.model.dstu.api;version="1.2.0",
|
||||
ca.uhn.fhir.model.dstu.composite;version="1.2.0",
|
||||
ca.uhn.fhir.model.dstu.resource;version="1.2.0",
|
||||
ca.uhn.fhir.model.dstu.valueset;version="1.2.0",
|
||||
ca.uhn.fhir.model.dstu2;version="1.2.0",
|
||||
ca.uhn.fhir.model.dstu2.composite;version="1.2.0",
|
||||
ca.uhn.fhir.model.dstu2.resource;version="1.2.0",
|
||||
ca.uhn.fhir.model.dstu2.valueset;version="1.2.0",
|
||||
ca.uhn.fhir.model.primitive;version="1.2.0",
|
||||
ca.uhn.fhir.model.valueset;version="1.2.0",
|
||||
ca.uhn.fhir.model.view;version="1.2.0",
|
||||
ca.uhn.fhir.narrative;version="1.2.0",
|
||||
ca.uhn.fhir.narrative.datatype;version="1.2.0",
|
||||
ca.uhn.fhir.narrative.title;version="1.2.0",
|
||||
ca.uhn.fhir.osgi;version="1.2.0",
|
||||
ca.uhn.fhir.osgi.impl;version="1.2.0",
|
||||
ca.uhn.fhir.parser;version="1.2.0",
|
||||
ca.uhn.fhir.rest.annotation;version="1.2.0",
|
||||
ca.uhn.fhir.rest.api;version="1.2.0",
|
||||
ca.uhn.fhir.rest.client;version="1.2.0",
|
||||
ca.uhn.fhir.rest.client.api;version="1.2.0",
|
||||
ca.uhn.fhir.rest.client.exceptions;version="1.2.0",
|
||||
ca.uhn.fhir.rest.client.interceptor;version="1.2.0",
|
||||
ca.uhn.fhir.rest.gclient;version="1.2.0",
|
||||
ca.uhn.fhir.rest.method;version="1.2.0",
|
||||
ca.uhn.fhir.rest.param;version="1.2.0",
|
||||
ca.uhn.fhir.rest.server;version="1.2.0",
|
||||
ca.uhn.fhir.rest.server.audit;version="1.2.0",
|
||||
ca.uhn.fhir.rest.server.exceptions;version="1.2.0",
|
||||
ca.uhn.fhir.rest.server.interceptor;version="1.2.0",
|
||||
ca.uhn.fhir.rest.server.provider;version="1.2.0",
|
||||
ca.uhn.fhir.rest.server.provider.dstu2;version="1.2.0",
|
||||
ca.uhn.fhir.rest.server.provider.dstu2hl7org,
|
||||
ca.uhn.fhir.store;version="1.2.0",
|
||||
ca.uhn.fhir.util;version="1.2.0",
|
||||
ca.uhn.fhir.validation;version="1.2.0",
|
||||
org.hl7.fhir.instance;version="1.2.0",
|
||||
org.hl7.fhir.instance.client;version="1.2.0",
|
||||
org.hl7.fhir.instance.conf;version="1.2.0",
|
||||
org.hl7.fhir.instance.formats;version="1.2.0",
|
||||
org.hl7.fhir.instance.model;version="1.2.0",
|
||||
org.hl7.fhir.instance.model.annotations;version="1.2.0",
|
||||
org.hl7.fhir.instance.model.api;version="1.2.0",
|
||||
org.hl7.fhir.instance.model.valuesets;version="1.2.0",
|
||||
org.hl7.fhir.instance.terminologies;version="1.2.0",
|
||||
org.hl7.fhir.instance.utils;version="1.2.0",
|
||||
org.hl7.fhir.instance.validation;version="1.2.0",
|
||||
org.hl7.fhir.utilities;version="1.2.0",
|
||||
org.hl7.fhir.utilities.xhtml;version="1.2.0",
|
||||
org.hl7.fhir.utilities.xml;version="1.2.0"
|
||||
Import-Package: com.ctc.wstx.api;version="4.4.0",
|
||||
com.ctc.wstx.stax;version="4.4.0",
|
||||
com.google.gson;resolution:=optional,
|
||||
com.phloc.commons;resolution:=optional,
|
||||
com.phloc.commons.error;resolution:=optional,
|
||||
com.phloc.schematron;resolution:=optional,
|
||||
com.phloc.schematron.xslt;resolution:=optional,
|
||||
javax.json,
|
||||
javax.json.stream,
|
||||
javax.servlet,
|
||||
javax.servlet.http,
|
||||
javax.xml.parsers,
|
||||
javax.xml.stream,
|
||||
javax.xml.stream,events,
|
||||
net.sf.saxon;resolution:=optional,
|
||||
net.sourceforge.cobertura;resolution:=optional,
|
||||
org.apache.commons.codec.binary,
|
||||
org.apache.commons.io,
|
||||
org.apache.commons.io.input,
|
||||
org.apache.commons.lang3,
|
||||
org.apache.commons.lang3.builder,
|
||||
org.apache.commons.lang3.exception,
|
||||
org.apache.commons.lang3.text,
|
||||
org.apache.commons.lang3.time,
|
||||
org.apache.http;version="4.4.0",
|
||||
org.apache.http.auth;version="4.4.0",
|
||||
org.apache.http.client;version="4.4.0",
|
||||
org.apache.http.client.config;version="4.4.0",
|
||||
org.apache.http.client.entity;version="4.4.0",
|
||||
org.apache.http.client.methods;version="4.4.0",
|
||||
org.apache.http.client.protocol;version="4.4.0",
|
||||
org.apache.http.client.utils;version="4.4.0",
|
||||
org.apache.http.entity;version="4.4.0",
|
||||
org.apache.http.impl.auth;version="4.4.0",
|
||||
org.apache.http.impl.client;version="4.4.0",
|
||||
org.apache.http.impl.conn;version="4.4.0",
|
||||
org.apache.http.message;version="4.4.0",
|
||||
org.apache.http.protocol;version="4.4.0",
|
||||
org.apache.xerces.parsers,
|
||||
org.apache.xerces.xni.parser,
|
||||
org.codehaus.stax2,
|
||||
org.codehaus.stax2.io,
|
||||
org.oclc.purl.dsdl.svrl,
|
||||
org.slf4j,
|
||||
org.thymeleaf,
|
||||
org.thymeleaf.context,
|
||||
org.thymeleaf.dialect,
|
||||
org.thymeleaf.dom,
|
||||
org.thymeleaf.exceptions,
|
||||
org.thymeleaf.messageresolver,
|
||||
org.thymeleaf.processor,
|
||||
org.thymeleaf.processor.attr,
|
||||
org.thymeleaf.resourceresolver,
|
||||
org.thymeleaf.standard,
|
||||
org.thymeleaf.standard.expression,
|
||||
org.thymeleaf.templatemode,
|
||||
org.thymeleaf.templateparser.xmlsax,
|
||||
org.thymeleaf.templateresolver,
|
||||
org.thymeleaf.util,
|
||||
org.unbescape.html,
|
||||
org.unbescape.java,
|
||||
org.unbescape.javascript,
|
||||
org.unbescape.uri,
|
||||
org.w3c.dom,
|
||||
org.w3c.dom.ls,
|
||||
org.xmlpull.v1;resolution:=optional,
|
||||
org.xml.sax,
|
||||
org.xml.sax.ext,
|
||||
org.xml.sax.helpers
|
||||
Bundle-Vendor: University Health Network
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:ctx="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:osgi="http://www.eclipse.org/gemini/blueprint/schema/blueprint"
|
||||
xmlns:osgix="http://www.eclipse.org/gemini/blueprint/schema/blueprint-compendium"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/util
|
||||
http://www.springframework.org/schema/util/spring-util-2.0.xsd
|
||||
http://www.eclipse.org/gemini/blueprint/schema/blueprint-compendium
|
||||
http://www.eclipse.org/gemini/blueprint/schema/blueprint-compendium/gemini-blueprint-compendium.xsd
|
||||
http://www.eclipse.org/gemini/blueprint/schema/blueprint
|
||||
http://www.eclipse.org/gemini/blueprint/schema/blueprint/gemini-blueprint.xsd">
|
||||
|
||||
<!-- ++====================================++
|
||||
|| S E R V E R M A N A G E R ||
|
||||
++====================================++
|
||||
-->
|
||||
<bean id="fhir.server.manager" class="ca.uhn.fhir.osgi.impl.FhirServerManager">
|
||||
</bean>
|
||||
|
||||
<!-- ++=====================++
|
||||
|| S E R V E R S ||
|
||||
++=====================++
|
||||
-->
|
||||
<osgi:list id="fhir.servers" interface="ca.uhn.fhir.osgi.FhirServer" cardinality="0..N">
|
||||
<osgi:listener ref="fhir.server.manager"
|
||||
bind-method="registerFhirServer"
|
||||
unbind-method="unregisterFhirServer" />
|
||||
</osgi:list>
|
||||
|
||||
<!-- ++========================================++
|
||||
|| P R O V I D E R B U N D L E S ||
|
||||
++========================================++
|
||||
-->
|
||||
<osgi:list id="fhir.osgi.providers" interface="ca.uhn.fhir.osgi.FhirProviderBundle" cardinality="0..N" >
|
||||
<osgi:listener ref="fhir.server.manager"
|
||||
bind-method="registerFhirProviders"
|
||||
unbind-method="unregisterFhirProviders" />
|
||||
</osgi:list>
|
||||
|
||||
</beans>
|
Loading…
Reference in New Issue