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.shade.resource;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Properties;
29  import java.util.jar.JarEntry;
30  import java.util.jar.JarOutputStream;
31  
32  import org.apache.maven.plugins.shade.relocation.Relocator;
33  
34  /**
35   * Aggregate Apache Groovy extension modules descriptors
36   */
37  public class GroovyResourceTransformer extends AbstractCompatibilityTransformer {
38  
39      static final String EXT_MODULE_NAME_LEGACY = "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule";
40  
41      // Since Groovy 2.5.x/Java 9 META-INF/services may only be used by Service Providers
42      static final String EXT_MODULE_NAME = "META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule";
43  
44      private List<String> extensionClassesList = new ArrayList<>();
45  
46      private List<String> staticExtensionClassesList = new ArrayList<>();
47  
48      private String extModuleName = "no-module-name";
49  
50      private String extModuleVersion = "1.0";
51  
52      private long time = Long.MIN_VALUE;
53  
54      @Override
55      public boolean canTransformResource(String resource) {
56          return EXT_MODULE_NAME.equals(resource) || EXT_MODULE_NAME_LEGACY.equals(resource);
57      }
58  
59      @Override
60      public void processResource(String resource, InputStream is, List<Relocator> relocators, long time)
61              throws IOException {
62          Properties out = new Properties();
63          try (InputStream props = is) {
64              out.load(props);
65          }
66          String extensionClasses = out.getProperty("extensionClasses", "").trim();
67          if (extensionClasses.length() > 0) {
68              append(extensionClasses, extensionClassesList);
69          }
70          String staticExtensionClasses =
71                  out.getProperty("staticExtensionClasses", "").trim();
72          if (staticExtensionClasses.length() > 0) {
73              append(staticExtensionClasses, staticExtensionClassesList);
74          }
75          if (time > this.time) {
76              this.time = time;
77          }
78      }
79  
80      private void append(String entry, List<String> list) {
81          if (entry != null) {
82              Collections.addAll(list, entry.split("\\s*,\\s*"));
83          }
84      }
85  
86      @Override
87      public boolean hasTransformedResource() {
88          return extensionClassesList.size() > 0 && staticExtensionClassesList.size() > 0;
89      }
90  
91      @Override
92      public void modifyOutputStream(JarOutputStream os) throws IOException {
93          if (hasTransformedResource()) {
94              JarEntry jarEntry = new JarEntry(EXT_MODULE_NAME);
95              jarEntry.setTime(time);
96              os.putNextEntry(jarEntry);
97  
98              Properties desc = new Properties();
99              desc.put("moduleName", extModuleName);
100             desc.put("moduleVersion", extModuleVersion);
101             if (extensionClassesList.size() > 0) {
102                 desc.put("extensionClasses", join(extensionClassesList));
103             }
104             if (staticExtensionClassesList.size() > 0) {
105                 desc.put("staticExtensionClasses", join(staticExtensionClassesList));
106             }
107             desc.store(os, null);
108         }
109     }
110 
111     private String join(Collection<String> strings) {
112         Iterator<String> it = strings.iterator();
113         switch (strings.size()) {
114             case 0:
115                 return "";
116             case 1:
117                 return it.next();
118             default:
119                 StringBuilder buff = new StringBuilder(it.next());
120                 while (it.hasNext()) {
121                     buff.append(",").append(it.next());
122                 }
123                 return buff.toString();
124         }
125     }
126 
127     public void setExtModuleName(String extModuleName) {
128         this.extModuleName = extModuleName;
129     }
130 
131     public void setExtModuleVersion(String extModuleVersion) {
132         this.extModuleVersion = extModuleVersion;
133     }
134 }