commit
e9497c019a
|
@ -0,0 +1,70 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 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 ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.annotation.ProvidesResources;
|
||||
|
||||
/**
|
||||
* Scans a class tagged with {@code ProvidesResources} and adds any resources listed to its FhirContext's resource
|
||||
* definition list. This makes the profile generator find the classes.
|
||||
*
|
||||
* @see ca.uhn.fhir.model.api.annotation.ProvidesResources
|
||||
*/
|
||||
public class ProvidedResourceScanner {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class);
|
||||
private FhirContext myContext;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param theContext - context whose resource definition list is to be updated by the scanner
|
||||
*/
|
||||
public ProvidedResourceScanner(FhirContext theContext) {
|
||||
myContext = theContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@code theProvider} is tagged with the {@code ProvidesResources} annotation, this method will add every resource listed
|
||||
* by the {@code resources} method.
|
||||
* <p/>
|
||||
* notes:
|
||||
* <ul>
|
||||
* <li>if {@code theProvider} isn't annotated with {@code resources} nothing is done; it's expected that most RestfulServers and
|
||||
* ResourceProviders won't be annotated.</li>
|
||||
* <li>any object listed in {@code resources} that doesn't implement {@code IResource} will generate a warning in the log.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param theProvider - Normally, either a {@link ca.uhn.fhir.rest.server.RestfulServer} or a {@link ca.uhn.fhir.rest.server.IResourceProvider}
|
||||
* that might be annotated with {@link ca.uhn.fhir.model.api.annotation.ProvidesResources}
|
||||
*/
|
||||
public void scanForProvidedResources(Object theProvider) {
|
||||
ProvidesResources annotation = theProvider.getClass().getAnnotation(ProvidesResources.class);
|
||||
if (annotation == null)
|
||||
return;
|
||||
for (Class clazz : annotation.resources()) {
|
||||
if (IResource.class.isAssignableFrom(clazz)) {
|
||||
myContext.getResourceDefinition(clazz);
|
||||
} else {
|
||||
ourLog.warn(clazz.getSimpleName() + "is not assignable from IResource");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package ca.uhn.fhir.model.api.annotation;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 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.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* IResourceProvider and RestfulServer subclasses can use this annotation to designate which custom resources they can provide.
|
||||
* These resources will automatically be added to the resource list used for profile generation.
|
||||
* <pre>
|
||||
* Examples:
|
||||
* {@code
|
||||
* @literal@ProvidesResources(resource=CustomObservation.class)
|
||||
* class CustomObservationResourceProvider implements IResourceProvider{...}
|
||||
*
|
||||
* @literal@ProvidesResources(resource={CustomPatient.class,CustomObservation.class}){...}
|
||||
* class FhirServer extends RestfulServer
|
||||
* }
|
||||
* </pre>
|
||||
* Note that you needn't annotate both the IResourceProvider and the RestfulServer for a given resource; either one will suffice.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ProvidesResources {
|
||||
Class[] resources();
|
||||
}
|
|
@ -50,6 +50,7 @@ import javax.servlet.http.HttpServlet;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import ca.uhn.fhir.context.ProvidedResourceScanner;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
@ -132,7 +133,7 @@ public class RestfulServer extends HttpServlet {
|
|||
|
||||
private void assertProviderIsValid(Object theNext) throws ConfigurationException {
|
||||
if (Modifier.isPublic(theNext.getClass().getModifiers()) == false) {
|
||||
throw new ConfigurationException("Can not use provider '" + theNext.getClass() + "' - Class ust be public");
|
||||
throw new ConfigurationException("Can not use provider '" + theNext.getClass() + "' - Class must be public");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -695,6 +696,9 @@ public class RestfulServer extends HttpServlet {
|
|||
ourLog.trace("No security manager has been provided");
|
||||
}
|
||||
|
||||
ProvidedResourceScanner providedResourceScanner = new ProvidedResourceScanner(getFhirContext());
|
||||
providedResourceScanner.scanForProvidedResources(this);
|
||||
|
||||
Collection<IResourceProvider> resourceProvider = getResourceProviders();
|
||||
if (resourceProvider != null) {
|
||||
Map<Class<? extends IResource>, IResourceProvider> typeToProvider = new HashMap<Class<? extends IResource>, IResourceProvider>();
|
||||
|
@ -707,6 +711,7 @@ public class RestfulServer extends HttpServlet {
|
|||
throw new ServletException("Multiple providers for type: " + resourceType.getCanonicalName());
|
||||
}
|
||||
typeToProvider.put(resourceType, nextProvider);
|
||||
providedResourceScanner.scanForProvidedResources(nextProvider);
|
||||
}
|
||||
ourLog.info("Got {} resource providers", typeToProvider.size());
|
||||
for (IResourceProvider provider : typeToProvider.values()) {
|
||||
|
|
|
@ -11,7 +11,7 @@ import ca.uhn.fhir.model.primitive.StringDt;
|
|||
* Created by Bill de Beaubien on 10/31/2014.
|
||||
*/
|
||||
@ResourceDef(name="Observation", id="customobservation")
|
||||
public class CustomObservation extends Observation {
|
||||
class CustomObservation extends Observation {
|
||||
@Child(name = "valueUnits", order = 3)
|
||||
@Extension(url = "http://hapi.test.com/profile/customobservation#valueUnits", definedLocally = true, isModifier = false)
|
||||
@Description(shortDefinition = "Units on an observation whose type is of valueString")
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.ProvidesResources;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
public class ProvidedResourceScannerTest extends TestCase {
|
||||
@Test
|
||||
public void testScannerShouldAddProvidedResources() {
|
||||
FhirContext ctx = new FhirContext();
|
||||
assertNull(ctx.getElementDefinition(CustomPatient.class));
|
||||
|
||||
ProvidedResourceScanner scanner = new ProvidedResourceScanner(ctx);
|
||||
scanner.scanForProvidedResources(new TestResourceProviderB());
|
||||
|
||||
assertNotNull(ctx.getElementDefinition(CustomPatient.class));
|
||||
}
|
||||
|
||||
@ProvidesResources(resources=CustomObservation.class)
|
||||
class TestResourceProviderA {
|
||||
}
|
||||
|
||||
@ProvidesResources(resources={CustomPatient.class,ResourceWithExtensionsA.class})
|
||||
class TestResourceProviderB {
|
||||
}
|
||||
|
||||
@ResourceDef(name = "Patient", id="CustomPatient")
|
||||
class CustomPatient extends Patient {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.annotation.ProvidesResources;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.dstu.resource.Observation;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Bill de Beaubien on 11/1/2014.
|
||||
*/
|
||||
public class ServerProvidedResourceScannerTest extends TestCase {
|
||||
@Test
|
||||
public void testWhenRestfulServerInitialized_annotatedResources_shouldBeAddedToContext() throws ServletException {
|
||||
// Given
|
||||
MyServer server = new MyServer();
|
||||
|
||||
// When
|
||||
server.init();
|
||||
|
||||
// Then
|
||||
assertNotNull(server.getFhirContext().getElementDefinition(CustomObservation.class));
|
||||
assertNotNull(server.getFhirContext().getElementDefinition(CustomPatient.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhenUnannotatedServerInitialized_annotatedResources_shouldNotBeAddedToContext() throws ServletException {
|
||||
// Given
|
||||
RestfulServer server = new RestfulServer();
|
||||
|
||||
// When
|
||||
server.init();
|
||||
|
||||
// Then
|
||||
assertNull(server.getFhirContext().getElementDefinition(CustomObservation.class));
|
||||
assertNull(server.getFhirContext().getElementDefinition(CustomPatient.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhenServletWithAnnotatedProviderInitialized_annotatedResource_shouldBeAddedToContext() throws ServletException {
|
||||
// Given
|
||||
MyServerWithProvider server = new MyServerWithProvider();
|
||||
|
||||
// When
|
||||
server.init();
|
||||
|
||||
// Then
|
||||
assertNotNull(server.getFhirContext().getElementDefinition(CustomObservation.class));
|
||||
}
|
||||
|
||||
@ResourceDef(name = "Patient", id="CustomPatient")
|
||||
class CustomPatient extends Patient {
|
||||
}
|
||||
|
||||
@ResourceDef(name = "Observation", id="CustomObservation")
|
||||
class CustomObservation extends Observation {
|
||||
}
|
||||
|
||||
@ProvidesResources(resources={CustomPatient.class,CustomObservation.class})
|
||||
class MyServer extends RestfulServer {
|
||||
}
|
||||
|
||||
class MyServerWithProvider extends RestfulServer {
|
||||
@Override
|
||||
protected void initialize() throws ServletException {
|
||||
List<IResourceProvider> providers = new ArrayList<IResourceProvider>();
|
||||
providers.add(new MyObservationProvider());
|
||||
setResourceProviders(providers);
|
||||
}
|
||||
}
|
||||
|
||||
@ProvidesResources(resources=CustomObservation.class)
|
||||
public static class MyObservationProvider implements IResourceProvider {
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return CustomObservation.class;
|
||||
}
|
||||
|
||||
@Read(version = false)
|
||||
public CustomObservation readObservation(@IdParam IdDt theId) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue