1 /**
2 * The contents of this file are subject to the Mozilla Public License Version 1.1
3 * (the "License"); you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
5 * Software distributed under the License is distributed on an "AS IS" basis,
6 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
7 * specific language governing rights and limitations under the License.
8 *
9 * The Original Code is "UnderlyingAccessor.java". Description:
10 * "This class is used to determine the name of the accessor method on the
11 * underlying object for a given conformance class. It is used to determine
12 * whether underlying accessors require a "rep" parameter. For instance,
13 * a message type might provide an accessor <code>getMSH()</code> to return
14 * its MSH segment. The runtime profile may not provide any clue as to whether
15 * the MSH segment in the HAPI library for the given message type is repeatable
16 * or not. This class determines this information."
17 *
18 * The Initial Developer of the Original Code is University Health Network. Copyright (C)
19 * 2001. All Rights Reserved.
20 *
21 * Contributor(s): James Agnew
22 * Paul Brohman
23 * Mitch Delachevrotiere
24 * Shawn Dyck
25 * Cory Metcalf
26 *
27 * Alternatively, the contents of this file may be used under the terms of the
28 * GNU General Public License (the ?GPL?), in which case the provisions of the GPL are
29 * applicable instead of those above. If you wish to allow use of your version of this
30 * file only under the terms of the GPL and not to allow others to use your version
31 * of this file under the MPL, indicate your decision by deleting the provisions above
32 * and replace them with the notice and other provisions required by the GPL License.
33 * If you do not delete the provisions above, a recipient may use your version of
34 * this file under either the MPL or the GPL.
35 *
36 */
37 package ca.uhn.hl7v2.conf.classes.generator.builders;
38
39 import java.lang.reflect.Method;
40
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import ca.uhn.hl7v2.conf.classes.exceptions.ConformanceError;
45 import ca.uhn.hl7v2.model.Composite;
46 import ca.uhn.hl7v2.model.GenericSegment;
47 import ca.uhn.hl7v2.model.Group;
48 import ca.uhn.hl7v2.model.Segment;
49
50 /**
51 * This class is used to determine the name of the accessor method on the
52 * underlying object for a given conformance class. It is used to determine
53 * whether underlying accessors require a "rep" parameter. For instance,
54 * a message type might provide an accessor <code>getMSH()</code> to return
55 * its MSH segment. The runtime profile may not provide any clue as to whether
56 * the MSH segment in the HAPI library for the given message type is repeatable
57 * or not. This class determines this information.
58 *
59 * @author <table><tr><td>James Agnew</td></tr>
60 * <tr><td>Paul Brohman</td></tr>
61 * <tr><td>Mitch Delachevrotiere</td></tr>
62 * <tr><td>Shawn Dyck</td></tr>
63 * <tr><td>Cory Metcalf</td></tr></table>
64 */
65 public class UnderlyingAccessor {
66
67 private static final Logger log = LoggerFactory.getLogger(UnderlyingAccessor.class);
68
69 boolean acceptsRep;
70 String theAccessor;
71
72 //these are used to keep track of child numbers in case we can't find
73 //a name-based getter
74 private static String ourCurrentParent = "";
75 private static int ourCurrentChild = 0;
76
77 /**
78 * Determines the name of the accessor method on the underlying object for a given
79 * conformance class. It is used to determine whether underlying accessors require
80 * a "rep" parameter.
81 * @param className the Class name
82 * @param accessorName the Accessor ame
83 */
84 public UnderlyingAccessor(String className, String accessorName) {
85 acceptsRep = false;
86
87 track(className);
88
89 try {
90 Class<?> c = getHapiModelClass(className);
91 theAccessor = makeName(c, accessorName);
92
93 //children of groups & segments repeat; children of composites don't
94 if (Group.class.isAssignableFrom(c)) {
95 acceptsRep = true;
96 } else if (Segment.class.isAssignableFrom(c)) {
97 Method m = getMethod(c, accessorName);
98 if (m == null || m.getParameterTypes().length == 1) {
99 acceptsRep = true;
100 }
101 }
102
103 // Method methods[] = c.getMethods();
104 // for (int i = 0; i < methods.length; i++) {
105 // if (methods[i].getName().equals(accessorName)) {
106 // foundAccessor = true;
107 // if (methods[i].getParameterTypes().length == 1) {
108 // acceptsRep = true;
109 // break;
110 // }
111 // }
112 // }
113 //
114 // if (foundAccessor == false)
115 // throw new ConformanceError("Underlying HAPI class \"" + className + "\" does not have accessor \"" + accessorName + "()\". This is probably a bug.");
116
117 } catch (Exception e) {
118 e.printStackTrace();
119 throw new ConformanceError("Underlying class/method " + className + "." + accessorName + "() can not be found. The complete HAPI API must be installed prior to using this system.");
120 }
121
122 // theAccessor = new String(accessorName);
123 // theAccessor += acceptsRep ? "( rep )" : "()";
124 }
125
126 /**
127 * Keeps track of the child number that is being processed. We assume
128 * they are processed in order.
129 * @param theParent
130 */
131 private static void track(String theParent) {
132 if (ourCurrentParent.equals(theParent)) {
133 ourCurrentChild++;
134 } else {
135 ourCurrentParent = theParent;
136 ourCurrentChild = 0;
137 }
138 }
139
140 /**
141 * @param theUnderlyingClassName the name of a HAPI model class
142 * @return the Java class by that name if one is on the classpath; otherwise it is assumed
143 * that we are dealing with a Z-segment, and GenericSegment.class is returned
144 */
145 public static Class<?>getHapiModelClass(String theUnderlyingClassName) {
146 Class<?> c;
147 try {
148 c = Class.forName(theUnderlyingClassName);
149 } catch (ClassNotFoundException e) {
150 log.debug("Interpreting class {} as a GenericSegment", theUnderlyingClassName);
151 c = GenericSegment.class;
152 }
153 return c;
154 }
155
156 /**
157 * @param theParentClass
158 * @param theChildName must be an integer when the parent is a composite
159 * @return the accessor name on the given parent that returns the the given child
160 */
161 private String makeName(Class<?> theParentClass, String theChildName) {
162 String result;
163 if (Group.class.isAssignableFrom(theParentClass)) {
164 result = "get(\"" + guessCompName(theChildName) + "\", rep)";
165 } else if (Segment.class.isAssignableFrom(theParentClass)) {
166 Method method = getMethod(theParentClass, theChildName);
167
168 //use number if we can't find the field by name (could be site-defined)
169 if (method == null) {
170 result = "getField(" + ourCurrentChild + ", rep)";
171 } else {
172 result = (method.getParameterTypes().length == 1) ? theChildName + "( rep )" : theChildName + "()";
173 }
174
175 } else if (Composite.class.isAssignableFrom(theParentClass)) {
176 result = "get(" + theChildName + ")";
177 } else {
178 throw new ConformanceError("The parent class " + theParentClass + " is not recognized as a Group, Segment, or Composite");
179 }
180 return result;
181 }
182
183 private static String guessCompName(String theAccessorName) {
184 return theAccessorName.substring(3);
185 }
186
187 private static Method getMethod(Class<?> theParentClass, String theChildName) {
188 Method result = null;
189 Method[] methods = theParentClass.getMethods();
190 for (Method method : methods) {
191 if (method.getName().equals(theChildName)) {
192 result = method;
193 if (result.getParameterTypes().length == 1) break;
194 }
195 }
196 return result;
197 }
198
199 /**
200 * Returns true if the underlying accessor accepts a rep argument, or
201 * false if the underlying accessor does not.
202 * @return boolean Returns true if the underlying accessor accepts a rep argument, or
203 * false if the underlying accessor does not.
204 */
205 public boolean getAcceptsRep() {
206 return acceptsRep;
207 }
208
209 /** This method returns a string representation of the Accessor
210 * @return a String representation of the Accessor
211 * @see java.lang.Object#toString()
212 */
213 public String toString() {
214 return theAccessor;
215 }
216
217 }