X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=blobdiff_plain;f=org.argeo.init%2Fsrc%2Forg%2Fargeo%2Fapi%2Fa2%2FAbstractProvisioningSource.java;fp=org.argeo.init%2Fsrc%2Forg%2Fargeo%2Fapi%2Fa2%2FAbstractProvisioningSource.java;h=62416fe4848b66a331a3321d902ac8d7b79357c9;hp=0000000000000000000000000000000000000000;hb=b95462873703848193e56fcbe997693630db6121;hpb=55d88fba80cec198a0f11ba7545e19878c51fc5e diff --git a/org.argeo.init/src/org/argeo/api/a2/AbstractProvisioningSource.java b/org.argeo.init/src/org/argeo/api/a2/AbstractProvisioningSource.java new file mode 100644 index 000000000..62416fe48 --- /dev/null +++ b/org.argeo.init/src/org/argeo/api/a2/AbstractProvisioningSource.java @@ -0,0 +1,269 @@ +package org.argeo.api.a2; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Collections; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.Version; + +/** Where components are retrieved from. */ +public abstract class AbstractProvisioningSource implements ProvisioningSource { + protected final Map contributions = Collections.synchronizedSortedMap(new TreeMap<>()); + + private final boolean usingReference; + + public AbstractProvisioningSource(boolean usingReference) { + this.usingReference = usingReference; + } + + public Iterable listContributions(Object filter) { + return contributions.values(); + } + + @Override + public Bundle install(BundleContext bc, A2Module module) { + try { + Object locator = module.getLocator(); + if (usingReference && locator instanceof Path locatorPath) { + String referenceUrl = "reference:file:" + locatorPath.toString(); + Bundle bundle = bc.installBundle(referenceUrl); + return bundle; + } else { + Path locatorPath = (Path) locator; + Path pathToUse; + boolean isTemp = false; + if (locator instanceof Path && Files.isDirectory(locatorPath)) { + pathToUse = toTempJar(locatorPath); + isTemp = true; + } else { + pathToUse = locatorPath; + } + Bundle bundle; + try (InputStream in = newInputStream(pathToUse)) { + bundle = bc.installBundle(locatorPath.toAbsolutePath().toString(), in); + } + + if (isTemp && pathToUse != null) + Files.deleteIfExists(pathToUse); + return bundle; + } + } catch (BundleException | IOException e) { + throw new A2Exception("Cannot install module " + module, e); + } + } + + @Override + public void update(Bundle bundle, A2Module module) { + try { + Object locator = module.getLocator(); + if (usingReference && locator instanceof Path) { + try (InputStream in = newInputStream(locator)) { + bundle.update(in); + } + } else { + Path locatorPath = (Path) locator; + Path pathToUse; + boolean isTemp = false; + if (locator instanceof Path && Files.isDirectory(locatorPath)) { + pathToUse = toTempJar(locatorPath); + isTemp = true; + } else { + pathToUse = locatorPath; + } + try (InputStream in = newInputStream(pathToUse)) { + bundle.update(in); + } + if (isTemp && pathToUse != null) + Files.deleteIfExists(pathToUse); + } + } catch (BundleException | IOException e) { + throw new A2Exception("Cannot update module " + module, e); + } + } + + @Override + public A2Branch findBranch(String componentId, Version version) { + A2Component component = findComponent(componentId); + if (component == null) + return null; + String branchId = version.getMajor() + "." + version.getMinor(); + if (!component.branches.containsKey(branchId)) + return null; + return component.branches.get(branchId); + } + + protected A2Contribution getOrAddContribution(String contributionId) { + if (contributions.containsKey(contributionId)) + return contributions.get(contributionId); + else { + A2Contribution contribution = new A2Contribution(this, contributionId); + contributions.put(contributionId, contribution); + return contribution; + } + } + + protected void asTree(String prefix, StringBuffer buf) { + if (prefix == null) + prefix = ""; + for (String contributionId : contributions.keySet()) { + buf.append(prefix); + buf.append(contributionId); + buf.append('\n'); + A2Contribution contribution = contributions.get(contributionId); + contribution.asTree(prefix + " ", buf); + } + } + + protected void asTree() { + StringBuffer buf = new StringBuffer(); + asTree("", buf); + System.out.println(buf); + } + + protected A2Component findComponent(String componentId) { + SortedMap res = new TreeMap<>(); + for (A2Contribution contribution : contributions.values()) { + components: for (String componentIdKey : contribution.components.keySet()) { + if (componentId.equals(componentIdKey)) { + res.put(contribution, contribution.components.get(componentIdKey)); + break components; + } + } + } + if (res.size() == 0) + return null; + // TODO explicit contribution priorities + return res.get(res.lastKey()); + + } + + protected String[] readNameVersionFromModule(Path modulePath) { + Manifest manifest; + if (Files.isDirectory(modulePath)) { + manifest = findManifest(modulePath); + } else { + try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) { + manifest = in.getManifest(); + } catch (IOException e) { + throw new A2Exception("Cannot read manifest from " + modulePath, e); + } + } + String versionStr = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION); + String symbolicName = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME); + int semiColIndex = symbolicName.indexOf(';'); + if (semiColIndex >= 0) + symbolicName = symbolicName.substring(0, semiColIndex); + return new String[] { symbolicName, versionStr }; + } + + protected String readVersionFromModule(Path modulePath) { + Manifest manifest; + if (Files.isDirectory(modulePath)) { + manifest = findManifest(modulePath); + } else { + try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) { + manifest = in.getManifest(); + } catch (IOException e) { + throw new A2Exception("Cannot read manifest from " + modulePath, e); + } + } + String versionStr = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION); + return versionStr; + } + + protected String readSymbolicNameFromModule(Path modulePath) { + Manifest manifest; + if (Files.isDirectory(modulePath)) { + manifest = findManifest(modulePath); + } else { + try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) { + manifest = in.getManifest(); + } catch (IOException e) { + throw new A2Exception("Cannot read manifest from " + modulePath, e); + } + } + String symbolicName = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME); + int semiColIndex = symbolicName.indexOf(';'); + if (semiColIndex >= 0) + symbolicName = symbolicName.substring(0, semiColIndex); + return symbolicName; + } + + protected boolean isUsingReference() { + return usingReference; + } + + private InputStream newInputStream(Object locator) throws IOException { + if (locator instanceof Path) { + return Files.newInputStream((Path) locator); + } else if (locator instanceof URL) { + return ((URL) locator).openStream(); + } else { + throw new IllegalArgumentException("Unsupported module locator type " + locator.getClass()); + } + } + + private static Manifest findManifest(Path currentPath) { + Path metaInfPath = currentPath.resolve("META-INF"); + if (Files.exists(metaInfPath) && Files.isDirectory(metaInfPath)) { + Path manifestPath = metaInfPath.resolve("MANIFEST.MF"); + try { + try (InputStream in = Files.newInputStream(manifestPath)) { + Manifest manifest = new Manifest(in); + return manifest; + } + } catch (IOException e) { + throw new A2Exception("Cannot read manifest from " + manifestPath, e); + } + } else { + Path parentPath = currentPath.getParent(); + if (parentPath == null) + throw new A2Exception("MANIFEST.MF file not found."); + return findManifest(currentPath.getParent()); + } + } + + private static Path toTempJar(Path dir) { + try { + Manifest manifest = findManifest(dir); + Path jarPath = Files.createTempFile("a2Source", ".jar"); + try (JarOutputStream zos = new JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest)) { + Files.walkFileTree(dir, new SimpleFileVisitor() { + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Path relPath = dir.relativize(file); + // skip MANIFEST from folder + if (relPath.toString().contentEquals("META-INF/MANIFEST.MF")) + return FileVisitResult.CONTINUE; + zos.putNextEntry(new ZipEntry(relPath.toString())); + Files.copy(file, zos); + zos.closeEntry(); + return FileVisitResult.CONTINUE; + } + }); + } + return jarPath; + } catch (IOException e) { + throw new A2Exception("Cannot install OSGi bundle from " + dir, e); + } + + } + +}