]> git.argeo.org Git - lgpl/argeo-commons.git/blob - AbstractProvisioningSource.java
7df851b2452c0d788c5618a9372238459d712021
[lgpl/argeo-commons.git] / AbstractProvisioningSource.java
1 package org.argeo.init.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 private final boolean useReference;
32
33 public AbstractProvisioningSource(boolean useReference) {
34 this.useReference = useReference;
35 }
36
37 public Iterable<A2Contribution> listContributions(Object filter) {
38 return contributions.values();
39 }
40
41 @Override
42 public Bundle install(BundleContext bc, A2Module module) {
43 try {
44 Object locator = module.getLocator();
45 if (useReference && locator instanceof Path locatorPath) {
46 String referenceUrl = "reference:file:" + locatorPath.toString();
47 Bundle bundle = bc.installBundle(referenceUrl);
48 return bundle;
49 } else {
50
51 Path tempJar = null;
52 if (locator instanceof Path && Files.isDirectory((Path) locator))
53 tempJar = toTempJar((Path) locator);
54 Bundle bundle;
55 try (InputStream in = newInputStream(tempJar != null ? tempJar : locator)) {
56 bundle = bc.installBundle(module.getBranch().getCoordinates(), in);
57 }
58
59 if (tempJar != null)
60 Files.deleteIfExists(tempJar);
61 return bundle;
62 }
63 } catch (BundleException | IOException e) {
64 throw new A2Exception("Cannot install module " + module, e);
65 }
66 }
67
68 @Override
69 public void update(Bundle bundle, A2Module module) {
70 try {
71 Object locator = module.getLocator();
72 if (useReference && locator instanceof Path) {
73 try (InputStream in = newInputStream(locator)) {
74 bundle.update(in);
75 }
76 } else {
77 Path tempJar = null;
78 if (locator instanceof Path && Files.isDirectory((Path) locator))
79 tempJar = toTempJar((Path) locator);
80 try (InputStream in = newInputStream(tempJar != null ? tempJar : locator)) {
81 bundle.update(in);
82 }
83 if (tempJar != null)
84 Files.deleteIfExists(tempJar);
85 }
86 } catch (BundleException | IOException e) {
87 throw new A2Exception("Cannot update module " + module, e);
88 }
89 }
90
91 @Override
92 public A2Branch findBranch(String componentId, Version version) {
93 A2Component component = findComponent(componentId);
94 if (component == null)
95 return null;
96 String branchId = version.getMajor() + "." + version.getMinor();
97 if (!component.branches.containsKey(branchId))
98 return null;
99 return component.branches.get(branchId);
100 }
101
102 protected A2Contribution getOrAddContribution(String contributionId) {
103 if (contributions.containsKey(contributionId))
104 return contributions.get(contributionId);
105 else {
106 A2Contribution contribution = new A2Contribution(this, contributionId);
107 contributions.put(contributionId, contribution);
108 return contribution;
109 }
110 }
111
112 protected void asTree(String prefix, StringBuffer buf) {
113 if (prefix == null)
114 prefix = "";
115 for (String contributionId : contributions.keySet()) {
116 buf.append(prefix);
117 buf.append(contributionId);
118 buf.append('\n');
119 A2Contribution contribution = contributions.get(contributionId);
120 contribution.asTree(prefix + " ", buf);
121 }
122 }
123
124 protected void asTree() {
125 StringBuffer buf = new StringBuffer();
126 asTree("", buf);
127 System.out.println(buf);
128 }
129
130 protected A2Component findComponent(String componentId) {
131 SortedMap<A2Contribution, A2Component> res = new TreeMap<>();
132 for (A2Contribution contribution : contributions.values()) {
133 components: for (String componentIdKey : contribution.components.keySet()) {
134 if (componentId.equals(componentIdKey)) {
135 res.put(contribution, contribution.components.get(componentIdKey));
136 break components;
137 }
138 }
139 }
140 if (res.size() == 0)
141 return null;
142 // TODO explicit contribution priorities
143 return res.get(res.lastKey());
144
145 }
146
147 protected String[] readNameVersionFromModule(Path modulePath) {
148 Manifest manifest;
149 if (Files.isDirectory(modulePath)) {
150 manifest = findManifest(modulePath);
151 } else {
152 try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) {
153 manifest = in.getManifest();
154 } catch (IOException e) {
155 throw new A2Exception("Cannot read manifest from " + modulePath, e);
156 }
157 }
158 String versionStr = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
159 String symbolicName = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
160 int semiColIndex = symbolicName.indexOf(';');
161 if (semiColIndex >= 0)
162 symbolicName = symbolicName.substring(0, semiColIndex);
163 return new String[] { symbolicName, versionStr };
164 }
165
166 protected String readVersionFromModule(Path modulePath) {
167 Manifest manifest;
168 if (Files.isDirectory(modulePath)) {
169 manifest = findManifest(modulePath);
170 } else {
171 try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) {
172 manifest = in.getManifest();
173 } catch (IOException e) {
174 throw new A2Exception("Cannot read manifest from " + modulePath, e);
175 }
176 }
177 String versionStr = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
178 return versionStr;
179 }
180
181 protected String readSymbolicNameFromModule(Path modulePath) {
182 Manifest manifest;
183 if (Files.isDirectory(modulePath)) {
184 manifest = findManifest(modulePath);
185 } else {
186 try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) {
187 manifest = in.getManifest();
188 } catch (IOException e) {
189 throw new A2Exception("Cannot read manifest from " + modulePath, e);
190 }
191 }
192 String symbolicName = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
193 int semiColIndex = symbolicName.indexOf(';');
194 if (semiColIndex >= 0)
195 symbolicName = symbolicName.substring(0, semiColIndex);
196 return symbolicName;
197 }
198
199 private static Manifest findManifest(Path currentPath) {
200 Path metaInfPath = currentPath.resolve("META-INF");
201 if (Files.exists(metaInfPath) && Files.isDirectory(metaInfPath)) {
202 Path manifestPath = metaInfPath.resolve("MANIFEST.MF");
203 try {
204 try (InputStream in = Files.newInputStream(manifestPath)) {
205 Manifest manifest = new Manifest(in);
206 return manifest;
207 }
208 } catch (IOException e) {
209 throw new A2Exception("Cannot read manifest from " + manifestPath, e);
210 }
211 } else {
212 Path parentPath = currentPath.getParent();
213 if (parentPath == null)
214 throw new A2Exception("MANIFEST.MF file not found.");
215 return findManifest(currentPath.getParent());
216 }
217 }
218
219 private static Path toTempJar(Path dir) {
220 try {
221 Manifest manifest = findManifest(dir);
222 Path jarPath = Files.createTempFile("a2Source", ".jar");
223 try (JarOutputStream zos = new JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest)) {
224 Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
225 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
226 Path relPath = dir.relativize(file);
227 // skip MANIFEST from folder
228 if (relPath.toString().contentEquals("META-INF/MANIFEST.MF"))
229 return FileVisitResult.CONTINUE;
230 zos.putNextEntry(new ZipEntry(relPath.toString()));
231 Files.copy(file, zos);
232 zos.closeEntry();
233 return FileVisitResult.CONTINUE;
234 }
235 });
236 }
237 return jarPath;
238 } catch (IOException e) {
239 throw new A2Exception("Cannot install OSGi bundle from " + dir, e);
240 }
241
242 }
243
244 private InputStream newInputStream(Object locator) throws IOException {
245 if (locator instanceof Path) {
246 return Files.newInputStream((Path) locator);
247 } else if (locator instanceof URL) {
248 return ((URL) locator).openStream();
249 } else {
250 throw new IllegalArgumentException("Unsupported module locator type " + locator.getClass());
251 }
252 }
253 }