Package org.jboss.forge.addon.angularjs

Source Code of org.jboss.forge.addon.angularjs.AngularScaffoldProvider

/**
* Copyright 2014 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Eclipse Public License version 1.0, available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.jboss.forge.addon.angularjs;

import static org.jboss.forge.addon.angularjs.ResourceProvider.ANGULAR_JS;
import static org.jboss.forge.addon.angularjs.ResourceProvider.ANGULAR_RESOURCE_JS;
import static org.jboss.forge.addon.angularjs.ResourceProvider.ANGULAR_ROUTE_JS;
import static org.jboss.forge.addon.angularjs.ResourceProvider.BOOTSTRAP_CSS;
import static org.jboss.forge.addon.angularjs.ResourceProvider.BOOTSTRAP_JS;
import static org.jboss.forge.addon.angularjs.ResourceProvider.BOOTSTRAP_THEME_CSS;
import static org.jboss.forge.addon.angularjs.ResourceProvider.FORGE_LOGO_PNG;
import static org.jboss.forge.addon.angularjs.ResourceProvider.GLYPHICONS_EOT;
import static org.jboss.forge.addon.angularjs.ResourceProvider.GLYPHICONS_SVG;
import static org.jboss.forge.addon.angularjs.ResourceProvider.GLYPHICONS_TTF;
import static org.jboss.forge.addon.angularjs.ResourceProvider.GLYPHICONS_WOFF;
import static org.jboss.forge.addon.angularjs.ResourceProvider.JQUERY_JS;
import static org.jboss.forge.addon.angularjs.ResourceProvider.LANDING_VIEW;
import static org.jboss.forge.addon.angularjs.ResourceProvider.MAIN_CSS;
import static org.jboss.forge.addon.angularjs.ResourceProvider.MODERNIZR_JS;
import static org.jboss.forge.addon.angularjs.ResourceProvider.OFFCANVAS_JS;
import static org.jboss.forge.addon.angularjs.ResourceProvider.getEntityTemplates;
import static org.jboss.forge.addon.angularjs.ResourceProvider.getGlobalTemplates;
import static org.jboss.forge.addon.angularjs.ResourceProvider.getStatics;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.inject.Inject;
import javax.persistence.Id;

import org.jboss.forge.addon.facets.FacetFactory;
import org.jboss.forge.addon.javaee.cdi.CDIFacet;
import org.jboss.forge.addon.javaee.cdi.ui.CDISetupCommand;
import org.jboss.forge.addon.javaee.ejb.EJBFacet;
import org.jboss.forge.addon.javaee.ejb.ui.EJBSetupWizard;
import org.jboss.forge.addon.javaee.jpa.JPAFacet;
import org.jboss.forge.addon.javaee.jpa.ui.setup.JPASetupWizard;
import org.jboss.forge.addon.javaee.rest.RestFacet;
import org.jboss.forge.addon.javaee.rest.ui.RestSetupWizard;
import org.jboss.forge.addon.javaee.servlet.ServletFacet;
import org.jboss.forge.addon.javaee.servlet.ServletFacet_3_0;
import org.jboss.forge.addon.javaee.servlet.ServletFacet_3_1;
import org.jboss.forge.addon.javaee.servlet.ui.ServletSetupWizard;
import org.jboss.forge.addon.parser.java.facets.JavaSourceFacet;
import org.jboss.forge.addon.parser.java.resources.JavaResource;
import org.jboss.forge.addon.projects.Project;
import org.jboss.forge.addon.projects.facets.DependencyFacet;
import org.jboss.forge.addon.projects.facets.MetadataFacet;
import org.jboss.forge.addon.projects.facets.WebResourcesFacet;
import org.jboss.forge.addon.resource.FileResource;
import org.jboss.forge.addon.resource.Resource;
import org.jboss.forge.addon.resource.ResourceFactory;
import org.jboss.forge.addon.resource.ResourceFilter;
import org.jboss.forge.addon.scaffold.metawidget.MetawidgetInspectorFacade;
import org.jboss.forge.addon.scaffold.spi.AccessStrategy;
import org.jboss.forge.addon.scaffold.spi.ScaffoldGenerationContext;
import org.jboss.forge.addon.scaffold.spi.ScaffoldProvider;
import org.jboss.forge.addon.scaffold.spi.ScaffoldSetupContext;
import org.jboss.forge.addon.templates.TemplateFactory;
import org.jboss.forge.addon.templates.facets.TemplateFacet;
import org.jboss.forge.addon.text.Inflector;
import org.jboss.forge.addon.ui.command.UICommand;
import org.jboss.forge.addon.ui.result.NavigationResult;
import org.jboss.forge.addon.ui.result.navigation.NavigationResultBuilder;
import org.jboss.forge.addon.ui.util.Metadata;
import org.jboss.forge.roaster.model.JavaClass;
import org.jboss.forge.roaster.model.Member;
import org.jboss.forge.roaster.model.source.JavaClassSource;
import org.jboss.forge.roaster.model.source.JavaSource;
import org.jboss.shrinkwrap.descriptor.api.webapp30.WebAppDescriptor;
import org.metawidget.util.simple.StringUtils;

/**
* A {@link ScaffoldProvider} that generates AngularJS scaffolding from JPA entities. The generated scaffold is utilizes
* the REST (JAX-RS) resources generated by the Java EE addon.
*/
public class AngularScaffoldProvider implements ScaffoldProvider
{

   private static final String BASE_PACKAGE = AngularScaffoldProvider.class.getPackage().getName();

   public static final String SCAFFOLD_DIR = "/" + BASE_PACKAGE.replace('.', '/');

   Project project;

   @Inject
   private FacetFactory facetFactory;

   @Inject
   private ResourceFactory resourceFactory;

   @Inject
   private TemplateFactory templateFactory;

   @Inject
   private Inflector inflector;

   @Override
   public String getName()
   {
      return "AngularJS";
   }

   @Override
   public String getDescription()
   {
      return "Scaffold a RESTful service and an AngularJS client, from JPA entities";
   }

   @Override
   public List<Resource<?>> setup(ScaffoldSetupContext setupContext)
   {
      setProject(setupContext.getProject());
      String targetDir = setupContext.getTargetDirectory();
      targetDir = (targetDir == null) ? "" : targetDir;

      // Setup static resources.
      ArrayList<Resource<?>> result = new ArrayList<>();
      WebResourcesFacet web = project.getFacet(WebResourcesFacet.class);
      ProcessingStrategy strategy = new CopyResourcesStrategy(web);
      for (ScaffoldResource scaffoldResource : getStatics(targetDir, strategy)) {
         result.add(scaffoldResource.generate());
      }

      return result;
   }

   @Override
   @SuppressWarnings("unchecked")
   public boolean isSetup(ScaffoldSetupContext setupContext)
   {
      Project project = setupContext.getProject();
      String targetDir = setupContext.getTargetDirectory();
      targetDir = targetDir == null ? "" : targetDir;
      if (project.hasAllFacets(WebResourcesFacet.class, DependencyFacet.class, JPAFacet.class, EJBFacet.class,
               CDIFacet.class, RestFacet.class))
      {
         WebResourcesFacet web = project.getFacet(WebResourcesFacet.class);
         boolean areResourcesInstalled = web.getWebResource(targetDir + GLYPHICONS_SVG).exists()
                  && web.getWebResource(targetDir + GLYPHICONS_EOT).exists()
                  && web.getWebResource(targetDir + GLYPHICONS_SVG).exists()
                  && web.getWebResource(targetDir + GLYPHICONS_TTF).exists()
                  && web.getWebResource(targetDir + GLYPHICONS_WOFF).exists()
                  && web.getWebResource(targetDir + FORGE_LOGO_PNG).exists()
                  && web.getWebResource(targetDir + ANGULAR_RESOURCE_JS).exists()
                  && web.getWebResource(targetDir + ANGULAR_ROUTE_JS).exists()
                  && web.getWebResource(targetDir + ANGULAR_JS).exists()
                  && web.getWebResource(targetDir + MODERNIZR_JS).exists()
                  && web.getWebResource(targetDir + JQUERY_JS).exists()
                  && web.getWebResource(targetDir + BOOTSTRAP_JS).exists()
                  && web.getWebResource(targetDir + OFFCANVAS_JS).exists()
                  && web.getWebResource(targetDir + MAIN_CSS).exists()
                  && web.getWebResource(targetDir + BOOTSTRAP_CSS).exists()
                  && web.getWebResource(targetDir + BOOTSTRAP_THEME_CSS).exists()
                  && web.getWebResource(targetDir + LANDING_VIEW).exists();
         return areResourcesInstalled;
      }
      return false;
   }

   @Override
   public List<Resource<?>> generateFrom(ScaffoldGenerationContext generationContext)
   {
      setProject(generationContext.getProject());
      String targetDir = generationContext.getTargetDirectory();
      targetDir = (targetDir == null) ? "" : targetDir;
      List<Resource<?>> result = new ArrayList<>();
      Collection<Resource<?>> resources = generationContext.getResources();
      for (Resource<?> resource : resources)
      {
         JavaSource<?> javaSource = null;
         if (resource instanceof JavaResource)
         {
            JavaResource javaResource = (JavaResource) resource;
            try
            {
               javaSource = javaResource.getJavaType();
            }
            catch (FileNotFoundException fileEx)
            {
               throw new IllegalStateException(fileEx);
            }
         }
         else
         {
            continue;
         }

         JavaClassSource entity = (JavaClassSource) javaSource;
         String resourceRootPath = getRootResourcePath(project);
         // Fetch the REST resource path from the existing JAX-RS resource if found.
         String entityResourcePath = parseResourcePath(entity);
         // If the path is not available, construct a default one from the JPA entity name
         // We'll let the user resolve the incorrect path later,
         // if needed through regeneration of the JAX-RS resources.
         String entityName = entity.getName();
         if (entityResourcePath == null || entityResourcePath.isEmpty())
         {
            entityResourcePath = inflector.pluralize(entityName.toLowerCase());
         }
         entityResourcePath = trimSlashes(entityResourcePath);

         // Inspect the JPA entity and obtain a list of inspection results. Every inspected property is represented as a
         // Map<String,String> and all such inspection results are collated into a list.
         MetawidgetInspectorFacade metawidgetInspectorFacade = new MetawidgetInspectorFacade(project);
         InspectionResultProcessor angularResultEnhancer = new InspectionResultProcessor(project,
                  metawidgetInspectorFacade);
         List<Map<String, String>> inspectionResults = metawidgetInspectorFacade.inspect(entity);
         String entityId = angularResultEnhancer.fetchEntityId(entity, inspectionResults);
         inspectionResults = angularResultEnhancer.enhanceResults(entity, inspectionResults);

         MetadataFacet metadata = project.getFacet(MetadataFacet.class);

         // TODO: Provide a 'utility' class for allowing transliteration across language naming schemes
         // We need this to use contextual naming schemes instead of performing toLowerCase etc. in FTLs.

         // Prepare the Freemarker data model
         Map<String, Object> dataModel = new HashMap<>();
         dataModel.put("entityName", entityName);
         dataModel.put("pluralizedEntityName", inflector.pluralize(entityName));
         dataModel.put("entityId", entityId);
         dataModel.put("properties", inspectionResults);
         dataModel.put("projectId", StringUtils.camelCase(metadata.getProjectName()));
         dataModel.put("projectTitle", StringUtils.uncamelCase(metadata.getProjectName()));
         dataModel.put("resourceRootPath", resourceRootPath);
         dataModel.put("resourcePath", entityResourcePath);
         dataModel.put("parentDirectories", getParentDirectories(targetDir));

         // Process the Freemarker templates with the Freemarker data model and retrieve the generated resources from
         // the registry.
         WebResourcesFacet web = project.getFacet(WebResourcesFacet.class);
         ProcessingStrategy strategy = new ProcessTemplateStrategy(web, resourceFactory, project, templateFactory, dataModel);
         List<ScaffoldResource> scaffoldResources = getEntityTemplates(targetDir, entityName, strategy);
         scaffoldResources.add(new ScaffoldResource("/views/detail.html.ftl", targetDir + "/views/" + entityName
                  + "/detail.html", new DetailTemplateStrategy(web, resourceFactory, project, templateFactory, dataModel)));
         scaffoldResources.add(new ScaffoldResource("/views/search.html.ftl", targetDir + "/views/" + entityName
                  + "/search.html", new SearchTemplateStrategy(web, resourceFactory, project, templateFactory, dataModel)));
         for (ScaffoldResource scaffoldResource : scaffoldResources) {
            result.add(scaffoldResource.generate());
         }
      }

      List<Resource<?>> indexResources = generateIndex(targetDir);
      result.addAll(indexResources);
      return result;
   }

   @Override
   public NavigationResult getSetupFlow(ScaffoldSetupContext setupContext)
   {
      Project project = setupContext.getProject();
      NavigationResultBuilder builder = NavigationResultBuilder.create();
      List<Class<? extends UICommand>> setupCommands = new ArrayList<>();
      if (!project.hasFacet(JPAFacet.class))
      {
         builder.add(JPASetupWizard.class);
      }
      if (!project.hasFacet(CDIFacet.class))
      {
         setupCommands.add(CDISetupCommand.class);
      }
      if (!project.hasFacet(EJBFacet.class))
      {
         setupCommands.add(EJBSetupWizard.class);
      }
      if (!project.hasFacet(ServletFacet.class))
      {
         // TODO: FORGE-1296. Ensure that this wizard only sets up Servlet 3.0+
         setupCommands.add(ServletSetupWizard.class);
      }
      if (!project.hasFacet(RestFacet.class))
      {
         setupCommands.add(RestSetupWizard.class);
      }

      if(setupCommands.size() >0)
      {
         Metadata compositeSetupMetadata = Metadata.forCommand(setupCommands.get(0))
                  .name("Setup Facets")
                  .description("Setup all dependent facets for the AngularJS scaffold.");
         builder.add(compositeSetupMetadata, setupCommands);
      }
      return builder.build();
   }

   @Override
   public NavigationResult getGenerationFlow(ScaffoldGenerationContext generationContext)
   {
      NavigationResultBuilder builder = NavigationResultBuilder.create();
      builder.add(ScaffoldableEntitySelectionWizard.class);
      return builder.build();
   }

   @Override
   public AccessStrategy getAccessStrategy()
   {
      return null;
   }

   private void setProject(Project project)
   {
      this.project = project;
   }

   /**
    * Generates the application's index aka landing page, among others. All artifacts that are generated once per
    * scaffolding run are generated here.
    *
    * @param targetDir The target directory for the generated scaffold artifacts.
    * @return A list of generated {@link Resource}s
    */
   public List<Resource<?>> generateIndex(String targetDir)
   {
      ArrayList<Resource<?>> result = new ArrayList<>();

      /*
       * TODO: Revert this change at a later date, if necessary. This is currently done to ensure that entities are
       * picked up during invocation of the plugin from the Forge wizard in JBDS.
       */
      ResourceFilter filter = new ResourceFilter()
      {
         @Override
         public boolean accept(Resource<?> resource)
         {
            FileResource<?> file = (FileResource<?>) resource;

            if (!file.isDirectory() || file.getName().equals("resources") || file.getName().equals("WEB-INF")
                     || file.getName().equals("META-INF"))
            {
               return false;
            }

            return true;
         }
      };

      WebResourcesFacet web = this.project.getFacet(WebResourcesFacet.class);
      List<Resource<?>> resources = web.getWebResource(targetDir + "/views/").listResources(filter);
      List<String> entityNames = new ArrayList<>();
      List<String> pluralizedEntityNames = new ArrayList<>();
      for (Resource<?> resource : resources)
      {
         String resourceName = resource.getName();
         entityNames.add(resourceName);
         pluralizedEntityNames.add(inflector.pluralize(resourceName));
      }

      MetadataFacet metadata = project.getFacet(MetadataFacet.class);

      Map<String, Object> dataModel = new HashMap<>();
      dataModel.put("entityNames", entityNames);
      dataModel.put("pluralizedEntityNames", pluralizedEntityNames);
      dataModel.put("projectId", StringUtils.camelCase(metadata.getProjectName()));
      dataModel.put("projectTitle", StringUtils.uncamelCase(metadata.getProjectName()));
      dataModel.put("targetDir", targetDir);

      ProcessingStrategy strategy = new ProcessTemplateStrategy(web, resourceFactory, project, templateFactory, dataModel);
      for (ScaffoldResource scaffoldResource : getGlobalTemplates(targetDir, strategy)) {
          result.add(scaffoldResource.generate());
      }

      configureWelcomeFile();
      return result;
   }

   /**
    * Configures the welcome file entry in the project's web application descriptor to the static ever-present
    * <code>index.html</code> file. This method adds the entry only if it is absent.
    */
   private void configureWelcomeFile()
   {
      String indexFileEntry = "/index.html";

      ServletFacet servlet = this.project.getFacet(ServletFacet.class);
      if (servlet instanceof ServletFacet_3_0)
      {
         WebAppDescriptor servletConfig = (WebAppDescriptor) servlet.getConfig();
         servletConfig.getOrCreateWelcomeFileList().welcomeFile(indexFileEntry);
         servlet.saveConfig(servletConfig);
      }
      else if (servlet instanceof ServletFacet_3_1)
      {
         org.jboss.shrinkwrap.descriptor.api.webapp31.WebAppDescriptor servletConfig = (org.jboss.shrinkwrap.descriptor.api.webapp31.WebAppDescriptor) servlet
                  .getConfig();
         servletConfig.getOrCreateWelcomeFileList().welcomeFile(indexFileEntry);
         servlet.saveConfig(servletConfig);
      }
      return;
   }

   /**
    * Installs the templates into src/main/templates. All Freemarker templates would be copied into the
    * src/main/templates/angularjs directory, obeying the same structure as the one in this provider.
    */
   private void installTemplates()
   {
      // Install the required facet so that the templates directory is created if not present.
      if (!project.hasFacet(TemplateFacet.class))
      {
         facetFactory.install(project, TemplateFacet.class);
      }

      TemplateFacet templates = project.getFacet(TemplateFacet.class);
      // Obtain a reference to the scaffold directory in the classpath
      URL resource = getClass().getClassLoader().getResource("scaffold");
      if (resource != null && resource.getProtocol().equals("jar"))
      {
         try
         {
            // Obtain a reference to the JAR containing the scaffold directory
            JarURLConnection connection = (JarURLConnection) resource.openConnection();
            JarFile jarFile = connection.getJarFile();
            Enumeration<JarEntry> entries = jarFile.entries();
            // Iterate through the JAR entries and copy files to the template directory. Only files ending with .ftl,
            // and
            // present in the scaffold/ directory are copied.
            while (entries.hasMoreElements())
            {
               JarEntry jarEntry = entries.nextElement();
               String entryName = jarEntry.getName();
               if (entryName.startsWith("scaffold/") && entryName.endsWith(".ftl"))
               {
                  String relativeFilename = entryName.substring("scaffold/".length());
                  InputStream is = jarFile.getInputStream(jarEntry);
                  // Copy the file into a sub-directory under src/main/templates named after the scaffold provider.
                  Resource<File> templateResource = resourceFactory.create(new File(relativeFilename));
                  FileResource<?> fileResource = templateResource.reify(FileResource.class);
                  fileResource.setContents(is);
               }
            }
         }
         catch (IOException ioEx)
         {
            throw new RuntimeException(ioEx);
         }
      }
   }

   private String parseResourcePath(JavaClass klass)
   {
      JavaSourceFacet java = project.getFacet(JavaSourceFacet.class);
      ResourcePathVisitor visitor = new ResourcePathVisitor(klass.getName());
      java.visitJavaSources(visitor);
      return visitor.getPath();
   }

   /**
    * Obtains the root path for REST resources so that the AngularJS resource factory will be generated with the correct
    * REST resource URL.
    *
    * @return The root path of the REST resources generated by the Forge REST plugin.
    */
   private String getRootResourcePath(Project project)
   {
      RestFacet rest = project.getFacet(RestFacet.class);
      String resourceRootPath = trimSlashes(rest.getApplicationPath());
      return resourceRootPath;
   }

   /**
    * Provided a target directory, this method calculates the parent directories to re-create the path to the web
    * resource root.
    *
    * @param targetDir The target directory that would be used as the basis for calculating the parent directories.
    * @return The parent directories to traverse. Represented as a sequence of '..' characters with '/' to denote
    *         multiple parent directories.
    */
   private String getParentDirectories(String targetDir)
   {
      if (targetDir == null || targetDir.isEmpty())
      {
         return "";
      }
      else
      {
         targetDir = trimSlashes(targetDir);
         int parents = countOccurrences(targetDir, '/') + 1;
         StringBuilder parentDirectories = new StringBuilder();
         for (int ctr = 0; ctr < parents; ctr++)
         {
            parentDirectories.append("../");
         }
         return parentDirectories.toString();
      }
   }

   private int countOccurrences(String searchString, char charToSearch)
   {
      int count = 0;
      for (int ctr = 0; ctr < searchString.length(); ctr++)
      {
         if (searchString.charAt(ctr) == charToSearch)
         {
            count++;
         }
      }
      return count;
   }

   private String trimSlashes(String aString)
   {
      if (aString.startsWith("/"))
      {
         aString = aString.substring(1);
      }
      if (aString.endsWith("/"))
      {
         aString = aString.substring(0, aString.length() - 1);
      }
      return aString;
   }

}
TOP

Related Classes of org.jboss.forge.addon.angularjs.AngularScaffoldProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.