/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.project.management; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.Comparator; import java.util.Enumeration; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import org.eclipse.core.runtime.Path; import org.eclipse.equinox.internal.p2.metadata.RequiredCapability; import org.eclipse.equinox.internal.p2.touchpoint.eclipse.Util; import org.eclipse.equinox.internal.p2.ui.query.RequiredIUsQuery; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.core.ProvisionException; import org.eclipse.equinox.p2.metadata.IArtifactKey; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IInstallableUnitFragment; import org.eclipse.equinox.p2.metadata.IRequirement; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.publisher.AdviceFileAdvice; import org.eclipse.equinox.p2.publisher.PublisherInfo; import org.eclipse.equinox.p2.publisher.eclipse.BundleShapeAdvice; import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; import org.eclipse.equinox.p2.publisher.eclipse.IBundleShapeAdvice; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.query.IQueryable; import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.equinox.p2.repository.artifact.ArtifactKeyQuery; import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; import org.eclipse.equinox.p2.repository.artifact.IFileArtifactRepository; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; import org.eclipse.osgi.service.resolver.BundleDescription; import org.osgi.framework.BundleException; import org.simantics.databoard.Bindings; import org.simantics.databoard.Files; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.util.StreamUtil; import org.simantics.graph.db.TransferableGraphException; import org.simantics.graph.representation.TransferableGraph1; /** * This class contains provisioning utilities. * * @see QueryUtil * @see Util * @author Toni Kalajainen */ @SuppressWarnings("restriction") public class ProvisioningUtil { private static IRequirement IS_FEATURE_REQUIREMENT = new RequiredCapability("org.eclipse.equinox.p2.eclipse.type", "feature", null, null, false, false, false); public static void getAllRequirements(IInstallableUnit iu, IQueryable repo, Set result) { if (result.contains(iu)) return; result.add(iu); IQuery reqsQuery = new RequiredIUsQuery(iu); for (IInstallableUnit _iu : repo.query( reqsQuery, null ).toSet()) { if (result.contains(_iu)) continue; getAllRequirements(_iu, repo, result); } } /** * Get IUs that are required to install this bundle. * Assumed architecture is x86 and os win32. * Throws an exception if not all requirements can be satisfied. * * @param iu * @param availableIUs * @return */ /* public static Collection getAllRequirements(IInstallableUnit iu, IQueryable repo) { // Installable Units analysed Set ius = new HashSet(); // Requirements Set reqs = new HashSet(); // Satisfied requirements Set sats = new HashSet(); ius.add(iu); reqs.addAll( iu.getRequirements() ); // Find satisfactions return result; }*/ /* static void _addIU(IInstallableUnit iu, Set ius, Set reqs, Set sats, Set unsats, IQueryable repo) { if (ius.contains(iu)) return; ius.add( iu ); for (IRequirement req : iu.getRequirements()) { if (sats.contains(req)) continue; if (unsats.contains(req)) continue; // req is unsatisfied IQuery IQueryResult result = repo.query(req, null); } for (IInstallableUnit _iu : availableIUs) { if (sats.contains(_iu)) continue; boolean satisfies = _iu.satisfies( ) } }*/ /** * Get all installable units from a metadata repository * * @param repo * @return */ public static Collection getInstallableUnits(IMetadataRepository repo) { // IQuery query = QueryUtil.createIUQuery(null, VersionRange.emptyRange); IQuery query = QueryUtil.createIUAnyQuery(); IQueryResult matches = repo.query(query, null); return matches.toUnmodifiableSet(); } /** * Test if the {@link IInstallableUnit} is a category. * @param iu the element being tested. * @return true if the parameter is a category. */ public static boolean isCategory(IInstallableUnit iu) { String PROP_TYPE_CATEGORY = "org.eclipse.equinox.p2.type.category"; //$NON-NLS-1$ String value = iu.getProperty(PROP_TYPE_CATEGORY); if (value != null && (value.equals(Boolean.TRUE.toString()))) return true; return false; } /** * Test if the {@link IInstallableUnit} is a fragment. * @param iu the element being tested. * @return true if the parameter is a fragment. */ public static boolean isFragment(IInstallableUnit iu) { return iu instanceof IInstallableUnitFragment; } /** * Test if the {@link IInstallableUnit} is a group. * @param iu the element being tested. * @return true if the parameter is a group. */ public static boolean isGroup(IInstallableUnit iu) { String PROP_TYPE_GROUP = "org.eclipse.equinox.p2.type.group"; //$NON-NLS-1$ String value = iu.getProperty(PROP_TYPE_GROUP); if (value != null && (value.equals(Boolean.TRUE.toString()))) return true; return false; } /** * Test if the {@link IInstallableUnit} is a patch. * @param iu the element being tested. * @return true if the parameter is a patch. */ public static boolean isPatch(IInstallableUnit iu) { String PROP_TYPE_PATCH = "org.eclipse.equinox.p2.type.patch"; //$NON-NLS-1$ String value = iu.getProperty(PROP_TYPE_PATCH); if (value != null && (value.equals(Boolean.TRUE.toString()))) return true; return false; } /** * Checks whether a installable unit is a feature * * @param iu * @return true if is feature */ public static boolean isFeature(IInstallableUnit iu) { // String value = iu.getProperty("org.eclipse.equinox.p2.eclipse.type"); // return value != null && value.equals("feature"); return iu.satisfies(IS_FEATURE_REQUIREMENT); } public static boolean isGraph(IInstallableUnit iu, IMetadataRepository metadata, IArtifactRepository arts) throws IOException { Collection artifacts = iu.getArtifacts(); for (IArtifactKey key : artifacts) { if (isGraphArtifact(arts, key)) return true; } return false; } /** * Checks whether artifact is a graph bundle. * * @param repo artifact repo * @param key key to artifact * @return true if is a graph bundle * @throws IOException */ public static boolean isGraphArtifact(IArtifactRepository repo, IArtifactKey key) throws IOException { return hasFile(repo, key, "graph.tg"); } public static boolean hasFile(IArtifactRepository repo, IArtifactKey key, String filename) throws IOException { boolean isBundle = key.getClassifier().equals("osgi.bundle"); if (!isBundle) return false; for (IArtifactDescriptor desc : repo.getArtifactDescriptors(key)) { if (repo instanceof IFileArtifactRepository) { IFileArtifactRepository filerepo = (IFileArtifactRepository) repo; File f = filerepo.getArtifactFile(key); if (!f.exists()) return false; boolean isJar = f.getName().toLowerCase().endsWith(".jar"); if (!isJar) return false; JarFile jf = new JarFile(f); try { Enumeration enm = jf.entries(); while (enm.hasMoreElements()) { JarEntry entry = enm.nextElement(); String entryName = entry.getName(); if ( entryName.equals(filename) ) return true; } } finally { jf.close(); } } else { int size = Integer.valueOf( desc.getProperties().get("download.size") ); ByteArrayOutputStream bos = new ByteArrayOutputStream(size); repo.getArtifact(desc, bos, null); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); JarInputStream jis = new JarInputStream( bis ); for (JarEntry entry = jis.getNextJarEntry(); entry!=null; entry = jis.getNextJarEntry()) { String entryName = entry.getName(); if ( entryName.equals(filename) ) return true; } } } return false; } /** * Get a file from a repository * * @param repo artifact repo * @param key key to artifact * @return input stream (must be closed) or null * @throws IOException */ public static InputStream getFile(IArtifactRepository repo, IArtifactKey key, String filename) throws IOException { boolean isBundle = key.getClassifier().equals("osgi.bundle"); if (!isBundle) return null; for (IArtifactDescriptor desc : repo.getArtifactDescriptors(key)) { if (repo instanceof IFileArtifactRepository) { IFileArtifactRepository filerepo = (IFileArtifactRepository) repo; File f = filerepo.getArtifactFile(key); if (!f.exists()) return null; boolean isJar = f.getName().toLowerCase().endsWith(".jar"); if (!isJar) return null; JarFile jf = new JarFile(f); try { Enumeration enm = jf.entries(); while (enm.hasMoreElements()) { JarEntry entry = enm.nextElement(); String entryName = entry.getName(); if (! entryName.equals(filename) ) continue; InputStream is = jf.getInputStream(entry); byte[] data = StreamUtil.readFully(is); is.close(); return new ByteArrayInputStream(data); } } finally { jf.close(); } } else { int size = Integer.valueOf( desc.getProperties().get("download.size") ); ByteArrayOutputStream bos = new ByteArrayOutputStream(size); repo.getArtifact(desc, bos, null); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); JarInputStream jis = new JarInputStream( bis ); for (JarEntry entry = jis.getNextJarEntry(); entry!=null; entry = jis.getNextJarEntry()) { String entryName = entry.getName(); if (! entryName.equals(filename) ) continue; return jis; } } } return null; } /** * Checks whether artifact is a graph bundle. * * @param repo artifact repo * @param key key to artifact * @return manifest or null * @throws IOException */ public static Manifest getManifest(IArtifactRepository repo, IArtifactKey key) throws IOException { InputStream is = getFile(repo, key, "META-INF/MANIFEST.MF"); if (is == null) return null; try { return new Manifest(is); } finally { is.close(); } } /** * Checks whether artifact is a graph bundle. * * @param repo artifact repo * @param key key to artifact * @return manifest or null * @throws IOException */ public static Manifest getSimanticsManifest(IArtifactRepository repo, IArtifactKey key) throws IOException { InputStream is = getFile(repo, key, "META-INF/SIMANTICS.MF"); if (is == null) return null; try { return new Manifest(is); } finally { is.close(); } } public static IArtifactKey[] getAllArtifactKeys(IArtifactRepository repo) { return repo.query( ArtifactKeyQuery.ALL_KEYS, null ).toArray( IArtifactKey.class ); } public static void getUserInstallables(IArtifactRepository repo, Collection result) throws IOException { IArtifactKey[] keys = repo.query( ArtifactKeyQuery.ALL_KEYS, null ).toArray( IArtifactKey.class ); for (IArtifactKey key : keys) { Manifest mf = getSimanticsManifest(repo, key); if (mf==null) continue; String bundleId = mf.getMainAttributes().getValue("Simantics-Feature-Bundle"); result.add( bundleId ); } } public static GraphBundle getGraphBundle(IArtifactRepository repo, IArtifactKey key, IInstallableUnit iu) throws TransferableGraphException { String name = ProvisioningUtil.getName(iu); TransferableGraph1 tg = getTransferableGraph(repo, key); return new GraphBundleEx(name, tg, key.getId(), key.getVersion()); } /** * Get the .tg file from a Graph bundle * * @param repo * @param key * @return byte[] transferable fraph * @throws TGException */ public static TransferableGraph1 getTransferableGraph(IArtifactRepository repo, IArtifactKey key) throws TransferableGraphException { boolean isBundle = key.getClassifier().equals("osgi.bundle"); if (!isBundle) throw new TransferableGraphException("Artifact Key is not osgi.bundle"); for (IArtifactDescriptor desc : repo.getArtifactDescriptors(key)) { if (repo instanceof IFileArtifactRepository) { IFileArtifactRepository filerepo = (IFileArtifactRepository) repo; File f = filerepo.getArtifactFile(key); if (!f.exists()) { throw new TransferableGraphException(f+" not found"); } boolean isJar = f.getName().toLowerCase().endsWith(".jar"); if (!isJar) throw new TransferableGraphException(f+" is not jar as expected"); JarFile jf = null; try { jf = new JarFile(f); Enumeration enm = jf.entries(); while (enm.hasMoreElements()) { JarEntry entry = enm.nextElement(); String entryName = entry.getName().toLowerCase(); boolean isTG = entryName.equalsIgnoreCase("graph.tg"); if (!isTG) continue; try { Binding binding = Bindings.getBindingUnchecked( TransferableGraph1.class ); long size = entry.getSize(); InputStream is = jf.getInputStream(entry); return (TransferableGraph1) Files.readFile(is, size, binding); } catch (IOException e) { throw new TransferableGraphException(e); } } } catch (IOException e) { throw new TransferableGraphException(e); } finally { try { if (jf!=null) jf.close(); } catch (IOException e) { } } throw new TransferableGraphException(".tg file was not found in "+key); } else { try { int size = Integer.valueOf( desc.getProperties().get("download.size") ); ByteArrayOutputStream bos = new ByteArrayOutputStream(size); repo.getArtifact(desc, bos, null); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); JarInputStream jis = new JarInputStream( bis ); for (JarEntry entry = jis.getNextJarEntry(); entry!=null; entry = jis.getNextJarEntry()) { String entryName = entry.getName().toLowerCase(); boolean isTG = entryName.equalsIgnoreCase("graph.tg"); if (!isTG) continue; //long fileSize = entry.getSize(); Binding binding = Bindings.getBindingUnchecked(TransferableGraph1.class); return (TransferableGraph1) Files.readFile(jis, binding); } } catch (IOException e) { throw new TransferableGraphException(e); } throw new TransferableGraphException(".tg file was not found in "+key); } } throw new TransferableGraphException(".tg file was not found in "+key); } public static String getDescription(IInstallableUnit iu) { return iu.getProperty("org.eclipse.equinox.p2.description"); } public static String getName(IInstallableUnit iu) { return iu.getProperty("org.eclipse.equinox.p2.name"); } /** * Returns an IU corresponding to the given artifact key and bundle, or null * if an IU could not be created. */ public static IInstallableUnit createBundleIU(IArtifactKey artifactKey, File bundleFile) { BundleDescription bundleDescription = null; try { bundleDescription = BundlesAction.createBundleDescription(bundleFile); } catch (IOException | BundleException e) { e.printStackTrace(); } if (bundleDescription == null) return null; PublisherInfo info = new PublisherInfo(); Version version = Version.create(bundleDescription.getVersion().toString()); AdviceFileAdvice advice = new AdviceFileAdvice(bundleDescription.getSymbolicName(), version, new Path(bundleFile.getAbsolutePath()), AdviceFileAdvice.BUNDLE_ADVICE_FILE); if (advice.containsAdvice()) info.addAdvice(advice); String shape = bundleFile.isDirectory() ? IBundleShapeAdvice.DIR : IBundleShapeAdvice.JAR; info.addAdvice(new BundleShapeAdvice(bundleDescription.getSymbolicName(), version, shape)); return BundlesAction.createBundleIU(bundleDescription, artifactKey, info); } public static IFileArtifactRepository getDownloadCacheRepo(IProvisioningAgent agent) throws ProvisionException { return org.eclipse.equinox.internal.p2.touchpoint.natives.Util.getDownloadCacheRepo(agent); } public static Comparator getIUComparator() { return new Comparator() { @Override public int compare(IInstallableUnit o1, IInstallableUnit o2) { return o1.getId().compareTo(o2.getId()); } }; } public static TreeSet getSorted( Iterator iter ) { TreeSet result = new TreeSet( getIUComparator() ); while (iter.hasNext()) { IInstallableUnit iu = iter.next(); result.add( iu ); } return result; } public static TreeSet getSorted( IQueryResult result ) { return getSorted(result.iterator()); } }