/******************************************************************************* * Copyright (c) 2014 BREDEX GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * BREDEX GmbH - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.jubula.toolkit.api.gen.internal; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.MessageFormat; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.eclipse.jubula.toolkit.api.gen.ActionHandlerGenerator; import org.eclipse.jubula.toolkit.api.gen.ComponentClassGenerator; import org.eclipse.jubula.toolkit.api.gen.FactoryGenerator; import org.eclipse.jubula.toolkit.api.gen.ToolkitInfoGenerator; import org.eclipse.jubula.toolkit.api.gen.internal.genmodel.CommonGenInfo; import org.eclipse.jubula.toolkit.api.gen.internal.genmodel.CompInfoForFactoryGen; import org.eclipse.jubula.toolkit.api.gen.internal.genmodel.CompInfoForToolkitGen; import org.eclipse.jubula.toolkit.api.gen.internal.genmodel.ComponentGenInfo; import org.eclipse.jubula.toolkit.api.gen.internal.genmodel.FactoryGenInfo; import org.eclipse.jubula.toolkit.api.gen.internal.genmodel.ToolkitGenInfo; import org.eclipse.jubula.toolkit.api.gen.internal.utils.ConfigLoader; import org.eclipse.jubula.tools.internal.constants.StringConstants; import org.eclipse.jubula.tools.internal.utils.generator.CompSystemProcessor; import org.eclipse.jubula.tools.internal.utils.generator.ComponentInfo; import org.eclipse.jubula.tools.internal.utils.generator.ToolkitConfig; import org.eclipse.jubula.tools.internal.utils.generator.ToolkitInfo; import org.eclipse.jubula.tools.internal.xml.businessmodell.CompSystem; import org.eclipse.jubula.tools.internal.xml.businessmodell.Component; import org.eclipse.jubula.tools.internal.xml.businessmodell.ComponentClass; import org.eclipse.jubula.tools.internal.xml.businessmodell.ConcreteComponent; import org.eclipse.jubula.tools.internal.xml.businessmodell.ToolkitDescriptor; /** * Generates classes for components from comp system */ public class APIGenerator { /** class generator */ private static ComponentClassGenerator componentClassGenerator = new ComponentClassGenerator(); /** action handler class generator */ private static ActionHandlerGenerator actionHandlerGenerator = new ActionHandlerGenerator(); /** factory generator */ private static FactoryGenerator factoryGenerator = new FactoryGenerator(); /** factory generator */ private static ToolkitInfoGenerator toolkitInfoGenerator = new ToolkitInfoGenerator(); /** containing information for factory generation. * will be reseted for each toolkit */ private static FactoryGenInfo factoryGenInfo; /** containing information for toolkit information generation. * will be reseted for each toolkit */ private static ToolkitGenInfo tookitGenInfo; /** whether a class containing information about a toolkit needs to be generated */ private static boolean toolkitNeedsInfoClass = false; /** * map containing component name mappings * will be reseted for each component */ private static Map<String, String> compNameMap = new TreeMap<String, String>(); /** * Constructor */ private APIGenerator() { // hidden } /** * main * @param args args */ public static void main(String[] args) { ConfigLoader loader = ConfigLoader.getInstance(); String generationBaseDir = loader.getGenerationDir(); ToolkitConfig config = loader.getToolkitConfig(); CompSystemProcessor processor = new CompSystemProcessor(config); List<ToolkitInfo> toolkitInfos = processor.getToolkitInfos(); String converterInfoDir = loader.getConverterInfoDir(); // Clean up File converterDirectory = new File(converterInfoDir); if (converterDirectory.exists()) { try { FileUtils.cleanDirectory(converterDirectory); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } else { converterDirectory.mkdirs(); } for (ToolkitInfo tkInfo : toolkitInfos) { cleanUp(tkInfo, generationBaseDir); } // Generate classes and interfaces toolkit by toolkit for (ToolkitInfo tkInfo : toolkitInfos) { factoryGenInfo = new FactoryGenInfo(); tookitGenInfo = new ToolkitGenInfo(); toolkitNeedsInfoClass = false; List<ComponentInfo> compInfos = processor.getCompInfos( tkInfo.getType(), tkInfo.getShortType()); for (ComponentInfo compInfo : compInfos) { compNameMap.clear(); Component component = compInfo.getComponent(); // generate interface createClass(component, generationBaseDir, true); //generate implementation class createClass(component, generationBaseDir, false); createComponentNameInfoFile(component, compNameMap, converterInfoDir); } // Generate a component factory and an information class for each toolkit CompSystem compSystem = processor.getCompSystem(); ToolkitDescriptor toolkitDesriptor = compSystem .getToolkitDescriptor(tkInfo.getType()); CommonGenInfo genInfoForFactory = new CommonGenInfo(toolkitDesriptor, false); if (toolkitNeedsInfoClass) { CommonGenInfo genInfoForToolkit = new CommonGenInfo(toolkitDesriptor, true); createToolkitInfo(genInfoForToolkit, generationBaseDir); factoryGenInfo.setToolkitInfoName( genInfoForToolkit.getToolkitName(), genInfoForToolkit.getFqClassName()); } createFactory(genInfoForFactory, generationBaseDir); } } /** * Creates the info file for a component for the converter * @param component the component * @param map name info map * @param dirPath path where to put info file */ private static void createComponentNameInfoFile(Component component, Map<String, String> map, String dirPath) { StringBuffer content = new StringBuffer(); for (String key : map.keySet()) { content.append(key + StringConstants.EQUALS_SIGN + map.get(key) + "\n"); //$NON-NLS-1$ } File dir = new File(dirPath); File file = new File(dirPath + StringConstants.SLASH + component.getType() + ".properties"); //$NON-NLS-1$ createFile(dir, file, content.toString()); } /** * Deletes all generated content of a given toolkit * @param tkInfo the toolkit * @param generationBaseDirTemplate location of generated content */ private static void cleanUp(ToolkitInfo tkInfo, String generationBaseDirTemplate) { String name = tkInfo.getShortType().toLowerCase() .replace("abstract", "base"); //$NON-NLS-1$ //$NON-NLS-2$ String generationBaseDir = MessageFormat.format( generationBaseDirTemplate, new Object[] {name}); File dir = new File(generationBaseDir); emptyDirectory(dir); } /** * Empties a directory recursively * @param dir the directory */ private static void emptyDirectory(File dir) { if (dir.exists()) { for (File file : dir.listFiles()) { if (file.isDirectory()) { try { FileUtils.deleteDirectory(file); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } } } } /** * creates class for component * @param component the component * @param generationBaseDirTemplate directory for generation * @param generateInterface whether an interface should be generated */ private static void createClass(Component component, String generationBaseDirTemplate, Boolean generateInterface) { CommonGenInfo genInfo = new CommonGenInfo(component); ComponentGenInfo compInfo = new ComponentGenInfo(component, generateInterface, genInfo.getToolkitPackageName(), genInfo.getClassName(), compNameMap); genInfo.setSpecificInformation(compInfo); String path = StringConstants.EMPTY; if (generateInterface) { path = compInfo.getInterfaceDirectoryPath(); } else { path = genInfo.getClassDirectoryPath(); } String className = genInfo.getClassName(); String generationBaseDir = MessageFormat.format( generationBaseDirTemplate, new Object[] {genInfo.getToolkitPackageName()}); File dir = new File(generationBaseDir + path); File file = new File(dir, className + ".java"); //$NON-NLS-1$ String content = componentClassGenerator.generate(genInfo); createFile(dir, file, content); dir = new File(generationBaseDir + path + "/handler"); //$NON-NLS-1$ file = new File(dir, className + "ActionHandler.java"); //$NON-NLS-1$ content = actionHandlerGenerator.generate(genInfo); createFile(dir, file, content); /* After generating an impl class, add component information * to factory and toolkit generation information */ if (!generateInterface) { ComponentClass componentClass = null; String testerClass = null; if (component instanceof ConcreteComponent) { ConcreteComponent concreteComponent = (ConcreteComponent) component; componentClass = concreteComponent.getComponentClass(); testerClass = concreteComponent.getTesterClass(); if (componentClass != null && testerClass != null) { toolkitNeedsInfoClass = true; } } if (!compInfo.hasDefaultMapping() || (componentClass != null && !componentClass.getName().isEmpty())) { CompInfoForFactoryGen compInfoForFactory = new CompInfoForFactoryGen( genInfo.getClassName(), genInfo.getClassPackageName(), componentClass, compInfo.hasDefaultMapping(), compInfo.getMostSpecificVisibleSuperTypeName()); String sinceC = component.getSince(); if (StringUtils.isNotBlank(sinceC)) { compInfoForFactory.setSince(sinceC); } factoryGenInfo.addCompInformation(compInfoForFactory); } tookitGenInfo.addCompInformation(new CompInfoForToolkitGen( componentClass, testerClass)); } } /** * creates factory for toolkit * @param tkGenInfo the generation information for the toolkit * @param generationBaseDirTemplate directory for generation */ private static void createFactory(CommonGenInfo tkGenInfo, String generationBaseDirTemplate) { tkGenInfo.setSpecificInformation(factoryGenInfo); String path = tkGenInfo.getClassDirectoryPath(); String className = tkGenInfo.getClassName(); String generationBaseDir = MessageFormat.format( generationBaseDirTemplate, new Object[] {tkGenInfo.getToolkitPackageName()}); File dir = new File(generationBaseDir + path); File file = new File(dir, className + ".java"); //$NON-NLS-1$ String content = factoryGenerator.generate(tkGenInfo); createFile(dir, file, content); } /** * creates toolkit information class * @param tkGenInfo the generation information for the toolkit * @param generationBaseDirTemplate directory for generation */ private static void createToolkitInfo(CommonGenInfo tkGenInfo, String generationBaseDirTemplate) { tkGenInfo.setSpecificInformation(tookitGenInfo); String path = tkGenInfo.getClassDirectoryPath(); String className = tkGenInfo.getClassName(); String generationBaseDir = MessageFormat.format( generationBaseDirTemplate, new Object[] {tkGenInfo.getToolkitPackageName()}); File dir = new File(generationBaseDir + path); File file = new File(dir, className + ".java"); //$NON-NLS-1$ String content = toolkitInfoGenerator.generate(tkGenInfo); createFile(dir, file, content); } /** creates a file with given content in a given directory * @param dir the directory * @param file the file * @param content the content */ private static void createFile(File dir, File file, String content) { if (!file.exists()) { try { dir.mkdirs(); file.createNewFile(); } catch (IOException e) { e.printStackTrace(); System.exit(1); } try (FileOutputStream fop = new FileOutputStream(file)) { byte[] contentInBytes = content.getBytes(); IOUtils.write(contentInBytes, fop); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } else { System.out.println("ERROR: " + file.getName() + " already exists!"); //$NON-NLS-1$ //$NON-NLS-2$ System.exit(1); } } }