Skip to content

Commit 553ecf1

Browse files
committed
added debloat goal
1 parent c8293f0 commit 553ecf1

File tree

9 files changed

+435
-2
lines changed

9 files changed

+435
-2
lines changed

lang-java/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@
7575
<groupId>commons-io</groupId>
7676
<artifactId>commons-io</artifactId>
7777
</dependency>
78+
<!-- Required by steady:debloat -->
79+
<dependency>
80+
<groupId>org.vafer</groupId>
81+
<artifactId>jdependency</artifactId>
82+
<version>2.7.0</version>
83+
</dependency>
7884

7985
<!-- Test dependencies -->
8086
<dependency>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/**
2+
* This file is part of Eclipse Steady.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
* SPDX-FileCopyrightText: Copyright (c) 2018-2020 SAP SE or an SAP affiliate company and Eclipse Steady contributors
18+
*/
19+
package org.eclipse.steady.java.tasks;
20+
21+
import java.io.FileWriter;
22+
import java.io.IOException;
23+
import java.nio.file.Path;
24+
import java.nio.file.Paths;
25+
import java.util.ArrayList;
26+
import java.util.Arrays;
27+
import java.util.HashMap;
28+
import java.util.HashSet;
29+
import java.util.List;
30+
import java.util.Map;
31+
import java.util.Set;
32+
33+
import org.apache.logging.log4j.Logger;
34+
import org.eclipse.steady.Construct;
35+
import org.eclipse.steady.core.util.CoreConfiguration;
36+
import org.eclipse.steady.goals.GoalConfigurationException;
37+
import org.eclipse.steady.goals.GoalExecutionException;
38+
import org.eclipse.steady.java.JarAnalyzer;
39+
import org.eclipse.steady.shared.enums.GoalClient;
40+
import org.eclipse.steady.shared.enums.ProgrammingLanguage;
41+
import org.eclipse.steady.shared.util.StringList;
42+
import org.eclipse.steady.shared.util.StringUtil;
43+
import org.eclipse.steady.shared.util.VulasConfiguration;
44+
import org.eclipse.steady.tasks.AbstractTask;
45+
import org.eclipse.steady.tasks.DebloatTask;
46+
import org.vafer.jdependency.Clazz;
47+
import org.vafer.jdependency.Clazzpath;
48+
import org.vafer.jdependency.ClazzpathUnit;
49+
50+
/**
51+
* <p>JavaBomTask class.</p>
52+
*/
53+
public class JavaDebloatTask extends AbstractTask implements DebloatTask {
54+
55+
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger();
56+
57+
private static final String[] EXT_FILTER = new String[] {"jar", "war", "class", "java", "aar"};
58+
59+
private String[] appPrefixes = null;
60+
61+
private StringList appJarNames = null;
62+
63+
private static final List<GoalClient> pluginGoalClients =
64+
Arrays.asList(GoalClient.MAVEN_PLUGIN, GoalClient.GRADLE_PLUGIN);
65+
66+
/** {@inheritDoc} */
67+
@Override
68+
public Set<ProgrammingLanguage> getLanguage() {
69+
return new HashSet<ProgrammingLanguage>(
70+
Arrays.asList(new ProgrammingLanguage[] {ProgrammingLanguage.JAVA}));
71+
}
72+
73+
/**
74+
* Returns true if the configuration setting {@link CoreConfiguration#APP_PREFIXES} shall be considered, false otherwise.
75+
*/
76+
private final boolean useAppPrefixes() {
77+
return this.appPrefixes != null && !this.isOneOfGoalClients(pluginGoalClients);
78+
}
79+
80+
/**
81+
* Returns true if the configuration setting {@link CoreConfiguration#APP_PREFIXES} shall be considered, false otherwise.
82+
*/
83+
private final boolean useAppJarNames() {
84+
return this.appJarNames != null && !this.isOneOfGoalClients(pluginGoalClients);
85+
}
86+
87+
/** {@inheritDoc} */
88+
@Override
89+
public void configure(VulasConfiguration _cfg) throws GoalConfigurationException {
90+
super.configure(_cfg);
91+
92+
// App constructs identified using package prefixes
93+
this.appPrefixes = _cfg.getStringArray(CoreConfiguration.APP_PREFIXES, null);
94+
95+
// Print warning message in case the setting is used as part of the Maven plugin
96+
if (this.appPrefixes != null && this.isOneOfGoalClients(pluginGoalClients)) {
97+
log.warn(
98+
"Configuration setting ["
99+
+ CoreConfiguration.APP_PREFIXES
100+
+ "] ignored when running the goal as Maven plugin");
101+
this.appPrefixes = null;
102+
}
103+
104+
// App constructs identified using JAR file name patterns (regex)
105+
final String[] app_jar_names = _cfg.getStringArray(CoreConfiguration.APP_JAR_NAMES, null);
106+
if (app_jar_names != null) {
107+
// Print warning message in case the setting is used as part of the Maven plugin
108+
if (this.isOneOfGoalClients(pluginGoalClients)) {
109+
log.warn(
110+
"Configuration setting ["
111+
+ CoreConfiguration.APP_JAR_NAMES
112+
+ "] ignored when running the goal as Maven plugin");
113+
this.appJarNames = null;
114+
} else {
115+
this.appJarNames = new StringList();
116+
this.appJarNames.addAll(app_jar_names);
117+
}
118+
}
119+
120+
// CLI: Only one of appPrefixes and appJarNames can be used
121+
if (!this.isOneOfGoalClients(pluginGoalClients)) {
122+
if (this.appPrefixes != null && this.appJarNames != null) {
123+
throw new GoalConfigurationException(
124+
"Exactly one of the configuration settings ["
125+
+ CoreConfiguration.APP_PREFIXES
126+
+ "] and ["
127+
+ CoreConfiguration.APP_JAR_NAMES
128+
+ "] must be set");
129+
} else if (this.appPrefixes == null && this.appJarNames == null) {
130+
throw new GoalConfigurationException(
131+
"Exactly one of the configuration settings ["
132+
+ CoreConfiguration.APP_PREFIXES
133+
+ "] and ["
134+
+ CoreConfiguration.APP_JAR_NAMES
135+
+ "] must be set");
136+
}
137+
}
138+
}
139+
140+
/** {@inheritDoc} */
141+
@Override
142+
public void execute() throws GoalExecutionException {
143+
144+
final Clazzpath cp = new Clazzpath();
145+
146+
List<ClazzpathUnit> app = new ArrayList<ClazzpathUnit>();
147+
try {
148+
//1) Add app paths
149+
if (this.hasSearchPath()) {
150+
for (Path p : this.getSearchPath()) {
151+
log.info(
152+
"Add app path ["
153+
+ p
154+
+ "] to classpath");
155+
app.add(cp.addClazzpathUnit(p));
156+
}
157+
}
158+
//2) Add dependencies to classpath
159+
if (this.getKnownDependencies() != null) {
160+
for (Path p : this.getKnownDependencies().keySet()) {
161+
log.info(
162+
"Add dep path ["
163+
+ p
164+
+ "] to classpath");
165+
cp.addClazzpathUnit(p);
166+
}
167+
}
168+
} catch (IOException e) {
169+
// TODO Auto-generated catch block
170+
e.printStackTrace();
171+
}
172+
173+
final Set<Clazz> needed = new HashSet<Clazz>();
174+
final Set<Clazz> removable = cp.getClazzes();
175+
for(ClazzpathUnit u: app) {
176+
removable.removeAll(u.getClazzes());
177+
removable.removeAll(u.getTransitiveDependencies());
178+
needed.addAll(u.getClazzes());
179+
needed.addAll(u.getTransitiveDependencies());
180+
}
181+
182+
log.info("Needed ["+ needed.size()+"] classes");
183+
log.info("Removable ["+ removable.size()+"] classes");
184+
for(Clazz clazz : removable) {
185+
System.out.println("class " + clazz + " is not required");
186+
}
187+
try {
188+
FileWriter writer=new FileWriter("needed.txt");
189+
for(Clazz c: needed) {
190+
writer.write(c + System.lineSeparator());
191+
}
192+
writer.close();
193+
} catch (IOException e){// TODO Auto-generated catch block
194+
e.printStackTrace();}
195+
}
196+
197+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.eclipse.steady.java.tasks.JavaDebloatTask

lang/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
<groupId>com.google.code.gson</groupId>
7979
<artifactId>gson</artifactId>
8080
</dependency>
81-
<!-- Required by vulas:report -->
81+
<!-- Required by steady:report -->
8282
<dependency>
8383
<groupId>org.apache.velocity</groupId>
8484
<artifactId>velocity-engine-core</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/**
2+
* This file is part of Eclipse Steady.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
* SPDX-FileCopyrightText: Copyright (c) 2018-2020 SAP SE or an SAP affiliate company and Eclipse Steady contributors
18+
*/
19+
package org.eclipse.steady.goals;
20+
21+
import java.nio.file.Paths;
22+
import java.util.ServiceLoader;
23+
import java.util.Set;
24+
25+
import org.apache.logging.log4j.Logger;
26+
import org.eclipse.steady.backend.BackendConnector;
27+
import org.eclipse.steady.core.util.CoreConfiguration;
28+
import org.eclipse.steady.malice.MaliciousnessAnalysisResult;
29+
import org.eclipse.steady.malice.MaliciousnessAnalyzerLoop;
30+
import org.eclipse.steady.shared.enums.GoalType;
31+
import org.eclipse.steady.shared.json.model.Application;
32+
import org.eclipse.steady.shared.json.model.Dependency;
33+
import org.eclipse.steady.shared.json.model.Library;
34+
import org.eclipse.steady.tasks.BomTask;
35+
import org.eclipse.steady.tasks.DebloatTask;
36+
37+
/**
38+
* <p>NeededGoal class.</p>
39+
*/
40+
public class DebloatGoal extends AbstractAppGoal {
41+
42+
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger();
43+
44+
/**
45+
* <p>Constructor for DebloatGoal.</p>
46+
*/
47+
public DebloatGoal() {
48+
super(GoalType.DEBLOAT);
49+
}
50+
51+
// /**
52+
// * {@inheritDoc}
53+
// *
54+
// * Evaluates the configuration setting {@link CoreConfiguration#APP_PREFIXES}.
55+
// */
56+
// @Override
57+
// protected void prepareExecution() throws GoalConfigurationException {
58+
// super.prepareExecution();
59+
// }
60+
61+
/** {@inheritDoc} */
62+
@Override
63+
protected void executeTasks() throws Exception {
64+
65+
// The application to be completed
66+
Application a = this.getApplicationContext();
67+
68+
// Create, configure and execute tasks
69+
final ServiceLoader<DebloatTask> loader = ServiceLoader.load(DebloatTask.class);
70+
for (DebloatTask t : loader) {
71+
try {
72+
// Configure
73+
t.setApplication(a);
74+
t.setSearchPaths(this.getAppPaths());
75+
t.setGoalClient(this.getGoalClient());
76+
t.setKnownDependencies(this.getKnownDependencies());
77+
t.configure(this.getConfiguration());
78+
79+
// Execute
80+
t.execute();
81+
t.cleanUp();
82+
// t.getNeededConstructs();
83+
} catch (Exception e) {
84+
log.error("Error running task " + t + ": " + e.getMessage(), e);
85+
}
86+
}
87+
88+
89+
// Upload libraries and binaries (if requested)
90+
if (a.getDependencies() != null) {
91+
for (Dependency dep : a.getDependencies()) {
92+
93+
94+
95+
// Upload lib
96+
final Library lib = dep.getLib();
97+
if (lib != null) {
98+
if (lib.hasValidDigest()) {
99+
BackendConnector.getInstance().uploadLibrary(this.getGoalContext(), lib);
100+
if (CoreConfiguration.isJarUploadEnabled(this.getGoalContext().getVulasConfiguration()))
101+
BackendConnector.getInstance()
102+
.uploadLibraryFile(lib.getDigest(), Paths.get(dep.getPath()));
103+
} else {
104+
log.error("Library of dependency [" + dep + "] has no valid digest");
105+
}
106+
} else {
107+
log.error("Dependency [" + dep + "] has no library");
108+
}
109+
}
110+
}
111+
112+
final boolean upload_empty =
113+
this.getConfiguration()
114+
.getConfiguration()
115+
.getBoolean(CoreConfiguration.APP_UPLOAD_EMPTY, false);
116+
final boolean app_exists_in_backend =
117+
BackendConnector.getInstance().isAppExisting(this.getGoalContext(), a);
118+
119+
// Upload if non-empty or already exists in backend or empty ones shall be uploaded
120+
if (!a.isEmpty() || app_exists_in_backend || upload_empty) {
121+
log.info(
122+
"Save app "
123+
+ a
124+
+ " with ["
125+
+ a.getDependencies().size()
126+
+ "] dependencies and ["
127+
+ a.getConstructs().size()
128+
+ "] constructs (uploadEmpty="
129+
+ upload_empty
130+
+ ")");
131+
BackendConnector.getInstance().uploadApp(this.getGoalContext(), a);
132+
} else {
133+
log.warn(
134+
"Skip save of empty app "
135+
+ this.getApplicationContext()
136+
+ " (uploadEmpty="
137+
+ upload_empty
138+
+ ", existsInBackend="
139+
+ app_exists_in_backend
140+
+ ")");
141+
this.skipGoalUpload();
142+
}
143+
}
144+
}

lang/src/main/java/org/eclipse/steady/goals/GoalFactory.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ public static AbstractGoal create(@NotNull GoalType _type)
117117
throw new IllegalStateException(
118118
"Cannot create instance of class [" + clazzname + "]: " + e.getMessage());
119119
}
120-
} else {
120+
} else if (_type.equals(GoalType.DEBLOAT)) {
121+
goal = new DebloatGoal();
122+
}else {
121123
throw new IllegalArgumentException("Goal [" + _type + "] is not supported");
122124
}
123125
return goal;

0 commit comments

Comments
 (0)