1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.axis2.wsdl.codegen;
21
22 import org.apache.axis2.AxisFault;
23 import org.apache.axis2.description.WSDL11ToAllAxisServicesBuilder;
24 import org.apache.axis2.description.WSDL11ToAxisServiceBuilder;
25 import org.apache.axis2.description.WSDL20ToAllAxisServicesBuilder;
26 import org.apache.axis2.description.WSDL20ToAxisServiceBuilder;
27 import org.apache.axis2.util.CommandLineOption;
28 import org.apache.axis2.util.CommandLineOptionConstants;
29 import org.apache.axis2.util.CommandLineOptionParser;
30 import org.apache.axis2.wsdl.codegen.emitter.Emitter;
31 import org.apache.axis2.wsdl.codegen.extension.CodeGenExtension;
32 import org.apache.axis2.wsdl.databinding.TypeMapper;
33 import org.apache.axis2.wsdl.i18n.CodegenMessages;
34 import org.apache.axis2.wsdl.util.ConfigPropertyFileLoader;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 import javax.wsdl.Definition;
39 import javax.wsdl.WSDLException;
40 import javax.wsdl.factory.WSDLFactory;
41 import javax.wsdl.xml.WSDLReader;
42 import javax.xml.namespace.QName;
43 import java.io.File;
44 import java.io.IOException;
45 import java.net.URISyntaxException;
46 import java.util.ArrayList;
47 import java.util.List;
48 import java.util.Map;
49
50 public class CodeGenerationEngine {
51
52 private static final Log log = LogFactory.getLog(CodeGenerationEngine.class);
53
54 /** Array List for pre-extensions. Extensions that run before the emitter */
55 private List preExtensions = new ArrayList();
56 /** Array List for post-extensions. Extensions that run after the codegens */
57 private List postExtensions = new ArrayList();
58
59 /** Codegen configuration reference */
60 private CodeGenConfiguration configuration;
61
62 /**
63 * @param configuration
64 * @throws CodeGenerationException
65 */
66 public CodeGenerationEngine(CodeGenConfiguration configuration) throws CodeGenerationException {
67 this.configuration = configuration;
68 loadExtensions();
69 }
70
71 /**
72 * @param parser
73 * @throws CodeGenerationException
74 */
75 public CodeGenerationEngine(CommandLineOptionParser parser) throws CodeGenerationException {
76 Map allOptions = parser.getAllOptions();
77 String wsdlUri;
78 try {
79
80 CommandLineOption option =
81 (CommandLineOption)allOptions.
82 get(CommandLineOptionConstants.WSDL2JavaConstants.WSDL_LOCATION_URI_OPTION);
83 wsdlUri = option.getOptionValue();
84 configuration = new CodeGenConfiguration(allOptions);
85
86
87 if (CommandLineOptionConstants.WSDL2JavaConstants.WSDL_VERSION_2.
88 equals(configuration.getWSDLVersion())) {
89
90 WSDL20ToAxisServiceBuilder builder;
91
92 // jibx currently does not support multiservice
93 if ((configuration.getServiceName() != null) || (configuration.getDatabindingType().equals("jibx"))) {
94 builder = new WSDL20ToAxisServiceBuilder(
95 wsdlUri,
96 configuration.getServiceName(),
97 configuration.getPortName(),
98 configuration.isAllPorts());
99 builder.setCodegen(true);
100 configuration.addAxisService(builder.populateService());
101 } else {
102 builder = new WSDL20ToAllAxisServicesBuilder(wsdlUri, configuration.getPortName());
103 builder.setCodegen(true);
104 builder.setAllPorts(configuration.isAllPorts());
105 configuration.setAxisServices(
106 ((WSDL20ToAllAxisServicesBuilder)builder).populateAllServices());
107 }
108
109 } else {
110 //It'll be WSDL 1.1
111 Definition wsdl4jDef = readInTheWSDLFile(wsdlUri);
112
113 // we save the original wsdl definition to write it to the resource folder later
114 // this is required only if it has imports
115 Map imports = wsdl4jDef.getImports();
116 if ((imports != null) && (imports.size() > 0)) {
117 configuration.setWsdlDefinition(readInTheWSDLFile(wsdlUri));
118 } else {
119 configuration.setWsdlDefinition(wsdl4jDef);
120 }
121
122 // we generate the code for one service and one port if the
123 // user has specified them.
124 // otherwise generate the code for every service.
125 // TODO: find out a permanant solution for this.
126 QName serviceQname = null;
127
128 if (configuration.getServiceName() != null) {
129 serviceQname = new QName(wsdl4jDef.getTargetNamespace(),
130 configuration.getServiceName());
131 }
132
133 WSDL11ToAxisServiceBuilder builder;
134 // jibx currently does not support multiservice
135 if ((serviceQname != null) || (configuration.getDatabindingType().equals("jibx"))) {
136 builder = new WSDL11ToAxisServiceBuilder(
137 wsdl4jDef,
138 serviceQname,
139 configuration.getPortName(),
140 configuration.isAllPorts());
141 builder.setCodegen(true);
142 configuration.addAxisService(builder.populateService());
143 } else {
144 builder = new WSDL11ToAllAxisServicesBuilder(wsdl4jDef, configuration.getPortName());
145 builder.setCodegen(true);
146 builder.setAllPorts(configuration.isAllPorts());
147 configuration.setAxisServices(
148 ((WSDL11ToAllAxisServicesBuilder)builder).populateAllServices());
149 }
150 }
151 configuration.setBaseURI(getBaseURI(wsdlUri));
152 } catch (AxisFault axisFault) {
153 throw new CodeGenerationException(
154 CodegenMessages.getMessage("engine.wsdlParsingException"), axisFault);
155 } catch (WSDLException e) {
156 throw new CodeGenerationException(
157 CodegenMessages.getMessage("engine.wsdlParsingException"), e);
158 } catch (Exception e) {
159 throw new CodeGenerationException(
160 CodegenMessages.getMessage("engine.wsdlParsingException"), e);
161 }
162
163 loadExtensions();
164 }
165
166 /**
167 * Loads the relevant preExtensions
168 *
169 * @throws CodeGenerationException
170 */
171 private void loadExtensions() throws CodeGenerationException {
172 //load pre extensions
173 String[] extensions = ConfigPropertyFileLoader.getExtensionClassNames();
174 if (extensions != null) {
175 for (int i = 0; i < extensions.length; i++) {
176 //load the Extension class
177 addPreExtension((CodeGenExtension)getObjectFromClassName(extensions[i].trim()));
178 }
179 }
180
181 //load post extensions
182 String[] postExtensions = ConfigPropertyFileLoader.getPostExtensionClassNames();
183 if (postExtensions != null) {
184 for (int i = 0; i < postExtensions.length; i++) {
185 //load the Extension class
186 addPostExtension(
187 (CodeGenExtension)getObjectFromClassName(postExtensions[i].trim()));
188 }
189 }
190
191 }
192
193 /**
194 * Adds a given extension to the list
195 *
196 * @param ext
197 */
198 private void addPreExtension(CodeGenExtension ext) {
199 if (ext != null) {
200 preExtensions.add(ext);
201 }
202 }
203
204 /**
205 * Adds a given extension to the list
206 *
207 * @param ext
208 */
209 private void addPostExtension(CodeGenExtension ext) {
210 if (ext != null) {
211 postExtensions.add(ext);
212 }
213 }
214
215 /**
216 * Generate the code!!
217 *
218 * @throws CodeGenerationException
219 */
220 public void generate() throws CodeGenerationException {
221 try {
222 //engage the pre-extensions
223 for (int i = 0; i < preExtensions.size(); i++) {
224 ((CodeGenExtension)preExtensions.get(i)).engage(configuration);
225 }
226
227 Emitter emitter;
228
229
230 TypeMapper mapper = configuration.getTypeMapper();
231 if (mapper == null) {
232 // this check is redundant here. The default databinding extension should
233 // have already figured this out and thrown an error message. However in case the
234 // users decides to mess with the config it is safe to keep this check in order to throw
235 // a meaningful error message
236 throw new CodeGenerationException(
237 CodegenMessages.getMessage("engine.noProperDatabindingException"));
238 }
239
240 //Find and invoke the emitter by reflection
241 Map emitterMap = ConfigPropertyFileLoader.getLanguageEmitterMap();
242 String className = (String)emitterMap.get(configuration.getOutputLanguage());
243 if (className != null) {
244 emitter = (Emitter)getObjectFromClassName(className);
245 emitter.setCodeGenConfiguration(configuration);
246 emitter.setMapper(mapper);
247 } else {
248 throw new Exception(CodegenMessages.getMessage("engine.emitterMissing"));
249 }
250
251 //invoke the necessary methods in the emitter
252 if (configuration.isServerSide()) {
253 emitter.emitSkeleton();
254 // if the users want both client and server, it would be in the
255 // generate all option
256 if (configuration.isGenerateAll()) {
257 emitter.emitStub();
258 }
259 } else {
260 emitter.emitStub();
261 }
262
263 //engage the post-extensions
264 for (int i = 0; i < postExtensions.size(); i++) {
265 ((CodeGenExtension)postExtensions.get(i)).engage(configuration);
266 }
267
268 } catch (ClassCastException e) {
269 throw new CodeGenerationException(CodegenMessages.getMessage("engine.wrongEmitter"), e);
270 } catch (Exception e) {
271 throw new CodeGenerationException(e);
272 }
273
274
275 }
276
277
278 /**
279 * Read the WSDL file
280 *
281 * @param uri
282 * @throws WSDLException
283 */
284 public Definition readInTheWSDLFile(final String uri) throws WSDLException {
285
286 WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
287 reader.setFeature("javax.wsdl.importDocuments", true);
288 return reader.readWSDL(uri);
289
290 }
291
292
293 /**
294 * gets a object from the class
295 *
296 * @param className
297 */
298 private Object getObjectFromClassName(String className) throws CodeGenerationException {
299 try {
300 Class extensionClass = getClass().getClassLoader().loadClass(className);
301 return extensionClass.newInstance();
302 } catch (ClassNotFoundException e) {
303 // TODO REVIEW FOR JAVA 6
304 // In Java 5, if you passed an array string such as "[Lcom.mypackage.MyClass;" to
305 // loadClass, the class would indeed be loaded.
306 // In JDK6, a ClassNotFoundException is thrown.
307 // The work-around is to use code Class.forName instead.
308 // Example:
309 // try {
310 // classLoader.loadClass(name);
311 // } catch (ClassNotFoundException e) {
312 // Class.forName(name, false, loader);
313 // }
314 log.debug(CodegenMessages.getMessage("engine.extensionLoadProblem"), e);
315 return null;
316 } catch (InstantiationException e) {
317 throw new CodeGenerationException(
318 CodegenMessages.getMessage("engine.extensionInstantiationProblem"), e);
319 } catch (IllegalAccessException e) {
320 throw new CodeGenerationException(CodegenMessages.getMessage("engine.illegalExtension"),
321 e);
322 } catch (NoClassDefFoundError e) {
323 log.debug(CodegenMessages.getMessage("engine.extensionLoadProblem"), e);
324 return null;
325 } catch (Exception e) {
326 throw new CodeGenerationException(e);
327 }
328
329 }
330
331 /**
332 * calculates the base URI Needs improvement but works fine for now ;)
333 *
334 * @param currentURI
335 */
336 private String getBaseURI(String currentURI) throws URISyntaxException, IOException {
337 File file = new File(currentURI);
338 if (file.exists()) {
339 return file.getCanonicalFile().getParentFile().toURI().toString();
340 }
341 String uriFragment = currentURI.substring(0, currentURI.lastIndexOf("/"));
342 return uriFragment + (uriFragment.endsWith("/") ? "" : "/");
343 }
344
345 /**
346 * calculates the URI
347 * needs improvement
348 *
349 * @param currentURI
350 */
351 private String getURI(String currentURI) throws URISyntaxException, IOException {
352
353 File file = new File(currentURI);
354 if (file.exists()){
355 return file.getCanonicalFile().toURI().toString();
356 } else {
357 return currentURI;
358 }
359
360 }
361
362 public CodeGenConfiguration getConfiguration() {
363 return configuration;
364 }
365 }