blob: 69d61dffb7e58b1519532354a0acafa360824b09 [file] [log] [blame]
Brian O'Connor42c38cf2016-04-05 17:05:57 -07001/*
2 * Copyright 2016 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onlab.osgiwrap;
18
19import aQute.bnd.osgi.Analyzer;
Brian O'Connor8aec1a12016-04-06 14:10:43 -070020import aQute.bnd.osgi.Builder;
Brian O'Connor42c38cf2016-04-05 17:05:57 -070021import aQute.bnd.osgi.Jar;
22import com.google.common.base.Joiner;
23import com.google.common.base.MoreObjects;
24import com.google.common.collect.Lists;
25import com.google.common.collect.Maps;
26import org.apache.felix.scrplugin.bnd.SCRDescriptorBndPlugin;
27
28import java.io.File;
29import java.util.Arrays;
30import java.util.HashSet;
31import java.util.List;
32import java.util.Map;
33import java.util.Objects;
34import java.util.Set;
35import java.util.jar.Manifest;
36
37/**
38 * BND-based wrapper to convert Buck JARs to OSGi-compatible JARs.
39 */
40public class OSGiWrapper {
41
42 private String inputJar;
43 private String outputJar;
44 private List<String> classpath;
45
46 private String bundleName;
47 private String groupId;
48 private String bundleSymbolicName;
49 private String bundleVersion;
50
51 private String bundleDescription;
52 private String bundleLicense;
53
54 private String webContext;
55
56 public static void main(String[] args) {
57
58 if (args.length < 7) {
59 System.err.println("Not enough args");
60 System.exit(1);
61 }
62
63 String jar = args[0];
64 String output = args[1];
65 String cp = args[2];
66 String name = args[3];
67 String group = args[4];
68 String version = args[5];
69 String license = args[6];
70 String webContext = args[7];
71 String desc = Joiner.on(' ').join(Arrays.copyOfRange(args, 8, args.length));
72
73 OSGiWrapper wrapper = new OSGiWrapper(jar, output, cp,
74 name, group,
75 version, license,
76 webContext, desc);
77 wrapper.log(wrapper + "\n");
78 if (!wrapper.execute()) {
79 System.err.println("ERROR");
80 System.exit(2);
81 }
82 }
83
84
85 public OSGiWrapper(String inputJar,
86 String outputJar,
87 String classpath,
88 String bundleName,
89 String groupId,
90 String bundleVersion,
91 String bundleLicense,
92 String webContext,
93 String bundleDescription) {
94 this.inputJar = inputJar;
95 this.classpath = Lists.newArrayList(classpath.split(":"));
96 if (!this.classpath.contains(inputJar)) {
97 this.classpath.add(0, inputJar);
98 }
99 this.outputJar = outputJar;
100
101 this.bundleName = bundleName;
102 this.groupId = groupId;
103 this.bundleSymbolicName = String.format("%s.%s", groupId, bundleName);
104
105 this.bundleVersion = bundleVersion;
106 this.bundleLicense = bundleLicense;
107 this.bundleDescription = bundleDescription;
108
109 this.webContext = webContext;
110 }
111
112 private void setProperties(Analyzer analyzer) {
113 analyzer.setProperty(Analyzer.BUNDLE_NAME, bundleName);
114 analyzer.setProperty(Analyzer.BUNDLE_SYMBOLICNAME, bundleSymbolicName);
115 analyzer.setProperty(Analyzer.BUNDLE_VERSION, bundleVersion.replace('-', '.'));
116
117 analyzer.setProperty(Analyzer.BUNDLE_DESCRIPTION, bundleDescription);
118 analyzer.setProperty(Analyzer.BUNDLE_LICENSE, bundleLicense);
119
120 //TODO consider using stricter version policy
121 //analyzer.setProperty("-provider-policy", "${range;[===,==+)}");
122 //analyzer.setProperty("-consumer-policy", "${range;[===,==+)}");
123
124 // There are no good defaults so make sure you set the Import-Package
Brian O'Connor60f6c952016-04-06 00:42:48 -0700125 analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*");
Brian O'Connor42c38cf2016-04-05 17:05:57 -0700126
127 // TODO include version in export, but not in import
128 analyzer.setProperty(Analyzer.EXPORT_PACKAGE, "*");
129
130 // TODO we may need INCLUDE_RESOURCE, or that might be done by Buck
131 //analyzer.setProperty(analyzer.INCLUDE_RESOURCE, ...)
132 if (isWab()) {
133 analyzer.setProperty(Analyzer.WAB, "src/main/webapp/");
134 analyzer.setProperty("Web-ContextPath", webContext);
Brian O'Connor60f6c952016-04-06 00:42:48 -0700135 analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*,org.glassfish.jersey.servlet");
Brian O'Connor42c38cf2016-04-05 17:05:57 -0700136 }
137 }
138
139 public boolean execute() {
Brian O'Connor8aec1a12016-04-06 14:10:43 -0700140 Analyzer analyzer = new Builder();
Brian O'Connor42c38cf2016-04-05 17:05:57 -0700141 try {
142
143 Jar jar = new Jar(new File(inputJar)); // where our data is
144 analyzer.setJar(jar); // give bnd the contents
145
146 // You can provide additional class path entries to allow
147 // bnd to pickup export version from the packageinfo file,
148 // Version annotation, or their manifests.
149 analyzer.addClasspath(classpath);
150
151 setProperties(analyzer);
152
153// analyzer.setProperty("DESTDIR");
154// analyzer.setBase();
155
156 // ------------- let's begin... -------------------------
157
158 // Analyze the target JAR first
159 analyzer.analyze();
160
161 // Scan the JAR for Felix SCR annotations and generate XML files
162 Map<String, String> properties = Maps.newHashMap();
163 SCRDescriptorBndPlugin scrDescriptorBndPlugin = new SCRDescriptorBndPlugin();
164 scrDescriptorBndPlugin.setProperties(properties);
165 scrDescriptorBndPlugin.setReporter(analyzer);
166 scrDescriptorBndPlugin.analyzeJar(analyzer);
167
168 // Repack the JAR as a WAR
169 doWabStaging(analyzer);
170
171 // Calculate the manifest
172 Manifest manifest = analyzer.calcManifest();
173 //OutputStream s = new FileOutputStream("/tmp/foo2.txt");
174 //manifest.write(s);
175 //s.close();
176
177 if (analyzer.isOk()) {
178 analyzer.getJar().setManifest(manifest);
179 analyzer.save(new File(outputJar), true);
180 log("Saved!\n");
181 } else {
182 warn("%s\n", analyzer.getErrors());
183 return false;
184 }
185
186 analyzer.close();
187
188 return true;
189 } catch (Exception e) {
190 e.printStackTrace();
191 return false;
192 }
193 }
194
195 private boolean isWab() {
196 return !Objects.equals(webContext, "NONE");
197 }
198
199 private void doWabStaging(Analyzer analyzer) throws Exception {
200 if (!isWab()) {
201 return;
202 }
203 String wab = analyzer.getProperty(analyzer.WAB);
204 Jar dot = analyzer.getJar();
205
206 log("wab %s", wab);
207 analyzer.setBundleClasspath("WEB-INF/classes," +
208 analyzer.getProperty(analyzer.BUNDLE_CLASSPATH));
209
210 Set<String> paths = new HashSet<String>(dot.getResources().keySet());
211
212 for (String path : paths) {
213 if (path.indexOf('/') > 0 && !Character.isUpperCase(path.charAt(0))) {
214 log("wab: moving: %s", path);
215 dot.rename(path, "WEB-INF/classes/" + path);
216 }
217 }
218 }
219
220 private void log(String format, Object... objects) {
221 //System.err.printf(format, objects);
222 }
223
224 private void warn(String format, Object... objects) {
225 System.err.printf(format, objects);
226 }
227
228 @Override
229 public String toString() {
230 return MoreObjects.toStringHelper(this)
231 .add("inputJar", inputJar)
232 .add("outputJar", outputJar)
233 .add("classpath", classpath)
234 .add("bundleName", bundleName)
235 .add("groupId", groupId)
236 .add("bundleSymbolicName", bundleSymbolicName)
237 .add("bundleVersion", bundleVersion)
238 .add("bundleDescription", bundleDescription)
239 .add("bundleLicense", bundleLicense)
240 .toString();
241
242 }
243}