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 }