mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-03-25 01:18:37 +00:00
Add some tests and some cleanup of unused code
This commit is contained in:
parent
f7667d2565
commit
437625505c
@ -806,8 +806,6 @@ class ModelScanner {
|
||||
try {
|
||||
// Datatypes
|
||||
|
||||
ourLog.warn("NEXT: {}", nextValue);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends IBase> dtType = (Class<? extends IBase>) Class.forName(nextValue);
|
||||
retVal.add(dtType);
|
||||
|
@ -75,4 +75,26 @@ public class ProvidedResourceScanner {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any metadata that was added by any {@code ProvidesResources} annotation
|
||||
* present in {@code theProvider}. This method is callled from {@code RestfulService}
|
||||
* when it is unregistering a Resource Provider.
|
||||
*
|
||||
* @param theProvider
|
||||
* - Normally a {@link ca.uhn.fhir.rest.server.IResourceProvider} that might
|
||||
* be annotated with {@link ca.uhn.fhir.model.api.annotation.ProvidesResources}
|
||||
*/
|
||||
public void removeProvidedResources(Object theProvider) {
|
||||
ProvidesResources annotation = theProvider.getClass().getAnnotation(ProvidesResources.class);
|
||||
if (annotation == null)
|
||||
return;
|
||||
for (Class<?> clazz : annotation.resources()) {
|
||||
if (IBaseResource.class.isAssignableFrom(clazz)) {
|
||||
// TODO -- not currently used but should be finished for completeness
|
||||
} else {
|
||||
ourLog.warn(clazz.getSimpleName() + "is not assignable from IResource");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -421,17 +421,8 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
||||
public static class QualifierDetails {
|
||||
|
||||
private String myColonQualifier;
|
||||
|
||||
private String myDotQualifier;
|
||||
|
||||
public String getColonQualifier() {
|
||||
return myColonQualifier;
|
||||
}
|
||||
|
||||
public String getDotQualifier() {
|
||||
return myDotQualifier;
|
||||
}
|
||||
|
||||
public boolean passes(Set<String> theQualifierWhitelist, Set<String> theQualifierBlacklist) {
|
||||
if (theQualifierWhitelist != null) {
|
||||
if (!theQualifierWhitelist.contains(".*")) {
|
||||
@ -445,7 +436,9 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!theQualifierWhitelist.contains(":*")) {
|
||||
/*
|
||||
* This was removed Sep 9 2015, as I don't see any way it could possibly be triggered.
|
||||
if (!theQualifierWhitelist.contains(SearchParameter.QUALIFIER_ANY_TYPE)) {
|
||||
if (myColonQualifier != null) {
|
||||
if (!theQualifierWhitelist.contains(myColonQualifier)) {
|
||||
return false;
|
||||
@ -456,6 +449,7 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
if (theQualifierBlacklist != null) {
|
||||
if (myDotQualifier != null) {
|
||||
|
@ -136,7 +136,7 @@ public class SearchParameter extends BaseQueryParameter {
|
||||
private List<Class<? extends IResource>> myDeclaredTypes;
|
||||
private String myDescription;
|
||||
private String myName;
|
||||
private IParamBinder myParamBinder;
|
||||
private IParamBinder<?> myParamBinder;
|
||||
private RestSearchParameterTypeEnum myParamType;
|
||||
private Set<String> myQualifierBlacklist;
|
||||
private Set<String> myQualifierWhitelist;
|
||||
@ -271,7 +271,7 @@ public class SearchParameter extends BaseQueryParameter {
|
||||
this.myRequired = required;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@SuppressWarnings({ "unchecked", "unused" })
|
||||
public void setType(final Class<?> type, Class<? extends Collection<?>> theInnerCollectionType, Class<? extends Collection<?>> theOuterCollectionType) {
|
||||
this.myType = type;
|
||||
if (IQueryParameterType.class.isAssignableFrom(type)) {
|
||||
|
@ -50,8 +50,6 @@ public abstract class BaseAndListParam<T extends IQueryParameterOr<?>> implement
|
||||
}
|
||||
}
|
||||
|
||||
public abstract RestSearchParameterTypeEnum getSearchParamType();
|
||||
|
||||
abstract T newInstance();
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
import net.sourceforge.cobertura.CoverageIgnore;
|
||||
|
||||
/*
|
||||
@ -41,11 +40,6 @@ public class CompositeAndListParam<A extends IQueryParameterType, B extends IQue
|
||||
return new CompositeOrListParam<A,B>(myLeftType, myRightType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestSearchParameterTypeEnum getSearchParamType() {
|
||||
return RestSearchParameterTypeEnum.COMPOSITE;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public CompositeAndListParam<A, B> addAnd(CompositeOrListParam<A, B> theValue) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
import net.sourceforge.cobertura.CoverageIgnore;
|
||||
|
||||
/*
|
||||
@ -31,11 +30,6 @@ public class DateAndListParam extends BaseAndListParam<DateOrListParam> {
|
||||
return new DateOrListParam();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestSearchParameterTypeEnum getSearchParamType() {
|
||||
return RestSearchParameterTypeEnum.DATE;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public DateAndListParam addAnd(DateOrListParam theValue) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
import net.sourceforge.cobertura.CoverageIgnore;
|
||||
|
||||
/*
|
||||
@ -31,11 +30,6 @@ public class NumberAndListParam extends BaseAndListParam<NumberOrListParam> {
|
||||
return new NumberOrListParam();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestSearchParameterTypeEnum getSearchParamType() {
|
||||
return RestSearchParameterTypeEnum.NUMBER;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public NumberAndListParam addAnd(NumberOrListParam theValue) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
import net.sourceforge.cobertura.CoverageIgnore;
|
||||
|
||||
/*
|
||||
@ -30,11 +29,6 @@ public class QuantityAndListParam extends BaseAndListParam<QuantityOrListParam>
|
||||
QuantityOrListParam newInstance() {
|
||||
return new QuantityOrListParam();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestSearchParameterTypeEnum getSearchParamType() {
|
||||
return RestSearchParameterTypeEnum.QUANTITY;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
|
@ -1,6 +1,5 @@
|
||||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
import net.sourceforge.cobertura.CoverageIgnore;
|
||||
|
||||
/*
|
||||
@ -31,11 +30,6 @@ public class ReferenceAndListParam extends BaseAndListParam<ReferenceOrListParam
|
||||
return new ReferenceOrListParam();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestSearchParameterTypeEnum getSearchParamType() {
|
||||
return RestSearchParameterTypeEnum.REFERENCE;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public ReferenceAndListParam addAnd(ReferenceOrListParam theValue) {
|
||||
|
@ -30,11 +30,6 @@ public class StringAndListParam extends BaseAndListParam<StringOrListParam> {
|
||||
StringOrListParam newInstance() {
|
||||
return new StringOrListParam();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestSearchParameterTypeEnum getSearchParamType() {
|
||||
return RestSearchParameterTypeEnum.STRING;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
|
@ -31,11 +31,6 @@ public class TokenAndListParam extends BaseAndListParam<TokenOrListParam> {
|
||||
return new TokenOrListParam();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestSearchParameterTypeEnum getSearchParamType() {
|
||||
return RestSearchParameterTypeEnum.TOKEN;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public TokenAndListParam addAnd(TokenOrListParam theValue) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
import net.sourceforge.cobertura.CoverageIgnore;
|
||||
|
||||
/*
|
||||
@ -31,11 +30,6 @@ public class UriAndListParam extends BaseAndListParam<UriOrListParam> {
|
||||
return new UriOrListParam();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestSearchParameterTypeEnum getSearchParamType() {
|
||||
return RestSearchParameterTypeEnum.URI;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public UriAndListParam addAnd(UriOrListParam theValue) {
|
||||
|
@ -33,4 +33,12 @@ public interface IServerConformanceProvider<T extends IBaseResource> {
|
||||
*/
|
||||
public abstract T getServerConformance(HttpServletRequest theRequest);
|
||||
|
||||
/**
|
||||
* This setter is needed in implementation classes (along with
|
||||
* a no-arg constructor) to avoid reference cycles in the
|
||||
* Spring wiring of a RestfulServer instance.
|
||||
*
|
||||
* @param theRestfulServer
|
||||
*/
|
||||
public void setRestfulServer (RestfulServer theRestfulServer);
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.UnavailableException;
|
||||
@ -92,9 +94,10 @@ public class RestfulServer extends HttpServlet {
|
||||
private String myImplementationDescription;
|
||||
private final List<IServerInterceptor> myInterceptors = new ArrayList<IServerInterceptor>();
|
||||
private IPagingProvider myPagingProvider;
|
||||
private Collection<Object> myPlainProviders;
|
||||
private Collection<Object> myPlainProviders = new ArrayList<Object>();
|
||||
private Map<String, ResourceBinding> myResourceNameToBinding = new HashMap<String, ResourceBinding>();
|
||||
private Collection<IResourceProvider> myResourceProviders;
|
||||
private Collection<IResourceProvider> myResourceProviders = new ArrayList<IResourceProvider>();
|
||||
private Map<String,IResourceProvider> myTypeToProvider = new HashMap<String, IResourceProvider>();
|
||||
private IServerAddressStrategy myServerAddressStrategy = new IncomingRequestAddressStrategy();
|
||||
private ResourceBinding myServerBinding = new ResourceBinding();
|
||||
private BaseMethodBinding<?> myServerConformanceMethod;
|
||||
@ -104,6 +107,7 @@ public class RestfulServer extends HttpServlet {
|
||||
private String myServerVersion = VersionUtil.getVersion();
|
||||
private boolean myStarted;
|
||||
private boolean myUseBrowserFriendlyContentTypes;
|
||||
private Lock myProviderRegistrationMutex = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Constructor. Note that if no {@link FhirContext} is passed in to the server (either through the constructor, or through {@link #setFhirContext(FhirContext)}) the server will determine which
|
||||
@ -192,6 +196,46 @@ public class RestfulServer extends HttpServlet {
|
||||
return theServletPath.length() + delta;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove registered RESTful methods for a Provider
|
||||
* (and all superclasses) when it is being unregistered
|
||||
*/
|
||||
private void removeResourceMethods (Object theProvider) throws Exception {
|
||||
ourLog.info("Removing RESTful methods for: {}", theProvider.getClass());
|
||||
Class<?> clazz = theProvider.getClass();
|
||||
Class<?> supertype = clazz.getSuperclass();
|
||||
Collection<String> resourceNames = new ArrayList<String>();
|
||||
while (!Object.class.equals(supertype)) {
|
||||
removeResourceMethods(theProvider, supertype, resourceNames);
|
||||
supertype = supertype.getSuperclass();
|
||||
}
|
||||
removeResourceMethods(theProvider, clazz, resourceNames);
|
||||
for (String resourceName : resourceNames) {
|
||||
myResourceNameToBinding.remove(resourceName);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect the set of RESTful methods for a single class
|
||||
* when it is being unregistered
|
||||
*/
|
||||
private void removeResourceMethods(Object theProvider, Class<?> clazz, Collection<String> resourceNames) throws ConfigurationException {
|
||||
for (Method m : ReflectionUtil.getDeclaredMethods(clazz)) {
|
||||
BaseMethodBinding<?> foundMethodBinding = BaseMethodBinding.bindMethod(m, getFhirContext(), theProvider);
|
||||
if (foundMethodBinding == null) {
|
||||
continue; // not a bound method
|
||||
}
|
||||
if (foundMethodBinding instanceof ConformanceMethodBinding) {
|
||||
myServerConformanceMethod = null;
|
||||
continue;
|
||||
}
|
||||
String resourceName = foundMethodBinding.getResourceName();
|
||||
if (!resourceNames.contains(resourceName)) {
|
||||
resourceNames.add(resourceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findResourceMethods(Object theProvider) throws Exception {
|
||||
|
||||
ourLog.info("Scanning type for RESTful methods: {}", theProvider.getClass());
|
||||
@ -768,79 +812,61 @@ public class RestfulServer extends HttpServlet {
|
||||
*/
|
||||
@Override
|
||||
public final void init() throws ServletException {
|
||||
initialize();
|
||||
|
||||
Object confProvider;
|
||||
myProviderRegistrationMutex.lock();
|
||||
try {
|
||||
ourLog.info("Initializing HAPI FHIR restful server running in " + getFhirContext().getVersion().getVersion().name() + " mode");
|
||||
initialize();
|
||||
|
||||
Object confProvider;
|
||||
try {
|
||||
ourLog.info("Initializing HAPI FHIR restful server running in " + getFhirContext().getVersion().getVersion().name() + " mode");
|
||||
|
||||
ProvidedResourceScanner providedResourceScanner = new ProvidedResourceScanner(getFhirContext());
|
||||
providedResourceScanner.scanForProvidedResources(this);
|
||||
ProvidedResourceScanner providedResourceScanner = new ProvidedResourceScanner(getFhirContext());
|
||||
providedResourceScanner.scanForProvidedResources(this);
|
||||
|
||||
Collection<IResourceProvider> resourceProvider = getResourceProviders();
|
||||
if (resourceProvider != null) {
|
||||
Map<String, IResourceProvider> typeToProvider = new HashMap<String, IResourceProvider>();
|
||||
for (IResourceProvider nextProvider : resourceProvider) {
|
||||
Collection<IResourceProvider> resourceProvider = getResourceProviders();
|
||||
// 'true' tells registerProviders() that
|
||||
// this call is part of initialization
|
||||
registerProviders(resourceProvider, true);
|
||||
|
||||
Class<? extends IBaseResource> resourceType = nextProvider.getResourceType();
|
||||
if (resourceType == null) {
|
||||
throw new NullPointerException("getResourceType() on class '" + nextProvider.getClass().getCanonicalName() + "' returned null");
|
||||
}
|
||||
Collection<Object> providers = getPlainProviders();
|
||||
// 'true' tells registerProviders() that
|
||||
// this call is part of initialization
|
||||
registerProviders(providers, true);
|
||||
|
||||
String resourceName = getFhirContext().getResourceDefinition(resourceType).getName();
|
||||
if (typeToProvider.containsKey(resourceName)) {
|
||||
throw new ServletException("Multiple resource providers return resource type[" + resourceName + "]: First[" + typeToProvider.get(resourceName).getClass().getCanonicalName()
|
||||
+ "] and Second[" + nextProvider.getClass().getCanonicalName() + "]");
|
||||
}
|
||||
typeToProvider.put(resourceName, nextProvider);
|
||||
providedResourceScanner.scanForProvidedResources(nextProvider);
|
||||
findResourceMethods(getServerProfilesProvider());
|
||||
|
||||
confProvider = getServerConformanceProvider();
|
||||
if (confProvider == null) {
|
||||
confProvider = getFhirContext().getVersion().createServerConformanceProvider(this);
|
||||
}
|
||||
ourLog.info("Got {} resource providers", typeToProvider.size());
|
||||
for (IResourceProvider provider : typeToProvider.values()) {
|
||||
assertProviderIsValid(provider);
|
||||
findResourceMethods(provider);
|
||||
// findSystemMethods(confProvider);
|
||||
findResourceMethods(confProvider);
|
||||
|
||||
} catch (Exception ex) {
|
||||
ourLog.error("An error occurred while loading request handlers!", ex);
|
||||
throw new ServletException("Failed to initialize FHIR Restful server", ex);
|
||||
}
|
||||
|
||||
ourLog.trace("Invoking provider initialize methods");
|
||||
if (getResourceProviders() != null) {
|
||||
for (IResourceProvider iResourceProvider : getResourceProviders()) {
|
||||
invokeInitialize(iResourceProvider);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<Object> providers = getPlainProviders();
|
||||
if (providers != null) {
|
||||
for (Object next : providers) {
|
||||
assertProviderIsValid(next);
|
||||
findResourceMethods(next);
|
||||
if (confProvider != null) {
|
||||
invokeInitialize(confProvider);
|
||||
}
|
||||
if (getPlainProviders() != null) {
|
||||
for (Object next : getPlainProviders()) {
|
||||
invokeInitialize(next);
|
||||
}
|
||||
}
|
||||
|
||||
findResourceMethods(getServerProfilesProvider());
|
||||
|
||||
confProvider = getServerConformanceProvider();
|
||||
if (confProvider == null) {
|
||||
confProvider = getFhirContext().getVersion().createServerConformanceProvider(this);
|
||||
}
|
||||
// findSystemMethods(confProvider);
|
||||
findResourceMethods(confProvider);
|
||||
|
||||
} catch (Exception ex) {
|
||||
ourLog.error("An error occurred while loading request handlers!", ex);
|
||||
throw new ServletException("Failed to initialize FHIR Restful server", ex);
|
||||
|
||||
myStarted = true;
|
||||
ourLog.info("A FHIR has been lit on this server");
|
||||
} finally {
|
||||
myProviderRegistrationMutex.unlock();
|
||||
}
|
||||
|
||||
ourLog.trace("Invoking provider initialize methods");
|
||||
if (getResourceProviders() != null) {
|
||||
for (IResourceProvider iResourceProvider : getResourceProviders()) {
|
||||
invokeInitialize(iResourceProvider);
|
||||
}
|
||||
}
|
||||
if (confProvider != null) {
|
||||
invokeInitialize(confProvider);
|
||||
}
|
||||
if (getPlainProviders() != null) {
|
||||
for (Object next : getPlainProviders()) {
|
||||
invokeInitialize(next);
|
||||
}
|
||||
}
|
||||
|
||||
myStarted = true;
|
||||
ourLog.info("A FHIR has been lit on this server");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -854,6 +880,153 @@ public class RestfulServer extends HttpServlet {
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a single provider. This could be a Resource Provider
|
||||
* or a "plain" provider not associated with any resource.
|
||||
*
|
||||
* @param provider
|
||||
* @throws Exception
|
||||
*/
|
||||
public void registerProvider (Object provider) throws Exception {
|
||||
if (provider != null) {
|
||||
Collection<Object> providerList = new ArrayList<Object>(1);
|
||||
providerList.add(provider);
|
||||
registerProviders(providerList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a group of providers. These could be Resource Providers,
|
||||
* "plain" providers or a mixture of the two.
|
||||
*
|
||||
* @param providers a {@code Collection} of providers. The parameter
|
||||
* could be null or an empty {@code Collection}
|
||||
* @throws Exception
|
||||
*/
|
||||
public void registerProviders (Collection<? extends Object> providers) throws Exception {
|
||||
myProviderRegistrationMutex.lock();
|
||||
try {
|
||||
if (!myStarted) {
|
||||
for (Object provider : providers) {
|
||||
ourLog.info("Registration of provider ["+provider.getClass().getName()+"] will be delayed until FHIR server startup");
|
||||
if (provider instanceof IResourceProvider) {
|
||||
myResourceProviders.add((IResourceProvider)provider);
|
||||
} else {
|
||||
myPlainProviders.add(provider);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
myProviderRegistrationMutex.unlock();
|
||||
}
|
||||
registerProviders(providers, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Inner method to actually register providers
|
||||
*/
|
||||
protected void registerProviders (Collection<? extends Object> providers, boolean inInit) throws Exception {
|
||||
List<IResourceProvider> newResourceProviders = new ArrayList<IResourceProvider>();
|
||||
List<Object> newPlainProviders = new ArrayList<Object>();
|
||||
ProvidedResourceScanner providedResourceScanner = new ProvidedResourceScanner(getFhirContext());
|
||||
|
||||
if (providers != null) {
|
||||
for (Object provider : providers) {
|
||||
if (provider instanceof IResourceProvider) {
|
||||
IResourceProvider rsrcProvider = (IResourceProvider)provider;
|
||||
Class<? extends IBaseResource> resourceType = rsrcProvider.getResourceType();
|
||||
if (resourceType == null) {
|
||||
throw new NullPointerException("getResourceType() on class '" + rsrcProvider.getClass().getCanonicalName() + "' returned null");
|
||||
}
|
||||
String resourceName = getFhirContext().getResourceDefinition(resourceType).getName();
|
||||
if (myTypeToProvider.containsKey(resourceName)) {
|
||||
throw new ServletException("Multiple resource providers return resource type[" + resourceName + "]: First[" + myTypeToProvider.get(resourceName).getClass().getCanonicalName() + "] and Second[" + rsrcProvider.getClass().getCanonicalName() + "]");
|
||||
}
|
||||
if (!inInit) {
|
||||
myResourceProviders.add(rsrcProvider);
|
||||
}
|
||||
myTypeToProvider.put(resourceName, rsrcProvider);
|
||||
providedResourceScanner.scanForProvidedResources(rsrcProvider);
|
||||
newResourceProviders.add(rsrcProvider);
|
||||
} else {
|
||||
if (!inInit) {
|
||||
myPlainProviders.add(provider);
|
||||
}
|
||||
newPlainProviders.add(provider);
|
||||
}
|
||||
|
||||
}
|
||||
if (!newResourceProviders.isEmpty()) {
|
||||
ourLog.info("Added {} resource provider(s). Total {}", newResourceProviders.size(), myTypeToProvider.size());
|
||||
for (IResourceProvider provider : newResourceProviders) {
|
||||
assertProviderIsValid(provider);
|
||||
findResourceMethods(provider);
|
||||
}
|
||||
}
|
||||
if (!newPlainProviders.isEmpty()) {
|
||||
ourLog.info("Added {} plain provider(s). Total {}", newPlainProviders.size());
|
||||
for (Object provider : newPlainProviders) {
|
||||
assertProviderIsValid(provider);
|
||||
findResourceMethods(provider);
|
||||
}
|
||||
}
|
||||
if (!inInit) {
|
||||
ourLog.trace("Invoking provider initialize methods");
|
||||
if (!newResourceProviders.isEmpty()) {
|
||||
for (IResourceProvider provider : newResourceProviders) {
|
||||
invokeInitialize(provider);
|
||||
}
|
||||
}
|
||||
if (!newPlainProviders.isEmpty()) {
|
||||
for (Object provider : newPlainProviders) {
|
||||
invokeInitialize(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister one provider (either a Resource provider or a plain provider)
|
||||
*
|
||||
* @param provider
|
||||
* @throws Exception
|
||||
*/
|
||||
public void unregisterProvider (Object provider) throws Exception {
|
||||
if (provider != null) {
|
||||
Collection<Object> providerList = new ArrayList<Object>(1);
|
||||
providerList.add(provider);
|
||||
unregisterProviders(providerList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a {@code Collection} of providers
|
||||
*
|
||||
* @param providers
|
||||
* @throws Exception
|
||||
*/
|
||||
public void unregisterProviders (Collection<? extends Object> providers) throws Exception {
|
||||
ProvidedResourceScanner providedResourceScanner = new ProvidedResourceScanner(getFhirContext());
|
||||
if (providers != null) {
|
||||
for (Object provider : providers) {
|
||||
removeResourceMethods(provider);
|
||||
if (provider instanceof IResourceProvider) {
|
||||
myResourceProviders.remove(provider);
|
||||
IResourceProvider rsrcProvider = (IResourceProvider)provider;
|
||||
Class<? extends IBaseResource> resourceType = rsrcProvider.getResourceType();
|
||||
String resourceName = getFhirContext().getResourceDefinition(resourceType).getName();
|
||||
myTypeToProvider.remove(resourceName);
|
||||
providedResourceScanner.removeProvidedResources(rsrcProvider);
|
||||
} else {
|
||||
myPlainProviders.remove(provider);
|
||||
}
|
||||
invokeDestroy(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeDestroy(Object theProvider) {
|
||||
invokeDestroy(theProvider, theProvider.getClass());
|
||||
}
|
||||
@ -1093,6 +1266,19 @@ public class RestfulServer extends HttpServlet {
|
||||
if (myStarted) {
|
||||
throw new IllegalStateException("Server is already started");
|
||||
}
|
||||
|
||||
// call the setRestfulServer() method to point the Conformance
|
||||
// Provider to this server instance. This is done to avoid
|
||||
// passing the server into the constructor. Having that sort
|
||||
// of cross linkage causes reference cycles in Spring wiring
|
||||
try {
|
||||
Method setRestfulServer = theServerConformanceProvider.getClass().getMethod("setRestfulServer", new Class[]{RestfulServer.class});
|
||||
if (setRestfulServer != null) {
|
||||
setRestfulServer.invoke(theServerConformanceProvider, new Object[]{this});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ourLog.warn("Error calling IServerConformanceProvider.setRestfulServer", e);
|
||||
}
|
||||
myServerConformanceProvider = theServerConformanceProvider;
|
||||
}
|
||||
|
||||
|
52
hapi-fhir-osgi-core/build.xml
Normal file
52
hapi-fhir-osgi-core/build.xml
Normal file
@ -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>
|
37
hapi-fhir-osgi-core/pom.xml
Normal file
37
hapi-fhir-osgi-core/pom.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<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>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>1.2-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-osgi-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<url>http://jamesagnew.github.io/hapi-fhir/</url>
|
||||
|
||||
<name>HAPI FHIR - OSGi Bundle</name>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>1.2-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
18
hapi-fhir-osgi-core/project.properties
Normal file
18
hapi-fhir-osgi-core/project.properties
Normal file
@ -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,50 @@
|
||||
package ca.uhn.fhir.osgi;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - OSGi Bundle
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 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%
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* 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,56 @@
|
||||
package ca.uhn.fhir.osgi;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - OSGi Bundle
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 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%
|
||||
*/
|
||||
|
||||
|
||||
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,87 @@
|
||||
package ca.uhn.fhir.osgi;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - OSGi Bundle
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 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%
|
||||
*/
|
||||
|
||||
|
||||
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,157 @@
|
||||
package ca.uhn.fhir.osgi.impl;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - OSGi Bundle
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 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%
|
||||
*/
|
||||
|
||||
|
||||
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,301 @@
|
||||
package ca.uhn.fhir.osgi.impl;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - OSGi Bundle
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 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%
|
||||
*/
|
||||
|
||||
|
||||
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<String,FhirServer>();
|
||||
private Map<String,Collection<Collection<Object>>> serverProviders = new ConcurrentHashMap<String,Collection<Collection<Object>>>();
|
||||
private Collection<Collection<Object>> registeredProviders = Collections.synchronizedList(new ArrayList<Collection<Object>>());
|
||||
private Map<String,Collection<Collection<Object>>> pendingProviders = new ConcurrentHashMap<String,Collection<Collection<Object>>>();
|
||||
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,58 @@
|
||||
package ca.uhn.fhir.osgi.impl;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - OSGi Bundle
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 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%
|
||||
*/
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
134
hapi-fhir-osgi-core/src/main/resources/META-INF/MANIFEST.MF
Normal file
134
hapi-fhir-osgi-core/src/main/resources/META-INF/MANIFEST.MF
Normal file
@ -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>
|
@ -77,11 +77,25 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
private boolean myCache = true;
|
||||
private volatile Conformance myConformance;
|
||||
private String myPublisher = "Not provided";
|
||||
private final RestfulServer myRestfulServer;
|
||||
private RestfulServer myRestfulServer;
|
||||
|
||||
public ServerConformanceProvider(RestfulServer theRestfulServer) {
|
||||
myRestfulServer = theRestfulServer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a no-arg constructor and seetter so that the
|
||||
* ServerConfirmanceProvider can be Spring-wired with
|
||||
* the RestfulService avoiding the potential reference
|
||||
* cycle that would happen.
|
||||
*/
|
||||
public ServerConformanceProvider () {
|
||||
super();
|
||||
}
|
||||
|
||||
public void setRestfulServer (RestfulServer theRestfulServer) {
|
||||
myRestfulServer = theRestfulServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the "publisher" that will be placed in the generated conformance statement. As this
|
||||
|
@ -15,6 +15,36 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class DateRangeParamTest {
|
||||
|
||||
@Test
|
||||
public void testAndList() {
|
||||
assertNotNull(new DateAndListParam().newInstance());
|
||||
assertNotNull(new NumberAndListParam().newInstance());
|
||||
assertNotNull(new ReferenceAndListParam().newInstance());
|
||||
assertNotNull(new QuantityAndListParam().newInstance());
|
||||
assertNotNull(new UriAndListParam().newInstance());
|
||||
assertNotNull(new StringAndListParam().newInstance());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAnd() {
|
||||
assertEquals(1, new DateAndListParam().addAnd(new DateOrListParam()).getValuesAsQueryTokens().size());
|
||||
assertEquals(1, new NumberAndListParam().addAnd(new NumberOrListParam()).getValuesAsQueryTokens().size());
|
||||
assertEquals(1, new ReferenceAndListParam().addAnd(new ReferenceOrListParam()).getValuesAsQueryTokens().size());
|
||||
assertEquals(1, new QuantityAndListParam().addAnd(new QuantityOrListParam()).getValuesAsQueryTokens().size());
|
||||
assertEquals(1, new UriAndListParam().addAnd(new UriOrListParam()).getValuesAsQueryTokens().size());
|
||||
assertEquals(1, new StringAndListParam().addAnd(new StringOrListParam()).getValuesAsQueryTokens().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrList() {
|
||||
assertNotNull(new DateOrListParam().newInstance());
|
||||
assertNotNull(new NumberOrListParam().newInstance());
|
||||
assertNotNull(new ReferenceOrListParam().newInstance());
|
||||
assertNotNull(new QuantityOrListParam().newInstance());
|
||||
assertNotNull(new UriOrListParam().newInstance());
|
||||
assertNotNull(new StringOrListParam().newInstance());
|
||||
}
|
||||
|
||||
private static DateRangeParam create(String theLower, String theUpper) throws InvalidRequestException {
|
||||
DateRangeParam p = new DateRangeParam();
|
||||
List<QualifiedParamList> tokens = new ArrayList<QualifiedParamList>();
|
||||
|
@ -123,6 +123,7 @@ public class DateRangeParamSearchTest {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Patient.class;
|
||||
|
@ -19,8 +19,7 @@ package ca.uhn.fhir.rest.server.provider.dstu2;
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -76,7 +75,6 @@ import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
||||
import ca.uhn.fhir.rest.server.ResourceBinding;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
|
||||
/**
|
||||
@ -94,11 +92,25 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
|
||||
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
|
||||
private String myPublisher = "Not provided";
|
||||
private final RestfulServer myRestfulServer;
|
||||
private RestfulServer myRestfulServer;
|
||||
|
||||
public ServerConformanceProvider(RestfulServer theRestfulServer) {
|
||||
myRestfulServer = theRestfulServer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a no-arg constructor and seetter so that the
|
||||
* ServerConfirmanceProvider can be Spring-wired with
|
||||
* the RestfulService avoiding the potential reference
|
||||
* cycle that would happen.
|
||||
*/
|
||||
public ServerConformanceProvider () {
|
||||
super();
|
||||
}
|
||||
|
||||
public void setRestfulServer (RestfulServer theRestfulServer) {
|
||||
myRestfulServer = theRestfulServer;
|
||||
}
|
||||
|
||||
private void checkBindingForSystemOps(Rest rest, Set<SystemRestfulInteractionEnum> systemOps, BaseMethodBinding<?> nextMethodBinding) {
|
||||
if (nextMethodBinding.getRestOperationType() != null) {
|
||||
|
@ -7,6 +7,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -21,6 +22,7 @@ import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -29,7 +31,10 @@ import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.param.DateAndListParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.util.PatternMatcher;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
|
||||
@ -42,10 +47,72 @@ public class SearchDstu2Test {
|
||||
private static FhirContext ourCtx = FhirContext.forDstu2();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchDstu2Test.class);
|
||||
private static int ourPort;
|
||||
|
||||
private static InstantDt ourReturnPublished;
|
||||
|
||||
private static Server ourServer;
|
||||
private static String ourLastMethod;
|
||||
private static DateAndListParam ourLastDateAndList;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastMethod = null;
|
||||
ourLastDateAndList = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWhitelist01Failing() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWhitelist01&ref=value");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchDateAndList() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?searchDateAndList=2001,2002&searchDateAndList=2003,2004");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals("searchDateAndList", ourLastMethod);
|
||||
assertEquals(2, ourLastDateAndList.getValuesAsQueryTokens().size());
|
||||
assertEquals(2, ourLastDateAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().size());
|
||||
assertEquals(2, ourLastDateAndList.getValuesAsQueryTokens().get(1).getValuesAsQueryTokens().size());
|
||||
assertEquals("2001", ourLastDateAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValueAsString());
|
||||
assertEquals("2002", ourLastDateAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(1).getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchBlacklist01Failing() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchBlacklist01&ref.black1=value");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
}
|
||||
@Test
|
||||
public void testSearchBlacklist01Passing() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchBlacklist01&ref.white1=value");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("searchBlacklist01", ourLastMethod);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWhitelist01Passing() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWhitelist01&ref.white1=value");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("searchWhitelist01", ourLastMethod);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeConvertsReferencesToRelative() throws Exception {
|
||||
@ -145,6 +212,34 @@ public class SearchDstu2Test {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Search(queryName="searchWhitelist01")
|
||||
public List<Patient> searchWhitelist01(
|
||||
@RequiredParam(chainWhitelist="white1", name = "ref") ReferenceParam theParam) {
|
||||
ourLastMethod = "searchWhitelist01";
|
||||
return Collections.emptyList();
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
@Search()
|
||||
public List<Patient> searchDateAndList(
|
||||
@RequiredParam(name = "searchDateAndList") DateAndListParam theParam) {
|
||||
ourLastMethod = "searchDateAndList";
|
||||
ourLastDateAndList = theParam;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
@Search(queryName="searchBlacklist01")
|
||||
public List<Patient> searchBlacklist01(
|
||||
@RequiredParam(chainBlacklist="black1", name = "ref") ReferenceParam theParam) {
|
||||
ourLastMethod = "searchBlacklist01";
|
||||
return Collections.emptyList();
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
@Search(queryName="searchWithBundleProvider")
|
||||
public IBundleProvider searchWithBundleProvider() {
|
||||
return new IBundleProvider() {
|
||||
|
@ -75,16 +75,19 @@ import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
||||
import ca.uhn.fhir.rest.server.ResourceBinding;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
|
||||
/**
|
||||
* Server FHIR Provider which serves the conformance statement for a RESTful server implementation
|
||||
* Server FHIR Provider which serves the conformance statement for a RESTful
|
||||
* server implementation
|
||||
*
|
||||
* <p>
|
||||
* Note: This class is safe to extend, but it is important to note that the same instance of {@link Conformance} is always returned unless
|
||||
* {@link #setCache(boolean)} is called with a value of <code>false</code>. This means that if you are adding anything to the returned conformance instance on
|
||||
* each call you should call <code>setCache(false)</code> in your provider constructor.
|
||||
* Note: This class is safe to extend, but it is important to note that the same
|
||||
* instance of {@link Conformance} is always returned unless
|
||||
* {@link #setCache(boolean)} is called with a value of <code>false</code>. This
|
||||
* means that if you are adding anything to the returned conformance instance on
|
||||
* each call you should call <code>setCache(false)</code> in your provider
|
||||
* constructor.
|
||||
* </p>
|
||||
*/
|
||||
public class ServerConformanceProvider implements IServerConformanceProvider<Conformance> {
|
||||
@ -94,12 +97,25 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
|
||||
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
|
||||
private String myPublisher = "Not provided";
|
||||
private final RestfulServer myRestfulServer;
|
||||
private RestfulServer myRestfulServer;
|
||||
|
||||
public ServerConformanceProvider(RestfulServer theRestfulServer) {
|
||||
myRestfulServer = theRestfulServer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a no-arg constructor and seetter so that the ServerConfirmanceProvider
|
||||
* can be Spring-wired with the RestfulService avoiding the potential
|
||||
* reference cycle that would happen.
|
||||
*/
|
||||
public ServerConformanceProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void setRestfulServer(RestfulServer theRestfulServer) {
|
||||
myRestfulServer = theRestfulServer;
|
||||
}
|
||||
|
||||
private void checkBindingForSystemOps(ConformanceRestComponent rest, Set<SystemRestfulInteraction> systemOps,
|
||||
BaseMethodBinding<?> nextMethodBinding) {
|
||||
if (nextMethodBinding.getRestOperationType() != null) {
|
||||
@ -148,8 +164,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the "publisher" that will be placed in the generated conformance statement. As this is a mandatory element, the value should not be null
|
||||
* (although this is not enforced). The value defaults to "Not provided" but may be set to null, which will cause this element to be omitted.
|
||||
* Gets the value of the "publisher" that will be placed in the generated
|
||||
* conformance statement. As this is a mandatory element, the value should not
|
||||
* be null (although this is not enforced). The value defaults to
|
||||
* "Not provided" but may be set to null, which will cause this element to be
|
||||
* omitted.
|
||||
*/
|
||||
public String getPublisher() {
|
||||
return myPublisher;
|
||||
@ -167,7 +186,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
retVal.setPublisher(myPublisher);
|
||||
retVal.setDate(new Date());
|
||||
retVal.setFhirVersion("1.0.0"); // TODO: pull from model
|
||||
retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big effort since the parser
|
||||
retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this
|
||||
// configurable -
|
||||
// this is a fairly
|
||||
// big effort since
|
||||
// the parser
|
||||
// needs to be modified to actually allow it
|
||||
|
||||
retVal.getImplementation().setDescription(myRestfulServer.getImplementationDescription());
|
||||
@ -197,7 +220,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
|
||||
TreeSet<String> includes = new TreeSet<String>();
|
||||
|
||||
// Map<String, Conformance.RestResourceSearchParam> nameToSearchParam = new HashMap<String,
|
||||
// Map<String, Conformance.RestResourceSearchParam> nameToSearchParam =
|
||||
// new HashMap<String,
|
||||
// Conformance.RestResourceSearchParam>();
|
||||
for (BaseMethodBinding<?> nextMethodBinding : nextEntry.getValue()) {
|
||||
if (nextMethodBinding.getRestOperationType() != null) {
|
||||
@ -325,7 +349,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
String nextParamDescription = nextParameter.getDescription();
|
||||
|
||||
/*
|
||||
* If the parameter has no description, default to the one from the resource
|
||||
* If the parameter has no description, default to the one from the
|
||||
* resource
|
||||
*/
|
||||
if (StringUtils.isBlank(nextParamDescription)) {
|
||||
RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName);
|
||||
@ -368,9 +393,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
// query = new OperationDefinition();
|
||||
// operation.setDefinition(new ResourceReferenceDt(query));
|
||||
// query.getDescriptionElement().setValue(searchMethodBinding.getDescription());
|
||||
// query.addUndeclaredExtension(false, ExtensionConstants.QUERY_RETURN_TYPE, new CodeDt(resourceName));
|
||||
// query.addUndeclaredExtension(false,
|
||||
// ExtensionConstants.QUERY_RETURN_TYPE, new CodeDt(resourceName));
|
||||
// for (String nextInclude : searchMethodBinding.getIncludes()) {
|
||||
// query.addUndeclaredExtension(false, ExtensionConstants.QUERY_ALLOWED_INCLUDE, new StringDt(nextInclude));
|
||||
// query.addUndeclaredExtension(false,
|
||||
// ExtensionConstants.QUERY_ALLOWED_INCLUDE, new StringDt(nextInclude));
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -388,7 +415,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
String nextParamDescription = nextParameter.getDescription();
|
||||
|
||||
/*
|
||||
* If the parameter has no description, default to the one from the resource
|
||||
* If the parameter has no description, default to the one from the
|
||||
* resource
|
||||
*/
|
||||
if (StringUtils.isBlank(nextParamDescription)) {
|
||||
RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName);
|
||||
@ -521,9 +549,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache property (default is true). If set to true, the same response will be returned for each invocation.
|
||||
* Sets the cache property (default is true). If set to true, the same
|
||||
* response will be returned for each invocation.
|
||||
* <p>
|
||||
* See the class documentation for an important note if you are extending this class
|
||||
* See the class documentation for an important note if you are extending this
|
||||
* class
|
||||
* </p>
|
||||
*/
|
||||
public void setCache(boolean theCache) {
|
||||
@ -531,8 +561,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the "publisher" that will be placed in the generated conformance statement. As this is a mandatory element, the value should not be null
|
||||
* (although this is not enforced). The value defaults to "Not provided" but may be set to null, which will cause this element to be omitted.
|
||||
* Sets the value of the "publisher" that will be placed in the generated
|
||||
* conformance statement. As this is a mandatory element, the value should not
|
||||
* be null (although this is not enforced). The value defaults to
|
||||
* "Not provided" but may be set to null, which will cause this element to be
|
||||
* omitted.
|
||||
*/
|
||||
public void setPublisher(String thePublisher) {
|
||||
myPublisher = thePublisher;
|
||||
|
1
pom.xml
1
pom.xml
@ -1275,6 +1275,7 @@
|
||||
<module>hapi-fhir-android</module>
|
||||
<module>hapi-fhir-dist</module>
|
||||
<module>examples</module>
|
||||
<module>hapi-fhir-osgi-core</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
|
@ -178,6 +178,10 @@
|
||||
words, if this parameter is found, the response won't be returned as
|
||||
HTML even if the request is detected as coming from a browser.
|
||||
</action>
|
||||
<action type="add">
|
||||
RestfulServer now supports dynamically adding and removing resource providers
|
||||
at runtime. Thanks to Bill Denton for adding this.
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.1" date="2015-07-13">
|
||||
<action type="add">
|
||||
|
Loading…
x
Reference in New Issue
Block a user