/** Check if the getSubBuilders properly predicts the output. */ public static void testSubBuilders() throws Exception { Workspace ws = Workspace.getWorkspace(new File("test/ws")); Project project = ws.getProject("p4-sub"); Collection<? extends Builder> bs = project.getSubBuilders(); assertNotNull(bs); assertEquals(3, bs.size()); Set<String> names = new HashSet<String>(); for (Builder b : bs) { names.add(b.getBsn()); } assertTrue(names.contains("p4-sub.a")); assertTrue(names.contains("p4-sub.b")); assertTrue(names.contains("p4-sub.c")); File[] files = project.build(); assertTrue(project.check()); System.err.println(Processor.join(project.getErrors(), "\n")); System.err.println(Processor.join(project.getWarnings(), "\n")); assertEquals(0, project.getErrors().size()); assertEquals(0, project.getWarnings().size()); assertNotNull(files); assertEquals(3, files.length); for (File file : files) { Jar jar = new Jar(file); Manifest m = jar.getManifest(); assertTrue(names.contains(m.getMainAttributes().getValue("Bundle-SymbolicName"))); } }
/** * All the BND magic happens here. * * @param jarInputStream On what to operate. * @param instructions BND instructions from user API * @param symbolicName Mandatory Header. In case user does not set it. * @return Bundle Jar Stream * @throws Exception Problems go here */ private InputStream createBundle( InputStream jarInputStream, Properties instructions, String symbolicName) throws Exception { NullArgumentException.validateNotNull(jarInputStream, "Jar URL"); NullArgumentException.validateNotNull(instructions, "Instructions"); NullArgumentException.validateNotEmpty(symbolicName, "Jar info"); final Jar jar = new Jar("dot", sink(jarInputStream)); final Properties properties = new Properties(); properties.putAll(instructions); final Analyzer analyzer = new Analyzer(); analyzer.setJar(jar); analyzer.setProperties(properties); // throw away already existing headers that we overwrite: analyzer.mergeManifest(jar.getManifest()); checkMandatoryProperties(analyzer, jar, symbolicName); Manifest manifest = analyzer.calcManifest(); jar.setManifest(manifest); return createInputStream(jar); }
/** * Test if we can select * * @throws Exception */ public void testSelect() throws Exception { Jar bjara = getContractExporter("atest", "2.5", "${exports}"); Jar bjarb = getContractExporter("btest", "2.5", "${exports}"); Builder a = newBuilder(); a.setTrace(true); a.addClasspath(bjara); // 1x a.addClasspath(bjarb); // 2x a.setProperty(Constants.CONTRACT, "atest;alpha=1"); a.setImportPackage("org.osgi.service.cm,*"); a.setProperty("Export-Package", "test.refer"); Jar ajar = a.build(); assertTrue(a.check()); ajar.getManifest().write(System.out); Domain domain = Domain.domain(ajar.getManifest()); Parameters p = domain.getRequireCapability(); p.remove("osgi.ee"); assertNotNull(p); assertEquals(1, p.size()); Attrs attrs = p.get("osgi.contract"); String alpha = attrs.get("alpha"); assertEquals("1", alpha); assertEquals("(&(osgi.contract=atest)(version=2.5.0))", attrs.get("filter:")); }
private void copy(File workspaceDir, InputStream in, Pattern glob, boolean overwrite) throws Exception { Jar jar = new Jar("dot", in); try { for (Entry<String, Resource> e : jar.getResources().entrySet()) { String path = e.getKey(); bnd.trace("path %s", path); if (glob != null && !glob.matcher(path).matches()) continue; Resource r = e.getValue(); File dest = Processor.getFile(workspaceDir, path); if (overwrite || !dest.isFile() || dest.lastModified() < r.lastModified() || r.lastModified() <= 0) { bnd.trace("copy %s to %s", path, dest); File dp = dest.getParentFile(); if (!dp.exists() && !dp.mkdirs()) { throw new IOException("Could not create directory " + dp); } IO.copy(r.openInputStream(), dest); } } } finally { jar.close(); } }
/** @throws Exception */ File[] getBundleClasspathFiles() throws Exception { if (this.bundleClasspathExpansion != null) return bundleClasspathExpansion; File file = getFile(); Manifest m = getManifest(); String bundleClassPath; if (m == null || (bundleClassPath = m.getMainAttributes().getValue(Constants.BUNDLE_CLASSPATH)) == null) { this.bundleClasspathExpansion = new File[] {file}; } else { File bundleClasspathDirectory = IO.getFile(file.getParentFile(), "." + file.getName() + "-bcp"); Parameters header = new Parameters(bundleClassPath); this.bundleClasspathExpansion = new File[header.size()]; bundleClasspathDirectory.mkdir(); int n = 0; Jar jar = null; try { for (Map.Entry<String, Attrs> entry : header.entrySet()) { if (".".equals(entry.getKey())) { this.bundleClasspathExpansion[n] = file; } else { File member = new File(bundleClasspathDirectory, n + "-" + toName(entry.getKey())); if (!isCurrent(file, member)) { if (jar == null) { jar = new Jar(file); } Resource resource = jar.getResource(entry.getKey()); if (resource == null) { warning += "Invalid bcp entry: " + entry.getKey() + "\n"; } else { IO.copy(resource.openInputStream(), member); member.setLastModified(file.lastModified()); } } this.bundleClasspathExpansion[n] = member; } n++; } } finally { if (jar != null) jar.close(); } } return this.bundleClasspathExpansion; }
public static void testSimple() throws Exception { Builder bmaker = new Builder(); bmaker.addClasspath(IO.getFile("jar/mina.jar")); bmaker.set("Export-Package", "org.apache.mina.*;version=1"); bmaker.set("DynamicImport-Package", "org.slf4j"); Jar jar = bmaker.build(); assertTrue(bmaker.check()); Manifest m = jar.getManifest(); m.write(System.err); assertTrue(m.getMainAttributes().getValue("Import-Package").indexOf("org.slf4j") >= 0); assertTrue(m.getMainAttributes().getValue("DynamicImport-Package").indexOf("org.slf4j") >= 0); }
/** Test default package versions. */ public static void testDefaultPackageVersion() throws Exception { Builder a = new Builder(); a.addClasspath(new File("bin")); a.setProperty("Bundle-Version", "1.2.3"); a.setProperty("Export-Package", "test.refer"); Jar jar = a.build(); Manifest m = jar.getManifest(); Parameters exports = Processor.parseHeader(m.getMainAttributes().getValue(Constants.EXPORT_PACKAGE), null); Map<String, String> attrs = exports.get("test.refer"); assertNotNull(attrs); assertEquals("1.2.3", attrs.get("version")); }
/** * Verify that the Meta-Persistence header is correctly verified * * @throws Exception */ public void verifyMetaPersistence() throws Exception { Builder b = new Builder(); b.setIncludeResource("foo.xml;literal='I exist'"); Jar inner = b.build(); assertTrue(b.check()); Jar outer = new Jar("x"); outer.putResource("foo.jar", new JarResource(inner)); Manifest m = new Manifest(); m.getMainAttributes() .putValue(Constants.META_PERSISTENCE, "foo.jar, foo.jar!/foo.xml, absent.xml"); outer.setManifest(m); Verifier v = new Verifier(outer); v.verifyMetaPersistence(); assertTrue(v.check("Meta-Persistence refers to resources not in the bundle: \\[absent.xml\\]")); }
/** Test import provide:. */ public static void testExportProvided() throws Exception { Builder a = new Builder(); a.addClasspath(IO.getFile("jar/osgi.jar")); a.addClasspath(new File("bin")); a.setProperty("Private-Package", "test.refer"); a.setProperty("Export-Package", "org.osgi.service.http;provide:=true"); Jar jar = a.build(); Map<String, String> event = a.getImports().getByFQN("org.osgi.service.event"); assertEquals("[1.0,2)", event.get("version")); Map<String, String> http = a.getImports().getByFQN("org.osgi.service.http"); assertEquals("[1.2,1.3)", http.get("version")); Manifest m = jar.getManifest(); String imports = m.getMainAttributes().getValue(Constants.IMPORT_PACKAGE); assertFalse(imports.contains(Constants.PROVIDE_DIRECTIVE)); }
/** * Test if the implementation of "AnnotatedProviderInterface", which is annotated with OSGi * R6 @ProviderType, causes import of the api package to use the provider version policy */ public static void testProviderTypeR6() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setPrivatePackage("test.versionpolicy.implemented.osgi"); b.setProperty("build", "123"); Jar jar = b.build(); assertTrue(b.check()); Manifest m = jar.getManifest(); m.write(System.err); Domain d = Domain.domain(m); Parameters params = d.getImportPackage(); Attrs attrs = params.get("test.version.annotations.osgi"); assertNotNull(attrs); assertEquals("[1.2,1.3)", attrs.get("version")); }
/** * Tests if the implementation of the EventHandler (which is marked as a ConsumerType) causes the * import of the api package to use the consumer version policy. */ public static void testConsumerType() throws Exception { Builder a = new Builder(); a.addClasspath(new File("bin")); a.setPrivatePackage("test.versionpolicy.uses"); a.setExportPackage("test.versionpolicy.api"); a.setProperty("build", "123"); Jar jar = a.build(); assertTrue(a.check()); Manifest m = jar.getManifest(); m.write(System.err); Domain d = Domain.domain(m); Parameters parameters = d.getImportPackage(); Attrs attrs = parameters.get("test.versionpolicy.api"); assertNotNull(attrs); assertEquals("[1.2,2)", attrs.get("version")); }
private File create(String bsn, Version v) throws Exception { String name = bsn + "-" + v; Builder b = new Builder(); b.setBundleSymbolicName(bsn); b.setBundleVersion(v); b.setProperty("Random", random++ + ""); b.setProperty("-resourceonly", true + ""); b.setIncludeResource("foo;literal='foo'"); Jar jar = b.build(); assertTrue(b.check()); File file = IO.getFile(tmp, name + ".jar"); file.getParentFile().mkdirs(); jar.updateModified(System.currentTimeMillis(), "Force it to now"); jar.write(file); b.close(); return file; }
/** * Make sure we do not add a contract if not used * * @throws Exception */ public void testUnused() throws Exception { Jar bjara = getContractExporter("atest", "2.5", "${exports}"); Builder a = newBuilder(); a.setTrace(true); a.addClasspath(bjara); a.setProperty(Constants.CONTRACT, "*"); a.setImportPackage("test.packageinfo,*"); a.setProperty("Export-Package", "test.refer"); Jar ajar = a.build(); assertTrue(a.check()); Domain domain = Domain.domain(ajar.getManifest()); Parameters p = domain.getRequireCapability(); p.remove("osgi.ee"); assertEquals(0, p.size()); }
/** Created a JAR that is a bundle and that contains its dependencies */ @Override public Jar executable() throws Exception { Collection<String> bsns = getProject().getBsns(); if (bsns.size() != 1) throw new IllegalArgumentException( "Can only handle a single bsn for a run configuration " + bsns); String bsn = bsns.iterator().next(); Jar jar = new Jar(bsn); String path = "aQute/remote/embedded/activator/EmbeddedActivator.class"; URLResource resource = new URLResource(getClass().getClassLoader().getResource(path)); jar.putResource("aQute/remote/embedded/activator/EmbeddedActivator.class", resource); Collection<Container> rb = getProject().getRunbundles(); rb = Container.flatten(rb); Attrs attrs = new Attrs(); for (Container c : rb) { if (c.getError() != null) { getProject().error("invalid runbundle %s", c); } else { File f = c.getFile(); String tbsn = c.getBundleSymbolicName(); String version = c.getVersion(); if (version == null || !Version.isVersion(version)) getProject() .warning("The version of embedded bundle %s does not have a proper version", c); jar.putResource("jar/" + c.getBundleSymbolicName() + ".jar", new FileResource(f)); attrs.put(tbsn, version); } } Analyzer a = new Analyzer(getProject()); a.setJar(jar); a.setBundleActivator(EmbeddedActivator.class.getName()); a.setProperty("Bnd-Embedded", attrs.toString().replace(';', ',')); Manifest manifest = a.calcManifest(); jar.setManifest(manifest); getProject().getInfo(a); return jar; }
@SuppressWarnings("deprecation") private void tryJMXDeploy(String jmx, String bsn) { JMXBundleDeployer jmxBundleDeployer = null; int port = -1; try { port = Integer.parseInt(jmx); } catch (Exception e) { // not an integer } try { if (port > -1) { jmxBundleDeployer = new JMXBundleDeployer(port); } else { jmxBundleDeployer = new JMXBundleDeployer(); } } catch (Exception e) { // ignore if we can't create bundle deployer (no remote osgi.core // jmx avail) } if (jmxBundleDeployer != null) { for (String path : this.getRunpath()) { File file = new File(path); try { Jar jar = new Jar(file); try { if (bsn.equals(jar.getBsn())) { long bundleId = jmxBundleDeployer.deploy(bsn, file); trace("agent installed with bundleId=%s", bundleId); break; } } finally { jar.close(); } } catch (Exception e) { // } } } }
/** * Tests if the implementation of the EventAdmin (which is marked as a ProviderType) causes the * import of the api package to use the provider version policy. */ public static void testProviderType() throws Exception { Builder a = new Builder(); a.addClasspath(new File("bin")); a.setPrivatePackage("test.versionpolicy.implemented"); a.setExportPackage("test.versionpolicy.api"); a.setImportPackage("test.versionpolicy.api"); // what changed so this is // not automatically // added? a.setProperty("build", "123"); Jar jar = a.build(); assertTrue(a.check()); Manifest m = jar.getManifest(); m.write(System.err); Domain d = Domain.domain(m); Parameters parameters = d.getImportPackage(); Attrs attrs = parameters.get("test.versionpolicy.api"); assertNotNull(attrs); assertEquals("[1.2,1.3)", attrs.get("version")); }
/** * Test the warnings that we have no no version * * @throws Exception */ public void testWarningVersion() throws Exception { Jar bjara = getContractExporter("abc", null, "${exports}"); Builder a = newBuilder(); a.setTrace(true); a.addClasspath(bjara); a.setProperty(Constants.CONTRACT, "*"); a.setImportPackage("test.packageinfo,*"); a.setProperty("Export-Package", "test.refer"); Jar ajar = a.build(); assertTrue( a.check( "Contract \\[name=abc;version=0.0.0;from=biz.aQute.bndlib.tests] does not declare a version")); Domain domain = Domain.domain(ajar.getManifest()); Parameters p = domain.getRequireCapability(); p.remove("osgi.ee"); assertEquals(0, p.size()); }
public void testSimple() throws Exception { Jar bjar = getContractExporter("test", "2.5", "${exports}"); Builder a = newBuilder(); a.setTrace(true); a.addClasspath(bjar); a.setProperty(Constants.CONTRACT, "*"); a.setImportPackage("org.osgi.service.cm,*"); a.setProperty("Export-Package", "test.refer"); Jar ajar = a.build(); assertTrue(a.check()); Domain domain = Domain.domain(ajar.getManifest()); Parameters rc = domain.getRequireCapability(); rc.remove("osgi.ee"); System.out.println(rc); assertEquals(1, rc.size()); Packages ps = a.getImports(); assertTrue(ps.containsFQN("org.osgi.service.cm")); Attrs attrs = ps.getByFQN("org.osgi.service.cm"); assertNotNull(attrs); assertNull(attrs.getVersion()); }
private static String getLatestRemoteBladeCLIJar() { _settingsDir.mkdirs(); repoCache.mkdirs(); Processor reporter = new Processor(); FixedIndexedRepo repo = new FixedIndexedRepo(); Map<String, String> props = new HashMap<String, String>(); props.put("name", "index1"); props.put("locations", getRepoURL() + "index.xml.gz"); props.put(FixedIndexedRepo.PROP_CACHE, repoCache.getAbsolutePath()); repo.setProperties(props); repo.setReporter(reporter); try { File[] files = repo.get("com.liferay.blade.cli", "[2,3)"); File cliJar = files[0]; try (Jar cliJarJar = new Jar(cliJar); Jar localJar = new Jar(getLocalCopy())) { Version cliJarVersion = new Version(cliJarJar.getVersion()); Version localCopyVersion = new Version(localJar.getVersion()); if (cliJarVersion.compareTo(localCopyVersion) >= 0) { cachedBladeCLIPath = new Path(cliJar.getCanonicalPath()); } else { return null; } } return cliJar.getName(); } catch (Exception e) { return null; } }
/** * Tests the handling of the -sub facility * * @throws Exception */ public static void testSub() throws Exception { Workspace ws = Workspace.getWorkspace(new File("test/ws")); Project project = ws.getProject("p4-sub"); File[] files = project.build(); Arrays.sort(files); System.err.println(Processor.join(project.getErrors(), "\n")); System.err.println(Processor.join(project.getWarnings(), "\n")); assertEquals(0, project.getErrors().size()); assertEquals(0, project.getWarnings().size()); assertNotNull(files); assertEquals(3, files.length); Jar a = new Jar(files[0]); Jar b = new Jar(files[1]); Manifest ma = a.getManifest(); Manifest mb = b.getManifest(); assertEquals("base", ma.getMainAttributes().getValue("Base-Header")); assertEquals("base", mb.getMainAttributes().getValue("Base-Header")); assertEquals("a", ma.getMainAttributes().getValue("Sub-Header")); assertEquals("b", mb.getMainAttributes().getValue("Sub-Header")); }
private String _calculateExportPackage(Jar jar) { StringBundler sb = new StringBundler(); String delimiter = StringPool.BLANK; Map<String, Map<String, Resource>> directories = jar.getDirectories(); for (String directory : directories.keySet()) { if (directory.equals("META-INF") || directory.startsWith("META-INF/")) { continue; } if (directory.equals("OSGI-OPT") || directory.startsWith("OSGI-OPT/")) { continue; } if (directory.equals(StringPool.SLASH)) { continue; } if (directory.endsWith(StringPool.SLASH)) { directory = directory.substring(0, directory.length() - 1); } if (directory.endsWith(StringPool.SLASH)) { directory = directory.substring(0, directory.length() - 1); } String className = directory.replace(StringPool.SLASH, StringPool.PERIOD); if (directories.get(directory) != null) { sb.append(delimiter); sb.append(className); delimiter = StringPool.COMMA; } } return sb.toString(); }
private void doManifest( Jar jar, String[] digestNames, MessageDigest[] algorithms, OutputStream out) throws Exception { for (Map.Entry<String, Resource> entry : jar.getResources().entrySet()) { String name = entry.getKey(); if (!METAINFDIR.matcher(name).matches()) { out.write("\r\n".getBytes("UTF-8")); out.write("Name: ".getBytes("UTF-8")); out.write(name.getBytes("UTF-8")); out.write("\r\n".getBytes("UTF-8")); digest(algorithms, entry.getValue()); for (int a = 0; a < algorithms.length; a++) { if (algorithms[a] != null) { byte[] digest = algorithms[a].digest(); String header = digestNames[a] + "-Digest: " + new Base64(digest) + "\r\n"; out.write(header.getBytes("UTF-8")); } } } } }
@SuppressWarnings("cast") private void executeBackwardCompatible() throws BuildException { try { if (files == null) throw new BuildException("No files set"); if (eclipse) { File project = getProject().getBaseDir(); EclipseClasspath cp = new EclipseClasspath(this, project.getParentFile(), project); classpath.addAll(cp.getClasspath()); classpath.addAll(cp.getBootclasspath()); sourcepath.addAll(cp.getSourcepath()); // classpath.add(cp.getOutput()); if (report()) throw new BuildException("Errors during Eclipse Path inspection"); } if (output == null) output = getProject().getBaseDir(); for (Iterator<File> f = files.iterator(); f.hasNext(); ) { File file = f.next(); Builder builder = new Builder(); builder.setPedantic(isPedantic()); if (file.exists()) { // Do nice property calculations // merging includes etc. builder.setProperties(file); } // get them and merge them with the project // properties, if the inherit flag is specified if (inherit) { Properties projectProperties = new UTF8Properties(); @SuppressWarnings("unchecked") Hashtable<Object, Object> antProps = getProject().getProperties(); projectProperties.putAll(antProps); projectProperties.putAll(builder.getProperties()); builder.setProperties(projectProperties); } builder.setClasspath(toFiles(classpath, "classpath")); builder.setSourcepath(toFiles(sourcepath, "sourcepath")); Jar jars[] = builder.builds(); // Report both task failures and bnd build failures. boolean taskFailed = report(); boolean bndFailed = report(builder); // Fail this build if failure is not ok and either the task // failed or the bnd build failed. if (!failok && (taskFailed || bndFailed)) { throw new BuildException( "bnd failed", new org.apache.tools.ant.Location(file.getAbsolutePath())); } for (int i = 0; i < jars.length; i++) { Jar jar = jars[i]; String bsn = jar.getName(); File base = file.getParentFile(); File output = this.output; String path = builder.getProperty("-output"); if (output == null) { if (path == null) output = getFile(base, bsn + ".jar"); else { output = getFile(base, path); } } else if (output.isDirectory()) { if (path == null) output = getFile(this.output, bsn + ".jar"); else output = getFile(this.output, path); } else if (output.isFile()) { if (files.size() > 1) messages.GotFileNeedDir_(output.getAbsoluteFile()); } String msg = ""; if (!output.exists() || output.lastModified() <= jar.lastModified()) { jar.write(output); } else { msg = "(not modified)"; } trace("%s (%s) %s %s", jar.getName(), output.getName(), jar.getResources().size(), msg); report(); jar.close(); } builder.close(); } } catch (Exception e) { // if (exceptions) e.printStackTrace(); if (!failok) throw new BuildException("Failed to build jar file: ", e); } }
protected void doBaselineJar(Jar jar, File output, aQute.bnd.build.Project bndProject) throws Exception { if (_reportLevelIsOff) { return; } ProjectBuilder projectBuilder = new ProjectBuilder(bndProject); projectBuilder.setClasspath(_classpathFiles.toArray(new File[_classpathFiles.size()])); projectBuilder.setPedantic(isPedantic()); projectBuilder.setProperties(_file); projectBuilder.setSourcepath(new File[] {_sourcePath}); Jar baselineJar = projectBuilder.getBaselineJar(); try { if (baselineJar == null) { bndProject.deploy(output); return; } Baseline baseline = new Baseline(this, _diffPluginImpl); Set<Info> infos = baseline.baseline(jar, baselineJar, null); if (infos.isEmpty()) { return; } BundleInfo bundleInfo = baseline.getBundleInfo(); Info[] infosArray = infos.toArray(new Info[infos.size()]); Arrays.sort( infosArray, new Comparator<Info>() { @Override public int compare(Info info1, Info info2) { return info1.packageName.compareTo(info2.packageName); } }); for (Info info : infosArray) { String warnings = "-"; Version newerVersion = info.newerVersion; Version suggestedVersion = info.suggestedVersion; if (suggestedVersion != null) { if (newerVersion.compareTo(suggestedVersion) > 0) { warnings = "EXCESSIVE VERSION INCREASE"; } else if (newerVersion.compareTo(suggestedVersion) < 0) { warnings = "VERSION INCREASE REQUIRED"; } } Diff packageDiff = info.packageDiff; Delta delta = packageDiff.getDelta(); if (delta == Delta.REMOVED) { warnings = "PACKAGE REMOVED"; } else if (delta == Delta.UNCHANGED) { boolean newVersionSuggested = false; if ((suggestedVersion.getMajor() != newerVersion.getMajor()) || (suggestedVersion.getMicro() != newerVersion.getMicro()) || (suggestedVersion.getMinor() != newerVersion.getMinor())) { warnings = "VERSION INCREASE SUGGESTED"; newVersionSuggested = true; } if (!newVersionSuggested && !info.mismatch) { continue; } } if (((_reportLevelIsStandard || _reportOnlyDirtyPackages) && warnings.equals("-")) || (_reportOnlyDirtyPackages && (delta == Delta.REMOVED))) { continue; } doInfo(bundleInfo, info, warnings); if (_reportLevelIsDiff && (delta != Delta.REMOVED)) { doPackageDiff(packageDiff); } } } finally { if (baselineJar != null) { baselineJar.close(); } if (_printWriter != null) { _printWriter.close(); } projectBuilder.close(); } }
public void signJar(Jar jar) { if (digestNames == null || digestNames.length == 0) error("Need at least one digest algorithm name, none are specified"); if (keystoreFile == null || !keystoreFile.getAbsoluteFile().exists()) { error("No such keystore file: " + keystoreFile); return; } if (alias == null) { error("Private key alias not set for signing"); return; } MessageDigest digestAlgorithms[] = new MessageDigest[digestNames.length]; getAlgorithms(digestNames, digestAlgorithms); try { Manifest manifest = jar.getManifest(); manifest.getMainAttributes().putValue("Signed-By", "Bnd"); // Create a new manifest that contains the // Name parts with the specified digests ByteArrayOutputStream o = new ByteArrayOutputStream(); manifest.write(o); doManifest(jar, digestNames, digestAlgorithms, o); o.flush(); byte newManifestBytes[] = o.toByteArray(); jar.putResource("META-INF/MANIFEST.MF", new EmbeddedResource(newManifestBytes, 0)); // Use the bytes from the new manifest to create // a signature file byte[] signatureFileBytes = doSignatureFile(digestNames, digestAlgorithms, newManifestBytes); jar.putResource("META-INF/BND.SF", new EmbeddedResource(signatureFileBytes, 0)); // Now we must create an RSA signature // this requires the private key from the keystore KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); KeyStore.PrivateKeyEntry privateKeyEntry = null; java.io.FileInputStream keystoreInputStream = null; try { keystoreInputStream = new java.io.FileInputStream(keystoreFile); char[] pw = password == null ? new char[0] : password.toCharArray(); keystore.load(keystoreInputStream, pw); keystoreInputStream.close(); privateKeyEntry = (PrivateKeyEntry) keystore.getEntry(alias, new KeyStore.PasswordProtection(pw)); } catch (Exception e) { error( "No able to load the private key from the give keystore(" + keystoreFile.getAbsolutePath() + ") with alias " + alias + " : " + e); return; } finally { IO.close(keystoreInputStream); } PrivateKey privateKey = privateKeyEntry.getPrivateKey(); Signature signature = Signature.getInstance("MD5withRSA"); signature.initSign(privateKey); signature.update(signatureFileBytes); signature.sign(); // TODO, place the SF in a PCKS#7 structure ... // no standard class for this? The following // is an idea but we will to have do ASN.1 BER // encoding ... ByteArrayOutputStream tmpStream = new ByteArrayOutputStream(); jar.putResource("META-INF/BND.RSA", new EmbeddedResource(tmpStream.toByteArray(), 0)); } catch (Exception e) { error("During signing: " + e); } }
private Manifest _calculateManifest(URL url, Manifest manifest) { Analyzer analyzer = new Analyzer(); Jar jar = null; try { URLConnection urlConnection = url.openConnection(); String fileName = url.getFile(); if (urlConnection instanceof JarURLConnection) { JarURLConnection jarURLConnection = (JarURLConnection) urlConnection; URL jarFileURL = jarURLConnection.getJarFileURL(); fileName = jarFileURL.getFile(); } File file = new File(fileName); if (!file.exists() || !file.canRead()) { return manifest; } fileName = file.getName(); analyzer.setJar(new Jar(fileName, file)); jar = analyzer.getJar(); String bundleSymbolicName = fileName; Matcher matcher = _bundleSymbolicNamePattern.matcher(bundleSymbolicName); if (matcher.matches()) { bundleSymbolicName = matcher.group(1); } analyzer.setProperty(Analyzer.BUNDLE_SYMBOLICNAME, bundleSymbolicName); String exportPackage = _calculateExportPackage(jar); analyzer.setProperty(Analyzer.EXPORT_PACKAGE, exportPackage); analyzer.mergeManifest(manifest); String bundleVersion = analyzer.getProperty(Analyzer.BUNDLE_VERSION); if (bundleVersion != null) { bundleVersion = Builder.cleanupVersion(bundleVersion); analyzer.setProperty(Analyzer.BUNDLE_VERSION, bundleVersion); } return analyzer.calcManifest(); } catch (Exception e) { _log.error(e, e); return manifest; } finally { if (jar != null) { jar.close(); } analyzer.close(); } }
/* * Useful for when exported as folder or unzipped */ void doStart(Jar jar, String fqn) throws UnsupportedEncodingException { String nix = "#!/bin/sh\njava -cp . " + fqn + "\n"; String pc = "java -cp . " + fqn + "\r\n"; jar.putResource("start", new EmbeddedResource(nix, 0)); jar.putResource("start.bat", new EmbeddedResource(pc, 0)); }
/** * Create a standalone executable. All entries on the runpath are rolled out into the JAR and the * runbundles are copied to a directory in the jar. The launcher will see that it starts in * embedded mode and will automatically detect that it should load the bundles from inside. This * is drive by the launcher.embedded flag. * * @throws Exception */ @Override public Jar executable() throws Exception { // TODO use constants in the future Parameters packageHeader = OSGiHeader.parseHeader(project.getProperty("-package")); boolean useShas = packageHeader.containsKey("jpm"); project.trace("Useshas %s %s", useShas, packageHeader); Jar jar = new Jar(project.getName()); Builder b = new Builder(); project.addClose(b); if (!project.getIncludeResource().isEmpty()) { b.setIncludeResource(project.getIncludeResource().toString()); b.setProperty(Constants.RESOURCEONLY, "true"); b.build(); if (b.isOk()) { jar.addAll(b.getJar()); } project.getInfo(b); } List<String> runpath = getRunpath(); Set<String> runpathShas = new LinkedHashSet<String>(); Set<String> runbundleShas = new LinkedHashSet<String>(); List<String> classpath = new ArrayList<String>(); for (String path : runpath) { project.trace("embedding runpath %s", path); File file = new File(path); if (file.isFile()) { if (useShas) { String sha = SHA1.digest(file).asHex(); runpathShas.add(sha + ";name=\"" + file.getName() + "\""); } else { String newPath = "jar/" + file.getName(); jar.putResource(newPath, new FileResource(file)); classpath.add(newPath); } } } // Copy the bundles to the JAR List<String> runbundles = (List<String>) getRunBundles(); List<String> actualPaths = new ArrayList<String>(); for (String path : runbundles) { project.trace("embedding run bundles %s", path); File file = new File(path); if (!file.isFile()) project.error("Invalid entry in -runbundles %s", file); else { if (useShas) { String sha = SHA1.digest(file).asHex(); runbundleShas.add(sha + ";name=\"" + file.getName() + "\""); actualPaths.add("${JPMREPO}/" + sha); } else { String newPath = "jar/" + file.getName(); jar.putResource(newPath, new FileResource(file)); actualPaths.add(newPath); } } } LauncherConstants lc = getConstants(actualPaths, true); lc.embedded = !useShas; lc.storageDir = null; // cannot use local info final Properties p = lc.getProperties(new UTF8Properties()); ByteArrayOutputStream bout = new ByteArrayOutputStream(); p.store(bout, ""); jar.putResource( LauncherConstants.DEFAULT_LAUNCHER_PROPERTIES, new EmbeddedResource(bout.toByteArray(), 0L)); Manifest m = new Manifest(); Attributes main = m.getMainAttributes(); for (Entry<Object, Object> e : project.getFlattenedProperties().entrySet()) { String key = (String) e.getKey(); if (key.length() > 0 && Character.isUpperCase(key.charAt(0))) main.putValue(key, (String) e.getValue()); } Instructions instructions = new Instructions(project.getProperty(Constants.REMOVEHEADERS)); Collection<Object> result = instructions.select(main.keySet(), false); main.keySet().removeAll(result); if (useShas) { project.trace("Use JPM launcher"); m.getMainAttributes().putValue("Main-Class", JPM_LAUNCHER_FQN); m.getMainAttributes().putValue("JPM-Classpath", Processor.join(runpathShas)); m.getMainAttributes().putValue("JPM-Runbundles", Processor.join(runbundleShas)); URLResource jpmLauncher = new URLResource(this.getClass().getResource("/" + JPM_LAUNCHER)); jar.putResource(JPM_LAUNCHER, jpmLauncher); doStart(jar, JPM_LAUNCHER_FQN); } else { project.trace("Use Embedded launcher"); m.getMainAttributes().putValue("Main-Class", EMBEDDED_LAUNCHER_FQN); m.getMainAttributes().putValue(EmbeddedLauncher.EMBEDDED_RUNPATH, Processor.join(classpath)); URLResource embeddedLauncher = new URLResource(this.getClass().getResource("/" + EMBEDDED_LAUNCHER)); jar.putResource(EMBEDDED_LAUNCHER, embeddedLauncher); doStart(jar, EMBEDDED_LAUNCHER_FQN); } if (project.getProperty(Constants.DIGESTS) != null) jar.setDigestAlgorithms(project.getProperty(Constants.DIGESTS).trim().split("\\s*,\\s*")); else jar.setDigestAlgorithms(new String[] {"SHA-1", "MD-5"}); jar.setManifest(m); return jar; }
public void sign(Builder builder, String alias) throws Exception { File f = builder.getFile(keystore); if (!f.isFile()) { builder.error("Invalid keystore %s", f.getAbsolutePath()); return; } Jar jar = builder.getJar(); File tmp = File.createTempFile("signdjar", ".jar"); tmp.deleteOnExit(); jar.write(tmp); Command command = new Command(); command.add(path); if (keystore != null) { command.add("-keystore"); command.add(f.getAbsolutePath()); } if (storetype != null) { command.add("-storetype"); command.add(storetype); } if (keypass != null) { command.add("-keypass"); command.add(keypass); } if (storepass != null) { command.add("-storepass"); command.add(storepass); } if (sigFile != null) { command.add("-sigFile"); command.add(sigFile); } if (digestalg != null) { command.add("-digestalg"); command.add(digestalg); } command.add(tmp.getAbsolutePath()); command.add(alias); logger.debug("Jarsigner command: {}", command); command.setTimeout(20, TimeUnit.SECONDS); StringBuilder out = new StringBuilder(); StringBuilder err = new StringBuilder(); int exitValue = command.execute(out, err); if (exitValue != 0) { builder.error("Signing Jar out: %s%nerr: %s", out, err); } else { logger.debug("Signing Jar out: {}\nerr: {}", out, err); } Jar signed = new Jar(tmp); builder.addClose(signed); Map<String, Resource> dir = signed.getDirectories().get("META-INF"); for (Entry<String, Resource> entry : dir.entrySet()) { String path = entry.getKey(); if (path.matches(".*\\.(DSA|RSA|SF|MF)$")) { jar.putResource(path, entry.getValue()); } } jar.setDoNotTouchManifest(); }
@Override protected void doExecute() throws Exception { aQute.bnd.build.Project bndProject = getBndProject(); Builder builder = new Builder(bndProject); builder.setClasspath(_classpathFiles.toArray(new File[_classpathFiles.size()])); builder.setPedantic(isPedantic()); builder.setProperties(_file); builder.setSourcepath(new File[] {_sourcePath}); Jar[] jars = builder.builds(); // Report both task failures and bnd build failures boolean taskFailed = report(); boolean bndFailed = report(builder); // Fail this build if failure is not ok and either the task failed or // the bnd build failed if (taskFailed || bndFailed) { throw new BuildException( "bnd failed", new org.apache.tools.ant.Location(_file.getAbsolutePath())); } for (Jar jar : jars) { String bsn = jar.getName(); File outputFile = _outputPath; if (_outputPath.isDirectory()) { String path = builder.getProperty("-output"); if (path != null) { outputFile = getFile(_outputPath, path); } else { outputFile = getFile(_outputPath, bsn + ".jar"); } } if (!outputFile.exists() || (outputFile.lastModified() <= jar.lastModified())) { jar.write(outputFile); Map<String, Resource> resources = jar.getResources(); log(jar.getName() + " (" + outputFile.getName() + ") " + resources.size()); doBaselineJar(jar, outputFile, bndProject); } else { Map<String, Resource> resources = jar.getResources(); log( jar.getName() + " (" + outputFile.getName() + ") " + resources.size() + " (not modified)"); } report(); jar.close(); } builder.close(); }