]> git.argeo.org Git - gpl/argeo-jcr.git/blob - org.argeo.slc.repo/src/org/argeo/slc/repo/ModularDistributionIndexer.java
Prepare next development cycle
[gpl/argeo-jcr.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.argeo.api.cms.CmsLog;
22 import org.argeo.jcr.JcrUtils;
23 import org.argeo.slc.CategoryNameVersion;
24 import org.argeo.slc.DefaultCategoryNameVersion;
25 import org.argeo.slc.NameVersion;
26 import org.argeo.slc.SlcException;
27 import org.argeo.slc.SlcNames;
28 import org.argeo.slc.SlcTypes;
29 import org.argeo.slc.build.Distribution;
30 import org.argeo.slc.repo.maven.AetherUtils;
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>
39 * <li>* .jar: dependency artifacts with csv index</li>
40 * <li>@Deprecated : .pom: artifact (binaries) that indexes a group, the .pom
41 * file contains a tag "dependencyManagement" that list all modules</li> </list>
42 */
43 public class ModularDistributionIndexer implements NodeIndexer, SlcNames {
44 private final static CmsLog log = CmsLog.getLog(ModularDistributionIndexer.class);
45
46 // Constants for csv indexing
47 private final static String INDEX_FILE_NAME = "modularDistribution.csv";
48 private String separator = ",";
49
50 private Manifest manifest;
51
52 public Boolean support(String path) {
53 if (FilenameUtils.getExtension(path).equals("jar"))
54 return true;
55 return false;
56 }
57
58 public void index(Node fileNode) {
59 Binary fileBinary = null;
60 try {
61 String fileNodePath = fileNode.getPath();
62 if (!support(fileNodePath))
63 return;
64
65 if (!fileNode.isNodeType(NodeType.NT_FILE))
66 return;
67
68 Node contentNode = fileNode.getNode(Node.JCR_CONTENT);
69 fileBinary = contentNode.getProperty(Property.JCR_DATA).getBinary();
70
71 MyModularDistribution currDist = null;
72 if (FilenameUtils.getExtension(fileNode.getPath()).equals("jar"))
73 currDist = listModulesFromCsvIndex(fileNode, fileBinary);
74
75 if (fileNode.isNodeType(SlcTypes.SLC_MODULAR_DISTRIBUTION) || currDist == null
76 || !currDist.nameVersions().hasNext())
77 return; // already indexed or no modules found
78 else {
79 fileNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION);
80 fileNode.addMixin(SlcTypes.SLC_CATEGORIZED_NAME_VERSION);
81 if (currDist.getCategory() != null)
82 fileNode.setProperty(SLC_CATEGORY, currDist.getCategory());
83 fileNode.setProperty(SLC_NAME, currDist.getName());
84 fileNode.setProperty(SLC_VERSION, currDist.getVersion());
85 indexDistribution(currDist, fileNode);
86 }
87
88 if (log.isTraceEnabled())
89 log.trace("Indexed " + fileNode + " as modular distribution");
90 } catch (Exception e) {
91 throw new SlcException("Cannot list dependencies from " + fileNode, e);
92 } finally {
93 JcrUtils.closeQuietly(fileBinary);
94 }
95 }
96
97 private void indexDistribution(ArgeoOsgiDistribution osgiDist, Node distNode) throws RepositoryException {
98 distNode.addMixin(SlcTypes.SLC_MODULAR_DISTRIBUTION);
99 distNode.addMixin(SlcTypes.SLC_CATEGORIZED_NAME_VERSION);
100 distNode.setProperty(SlcNames.SLC_CATEGORY, osgiDist.getCategory());
101 distNode.setProperty(SlcNames.SLC_NAME, osgiDist.getName());
102 distNode.setProperty(SlcNames.SLC_VERSION, osgiDist.getVersion());
103 if (distNode.hasNode(SLC_MODULES))
104 distNode.getNode(SLC_MODULES).remove();
105 Node modules = distNode.addNode(SLC_MODULES, NodeType.NT_UNSTRUCTURED);
106
107 for (Iterator<? extends NameVersion> it = osgiDist.nameVersions(); it.hasNext();)
108 addModule(modules, it.next());
109 }
110
111 // Helpers
112 private Node addModule(Node modules, NameVersion nameVersion) throws RepositoryException {
113 CategoryNameVersion cnv = (CategoryNameVersion) nameVersion;
114 Node moduleCoord = null;
115 moduleCoord = modules.addNode(cnv.getName(), SlcTypes.SLC_MODULE_COORDINATES);
116 moduleCoord.setProperty(SlcNames.SLC_CATEGORY, cnv.getCategory());
117 moduleCoord.setProperty(SlcNames.SLC_NAME, cnv.getName());
118 moduleCoord.setProperty(SlcNames.SLC_VERSION, cnv.getVersion());
119 return moduleCoord;
120 }
121
122 private MyModularDistribution listModulesFromCsvIndex(Node fileNode, Binary fileBinary) {
123 JarInputStream jarIn = null;
124 BufferedReader reader = null;
125 try {
126 jarIn = new JarInputStream(fileBinary.getStream());
127
128 List<CategoryNameVersion> modules = new ArrayList<CategoryNameVersion>();
129
130 // meta data
131 manifest = jarIn.getManifest();
132 if (manifest == null) {
133 log.error(fileNode + " has no MANIFEST");
134 return null;
135 }
136 String category = manifest.getMainAttributes().getValue(RepoConstants.SLC_CATEGORY_ID);
137 String name = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
138 String version = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
139
140 Artifact distribution = new DefaultArtifact(category, name, "jar", version);
141 // Retrieve the index file
142 JarEntry indexEntry;
143 while ((indexEntry = jarIn.getNextJarEntry()) != null) {
144 String entryName = indexEntry.getName();
145 if (entryName.equals(INDEX_FILE_NAME)) {
146 break;
147 }
148 try {
149 jarIn.closeEntry();
150 } catch (SecurityException se) {
151 log.error("Invalid signature file digest " + "for Manifest main attributes: " + entryName
152 + " while looking for an index in bundle " + name);
153 }
154 }
155 if (indexEntry == null)
156 return null; // Not a modular definition
157
158 if (category == null) {
159 log.warn("Modular definition found but no " + RepoConstants.SLC_CATEGORY_ID + " in " + fileNode);
160 }
161
162 // Process the index
163 reader = new BufferedReader(new InputStreamReader(jarIn));
164 String line = null;
165 while ((line = reader.readLine()) != null) {
166 StringTokenizer st = new StringTokenizer(line, separator);
167 st.nextToken(); // moduleName
168 st.nextToken(); // moduleVersion
169 String relativeUrl = st.nextToken();
170 Artifact currModule = AetherUtils.convertPathToArtifact(relativeUrl, null);
171 modules.add(new DefaultCategoryNameVersion(currModule.getGroupId(), currModule.getArtifactId(),
172 currModule.getVersion()));
173 }
174 return new MyModularDistribution(distribution, modules);
175 } catch (Exception e) {
176 throw new SlcException("Cannot list artifacts", e);
177 } finally {
178 IOUtils.closeQuietly(jarIn);
179 IOUtils.closeQuietly(reader);
180 }
181 }
182
183 /**
184 * A consistent and versioned OSGi distribution, which can be built and tested.
185 */
186 private class MyModularDistribution extends ArtifactDistribution implements ArgeoOsgiDistribution {
187
188 private List<CategoryNameVersion> modules;
189
190 public MyModularDistribution(Artifact artifact, List<CategoryNameVersion> modules) {
191 super(artifact);
192 this.modules = modules;
193 }
194
195 public Iterator<CategoryNameVersion> nameVersions() {
196 return modules.iterator();
197 }
198
199 // Modular distribution interface methods. Not yet used.
200 public Distribution getModuleDistribution(String moduleName, String moduleVersion) {
201 return null;
202 }
203
204 public Object getModulesDescriptor(String descriptorType) {
205 return null;
206 }
207 }
208
209 /** Separator used to parse the tabular file, default is "," */
210 public void setSeparator(String modulesUrlSeparator) {
211 this.separator = modulesUrlSeparator;
212 }
213 }