View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.assembly.filter;
20  
21  import javax.inject.Named;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.InputStreamReader;
26  import java.io.OutputStreamWriter;
27  import java.io.Reader;
28  import java.io.StringWriter;
29  import java.io.Writer;
30  import java.nio.charset.StandardCharsets;
31  import java.nio.file.Files;
32  import java.util.ArrayList;
33  import java.util.Collections;
34  import java.util.Date;
35  import java.util.List;
36  
37  import org.apache.commons.io.IOUtils;
38  import org.apache.maven.plugins.assembly.utils.AssemblyFileUtils;
39  import org.codehaus.plexus.archiver.Archiver;
40  import org.codehaus.plexus.archiver.ArchiverException;
41  import org.codehaus.plexus.archiver.UnArchiver;
42  import org.codehaus.plexus.components.io.fileselectors.FileInfo;
43  
44  /**
45   * <code>file-aggregator</code>: Generic aggregating handler, configured with filePattern and outputPath.
46   */
47  @Named("file-aggregator")
48  public class SimpleAggregatingDescriptorHandler implements ContainerDescriptorHandler {
49      // component configuration.
50  
51      @SuppressWarnings("FieldCanBeLocal")
52      private final String commentChars = "#";
53  
54      private final StringWriter aggregateWriter = new StringWriter();
55  
56      private final List<String> filenames = new ArrayList<>();
57  
58      // calculated, temporary values.
59  
60      private String filePattern;
61  
62      private String outputPath;
63  
64      private boolean overrideFilterAction;
65  
66      @Override
67      public void finalizeArchiveCreation(final Archiver archiver) {
68          checkConfig();
69  
70          if (outputPath.endsWith("/")) {
71              throw new ArchiverException("Cannot write aggregated properties to a directory. "
72                      + "You must specify a file name in the outputPath configuration for this"
73                      + " handler. (handler: " + getClass().getName());
74          }
75  
76          if (outputPath.startsWith("/")) {
77              outputPath = outputPath.substring(1);
78          }
79  
80          final File temp = writePropertiesFile();
81  
82          overrideFilterAction = true;
83  
84          archiver.addFile(temp, outputPath);
85  
86          overrideFilterAction = false;
87      }
88  
89      private File writePropertiesFile() {
90          File f;
91          try {
92              f = Files.createTempFile("maven-assembly-plugin", "tmp").toFile();
93              f.deleteOnExit();
94  
95              try (Writer writer = getWriter(f)) {
96                  writer.write(commentChars + " Aggregated on " + new Date() + " from: ");
97  
98                  for (final String filename : filenames) {
99                      writer.write("\n" + commentChars + " " + filename);
100                 }
101 
102                 writer.write("\n\n");
103                 writer.write(aggregateWriter.toString());
104             }
105         } catch (final IOException e) {
106             throw new ArchiverException(
107                     "Error adding aggregated properties to finalize archive creation. Reason: " + e.getMessage(), e);
108         }
109 
110         return f;
111     }
112 
113     private Writer getWriter(File f) throws IOException {
114         Writer writer;
115         writer = AssemblyFileUtils.isPropertyFile(f)
116                 ? new OutputStreamWriter(Files.newOutputStream(f.toPath()), StandardCharsets.ISO_8859_1)
117                 : new OutputStreamWriter(Files.newOutputStream(f.toPath())); // Still platform encoding
118         return writer;
119     }
120 
121     @Override
122     public void finalizeArchiveExtraction(final UnArchiver unarchiver) {}
123 
124     @Override
125     public List<String> getVirtualFiles() {
126         checkConfig();
127 
128         return Collections.singletonList(outputPath);
129     }
130 
131     @Override
132     public boolean isSelected(final FileInfo fileInfo) throws IOException {
133         checkConfig();
134 
135         if (overrideFilterAction) {
136             return true;
137         }
138 
139         String name = AssemblyFileUtils.normalizeFileInfo(fileInfo);
140 
141         if (fileInfo.isFile() && name.matches(filePattern)) {
142             readProperties(fileInfo);
143             filenames.add(name);
144 
145             return false;
146         }
147 
148         return true;
149     }
150 
151     private void checkConfig() {
152         if (filePattern == null || outputPath == null) {
153             throw new IllegalStateException(
154                     "You must configure filePattern and outputPath in your containerDescriptorHandler declaration.");
155         }
156     }
157 
158     private void readProperties(final FileInfo fileInfo) throws IOException {
159         try (StringWriter writer = new StringWriter();
160                 Reader reader = AssemblyFileUtils.isPropertyFile(fileInfo.getName())
161                         ? new InputStreamReader(fileInfo.getContents(), StandardCharsets.ISO_8859_1)
162                         : new InputStreamReader(fileInfo.getContents())) // platform encoding
163         {
164             IOUtils.copy(reader, writer);
165             final String content = writer.toString();
166             aggregateWriter.write("\n");
167             aggregateWriter.write(content);
168         }
169     }
170 
171     @SuppressWarnings("UnusedDeclaration")
172     public String getFilePattern() {
173         return filePattern;
174     }
175 
176     @SuppressWarnings("UnusedDeclaration")
177     public void setFilePattern(final String filePattern) {
178         this.filePattern = filePattern;
179     }
180 
181     @SuppressWarnings("UnusedDeclaration")
182     public String getOutputPath() {
183         return outputPath;
184     }
185 
186     @SuppressWarnings("UnusedDeclaration")
187     public void setOutputPath(final String outputPath) {
188         this.outputPath = outputPath;
189     }
190 }