All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.wcm.maven.plugins.contentpackage.unpacker.ContentUnpacker Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
/*
 * #%L
 * wcm.io
 * %%
 * Copyright (C) 2014 wcm.io
 * %%
 * 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.
 * #L%
 */
package io.wcm.maven.plugins.contentpackage.unpacker;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.LineSeparator;
import org.jdom2.output.XMLOutputter;

/**
 * Manages unpacking ZIP file content applying exclude patterns.
 */
public class ContentUnpacker {

  private final Pattern[] excludeFiles;
  private final Pattern[] excludeNodes;
  private final Pattern[] excludeProperties;

  /**
   * @param excludeFiles Exclude files
   * @param excludeNodes Exclude nodes
   * @param excludeProperties Exclude properties
   * @throws MojoFailureException
   */
  public ContentUnpacker(String[] excludeFiles, String[] excludeNodes, String[] excludeProperties) throws MojoFailureException {
    this.excludeFiles = toPatternArray(excludeFiles);
    this.excludeNodes = toPatternArray(excludeNodes);
    this.excludeProperties = toPatternArray(excludeProperties);
  }

  private static Pattern[] toPatternArray(String[] patternStrings) throws MojoFailureException {
    if (patternStrings == null) {
      return new Pattern[0];
    }
    Pattern[] patterns = new Pattern[patternStrings.length];
    for (int i = 0; i < patternStrings.length; i++) {
      try {
        patterns[i] = Pattern.compile(patternStrings[i]);
      }
      catch (PatternSyntaxException ex) {
        throw new MojoFailureException("Invalid regexp pattern: " + patternStrings[i], ex);
      }
    }
    return patterns;
  }

  private static boolean exclude(String name, Pattern[] patterns) {
    for (Pattern pattern : patterns) {
      if (pattern.matcher(name).matches()) {
        return true;
      }
    }
    return false;
  }

  private boolean applyXmlExcludes(String name) {
    if (this.excludeNodes.length == 0 & this.excludeProperties.length == 0) {
      return false;
    }
    return StringUtils.endsWith(name, "/.content.xml");
  }

  /**
   * Unpacks file
   * @param file File
   * @param outputDirectory Output directory
   * @throws MojoExecutionException
   */
  public void unpack(File file, File outputDirectory) throws MojoExecutionException {
    ZipFile zipFile = null;
    try {
      zipFile = new ZipFile(file);
      Enumeration entries = zipFile.getEntries();
      while (entries.hasMoreElements()) {
        ZipArchiveEntry entry = entries.nextElement();
        if (!exclude(entry.getName(), excludeFiles)) {
          unpackEntry(zipFile, entry, outputDirectory);
        }
      }
    }
    catch (IOException ex) {
      throw new MojoExecutionException("Error reading content package " + file.getAbsolutePath(), ex);
    }
    finally {
      IOUtils.closeQuietly(zipFile);
    }
  }

  private void unpackEntry(ZipFile zipFile, ZipArchiveEntry entry, File outputDirectory)
      throws IOException, MojoExecutionException {
    if (entry.isDirectory()) {
      File directory = FileUtils.getFile(outputDirectory, entry.getName());
      directory.mkdirs();
    }
    else {
      InputStream entryStream = null;
      FileOutputStream fos = null;
      try {
        entryStream = zipFile.getInputStream(entry);
        File outputFile = FileUtils.getFile(outputDirectory, entry.getName());
        if (outputFile.exists()) {
          outputFile.delete();
        }
        File directory = outputFile.getParentFile();
        directory.mkdirs();
        fos = new FileOutputStream(outputFile);
        if (applyXmlExcludes(entry.getName())) {
          // write file with XML filtering
          try {
            writeXmlWithExcludes(entryStream, fos);
          }
          catch (JDOMException ex) {
            throw new MojoExecutionException("Unable to parse XML file: " + entry.getName(), ex);
          }
        }
        else {
          // write file directly without XML filtering
          IOUtils.copy(entryStream, fos);
        }
      }
      finally {
        IOUtils.closeQuietly(entryStream);
        IOUtils.closeQuietly(fos);
      }
    }
  }

  private void writeXmlWithExcludes(InputStream inputStream, OutputStream outputStream)
      throws IOException, JDOMException {
    SAXBuilder saxBuilder = new SAXBuilder();
    Document doc = saxBuilder.build(inputStream);
    applyXmlExcludes(doc.getRootElement(), "");

    XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat()
        .setLineSeparator(LineSeparator.UNIX));
    outputter.setXMLOutputProcessor(new OneAttributePerLineXmlProcessor());
    outputter.output(doc, outputStream);
    outputStream.flush();
  }

  private void applyXmlExcludes(Element element, String parentPath) {
    String path = parentPath + "/" + element.getName();
    if (exclude(path, this.excludeNodes)) {
      element.detach();
      return;
    }
    List attributes = new ArrayList<>(element.getAttributes());
    for (Attribute attribute : attributes) {
      if (exclude(attribute.getQualifiedName(), this.excludeProperties)) {
        attribute.detach();
      }
    }
    List children = new ArrayList<>(element.getChildren());
    for (Element child : children) {
      applyXmlExcludes(child, path);
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy