Skip to content

Commit 8356bf6

Browse files
Merge pull request #393 from paul-nelson-baker/master
Migrating Maven transformer to Gradle.
2 parents cc58162 + b4b9ff2 commit 8356bf6

File tree

3 files changed

+204
-0
lines changed

3 files changed

+204
-0
lines changed

gradle/dependencies.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dependencies {
1010
compile 'commons-io:commons-io:2.5'
1111
compile 'org.apache.ant:ant:1.9.7'
1212
compile 'org.codehaus.plexus:plexus-utils:3.0.24'
13+
compile "org.apache.logging.log4j:log4j-core:2.11.0"
1314

1415
testCompile("org.spockframework:spock-core:1.0-groovy-2.4") {
1516
exclude module: 'groovy-all'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
20+
package com.github.jengelman.gradle.plugins.shadow.transformers
21+
22+
import com.github.jengelman.gradle.plugins.shadow.ShadowStats
23+
import com.github.jengelman.gradle.plugins.shadow.relocation.RelocateClassContext
24+
import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator
25+
import org.apache.commons.io.IOUtils
26+
import org.apache.commons.io.output.CloseShieldOutputStream
27+
import org.apache.logging.log4j.core.config.plugins.processor.PluginCache
28+
import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry
29+
import org.apache.tools.zip.ZipEntry
30+
import org.apache.tools.zip.ZipOutputStream
31+
import org.gradle.api.file.FileTreeElement
32+
33+
import static org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE;
34+
35+
/**
36+
* Modified from the maven equivalent to work with gradle
37+
*
38+
* @author Paul Nelson Baker
39+
* @see <a href="https://www.linkedin.com/in/paul-n-baker/">LinkedIn</a>
40+
* @see <a href="https://github.com/paul-nelson-baker/">GitHub</a>
41+
* @see <a href="https://github.com/edwgiz/maven-shaded-log4j-transformer">edwgiz/maven-shaded-log4j-transformer</a>
42+
* @see <a href="https://github.com/edwgiz/maven-shaded-log4j-transformer/blob/master/src/main/java/com/github/edwgiz/mavenShadePlugin/log4j2CacheTransformer/PluginsCacheFileTransformer.java">PluginsCacheFileTransformer.java</a>
43+
*/
44+
class Log4j2PluginsCacheFileTransformer implements Transformer {
45+
46+
private final List<File> temporaryFiles;
47+
private final List<Relocator> relocators;
48+
49+
public Log4j2PluginsCacheFileTransformer() {
50+
temporaryFiles = new ArrayList<>();
51+
relocators = new ArrayList<>();
52+
}
53+
54+
@Override
55+
boolean canTransformResource(FileTreeElement element) {
56+
return PLUGIN_CACHE_FILE == element.name
57+
}
58+
59+
@Override
60+
void transform(TransformerContext context) {
61+
def inputStream = context.is
62+
def temporaryFile = File.createTempFile("Log4j2Plugins", ".dat")
63+
temporaryFile.deleteOnExit()
64+
temporaryFiles.add(temporaryFile)
65+
IOUtils.copy(inputStream, new FileOutputStream(temporaryFile))
66+
def contextRelocators = context.relocators
67+
if (contextRelocators != null) {
68+
this.relocators.addAll(contextRelocators)
69+
}
70+
}
71+
72+
@Override
73+
boolean hasTransformedResource() {
74+
// This functionality matches the original plugin, however, I'm not clear what
75+
// the exact logic is. From what I can tell temporaryFiles should be never be empty
76+
// if anything has been performed.
77+
def hasTransformedMultipleFiles = temporaryFiles.size() > 1
78+
def hasAtLeastOneFileAndRelocator = !temporaryFiles.isEmpty() && !relocators.isEmpty()
79+
def hasTransformedResources = hasTransformedMultipleFiles || hasAtLeastOneFileAndRelocator
80+
return hasTransformedResources
81+
}
82+
83+
@Override
84+
void modifyOutputStream(ZipOutputStream zipOutputStream) {
85+
PluginCache pluginCache = new PluginCache()
86+
pluginCache.loadCacheFiles(getUrlEnumeration())
87+
relocatePlugins(pluginCache)
88+
zipOutputStream.putNextEntry(new ZipEntry(PLUGIN_CACHE_FILE))
89+
pluginCache.writeCache(new CloseShieldOutputStream(zipOutputStream))
90+
temporaryFiles.clear()
91+
}
92+
93+
private Enumeration<URL> getUrlEnumeration() {
94+
def urls = temporaryFiles.collect({ it.toURL() }).asList()
95+
return Collections.enumeration(urls)
96+
}
97+
98+
private void relocatePlugins(PluginCache pluginCache) {
99+
for (Map<String, PluginEntry> currentMap : pluginCache.getAllCategories().values()) {
100+
pluginEntryLoop:
101+
for (PluginEntry currentPluginEntry : currentMap.values()) {
102+
String className = currentPluginEntry.getClassName();
103+
RelocateClassContext relocateClassContext = new RelocateClassContext(className, new ShadowStats());
104+
for (Relocator currentRelocator : relocators) {
105+
// If we have a relocator that can relocate our current entry...
106+
boolean canRelocateClass = currentRelocator.canRelocateClass(relocateClassContext);
107+
if (canRelocateClass) {
108+
// Then we perform that relocation and update the plugin entry to reflect the new value.
109+
String relocatedClassName = currentRelocator.relocateClass(relocateClassContext);
110+
currentPluginEntry.setClassName(relocatedClassName);
111+
continue pluginEntryLoop;
112+
}
113+
}
114+
}
115+
}
116+
}
117+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.github.jengelman.gradle.plugins.shadow.transformers
2+
3+
import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator
4+
import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator
5+
import org.apache.tools.zip.ZipOutputStream
6+
import org.junit.Before
7+
import org.junit.Test
8+
9+
import java.util.zip.ZipEntry
10+
import java.util.zip.ZipFile
11+
12+
import static java.util.Collections.singletonList
13+
import static org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE
14+
import static org.junit.Assert.assertFalse
15+
import static org.junit.Assert.assertTrue
16+
17+
/**
18+
* @author Paul Nelson Baker
19+
* @since 2018-08
20+
* @see <a href="https://github.com/paul-nelson-baker/">GitHub</a>
21+
* @see <a href="https://www.linkedin.com/in/paul-n-baker/">LinkedIn</a>
22+
*/
23+
//@RunWith(Parameterized.class)
24+
class Log4j2PluginsCacheFileTransformerTest {
25+
26+
Log4j2PluginsCacheFileTransformer transformer
27+
28+
@Before
29+
void setUp() {
30+
transformer = new Log4j2PluginsCacheFileTransformer()
31+
}
32+
33+
@Test
34+
void testShouldNotTransform() {
35+
transformer.transform(new TransformerContext(PLUGIN_CACHE_FILE, getResourceStream(PLUGIN_CACHE_FILE), null))
36+
assertFalse(transformer.hasTransformedResource())
37+
}
38+
39+
@Test
40+
void testShouldTransform() {
41+
List<Relocator> relocators = new ArrayList<>()
42+
relocators.add(new SimpleRelocator(null, null, null, null))
43+
transformer.transform(new TransformerContext(PLUGIN_CACHE_FILE, getResourceStream(PLUGIN_CACHE_FILE), relocators))
44+
assertTrue(transformer.hasTransformedResource())
45+
}
46+
47+
@Test
48+
void testRelocators() {
49+
testRelocate("org.apache.logging", "new.location.org.apache.logging", "new.location.org.apache.logging")
50+
testRelocate("org.apache.logging", "new.location.org.apache.logging", "org.apache.logging")
51+
}
52+
53+
void testRelocate(String source, String pattern, String target) throws IOException {
54+
List<Relocator> relocators = singletonList((Relocator) new SimpleRelocator(source, pattern, null, null))
55+
transformer.transform(new TransformerContext(PLUGIN_CACHE_FILE, getResourceStream(PLUGIN_CACHE_FILE), relocators))
56+
assertTrue("Transformer didn't transform resources", transformer.hasTransformedResource())
57+
// Write out to a fake jar file
58+
def testableZipFile = File.createTempFile("testable-zip-file-", ".jar")
59+
def fileOutputStream = new FileOutputStream(testableZipFile)
60+
def bufferedOutputStream = new BufferedOutputStream(fileOutputStream)
61+
def zipOutputStream = new ZipOutputStream(bufferedOutputStream)
62+
transformer.modifyOutputStream(zipOutputStream)
63+
zipOutputStream.close()
64+
bufferedOutputStream.close()
65+
fileOutputStream.close()
66+
// Pull the data back out and make sure it was transformed
67+
ZipFile zipFile = new ZipFile(testableZipFile)
68+
ZipEntry zipFileEntry = zipFile.getEntry(PLUGIN_CACHE_FILE)
69+
InputStream inputStream = zipFile.getInputStream(zipFileEntry)
70+
new Scanner(inputStream).withCloseable { scanner ->
71+
boolean hasAtLeastOneTransform = false
72+
while (scanner.hasNextLine()) {
73+
String nextLine = scanner.nextLine()
74+
if (nextLine.contains(source)) {
75+
hasAtLeastOneTransform = true
76+
assertTrue("Target wasn't included in transform", nextLine.contains(target))
77+
}
78+
}
79+
assertTrue("There were no transformations inside the file", hasAtLeastOneTransform)
80+
}
81+
}
82+
83+
InputStream getResourceStream(String resource) {
84+
return this.class.getClassLoader().getResourceAsStream(resource);
85+
}
86+
}

0 commit comments

Comments
 (0)