1 package org
.argeo
.api
.a2
;
3 import java
.io
.FileOutputStream
;
4 import java
.io
.IOException
;
5 import java
.io
.InputStream
;
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
;
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
;
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
;
27 /** Where components are retrieved from. */
28 public abstract class AbstractProvisioningSource
implements ProvisioningSource
{
29 protected final Map
<String
, A2Contribution
> contributions
= Collections
.synchronizedSortedMap(new TreeMap
<>());
31 private final boolean usingReference
;
33 public AbstractProvisioningSource(boolean usingReference
) {
34 this.usingReference
= usingReference
;
37 public Iterable
<A2Contribution
> listContributions(Object filter
) {
38 return contributions
.values();
42 public Bundle
install(BundleContext bc
, A2Module module
) {
44 Object locator
= module
.getLocator();
45 if (usingReference
&& locator
instanceof Path locatorPath
) {
46 String referenceUrl
= "reference:file:" + locatorPath
.toString();
47 Bundle bundle
= bc
.installBundle(referenceUrl
);
50 Path locatorPath
= (Path
) locator
;
52 boolean isTemp
= false;
53 if (locator
instanceof Path
&& Files
.isDirectory(locatorPath
)) {
54 pathToUse
= toTempJar(locatorPath
);
57 pathToUse
= locatorPath
;
60 try (InputStream in
= newInputStream(pathToUse
)) {
61 bundle
= bc
.installBundle(locatorPath
.toAbsolutePath().toString(), in
);
64 if (isTemp
&& pathToUse
!= null)
65 Files
.deleteIfExists(pathToUse
);
68 } catch (BundleException
| IOException e
) {
69 throw new A2Exception("Cannot install module " + module
, e
);
74 public void update(Bundle bundle
, A2Module module
) {
76 Object locator
= module
.getLocator();
77 if (usingReference
&& locator
instanceof Path
) {
78 try (InputStream in
= newInputStream(locator
)) {
82 Path locatorPath
= (Path
) locator
;
84 boolean isTemp
= false;
85 if (locator
instanceof Path
&& Files
.isDirectory(locatorPath
)) {
86 pathToUse
= toTempJar(locatorPath
);
89 pathToUse
= locatorPath
;
91 try (InputStream in
= newInputStream(pathToUse
)) {
94 if (isTemp
&& pathToUse
!= null)
95 Files
.deleteIfExists(pathToUse
);
97 } catch (BundleException
| IOException e
) {
98 throw new A2Exception("Cannot update module " + module
, e
);
103 public A2Branch
findBranch(String componentId
, Version version
) {
104 A2Component component
= findComponent(componentId
);
105 if (component
== null)
107 String branchId
= version
.getMajor() + "." + version
.getMinor();
108 if (!component
.branches
.containsKey(branchId
))
110 return component
.branches
.get(branchId
);
113 protected A2Contribution
getOrAddContribution(String contributionId
) {
114 if (contributions
.containsKey(contributionId
))
115 return contributions
.get(contributionId
);
117 A2Contribution contribution
= new A2Contribution(this, contributionId
);
118 contributions
.put(contributionId
, contribution
);
123 protected void asTree(String prefix
, StringBuffer buf
) {
126 for (String contributionId
: contributions
.keySet()) {
128 buf
.append(contributionId
);
130 A2Contribution contribution
= contributions
.get(contributionId
);
131 contribution
.asTree(prefix
+ " ", buf
);
135 protected void asTree() {
136 StringBuffer buf
= new StringBuffer();
138 System
.out
.println(buf
);
141 protected A2Component
findComponent(String componentId
) {
142 SortedMap
<A2Contribution
, A2Component
> res
= new TreeMap
<>();
143 for (A2Contribution contribution
: contributions
.values()) {
144 components
: for (String componentIdKey
: contribution
.components
.keySet()) {
145 if (componentId
.equals(componentIdKey
)) {
146 res
.put(contribution
, contribution
.components
.get(componentIdKey
));
153 // TODO explicit contribution priorities
154 return res
.get(res
.lastKey());
158 protected String
[] readNameVersionFromModule(Path modulePath
) {
160 if (Files
.isDirectory(modulePath
)) {
161 manifest
= findManifest(modulePath
);
163 try (JarInputStream in
= new JarInputStream(newInputStream(modulePath
))) {
164 manifest
= in
.getManifest();
165 } catch (IOException e
) {
166 throw new A2Exception("Cannot read manifest from " + modulePath
, e
);
169 String versionStr
= manifest
.getMainAttributes().getValue(Constants
.BUNDLE_VERSION
);
170 String symbolicName
= manifest
.getMainAttributes().getValue(Constants
.BUNDLE_SYMBOLICNAME
);
171 int semiColIndex
= symbolicName
.indexOf(';');
172 if (semiColIndex
>= 0)
173 symbolicName
= symbolicName
.substring(0, semiColIndex
);
174 return new String
[] { symbolicName
, versionStr
};
177 protected String
readVersionFromModule(Path modulePath
) {
179 if (Files
.isDirectory(modulePath
)) {
180 manifest
= findManifest(modulePath
);
182 try (JarInputStream in
= new JarInputStream(newInputStream(modulePath
))) {
183 manifest
= in
.getManifest();
184 } catch (IOException e
) {
185 throw new A2Exception("Cannot read manifest from " + modulePath
, e
);
188 String versionStr
= manifest
.getMainAttributes().getValue(Constants
.BUNDLE_VERSION
);
192 protected String
readSymbolicNameFromModule(Path modulePath
) {
194 if (Files
.isDirectory(modulePath
)) {
195 manifest
= findManifest(modulePath
);
197 try (JarInputStream in
= new JarInputStream(newInputStream(modulePath
))) {
198 manifest
= in
.getManifest();
199 } catch (IOException e
) {
200 throw new A2Exception("Cannot read manifest from " + modulePath
, e
);
203 String symbolicName
= manifest
.getMainAttributes().getValue(Constants
.BUNDLE_SYMBOLICNAME
);
204 int semiColIndex
= symbolicName
.indexOf(';');
205 if (semiColIndex
>= 0)
206 symbolicName
= symbolicName
.substring(0, semiColIndex
);
210 protected boolean isUsingReference() {
211 return usingReference
;
214 private InputStream
newInputStream(Object locator
) throws IOException
{
215 if (locator
instanceof Path
) {
216 return Files
.newInputStream((Path
) locator
);
217 } else if (locator
instanceof URL
) {
218 return ((URL
) locator
).openStream();
220 throw new IllegalArgumentException("Unsupported module locator type " + locator
.getClass());
224 private static Manifest
findManifest(Path currentPath
) {
225 Path metaInfPath
= currentPath
.resolve("META-INF");
226 if (Files
.exists(metaInfPath
) && Files
.isDirectory(metaInfPath
)) {
227 Path manifestPath
= metaInfPath
.resolve("MANIFEST.MF");
229 try (InputStream in
= Files
.newInputStream(manifestPath
)) {
230 Manifest manifest
= new Manifest(in
);
233 } catch (IOException e
) {
234 throw new A2Exception("Cannot read manifest from " + manifestPath
, e
);
237 Path parentPath
= currentPath
.getParent();
238 if (parentPath
== null)
239 throw new A2Exception("MANIFEST.MF file not found.");
240 return findManifest(currentPath
.getParent());
244 private static Path
toTempJar(Path dir
) {
246 Manifest manifest
= findManifest(dir
);
247 Path jarPath
= Files
.createTempFile("a2Source", ".jar");
248 try (JarOutputStream zos
= new JarOutputStream(new FileOutputStream(jarPath
.toFile()), manifest
)) {
249 Files
.walkFileTree(dir
, new SimpleFileVisitor
<Path
>() {
250 public FileVisitResult
visitFile(Path file
, BasicFileAttributes attrs
) throws IOException
{
251 Path relPath
= dir
.relativize(file
);
252 // skip MANIFEST from folder
253 if (relPath
.toString().contentEquals("META-INF/MANIFEST.MF"))
254 return FileVisitResult
.CONTINUE
;
255 zos
.putNextEntry(new ZipEntry(relPath
.toString()));
256 Files
.copy(file
, zos
);
258 return FileVisitResult
.CONTINUE
;
263 } catch (IOException e
) {
264 throw new A2Exception("Cannot install OSGi bundle from " + dir
, e
);