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 "SourceGenerator.java".  Description:
10   * "Manages automatic generation of HL7 API source code for all data types,
11   * segments, groups, and message structures"
12   *
13   * The Initial Developer of the Original Code is University Health Network. Copyright (C)
14   * 2001.  All Rights Reserved.
15   *
16   * Contributor(s): ______________________________________.
17   *
18   * Alternatively, the contents of this file may be used under the terms of the
19   * GNU General Public License (the  �GPL�), in which case the provisions of the GPL are
20   * applicable instead of those above.  If you wish to allow use of your version of this
21   * file only under the terms of the GPL and not to allow others to use your version
22   * of this file under the MPL, indicate your decision by deleting  the provisions above
23   * and replace  them with the notice and other provisions required by the GPL License.
24   * If you do not delete the provisions above, a recipient may use your version of
25   * this file under either the MPL or the GPL.
26   *
27   */
28  
29  package ca.uhn.hl7v2.sourcegen;
30  
31  import java.util.StringTokenizer;
32  import java.io.File;
33  import java.io.IOException;
34  
35  import ca.uhn.hl7v2.HL7Exception;
36  import org.apache.commons.lang.StringUtils;
37  
38  /**
39   * <p>Manages automatic generation of HL7 API source code for all data types,
40   * segments, groups, and message structures. </p>
41   * <p>Note: should put a nice UI on this</p>
42   * @author Bryan Tripp (bryan_tripp@sourceforge.net)
43   */
44  public class SourceGenerator extends Object {
45      
46  	public static final String ENCODING = "UTF-8";
47  	
48      /** Creates new SourceGenerator */
49      public SourceGenerator() {
50      }
51      
52      /**
53       * Generates source code for all data types, segments, groups, and messages.
54       * @param baseDirectory the directory where source should be written
55       * @param theJdbcUrl The JDBC URL
56       * @throws HL7Exception - 
57       */
58      public static void makeAll(String baseDirectory, String version, boolean failOnError, String theTemplatePackage, String theFileExt) throws HL7Exception  {
59          //load driver and set DB URL
60          /*if (System.getProperty("ca.on.uhn.hl7.database.url") == null) {
61              System.setProperty("ca.on.uhn.hl7.database.url", "jdbc:odbc:hl7");
62          }*/
63          
64          try {
65              Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
66              MessageGenerator.makeAll(baseDirectory, version, failOnError, theTemplatePackage, theFileExt);
67              SegmentGenerator.makeAll(baseDirectory, version, theTemplatePackage, theFileExt);
68              DataTypeGenerator.makeAll(baseDirectory, version, theTemplatePackage, theFileExt);
69              // group and message not implemented
70          } catch (Exception e) {
71          	throw new HL7Exception(e);
72          }
73          
74      }
75      
76      /**
77       * Make a Java-ish accessor method name out of a field or component description
78       * by removing non-letters and adding "get".  One complication is that some description
79       * entries in the DB have their data types in brackets, and these should not be
80       * part of the method name.  On the other hand, sometimes critical distinguishing
81       * information is in brackets, so we can't omit everything in brackets.  The approach
82       * taken here is to eliminate bracketed text if a it looks like a data type.
83       */
84      public static String makeAccessorName(String fieldDesc, String parentName) {
85          StringBuffer aName = new StringBuffer();
86          char[] chars = fieldDesc.toCharArray();
87          boolean lastCharWasNotLetter = true;
88          int inBrackets = 0;
89          StringBuffer bracketContents = new StringBuffer();
90          for (int i = 0; i < chars.length; i++) {
91              if (chars[i] == '(' ) inBrackets++;
92              if (chars[i] == ')' ) inBrackets--;
93              
94              if (Character.isLetterOrDigit(chars[i])) {
95                  if (inBrackets > 0) {
96                      //buffer everthing in brackets
97                      bracketContents.append(chars[i]);
98                  } else {
99                      //add capitalized bracketed text if appropriate 
100                     if (bracketContents.length() > 0) {
101                         aName.append(capitalize(filterBracketedText(bracketContents.toString())));
102                         bracketContents = new StringBuffer();
103                     }
104                     if (lastCharWasNotLetter) {
105                         //first letter of each word is upper-case
106                         aName.append(Character.toUpperCase(chars[i]));
107                     } else {
108                         aName.append(chars[i]);
109                     }
110                     lastCharWasNotLetter = false;
111                 }
112             } else {
113                 lastCharWasNotLetter = true;
114             }
115         }
116         aName.append(capitalize(filterBracketedText(bracketContents.toString())));        
117         String retVal = aName.toString();
118 
119         // Accessors with these two names conflict with existing superclass accessor names
120         if (retVal.equals("Parent")) {
121             retVal = parentName + "Parent";
122         }
123         if (retVal.equals("Name")) {
124             retVal = parentName + "Name";
125         }
126         
127         return retVal;
128     }
129     
130     /**
131      * Bracketed text in a field description should be included in the accessor 
132      * name unless it corresponds to a data type name. Given the text that appears in 
133      * brackets in a field description, this method returns an empty string if it 
134      * corresponds to a data type name, or returns original text if not.  It isn't 
135      * convenient to actually check (e.g. with DataTypeGenerator) whether the given 
136      * text actually corresponds to a data type name, so we are going to conclude that 
137      * it is a data type if and only if it is all caps and has 2 or 3 characters.  
138      */
139     private static String filterBracketedText(String text) {
140         String filtered = "";
141         boolean isDataType = true;
142         if (!text.equals(text.toUpperCase())) isDataType = false;
143         if (text.length() < 2 || text.length() > 3) isDataType = false;
144 
145         if (!isDataType) filtered = text;
146         return filtered;
147     }
148     
149     /** Capitalizes first character of the given text. */
150     private static String capitalize(String text) {
151         StringBuffer cap = new StringBuffer();
152         if (text.length() > 0) {
153             cap.append(Character.toUpperCase(text.charAt(0)));
154             cap.append(text.substring(1, text.length()));
155         }
156         return cap.toString();
157     }
158     
159     /**
160      * Creates the given directory if it does not exist.
161      */
162     public static File makeDirectory(String directory) throws IOException {
163         StringTokenizer tok = new StringTokenizer(directory, "\\/", false);
164         
165         File currDir = directory.startsWith("/") ? new File("/") : null;
166         while (tok.hasMoreTokens()) {
167             String thisDirName = tok.nextToken();
168             
169             currDir = new File(currDir, thisDirName); //if currDir null, defaults to 1 arg call
170             
171             if (!currDir.exists()) {
172                 //create
173                 currDir.mkdir();;
174             } else if (currDir.isFile()) {
175                 throw new IOException("Can't create directory " + thisDirName +
176                 " - file with same name exists.");
177             }
178         }
179         
180         return currDir;
181     }
182     
183     /**
184      * <p>Returns either the given data type name or an alternate data type that Composites
185      * and Segments should use in place of the given Type.  </p>
186      * <p>As currently implemented, substitutions
187      * may be desired if there is a validating subclass of the given Type.
188      * By convention such classes would be named ValidX (where X is the Type name).  This
189      * method checks the classpath for classes of this name in the datatype package and
190      * returns this name if one is found.</p>
191      * <p>Also converts "varies" to Varies which is an implementation of Type that contains
192      * a Type that can be set at run-time.</p>
193      */
194     public static String getAlternateType(String dataTypeName, String version) {
195         String ret = dataTypeName;
196         
197         //convert to varies to Varies
198         if (ret.equals("varies")) ret = "Varies";
199         
200         // Null/withdrawn
201         if (ret.equals("NUL")) ret = "NULLDT";
202         if (ret.equals("-")) ret = "NULLDT";
203         
204         //Valid.. classes are removed as of HAPI 0.3 (validating code implemented directly in Primitive classes
205         /*try {
206             Class.forName(getVersionPackageName(version) + "datatype.Valid" + dataTypeName);
207             ret = "Valid" + dataTypeName;
208         } catch (Exception e) {
209             // fine ... there isn't a ValidX implementation
210             // I don't like using Class.forName here but I don't know a better way to
211             // search for the class 
212         }*/
213         
214         return ret;
215     }
216     
217     public static void main(String[] args) throws ClassNotFoundException, HL7Exception {
218     	Class.forName("com.mysql.jdbc.Driver");
219     	System.setProperty("ca.on.uhn.hl7.database.url", "jdbc:mysql://localhost:3306/hl7v65");
220         System.setProperty("ca.on.uhn.hl7.database.user", "hl7");
221         System.setProperty("ca.on.uhn.hl7.database.password", "hl7");
222         makeAll("tmp", "2.5.1", true, "", "java");
223     }
224 
225 	public static String makeAlternateAccessorName(String fieldDesc, String parentName, int index) {
226         StringBuffer aName = new StringBuffer();
227         
228         aName.append(StringUtils.capitalize(parentName.toLowerCase())).append(index).append("_");
229         
230         char[] chars = fieldDesc.toCharArray();
231         boolean lastCharWasNotLetter = true;
232         int inBrackets = 0;
233         StringBuffer bracketContents = new StringBuffer();
234         for (int i = 0; i < chars.length; i++) {
235             if (chars[i] == '(' ) inBrackets++;
236             if (chars[i] == ')' ) inBrackets--;
237             
238             if (Character.isLetterOrDigit(chars[i])) {
239                 if (inBrackets > 0) {
240                     //buffer everthing in brackets
241                     bracketContents.append(chars[i]);
242                 } else {
243                     //add capitalized bracketed text if appropriate 
244                     if (bracketContents.length() > 0) {
245                         aName.append(capitalize(filterBracketedText(bracketContents.toString())));
246                         bracketContents = new StringBuffer();
247                     }
248                     if (lastCharWasNotLetter) {
249                         //first letter of each word is upper-case
250                         aName.append(Character.toUpperCase(chars[i]));
251                     } else {
252                         aName.append(chars[i]);
253                     }
254                     lastCharWasNotLetter = false;
255                 }
256             } else {
257                 lastCharWasNotLetter = true;
258             }
259         }
260         aName.append(capitalize(filterBracketedText(bracketContents.toString())));        
261         String retVal = aName.toString();
262 
263         
264         return retVal;
265 	}
266     
267 }