]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.repo/src/org/argeo/slc/repo/ModularDistributionIndexer.java
Start adapting SLC IDE
[gpl/argeo-slc.git] / org.argeo.slc.repo / src / 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.slc.CategorizedNameVersion;
24 import org.argeo.slc.DefaultNameVersion;
25 import org.argeo.slc.NameVersion;
26 import org.argeo.slc.SlcException;
27 import org.argeo.slc.aether.AetherUtils;
28 import org.argeo.slc.build.Distribution;
29 import org.argeo.slc.jcr.SlcNames;
30 import org.argeo.slc.jcr.SlcTypes;
31 import org.eclipse.aether.artifact.Artifact;
32 import org.eclipse.aether.artifact.DefaultArtifact;
33 import org.osgi.framework.Constants;
34
35 /**
36 * Create or update JCR meta-data for an SLC Modular Distribution
37 *
38 * Currently, following types are managed: <list><li>* .jar: dependency
39 * artifacts with csv index</li> <li>@Deprecated : .pom: artifact (binaries)
40 * that indexes a group, the .pom file contains a tag "dependencyManagement"
41 * that list all modules</li> </list>
42 */
43 public class ModularDistributionIndexer implements NodeIndexer, SlcNames {
44 private final static Log log = LogFactory
45 .getLog(ModularDistributionIndexer.class);
46
47 // Constants for csv indexing
48 private final static String INDEX_FILE_NAME = "modularDistribution.csv";
49 private String separator = ",";
50
51 // TODO remove this: binaries have been replaced by modular distribution
52 // // Artifact indexing
53 // private final static List<String> BINARIES_ARTIFACTS_NAME;
54 // static {
55 // List<String> tmpList = new ArrayList<String>();
56 // tmpList.add(RepoConstants.BINARIES_ARTIFACT_ID);
57 // // tmpList.add(RepoConstants.SOURCES_ARTIFACT_ID);
58 // // tmpList.add(RepoConstants.SDK_ARTIFACT_ID);
59 // BINARIES_ARTIFACTS_NAME = Collections.unmodifiableList(tmpList);
60 // }
61
62 private Manifest manifest;
63
64 public Boolean support(String path) {
65 if (FilenameUtils.getExtension(path).equals("jar"))
66 return true;
67 // if (FilenameUtils.getExtension(path).equals("pom")
68 // && BINARIES_ARTIFACTS_NAME.contains(FilenameUtils.getName(path)
69 // .split("-")[0]))
70 // return true;
71 return false;
72 }
73
74 public void index(Node fileNode) {
75 Binary fileBinary = null;
76 try {
77
78 String fileNodePath = fileNode.getPath();
79 if (!support(fileNodePath))
80 return;
81
82 if (!fileNode.isNodeType(NodeType.NT_FILE))
83 return;
84
85 Node contentNode = fileNode.getNode(Node.JCR_CONTENT);
86 fileBinary = contentNode.getProperty(Property.JCR_DATA).getBinary();
87
88 MyModularDistribution currDist = null;
89 if (FilenameUtils.getExtension(fileNode.getPath()).equals("jar"))
90 currDist = listModulesFromCsvIndex(fileNode, fileBinary);
91 // else if (FilenameUtils.getExtension(fileNode.getPath()).equals(
92 // "pom"))
93 // currDist = listModulesFromPomIndex(fileNode, fileBinary);
94
95 if (fileNode.isNodeType(SlcTypes.SLC_MODULAR_DISTRIBUTION)
96 || currDist == null || !currDist.nameVersions().hasNext())
97 return; // already indexed or no modules found
98 else {
99 fileNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION);
100 fileNode.addMixin(SlcTypes.SLC_CATEGORIZED_NAME_VERSION);
101 if (currDist.getCategory() != null)
102 fileNode.setProperty(SLC_CATEGORY, currDist.getCategory());
103 fileNode.setProperty(SLC_NAME, currDist.getName());
104 fileNode.setProperty(SLC_VERSION, currDist.getVersion());
105 indexDistribution(currDist, fileNode);
106 }
107
108 if (log.isTraceEnabled())
109 log.trace("Indexed " + fileNode + " as modular distribution");
110 } catch (Exception e) {
111 throw new SlcException("Cannot list dependencies from " + fileNode,
112 e);
113 }
114 }
115
116 private void indexDistribution(ArgeoOsgiDistribution osgiDist, Node distNode)
117 throws RepositoryException {
118 distNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION);
119 distNode.addMixin(SlcTypes.SLC_CATEGORIZED_NAME_VERSION);
120 distNode.setProperty(SlcNames.SLC_CATEGORY, osgiDist.getCategory());
121 distNode.setProperty(SlcNames.SLC_NAME, osgiDist.getName());
122 distNode.setProperty(SlcNames.SLC_VERSION, osgiDist.getVersion());
123 if (distNode.hasNode(SLC_MODULES))
124 distNode.getNode(SLC_MODULES).remove();
125 Node modules = distNode.addNode(SLC_MODULES, 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 }