blob: 3425bdefe187d8dbfb10d1b5d4dfafe3feebbaf2 [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
124 analyzer.setProperty(Analyzer.IMPORT_PACKAGE, "*,org.glassfish.jersey.servlet");
125
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);
134 }
135 }
136
137 public boolean execute() {
138 Analyzer analyzer = new Analyzer();
139 try {
140
141 Jar jar = new Jar(new File(inputJar)); // where our data is
142 analyzer.setJar(jar); // give bnd the contents
143
144 // You can provide additional class path entries to allow
145 // bnd to pickup export version from the packageinfo file,
146 // Version annotation, or their manifests.
147 analyzer.addClasspath(classpath);
148
149 setProperties(analyzer);
150
151// analyzer.setProperty("DESTDIR");
152// analyzer.setBase();
153
154 // ------------- let's begin... -------------------------
155
156 // Analyze the target JAR first
157 analyzer.analyze();
158
159 // Scan the JAR for Felix SCR annotations and generate XML files
160 Map<String, String> properties = Maps.newHashMap();
161 SCRDescriptorBndPlugin scrDescriptorBndPlugin = new SCRDescriptorBndPlugin();
162 scrDescriptorBndPlugin.setProperties(properties);
163 scrDescriptorBndPlugin.setReporter(analyzer);
164 scrDescriptorBndPlugin.analyzeJar(analyzer);
165
166 // Repack the JAR as a WAR
167 doWabStaging(analyzer);
168
169 // Calculate the manifest
170 Manifest manifest = analyzer.calcManifest();
171 //OutputStream s = new FileOutputStream("/tmp/foo2.txt");
172 //manifest.write(s);
173 //s.close();
174
175 if (analyzer.isOk()) {
176 analyzer.getJar().setManifest(manifest);
177 analyzer.save(new File(outputJar), true);
178 log("Saved!\n");
179 } else {
180 warn("%s\n", analyzer.getErrors());
181 return false;
182 }
183
184 analyzer.close();
185
186 return true;
187 } catch (Exception e) {
188 e.printStackTrace();
189 return false;
190 }
191 }
192
193 private boolean isWab() {
194 return !Objects.equals(webContext, "NONE");
195 }
196
197 private void doWabStaging(Analyzer analyzer) throws Exception {
198 if (!isWab()) {
199 return;
200 }
201 String wab = analyzer.getProperty(analyzer.WAB);
202 Jar dot = analyzer.getJar();
203
204 log("wab %s", wab);
205 analyzer.setBundleClasspath("WEB-INF/classes," +
206 analyzer.getProperty(analyzer.BUNDLE_CLASSPATH));
207
208 Set<String> paths = new HashSet<String>(dot.getResources().keySet());
209
210 for (String path : paths) {
211 if (path.indexOf('/') > 0 && !Character.isUpperCase(path.charAt(0))) {
212 log("wab: moving: %s", path);
213 dot.rename(path, "WEB-INF/classes/" + path);
214 }
215 }
216 }
217
218 private void log(String format, Object... objects) {
219 //System.err.printf(format, objects);
220 }
221
222 private void warn(String format, Object... objects) {
223 System.err.printf(format, objects);
224 }
225
226 @Override
227 public String toString() {
228 return MoreObjects.toStringHelper(this)
229 .add("inputJar", inputJar)
230 .add("outputJar", outputJar)
231 .add("classpath", classpath)
232 .add("bundleName", bundleName)
233 .add("groupId", groupId)
234 .add("bundleSymbolicName", bundleSymbolicName)
235 .add("bundleVersion", bundleVersion)
236 .add("bundleDescription", bundleDescription)
237 .add("bundleLicense", bundleLicense)
238 .toString();
239
240 }
241}