1 package com.atlassian.plugin.osgi.util;
2
3 import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
4 import com.atlassian.plugin.osgi.container.PackageScannerConfiguration;
5 import com.atlassian.plugin.util.ClassLoaderUtils;
6 import com.atlassian.plugin.util.ClassUtils;
7
8 import java.util.*;
9 import java.util.jar.Manifest;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.io.BufferedReader;
13 import java.io.InputStreamReader;
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.Version;
22 import org.osgi.framework.Constants;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.commons.io.IOUtils;
26 import aQute.lib.osgi.Analyzer;
27 import aQute.lib.osgi.Jar;
28
29
30
31
32 public class OsgiHeaderUtil
33 {
34 static final String JDK_PACKAGES_PATH = "jdk-packages.txt";
35 static Log log = LogFactory.getLog(OsgiHeaderUtil.class);
36
37
38
39
40
41
42
43
44 public static String findReferredPackages(List<HostComponentRegistration> registrations) throws IOException
45 {
46 StringBuffer sb = new StringBuffer();
47 Set<String> referredPackages = new HashSet<String>();
48 Set<String> referredClasses = new HashSet<String>();
49 if (registrations == null)
50 {
51 sb.append(",");
52 }
53 else
54 {
55 for (HostComponentRegistration reg : registrations)
56 {
57 Set<Class> classesToScan = new HashSet<Class>();
58
59
60 for (Class inf : reg.getMainInterfaceClasses())
61 ClassUtils.findAllTypes(inf, classesToScan);
62
63 for (Class inf : classesToScan)
64 {
65 String clsName = inf.getName().replace('.','/')+".class";
66 crawlReferenceTree(clsName, referredClasses, referredPackages, 1);
67 }
68 }
69 for (String pkg : referredPackages)
70 {
71 sb.append(pkg).append(",");
72 }
73 }
74 return sb.toString();
75 }
76
77
78
79
80
81
82
83
84
85
86 static void crawlReferenceTree(String className, Set<String> scannedClasses, Set<String> packageImports, int level) throws IOException
87 {
88 if (level <= 0)
89 {
90 return;
91 }
92
93 if (className.startsWith("java/"))
94 return;
95
96 if (scannedClasses.contains(className))
97 return;
98 else
99 scannedClasses.add(className);
100
101 if (log.isDebugEnabled())
102 log.debug("Crawling "+className);
103
104 InputStream in = ClassLoaderUtils.getResourceAsStream(className, OsgiHeaderUtil.class);
105 if (in == null)
106 {
107 log.error("Cannot find interface "+className);
108 return;
109 }
110 Clazz clz = new Clazz(className, in);
111 packageImports.addAll(clz.getReferred().keySet());
112
113 Set<String> referredClasses = clz.getReferredClasses();
114 for (String ref : referredClasses)
115 crawlReferenceTree(ref, scannedClasses, packageImports, level-1);
116
117 }
118
119
120
121
122
123
124
125
126 public static String determineExports(List<HostComponentRegistration> regs, PackageScannerConfiguration packageScannerConfig){
127 String exports = null;
128
129 StringBuilder origExports = new StringBuilder();
130 origExports.append("org.osgi.framework; version=1.3.0,");
131 origExports.append("org.osgi.service.packageadmin; version=1.2.0," );
132 origExports.append("org.osgi.service.startlevel; version=1.0.0,");
133 origExports.append("org.osgi.service.url; version=1.0.0,");
134 origExports.append("org.osgi.util; version=1.3.0,");
135 origExports.append("org.osgi.util.tracker; version=1.3.0,");
136 origExports.append("host.service.command; version=1.0.0,");
137
138 constructJdkExports(origExports, JDK_PACKAGES_PATH);
139 origExports.append(",");
140
141 Collection<ExportPackage> exportList = generateExports(packageScannerConfig);
142 constructAutoExports(origExports, exportList);
143
144
145 try
146 {
147 origExports.append(findReferredPackages(regs));
148
149 Analyzer analyzer = new Analyzer();
150 analyzer.setJar(new Jar("somename.jar"));
151
152
153
154 analyzer.setProperty(Constants.IMPORT_PACKAGE, origExports.toString());
155 Manifest mf = analyzer.calcManifest();
156
157 exports = mf.getMainAttributes().getValue(Constants.IMPORT_PACKAGE);
158 } catch (IOException ex)
159 {
160 log.error("Unable to calculate necessary exports based on host components", ex);
161 exports = origExports.toString();
162 }
163
164 if (log.isDebugEnabled()) {
165 log.debug("Exports:\n"+exports.replaceAll(",", "\r\n"));
166 }
167 return exports;
168 }
169
170 static void constructAutoExports(StringBuilder sb, Collection<ExportPackage> packageExports) {
171 for (Iterator<ExportPackage> i = packageExports.iterator(); i.hasNext(); ) {
172 ExportPackage pkg = i.next();
173 sb.append(pkg.getPackageName());
174 if (pkg.getVersion() != null) {
175 try {
176 Version.parseVersion(pkg.getVersion());
177 sb.append(";version=").append(pkg.getVersion());
178 } catch (IllegalArgumentException ex) {
179 log.info("Unable to parse version: "+pkg.getVersion());
180 }
181 }
182 sb.append(",");
183 }
184 }
185
186 static Collection<ExportPackage> generateExports(PackageScannerConfiguration packageScannerConfig)
187 {
188 String[] arrType = new String[0];
189 Collection<ExportPackage> exports = new PackageScanner()
190 .select(
191 jars(
192 include(packageScannerConfig.getJarIncludes().toArray(arrType)),
193 exclude(packageScannerConfig.getJarExcludes().toArray(arrType))),
194 packages(
195 include(packageScannerConfig.getPackageIncludes().toArray(arrType)),
196 exclude(packageScannerConfig.getPackageExcludes().toArray(arrType)))
197 )
198 .withMappings(packageScannerConfig.getPackageVersions())
199 .scan();
200 return exports;
201 }
202
203 static void constructJdkExports(StringBuilder sb, String packageListPath)
204 {
205 InputStream in = null;
206 try
207 {
208 in = ClassLoaderUtils.getResourceAsStream(packageListPath, OsgiHeaderUtil.class);
209 BufferedReader reader = new BufferedReader(new InputStreamReader(in));
210 String line;
211 while ((line = reader.readLine()) != null)
212 {
213 line = line.trim();
214 if (line.length() > 0)
215 {
216 if (line.charAt(0) != '#')
217 {
218 if (sb.length() > 0)
219 sb.append(',');
220 sb.append(line);
221 }
222 }
223 }
224 } catch (IOException e)
225 {
226 IOUtils.closeQuietly(in);
227 }
228 }
229
230 }