X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.project%2Fsrc%2Forg%2Fsimantics%2Fproject%2Fmanagement%2FProvisioningUtil.java;fp=bundles%2Forg.simantics.project%2Fsrc%2Forg%2Fsimantics%2Fproject%2Fmanagement%2FProvisioningUtil.java;h=858a13e34afbc7742d034455e85d2c7c5df84c36;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.project/src/org/simantics/project/management/ProvisioningUtil.java b/bundles/org.simantics.project/src/org/simantics/project/management/ProvisioningUtil.java new file mode 100644 index 000000000..858a13e34 --- /dev/null +++ b/bundles/org.simantics.project/src/org/simantics/project/management/ProvisioningUtil.java @@ -0,0 +1,520 @@ +/******************************************************************************* + * 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()); + } + +} +