com.google.gct.intellij.endpoints.generator.sample.AppEngineMavenGcmGenerator.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gct.intellij.endpoints.generator.sample.AppEngineMavenGcmGenerator.java

Source

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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 com.google.gct.intellij.endpoints.generator.sample;

import com.google.common.io.Files;
import com.google.common.io.Resources;
import com.google.gct.intellij.endpoints.GctConstants;
import com.google.gct.intellij.endpoints.generator.AppEngineMavenGenerator;
import com.google.gct.intellij.endpoints.project.AppEngineMavenProject;
import com.google.gct.intellij.endpoints.generator.template.TemplateHelper;
import com.google.gct.intellij.endpoints.util.PsiUtils;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.project.MavenProjectsManager;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;

/**
 * Instance of AppEngineMavenGenerator that creates an AppEngine sample specifically and only for
 * the GCM sample project (CloudBackendGenerator)
 */
public class AppEngineMavenGcmGenerator extends AppEngineMavenGenerator {

    protected final String myAppId;
    protected final String myApiKey;

    public static final String[] SAMPLE_ENTITY_NAMES = { "DeviceInfo", "MessageData" };
    public static final String[] SAMPLE_ENDPOINTS_NAMES = { "DeviceInfoEndpoint", "MessageEndpoint" };
    public static final String[] SAMPLE_API_NAMES = { "deviceinfoendpoint", "messageEndpoint" };

    private static final Logger LOG = Logger.getInstance(AppEngineMavenGcmGenerator.class);

    /**
     *
     * @param project
     *    The IDEA/Studio project
     * @param moduleName
     *    The name of the AppEngine module
     * @param rootPackage
     *    The root java package that will be the base package of this module
     * @param apiKey
     *    A cloud console API key (for endpoints)
     * @param appId
     *    A app engine appID (for general app engine functionality)
     */
    public AppEngineMavenGcmGenerator(@NotNull Project project, @NotNull String moduleName,
            @NotNull String rootPackage, @NotNull String apiKey, @NotNull String appId) {
        super(project, moduleName, rootPackage);
        myApiKey = apiKey;
        myAppId = appId;
    }

    /** Generate a Maven App Engine module as a backend for the Cloud Backend Sample */
    @Override
    public void generate(@Nullable final Callback callback) {
        try {
            createAppEngineDirStructure();
        } catch (IOException e) {
            logAndCallbackFailure("IOException when trying to create App Engine module directory structure", e,
                    callback);
            return;
        }

        try {
            addAppEngineSampleCode(myRootPackage, myAppId, myApiKey);
        } catch (IOException e) {
            logAndCallbackFailure("IOException when trying to add App Engine sample code", e, callback);
            return;
        }

        try {
            addMavenFunctionality();
        } catch (IOException e) {
            logAndCallbackFailure("IOException when trying to add Maven functionality to App Engine module", e,
                    callback);
            return;
        } catch (ConfigurationException e) {
            logAndCallbackFailure("Configuration exception when trying import App Engine Maven project", e,
                    callback);
            return;
        }

        try {
            addGradleRequirements();
        } catch (IOException e) {
            logAndCallbackFailure("Failed to add build.gradle file", e, callback);
            return;
        }

        // We need to invoke later to ensure the maven module is imported fully and searchable
        // TODO : we are waiting earlier for the maven Import, it is worth taking a look at the necessity of this invokeLater
        ApplicationManager.getApplication().invokeLater(new Runnable() {
            @Override
            public void run() {
                // Needed to call this here instead of immediately after addMavenFunctionality to prevent
                // the UI from hanging
                waitForMavenImport();
                myModule = ModuleManager.getInstance(myProject).findModuleByName(myModuleName);

                final AppEngineMavenProject mavenProject = AppEngineMavenProject.get(myModule);
                if (mavenProject != null) {
                    mavenProject.runGenClientLibraries(new AppEngineMavenProject.MavenBuildCallback() {
                        @Override
                        public void onBuildCompleted(int resultCode, String text) {
                            if (resultCode == 0) {
                                try {
                                    for (String apiName : SAMPLE_API_NAMES) {
                                        mavenProject.expandClientLibrary(apiName);
                                    }
                                } catch (IOException e) {
                                    logAndCallbackFailure(
                                            "IOException when expanding client library source folders", e,
                                            callback);
                                    return;
                                }
                                if (callback != null) {
                                    callback.moduleCreated(myModule);
                                    return;
                                }
                            }
                            if (callback != null) {
                                logAndCallbackFailure(
                                        "Maven build failed : (result code " + resultCode + ") " + text, null,
                                        callback);
                                return;
                            }
                        }
                    });
                } else {
                    if (callback != null) {
                        logAndCallbackFailure("App Engine module failed to import maven functionality", null,
                                callback);
                        return;
                    }
                }
            }
        });
        // careful not add any code here, the code above makes some assumptions about code flow that means no non-conditional code is
        // executed
    }

    /** Pull in appEngineSampleCode from somewhere, right now it's the in-plugin templating, but maybe this whole things changes */
    protected void addAppEngineSampleCode(final String rootPackage, final String appId, final String apiKey)
            throws IOException {

        ApplicationManager.getApplication().runWriteAction(new ThrowableComputable<Void, IOException>() {
            @Override
            public Void compute() throws IOException {
                LocalFileSystem fs = LocalFileSystem.getInstance();
                PsiManager psiManager = PsiManager.getInstance(myProject);
                PsiDirectory moduleRootDir = psiManager.findDirectory(myModuleRootDir);
                PsiDirectory javaSrcDirectory = psiManager
                        .findDirectory(myModuleRootDir.findFileByRelativePath("src/main/java"));
                PsiDirectory resourcesDirectory = psiManager
                        .findDirectory(myModuleRootDir.findFileByRelativePath("src/main/resources"));
                PsiDirectory webappDirectory = psiManager
                        .findDirectory(myModuleRootDir.findFileByRelativePath("src/main/webapp"));

                // Create package directory
                PsiDirectory curPackageDir = javaSrcDirectory;
                for (String packageComponent : rootPackage.split("\\.")) {
                    curPackageDir = curPackageDir.createSubdirectory(packageComponent);
                }

                // Add entity manager
                curPackageDir.add(TemplateHelper.loadJpaEntityManagerFactoryClass(myProject, rootPackage));

                TemplateHelper.EndpointPackageInfo endpointPackageInfo = TemplateHelper
                        .getEndpointPackageInfo(rootPackage);

                // Add entities
                for (String entityName : SAMPLE_ENTITY_NAMES) {
                    curPackageDir.add(TemplateHelper.generateJavaTemplateContentWithOwnerDomain(myProject,
                            entityName, rootPackage, endpointPackageInfo));
                }

                // Add endpoints
                for (String endpointName : SAMPLE_ENDPOINTS_NAMES) {
                    PsiElement addedEndpoint = curPackageDir
                            .add(TemplateHelper.generateJavaSampleTemplateWithOwnerDomainAndApiKey(myProject,
                                    endpointName, rootPackage, endpointPackageInfo, apiKey));
                    PsiDocumentManager docManager = PsiDocumentManager.getInstance(myProject);
                    docManager.doPostponedOperationsAndUnblockDocument(
                            docManager.getDocument((PsiFile) addedEndpoint));
                }

                // Add/replace persistence.xml
                final PsiDirectory metaInfDir = resourcesDirectory
                        .findSubdirectory(GctConstants.APP_ENGINE_META_INF_DIR);
                PsiUtils.addOrReplaceFile(metaInfDir, TemplateHelper.loadPersistenceXml(myProject));

                // Add static content

                // css
                PsiDirectory cssDir = webappDirectory.createSubdirectory(GctConstants.APP_ENGINE_CSS_DIR);
                cssDir.add(TemplateHelper.generateStaticContent(myProject, "bootstrap.min.css"));

                // js
                PsiDirectory jsDir = webappDirectory.createSubdirectory(GctConstants.APP_ENGINE_JS_DIR);
                jsDir.add(TemplateHelper.generateStaticContent(myProject, "bootstrap.min.js"));
                jsDir.add(TemplateHelper.generateStaticContent(myProject, "jquery-1.9.0.min.js"));

                // images (to support twitter bootstrap)
                VirtualFile moduleImgDir = webappDirectory.getVirtualFile().createChildDirectory(null,
                        GctConstants.APP_ENGINE_IMG_DIR);
                File img = new File(moduleImgDir.getPath() + "/glyphicons-halflings.png");
                Files.write(Resources.toByteArray(TemplateHelper.class.getResource("glyphicons-halflings.png")),
                        img);

                img = new File(moduleImgDir.getPath() + "/glyphicons-halflings-white.png");
                Files.write(
                        Resources.toByteArray(TemplateHelper.class.getResource("glyphicons-halflings-white.png")),
                        img);
                moduleImgDir.refresh(false, true);

                // xml
                PsiDirectory webInfDirectory = webappDirectory
                        .createSubdirectory(GctConstants.APP_ENGINE_WEB_INF_DIR);
                webInfDirectory.add(TemplateHelper.loadWebXml(myProject));
                webInfDirectory.add(TemplateHelper.generateAppEngineWebXml(myProject, appId));

                // html
                webappDirectory.add(TemplateHelper.generateStaticContent(myProject, "index.html"));
                return null; // to Void
            }
        });
    }

    /** Add a build.gradle so the IDE doesn't complain like a nut, this may not be necessary
     * must be run on the event dispatch thread */
    private void addGradleRequirements() throws IOException {
        PsiManager psiManager = PsiManager.getInstance(myProject);
        final PsiDirectory moduleDirectory = psiManager.findDirectory(myModuleRootDir);
        if (moduleDirectory == null) {
            // not sure this is a reachable error because the maven project get root directory has got to exist
            throw new FileNotFoundException("Could not find App Engine maven project root directory");
        }
        final PsiFile gradlebuildFile = TemplateHelper.loadGradleBuildFile(myProject);
        ApplicationManager.getApplication().runWriteAction(new Runnable() {
            @Override
            public void run() {
                moduleDirectory.add(gradlebuildFile);
            }
        });
    }

    private static void logAndCallbackFailure(String message, @Nullable Throwable t, @Nullable Callback callback) {
        if (t == null) {
            LOG.error(message);
        } else {
            LOG.error(message, t);
        }
        if (callback != null) {
            callback.onFailure(message);
        }
    }
}