| /** |
| * |
| * Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com> |
| * |
| * ==================================================================== |
| * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * ==================================================================== |
| */ |
| package org.jclouds.codegen.util; |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileReader; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.jclouds.codegen.model.API; |
| import org.jclouds.codegen.model.Command; |
| import org.jclouds.codegen.model.DomainType; |
| import org.jclouds.codegen.model.Package; |
| import org.jclouds.codegen.model.Type; |
| |
| import com.google.gson.Gson; |
| import com.google.gson.JsonParseException; |
| |
| import freemarker.template.Configuration; |
| import freemarker.template.Template; |
| import freemarker.template.TemplateException; |
| |
| /** |
| * Converts object models representing AWS API beans into Java classes. |
| * <p> |
| * This implementation is designed to perform the following steps: |
| * <ul> |
| * <li>Parse the JSON object representation produced by the <tt>parse_ec2.pl</tt> perl script</li> |
| * <li>Convert the JSON into Java object models (@see org.jclouds.aws.codegen.models)</li> |
| * <li>Iterate through the Command objects generated above and with each one: |
| * <ul> |
| * <li>Load the <a href="http://freemarker.org/">FreeMarker</a>template file for the given object</li> |
| * <li>Create a package directory to receive the Java file, if necessary</li> |
| * <li>Process the object through the template, producing a Java implementation of the object</li> |
| * <ul></li> |
| * |
| * @author James Murty |
| */ |
| public class CodeGenerator { |
| public final static String COMMAND_TEMPLATE_FILENAME = "Command.ftl"; |
| public final static String BEAN_TEMPLATE_FILENAME = "Bean.ftl"; |
| public final static String OPTIONS_TEMPLATE_FILENAME = "Options.ftl"; |
| public final static String VALUE_TEMPLATE_FILENAME = "Value.ftl"; |
| public final static String RESPONSE_TEMPLATE_FILENAME = "Response.ftl"; |
| |
| private final File targetDirectory; |
| private final String rootPackageName; |
| private final Configuration config; |
| |
| public CodeGenerator(String rootPackageName, File targetDirectory) throws IOException { |
| this.rootPackageName = rootPackageName; |
| this.targetDirectory = targetDirectory; |
| |
| config = new Configuration(); |
| config.setClassForTemplateLoading(this.getClass(), "/templates"); |
| } |
| |
| /** |
| * Parse a JSON object model file (as generated by <tt>aws/src/main/bin/parse_ec2.pl</tt>) and |
| * convert it into a Java object graph. |
| * |
| * @param objectModelFile |
| * @return |
| * @throws JsonParseException |
| * @throws FileNotFoundException |
| */ |
| public API parseModelFromJSON(File objectModelFile) throws JsonParseException, |
| FileNotFoundException { |
| Gson gson = new Gson(); |
| return gson.fromJson(new FileReader(objectModelFile), API.class); |
| } |
| |
| /** |
| * Parse a JSON object model file and iterate over the resulting objects generating Java code |
| * files. |
| * |
| * @param objectModelFile |
| * @throws JsonParseException |
| * @throws IOException |
| * @throws TemplateException |
| */ |
| public void generateCode(File objectModelFile) throws JsonParseException, IOException, |
| TemplateException { |
| API model = parseModelFromJSON(objectModelFile); |
| |
| for (Package pkg : model.getPackages()) { |
| for (Command command : pkg.getCommands()) { |
| generateClassFile(command, COMMAND_TEMPLATE_FILENAME); |
| |
| if (command.getHandler() != null) { |
| generateClassFile(command.getHandler(), BEAN_TEMPLATE_FILENAME); |
| } |
| if (command.getOptions() != null |
| && command.getOptions().getJavaName().indexOf( |
| "BaseEC2RequestOptions<EC2RequestOptions>") == -1) { |
| generateClassFile(command.getOptions(), OPTIONS_TEMPLATE_FILENAME); |
| } |
| if (command.getResponse() != null |
| && !command.getResponse().getJavaName().equals("Boolean")) { |
| generateClassFile(command.getResponse(), RESPONSE_TEMPLATE_FILENAME); |
| } |
| } |
| } |
| for (DomainType value : model.getDomain().values()) { |
| generateClassFile(value, VALUE_TEMPLATE_FILENAME); |
| } |
| |
| } |
| |
| /** |
| * Generate a Java code file for the given object model bean, using the given template name as |
| * the basis for the Java class. |
| * |
| * @param bean |
| * @param templateFileName |
| * @throws IOException |
| * @throws TemplateException |
| */ |
| public void generateClassFile(Type bean, String templateFileName) throws IOException, |
| TemplateException { |
| String shortClassName = bean.getJavaName().substring( |
| bean.getJavaName().lastIndexOf('.') + 1); |
| |
| Map<String, Object> objectMap = new HashMap<String, Object>(); |
| objectMap.put("bean", bean); |
| objectMap.put("rootPackageName", this.rootPackageName); |
| objectMap.put("shortClassName", shortClassName); |
| |
| File packageDir = new File(this.targetDirectory, bean.getPackageName().replace('.', '/')); |
| |
| if (packageDir.exists() || packageDir.mkdirs()) { |
| File javaFile = new File(packageDir, shortClassName + ".java"); |
| FileWriter fw = new FileWriter(javaFile); |
| System.out.println("Generated " + javaFile); |
| applyTemplate(templateFileName, objectMap, fw); |
| } else { |
| throw new IllegalStateException("Unable to create target package directory: " + packageDir); |
| } |
| } |
| |
| /** |
| * Apply the given template to the given object, and output the results into the given writer. |
| * |
| * @param templateFileName |
| * @param objectMap |
| * @param writer |
| * @throws IOException |
| * @throws TemplateException |
| */ |
| public void applyTemplate(String templateFileName, Map<String, Object> objectMap, Writer writer) |
| throws IOException, TemplateException { |
| Template template = this.config.getTemplate(templateFileName, "UTF-8"); |
| template.process(objectMap, writer); |
| } |
| |
| public static void main(String[] args) throws Exception { |
| if (args.length != 3) { |
| System.out.println("Usage: CodeGenerator objectModelFile rootPackage targetDir"); |
| System.out.println(" E.g: CodeGenerator ec2.json org.jclouds.aws.ec2 aws/ec2/api/src"); |
| System.exit(1); |
| } |
| File objectModelFile = new File(args[0]); |
| |
| String rootPackage = args[1]; |
| |
| File targetDir = new File(args[2]); |
| |
| new CodeGenerator(rootPackage, targetDir).generateCode(objectModelFile); |
| } |
| |
| } |