001package ca.uhn.fhir.context;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2017 University Health Network
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import org.hl7.fhir.instance.model.api.IBaseResource;
024
025import ca.uhn.fhir.model.api.annotation.ProvidesResources;
026
027/**
028 * Scans a class tagged with {@code ProvidesResources} and adds any resources listed to its FhirContext's resource
029 * definition list. This makes the profile generator find the classes.
030 *
031 * @see ca.uhn.fhir.model.api.annotation.ProvidesResources
032 */
033public class ProvidedResourceScanner {
034        private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ProvidedResourceScanner.class);
035        private FhirContext myContext;
036
037        /**
038         * Constructor
039         * 
040         * @param theContext
041         *           - context whose resource definition list is to be updated by the scanner
042         */
043        public ProvidedResourceScanner(FhirContext theContext) {
044                myContext = theContext;
045        }
046
047        /**
048         * If {@code theProvider} is tagged with the {@code ProvidesResources} annotation, this method will add every
049         * resource listed by the {@code resources} method.
050         * <p>
051         * Notes:
052         * </p>
053         * <ul>
054         * <li>if {@code theProvider} isn't annotated with {@code resources} nothing is done; it's expected that most
055         * RestfulServers and ResourceProviders won't be annotated.</li>
056         * <li>any object listed in {@code resources} that doesn't implement {@code IResource} will generate a warning in the
057         * log.</li>
058         * </ul>
059         *
060         * @param theProvider
061         *           - Normally, either a {@link ca.uhn.fhir.rest.server.RestfulServer} or a
062         *           {@link ca.uhn.fhir.rest.server.IResourceProvider} that might be annotated with
063         *           {@link ca.uhn.fhir.model.api.annotation.ProvidesResources}
064         */
065        @SuppressWarnings("unchecked")
066        public void scanForProvidedResources(Object theProvider) {
067                ProvidesResources annotation = theProvider.getClass().getAnnotation(ProvidesResources.class);
068                if (annotation == null)
069                        return;
070                for (Class<?> clazz : annotation.resources()) {
071                        if (IBaseResource.class.isAssignableFrom(clazz)) {
072                                myContext.getResourceDefinition((Class<? extends IBaseResource>) clazz);
073                        } else {
074                                ourLog.warn(clazz.getSimpleName() + "is not assignable from IResource");
075                        }
076                }
077        }
078
079        /**
080         * Remove any metadata that was added by any {@code ProvidesResources} annotation
081         * present in {@code theProvider}. This method is callled from {@code RestfulService}
082         * when it is unregistering a Resource Provider.
083         *  
084         * @param theProvider
085         *           - Normally a {@link ca.uhn.fhir.rest.server.IResourceProvider} that might 
086         *           be annotated with {@link ca.uhn.fhir.model.api.annotation.ProvidesResources}
087         */
088        public void removeProvidedResources(Object theProvider) {
089                ProvidesResources annotation = theProvider.getClass().getAnnotation(ProvidesResources.class);
090                if (annotation == null)
091                        return;
092                for (Class<?> clazz : annotation.resources()) {
093                        if (IBaseResource.class.isAssignableFrom(clazz)) {
094                                // TODO -- not currently used but should be finished for completeness
095                        } else {
096                                ourLog.warn(clazz.getSimpleName() + "is not assignable from IResource");
097                        }
098                }
099        }
100}