]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/DistributionBundleIndexer.java
Clean session management.
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / DistributionBundleIndexer.java
1 package org.argeo.slc.repo;
2
3 import java.io.BufferedReader;
4 import java.io.InputStream;
5 import java.io.InputStreamReader;
6 import java.util.ArrayList;
7 import java.util.Collections;
8 import java.util.Comparator;
9 import java.util.List;
10 import java.util.Properties;
11 import java.util.Set;
12 import java.util.StringTokenizer;
13 import java.util.TreeSet;
14 import java.util.jar.JarEntry;
15 import java.util.jar.JarInputStream;
16 import java.util.jar.Manifest;
17
18 import javax.jcr.Binary;
19 import javax.jcr.Node;
20 import javax.jcr.Property;
21 import javax.jcr.nodetype.NodeType;
22 import javax.xml.parsers.DocumentBuilder;
23 import javax.xml.parsers.DocumentBuilderFactory;
24
25 import org.apache.commons.io.FilenameUtils;
26 import org.apache.commons.io.IOUtils;
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.argeo.jcr.JcrUtils;
30 import org.argeo.slc.SlcException;
31 import org.argeo.slc.aether.AetherUtils;
32 import org.argeo.slc.aether.ArtifactIdComparator;
33 import org.argeo.slc.jcr.SlcNames;
34 import org.argeo.slc.jcr.SlcTypes;
35 import org.sonatype.aether.artifact.Artifact;
36 import org.sonatype.aether.util.artifact.DefaultArtifact;
37 import org.w3c.dom.Document;
38 import org.w3c.dom.Element;
39 import org.w3c.dom.NodeList;
40
41 /**
42 * Create or update JCR meta-data for modularDistribution bundles: <list><li>
43 * .jar: dependency artifacts with csv index</li> <li>.pom: group index artifact
44 * (binaries, sources) with tag dependency management</li> </list>
45 */
46 public class DistributionBundleIndexer implements NodeIndexer {
47 private final static Log log = LogFactory
48 .getLog(DistributionBundleIndexer.class);
49
50 private final static String INDEX_FILE_NAME = "modularDistribution.csv";
51 private final static List<String> BINARIES_ARTIFACTS_NAME;
52 static {
53 List<String> tmpList = new ArrayList<String>();
54 tmpList.add(RepoConstants.BINARIES_ARTIFACT_ID);
55 //tmpList.add(RepoConstants.SOURCES_ARTIFACT_ID);
56 //tmpList.add(RepoConstants.SDK_ARTIFACT_ID);
57 BINARIES_ARTIFACTS_NAME = Collections.unmodifiableList(tmpList);
58 }
59
60 private Manifest manifest;
61 // private String symbolicName;
62 // private String version;
63
64 // private List<Artifact> artifacts;
65 private String separator = ",";
66
67 private Comparator<Artifact> artifactComparator = new ArtifactIdComparator();
68
69 // private Set<Artifact> artifacts = new
70 // TreeSet<Artifact>(artifactComparator);
71
72 public Boolean support(String path) {
73 if (FilenameUtils.getExtension(path).equals("jar"))
74 return true;
75
76 if (FilenameUtils.getExtension(path).equals("pom")
77 && BINARIES_ARTIFACTS_NAME.contains(FilenameUtils.getName(path)
78 .split("-")[0]))
79 return true;
80 return false;
81 }
82
83 public void index(Node fileNode) {
84 // JarInputStream jarIn = null;
85 Binary fileBinary = null;
86 try {
87
88 String fileNodePath = fileNode.getPath();
89 if (!support(fileNodePath))
90 return;
91
92 if (!fileNode.isNodeType(NodeType.NT_FILE))
93 return;
94
95 // Session jcrSession = fileNode.getSession();
96 Node contentNode = fileNode.getNode(Node.JCR_CONTENT);
97 fileBinary = contentNode.getProperty(Property.JCR_DATA).getBinary();
98
99 Set<Artifact> artifacts = new TreeSet<Artifact>(artifactComparator);
100
101 if (FilenameUtils.getExtension(fileNode.getPath()).equals("jar"))
102 listModulesFromCsvIndex(artifacts, fileNode, fileBinary);
103 else if (FilenameUtils.getExtension(fileNode.getPath()).equals(
104 "pom"))
105 listModulesFromPomIndex(artifacts, fileNode, fileBinary);
106
107 if (artifacts.isEmpty())
108 return; // no modules found
109 else {
110 Node modules;
111 if (fileNode.isNodeType(SlcTypes.SLC_MODULAR_DISTRIBUTION)) {
112 modules = fileNode.getNode(SlcNames.SLC_MODULES);
113 } else {
114 fileNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION);
115 modules = JcrUtils.mkdirs(fileNode, SlcNames.SLC_MODULES,
116 NodeType.NT_UNSTRUCTURED);
117 }
118
119 for (Artifact artifact : artifacts) {
120 // TODO clean this once an overwrite policy has been
121 // decided.
122 if (!modules.hasNode(artifact.getArtifactId())) {
123 Node moduleCoord = modules.addNode(
124 artifact.getArtifactId(),
125 SlcTypes.SLC_MODULE_COORDINATES);
126 moduleCoord.setProperty(SlcNames.SLC_NAME,
127 artifact.getArtifactId());
128 moduleCoord.setProperty(SlcNames.SLC_VERSION,
129 artifact.getVersion());
130 String groupId = artifact.getGroupId();
131 if (groupId != null && !"".equals(groupId.trim()))
132 moduleCoord.setProperty(SlcNames.SLC_CATEGORY,
133 artifact.getGroupId());
134 }
135 }
136
137 }
138
139 // find base URL
140 // won't work if distribution artifact is not listed
141 // for (int i = 0; i < artifacts.size(); i++) {
142 // OsgiArtifact osgiArtifact = artifacts.get(i);
143 // if (osgiArtifact.getSymbolicName().equals(symbolicName)
144 // && osgiArtifact.getVersion().equals(version)) {
145 // String relativeUrl = osgiArtifact.getRelativeUrl();
146 // if (url.endsWith(relativeUrl)) {
147 // baseUrl = url.substring(0, url.length()
148 // - osgiArtifact.getRelativeUrl().length());
149 // break;
150 // }
151 // }
152 // }
153 } catch (Exception e) {
154 throw new SlcException("Cannot list dependencies from " + fileNode,
155 e);
156 }
157 }
158
159 protected void listModulesFromCsvIndex(Set<Artifact> artifacts,
160 Node fileNode, Binary fileBinary) {
161 // List<Artifact> artifacts = new ArrayList<Artifact>();
162 JarInputStream jarIn = null;
163 BufferedReader reader = null;
164
165 try {
166 jarIn = new JarInputStream(fileBinary.getStream());
167
168 // meta data
169 // symbolicName = manifest.getMainAttributes().getValue(
170 // Constants.BUNDLE_SYMBOLICNAME);
171 // version = manifest.getMainAttributes().getValue(
172 // Constants.BUNDLE_VERSION);
173
174 manifest = jarIn.getManifest();
175 if (manifest == null) {
176 log.error(fileNode + " has no MANIFEST");
177 return;
178 }
179
180 JarEntry indexEntry;
181 while ((indexEntry = jarIn.getNextJarEntry()) != null) {
182 String entryName = indexEntry.getName();
183 if (entryName.equals(INDEX_FILE_NAME)) {
184 break;
185 }
186 jarIn.closeEntry();
187 }
188
189 if (indexEntry == null)
190 return; // Not a modular definition artifact
191
192 reader = new BufferedReader(new InputStreamReader(jarIn));
193 String line = null;
194 while ((line = reader.readLine()) != null) {
195 StringTokenizer st = new StringTokenizer(line, separator);
196 st.nextToken(); // moduleName
197 st.nextToken(); // moduleVersion
198 String relativeUrl = st.nextToken();
199
200 artifacts.add(AetherUtils.convertPathToArtifact(relativeUrl,
201 null));
202 if (log.isTraceEnabled())
203 log.debug("Processed dependency: " + line);
204 }
205 } catch (Exception e) {
206 throw new SlcException("Cannot list artifacts", e);
207 } finally {
208 IOUtils.closeQuietly(jarIn);
209 IOUtils.closeQuietly(reader);
210 }
211 }
212
213 protected void listModulesFromPomIndex(Set<Artifact> artifacts,
214 Node fileNode, Binary fileBinary) {
215 InputStream input = null;
216 try {
217 input = fileBinary.getStream();
218
219 DocumentBuilder documentBuilder = DocumentBuilderFactory
220 .newInstance().newDocumentBuilder();
221 Document doc = documentBuilder.parse(input);
222
223 // properties
224 Properties props = new Properties();
225 // props.setProperty("project.version",
226 // pomArtifact.getBaseVersion());
227 NodeList properties = doc.getElementsByTagName("properties");
228 if (properties.getLength() > 0) {
229 NodeList propertiesElems = properties.item(0).getChildNodes();
230 for (int i = 0; i < propertiesElems.getLength(); i++) {
231 if (propertiesElems.item(i) instanceof Element) {
232 Element property = (Element) propertiesElems.item(i);
233 props.put(property.getNodeName(),
234 property.getTextContent());
235 }
236 }
237 }
238
239 // full coordinates are under <dependencyManagement><dependencies>
240 NodeList dependencies = ((Element) doc.getElementsByTagName(
241 "dependencyManagement").item(0))
242 .getElementsByTagName("dependency");
243 for (int i = 0; i < dependencies.getLength(); i++) {
244 Element dependency = (Element) dependencies.item(i);
245 String groupId = dependency.getElementsByTagName("groupId")
246 .item(0).getTextContent().trim();
247 String artifactId = dependency
248 .getElementsByTagName("artifactId").item(0)
249 .getTextContent().trim();
250 String version = dependency.getElementsByTagName("version")
251 .item(0).getTextContent().trim();
252 // if (version.startsWith("${")) {
253 // String versionKey = version.substring(0,
254 // version.length() - 1).substring(2);
255 // if (!props.containsKey(versionKey))
256 // throw new SlcException("Cannot interpret version "
257 // + version);
258 // version = props.getProperty(versionKey);
259 // }
260 // NodeList scopes = dependency.getElementsByTagName("scope");
261 // if (scopes.getLength() > 0
262 // && scopes.item(0).getTextContent().equals("import")) {
263 // // recurse
264 // gatherPomDependencies(aetherTemplate, artifacts,
265 // new DefaultArtifact(groupId, artifactId, "pom",
266 // version));
267 // } else {
268 // TODO: deal with scope?
269 // TODO: deal with type
270 String type = "jar";
271 Artifact artifact = new DefaultArtifact(groupId, artifactId,
272 type, version);
273 artifacts.add(artifact);
274 // }
275 }
276 } catch (Exception e) {
277 throw new SlcException("Cannot process pom " + fileNode, e);
278 } finally {
279 IOUtils.closeQuietly(input);
280 }
281 }
282
283 /** Separator used to parse the tabular file, default is "," */
284 public void setSeparator(String modulesUrlSeparator) {
285 this.separator = modulesUrlSeparator;
286 }
287
288 /** One of the listed artifact */
289 protected static class OsgiArtifact {
290 private final String category;
291 private final String symbolicName;
292 private final String version;
293 private final String relativeUrl;
294
295 public OsgiArtifact(String category, String symbolicName,
296 String version, String relativeUrl) {
297 super();
298 this.category = category;
299 this.symbolicName = symbolicName;
300 this.version = version;
301 this.relativeUrl = relativeUrl;
302 }
303
304 public String getCategory() {
305 return category;
306 }
307
308 public String getSymbolicName() {
309 return symbolicName;
310 }
311
312 public String getVersion() {
313 return version;
314 }
315
316 public String getRelativeUrl() {
317 return relativeUrl;
318 }
319
320 }
321 }