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