org.eclipse.che.util.ExtensionRegistryGenerator.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.che.util.ExtensionRegistryGenerator.java

Source

/*******************************************************************************
 * Copyright (c) 2012-2016 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.eclipse.che.ide.api.extension.Extension;
import org.eclipse.che.ide.api.extension.ExtensionRegistry;
import org.eclipse.che.ide.api.extension.SDK;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JConstructor;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.google.inject.Inject;
import com.google.inject.Provider;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * This class generates implementation for {@link org.eclipse.che.ide.api.extension.ExtensionRegistry} that contains descriptive information about
 * extensions present in IDE Bundle.
 * Generator processes all Types found by TypeOracle, looking for {@link Extension} annotation.
 * Each class annotated with Extension is processed to retrieve dependency information. Dependencies
 * are collected by reading constructor annotated with {@link Inject}. All arguments retrieved and asked if
 * annotated with {@link Extension} of {@link SDK}.
 *
 * @author <a href="mailto:nzamosenchuk@exoplatform.com">Nikolay Zamosenchuk</a>
 */
public class ExtensionRegistryGenerator extends Generator {

    /** {@inheritDoc} */
    @Override
    public String generate(TreeLogger logger, GeneratorContext context, String typeName)
            throws UnableToCompleteException {
        TypeOracle typeOracle = context.getTypeOracle();
        JClassType extensionManager = typeOracle.findType(typeName);
        if (extensionManager == null) {
            logger.log(TreeLogger.ERROR, "Can't find interface type '" + typeName + "'", null);
            throw new UnableToCompleteException();
        }
        if (extensionManager.isInterface() == null) {
            logger.log(TreeLogger.ERROR, extensionManager.getQualifiedSourceName() + " is not an interface", null);
            throw new UnableToCompleteException();
        }

        List<JClassType> extensions = new ArrayList<>();
        for (JClassType type : typeOracle.getTypes()) {
            if (type.isAnnotationPresent(Extension.class)) {
                extensions.add(type);
            }
        }

        String packageName = extensionManager.getPackage().getName();
        String className = extensionManager.getSimpleSourceName() + "Impl";

        generateClass(logger, context, packageName, className, extensions);

        return packageName + "." + className;
    }

    /**
     * Generate the content of the class
     *
     * @param logger
     * @param context
     * @param packageName
     * @param className
     * @param extensions
     * @throws UnableToCompleteException
     */
    private void generateClass(TreeLogger logger, GeneratorContext context, String packageName, String className,
            List<JClassType> extensions) throws UnableToCompleteException {
        PrintWriter pw = context.tryCreate(logger, packageName, className);
        if (pw == null) {
            return;
        }

        ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(packageName, className);
        // generate imports
        generateImports(extensions, composerFactory);

        // interface
        composerFactory.addImplementedInterface(ExtensionRegistry.class.getCanonicalName());

        // get source writer
        SourceWriter sw = composerFactory.createSourceWriter(context, pw);
        // begin class definition
        // fields
        sw.println("private final Map<String, ExtensionDescription> extensions = new HashMap<>();");

        generateConstructor(className, extensions, sw);

        // methods
        generateGetExtensionsMethod(sw);
        // close it out
        sw.outdent();
        sw.println("}");

        context.commit(logger, pw);
    }

    /**
     * Inject imports
     *
     * @param extensions
     * @param composerFactory
     */
    private void generateImports(List<JClassType> extensions, ClassSourceFileComposerFactory composerFactory) {
        // imports
        composerFactory.addImport(GWT.class.getCanonicalName());
        composerFactory.addImport(Extension.class.getCanonicalName());
        composerFactory.addImport(ExtensionRegistry.class.getCanonicalName());
        composerFactory.addImport(Inject.class.getCanonicalName());
        composerFactory.addImport(Provider.class.getCanonicalName());
        composerFactory.addImport(List.class.getCanonicalName());
        composerFactory.addImport(ArrayList.class.getCanonicalName());
        composerFactory.addImport(Map.class.getCanonicalName());
        composerFactory.addImport(HashMap.class.getCanonicalName());
        // import for extensions
        for (JClassType jClassType : extensions) {
            composerFactory.addImport(jClassType.getQualifiedSourceName());
        }
    }

    /**
     * Generate constructor with dependencies added into field
     *
     * @param className
     * @param extensions
     * @param sw
     * @throws UnableToCompleteException
     */
    private void generateConstructor(String className, List<JClassType> extensions, SourceWriter sw)
            throws UnableToCompleteException {
        // constructor
        sw.indent();
        sw.print("public %s()", className);
        sw.println("{");
        sw.indent();
        {
            for (JClassType extension : extensions) {
                sw.println("{");
                sw.indent();
                /*
                   Array<DependencyDescription> deps = Collections.<DependencyDescription> createArray();
                */
                generateDependenciesForExtension(sw, extension);

                Extension annotation = extension.getAnnotation(Extension.class);

                /*
                   extensions.put("ide.ext.demo", new ExtensionDescription("ide.ext.demo", "1.0.0", "Demo extension", deps,
                   demoExtProvider));
                */

                // the class's fqn
                String extensionId = extension.getQualifiedSourceName();

                sw.println("extensions.put(\"%s\", new ExtensionDescription(\"%s\",\"%s\",\"%s\",\"%s\",deps));",
                        escape(extensionId), escape(extensionId), escape(annotation.version()),
                        escape(annotation.title()), escape(annotation.description()));
                sw.outdent();
                sw.println("}");
            }
        }
        sw.outdent();
        sw.println("}");
    }

    /**
     * Writes dependency gathering code, like:
     * <p/>
     * Array<DependencyDescription> deps = Collections.<DependencyDescription> createArray();
     * deps.add(new DependencyDescription("ide.api.ui.menu", ""));
     * deps.add(new DependencyDescription("extension.demo", "1.0.0-alpha"));
     *
     * @param sw
     * @param extension
     * @throws UnableToCompleteException
     */
    private void generateDependenciesForExtension(SourceWriter sw, JClassType extension)
            throws UnableToCompleteException {
        // expected code
        /*      
        Array<DependencyDescription> deps = Collections.<DependencyDescription> createArray();
        deps.add(new DependencyDescription("ide.api.ui.menu", ""));
        */
        if (extension.getConstructors().length == 0) {
            throw new UnableToCompleteException();
        }
        sw.println("List<DependencyDescription> deps = new ArrayList<>();");

        JConstructor jConstructor = extension.getConstructors()[0];
        JType[] parameterTypes = jConstructor.getParameterTypes();

        for (JType jType : parameterTypes) {
            JClassType argType = jType.isClassOrInterface();
            if (argType != null
                    && (argType.isAnnotationPresent(SDK.class) || argType.isAnnotationPresent(Extension.class))) {
                String id = "";
                String version = "";
                if (argType.isAnnotationPresent(SDK.class)) {
                    id = argType.getAnnotation(SDK.class).title();
                } else if (argType.isAnnotationPresent(Extension.class)) {
                    id = argType.getQualifiedSourceName();
                    version = argType.getAnnotation(Extension.class).version();
                }
                sw.println("deps.add(new DependencyDescription(\"%s\", \"%s\"));", escape(id), escape(version));
            }
        }
    }

    /**
     * Generate the code for {@link ExtensionRegistry#getExtensionDescriptions()}
     *
     * @param sw
     */
    private void generateGetExtensionsMethod(SourceWriter sw) {
        /*
        @Override
        public StringMap<ExtensionDescription> getExtensionDescriptions()
        {
           return extensions;
        }
         */

        sw.println("@Override");
        sw.println("public Map<String, ExtensionDescription> getExtensionDescriptions()");

        sw.println("{");
        sw.indent();

        sw.println("return extensions;");

        sw.outdent();
        sw.println("}");
    }
}