001    /**
002    The contents of this file are subject to the Mozilla Public License Version 1.1
003    (the "License"); you may not use this file except in compliance with the License.
004    You may obtain a copy of the License at http://www.mozilla.org/MPL/
005    Software distributed under the License is distributed on an "AS IS" basis,
006    WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
007    specific language governing rights and limitations under the License.
008    
009    The Initial Developer of the Original Code is University Health Network. Copyright (C)
010    2001.  All Rights Reserved.
011    
012    Contributor(s): ______________________________________.
013    
014    Alternatively, the contents of this file may be used under the terms of the
015    GNU General Public License (the  �GPL�), in which case the provisions of the GPL are
016    applicable instead of those above.  If you wish to allow use of your version of this
017    file only under the terms of the GPL and not to allow others to use your version
018    of this file under the MPL, indicate your decision by deleting  the provisions above
019    and replace  them with the notice and other provisions required by the GPL License.
020    If you do not delete the provisions above, a recipient may use your version of
021    this file under either the MPL or the GPL.
022    
023    */
024    package ca.uhn.hl7v2.parser;
025    
026    import java.util.HashMap;
027    import java.util.Map;
028    
029    import org.slf4j.Logger;
030    import org.slf4j.LoggerFactory;
031    
032    import ca.uhn.hl7v2.HL7Exception;
033    import ca.uhn.hl7v2.Version;
034    import ca.uhn.hl7v2.model.Group;
035    import ca.uhn.hl7v2.model.Message;
036    import ca.uhn.hl7v2.model.Segment;
037    import ca.uhn.hl7v2.model.Type;
038    
039    /**
040     * ModelClassFactory which allows custom packages to search to be specified.
041     * These packages will be searched first, and if nothing is found for a particular
042     * structure, DefaultModelClassFactory is used.
043     *
044     * @author Based on implementation by Christian Ohr
045     * @author James Agnew
046     * @since 1.0
047     */
048    public class CustomModelClassFactory implements ModelClassFactory {
049    
050        private static final long serialVersionUID = 1;
051        private final ModelClassFactory defaultFactory;
052        private Map<String, String[]> customModelClasses;
053        private static Logger LOG = LoggerFactory.getLogger(CustomModelClassFactory.class);
054    
055        /**
056         * Constructor which just delegated to {@link DefaultModelClassFactory}
057         */
058        public CustomModelClassFactory() {
059            this((Map<String, String[]>)null);
060        }
061    
062    
063        /**
064         * Constructor
065         *
066         * @param packageName The base package name to use.
067         * <p>
068         * When searching, package specified here will be appended with .[version].[structure type].
069         * </p>
070         * <p>
071         * So, for instance, when looking for a v2.5 segment object, if "<code>com.foo</code>" is passed in, HAPI will look in "<code>com.foo.v25.segment.*</code>"
072         * </p>
073         */
074        public CustomModelClassFactory(String packageName) {
075            defaultFactory = new DefaultModelClassFactory();
076            customModelClasses = new HashMap<String, String[]>();
077    
078            if (!packageName.endsWith(".")) {
079                packageName += ".";
080            }
081    
082            for (Version v : Version.values()) {
083                customModelClasses.put(v.getVersion(), new String[] {packageName + v.getPackageVersion()});
084            }
085        }
086    
087        
088        /**
089         * Constructor
090         * @param map Map of packages to include.
091         * <p>
092         * Keys are versions of HL7, e.g. "2.5".
093         * </p>
094         * <p>
095         * Values are an array of packages to search in for custom model classes.
096         * When searching, the package name here will be appended with "<b>.[structure type]</b>".
097         * So, for example, to specify a custom message type, you could create the class
098         * <code>foo.example.v23.message.ZRM_Z01</code>, and pass in the string "<code>foo.example.v23</code>".
099         * </p>
100         */
101        public CustomModelClassFactory(Map<String, String[]> map) {
102            defaultFactory = new DefaultModelClassFactory();
103            customModelClasses = map;
104        }
105    
106    
107        /**
108         * {@inheritDoc }
109         */
110        @SuppressWarnings("unchecked")
111            public Class<? extends Message> getMessageClass(String name, String version, boolean isExplicit) throws HL7Exception {
112            if (!isExplicit) {
113                name = Parser.getMessageStructureForEvent(name, version);
114            }
115            Class<? extends Message> retVal = (Class<? extends Message>) findClass("message", name, version);
116            if (retVal == null) {
117                retVal = defaultFactory.getMessageClass(name, version, isExplicit);
118            }
119            return retVal;
120        }
121    
122        /**
123         * {@inheritDoc }
124         */
125        @SuppressWarnings("unchecked")
126            public Class<? extends Group> getGroupClass(String name, String version) throws HL7Exception {
127            Class<? extends Group> retVal = (Class<? extends Group>) findClass("group", name, version);
128            if (retVal == null) {
129                retVal = defaultFactory.getGroupClass(name, version);
130            }
131            return retVal;
132        }
133    
134        /**
135         * {@inheritDoc }
136         */
137        @SuppressWarnings("unchecked")
138            public Class<? extends Segment> getSegmentClass(String name, String version) throws HL7Exception {
139            Class<? extends Segment> retVal = (Class<? extends Segment>) findClass("segment", name, version);
140            if (retVal == null) {
141                retVal = defaultFactory.getSegmentClass(name, version);
142            }
143            return retVal;
144        }
145    
146        /**
147         * {@inheritDoc }
148         */
149        @SuppressWarnings("unchecked")
150            public Class<? extends Type> getTypeClass(String name, String version) throws HL7Exception {
151            Class<? extends Type> retVal = (Class<? extends Type>) findClass("datatype", name, version);
152            if (retVal == null) {
153                retVal = defaultFactory.getTypeClass(name, version);
154            }
155            return retVal;
156        }
157    
158        /**
159         * Finds appropriate classes to be loaded for the given structure/type
160         */
161        protected Class<?> findClass(String subpackage, String name, String version) throws HL7Exception {
162            if (!Parser.validVersion(version)) {
163                throw new HL7Exception("HL7 version " + version + " is not supported",
164                        HL7Exception.UNSUPPORTED_VERSION_ID);
165            }
166            Class<?> classLoaded = null;
167            if (customModelClasses != null) {
168                if (customModelClasses.containsKey(version)) {
169                    for (String next : customModelClasses.get(version)) {
170                        if (!next.endsWith(".")) {
171                            next += ".";
172                        }
173                        String fullyQualifiedName = next + subpackage + '.' + name;
174                        try {
175                            classLoaded = Class.forName(fullyQualifiedName);
176                            LOG.debug("Found " + fullyQualifiedName + " in custom HL7 model");
177                        } catch (ClassNotFoundException e) {
178                            // ignore
179                        }
180                    }
181                }
182            }
183            return classLoaded;
184        }
185    
186        /**
187         * Delegates calls to {@link DefaultModelClassFactory#getMessageClassInASpecificPackage(String, String, boolean, String)}
188         */
189            public Class<? extends Message> getMessageClassInASpecificPackage(String theName, String theVersion, boolean theIsExplicit, String thePackageName) throws HL7Exception {
190                    return defaultFactory.getMessageClassInASpecificPackage(theName, theVersion, theIsExplicit, thePackageName);
191            }
192    }