1 package org
.argeo
.slc
.repo
;
3 import java
.io
.ByteArrayInputStream
;
4 import java
.io
.ByteArrayOutputStream
;
5 import java
.util
.ArrayList
;
7 import java
.util
.jar
.Attributes
;
8 import java
.util
.jar
.Attributes
.Name
;
9 import java
.util
.jar
.JarInputStream
;
10 import java
.util
.jar
.Manifest
;
12 import javax
.jcr
.Binary
;
13 import javax
.jcr
.Node
;
14 import javax
.jcr
.NodeIterator
;
15 import javax
.jcr
.Property
;
16 import javax
.jcr
.RepositoryException
;
17 import javax
.jcr
.Session
;
18 import javax
.jcr
.nodetype
.NodeType
;
20 import org
.apache
.commons
.io
.FilenameUtils
;
21 import org
.apache
.commons
.io
.IOUtils
;
22 import org
.apache
.commons
.logging
.Log
;
23 import org
.apache
.commons
.logging
.LogFactory
;
24 import org
.argeo
.jcr
.JcrUtils
;
25 import org
.argeo
.slc
.SlcException
;
26 import org
.argeo
.slc
.jcr
.SlcNames
;
27 import org
.argeo
.slc
.jcr
.SlcTypes
;
28 import org
.osgi
.framework
.Constants
;
29 import org
.osgi
.framework
.Version
;
32 * Indexes jar file, currently supports standard J2SE and OSGi metadata (both
35 public class JarFileIndexer
implements NodeIndexer
{
36 private final static Log log
= LogFactory
.getLog(JarFileIndexer
.class);
38 public Boolean
support(String path
) {
39 return FilenameUtils
.getExtension(path
).equals("jar");
42 public void index(Node fileNode
) {
43 Binary fileBinary
= null;
44 JarInputStream jarIn
= null;
45 ByteArrayOutputStream bo
= null;
46 ByteArrayInputStream bi
= null;
47 Binary manifestBinary
= null;
49 if (!fileNode
.isNodeType(NodeType
.NT_FILE
))
52 Session jcrSession
= fileNode
.getSession();
53 Node contentNode
= fileNode
.getNode(Node
.JCR_CONTENT
);
54 fileBinary
= contentNode
.getProperty(Property
.JCR_DATA
).getBinary();
56 // if (!FilenameUtils.isExtension(fileNode.getName(), "jar")) {
60 jarIn
= new JarInputStream(fileBinary
.getStream());
61 Manifest manifest
= jarIn
.getManifest();
63 log
.error(fileNode
+" has no MANIFEST");
66 bo
= new ByteArrayOutputStream();
68 bi
= new ByteArrayInputStream(bo
.toByteArray());
69 manifestBinary
= jcrSession
.getValueFactory().createBinary(bi
);
72 fileNode
.addMixin(SlcTypes
.SLC_JAR_FILE
);
73 fileNode
.setProperty(SlcNames
.SLC_MANIFEST
, manifestBinary
);
74 Attributes attrs
= manifest
.getMainAttributes();
75 if (log
.isTraceEnabled())
76 for (Object key
: attrs
.keySet())
77 log
.trace(key
+ ": " + attrs
.getValue(key
.toString()));
79 // standard J2SE MANIFEST attributes
80 addAttr(Attributes
.Name
.MANIFEST_VERSION
, fileNode
, attrs
);
81 addAttr(Attributes
.Name
.SIGNATURE_VERSION
, fileNode
, attrs
);
82 addAttr(Attributes
.Name
.CLASS_PATH
, fileNode
, attrs
);
83 addAttr(Attributes
.Name
.MAIN_CLASS
, fileNode
, attrs
);
84 addAttr(Attributes
.Name
.EXTENSION_NAME
, fileNode
, attrs
);
85 addAttr(Attributes
.Name
.IMPLEMENTATION_VERSION
, fileNode
, attrs
);
86 addAttr(Attributes
.Name
.IMPLEMENTATION_VENDOR
, fileNode
, attrs
);
87 addAttr(Attributes
.Name
.IMPLEMENTATION_VENDOR_ID
, fileNode
, attrs
);
88 addAttr(Attributes
.Name
.SPECIFICATION_TITLE
, fileNode
, attrs
);
89 addAttr(Attributes
.Name
.SPECIFICATION_VERSION
, fileNode
, attrs
);
90 addAttr(Attributes
.Name
.SPECIFICATION_VENDOR
, fileNode
, attrs
);
91 addAttr(Attributes
.Name
.SEALED
, fileNode
, attrs
);
94 if (attrs
.containsKey(new Name(Constants
.BUNDLE_SYMBOLICNAME
))) {
95 addOsgiMetadata(fileNode
, attrs
);
96 if (log
.isTraceEnabled())
97 log
.trace("Indexed OSGi bundle " + fileNode
);
99 if (log
.isTraceEnabled())
100 log
.trace("Indexed JAR file " + fileNode
);
102 } catch (Exception e
) {
103 throw new SlcException("Cannot index jar " + fileNode
, e
);
105 IOUtils
.closeQuietly(bi
);
106 IOUtils
.closeQuietly(bo
);
107 IOUtils
.closeQuietly(jarIn
);
108 JcrUtils
.closeQuietly(manifestBinary
);
109 JcrUtils
.closeQuietly(fileBinary
);
114 protected void addOsgiMetadata(Node fileNode
, Attributes attrs
)
115 throws RepositoryException
{
116 fileNode
.addMixin(SlcTypes
.SLC_BUNDLE_ARTIFACT
);
119 String symbolicName
= attrs
.getValue(Constants
.BUNDLE_SYMBOLICNAME
);
120 // make sure there is no directive
121 symbolicName
= symbolicName
.split(";")[0];
122 fileNode
.setProperty(SlcNames
.SLC_SYMBOLIC_NAME
, symbolicName
);
125 addAttr(Constants
.BUNDLE_SYMBOLICNAME
, fileNode
, attrs
);
126 addAttr(Constants
.BUNDLE_NAME
, fileNode
, attrs
);
127 addAttr(Constants
.BUNDLE_DESCRIPTION
, fileNode
, attrs
);
128 addAttr(Constants
.BUNDLE_MANIFESTVERSION
, fileNode
, attrs
);
129 addAttr(Constants
.BUNDLE_CATEGORY
, fileNode
, attrs
);
130 addAttr(Constants
.BUNDLE_ACTIVATIONPOLICY
, fileNode
, attrs
);
131 addAttr(Constants
.BUNDLE_COPYRIGHT
, fileNode
, attrs
);
132 addAttr(Constants
.BUNDLE_VENDOR
, fileNode
, attrs
);
133 addAttr("Bundle-License", fileNode
, attrs
);
134 addAttr(Constants
.BUNDLE_DOCURL
, fileNode
, attrs
);
135 addAttr(Constants
.BUNDLE_CONTACTADDRESS
, fileNode
, attrs
);
136 addAttr(Constants
.BUNDLE_ACTIVATOR
, fileNode
, attrs
);
137 addAttr(Constants
.BUNDLE_UPDATELOCATION
, fileNode
, attrs
);
138 addAttr(Constants
.BUNDLE_LOCALIZATION
, fileNode
, attrs
);
140 // required execution environment
141 if (attrs
.containsKey(new Name(
142 Constants
.BUNDLE_REQUIREDEXECUTIONENVIRONMENT
)))
143 fileNode
.setProperty(SlcNames
.SLC_
144 + Constants
.BUNDLE_REQUIREDEXECUTIONENVIRONMENT
, attrs
145 .getValue(Constants
.BUNDLE_REQUIREDEXECUTIONENVIRONMENT
)
149 if (attrs
.containsKey(new Name(Constants
.BUNDLE_CLASSPATH
)))
150 fileNode
.setProperty(SlcNames
.SLC_
+ Constants
.BUNDLE_CLASSPATH
,
151 attrs
.getValue(Constants
.BUNDLE_CLASSPATH
).split(","));
154 Version version
= new Version(attrs
.getValue(Constants
.BUNDLE_VERSION
));
155 fileNode
.setProperty(SlcNames
.SLC_BUNDLE_VERSION
, version
.toString());
156 cleanSubNodes(fileNode
, SlcNames
.SLC_
+ Constants
.BUNDLE_VERSION
);
157 Node bundleVersionNode
= fileNode
.addNode(SlcNames
.SLC_
158 + Constants
.BUNDLE_VERSION
, SlcTypes
.SLC_OSGI_VERSION
);
159 mapOsgiVersion(version
, bundleVersionNode
);
162 cleanSubNodes(fileNode
, SlcNames
.SLC_
+ Constants
.FRAGMENT_HOST
);
163 if (attrs
.containsKey(new Name(Constants
.FRAGMENT_HOST
))) {
164 String fragmentHost
= attrs
.getValue(Constants
.FRAGMENT_HOST
);
165 String
[] tokens
= fragmentHost
.split(";");
166 Node node
= fileNode
.addNode(SlcNames
.SLC_
167 + Constants
.FRAGMENT_HOST
, SlcTypes
.SLC_FRAGMENT_HOST
);
168 node
.setProperty(SlcNames
.SLC_SYMBOLIC_NAME
, tokens
[0]);
169 for (int i
= 1; i
< tokens
.length
; i
++) {
170 if (tokens
[i
].startsWith(Constants
.BUNDLE_VERSION_ATTRIBUTE
)) {
171 node
.setProperty(SlcNames
.SLC_BUNDLE_VERSION
,
172 attributeValue(tokens
[i
]));
178 cleanSubNodes(fileNode
, SlcNames
.SLC_
+ Constants
.IMPORT_PACKAGE
);
179 if (attrs
.containsKey(new Name(Constants
.IMPORT_PACKAGE
))) {
180 String importPackages
= attrs
.getValue(Constants
.IMPORT_PACKAGE
);
181 List
<String
> packages
= parsePackages(importPackages
);
182 for (String pkg
: packages
) {
183 String
[] tokens
= pkg
.split(";");
184 Node node
= fileNode
.addNode(SlcNames
.SLC_
185 + Constants
.IMPORT_PACKAGE
,
186 SlcTypes
.SLC_IMPORTED_PACKAGE
);
187 node
.setProperty(SlcNames
.SLC_NAME
, tokens
[0]);
188 for (int i
= 1; i
< tokens
.length
; i
++) {
189 if (tokens
[i
].startsWith(Constants
.VERSION_ATTRIBUTE
)) {
190 node
.setProperty(SlcNames
.SLC_VERSION
,
191 attributeValue(tokens
[i
]));
193 .startsWith(Constants
.RESOLUTION_DIRECTIVE
)) {
195 SlcNames
.SLC_OPTIONAL
,
196 directiveValue(tokens
[i
]).equals(
197 Constants
.RESOLUTION_OPTIONAL
));
203 // dynamic import package
204 cleanSubNodes(fileNode
, SlcNames
.SLC_
+ Constants
.DYNAMICIMPORT_PACKAGE
);
205 if (attrs
.containsKey(new Name(Constants
.DYNAMICIMPORT_PACKAGE
))) {
206 String importPackages
= attrs
207 .getValue(Constants
.DYNAMICIMPORT_PACKAGE
);
208 List
<String
> packages
= parsePackages(importPackages
);
209 for (String pkg
: packages
) {
210 String
[] tokens
= pkg
.split(";");
211 Node node
= fileNode
.addNode(SlcNames
.SLC_
212 + Constants
.DYNAMICIMPORT_PACKAGE
,
213 SlcTypes
.SLC_DYNAMIC_IMPORTED_PACKAGE
);
214 node
.setProperty(SlcNames
.SLC_NAME
, tokens
[0]);
215 for (int i
= 1; i
< tokens
.length
; i
++) {
216 if (tokens
[i
].startsWith(Constants
.VERSION_ATTRIBUTE
)) {
217 node
.setProperty(SlcNames
.SLC_VERSION
,
218 attributeValue(tokens
[i
]));
225 cleanSubNodes(fileNode
, SlcNames
.SLC_
+ Constants
.EXPORT_PACKAGE
);
226 if (attrs
.containsKey(new Name(Constants
.EXPORT_PACKAGE
))) {
227 String exportPackages
= attrs
.getValue(Constants
.EXPORT_PACKAGE
);
228 List
<String
> packages
= parsePackages(exportPackages
);
229 for (String pkg
: packages
) {
230 String
[] tokens
= pkg
.split(";");
231 Node node
= fileNode
.addNode(SlcNames
.SLC_
232 + Constants
.EXPORT_PACKAGE
,
233 SlcTypes
.SLC_EXPORTED_PACKAGE
);
234 node
.setProperty(SlcNames
.SLC_NAME
, tokens
[0]);
235 // TODO: are these cleans really necessary?
236 cleanSubNodes(node
, SlcNames
.SLC_USES
);
237 cleanSubNodes(node
, SlcNames
.SLC_VERSION
);
238 for (int i
= 1; i
< tokens
.length
; i
++) {
239 if (tokens
[i
].startsWith(Constants
.VERSION_ATTRIBUTE
)) {
240 String versionStr
= attributeValue(tokens
[i
]);
241 Node versionNode
= node
.addNode(SlcNames
.SLC_VERSION
,
242 SlcTypes
.SLC_OSGI_VERSION
);
243 mapOsgiVersion(new Version(versionStr
), versionNode
);
244 } else if (tokens
[i
].startsWith(Constants
.USES_DIRECTIVE
)) {
245 String usedPackages
= directiveValue(tokens
[i
]);
246 // log.debug("uses='" + usedPackages + "'");
247 for (String usedPackage
: usedPackages
.split(",")) {
248 // log.debug("usedPackage='" +
251 Node usesNode
= node
.addNode(SlcNames
.SLC_USES
,
252 SlcTypes
.SLC_JAVA_PACKAGE
);
253 usesNode
.setProperty(SlcNames
.SLC_NAME
, usedPackage
);
261 cleanSubNodes(fileNode
, SlcNames
.SLC_
+ Constants
.REQUIRE_BUNDLE
);
262 if (attrs
.containsKey(new Name(Constants
.REQUIRE_BUNDLE
))) {
263 String requireBundle
= attrs
.getValue(Constants
.REQUIRE_BUNDLE
);
264 String
[] bundles
= requireBundle
.split(",");
265 for (String bundle
: bundles
) {
266 String
[] tokens
= bundle
.split(";");
267 Node node
= fileNode
.addNode(SlcNames
.SLC_
268 + Constants
.REQUIRE_BUNDLE
,
269 SlcTypes
.SLC_REQUIRED_BUNDLE
);
270 node
.setProperty(SlcNames
.SLC_SYMBOLIC_NAME
, tokens
[0]);
271 for (int i
= 1; i
< tokens
.length
; i
++) {
273 .startsWith(Constants
.BUNDLE_VERSION_ATTRIBUTE
)) {
274 node
.setProperty(SlcNames
.SLC_BUNDLE_VERSION
,
275 attributeValue(tokens
[i
]));
277 .startsWith(Constants
.RESOLUTION_DIRECTIVE
)) {
279 SlcNames
.SLC_OPTIONAL
,
280 directiveValue(tokens
[i
]).equals(
281 Constants
.RESOLUTION_OPTIONAL
));
289 private void addAttr(String key
, Node node
, Attributes attrs
)
290 throws RepositoryException
{
291 addAttr(new Name(key
), node
, attrs
);
294 private void addAttr(Name key
, Node node
, Attributes attrs
)
295 throws RepositoryException
{
296 if (attrs
.containsKey(key
)) {
297 String value
= attrs
.getValue(key
);
298 node
.setProperty(SlcNames
.SLC_
+ key
, value
);
302 private void cleanSubNodes(Node node
, String name
)
303 throws RepositoryException
{
304 if (node
.hasNode(name
)) {
305 NodeIterator nit
= node
.getNodes(name
);
306 while (nit
.hasNext())
307 nit
.nextNode().remove();
311 private String
attributeValue(String str
) {
312 return extractValue(str
, "=");
315 private String
directiveValue(String str
) {
316 return extractValue(str
, ":=");
319 private String
extractValue(String str
, String eq
) {
320 String
[] tokens
= str
.split(eq
);
321 // String key = tokens[0];
322 String value
= tokens
[1].trim();
324 if (value
.startsWith("\""))
325 value
= value
.substring(1);
326 if (value
.endsWith("\""))
327 value
= value
.substring(0, value
.length() - 1);
331 /** Parse package list with nested directive with ',' */
332 private List
<String
> parsePackages(String str
) {
333 List
<String
> res
= new ArrayList
<String
>();
334 StringBuffer curr
= new StringBuffer("");
336 for (char c
: str
.toCharArray()) {
339 res
.add(curr
.toString());
340 curr
= new StringBuffer("");
342 } else if (c
== '\"') {
349 res
.add(curr
.toString());
354 protected void mapOsgiVersion(Version version
, Node versionNode
)
355 throws RepositoryException
{
356 versionNode
.setProperty(SlcNames
.SLC_AS_STRING
, version
.toString());
357 versionNode
.setProperty(SlcNames
.SLC_MAJOR
, version
.getMajor());
358 versionNode
.setProperty(SlcNames
.SLC_MINOR
, version
.getMinor());
359 versionNode
.setProperty(SlcNames
.SLC_MICRO
, version
.getMicro());
360 if (!version
.getQualifier().equals(""))
361 versionNode
.setProperty(SlcNames
.SLC_QUALIFIER
,
362 version
.getQualifier());