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