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);
57 }
58 }
59 for (String pkg : referredPackages)
60 {
61 sb.append(pkg).append(",");
62 }
63 }
64 return sb.toString();
65 }
66
67 static void crawlReferenceTree(String className, Set<String> scannedClasses, Set<String> packageImports) throws IOException
68 {
69 if (className.startsWith("java/"))
70 return;
71
72 if (scannedClasses.contains(className))
73 return;
74 else
75 scannedClasses.add(className);
76
77 if (log.isDebugEnabled())
78 log.debug("Crawling "+className);
79
80 InputStream in = ClassLoaderUtils.getResourceAsStream(className, OsgiHeaderUtil.class);
81 if (in == null)
82 {
83 log.error("Cannot find interface "+className);
84 return;
85 }
86 Clazz clz = new Clazz(className, in);
87 packageImports.addAll(clz.getReferred().keySet());
88
89 Set<String> referredClasses = clz.getReferredClasses();
90 for (String ref : referredClasses)
91 crawlReferenceTree(ref, scannedClasses, packageImports);
92
93 }
94
95
96
97
98
99
100
101
102 public static String determineExports(List<HostComponentRegistration> regs, PackageScannerConfiguration packageScannerConfig){
103 String exports = null;
104
105 StringBuilder origExports = new StringBuilder();
106 origExports.append("org.osgi.framework; version=1.3.0,");
107 origExports.append("org.osgi.service.packageadmin; version=1.2.0," );
108 origExports.append("org.osgi.service.startlevel; version=1.0.0,");
109 origExports.append("org.osgi.service.url; version=1.0.0,");
110 origExports.append("org.osgi.util; version=1.3.0,");
111 origExports.append("org.osgi.util.tracker; version=1.3.0,");
112 origExports.append("host.service.command; version=1.0.0,");
113 origExports.append("javax.swing.tree,javax.swing,org.xml.sax,org.xml.sax.helpers,");
114 origExports.append("javax.xml,javax.xml.parsers,javax.xml.transform,javax.xml.transform.sax,");
115 origExports.append("javax.xml.transform.stream,javax.xml.transform.dom,org.w3c.dom,javax.naming,javax.naming.spi,");
116 origExports.append("javax.swing.border,javax.swing.event,javax.swing.text,");
117
118 Collection<ExportPackage> exportList = generateExports(packageScannerConfig);
119 constructAutoExports(origExports, exportList);
120
121
122 try
123 {
124 origExports.append(findReferredPackages(regs));
125
126 Analyzer analyzer = new Analyzer();
127 analyzer.setJar(new Jar("somename.jar"));
128
129
130
131 analyzer.setProperty(Constants.IMPORT_PACKAGE, origExports.toString());
132 Manifest mf = analyzer.calcManifest();
133
134 exports = mf.getMainAttributes().getValue(Constants.IMPORT_PACKAGE);
135 } catch (IOException ex)
136 {
137 log.error("Unable to calculate necessary exports based on host components", ex);
138 exports = origExports.toString();
139 }
140
141 if (log.isDebugEnabled()) {
142 log.debug("Exports:\n"+exports.replaceAll(",", "\r\n"));
143 }
144 return exports;
145 }
146
147 static void constructAutoExports(StringBuilder sb, Collection<ExportPackage> packageExports) {
148
149 for (Iterator<ExportPackage> i = packageExports.iterator(); i.hasNext(); ) {
150 ExportPackage pkg = i.next();
151 sb.append(pkg.getPackageName());
152 if (pkg.getVersion() != null) {
153 try {
154 Version.parseVersion(pkg.getVersion());
155 sb.append(";version=").append(pkg.getVersion());
156 } catch (IllegalArgumentException ex) {
157 log.info("Unable to parse version: "+pkg.getVersion());
158 }
159 }
160 sb.append(",");
161 }
162 }
163
164 static Collection<ExportPackage> generateExports(PackageScannerConfiguration packageScannerConfig)
165 {
166 String[] arrType = new String[0];
167 Collection<ExportPackage> exports = new PackageScanner()
168 .select(
169 jars(
170 include(packageScannerConfig.getJarIncludes().toArray(arrType)),
171 exclude(packageScannerConfig.getJarExcludes().toArray(arrType))),
172 packages(
173 include(packageScannerConfig.getPackageIncludes().toArray(arrType)),
174 exclude(packageScannerConfig.getPackageExcludes().toArray(arrType)))
175 )
176 .withMappings(packageScannerConfig.getPackageVersions())
177 .scan();
178 return exports;
179 }
180 }