1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.project.management;
\r
14 import java.io.ByteArrayInputStream;
\r
15 import java.io.ByteArrayOutputStream;
\r
16 import java.io.File;
\r
17 import java.io.IOException;
\r
18 import java.io.InputStream;
\r
19 import java.util.Collection;
\r
20 import java.util.Comparator;
\r
21 import java.util.Enumeration;
\r
22 import java.util.Iterator;
\r
23 import java.util.Set;
\r
24 import java.util.TreeSet;
\r
25 import java.util.jar.JarEntry;
\r
26 import java.util.jar.JarFile;
\r
27 import java.util.jar.JarInputStream;
\r
28 import java.util.jar.Manifest;
\r
30 import org.eclipse.core.runtime.Path;
\r
31 import org.eclipse.equinox.internal.p2.metadata.RequiredCapability;
\r
32 import org.eclipse.equinox.internal.p2.touchpoint.eclipse.Util;
\r
33 import org.eclipse.equinox.internal.p2.ui.query.RequiredIUsQuery;
\r
34 import org.eclipse.equinox.p2.core.IProvisioningAgent;
\r
35 import org.eclipse.equinox.p2.core.ProvisionException;
\r
36 import org.eclipse.equinox.p2.metadata.IArtifactKey;
\r
37 import org.eclipse.equinox.p2.metadata.IInstallableUnit;
\r
38 import org.eclipse.equinox.p2.metadata.IInstallableUnitFragment;
\r
39 import org.eclipse.equinox.p2.metadata.IRequirement;
\r
40 import org.eclipse.equinox.p2.metadata.Version;
\r
41 import org.eclipse.equinox.p2.publisher.AdviceFileAdvice;
\r
42 import org.eclipse.equinox.p2.publisher.PublisherInfo;
\r
43 import org.eclipse.equinox.p2.publisher.eclipse.BundleShapeAdvice;
\r
44 import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction;
\r
45 import org.eclipse.equinox.p2.publisher.eclipse.IBundleShapeAdvice;
\r
46 import org.eclipse.equinox.p2.query.IQuery;
\r
47 import org.eclipse.equinox.p2.query.IQueryResult;
\r
48 import org.eclipse.equinox.p2.query.IQueryable;
\r
49 import org.eclipse.equinox.p2.query.QueryUtil;
\r
50 import org.eclipse.equinox.p2.repository.artifact.ArtifactKeyQuery;
\r
51 import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor;
\r
52 import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
\r
53 import org.eclipse.equinox.p2.repository.artifact.IFileArtifactRepository;
\r
54 import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
\r
55 import org.eclipse.osgi.service.resolver.BundleDescription;
\r
56 import org.osgi.framework.BundleException;
\r
57 import org.simantics.databoard.Bindings;
\r
58 import org.simantics.databoard.Files;
\r
59 import org.simantics.databoard.binding.Binding;
\r
60 import org.simantics.databoard.util.StreamUtil;
\r
61 import org.simantics.graph.db.TransferableGraphException;
\r
62 import org.simantics.graph.representation.TransferableGraph1;
\r
65 * This class contains provisioning utilities.
\r
69 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
\r
71 @SuppressWarnings("restriction")
\r
72 public class ProvisioningUtil {
\r
74 private static IRequirement IS_FEATURE_REQUIREMENT = new RequiredCapability("org.eclipse.equinox.p2.eclipse.type", "feature", null, null, false, false, false);
\r
76 public static void getAllRequirements(IInstallableUnit iu, IQueryable<IInstallableUnit> repo, Set<IInstallableUnit> result)
\r
78 if (result.contains(iu)) return;
\r
80 IQuery<IInstallableUnit> reqsQuery = new RequiredIUsQuery(iu);
\r
81 for (IInstallableUnit _iu : repo.query( reqsQuery, null ).toSet()) {
\r
82 if (result.contains(_iu)) continue;
\r
83 getAllRequirements(_iu, repo, result);
\r
89 * Get IUs that are required to install this bundle.
\r
90 * Assumed architecture is x86 and os win32.
\r
91 * Throws an exception if not all requirements can be satisfied.
\r
94 * @param availableIUs
\r
98 public static Collection<IRequirement> getAllRequirements(IInstallableUnit iu, IQueryable<IInstallableUnit> repo)
\r
100 // Installable Units analysed
\r
101 Set<IInstallableUnit> ius = new HashSet<IInstallableUnit>();
\r
104 Set<IRequirement> reqs = new HashSet<IRequirement>();
\r
106 // Satisfied requirements
\r
107 Set<IRequirement> sats = new HashSet<IRequirement>();
\r
109 reqs.addAll( iu.getRequirements() );
\r
111 // Find satisfactions
\r
115 static void _addIU(IInstallableUnit iu, Set<IInstallableUnit> ius, Set<IRequirement> reqs, Set<IRequirement> sats, Set<IRequirement> unsats, IQueryable<IInstallableUnit> repo)
\r
117 if (ius.contains(iu)) return;
\r
120 for (IRequirement req : iu.getRequirements()) {
\r
121 if (sats.contains(req)) continue;
\r
122 if (unsats.contains(req)) continue;
\r
124 // req is unsatisfied
\r
126 IQueryResult<IInstallableUnit> result = repo.query(req, null);
\r
129 for (IInstallableUnit _iu : availableIUs) {
\r
130 if (sats.contains(_iu)) continue;
\r
132 boolean satisfies = _iu.satisfies( )
\r
137 * Get all installable units from a metadata repository
\r
142 public static Collection<IInstallableUnit> getInstallableUnits(IMetadataRepository repo) {
\r
144 // IQuery<IInstallableUnit> query = QueryUtil.createIUQuery(null, VersionRange.emptyRange);
\r
145 IQuery<IInstallableUnit> query = QueryUtil.createIUAnyQuery();
\r
146 IQueryResult<IInstallableUnit> matches = repo.query(query, null);
\r
147 return matches.toUnmodifiableSet();
\r
152 * Test if the {@link IInstallableUnit} is a category.
\r
153 * @param iu the element being tested.
\r
154 * @return <tt>true</tt> if the parameter is a category.
\r
156 public static boolean isCategory(IInstallableUnit iu) {
\r
157 String PROP_TYPE_CATEGORY = "org.eclipse.equinox.p2.type.category"; //$NON-NLS-1$
\r
158 String value = iu.getProperty(PROP_TYPE_CATEGORY);
\r
159 if (value != null && (value.equals(Boolean.TRUE.toString())))
\r
165 * Test if the {@link IInstallableUnit} is a fragment.
\r
166 * @param iu the element being tested.
\r
167 * @return <tt>true</tt> if the parameter is a fragment.
\r
169 public static boolean isFragment(IInstallableUnit iu) {
\r
170 return iu instanceof IInstallableUnitFragment;
\r
174 * Test if the {@link IInstallableUnit} is a group.
\r
175 * @param iu the element being tested.
\r
176 * @return <tt>true</tt> if the parameter is a group.
\r
178 public static boolean isGroup(IInstallableUnit iu) {
\r
179 String PROP_TYPE_GROUP = "org.eclipse.equinox.p2.type.group"; //$NON-NLS-1$
\r
180 String value = iu.getProperty(PROP_TYPE_GROUP);
\r
181 if (value != null && (value.equals(Boolean.TRUE.toString())))
\r
187 * Test if the {@link IInstallableUnit} is a patch.
\r
188 * @param iu the element being tested.
\r
189 * @return <tt>true</tt> if the parameter is a patch.
\r
191 public static boolean isPatch(IInstallableUnit iu) {
\r
192 String PROP_TYPE_PATCH = "org.eclipse.equinox.p2.type.patch"; //$NON-NLS-1$
\r
193 String value = iu.getProperty(PROP_TYPE_PATCH);
\r
194 if (value != null && (value.equals(Boolean.TRUE.toString())))
\r
200 * Checks whether a installable unit is a feature
\r
203 * @return <code>true</code> if is feature
\r
205 public static boolean isFeature(IInstallableUnit iu) {
\r
206 // String value = iu.getProperty("org.eclipse.equinox.p2.eclipse.type");
\r
207 // return value != null && value.equals("feature");
\r
208 return iu.satisfies(IS_FEATURE_REQUIREMENT);
\r
211 public static boolean isGraph(IInstallableUnit iu, IMetadataRepository metadata, IArtifactRepository arts) throws IOException {
\r
212 Collection<IArtifactKey> artifacts = iu.getArtifacts();
\r
213 for (IArtifactKey key : artifacts) {
\r
214 if (isGraphArtifact(arts, key)) return true;
\r
220 * Checks whether artifact is a graph bundle.
\r
222 * @param repo artifact repo
\r
223 * @param key key to artifact
\r
224 * @return <code>true</code> if is a graph bundle
\r
225 * @throws IOException
\r
227 public static boolean isGraphArtifact(IArtifactRepository repo, IArtifactKey key) throws IOException {
\r
228 return hasFile(repo, key, "graph.tg");
\r
231 public static boolean hasFile(IArtifactRepository repo, IArtifactKey key, String filename) throws IOException {
\r
232 boolean isBundle = key.getClassifier().equals("osgi.bundle");
\r
233 if (!isBundle) return false;
\r
235 for (IArtifactDescriptor desc : repo.getArtifactDescriptors(key)) {
\r
236 if (repo instanceof IFileArtifactRepository) {
\r
237 IFileArtifactRepository filerepo = (IFileArtifactRepository) repo;
\r
238 File f = filerepo.getArtifactFile(key);
\r
239 if (!f.exists()) return false;
\r
241 boolean isJar = f.getName().toLowerCase().endsWith(".jar");
\r
242 if (!isJar) return false;
\r
244 JarFile jf = new JarFile(f);
\r
246 Enumeration<JarEntry> enm = jf.entries();
\r
247 while (enm.hasMoreElements()) {
\r
248 JarEntry entry = enm.nextElement();
\r
249 String entryName = entry.getName();
\r
250 if ( entryName.equals(filename) ) return true;
\r
257 int size = Integer.valueOf( desc.getProperties().get("download.size") );
\r
258 ByteArrayOutputStream bos = new ByteArrayOutputStream(size);
\r
259 repo.getArtifact(desc, bos, null);
\r
260 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
\r
261 JarInputStream jis = new JarInputStream( bis );
\r
262 for (JarEntry entry = jis.getNextJarEntry(); entry!=null; entry = jis.getNextJarEntry()) {
\r
263 String entryName = entry.getName();
\r
264 if ( entryName.equals(filename) ) return true;
\r
273 * Get a file from a repository
\r
275 * @param repo artifact repo
\r
276 * @param key key to artifact
\r
277 * @return input stream (must be closed) or null
\r
278 * @throws IOException
\r
280 public static InputStream getFile(IArtifactRepository repo, IArtifactKey key, String filename) throws IOException {
\r
281 boolean isBundle = key.getClassifier().equals("osgi.bundle");
\r
282 if (!isBundle) return null;
\r
284 for (IArtifactDescriptor desc : repo.getArtifactDescriptors(key)) {
\r
285 if (repo instanceof IFileArtifactRepository) {
\r
286 IFileArtifactRepository filerepo = (IFileArtifactRepository) repo;
\r
287 File f = filerepo.getArtifactFile(key);
\r
288 if (!f.exists()) return null;
\r
290 boolean isJar = f.getName().toLowerCase().endsWith(".jar");
\r
291 if (!isJar) return null;
\r
293 JarFile jf = new JarFile(f);
\r
295 Enumeration<JarEntry> enm = jf.entries();
\r
296 while (enm.hasMoreElements()) {
\r
297 JarEntry entry = enm.nextElement();
\r
298 String entryName = entry.getName();
\r
299 if (! entryName.equals(filename) ) continue;
\r
300 InputStream is = jf.getInputStream(entry);
\r
301 byte[] data = StreamUtil.readFully(is);
\r
303 return new ByteArrayInputStream(data);
\r
310 int size = Integer.valueOf( desc.getProperties().get("download.size") );
\r
311 ByteArrayOutputStream bos = new ByteArrayOutputStream(size);
\r
312 repo.getArtifact(desc, bos, null);
\r
313 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
\r
314 JarInputStream jis = new JarInputStream( bis );
\r
315 for (JarEntry entry = jis.getNextJarEntry(); entry!=null; entry = jis.getNextJarEntry()) {
\r
316 String entryName = entry.getName();
\r
317 if (! entryName.equals(filename) ) continue;
\r
326 * Checks whether artifact is a graph bundle.
\r
328 * @param repo artifact repo
\r
329 * @param key key to artifact
\r
330 * @return manifest or null
\r
331 * @throws IOException
\r
333 public static Manifest getManifest(IArtifactRepository repo, IArtifactKey key) throws IOException {
\r
334 InputStream is = getFile(repo, key, "META-INF/MANIFEST.MF");
\r
335 if (is == null) return null;
\r
337 return new Manifest(is);
\r
344 * Checks whether artifact is a graph bundle.
\r
346 * @param repo artifact repo
\r
347 * @param key key to artifact
\r
348 * @return manifest or null
\r
349 * @throws IOException
\r
351 public static Manifest getSimanticsManifest(IArtifactRepository repo, IArtifactKey key) throws IOException {
\r
352 InputStream is = getFile(repo, key, "META-INF/SIMANTICS.MF");
\r
353 if (is == null) return null;
\r
355 return new Manifest(is);
\r
361 public static IArtifactKey[] getAllArtifactKeys(IArtifactRepository repo) {
\r
362 return repo.query( ArtifactKeyQuery.ALL_KEYS, null ).toArray( IArtifactKey.class );
\r
365 public static void getUserInstallables(IArtifactRepository repo, Collection<String> result) throws IOException {
\r
366 IArtifactKey[] keys = repo.query( ArtifactKeyQuery.ALL_KEYS, null ).toArray( IArtifactKey.class );
\r
367 for (IArtifactKey key : keys) {
\r
368 Manifest mf = getSimanticsManifest(repo, key);
\r
369 if (mf==null) continue;
\r
370 String bundleId = mf.getMainAttributes().getValue("Simantics-Feature-Bundle");
\r
371 result.add( bundleId );
\r
375 public static GraphBundle getGraphBundle(IArtifactRepository repo, IArtifactKey key, IInstallableUnit iu)
\r
376 throws TransferableGraphException
\r
378 String name = ProvisioningUtil.getName(iu);
\r
379 TransferableGraph1 tg = getTransferableGraph(repo, key);
\r
380 return new GraphBundleEx(name, tg, key.getId(), key.getVersion());
\r
384 * Get the .tg file from a Graph bundle
\r
388 * @return byte[] transferable fraph
\r
389 * @throws TGException
\r
391 public static TransferableGraph1 getTransferableGraph(IArtifactRepository repo, IArtifactKey key)
\r
392 throws TransferableGraphException
\r
394 boolean isBundle = key.getClassifier().equals("osgi.bundle");
\r
395 if (!isBundle) throw new TransferableGraphException("Artifact Key is not osgi.bundle");
\r
397 for (IArtifactDescriptor desc : repo.getArtifactDescriptors(key)) {
\r
398 if (repo instanceof IFileArtifactRepository) {
\r
399 IFileArtifactRepository filerepo = (IFileArtifactRepository) repo;
\r
400 File f = filerepo.getArtifactFile(key);
\r
402 throw new TransferableGraphException(f+" not found");
\r
405 boolean isJar = f.getName().toLowerCase().endsWith(".jar");
\r
406 if (!isJar) throw new TransferableGraphException(f+" is not jar as expected");
\r
410 jf = new JarFile(f);
\r
411 Enumeration<JarEntry> enm = jf.entries();
\r
412 while (enm.hasMoreElements()) {
\r
413 JarEntry entry = enm.nextElement();
\r
414 String entryName = entry.getName().toLowerCase();
\r
415 boolean isTG = entryName.equalsIgnoreCase("graph.tg");
\r
416 if (!isTG) continue;
\r
418 Binding binding = Bindings.getBindingUnchecked( TransferableGraph1.class );
\r
419 long size = entry.getSize();
\r
420 InputStream is = jf.getInputStream(entry);
\r
421 return (TransferableGraph1) Files.readFile(is, size, binding);
\r
422 } catch (IOException e) {
\r
423 throw new TransferableGraphException(e);
\r
426 } catch (IOException e) {
\r
427 throw new TransferableGraphException(e);
\r
430 if (jf!=null) jf.close();
\r
431 } catch (IOException e) {
\r
434 throw new TransferableGraphException(".tg file was not found in "+key);
\r
438 int size = Integer.valueOf( desc.getProperties().get("download.size") );
\r
439 ByteArrayOutputStream bos = new ByteArrayOutputStream(size);
\r
440 repo.getArtifact(desc, bos, null);
\r
441 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
\r
442 JarInputStream jis = new JarInputStream( bis );
\r
443 for (JarEntry entry = jis.getNextJarEntry(); entry!=null; entry = jis.getNextJarEntry()) {
\r
444 String entryName = entry.getName().toLowerCase();
\r
445 boolean isTG = entryName.equalsIgnoreCase("graph.tg");
\r
446 if (!isTG) continue;
\r
447 //long fileSize = entry.getSize();
\r
448 Binding binding = Bindings.getBindingUnchecked(TransferableGraph1.class);
\r
449 return (TransferableGraph1) Files.readFile(jis, binding);
\r
452 } catch (IOException e) {
\r
453 throw new TransferableGraphException(e);
\r
455 throw new TransferableGraphException(".tg file was not found in "+key);
\r
458 throw new TransferableGraphException(".tg file was not found in "+key);
\r
461 public static String getDescription(IInstallableUnit iu) {
\r
462 return iu.getProperty("org.eclipse.equinox.p2.description");
\r
465 public static String getName(IInstallableUnit iu) {
\r
466 return iu.getProperty("org.eclipse.equinox.p2.name");
\r
470 * Returns an IU corresponding to the given artifact key and bundle, or <code>null</code>
\r
471 * if an IU could not be created.
\r
473 public static IInstallableUnit createBundleIU(IArtifactKey artifactKey, File bundleFile) {
\r
474 BundleDescription bundleDescription = null;
\r
476 bundleDescription = BundlesAction.createBundleDescription(bundleFile);
\r
477 } catch (IOException | BundleException e) {
\r
478 e.printStackTrace();
\r
480 if (bundleDescription == null)
\r
482 PublisherInfo info = new PublisherInfo();
\r
483 Version version = Version.create(bundleDescription.getVersion().toString());
\r
484 AdviceFileAdvice advice = new AdviceFileAdvice(bundleDescription.getSymbolicName(), version, new Path(bundleFile.getAbsolutePath()), AdviceFileAdvice.BUNDLE_ADVICE_FILE);
\r
485 if (advice.containsAdvice())
\r
486 info.addAdvice(advice);
\r
487 String shape = bundleFile.isDirectory() ? IBundleShapeAdvice.DIR : IBundleShapeAdvice.JAR;
\r
488 info.addAdvice(new BundleShapeAdvice(bundleDescription.getSymbolicName(), version, shape));
\r
489 return BundlesAction.createBundleIU(bundleDescription, artifactKey, info);
\r
492 public static IFileArtifactRepository getDownloadCacheRepo(IProvisioningAgent agent) throws ProvisionException {
\r
493 return org.eclipse.equinox.internal.p2.touchpoint.natives.Util.getDownloadCacheRepo(agent);
\r
496 public static Comparator<IInstallableUnit> getIUComparator() {
\r
497 return new Comparator<IInstallableUnit>() {
\r
499 public int compare(IInstallableUnit o1, IInstallableUnit o2) {
\r
500 return o1.getId().compareTo(o2.getId());
\r
506 public static TreeSet<IInstallableUnit> getSorted( Iterator<IInstallableUnit> iter ) {
\r
507 TreeSet<IInstallableUnit> result = new TreeSet<IInstallableUnit>( getIUComparator() );
\r
508 while (iter.hasNext()) {
\r
509 IInstallableUnit iu = iter.next();
\r
515 public static TreeSet<IInstallableUnit> getSorted( IQueryResult<IInstallableUnit> result ) {
\r
516 return getSorted(result.iterator());
\r