/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * 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: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.util; import org.apache.commons.io.FileUtils; import org.eclipse.che.ide.api.extension.Extension; import org.reflections.Reflections; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.regex.Pattern; import static org.eclipse.che.util.IgnoreUnExistedResourcesReflectionConfigurationBuilder.*; /** * Generates {ExtensionManager} class source * * @author <a href="mailto:nzamosenchuk@exoplatform.com">Nikolay Zamosenchuk</a> */ public class ExtensionManagerGenerator { /** Annotation to look for. */ protected static final String EXT_ANNOTATION = "@Extension"; /** Reg Exp that matches the "@Extension ( ... )" */ protected static final Pattern EXT_PATTERN = Pattern.compile(".*@Extension\\s*\\(.*\\).*", Pattern.DOTALL); /** * Path of the output class, it definitely should already exits. To ensure proper config. * File content will be overridden. */ protected static final String EXT_MANAGER_PATH = "/org/eclipse/che/ide/client/ExtensionManager.java"; /** Map containing <FullFQN, ClassName> */ protected static final Map<String, String> EXTENSIONS_FQN = new HashMap<String, String>(); /** * Entry point. --rootDir is the optional parameter. * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { File rootFolder = GeneratorUtils.getRootFolder(args); System.out.println(" ------------------------------------------------------------------------ "); System.out.println(String.format("Searching for Extensions in %s", rootFolder.getAbsolutePath())); System.out.println(" ------------------------------------------------------------------------ "); // find all Extension FQNs findExtensions(); generateExtensionManager(rootFolder); } /** * Generate to source of the Class * * @param rootFolder */ public static void generateExtensionManager(File rootFolder) throws IOException { File extManager = new File(rootFolder, EXT_MANAGER_PATH); StringBuilder builder = new StringBuilder(); builder.append("package org.eclipse.che.ide.client;\n\n"); generateImports(builder); generateClass(builder); // flush content FileUtils.writeStringToFile(extManager, builder.toString()); } /** * Generate Class declarations * * @param builder */ public static void generateClass(StringBuilder builder) { // generate class header builder.append("/**\n"); builder.append(" * THIS CLASS WILL BE OVERRIDDEN BY MAVEN BUILD. DON'T EDIT CLASS, IT WILL HAVE NO EFFECT.\n"); builder.append(" */\n"); builder.append("@Singleton\n"); builder.append("@SuppressWarnings(\"rawtypes\")\n"); builder.append("public class ExtensionManager\n"); builder.append("{\n"); builder.append("\n"); // field builder.append(GeneratorUtils.TAB) .append("/** Contains the map will all the Extension Providers <FullClassFQN, Provider>. */\n"); builder.append(GeneratorUtils.TAB) .append("protected final Map<String, Provider> extensions = new HashMap<>();\n\n"); // generate constructor builder.append(GeneratorUtils.TAB) .append("/** Constructor that accepts all the Extension found in IDE package */\n"); builder.append(GeneratorUtils.TAB).append("@Inject\n"); builder.append(GeneratorUtils.TAB).append("public ExtensionManager(\n"); // paste args here Iterator<Entry<String, String>> entryIterator = EXTENSIONS_FQN.entrySet().iterator(); while (entryIterator.hasNext()) { // <FullFQN, ClassName> Entry<String, String> extensionEntry = entryIterator.next(); String hasComma = entryIterator.hasNext() ? "," : ""; // add constructor argument like: // fullFQN classNameToLowerCase, String classFQN = String.format("Provider<%s>", extensionEntry.getKey()); String variableName = extensionEntry.getValue().toLowerCase(); builder.append(GeneratorUtils.TAB2).append(classFQN).append(" ").append(variableName).append(hasComma).append("\n"); } builder.append(GeneratorUtils.TAB).append(")\n"); builder.append(GeneratorUtils.TAB).append("{\n"); // paste add here for (Entry<String, String> extension : EXTENSIONS_FQN.entrySet()) { String fullFqn = extension.getKey(); String variableName = extension.getValue().toLowerCase(); String putStatement = String.format("this.extensions.put(\"%s\",%s);%n", fullFqn, variableName); builder.append(GeneratorUtils.TAB2).append(putStatement); } // close constructor builder.append(GeneratorUtils.TAB).append("}\n\n"); // generate getter builder.append(GeneratorUtils.TAB) .append("/** Returns the map will all the Extension Providers <FullClassFQN, Provider>. */\n"); builder.append(GeneratorUtils.TAB).append("public Map<String, Provider> getExtensions()\n"); builder.append(GeneratorUtils.TAB).append("{\n"); builder.append(GeneratorUtils.TAB2).append("return extensions;\n"); builder.append(GeneratorUtils.TAB).append("}\n"); // close class builder.append("}\n"); } /** * Generate imports * * @param builder */ public static void generateImports(StringBuilder builder) { builder.append("import com.google.inject.Inject;\n"); builder.append("import com.google.inject.Provider;\n"); builder.append("import com.google.inject.Singleton;\n"); builder.append("import java.util.HashMap;\n"); builder.append("import java.util.Map;\n"); } /** * Find all the Java Classes that have proper @Extension declaration * * @throws IOException */ @SuppressWarnings("unchecked") public static void findExtensions() throws IOException { Reflections reflection = new Reflections(getConfigurationBuilder()); Set<Class<?>> classes = reflection.getTypesAnnotatedWith(Extension.class); for (Class clazz : classes) { EXTENSIONS_FQN.put(clazz.getCanonicalName(), clazz.getSimpleName()); System.out.println(String.format("New Extension Found: %s", clazz.getCanonicalName())); } System.out.println(String.format("Found: %d extensions", EXTENSIONS_FQN.size())); } }