]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/ModularDistributionIndexer.java
Implement order for versions and name versions.
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / ModularDistributionIndexer.java
1 package org.argeo.slc.repo;
2
3 import java.io.BufferedReader;
4 import java.io.InputStreamReader;
5 import java.util.ArrayList;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.StringTokenizer;
9 import java.util.jar.JarEntry;
10 import java.util.jar.JarInputStream;
11 import java.util.jar.Manifest;
12
13 import javax.jcr.Binary;
14 import javax.jcr.Node;
15 import javax.jcr.Property;
16 import javax.jcr.RepositoryException;
17 import javax.jcr.nodetype.NodeType;
18
19 import org.apache.commons.io.FilenameUtils;
20 import org.apache.commons.io.IOUtils;
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.argeo.jcr.JcrUtils;
24 import org.argeo.slc.CategorizedNameVersion;
25 import org.argeo.slc.DefaultNameVersion;
26 import org.argeo.slc.NameVersion;
27 import org.argeo.slc.SlcException;
28 import org.argeo.slc.aether.AetherUtils;
29 import org.argeo.slc.build.Distribution;
30 import org.argeo.slc.jcr.SlcNames;
31 import org.argeo.slc.jcr.SlcTypes;
32 import org.osgi.framework.Constants;
33 import org.sonatype.aether.artifact.Artifact;
34 import org.sonatype.aether.util.artifact.DefaultArtifact;
35
36 /**
37 * Create or update JCR meta-data for an SLC Modular Distribution
38 *
39 * Currently, following types are managed: <list><li>* .jar: dependency
40 * artifacts with csv index</li> <li>@Deprecated : .pom: artifact (binaries)
41 * that indexes a group, the .pom file contains a tag "dependencyManagement"
42 * that list all modules</li> </list>
43 */
44 public class ModularDistributionIndexer implements NodeIndexer, SlcNames {
45 private final static Log log = LogFactory
46 .getLog(ModularDistributionIndexer.class);
47
48 // Constants for csv indexing
49 private final static String INDEX_FILE_NAME = "modularDistribution.csv";
50 private String separator = ",";
51
52 // TODO remove this: binaries have been replaced by modular distribution
53 // // Artifact indexing
54 // private final static List<String> BINARIES_ARTIFACTS_NAME;
55 // static {
56 // List<String> tmpList = new ArrayList<String>();
57 // tmpList.add(RepoConstants.BINARIES_ARTIFACT_ID);
58 // // tmpList.add(RepoConstants.SOURCES_ARTIFACT_ID);
59 // // tmpList.add(RepoConstants.SDK_ARTIFACT_ID);
60 // BINARIES_ARTIFACTS_NAME = Collections.unmodifiableList(tmpList);
61 // }
62
63 private Manifest manifest;
64
65 public Boolean support(String path) {
66 if (FilenameUtils.getExtension(path).equals("jar"))
67 return true;
68 // if (FilenameUtils.getExtension(path).equals("pom")
69 // && BINARIES_ARTIFACTS_NAME.contains(FilenameUtils.getName(path)
70 // .split("-")[0]))
71 // return true;
72 return false;
73 }
74
75 public void index(Node fileNode) {
76 Binary fileBinary = null;
77 try {
78
79 String fileNodePath = fileNode.getPath();
80 if (!support(fileNodePath))
81 return;
82
83 if (!fileNode.isNodeType(NodeType.NT_FILE))
84 return;
85
86 Node contentNode = fileNode.getNode(Node.JCR_CONTENT);
87 fileBinary = contentNode.getProperty(Property.JCR_DATA).getBinary();
88
89 MyModularDistribution currDist = null;
90 if (FilenameUtils.getExtension(fileNode.getPath()).equals("jar"))
91 currDist = listModulesFromCsvIndex(fileNode, fileBinary);
92 // else if (FilenameUtils.getExtension(fileNode.getPath()).equals(
93 // "pom"))
94 // currDist = listModulesFromPomIndex(fileNode, fileBinary);
95
96 if (fileNode.isNodeType(SlcTypes.SLC_MODULAR_DISTRIBUTION)
97 || currDist == null || !currDist.nameVersions().hasNext())
98 return; // already indexed or no modules found
99 else {
100 fileNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION);
101 fileNode.addMixin(SlcTypes.SLC_CATEGORIZED_NAME_VERSION);
102 if (currDist.getCategory() != null)
103 fileNode.setProperty(SLC_CATEGORY, currDist.getCategory());
104 fileNode.setProperty(SLC_NAME, currDist.getName());
105 fileNode.setProperty(SLC_VERSION, currDist.getVersion());
106 indexDistribution(currDist, fileNode);
107 }
108
109 if (log.isTraceEnabled())
110 log.trace("Indexed " + fileNode + " as modular distribution");
111 } catch (Exception e) {
112 throw new SlcException("Cannot list dependencies from " + fileNode,
113 e);
114 }
115 }
116
117 private void indexDistribution(ArgeoOsgiDistribution osgiDist, Node distNode)
118 throws RepositoryException {
119 distNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION);
120 distNode.addMixin(SlcTypes.SLC_CATEGORIZED_NAME_VERSION);
121 distNode.setProperty(SlcNames.SLC_CATEGORY, osgiDist.getCategory());
122 distNode.setProperty(SlcNames.SLC_NAME, osgiDist.getName());
123 distNode.setProperty(SlcNames.SLC_VERSION, osgiDist.getVersion());
124 Node modules = JcrUtils.mkdirs(distNode, SlcNames.SLC_MODULES,
125 NodeType.NT_UNSTRUCTURED);
126
127 for (Iterator<? extends NameVersion> it = osgiDist.nameVersions(); it
128 .hasNext();)
129 addModule(modules, it.next());
130 }
131
132 // Helpers
133 private Node addModule(Node modules, NameVersion nameVersion)
134 throws RepositoryException {
135 CategorizedNameVersion cnv = (CategorizedNameVersion) nameVersion;
136 Node moduleCoord = null;
137 moduleCoord = modules.addNode(cnv.getName(),
138 SlcTypes.SLC_MODULE_COORDINATES);
139 moduleCoord.setProperty(SlcNames.SLC_CATEGORY, cnv.getCategory());
140 moduleCoord.setProperty(SlcNames.SLC_NAME, cnv.getName());
141 moduleCoord.setProperty(SlcNames.SLC_VERSION, cnv.getVersion());
142 return moduleCoord;
143 }
144
145 private MyModularDistribution listModulesFromCsvIndex(Node fileNode,
146 Binary fileBinary) {
147 JarInputStream jarIn = null;
148 BufferedReader reader = null;
149 try {
150 jarIn = new JarInputStream(fileBinary.getStream());
151
152 List<CategorizedNameVersion> modules = new ArrayList<CategorizedNameVersion>();
153
154 // meta data
155 manifest = jarIn.getManifest();
156 if (manifest == null) {
157 log.error(fileNode + " has no MANIFEST");
158 return null;
159 }
160 String category = manifest.getMainAttributes().getValue(
161 RepoConstants.SLC_GROUP_ID);
162 String name = manifest.getMainAttributes().getValue(
163 Constants.BUNDLE_SYMBOLICNAME);
164 String version = manifest.getMainAttributes().getValue(
165 Constants.BUNDLE_VERSION);
166
167 Artifact distribution = new DefaultArtifact(category, name, "jar",
168 version);
169 // Retrieve the index file
170 JarEntry indexEntry;
171 while ((indexEntry = jarIn.getNextJarEntry()) != null) {
172 String entryName = indexEntry.getName();
173 if (entryName.equals(INDEX_FILE_NAME)) {
174 break;
175 }
176 try {
177 jarIn.closeEntry();
178 } catch (SecurityException se) {
179 log.error("Invalid signature file digest "
180 + "for Manifest main attributes: " + entryName
181 + " while looking for an index in bundle " + name);
182 }
183 }
184 if (indexEntry == null)
185 return null; // Not a modular definition
186
187 // Process the index
188 reader = new BufferedReader(new InputStreamReader(jarIn));
189 String line = null;
190 while ((line = reader.readLine()) != null) {
191 StringTokenizer st = new StringTokenizer(line, separator);
192 st.nextToken(); // moduleName
193 st.nextToken(); // moduleVersion
194 String relativeUrl = st.nextToken();
195 Artifact currModule = AetherUtils.convertPathToArtifact(
196 relativeUrl, null);
197 modules.add(new MyCategorizedNameVersion(currModule
198 .getGroupId(), currModule.getArtifactId(), currModule
199 .getVersion()));
200 }
201 return new MyModularDistribution(distribution, modules);
202 } catch (Exception e) {
203 throw new SlcException("Cannot list artifacts", e);
204 } finally {
205 IOUtils.closeQuietly(jarIn);
206 IOUtils.closeQuietly(reader);
207 }
208 }
209
210 // private MyModularDistribution listModulesFromPomIndex(Node fileNode,
211 // Binary fileBinary) {
212 // InputStream input = null;
213 // List<CategorizedNameVersion> modules = new
214 // ArrayList<CategorizedNameVersion>();
215 // try {
216 // input = fileBinary.getStream();
217 //
218 // DocumentBuilder documentBuilder = DocumentBuilderFactory
219 // .newInstance().newDocumentBuilder();
220 // Document doc = documentBuilder.parse(input);
221 // // properties
222 // Properties props = new Properties();
223 // // props.setProperty("project.version",
224 // // pomArtifact.getBaseVersion());
225 // NodeList properties = doc.getElementsByTagName("properties");
226 // if (properties.getLength() > 0) {
227 // NodeList propertiesElems = properties.item(0).getChildNodes();
228 // for (int i = 0; i < propertiesElems.getLength(); i++) {
229 // if (propertiesElems.item(i) instanceof Element) {
230 // Element property = (Element) propertiesElems.item(i);
231 // props.put(property.getNodeName(),
232 // property.getTextContent());
233 // }
234 // }
235 // }
236 //
237 // // full coordinates are under <dependencyManagement><dependencies>
238 // NodeList dependencies = ((Element) doc.getElementsByTagName(
239 // "dependencyManagement").item(0))
240 // .getElementsByTagName("dependency");
241 // for (int i = 0; i < dependencies.getLength(); i++) {
242 // Element dependency = (Element) dependencies.item(i);
243 // String groupId = dependency.getElementsByTagName("groupId")
244 // .item(0).getTextContent().trim();
245 // String artifactId = dependency
246 // .getElementsByTagName("artifactId").item(0)
247 // .getTextContent().trim();
248 // String version = dependency.getElementsByTagName("version")
249 // .item(0).getTextContent().trim();
250 // modules.add(new MyCategorizedNameVersion(groupId, artifactId,
251 // version));
252 // }
253 //
254 // String groupId = doc.getElementsByTagName("groupId").item(0)
255 // .getTextContent().trim();
256 // String artifactId = doc.getElementsByTagName("artifactId").item(0)
257 // .getTextContent().trim();
258 // String version = doc.getElementsByTagName("version").item(0)
259 // .getTextContent().trim();
260 //
261 // Artifact currDist = new DefaultArtifact(groupId, artifactId, "pom",
262 // version);
263 //
264 // return new MyModularDistribution(currDist, modules);
265 // } catch (Exception e) {
266 // throw new SlcException("Cannot process pom " + fileNode, e);
267 // } finally {
268 // IOUtils.closeQuietly(input);
269 // }
270 // }
271
272 /** The created modular distribution */
273 private static class MyCategorizedNameVersion extends DefaultNameVersion
274 implements CategorizedNameVersion {
275 private final String category;
276
277 public MyCategorizedNameVersion(String category, String name,
278 String version) {
279 super(name, version);
280 this.category = category;
281 }
282
283 public String getCategory() {
284 return category;
285 }
286 }
287
288 /**
289 * A consistent and versioned OSGi distribution, which can be built and
290 * tested.
291 */
292 private class MyModularDistribution extends ArtifactDistribution implements
293 ArgeoOsgiDistribution {
294
295 private List<CategorizedNameVersion> modules;
296
297 public MyModularDistribution(Artifact artifact,
298 List<CategorizedNameVersion> modules) {
299 super(artifact);
300 this.modules = modules;
301 }
302
303 public Iterator<CategorizedNameVersion> nameVersions() {
304 return modules.iterator();
305 }
306
307 // Modular distribution interface methods. Not yet used.
308 public Distribution getModuleDistribution(String moduleName,
309 String moduleVersion) {
310 return null;
311 }
312
313 public Object getModulesDescriptor(String descriptorType) {
314 return null;
315 }
316 }
317
318 /** Separator used to parse the tabular file, default is "," */
319 public void setSeparator(String modulesUrlSeparator) {
320 this.separator = modulesUrlSeparator;
321 }
322 }