]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.osgi.boot/src/org/argeo/osgi/a2/AbstractProvisioningSource.java
Merge remote-tracking branch 'origin/master' into v2.x
[lgpl/argeo-commons.git] / org.argeo.osgi.boot / src / org / argeo / osgi / a2 / AbstractProvisioningSource.java
1 package org.argeo.osgi.a2;
2
3 import java.io.FileOutputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.net.URL;
7 import java.nio.file.FileVisitResult;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.nio.file.SimpleFileVisitor;
11 import java.nio.file.attribute.BasicFileAttributes;
12 import java.util.Collections;
13 import java.util.Map;
14 import java.util.SortedMap;
15 import java.util.TreeMap;
16 import java.util.jar.JarInputStream;
17 import java.util.jar.JarOutputStream;
18 import java.util.jar.Manifest;
19 import java.util.zip.ZipEntry;
20
21 import org.osgi.framework.Bundle;
22 import org.osgi.framework.BundleContext;
23 import org.osgi.framework.BundleException;
24 import org.osgi.framework.Constants;
25 import org.osgi.framework.Version;
26
27 /** Where components are retrieved from. */
28 public abstract class AbstractProvisioningSource implements ProvisioningSource {
29 protected final Map<String, A2Contribution> contributions = Collections.synchronizedSortedMap(new TreeMap<>());
30
31 public Iterable<A2Contribution> listContributions(Object filter) {
32 return contributions.values();
33 }
34
35 @Override
36 public Bundle install(BundleContext bc, A2Module module) {
37 try {
38 Path tempJar = null;
39 if (module.getLocator() instanceof Path && Files.isDirectory((Path) module.getLocator()))
40 tempJar = toTempJar((Path) module.getLocator());
41 Bundle bundle;
42 try (InputStream in = newInputStream(tempJar != null ? tempJar : module.getLocator())) {
43 bundle = bc.installBundle(module.getBranch().getCoordinates(), in);
44 }
45 if (tempJar != null)
46 Files.deleteIfExists(tempJar);
47 return bundle;
48 } catch (BundleException | IOException e) {
49 throw new A2Exception("Cannot install module " + module, e);
50 }
51 }
52
53 @Override
54 public void update(Bundle bundle, A2Module module) {
55 try {
56 Path tempJar = null;
57 if (module.getLocator() instanceof Path && Files.isDirectory((Path) module.getLocator()))
58 tempJar = toTempJar((Path) module.getLocator());
59 try (InputStream in = newInputStream(tempJar != null ? tempJar : module.getLocator())) {
60 bundle.update(in);
61 }
62 if (tempJar != null)
63 Files.deleteIfExists(tempJar);
64 } catch (BundleException | IOException e) {
65 throw new A2Exception("Cannot update module " + module, e);
66 }
67 }
68
69 @Override
70 public A2Branch findBranch(String componentId, Version version) {
71 A2Component component = findComponent(componentId);
72 if (component == null)
73 return null;
74 String branchId = version.getMajor() + "." + version.getMinor();
75 if (!component.branches.containsKey(branchId))
76 return null;
77 return component.branches.get(branchId);
78 }
79
80 protected A2Contribution getOrAddContribution(String contributionId) {
81 if (contributions.containsKey(contributionId))
82 return contributions.get(contributionId);
83 else {
84 A2Contribution contribution = new A2Contribution(this, contributionId);
85 contributions.put(contributionId, contribution);
86 return contribution;
87 }
88 }
89
90 protected void asTree(String prefix, StringBuffer buf) {
91 if (prefix == null)
92 prefix = "";
93 for (String contributionId : contributions.keySet()) {
94 buf.append(prefix);
95 buf.append(contributionId);
96 buf.append('\n');
97 A2Contribution contribution = contributions.get(contributionId);
98 contribution.asTree(prefix + " ", buf);
99 }
100 }
101
102 protected void asTree() {
103 StringBuffer buf = new StringBuffer();
104 asTree("", buf);
105 System.out.println(buf);
106 }
107
108 protected A2Component findComponent(String componentId) {
109 SortedMap<A2Contribution, A2Component> res = new TreeMap<>();
110 for (A2Contribution contribution : contributions.values()) {
111 components: for (String componentIdKey : contribution.components.keySet()) {
112 if (componentId.equals(componentIdKey)) {
113 res.put(contribution, contribution.components.get(componentIdKey));
114 break components;
115 }
116 }
117 }
118 if (res.size() == 0)
119 return null;
120 // TODO explicit contribution priorities
121 return res.get(res.lastKey());
122
123 }
124
125 protected String readVersionFromModule(Path modulePath) {
126 Manifest manifest;
127 if (Files.isDirectory(modulePath)) {
128 manifest = findManifest(modulePath);
129 } else {
130 try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) {
131 manifest = in.getManifest();
132 } catch (IOException e) {
133 throw new A2Exception("Cannot read manifest from " + modulePath, e);
134 }
135 }
136 String versionStr = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
137 return versionStr;
138 }
139
140 protected String readSymbolicNameFromModule(Path modulePath) {
141 Manifest manifest;
142 if (Files.isDirectory(modulePath)) {
143 manifest = findManifest(modulePath);
144 } else {
145 try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) {
146 manifest = in.getManifest();
147 } catch (IOException e) {
148 throw new A2Exception("Cannot read manifest from " + modulePath, e);
149 }
150 }
151 String symbolicName = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
152 int semiColIndex = symbolicName.indexOf(';');
153 if (semiColIndex >= 0)
154 symbolicName = symbolicName.substring(0, semiColIndex);
155 return symbolicName;
156 }
157
158 private static Manifest findManifest(Path currentPath) {
159 Path metaInfPath = currentPath.resolve("META-INF");
160 if (Files.exists(metaInfPath) && Files.isDirectory(metaInfPath)) {
161 Path manifestPath = metaInfPath.resolve("MANIFEST.MF");
162 try {
163 try (InputStream in = Files.newInputStream(manifestPath)) {
164 Manifest manifest = new Manifest(in);
165 return manifest;
166 }
167 } catch (IOException e) {
168 throw new A2Exception("Cannot read manifest from " + manifestPath, e);
169 }
170 } else {
171 Path parentPath = currentPath.getParent();
172 if (parentPath == null)
173 throw new A2Exception("MANIFEST.MF file not found.");
174 return findManifest(currentPath.getParent());
175 }
176 }
177
178 private static Path toTempJar(Path dir) {
179 try {
180 Manifest manifest = findManifest(dir);
181 Path jarPath = Files.createTempFile("a2Source", ".jar");
182 try (JarOutputStream zos = new JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest)) {
183 Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
184 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
185 Path relPath = dir.relativize(file);
186 // skip MANIFEST from folder
187 if (relPath.toString().contentEquals("META-INF/MANIFEST.MF"))
188 return FileVisitResult.CONTINUE;
189 zos.putNextEntry(new ZipEntry(relPath.toString()));
190 Files.copy(file, zos);
191 zos.closeEntry();
192 return FileVisitResult.CONTINUE;
193 }
194 });
195 }
196 return jarPath;
197 } catch (IOException e) {
198 throw new A2Exception("Cannot install OSGi bundle from " + dir, e);
199 }
200
201 }
202
203 private InputStream newInputStream(Object locator) throws IOException {
204 if (locator instanceof Path) {
205 return Files.newInputStream((Path) locator);
206 } else if (locator instanceof URL) {
207 return ((URL) locator).openStream();
208 } else {
209 throw new IllegalArgumentException("Unsupported module locator type " + locator.getClass());
210 }
211 }
212 }