Package net.jangaroo.jooc.mvnplugin

Source Code of net.jangaroo.jooc.mvnplugin.PackageApplicationMojo$ZipEntryModuleSource

package net.jangaroo.jooc.mvnplugin;

import net.jangaroo.utils.BOMStripperInputStream;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.codehaus.plexus.archiver.zip.ZipEntry;
import org.codehaus.plexus.archiver.zip.ZipFile;
import org.codehaus.plexus.util.IOUtil;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* An abstract goal to build a Jangaroo application, either for testing or for an actual application.
* It aggregates all needed resources into a given Web app directory:
* <ul>
* <li>extract all dependent jangaroo artifacts</li>
* <li>optionally add Jangaroo compiler output from the current module</li>
* <li>concatenate <artifactId>.js from all dependent jangaroo artifacts into jangaroo-application.js in the correct order</li>
* </ul>
*
* @requiresDependencyResolution runtime
*/
public abstract class PackageApplicationMojo extends AbstractMojo {

  /**
   * The maven project.
   *
   * @parameter expression="${project}"
   * @required
   * @readonly
   */
  protected MavenProject project;


  /**
   * @component
   */
  @SuppressWarnings("UnusedDeclaration")
  private MavenProjectBuilder mavenProjectBuilder;

  /**
   * @parameter expression="${localRepository}"
   * @required
   */
  @SuppressWarnings("UnusedDeclaration")
  private ArtifactRepository localRepository;

  /**
   * @parameter expression="${project.remoteArtifactRepositories}"
   * @required
   */
  @SuppressWarnings("UnusedDeclaration")
  private List remoteRepositories;

  public abstract File getPackageSourceDirectory();

  /**
   * Create the Jangaroo Web app in the given Web app directory.
   * @param webappDirectory the directory where to build the Jangaroo Web app.
   * @throws org.apache.maven.plugin.MojoExecutionException if anything goes wrong
   */
  protected void createWebapp(File webappDirectory) throws MojoExecutionException {
    if (webappDirectory.mkdirs()) {
      getLog().debug("created webapp directory " + webappDirectory);
    }

    try {
      concatModuleScripts(new File(webappDirectory, "joo"));
    } catch (IOException e) {
      throw new MojoExecutionException("Failed to create jangaroo-application[-all].js", e);
    } catch (ProjectBuildingException e) {
      throw new MojoExecutionException("Failed to create jangaroo-application[-all].js", e);
    }
  }

  /**
   * Linearizes the acyclic, directed graph of all dependent artifacts to a list
   * where every item just depends on items that are contained in the list before itself.
   *
   * @return linearized dependency list of artifacts
   */
  private List<Artifact> getLinearizedDependencies() throws ProjectBuildingException {
    final Map<String, Artifact> internalId2Artifact = artifactByInternalId();

    List<String> depthFirstArtifactIds = new ArrayList<String>();
    Set<String> openArtifacts = new HashSet<String>(internalId2Artifact.keySet());
    while (!openArtifacts.isEmpty()) {
      depthFirst(internalId2Artifact, depthFirstArtifactIds, openArtifacts, openArtifacts.iterator().next());
    }

    getLog().debug("linearized dependencies: " + depthFirstArtifactIds);

    // back from internal IDs to Artifacts:
    List<Artifact> depthFirstArtifacts = new ArrayList<Artifact>(depthFirstArtifactIds.size());
    for (String depthFirstArtifactId : depthFirstArtifactIds) {
      depthFirstArtifacts.add(internalId2Artifact.get(depthFirstArtifactId));
    }
    return depthFirstArtifacts;
  }

  private void depthFirst(Map<String, Artifact> internalId2Artifact, List<String> depthFirstArtifactIds,
                          Set<String> openArtifacts, String artifactId) throws ProjectBuildingException {
    if (openArtifacts.remove(artifactId)) {
      // first, my dependencies:
      List<String> dependencies = getDependencies(internalId2Artifact.get(artifactId));
      for (String dependency : dependencies) {
        depthFirst(internalId2Artifact, depthFirstArtifactIds, openArtifacts, dependency);
      }
      // then, my artifact
      depthFirstArtifactIds.add(artifactId);
    }
  }

  private static String getInternalId(Dependency dep) {
    return dep.getGroupId() + ":" + dep.getArtifactId();
  }

  private static String getInternalId(Artifact art) {
    return art.getGroupId() + ":" + art.getArtifactId();
  }

  private static final String JOO_FLUSH_STYLE_SHEETS = "\njoo.flushStyleSheets();\n";

  private void concatModuleScripts(File scriptDirectory) throws IOException, ProjectBuildingException {
    Writer jangarooApplicationWriter = createJangarooModulesFile(scriptDirectory, "jangaroo-application.js");
    Writer jangarooApplicationAllWriter = createJangarooModulesFile(scriptDirectory, "jangaroo-application-all.js");
    try {
      jangarooApplicationWriter.write("// This file loads all collected JavaScript code from dependent Jangaroo modules.\n\n");
      jangarooApplicationAllWriter.write("// This file contains all collected JavaScript code from dependent Jangaroo modules.\n\n");

      for (Artifact artifact : getLinearizedDependencies()) {
        includeJangarooModuleScript(scriptDirectory, artifact, jangarooApplicationWriter, jangarooApplicationAllWriter);
      }
      writeThisJangarooModuleScript(scriptDirectory, jangarooApplicationWriter, jangarooApplicationAllWriter);

      jangarooApplicationWriter.write(JOO_FLUSH_STYLE_SHEETS);
      jangarooApplicationAllWriter.write(JOO_FLUSH_STYLE_SHEETS);
    } finally {
      try {
        jangarooApplicationWriter.close();
        jangarooApplicationAllWriter.close();
      } catch (IOException e) {
        getLog().warn("IOException on close ignored.", e);
      }
    }
  }

  protected void writeThisJangarooModuleScript(File scriptDirectory, Writer jangarooApplicationWriter, Writer jangarooApplicationAllWriter) throws IOException {
    ModuleSource jooModuleSource = null;
    File packageSourceDirectory = getPackageSourceDirectory();
    if (packageSourceDirectory != null) {
      File jangarooModuleFile = new File(packageSourceDirectory, computeModuleJsFileName(project.getArtifactId()));
      if (jangarooModuleFile.exists()) {
        jooModuleSource = new FileModuleSource(jangarooModuleFile);
      }
    }
    writeJangarooModuleScript(scriptDirectory, project.getArtifact(), jooModuleSource, jangarooApplicationWriter, jangarooApplicationAllWriter);
  }

  private static String computeModuleJsFileName(String artifactId) {
    return "META-INF/resources/joo/" + artifactId + ".module.js";
  }

  private Writer createJangarooModulesFile(File scriptDirectory, String fileName) throws IOException {
    //noinspection ResultOfMethodCallIgnored
    if (scriptDirectory.mkdirs()) {
      getLog().debug("created script output directory " + scriptDirectory);
    }
    File f = new File(scriptDirectory, fileName);
    getLog().info("Creating Jangaroo application script '" + f.getAbsolutePath() + "'.");
    return new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
  }

  private void includeJangarooModuleScript(File scriptDirectory, Artifact artifact, Writer jangarooApplicationWriter, Writer jangarooApplicationAllWriter) throws IOException {
    ZipFile zipFile = new ZipFile(artifact.getFile());
    ZipEntry zipEntry = zipFile.getEntry(computeModuleJsFileName(artifact.getArtifactId()));
    ModuleSource jooModuleSource = zipEntry != null ? new ZipEntryModuleSource(zipFile, zipEntry) : null;
    writeJangarooModuleScript(scriptDirectory, artifact, jooModuleSource, jangarooApplicationWriter, jangarooApplicationAllWriter);
  }

  private static final Pattern LOAD_SCRIPT_CODE_PATTERN = Pattern.compile("\\s*joo\\.loadScript\\(['\"]([^'\"]+)['\"]\\s*[,)].*");
  private static final Pattern LOAD_MODULE_CODE_PATTERN = Pattern.compile("\\s*joo\\.loadModule\\(['\"]([^'\"]+)['\"]\\s*,\\s*['\"]([^'\"]+)['\"].*");

  private static String fromArtifactMessage(Artifact artifact) {
    return fromArtifactMessage(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion());
  }

  private static String fromArtifactMessage(String groupId, String artifactId, String version) {
    return "// FROM " + fullArtifactName(groupId, artifactId, version) + ":\n";
  }

  private static String fullArtifactName(Artifact artifact) {
    return fullArtifactName(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion());
  }

  private static String fullArtifactName(String groupId, String artifactId, String version) {
    return String.format("%s:%s:%s", groupId, artifactId, version);
  }

  private void writeJangarooModuleScript(File scriptDirectory, Artifact artifact, ModuleSource jooModuleSource, Writer jangarooApplicationWriter, Writer jangarooApplicationAllWriter) throws IOException {
    String fullArtifactName = fullArtifactName(artifact);
    if (jooModuleSource == null) {
      getLog().debug("No " + artifact.getArtifactId() + ".module.js in " + fullArtifactName + ".");
      writeModule(scriptDirectory, artifact, jangarooApplicationWriter, jangarooApplicationAllWriter);
    } else {
      getLog().info("Appending " + artifact.getArtifactId() + ".module.js from " + fullArtifactName);
      String fromMessage = fromArtifactMessage(artifact);
      jangarooApplicationWriter.write(fromMessage);
      appendFromInputStream(jangarooApplicationWriter, jooModuleSource.getInputStream());
      jangarooApplicationAllWriter.write(fromMessage);
      writeModuleWithInlineScripts(scriptDirectory, jooModuleSource, jangarooApplicationAllWriter);
    }
  }

  private void writeModuleWithInlineScripts(File scriptDirectory, ModuleSource jooModuleSource, Writer jangarooApplicationAllWriter) throws IOException {
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(jooModuleSource.getInputStream(), "UTF-8"));
    while (true) {
      String line = bufferedReader.readLine();
      if (line == null) {
        break;
      }
      String scriptFilename = null;
      Matcher loadModuleMatcher = LOAD_MODULE_CODE_PATTERN.matcher(line);
      if (loadModuleMatcher.matches()) {
        String groupId = loadModuleMatcher.group(1);
        String artifactId = loadModuleMatcher.group(2);
        scriptFilename = "joo/" + groupId + "." + artifactId + ".classes.js";
        getLog().debug(" found loadModule: " + groupId + " / " + artifactId);
      } else {
        Matcher loadScriptMatcher = LOAD_SCRIPT_CODE_PATTERN.matcher(line);
        if (loadScriptMatcher.matches()) {
          scriptFilename = loadScriptMatcher.group(1);
          getLog().debug(" found loadScript: " + scriptFilename);
        }
      }
      File scriptFile = null;
      if (scriptFilename != null) {
        scriptFile = new File(scriptDirectory.getParent(), scriptFilename);
        if (!scriptFile.exists()) {
          scriptFile = null;
        }
      }
      if (scriptFile == null) {
        jangarooApplicationAllWriter.write(line + '\n');
      } else {
        appendFile(jangarooApplicationAllWriter, scriptFile);
      }
    }
  }

  private void writeModule(File scriptDirectory, Artifact artifact, Writer jangarooApplicationWriter, Writer jangarooApplicationAllWriter) throws IOException {
    writeModule(scriptDirectory, artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(),
      jangarooApplicationWriter, jangarooApplicationAllWriter);
  }

  protected void writeModule(File scriptDirectory, String groupId, String artifactId, String version, Writer jangarooApplicationWriter, Writer jangarooApplicationAllWriter) throws IOException {
    File classesJsFile = new File(scriptDirectory, groupId + "." + artifactId + ".classes.js");
    if (classesJsFile.exists()) {
      getLog().debug("Creating joo.loadModule(...) code for / appending .classes.js of " + fullArtifactName(groupId, artifactId, version) + ".");
      jangarooApplicationWriter.write(fromArtifactMessage(groupId, artifactId, version));
      jangarooApplicationWriter.write("joo.loadModule(\"" + groupId + "\",\"" + artifactId + "\");\n");
      jangarooApplicationAllWriter.write(fromArtifactMessage(groupId, artifactId, version));
      appendFile(jangarooApplicationAllWriter, classesJsFile);
    } else {
      getLog().debug("No file " + classesJsFile.getAbsolutePath() + " in module " + fullArtifactName(groupId, artifactId, version) +".");
    }
  }

  private void appendFile(Writer writer, File file) throws IOException {
    appendFromInputStream(writer, new BOMStripperInputStream(new FileInputStream(file)));
  }

  private void appendFromInputStream(Writer writer, InputStream inputStream) throws IOException {
    IOUtil.copy(inputStream, writer, "UTF-8");
    writer.write('\n'); // file might not end with new-line, better insert one
  }

  private Map<String, Artifact> artifactByInternalId() {
    final Map<String, Artifact> internalId2Artifact = new HashMap<String, Artifact>();
    for (Artifact artifact : getArtifacts()) {
      if ("jar".equals(artifact.getType())) {
        String internalId = getInternalId(artifact);
        internalId2Artifact.put(internalId, artifact);
      }
    }
    return internalId2Artifact;
  }

  private List<String> getDependencies(Artifact artifact) throws ProjectBuildingException {
    MavenProject mp = mavenProjectBuilder.buildFromRepository(artifact, remoteRepositories, localRepository, true);
    List<String> deps = new LinkedList<String>();
    for (Dependency dep : getDependencies(mp)) {
      if ("jar".equals(dep.getType()) &&
        (dep.getScope().equals("compile") || dep.getScope().equals("runtime"))) {
        deps.add(getInternalId(dep));
      }
    }
    return deps;
  }

  @SuppressWarnings({ "unchecked" })
  private static List<Dependency> getDependencies(MavenProject mp) {
    return (List<Dependency>) mp.getDependencies();
  }

  @SuppressWarnings({ "unchecked" })
  protected Set<Artifact> getArtifacts() {
    return (Set<Artifact>)project.getArtifacts();
  }

  private static interface ModuleSource {
    InputStream getInputStream() throws IOException;
  }

  private static class FileModuleSource implements ModuleSource {
    private final File file;

    private FileModuleSource(File file) {
      this.file = file;
    }

    @Override
    public InputStream getInputStream() throws IOException {
      return new BOMStripperInputStream(new FileInputStream(file));
    }
  }

  private static class ZipEntryModuleSource implements ModuleSource {
    private final ZipFile zipFile;
    private final ZipEntry zipEntry;

    private ZipEntryModuleSource(ZipFile zipFile, ZipEntry zipEntry) {
      this.zipFile = zipFile;
      this.zipEntry = zipEntry;
    }

    @Override
    public InputStream getInputStream() throws IOException {
      return new BOMStripperInputStream(zipFile.getInputStream(zipEntry));
    }
  }
}
TOP

Related Classes of net.jangaroo.jooc.mvnplugin.PackageApplicationMojo$ZipEntryModuleSource

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.