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 }