1 package org
.argeo
.init
.osgi
;
3 import static java
.lang
.System
.Logger
.Level
.WARNING
;
5 import java
.io
.BufferedReader
;
6 import java
.io
.IOException
;
7 import java
.io
.InputStream
;
8 import java
.io
.InputStreamReader
;
9 import java
.lang
.System
.Logger
;
11 import java
.net
.URISyntaxException
;
13 import java
.nio
.file
.DirectoryStream
;
14 import java
.nio
.file
.Files
;
15 import java
.nio
.file
.Path
;
16 import java
.nio
.file
.PathMatcher
;
17 import java
.nio
.file
.Paths
;
18 import java
.util
.ArrayList
;
19 import java
.util
.List
;
20 import java
.util
.SortedMap
;
21 import java
.util
.StringTokenizer
;
22 import java
.util
.TreeMap
;
23 import java
.util
.jar
.JarEntry
;
24 import java
.util
.jar
.JarInputStream
;
25 import java
.util
.jar
.Manifest
;
27 import org
.osgi
.framework
.Constants
;
28 import org
.osgi
.framework
.Version
;
31 * A distribution bundle is a bundle within a maven-like distribution
32 * groupId:Bundle-SymbolicName:Bundle-Version which references others OSGi
33 * bundle. It is not required to be OSGi complete also it will generally be
34 * expected that it is. The root of the repository is computed based on the file
35 * name of the URL and of the content of the index.
37 public class DistributionBundle
{
38 private final static Logger logger
= System
.getLogger(DistributionBundle
.class.getName());
40 private final static String INDEX_FILE_NAME
= "modularDistribution.csv";
42 private final String url
;
44 private Manifest manifest
;
45 private String symbolicName
;
46 private String version
;
49 private String baseUrl
;
51 private String relativeUrl
;
52 private String localCache
;
54 private List
<OsgiArtifact
> artifacts
;
56 private String separator
= ",";
58 public DistributionBundle(String url
) {
62 public DistributionBundle(String baseUrl
, String relativeUrl
, String localCache
) {
63 if (baseUrl
== null || !baseUrl
.endsWith("/"))
64 throw new IllegalArgumentException("Base url " + baseUrl
+ " badly formatted");
65 if (relativeUrl
.startsWith("http") || relativeUrl
.startsWith("file:"))
66 throw new IllegalArgumentException("Relative URL " + relativeUrl
+ " badly formatted");
67 this.url
= constructUrl(baseUrl
, relativeUrl
);
68 this.baseUrl
= baseUrl
;
69 this.relativeUrl
= relativeUrl
;
70 this.localCache
= localCache
;
73 protected String
constructUrl(String baseUrl
, String relativeUrl
) {
75 if (relativeUrl
.indexOf('*') >= 0) {
76 if (!baseUrl
.startsWith("file:"))
77 throw new IllegalArgumentException(
78 "Wildcard support only for file:, badly formatted " + baseUrl
+ " and " + relativeUrl
);
79 Path basePath
= Paths
.get(new URI(baseUrl
));
80 // Path basePath = Paths.get(new URI(baseUrl));
81 // int li = relativeUrl.lastIndexOf('/');
82 // String relativeDir = relativeUrl.substring(0, li);
83 // String relativeFile = relativeUrl.substring(li,
84 // relativeUrl.length());
85 String pattern
= "glob:" + basePath
+ '/' + relativeUrl
;
86 PathMatcher pm
= basePath
.getFileSystem().getPathMatcher(pattern
);
87 SortedMap
<Version
, Path
> res
= new TreeMap
<>();
88 checkDir(basePath
, pm
, res
);
90 throw new IllegalArgumentException("No file matching " + relativeUrl
+ " found in " + baseUrl
);
91 return res
.get(res
.firstKey()).toUri().toString();
93 return baseUrl
+ relativeUrl
;
95 } catch (Exception e
) {
96 throw new RuntimeException("Cannot build URL from " + baseUrl
+ " and " + relativeUrl
, e
);
100 private void checkDir(Path dir
, PathMatcher pm
, SortedMap
<Version
, Path
> res
) throws IOException
{
101 try (DirectoryStream
<Path
> ds
= Files
.newDirectoryStream(dir
)) {
102 for (Path path
: ds
) {
103 if (Files
.isDirectory(path
))
104 checkDir(path
, pm
, res
);
105 else if (pm
.matches(path
)) {
106 String fileName
= path
.getFileName().toString();
107 fileName
= fileName
.substring(0, fileName
.lastIndexOf('.'));
108 if (fileName
.endsWith("-SNAPSHOT"))
109 fileName
= fileName
.substring(0, fileName
.lastIndexOf('-')) + ".SNAPSHOT";
110 fileName
= fileName
.substring(fileName
.lastIndexOf('-') + 1);
111 Version version
= new Version(fileName
);
112 res
.put(version
, path
);
118 public void processUrl() {
119 JarInputStream jarIn
= null;
121 URL u
= new URI(url
).toURL();
124 URI localUri
= new URI(localCache
+ relativeUrl
);
125 Path localPath
= Paths
.get(localUri
);
126 if (Files
.exists(localPath
))
127 u
= localUri
.toURL();
128 jarIn
= new JarInputStream(u
.openStream());
131 manifest
= jarIn
.getManifest();
132 symbolicName
= manifest
.getMainAttributes().getValue(Constants
.BUNDLE_SYMBOLICNAME
);
133 version
= manifest
.getMainAttributes().getValue(Constants
.BUNDLE_VERSION
);
136 while ((indexEntry
= jarIn
.getNextJarEntry()) != null) {
137 String entryName
= indexEntry
.getName();
138 if (entryName
.equals(INDEX_FILE_NAME
)) {
145 if (indexEntry
== null)
146 throw new IllegalArgumentException("No index " + INDEX_FILE_NAME
+ " in " + url
);
147 artifacts
= listArtifacts(jarIn
);
151 // won't work if distribution artifact is not listed
152 for (int i
= 0; i
< artifacts
.size(); i
++) {
153 OsgiArtifact osgiArtifact
= (OsgiArtifact
) artifacts
.get(i
);
154 if (osgiArtifact
.getSymbolicName().equals(symbolicName
) && osgiArtifact
.getVersion().equals(version
)) {
155 String relativeUrl
= osgiArtifact
.getRelativeUrl();
156 if (url
.endsWith(relativeUrl
)) {
157 baseUrl
= url
.substring(0, url
.length() - osgiArtifact
.getRelativeUrl().length());
162 } catch (Exception e
) {
163 throw new RuntimeException("Cannot list URLs from " + url
, e
);
168 } catch (IOException e
) {
174 protected List
<OsgiArtifact
> listArtifacts(InputStream in
) {
175 List
<OsgiArtifact
> osgiArtifacts
= new ArrayList
<OsgiArtifact
>();
176 BufferedReader reader
= null;
178 reader
= new BufferedReader(new InputStreamReader(in
));
180 lines
: while ((line
= reader
.readLine()) != null) {
181 StringTokenizer st
= new StringTokenizer(line
, separator
);
182 String moduleName
= st
.nextToken();
183 String moduleVersion
= st
.nextToken();
184 String relativeUrl
= st
.nextToken();
185 if (relativeUrl
.endsWith(".pom"))
187 osgiArtifacts
.add(new OsgiArtifact(moduleName
, moduleVersion
, relativeUrl
));
189 } catch (Exception e
) {
190 throw new RuntimeException("Cannot list artifacts", e
);
192 return osgiArtifacts
;
195 /** Convenience method */
196 public static DistributionBundle
processUrl(String baseUrl
, String relativeUrl
, String localCache
) {
197 DistributionBundle distributionBundle
= new DistributionBundle(baseUrl
, relativeUrl
, localCache
);
198 distributionBundle
.processUrl();
199 return distributionBundle
;
203 * List full URLs of the bundles, based on base URL, usable directly for
206 public List
<String
> listUrls() {
208 throw new IllegalArgumentException("Base URL is not set");
210 if (artifacts
== null)
211 throw new IllegalStateException("Artifact list not initialized");
213 List
<String
> urls
= new ArrayList
<String
>();
214 for (int i
= 0; i
< artifacts
.size(); i
++) {
215 OsgiArtifact osgiArtifact
= (OsgiArtifact
) artifacts
.get(i
);
219 localUri
= new URI(localCache
+ relativeUrl
);
220 } catch (URISyntaxException e
) {
221 logger
.log(WARNING
, e
.getMessage());
224 Version version
= new Version(osgiArtifact
.getVersion());
225 if (localUri
!= null && Files
.exists(Paths
.get(localUri
)) && version
.getQualifier() != null
226 && version
.getQualifier().startsWith("SNAPSHOT")) {
227 urls
.add(localCache
+ osgiArtifact
.getRelativeUrl());
229 urls
.add(baseUrl
+ osgiArtifact
.getRelativeUrl());
235 public void setBaseUrl(String baseUrl
) {
236 this.baseUrl
= baseUrl
;
239 /** Separator used to parse the tabular file */
240 public void setSeparator(String modulesUrlSeparator
) {
241 this.separator
= modulesUrlSeparator
;
244 public String
getRelativeUrl() {
248 /** One of the listed artifact */
249 protected static class OsgiArtifact
{
250 private final String symbolicName
;
251 private final String version
;
252 private final String relativeUrl
;
254 public OsgiArtifact(String symbolicName
, String version
, String relativeUrl
) {
256 this.symbolicName
= symbolicName
;
257 this.version
= version
;
258 this.relativeUrl
= relativeUrl
;
261 public String
getSymbolicName() {
265 public String
getVersion() {
269 public String
getRelativeUrl() {