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
7 import java.util.*;
8 import java.util.jar.Manifest;
9 import java.io.IOException;
10 import java.io.InputStream;
11
12 import org.twdata.pkgscanner.ExportPackage;
13 import org.twdata.pkgscanner.PackageScanner;
14 import static org.twdata.pkgscanner.PackageScanner.jars;
15 import static org.twdata.pkgscanner.PackageScanner.include;
16 import static org.twdata.pkgscanner.PackageScanner.exclude;
17 import static org.twdata.pkgscanner.PackageScanner.packages;
18 import org.osgi.framework.Version;
19 import org.osgi.framework.Constants;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import aQute.lib.osgi.Clazz;
23 import aQute.lib.osgi.Analyzer;
24 import aQute.lib.osgi.Jar;
25
26
27
28
29 public class OsgiHeaderUtil
30 {
31 static Log log = LogFactory.getLog(OsgiHeaderUtil.class);
32
33
34
35
36
37
38
39
40 public static String findReferredPackages(List<HostComponentRegistration> registrations) throws IOException
41 {
42 StringBuffer sb = new StringBuffer();
43 Set<String> referredPackages = new HashSet<String>();
44 Set<String> referredClasses = new HashSet<String>();
45 if (registrations == null)
46 {
47 sb.append(",");
48 }
49 else
50 {
51 for (HostComponentRegistration reg : registrations)
52 {
53 for (String inf : reg.getMainInterfaces())
54 {
55 String clsName = inf.replace('.','/')+".class";
56 crawlReferenceTree(clsName, referredClasses, referredPackages, 1);
57 }
58 }
59 for (String pkg : referredPackages)
60 {
61 sb.append(pkg).append(",");
62 }
63 }
64 return sb.toString();
65 }
66
67
68
69
70
71
72
73
74
75
76 static void crawlReferenceTree(String className, Set<String> scannedClasses, Set<String> packageImports, int level) throws IOException
77 {
78 if (level <= 0)
79 {
80 return;
81 }
82
83 if (className.startsWith("java/"))
84 return;
85
86 if (scannedClasses.contains(className))
87 return;
88 else
89 scannedClasses.add(className);
90
91 if (log.isDebugEnabled())
92 log.debug("Crawling "+className);
93
94 InputStream in = ClassLoaderUtils.getResourceAsStream(className, OsgiHeaderUtil.class);
95 if (in == null)
96 {
97 log.error("Cannot find interface "+className);
98 return;
99 }
100 Clazz clz = new Clazz(className, in);
101 packageImports.addAll(clz.getReferred().keySet());
102
103 Set<String> referredClasses = clz.getReferredClasses();
104 for (String ref : referredClasses)
105 crawlReferenceTree(ref, scannedClasses, packageImports, level-1);
106
107 }
108
109
110
111
112
113
114
115
116 public static String determineExports(List<HostComponentRegistration> regs, PackageScannerConfiguration packageScannerConfig){
117 String exports = null;
118
119 StringBuilder origExports = new StringBuilder();
120 origExports.append("org.osgi.framework; version=1.3.0,");
121 origExports.append("org.osgi.service.packageadmin; version=1.2.0," );
122 origExports.append("org.osgi.service.startlevel; version=1.0.0,");
123 origExports.append("org.osgi.service.url; version=1.0.0,");
124 origExports.append("org.osgi.util; version=1.3.0,");
125 origExports.append("org.osgi.util.tracker; version=1.3.0,");
126 origExports.append("host.service.command; version=1.0.0,");
127 origExports.append("javax.swing.tree,javax.swing,org.xml.sax,org.xml.sax.helpers,");
128 origExports.append("javax.xml,javax.xml.parsers,javax.xml.transform,javax.xml.transform.sax,");
129 origExports.append("javax.xml.transform.stream,javax.xml.transform.dom,org.w3c.dom,javax.naming,javax.naming.spi,");
130 origExports.append("javax.swing.border,javax.swing.event,javax.swing.text,");
131
132 Collection<ExportPackage> exportList = generateExports(packageScannerConfig);
133 constructAutoExports(origExports, exportList);
134
135
136 try
137 {
138 origExports.append(findReferredPackages(regs));
139
140 Analyzer analyzer = new Analyzer();
141 analyzer.setJar(new Jar("somename.jar"));
142
143
144
145 analyzer.setProperty(Constants.IMPORT_PACKAGE, origExports.toString());
146 Manifest mf = analyzer.calcManifest();
147
148 exports = mf.getMainAttributes().getValue(Constants.IMPORT_PACKAGE);
149 } catch (IOException ex)
150 {
151 log.error("Unable to calculate necessary exports based on host components", ex);
152 exports = origExports.toString();
153 }
154
155 if (log.isDebugEnabled()) {
156 log.debug("Exports:\n"+exports.replaceAll(",", "\r\n"));
157 }
158 return exports;
159 }
160
161 static void constructAutoExports(StringBuilder sb, Collection<ExportPackage> packageExports) {
162
163 for (Iterator<ExportPackage> i = packageExports.iterator(); i.hasNext(); ) {
164 ExportPackage pkg = i.next();
165 sb.append(pkg.getPackageName());
166 if (pkg.getVersion() != null) {
167 try {
168 Version.parseVersion(pkg.getVersion());
169 sb.append(";version=").append(pkg.getVersion());
170 } catch (IllegalArgumentException ex) {
171 log.info("Unable to parse version: "+pkg.getVersion());
172 }
173 }
174 sb.append(",");
175 }
176 }
177
178 static Collection<ExportPackage> generateExports(PackageScannerConfiguration packageScannerConfig)
179 {
180 String[] arrType = new String[0];
181 Collection<ExportPackage> exports = new PackageScanner()
182 .select(
183 jars(
184 include(packageScannerConfig.getJarIncludes().toArray(arrType)),
185 exclude(packageScannerConfig.getJarExcludes().toArray(arrType))),
186 packages(
187 include(packageScannerConfig.getPackageIncludes().toArray(arrType)),
188 exclude(packageScannerConfig.getPackageExcludes().toArray(arrType)))
189 )
190 .withMappings(packageScannerConfig.getPackageVersions())
191 .scan();
192 return exports;
193 }
194 }