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 "ConformanceComponentBuilder.java".  Description: 
10  "This method builds Conformance Component Classes" 
11  
12  The Initial Developer of the Original Code is University Health Network. Copyright (C) 
13  2001.  All Rights Reserved. 
14  
15  Contributor(s): James Agnew
16                  Paul Brohman
17                  Mitch Delachevrotiere
18                  Shawn Dyck
19    				Cory Metcalf
20    				
21  Alternatively, the contents of this file may be used under the terms of the 
22  GNU General Public License (the  ?GPL?), in which case the provisions of the GPL are 
23  applicable instead of those above.  If you wish to allow use of your version of this 
24  file only under the terms of the GPL and not to allow others to use your version 
25  of this file under the MPL, indicate your decision by deleting  the provisions above 
26  and replace  them with the notice and other provisions required by the GPL License.  
27  If you do not delete the provisions above, a recipient may use your version of 
28  this file under either the MPL or the GPL. 
29  
30  */
31  package ca.uhn.hl7v2.conf.classes.generator.builders;
32  
33  import java.lang.reflect.Constructor;
34  import java.lang.reflect.Method;
35  
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  
39  import ca.uhn.hl7v2.conf.ProfileException;
40  import ca.uhn.hl7v2.conf.classes.exceptions.ConformanceError;
41  import ca.uhn.hl7v2.conf.classes.generator.genclasses.GeneratedConformanceContainer;
42  import ca.uhn.hl7v2.conf.spec.message.Component;
43  import ca.uhn.hl7v2.conf.spec.message.SubComponent;
44  import ca.uhn.hl7v2.model.Composite;
45  import ca.uhn.hl7v2.model.Message;
46  
47  /** This class builds Conformance Component Classes
48   * @author <table><tr>James Agnew</tr>
49   *                <tr>Paul Brohman</tr>
50   *                <tr>Mitch Delachevrotiere</tr>
51   *                <tr>Shawn Dyck</tr>
52   * 				  <tr>Cory Metcalf</tr></table>
53   */
54  public class ConformanceComponentBuilder {
55  	
56  	private static final Logger ourLog = LoggerFactory.getLogger(ConformanceComponentBuilder.class);
57  	
58     private DeploymentManager depManager; // The deployment manager
59     private DocumentationBuilder docBuilder;
60     private String packageName;
61     private String versionString;
62  
63     /** This constructor will create a new ConformanceComponentBuilder
64      * @param packageName the name of the package
65      * @param versionString the version of HL7 which these classes are conforming to
66      * @param depManager the instance of DeploymentManager
67      */
68     public ConformanceComponentBuilder(String packageName, DeploymentManager depManager, String versionString) {
69        this.packageName = packageName;
70        this.docBuilder = DocumentationBuilder.getDocumentationBuilder();
71        this.depManager = depManager;
72        this.versionString = versionString;
73     }
74  
75     /** This method builds a Conformance Component Class
76      * @param comp the Component to build
77      */
78     public void buildClass(Component comp) {
79  
80        ProfileName profileName = new ProfileName(comp.getName(), ProfileName.PS_COMP);
81        GeneratedConformanceContainer gcc = new GeneratedConformanceContainer();
82  
83        gcc.setClassPackage(packageName);
84  
85        gcc.addClassImport("ca.uhn.hl7v2.conf.classes.abs.*");
86        gcc.addClassImport("ca.uhn.hl7v2.conf.classes.exceptions.*");
87        gcc.addClassImport("ca.uhn.hl7v2.model.*");
88        gcc.addClassImport(packageName + "." + profileName.getPackageName() + ".*");
89  
90        gcc.setName(profileName.getClassName());
91        gcc.setProperties("extends AbstractConformanceContainer");
92        gcc.addMemberVariable("private Composite hapiType;");
93  
94        gcc.getConstructor().addToComments("Creates new instances of all SubComponents contained in this Component");
95        gcc.getConstructor().addToBody("this.hapiType = hapiType;");
96  
97  	  docBuilder.decorateConstructor( gcc.getConstructor(), profileName.getClassName() );
98        // Add member variables and getters for subcomponents
99        gcc.getConstructor().addToBody("try{");
100       for (int i = 1; i <= comp.getSubComponents(); i++) {
101 		//don't build not supported, backward, or unknown types
102 		 String usage = comp.getSubComponent(i).getUsage();
103 		 if( usage != null && (usage.equals("X") || usage.equals("B") || usage.equals("U")) )
104 			continue;
105 			
106 			// The following is a workaround to allow for composite subcomponents. 
107 			Class<?> c;
108 			Object instance;
109 			try {
110             
111         	 String className = "ca.uhn.hl7v2.model." + versionString + ".datatype." + comp.getSubComponent(i).getDatatype();
112         	 ourLog.info("Analyzing class: "+ className);
113             
114 			c = Class.forName(className);
115             Constructor<?> constructor = c.getConstructors()[0];
116 			if (constructor.getParameterTypes().length == 1) {
117 				instance = constructor.newInstance((Message)null);
118 			} else {
119 				instance = constructor.newInstance((Message)null, 0);
120 			}
121          } catch ( Exception e ) {
122 				throw new ConformanceError("Could not find underlying SubComponent datatype. This is a bug. Exception: " + e.toString(), e);
123 			}
124 
125          if ( instance instanceof Composite ) {
126         	 	
127         	 	@SuppressWarnings("unchecked")
128 				Class<? extends Composite> cComp = (Class<? extends Composite>) c;
129         	 
130 				// In this case, the child is a composite subcomponent
131 				Component generatedComponent = createSubComponentProfile(cComp, comp.getSubComponent(i).getName());
132 				gcc.addComponent(new ProfileName(comp.getSubComponent(i).getName(), ProfileName.PS_COMP), i - 1, true);
133 				ConformanceComponentBuilder childBuilder = new ConformanceComponentBuilder(packageName + "." + profileName.getPackageName(), depManager, versionString);
134 				childBuilder.buildClass(generatedComponent);
135          } else { 
136 				// In this case, the child is a primitive (this is the normal case)
137 				gcc.addSubComponent(new ProfileName(comp.getSubComponent(i).getName(), ProfileName.PS_SUBC), i - 1);
138 				ConformancePrimitiveBuilder childBuilder = new ConformancePrimitiveBuilder(packageName + "." + profileName.getPackageName(), depManager);
139 				childBuilder.buildClass(comp.getSubComponent(i), ProfileName.PS_SUBC);
140          }
141 
142       }
143 
144       gcc.getConstructor().addParam("Composite hapiType", "Reference to the underlying HAPI Composite data type.");
145       gcc.getConstructor().addToBody("} catch ( DataTypeException e ) {");
146       gcc.getConstructor().addToBody("   throw new ConformanceError(\"Invalid Attempt to access a rep. This is a Conformance Class Bug\");");
147       gcc.getConstructor().addToBody("}");
148 
149       // Decorate with comments
150       docBuilder.decorateComponent(gcc, comp);
151 
152       if (depManager.getVerbose())
153          System.out.println("Generating Component: " + packageName + "." + gcc.getName());
154 
155       depManager.generateFile(gcc, packageName, gcc.getName());
156    }
157 
158    /** This method creates a Sub Component profile 
159     * @param compositeClass - the Class
160     * @param name - the Component name
161     * @return Component - the Component
162     */
163    private Component createSubComponentProfile(Class<? extends Composite> compositeClass, String name) {
164       Component theComponent = new Component();
165       int numSubComponents = 0;
166 
167       try {
168          theComponent.setName(name);
169          theComponent.setDatatype(compositeClass.getName().substring(compositeClass.getName().lastIndexOf('.') + 1));
170          Method[] methods = compositeClass.getMethods();
171 
172          for (int i = 0; i < methods.length; i++) {
173 
174             if (methods[i].getReturnType().getName().length() > 18 && methods[i].getReturnType().getName().substring(0, 18).equals("ca.uhn.hl7v2.model") && methods[i].getParameterTypes().length == 0 && methods[i].getName().subSequence(0, 3).equals("get")) {
175 
176                SubComponent sc = new SubComponent();
177                sc.setName(methods[i].getName().substring(3));
178                sc.setDatatype(methods[i].getReturnType().getName().substring(methods[i].getReturnType().getName().lastIndexOf('.') + 1));
179                sc.setConstantValue("");
180 
181                numSubComponents++;
182                theComponent.setSubComponent(numSubComponents, sc);
183             }
184 
185          }
186 
187          /* Workaround for the TS datatype, as it does not currently
188           * provide named getters for its subcomponents. */	
189          if (theComponent.getDatatype().equals("TS") && theComponent.getSubComponents() == 0) {
190             SubComponent sc = new SubComponent();
191             sc.setName("DateTime");
192             sc.setDatatype("NM");
193             sc.setConstantValue("");
194             theComponent.setSubComponent(1, sc);
195 
196             sc = new SubComponent();
197             sc.setName("DegreeOfPrecision");
198             sc.setDatatype("ST");
199             sc.setConstantValue("");
200             theComponent.setSubComponent(2, sc);
201          }
202 
203       } catch (ProfileException e) {
204          e.printStackTrace();
205       }
206 
207       return theComponent;
208    }
209 }