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