1 package com.atlassian.plugin.osgi.container.felix;
2
3 import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
4 import com.atlassian.plugin.osgi.container.PackageScannerConfiguration;
5 import com.atlassian.plugin.osgi.util.OsgiHeaderUtil;
6 import com.atlassian.plugin.util.ClassLoaderUtils;
7
8 import java.util.List;
9 import java.util.Collection;
10 import java.util.Iterator;
11 import java.util.jar.Manifest;
12 import java.io.*;
13 import java.net.MalformedURLException;
14
15 import org.twdata.pkgscanner.ExportPackage;
16 import org.twdata.pkgscanner.PackageScanner;
17 import static org.twdata.pkgscanner.PackageScanner.jars;
18 import static org.twdata.pkgscanner.PackageScanner.include;
19 import static org.twdata.pkgscanner.PackageScanner.exclude;
20 import static org.twdata.pkgscanner.PackageScanner.packages;
21 import org.osgi.framework.Constants;
22 import org.osgi.framework.Version;
23 import org.apache.commons.io.IOUtils;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import aQute.lib.osgi.Analyzer;
27 import aQute.lib.osgi.Jar;
28
29 import javax.servlet.ServletContext;
30
31
32
33
34 class ExportsBuilder
35 {
36
37 static final String JDK_PACKAGES_PATH = "jdk-packages.txt";
38 static final String JDK6_PACKAGES_PATH = "jdk6-packages.txt";
39 private static Log log = LogFactory.getLog(ExportsBuilder.class);
40 private static final String EXPORTS_TXT = "exports.txt";
41 private static String exportStringCache;
42
43
44
45
46
47
48
49
50
51
52
53
54 public String getExports(List<HostComponentRegistration> regs, PackageScannerConfiguration packageScannerConfig) {
55 if (exportStringCache == null)
56 {
57 exportStringCache = determineExports(regs, packageScannerConfig);
58 }
59 return exportStringCache;
60 }
61
62
63
64
65
66
67
68
69
70
71 @SuppressWarnings ({ "UnusedDeclaration" })
72 public String determineExports(List<HostComponentRegistration> regs, PackageScannerConfiguration packageScannerConfig, File cacheDir){
73 return determineExports(regs, packageScannerConfig);
74 }
75
76
77
78
79
80
81
82
83 private String determineExports(List<HostComponentRegistration> regs, PackageScannerConfiguration packageScannerConfig){
84
85 String exports = null;
86
87 StringBuilder origExports = new StringBuilder();
88 origExports.append("org.osgi.framework; version=1.4.1,");
89 origExports.append("org.osgi.service.packageadmin; version=1.2.0," );
90 origExports.append("org.osgi.service.startlevel; version=1.1.0,");
91 origExports.append("org.osgi.service.url; version=1.0.0,");
92 origExports.append("org.osgi.util; version=1.4.1,");
93 origExports.append("org.osgi.util.tracker; version=1.4.1,");
94 origExports.append("host.service.command; version=1.0.0,");
95
96 constructJdkExports(origExports, JDK_PACKAGES_PATH);
97 origExports.append(",");
98
99 if (System.getProperty("java.specification.version").equals("1.6")) {
100 constructJdkExports(origExports, JDK6_PACKAGES_PATH);
101 origExports.append(",");
102 }
103
104 Collection<ExportPackage> exportList = generateExports(packageScannerConfig);
105 constructAutoExports(origExports, exportList);
106
107
108 try
109 {
110 origExports.append(OsgiHeaderUtil.findReferredPackages(regs, packageScannerConfig.getPackageVersions()));
111
112 Analyzer analyzer = new Analyzer();
113 analyzer.setJar(new Jar("somename.jar"));
114
115
116
117 analyzer.setProperty(Constants.IMPORT_PACKAGE, origExports.toString());
118 Manifest mf = analyzer.calcManifest();
119
120 exports = mf.getMainAttributes().getValue(Constants.IMPORT_PACKAGE);
121 } catch (IOException ex)
122 {
123 log.error("Unable to calculate necessary exports based on host components", ex);
124 exports = origExports.toString();
125 }
126
127 if (log.isDebugEnabled()) {
128 log.debug("Exports:\n"+exports.replaceAll(",", "\r\n"));
129 }
130 return exports;
131 }
132
133 void constructAutoExports(StringBuilder sb, Collection<ExportPackage> packageExports) {
134 for (Iterator<ExportPackage> i = packageExports.iterator(); i.hasNext(); ) {
135 ExportPackage pkg = i.next();
136 sb.append(pkg.getPackageName());
137 if (pkg.getVersion() != null) {
138 try {
139 Version.parseVersion(pkg.getVersion());
140 sb.append(";version=").append(pkg.getVersion());
141 } catch (IllegalArgumentException ex) {
142 log.info("Unable to parse version: "+pkg.getVersion());
143 }
144 }
145 sb.append(",");
146 }
147 }
148
149 Collection<ExportPackage> generateExports(PackageScannerConfiguration packageScannerConfig)
150 {
151 String[] arrType = new String[0];
152 PackageScanner scanner = new PackageScanner()
153 .select(
154 jars(
155 include(packageScannerConfig.getJarIncludes().toArray(arrType)),
156 exclude(packageScannerConfig.getJarExcludes().toArray(arrType))),
157 packages(
158 include(packageScannerConfig.getPackageIncludes().toArray(arrType)),
159 exclude(packageScannerConfig.getPackageExcludes().toArray(arrType)))
160 )
161 .withMappings(packageScannerConfig.getPackageVersions());
162
163 if (log.isDebugEnabled())
164 {
165 scanner.enableDebug();
166 }
167
168 Collection<ExportPackage> exports = scanner.scan();
169 log.info("Package scan completed. Found " + exports.size() + " packages to export.");
170
171 if (!isPackageScanSuccessful(exports) && packageScannerConfig.getServletContext() != null)
172 {
173 log.warn("Unable to find expected packages via classloader scanning. Trying ServletContext scanning...");
174 ServletContext ctx = packageScannerConfig.getServletContext();
175 try
176 {
177 exports = scanner.scan(ctx.getResource("/WEB-INF/lib"), ctx.getResource("/WEB-INF/classes"));
178 }
179 catch (MalformedURLException e)
180 {
181 log.warn(e);
182 }
183 }
184
185 if (!isPackageScanSuccessful(exports))
186 {
187 throw new IllegalStateException("Unable to find required packages via classloader or servlet context"
188 + " scanning, most likely due to an application server bug.");
189 }
190 return exports;
191 }
192
193
194
195
196
197
198
199 private static boolean isPackageScanSuccessful(Collection<ExportPackage> exports)
200 {
201 boolean log4jFound = false;
202 for (ExportPackage export : exports)
203 {
204 if (export.getPackageName().equals("org.apache.log4j"))
205 {
206 log4jFound = true;
207 break;
208 }
209 }
210 return log4jFound;
211 }
212
213 void constructJdkExports(StringBuilder sb, String packageListPath)
214 {
215 InputStream in = null;
216 try
217 {
218 in = ClassLoaderUtils.getResourceAsStream(packageListPath, ExportsBuilder.class);
219 BufferedReader reader = new BufferedReader(new InputStreamReader(in));
220 String line;
221 while ((line = reader.readLine()) != null)
222 {
223 line = line.trim();
224 if (line.length() > 0)
225 {
226 if (line.charAt(0) != '#')
227 {
228 if (sb.length() > 0)
229 sb.append(',');
230 sb.append(line);
231 }
232 }
233 }
234 } catch (IOException e)
235 {
236 IOUtils.closeQuietly(in);
237 }
238 }
239 }