Java tutorial
/** * The contents of this file are subject to the Mozilla Public License Version 1.1 * (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.mozilla.org/MPL/ * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the * specific language governing rights and limitations under the License. * * The Original Code is "SegmentGenerator.java". Description: * "This class is responsible for generating source code for HL7 segment objects" * * The Initial Developer of the Original Code is University Health Network. Copyright (C) * 2001. All Rights Reserved. * * Contributor(s): Eric Poiseau. * * Alternatively, the contents of this file may be used under the terms of the * GNU General Public License (the GPL), in which case the provisions of the GPL are * applicable instead of those above. If you wish to allow use of your version of this * file only under the terms of the GPL and not to allow others to use your version * of this file under the MPL, indicate your decision by deleting the provisions above * and replace them with the notice and other provisions required by the GPL License. * If you do not delete the provisions above, a recipient may use your version of * this file under either the MPL or the GPL. * */ package ca.uhn.hl7v2.sourcegen; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ca.uhn.hl7v2.AbstractHL7Exception; import ca.uhn.hl7v2.HL7Exception; import ca.uhn.hl7v2.database.NormativeDatabase; import ca.uhn.hl7v2.parser.DefaultModelClassFactory; import ca.uhn.hl7v2.sourcegen.util.VelocityFactory; /** * This class is responsible for generating source code for HL7 segment objects. * Each automatically generated segment inherits from AbstractSegment. * * @author Bryan Tripp (bryan_tripp@sourceforge.net) * @author Eric Poiseau */ public class SegmentGenerator extends java.lang.Object { private static final Logger log = LoggerFactory.getLogger(SegmentGenerator.class); /** * <p>Creates skeletal source code (without correct data structure but no business * logic) for all segments found in the normative database. </p> */ public static void makeAll(String baseDirectory, String version, String theTemplatePackage, String theFileExt) throws IOException, SQLException, HL7Exception, MojoExecutionException { //make base directory if (!(baseDirectory.endsWith("\\") || baseDirectory.endsWith("/"))) { baseDirectory = baseDirectory + "/"; } File targetDir = SourceGenerator .makeDirectory(baseDirectory + DefaultModelClassFactory.getVersionPackagePath(version) + "segment"); ArrayList<String> segments = getSegmentNames(version); if (segments.size() == 0) { log.warn("No version {} segments found in database {}", version, System.getProperty("ca.on.uhn.hl7.database.url")); } for (int i = 0; i < segments.size(); i++) { try { String seg = (String) segments.get(i); String hapiTestGenSegment = System.getProperty("hapi.test.gensegment"); if (hapiTestGenSegment != null && !hapiTestGenSegment.contains(seg)) { continue; } makeSegment(seg, version, theTemplatePackage, targetDir, theFileExt); } catch (Exception e) { // System.err.println("Error creating source code for all segments: " + e.getMessage()); // e.printStackTrace(); throw new MojoExecutionException("Failure generating segments", e); } } } public static ArrayList<String> getSegmentNames(String version) throws SQLException { //get list of segments NormativeDatabase normativeDatabase = NormativeDatabase.getInstance(); Connection conn = normativeDatabase.getConnection(); Statement stmt = conn.createStatement(); String sql = "SELECT seg_code, section from HL7Segments, HL7Versions where HL7Segments.version_id = HL7Versions.version_id AND hl7_version = '" + version + "'"; //System.out.println(sql); ResultSet rs = stmt.executeQuery(sql); ArrayList<String> segments = new ArrayList<String>(); while (rs.next()) { String segName = rs.getString(1); // The DB has an invalid segment with this name if ("ED".equals(segName)) { continue; } if (Character.isLetter(segName.charAt(0))) { segments.add(altSegName(segName)); } } stmt.close(); normativeDatabase.returnConnection(conn); return segments; } /** * <p>Returns an alternate segment name to replace the given segment name. Substitutions * made include: </p> * <ul><li>Replacing Z.. with Z</li> *<li>Replacing ??? with ???</li></ul> */ public static String altSegName(String segmentName) { String ret = segmentName; if (ret.equals("Z..")) { ret = "Z"; } if (ret.equals("CON")) { ret = "CON_"; } return ret; } /** * Returns the Java source code for a class that represents the specified segment. */ public static void makeSegment(String name, String version, String theTemplatePackage, File theTargetDir, String theFileExt) throws Exception { ArrayList<SegmentElement> elements = new ArrayList<SegmentElement>(); String segDesc = null; SegmentElement se = null; NormativeDatabase normativeDatabase = NormativeDatabase.getInstance(); try { Connection conn = normativeDatabase.getConnection(); // sql.append("SELECT "); // sql.append("HL7SegmentDataElements.seg_code, HL7SegmentDataElements.seq_no, "); // sql.append("HL7SegmentDataElements.repetitional, HL7SegmentDataElements.repetitions, "); // sql.append("HL7DataElements.description, HL7DataElements.length, HL7DataElements.table_id, "); // sql.append("HL7SegmentDataElements.req_opt, HL7Segments.description, HL7DataElements.data_structure "); // sql.append("FROM HL7Versions RIGHT JOIN (HL7Segments INNER JOIN (HL7DataElements INNER JOIN HL7SegmentDataElements "); // sql.append("ON (HL7DataElements.version_id = HL7SegmentDataElements.version_id) "); // sql.append("AND (HL7DataElements.data_item = HL7SegmentDataElements.data_item)) "); // sql.append("ON (HL7Segments.version_id = HL7SegmentDataElements.version_id) "); // sql.append("AND (HL7Segments.seg_code = HL7SegmentDataElements.seg_code)) "); // sql.append("ON (HL7Versions.version_id = HL7Segments.version_id) "); // sql.append("WHERE HL7SegmentDataElements.seg_code = '"); // sql.append(name); // sql.append("' and HL7Versions.hl7_version = '"); // sql.append(version); // sql.append("' ORDER BY HL7SegmentDataElements.seg_code, HL7SegmentDataElements.seq_no;"); // if (false) { listTables(conn, "HL7SegmentDataElements"); listTables(conn, "HL7DataElements"); listTables(conn, "HL7Segments"); // } String lengthColName; if (version.startsWith("2.7") || version.startsWith("2.8")) { lengthColName = "HL7DataElements.max_length"; } else { lengthColName = "HL7DataElements.length"; } StringBuffer sql = new StringBuffer(); sql.append("SELECT "); // sql.append("HL7SegmentDataElements.*, "); // sql.append("HL7DataElements.*, "); // sql.append("HL7Segments.* "); sql.append("HL7SegmentDataElements.seg_code, HL7SegmentDataElements.seq_no, "); sql.append("HL7SegmentDataElements.repetitional, HL7SegmentDataElements.repetitions, "); sql.append("HL7DataElements.description, " + lengthColName + ", HL7DataElements.table_id, "); sql.append("HL7SegmentDataElements.req_opt, HL7Segments.description, HL7DataElements.data_structure "); sql.append( "FROM HL7Versions RIGHT JOIN (HL7Segments INNER JOIN (HL7DataElements INNER JOIN HL7SegmentDataElements "); sql.append("ON (HL7DataElements.version_id = HL7SegmentDataElements.version_id) "); sql.append("AND (HL7DataElements.data_item = HL7SegmentDataElements.data_item)) "); sql.append("ON (HL7Segments.version_id = HL7SegmentDataElements.version_id) "); sql.append("AND (HL7Segments.seg_code = HL7SegmentDataElements.seg_code)) "); sql.append("ON (HL7Versions.version_id = HL7Segments.version_id) "); sql.append("WHERE "); sql.append("HL7SegmentDataElements.seg_code = '"); sql.append(name); sql.append("' and HL7Versions.hl7_version = '"); sql.append(version); sql.append("' "); sql.append("ORDER BY HL7SegmentDataElements.seg_code, HL7SegmentDataElements.seq_no;"); //System.out.println(sql.toString()); //for debugging Statement stmt; ResultSet rs; try { stmt = conn.createStatement(); rs = stmt.executeQuery(sql.toString()); } catch (Exception e) { throw new MojoFailureException("Failed to execute the following SQL: " + sql.toString(), e); } List<String> usedFieldDescs = new ArrayList<String>(); int index = 0; while (rs.next()) { if (segDesc == null) { segDesc = rs.getString(9); } se = new SegmentElement(name, version, index++); se.field = rs.getInt(2); se.rep = rs.getString(3); se.repetitions = rs.getInt(4); if (se.repetitions == 0) { if (se.rep == null || !se.rep.equalsIgnoreCase("Y")) { se.repetitions = 1; } } se.desc = rs.getString(5); // If two fields have the same name, add "Rep 1" or "Rep 2" etc to the name String originalSeDesc = se.desc; if (usedFieldDescs.contains(se.desc)) { se.desc = se.desc + " Number " + (Collections.frequency(usedFieldDescs, originalSeDesc) + 1); } usedFieldDescs.add(originalSeDesc); se.length = rs.getInt(6); se.table = rs.getInt(7); se.opt = rs.getString(8); se.type = rs.getString(10); //shorten CE_x to CE if (se.type.startsWith("CE")) { se.type = "CE"; } // Fix problems if (se.type.equals("-") || se.type.equals("NUL")) { se.type = "NULLDT"; } /* * *** * index is 1-indexed here!! * *** */ // 3454369 if (version.equals("2.3") && name.equals("MRG") && index == 7) { se.type = "XPN"; } // https://sourceforge.net/p/hl7api/bugs/95/ if (version.equals("2.3") && name.equals("ORC") && index == 14) { se.type = "XTN"; } // 2864817 if (version.equals("2.3") && name.equals("PID") && index == 5) { se.rep = "Y"; se.repetitions = -1; } elements.add(se); /*System.out.println("Segment: " + name + " Field: " + se.field + " Rep: " + se.rep + " Repetitions: " + se.repetitions + " Desc: " + se.desc + " Length: " + se.length + " Table: " + se.table + " Segment Desc: " + segDesc);*/ } stmt.close(); normativeDatabase.returnConnection(conn); } catch (SQLException sqle) { // sqle.printStackTrace(); // return; throw new MojoFailureException("Failed to generate segment", sqle); } String fileName = theTargetDir.toString() + "/" + name + "." + theFileExt; String basePackageName = DefaultModelClassFactory.getVersionPackageName(version); String[] datatypePackages = { basePackageName + "datatype" }; writeSegment(fileName, version, name, elements, segDesc, basePackageName, datatypePackages, theTemplatePackage); } private static void listTables(Connection conn, String tableName) throws MojoFailureException, SQLException { { StringBuffer sql = new StringBuffer(); sql.append("SELECT "); sql.append(tableName + ".* "); sql.append("FROM " + tableName + " "); //System.out.println(sql.toString()); //for debugging Statement stmt; ResultSet rs; try { stmt = conn.createStatement(); rs = stmt.executeQuery(sql.toString()); } catch (Exception e) { throw new MojoFailureException("Failed to execute the following SQL: " + sql.toString(), e); } rs.next(); Set<String> cols = new HashSet<String>(); for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) { cols.add(rs.getMetaData().getColumnName(i + 1)); } // System.out.println(); // System.out.println(tableName + "Cols: " + cols); // System.out.println(); rs.close(); stmt.close(); } } public static void writeSegment(String fileName, String version, String segmentName, ArrayList<SegmentElement> elements, String description, String basePackage, String[] datatypePackages, String theTemplatePackage) throws Exception { log.debug("Writing segment: {}", fileName); BufferedWriter out = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(fileName, false), SourceGenerator.ENCODING)); theTemplatePackage = theTemplatePackage.replace(".", "/"); Template template = VelocityFactory.getClasspathTemplateInstance(theTemplatePackage + "/segment.vsm"); VelocityContext ctx = new VelocityContext(); ctx.put("segmentName", segmentName); ctx.put("typeDescription", description); ctx.put("basePackageName", basePackage); ctx.put("elements", elements); ctx.put("datatypePackages", datatypePackages); ctx.put("hl7VersionInQuotes", '"' + version + '"'); template.merge(ctx, out); // String string = createSegmentString(version, segmentName, elements, description, basePackage, datatypePackageString); // out.write(string); out.flush(); out.close(); } }