]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoUtils.java
Make import more robust
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / RepoUtils.java
1 package org.argeo.slc.repo;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.OutputStream;
9 import java.util.Enumeration;
10 import java.util.Iterator;
11 import java.util.StringTokenizer;
12 import java.util.jar.Attributes;
13 import java.util.jar.JarEntry;
14 import java.util.jar.JarFile;
15 import java.util.jar.JarInputStream;
16 import java.util.jar.JarOutputStream;
17 import java.util.jar.Manifest;
18
19 import javax.jcr.Node;
20 import javax.jcr.RepositoryException;
21
22 import org.apache.commons.io.FilenameUtils;
23 import org.apache.commons.io.IOUtils;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.argeo.jcr.JcrUtils;
27 import org.argeo.slc.BasicNameVersion;
28 import org.argeo.slc.NameVersion;
29 import org.argeo.slc.SlcException;
30 import org.argeo.slc.jcr.SlcNames;
31 import org.argeo.slc.jcr.SlcTypes;
32 import org.argeo.slc.repo.maven.MavenConventionsUtils;
33 import org.osgi.framework.Constants;
34 import org.sonatype.aether.artifact.Artifact;
35 import org.sonatype.aether.util.artifact.DefaultArtifact;
36
37 /** Utilities around repo */
38 public class RepoUtils implements SlcNames {
39 private final static Log log = LogFactory.getLog(RepoUtils.class);
40
41 /** Packages a regular sources jar as PDE source. */
42 public static void packagesAsPdeSource(File sourceFile,
43 NameVersion nameVersion, OutputStream out) throws IOException {
44 if (isAlreadyPdeSource(sourceFile)) {
45 FileInputStream in = new FileInputStream(sourceFile);
46 IOUtils.copy(in, out);
47 IOUtils.closeQuietly(in);
48 } else {
49 String sourceSymbolicName = nameVersion.getName() + ".source";
50
51 Manifest sourceManifest = null;
52 sourceManifest = new Manifest();
53 sourceManifest.getMainAttributes().put(
54 Attributes.Name.MANIFEST_VERSION, "1.0");
55 sourceManifest.getMainAttributes().putValue("Bundle-SymbolicName",
56 sourceSymbolicName);
57 sourceManifest.getMainAttributes().putValue("Bundle-Version",
58 nameVersion.getVersion());
59 sourceManifest.getMainAttributes().putValue(
60 "Eclipse-SourceBundle",
61 nameVersion.getName() + ";version="
62 + nameVersion.getVersion());
63 copyJar(sourceFile, out, sourceManifest);
64 }
65 }
66
67 public static byte[] packageAsPdeSource(InputStream sourceJar,
68 NameVersion nameVersion) {
69 String sourceSymbolicName = nameVersion.getName() + ".source";
70
71 Manifest sourceManifest = null;
72 sourceManifest = new Manifest();
73 sourceManifest.getMainAttributes().put(
74 Attributes.Name.MANIFEST_VERSION, "1.0");
75 sourceManifest.getMainAttributes().putValue("Bundle-SymbolicName",
76 sourceSymbolicName);
77 sourceManifest.getMainAttributes().putValue("Bundle-Version",
78 nameVersion.getVersion());
79 sourceManifest.getMainAttributes().putValue("Eclipse-SourceBundle",
80 nameVersion.getName() + ";version=" + nameVersion.getVersion());
81
82 return modifyManifest(sourceJar, sourceManifest);
83 }
84
85 /**
86 * Check whether the file as already been packaged as PDE source, in order
87 * not to mess with Jar signing
88 */
89 private static boolean isAlreadyPdeSource(File sourceFile) {
90 JarInputStream jarInputStream = null;
91
92 try {
93 jarInputStream = new JarInputStream(new FileInputStream(sourceFile));
94
95 Manifest manifest = jarInputStream.getManifest();
96 Iterator<?> it = manifest.getMainAttributes().keySet().iterator();
97 boolean res = false;
98 // containsKey() does not work, iterating...
99 while (it.hasNext())
100 if (it.next().toString().equals("Eclipse-SourceBundle")) {
101 res = true;
102 break;
103 }
104 // boolean res = manifest.getMainAttributes().get(
105 // "Eclipse-SourceBundle") != null;
106 if (res)
107 log.info(sourceFile + " is already a PDE source");
108 return res;
109 } catch (Exception e) {
110 // probably not a jar, skipping
111 if (log.isDebugEnabled())
112 log.debug("Skipping " + sourceFile + " because of "
113 + e.getMessage());
114 return false;
115 } finally {
116 IOUtils.closeQuietly(jarInputStream);
117 }
118 }
119
120 /**
121 * Copy a jar, replacing its manifest with the provided one
122 *
123 * @param manifest
124 * can be null
125 */
126 private static void copyJar(File source, OutputStream out, Manifest manifest)
127 throws IOException {
128 JarFile sourceJar = null;
129 JarOutputStream output = null;
130 try {
131 output = manifest != null ? new JarOutputStream(out, manifest)
132 : new JarOutputStream(out);
133 sourceJar = new JarFile(source);
134
135 entries: for (Enumeration<?> entries = sourceJar.entries(); entries
136 .hasMoreElements();) {
137 JarEntry entry = (JarEntry) entries.nextElement();
138 if (manifest != null
139 && entry.getName().equals("META-INF/MANIFEST.MF"))
140 continue entries;
141
142 InputStream entryStream = sourceJar.getInputStream(entry);
143 JarEntry newEntry = new JarEntry(entry.getName());
144 // newEntry.setMethod(JarEntry.DEFLATED);
145 output.putNextEntry(newEntry);
146 IOUtils.copy(entryStream, output);
147 }
148 } finally {
149 IOUtils.closeQuietly(output);
150 try {
151 if (sourceJar != null)
152 sourceJar.close();
153 } catch (IOException e) {
154 // silent
155 }
156 }
157 }
158
159 /** Copy a jar changing onlythe manifest */
160 public static void copyJar(InputStream in, OutputStream out,
161 Manifest manifest) {
162 JarInputStream jarIn = null;
163 JarOutputStream jarOut = null;
164 try {
165 jarIn = new JarInputStream(in);
166 jarOut = new JarOutputStream(out, manifest);
167 JarEntry jarEntry = null;
168 while ((jarEntry = jarIn.getNextJarEntry()) != null) {
169 jarOut.putNextEntry(jarEntry);
170 IOUtils.copy(jarIn, jarOut);
171 jarIn.closeEntry();
172 jarOut.closeEntry();
173 }
174 } catch (IOException e) {
175 throw new SlcException("Could not copy jar with MANIFEST "
176 + manifest.getMainAttributes(), e);
177 } finally {
178 IOUtils.closeQuietly(jarIn);
179 IOUtils.closeQuietly(jarOut);
180 }
181 }
182
183 /** Reads a jar file, modify its manifest */
184 public static byte[] modifyManifest(InputStream in, Manifest manifest) {
185 ByteArrayOutputStream out = new ByteArrayOutputStream(200 * 1024);
186 try {
187 copyJar(in, out, manifest);
188 return out.toByteArray();
189 } finally {
190 IOUtils.closeQuietly(out);
191 }
192 }
193
194 /** Read the OSGi {@link NameVersion} */
195 public static NameVersion readNameVersion(Artifact artifact) {
196 File artifactFile = artifact.getFile();
197 if (artifact.getExtension().equals("pom")) {
198 // hack to process jars which weirdly appear as POMs
199 File jarFile = new File(artifactFile.getParentFile(),
200 FilenameUtils.getBaseName(artifactFile.getPath()) + ".jar");
201 if (jarFile.exists()) {
202 log.warn("Use " + jarFile + " instead of " + artifactFile
203 + " for " + artifact);
204 artifactFile = jarFile;
205 }
206 }
207 return readNameVersion(artifactFile);
208 }
209
210 /** Read the OSGi {@link NameVersion} */
211 public static NameVersion readNameVersion(File artifactFile) {
212 JarInputStream jarInputStream = null;
213 try {
214 jarInputStream = new JarInputStream(new FileInputStream(
215 artifactFile));
216 return readNameVersion(jarInputStream.getManifest());
217 } catch (Exception e) {
218 // probably not a jar, skipping
219 if (log.isDebugEnabled()) {
220 log.debug("Skipping " + artifactFile + " because of " + e);
221 // e.printStackTrace();
222 }
223 } finally {
224 IOUtils.closeQuietly(jarInputStream);
225 }
226 return null;
227 }
228
229 /** Read the OSGi {@link NameVersion} */
230 public static NameVersion readNameVersion(Manifest manifest) {
231 BasicNameVersion nameVersion = new BasicNameVersion();
232 nameVersion.setName(manifest.getMainAttributes().getValue(
233 Constants.BUNDLE_SYMBOLICNAME));
234
235 // Skip additional specs such as
236 // ; singleton:=true
237 if (nameVersion.getName().indexOf(';') > -1) {
238 nameVersion
239 .setName(new StringTokenizer(nameVersion.getName(), " ;")
240 .nextToken());
241 }
242
243 nameVersion.setVersion(manifest.getMainAttributes().getValue(
244 Constants.BUNDLE_VERSION));
245
246 return nameVersion;
247 }
248
249 /*
250 * DATA MODEL
251 */
252 /** The artifact described by this node */
253 public static Artifact asArtifact(Node node) throws RepositoryException {
254 if (node.isNodeType(SlcTypes.SLC_ARTIFACT_VERSION_BASE)) {
255 // FIXME update data model to store packaging at this level
256 String extension = "jar";
257 return new DefaultArtifact(node.getProperty(SLC_GROUP_ID)
258 .getString(),
259 node.getProperty(SLC_ARTIFACT_ID).getString(), extension,
260 node.getProperty(SLC_ARTIFACT_VERSION).getString());
261 } else if (node.isNodeType(SlcTypes.SLC_ARTIFACT)) {
262 return new DefaultArtifact(node.getProperty(SLC_GROUP_ID)
263 .getString(),
264 node.getProperty(SLC_ARTIFACT_ID).getString(), node
265 .getProperty(SLC_ARTIFACT_CLASSIFIER).getString(),
266 node.getProperty(SLC_ARTIFACT_EXTENSION).getString(), node
267 .getProperty(SLC_ARTIFACT_VERSION).getString());
268 } else {
269 throw new SlcException("Unsupported node type for " + node);
270 }
271 }
272
273 /**
274 * Copy this bytes array as an artifact, relative to the root of the
275 * repository (typically the workspace root node)
276 */
277 public static Node copyBytesAsArtifact(Node artifactsBase,
278 Artifact artifact, byte[] bytes) throws RepositoryException {
279 String parentPath = MavenConventionsUtils.artifactParentPath(
280 artifactsBase.getPath(), artifact);
281 Node folderNode = JcrUtils.mkfolders(artifactsBase.getSession(),
282 parentPath);
283 return JcrUtils.copyBytesAsFile(folderNode,
284 MavenConventionsUtils.artifactFileName(artifact), bytes);
285 }
286
287 private RepoUtils() {
288 }
289 }