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
42
43
44
45
46
47
48
49 public String determineExports(List<HostComponentRegistration> regs, PackageScannerConfiguration packageScannerConfig, File cacheDir){
50
51 String exports = null;
52
53 StringBuilder origExports = new StringBuilder();
54 origExports.append("org.osgi.framework; version=1.4.1,");
55 origExports.append("org.osgi.service.packageadmin; version=1.2.0," );
56 origExports.append("org.osgi.service.startlevel; version=1.1.0,");
57 origExports.append("org.osgi.service.url; version=1.0.0,");
58 origExports.append("org.osgi.util; version=1.4.1,");
59 origExports.append("org.osgi.util.tracker; version=1.4.1,");
60 origExports.append("host.service.command; version=1.0.0,");
61
62 constructJdkExports(origExports, JDK_PACKAGES_PATH);
63 origExports.append(",");
64
65 if (System.getProperty("java.specification.version").equals("1.6")) {
66 constructJdkExports(origExports, JDK6_PACKAGES_PATH);
67 origExports.append(",");
68 }
69
70 Collection<ExportPackage> exportList = generateExports(packageScannerConfig);
71 constructAutoExports(origExports, exportList);
72
73
74 try
75 {
76 origExports.append(OsgiHeaderUtil.findReferredPackages(regs));
77
78 Analyzer analyzer = new Analyzer();
79 analyzer.setJar(new Jar("somename.jar"));
80
81
82
83 analyzer.setProperty(Constants.IMPORT_PACKAGE, origExports.toString());
84 Manifest mf = analyzer.calcManifest();
85
86 exports = mf.getMainAttributes().getValue(Constants.IMPORT_PACKAGE);
87 } catch (IOException ex)
88 {
89 log.error("Unable to calculate necessary exports based on host components", ex);
90 exports = origExports.toString();
91 }
92
93 if (log.isDebugEnabled()) {
94 log.debug("Exports:\n"+exports.replaceAll(",", "\r\n"));
95 }
96 return exports;
97 }
98
99 void constructAutoExports(StringBuilder sb, Collection<ExportPackage> packageExports) {
100 for (Iterator<ExportPackage> i = packageExports.iterator(); i.hasNext(); ) {
101 ExportPackage pkg = i.next();
102 sb.append(pkg.getPackageName());
103 if (pkg.getVersion() != null) {
104 try {
105 Version.parseVersion(pkg.getVersion());
106 sb.append(";version=").append(pkg.getVersion());
107 } catch (IllegalArgumentException ex) {
108 log.info("Unable to parse version: "+pkg.getVersion());
109 }
110 }
111 sb.append(",");
112 }
113 }
114
115 Collection<ExportPackage> generateExports(PackageScannerConfiguration packageScannerConfig)
116 {
117 String[] arrType = new String[0];
118 PackageScanner scanner = new PackageScanner()
119 .select(
120 jars(
121 include(packageScannerConfig.getJarIncludes().toArray(arrType)),
122 exclude(packageScannerConfig.getJarExcludes().toArray(arrType))),
123 packages(
124 include(packageScannerConfig.getPackageIncludes().toArray(arrType)),
125 exclude(packageScannerConfig.getPackageExcludes().toArray(arrType)))
126 )
127 .withMappings(packageScannerConfig.getPackageVersions());
128
129 if (log.isDebugEnabled())
130 {
131 scanner.enableDebug();
132 }
133
134 Collection<ExportPackage> exports = scanner.scan();
135
136 if (!isPackageScanSuccessful(exports) && packageScannerConfig.getServletContext() != null)
137 {
138 log.warn("Unable to find expected packages via classloader scanning. Trying ServletContext scanning...");
139 ServletContext ctx = packageScannerConfig.getServletContext();
140 try
141 {
142 exports = scanner.scan(ctx.getResource("/WEB-INF/lib"), ctx.getResource("/WEB-INF/classes"));
143 }
144 catch (MalformedURLException e)
145 {
146 log.warn(e);
147 }
148 }
149
150 if (!isPackageScanSuccessful(exports))
151 {
152 throw new IllegalStateException("Unable to find required packages via classloader or servlet context"
153 + " scanning, most likely due to an application server bug.");
154 }
155 return exports;
156 }
157
158
159
160
161
162
163
164 private static boolean isPackageScanSuccessful(Collection<ExportPackage> exports)
165 {
166 boolean log4jFound = false;
167 for (ExportPackage export : exports)
168 {
169 if (export.getPackageName().equals("org.apache.log4j"))
170 {
171 log4jFound = true;
172 break;
173 }
174 }
175 return log4jFound;
176 }
177
178 void constructJdkExports(StringBuilder sb, String packageListPath)
179 {
180 InputStream in = null;
181 try
182 {
183 in = ClassLoaderUtils.getResourceAsStream(packageListPath, ExportsBuilder.class);
184 BufferedReader reader = new BufferedReader(new InputStreamReader(in));
185 String line;
186 while ((line = reader.readLine()) != null)
187 {
188 line = line.trim();
189 if (line.length() > 0)
190 {
191 if (line.charAt(0) != '#')
192 {
193 if (sb.length() > 0)
194 sb.append(',');
195 sb.append(line);
196 }
197 }
198 }
199 } catch (IOException e)
200 {
201 IOUtils.closeQuietly(in);
202 }
203 }
204 }