View Javadoc
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 }