1 package org
.argeo
.osgi
.boot
;
3 import java
.io
.BufferedReader
;
4 import java
.io
.IOException
;
5 import java
.io
.InputStream
;
6 import java
.io
.InputStreamReader
;
8 import java
.net
.URISyntaxException
;
10 import java
.nio
.file
.DirectoryStream
;
11 import java
.nio
.file
.Files
;
12 import java
.nio
.file
.Path
;
13 import java
.nio
.file
.PathMatcher
;
14 import java
.nio
.file
.Paths
;
15 import java
.util
.ArrayList
;
16 import java
.util
.List
;
17 import java
.util
.SortedMap
;
18 import java
.util
.StringTokenizer
;
19 import java
.util
.TreeMap
;
20 import java
.util
.jar
.JarEntry
;
21 import java
.util
.jar
.JarInputStream
;
22 import java
.util
.jar
.Manifest
;
24 import org
.osgi
.framework
.Constants
;
25 import org
.osgi
.framework
.Version
;
28 * A distribution bundle is a bundle within a maven-like distribution
29 * groupId:Bundle-SymbolicName:Bundle-Version which references others OSGi
30 * bundle. It is not required to be OSGi complete also it will generally be
31 * expected that it is. The root of the repository is computed based on the file
32 * name of the URL and of the content of the index.
34 public class DistributionBundle
{
35 private final static String INDEX_FILE_NAME
= "modularDistribution.csv";
37 private final String url
;
39 private Manifest manifest
;
40 private String symbolicName
;
41 private String version
;
44 private String baseUrl
;
46 private String relativeUrl
;
47 private String localCache
;
49 private List
<OsgiArtifact
> artifacts
;
51 private String separator
= ",";
53 public DistributionBundle(String url
) {
57 public DistributionBundle(String baseUrl
, String relativeUrl
, String localCache
) {
58 if (baseUrl
== null || !baseUrl
.endsWith("/"))
59 throw new OsgiBootException("Base url " + baseUrl
+ " badly formatted");
60 if (relativeUrl
.startsWith("http") || relativeUrl
.startsWith("file:"))
61 throw new OsgiBootException("Relative URL " + relativeUrl
+ " badly formatted");
62 this.url
= constructUrl(baseUrl
, relativeUrl
);
63 this.baseUrl
= baseUrl
;
64 this.relativeUrl
= relativeUrl
;
65 this.localCache
= localCache
;
68 protected String
constructUrl(String baseUrl
, String relativeUrl
) {
70 if (relativeUrl
.indexOf('*') >= 0) {
71 if (!baseUrl
.startsWith("file:"))
72 throw new IllegalArgumentException(
73 "Wildcard support only for file:, badly formatted " + baseUrl
+ " and " + relativeUrl
);
74 Path basePath
= Paths
.get(new URI(baseUrl
));
75 // Path basePath = Paths.get(new URI(baseUrl));
76 // int li = relativeUrl.lastIndexOf('/');
77 // String relativeDir = relativeUrl.substring(0, li);
78 // String relativeFile = relativeUrl.substring(li,
79 // relativeUrl.length());
80 String pattern
= "glob:" + basePath
+ '/' + relativeUrl
;
81 PathMatcher pm
= basePath
.getFileSystem().getPathMatcher(pattern
);
82 SortedMap
<Version
, Path
> res
= new TreeMap
<>();
83 checkDir(basePath
, pm
, res
);
85 throw new OsgiBootException("No file matching " + relativeUrl
+ " found in " + baseUrl
);
86 return res
.get(res
.firstKey()).toUri().toString();
88 return baseUrl
+ relativeUrl
;
90 } catch (Exception e
) {
91 throw new OsgiBootException("Cannot build URL from " + baseUrl
+ " and " + relativeUrl
, e
);
95 private void checkDir(Path dir
, PathMatcher pm
, SortedMap
<Version
, Path
> res
) throws IOException
{
96 try (DirectoryStream
<Path
> ds
= Files
.newDirectoryStream(dir
)) {
97 for (Path path
: ds
) {
98 if (Files
.isDirectory(path
))
99 checkDir(path
, pm
, res
);
100 else if (pm
.matches(path
)) {
101 String fileName
= path
.getFileName().toString();
102 fileName
= fileName
.substring(0, fileName
.lastIndexOf('.'));
103 if (fileName
.endsWith("-SNAPSHOT"))
104 fileName
= fileName
.substring(0, fileName
.lastIndexOf('-')) + ".SNAPSHOT";
105 fileName
= fileName
.substring(fileName
.lastIndexOf('-') + 1);
106 Version version
= new Version(fileName
);
107 res
.put(version
, path
);
113 public void processUrl() {
114 JarInputStream jarIn
= null;
116 URL u
= new URL(url
);
119 URI localUri
= new URI(localCache
+ relativeUrl
);
120 Path localPath
= Paths
.get(localUri
);
121 if (Files
.exists(localPath
))
122 u
= localUri
.toURL();
123 jarIn
= new JarInputStream(u
.openStream());
126 manifest
= jarIn
.getManifest();
127 symbolicName
= manifest
.getMainAttributes().getValue(Constants
.BUNDLE_SYMBOLICNAME
);
128 version
= manifest
.getMainAttributes().getValue(Constants
.BUNDLE_VERSION
);
131 while ((indexEntry
= jarIn
.getNextJarEntry()) != null) {
132 String entryName
= indexEntry
.getName();
133 if (entryName
.equals(INDEX_FILE_NAME
)) {
140 if (indexEntry
== null)
141 throw new OsgiBootException("No index " + INDEX_FILE_NAME
+ " in " + url
);
142 artifacts
= listArtifacts(jarIn
);
146 // won't work if distribution artifact is not listed
147 for (int i
= 0; i
< artifacts
.size(); i
++) {
148 OsgiArtifact osgiArtifact
= (OsgiArtifact
) artifacts
.get(i
);
149 if (osgiArtifact
.getSymbolicName().equals(symbolicName
) && osgiArtifact
.getVersion().equals(version
)) {
150 String relativeUrl
= osgiArtifact
.getRelativeUrl();
151 if (url
.endsWith(relativeUrl
)) {
152 baseUrl
= url
.substring(0, url
.length() - osgiArtifact
.getRelativeUrl().length());
157 } catch (Exception e
) {
158 throw new OsgiBootException("Cannot list URLs from " + url
, e
);
163 } catch (IOException e
) {
169 protected List
<OsgiArtifact
> listArtifacts(InputStream in
) {
170 List
<OsgiArtifact
> osgiArtifacts
= new ArrayList
<OsgiArtifact
>();
171 BufferedReader reader
= null;
173 reader
= new BufferedReader(new InputStreamReader(in
));
175 lines
: while ((line
= reader
.readLine()) != null) {
176 StringTokenizer st
= new StringTokenizer(line
, separator
);
177 String moduleName
= st
.nextToken();
178 String moduleVersion
= st
.nextToken();
179 String relativeUrl
= st
.nextToken();
180 if (relativeUrl
.endsWith(".pom"))
182 osgiArtifacts
.add(new OsgiArtifact(moduleName
, moduleVersion
, relativeUrl
));
184 } catch (Exception e
) {
185 throw new OsgiBootException("Cannot list artifacts", e
);
187 return osgiArtifacts
;
190 /** Convenience method */
191 public static DistributionBundle
processUrl(String baseUrl
, String relativeUrl
, String localCache
) {
192 DistributionBundle distributionBundle
= new DistributionBundle(baseUrl
, relativeUrl
, localCache
);
193 distributionBundle
.processUrl();
194 return distributionBundle
;
198 * List full URLs of the bundles, based on base URL, usable directly for
201 public List
<String
> listUrls() {
203 throw new OsgiBootException("Base URL is not set");
205 if (artifacts
== null)
206 throw new OsgiBootException("Artifact list not initialized");
208 List
<String
> urls
= new ArrayList
<String
>();
209 for (int i
= 0; i
< artifacts
.size(); i
++) {
210 OsgiArtifact osgiArtifact
= (OsgiArtifact
) artifacts
.get(i
);
214 localUri
= new URI(localCache
+ relativeUrl
);
215 } catch (URISyntaxException e
) {
216 OsgiBootUtils
.warn(e
.getMessage());
219 Version version
= new Version(osgiArtifact
.getVersion());
220 if (localUri
!= null && Files
.exists(Paths
.get(localUri
)) && version
.getQualifier() != null
221 && version
.getQualifier().startsWith("SNAPSHOT")) {
222 urls
.add(localCache
+ osgiArtifact
.getRelativeUrl());
224 urls
.add(baseUrl
+ osgiArtifact
.getRelativeUrl());
230 public void setBaseUrl(String baseUrl
) {
231 this.baseUrl
= baseUrl
;
234 /** Separator used to parse the tabular file */
235 public void setSeparator(String modulesUrlSeparator
) {
236 this.separator
= modulesUrlSeparator
;
239 public String
getRelativeUrl() {
243 /** One of the listed artifact */
244 protected static class OsgiArtifact
{
245 private final String symbolicName
;
246 private final String version
;
247 private final String relativeUrl
;
249 public OsgiArtifact(String symbolicName
, String version
, String relativeUrl
) {
251 this.symbolicName
= symbolicName
;
252 this.version
= version
;
253 this.relativeUrl
= relativeUrl
;
256 public String
getSymbolicName() {
260 public String
getVersion() {
264 public String
getRelativeUrl() {