/******************************************************************************* * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. * 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.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.jar.Manifest; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.equinox.internal.p2.artifact.repository.CompositeArtifactRepository; import org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepository; import org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepositoryFactory; import org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository; import org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository; import org.eclipse.equinox.internal.p2.metadata.repository.SimpleMetadataRepositoryFactory; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.core.ProvisionException; import org.eclipse.equinox.p2.internal.repository.mirroring.Mirroring; import org.eclipse.equinox.p2.metadata.IArtifactKey; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IVersionedId; import org.eclipse.equinox.p2.metadata.VersionedId; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.equinox.p2.repository.artifact.ArtifactKeyQuery; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager; import org.simantics.graph.db.TransferableGraphException; import org.simantics.graph.query.Graphs; import org.simantics.graph.query.IGraph; import org.simantics.graph.query.Paths; import org.simantics.graph.query.Res; import org.simantics.graph.query.UriUtils; import org.simantics.graph.representation.TransferableGraph1; import org.simantics.scl.reflection.OntologyVersions; import org.simantics.utils.FileUtils; /** * Bundlepool is a repository of artifacts and installable units. * * @author Toni Kalajainen */ @SuppressWarnings("restriction") public class BundlePool { /** Application default pool. It is located at "workspace/bundlepool" */ static BundlePool DEFAULT; IMetadataRepository metadataRepository; IArtifactRepository artifactRepository; IProvisioningAgent metadataAgent; IProvisioningAgent artifactAgent; URI metadataAgentLocation; URI artifactAgentLocation; List userInstallables; /** All features that were discovered in the repository */ Set projectFeatures = new HashSet(); /** * Get SPM Bundle Pool * * @return SPM Bundle Pool */ public synchronized static BundlePool getDefault() { if (DEFAULT == null) { try { IPath path = Platform.getLocation().append("bundlepool"); URI metadataRepositoryLocation = path.toFile().toURI(); URI artifactRepositoryLocation = path.toFile().toURI(); IProvisioningAgent agent = P2Util.createAgent( path ); DEFAULT = new BundlePool(metadataRepositoryLocation, artifactRepositoryLocation, agent); } catch (ProvisionException e) { // Not expected throw new RuntimeException(e); } } return DEFAULT; } /** * Create bundle pool in a directory on a local hard drive. * This location will contain metadata repository, artifact repository and * P2 workarea (Agent). * * @param location * @return bundle pool */ public static BundlePool createAt(File location) { try { File canonicalLocation = location.getCanonicalFile(); URI metadataRepositoryLocation = canonicalLocation.toURI(); URI artifactRepositoryLocation = canonicalLocation.toURI(); IPath agentLocation = new Path( canonicalLocation.toString() ); IProvisioningAgent agent = P2Util.createAgent( agentLocation ); return new BundlePool(metadataRepositoryLocation, artifactRepositoryLocation, agent); } catch (IOException e) { throw new RuntimeException(e); } catch (org.eclipse.equinox.p2.core.ProvisionException e) { throw new RuntimeException(e); } } public BundlePool(URI metadataRepositoryLocation, URI artifactRepositoryLocation, IProvisioningAgent agent) throws ProvisionException { this.metadataAgent = agent; this.artifactAgent = agent; SimpleMetadataRepositoryFactory metRepFactory = new SimpleMetadataRepositoryFactory(); metRepFactory.setAgent( metadataAgent ); try { metadataRepository = metRepFactory.load(metadataRepositoryLocation, 0, null); } catch (org.eclipse.equinox.p2.core.ProvisionException pe) { new File(metadataRepositoryLocation).mkdirs(); Map repoProperties = new HashMap(); metadataRepository = metRepFactory.create(metadataRepositoryLocation, "SPM Bundle Pool", "file", repoProperties); } // IMetadataRepository metadataRepository = new LocalMetadataRepository( agent, repositoryLocation, "My Metadata Repository", Collections.EMPTY_MAP ); // IMetadataRepository metadataRepository = getMetadataRepository(agent, repositoryLocation); // IArtifactRepository artifactRepository = new SimpleArtifactRepositoryFactory().create(repositoryLocation, "Sample Artifact Repository", ArtifactRepositoryManager.TYPE_SIMPLE_REPOSITORY, Collections.EMPTY_MAP); // SimpleArtifactRepository artifactRepository = new SimpleArtifactRepository( agent, "My Simple Artifact Repository", repositoryLocation, Collections.EMPTY_MAP); SimpleArtifactRepositoryFactory artRepFactory = new SimpleArtifactRepositoryFactory(); artRepFactory.setAgent( artifactAgent ); try { artifactRepository = artRepFactory.load(artifactRepositoryLocation, 0, null); } catch (org.eclipse.equinox.p2.core.ProvisionException pe) { new File(artifactRepositoryLocation).mkdirs(); Map repoProperties = new HashMap(); artifactRepository = artRepFactory.create(artifactRepositoryLocation, "SPM Bundle Pool", "file", repoProperties); } init(); } public BundlePool(IMetadataRepository metadataRepository, IArtifactRepository artifactRepository) throws ProvisionException { this.metadataRepository = metadataRepository; this.artifactRepository = artifactRepository; this.metadataAgent = metadataRepository.getProvisioningAgent(); this.artifactAgent = artifactRepository.getProvisioningAgent(); init(); } /** * Init prepares with the following actions: * o loads transferable graphs * o discovers Features and collects Feature URIs, Artifacts and Installable Units * * @throws ProvisionException */ protected void init() throws ProvisionException { try { projectFeatures.clear(); ArrayList platformTGs = new ArrayList(); for (IArtifactKey key : getAllArtifactKeys()) { boolean hasGraph = ProvisioningUtil.hasFile(artifactRepository, key, "graph.tg"); if (!hasGraph) continue; // Read Graph TransferableGraph1 graph = ProvisioningUtil.getTransferableGraph(artifactRepository, key); platformTGs.add(graph); } // Create new project, use all features available in Platform final List poolFeatures = new ArrayList(); // Convert graph instances GraphBundleEx l0 = getLayer0(); String l0v = l0.getMajor() + "." + l0.getMinor(); IGraph graph = Graphs.createGraph(new Paths(l0v), platformTGs); for(Res feature : graph.getInstances(UriUtils.uriToPath(OntologyVersions.getInstance().currentVersion("http://www.simantics.org/Project-0.0/Feature" )))) { poolFeatures.add( feature.toString() ); } } catch (TransferableGraphException e) { throw new ProvisionException("Problem", e); } catch (IOException e) { throw new ProvisionException("Failed to read graph.tg", e); } } public IMetadataRepository getMetadataRepository() { return metadataRepository; } public IArtifactRepository getArtifactRepository() { return artifactRepository; } public IArtifactKey[] getAllArtifactKeys() { return artifactRepository.query( ArtifactKeyQuery.ALL_KEYS, null ).toArray( IArtifactKey.class ); } public GraphBundleEx getLayer0() throws ProvisionException, TransferableGraphException { IVersionedId vid = VersionedId.parse("org.simantics.layer0"); Set result = metadataRepository.query( QueryUtil.createLatestQuery( QueryUtil.createIUQuery(vid) ), null).toSet(); if (result.isEmpty()) throw new RuntimeException("Unexpectedly got no IU for "+vid); if (result.size()>1) throw new RuntimeException("Unexpectedly got more than one latest IU for "+vid); IInstallableUnit iu = result.iterator().next(); IArtifactKey key = toSingleArtifact(iu); TransferableGraph1 graph = getTransferableGraph( key ); return new GraphBundleEx( "Layer0", graph, key); } public TransferableGraph1 getTransferableGraph(IArtifactKey artifactKey) throws ProvisionException, TransferableGraphException { return ProvisioningUtil.getTransferableGraph( artifactRepository, artifactKey); } /** * Get all features. * * @param a list of features * @throws ProvisionException */ public void getFeatures(List features) throws ProvisionException { IMetadataRepository metadataRepository = getMetadataRepository(); Collection ius = ProvisioningUtil.getInstallableUnits(metadataRepository); for (IInstallableUnit iu : ius) { if (ProvisioningUtil.isGroup(iu)) { // if (P2Util.isFeature(iu)) { BundleInfo b = BundleInfo.read(iu); features.add( b ); } } } /** * Get bundle info * * @param id bundle id * @return bundle info */ public BundleInfo getBundleInfo(String id) { IQuery query = QueryUtil.createLatestQuery( QueryUtil.createIUQuery(id) ); IQueryResult queryResult = metadataRepository.query(query, null); IInstallableUnit[] array = queryResult.toArray( IInstallableUnit.class ); for (IInstallableUnit iu : array) { BundleInfo bi = BundleInfo.read(iu); return bi; } return null; } /** * Get the features that visible for the end-user. * User installable features are configured in Simantics manifest files * (META-INF/SIMANTICS.MF as Simantics-Features-Bundle -property) * * @param result * @throws IOException */ // public void getUserInstallableFeatures(Collection result) throws IOException { // ArrayList ids = new ArrayList(); // ProvisioningUtil.getUserInstallables(artifactRepository, ids); // for (String id : ids) { // BundleInfo bi = getBundleInfo(id); // if (bi != null) result.add( bi ); // } // // Add workspace bundle // BundleInfo bi = getBundleInfo( "org.simantics.workbench.product" ); // if (bi != null) result.add( bi ); // } /** * Get all groups. * * @param a list of features * @throws ProvisionException */ // public void getInstallableFeatures(List features) throws ProvisionException { // IMetadataRepository metadataRepository = getMetadataRepository(); // // Collection ius = ProvisioningUtil.getInstallableUnits(metadataRepository); // for (IInstallableUnit iu : ius) { // if (ProvisioningUtil.isGroup(iu)) { //// if (P2Util.isFeature(iu)) { // BundleInfo b = BundleInfo.read(iu); // features.add( b ); // } // } // } /** * Mirror source locations to the bundle pool. * * @param monitor * @param sourceLocations * @return * @throws ProvisionException */ public IStatus download(IProgressMonitor monitor, URI[] sourceLocations) throws ProvisionException { try { monitor.beginTask("Synchronizing Local repository with web repositories", 10); @SuppressWarnings("unused") IMetadataRepositoryManager metaRepoMgr = (IMetadataRepositoryManager) metadataAgent.getService(IMetadataRepositoryManager.SERVICE_NAME); @SuppressWarnings("unused") IArtifactRepositoryManager artsRepoMgr = (IArtifactRepositoryManager) artifactAgent.getService(IArtifactRepositoryManager.SERVICE_NAME); // Create dest repos monitor.setTaskName("Setting up local metadata repository"); LocalMetadataRepository dstMetaRepo = (LocalMetadataRepository) metadataRepository; monitor.worked(1); monitor.setTaskName("Setting up local artifact repository"); SimpleArtifactRepository dstArtsRepo = (SimpleArtifactRepository) artifactRepository; monitor.worked(1); // Create a source repos monitor.setTaskName("Setting up remote artifact repository"); CompositeArtifactRepository srcArtsRepo = CompositeArtifactRepository.createMemoryComposite( metadataAgent /* ? */ ); for (URI uri : sourceLocations) srcArtsRepo.addChild(uri); monitor.worked(1); monitor.setTaskName("Setting up remote metadata repository"); CompositeMetadataRepository srcMetaRepo = CompositeMetadataRepository.createMemoryComposite( artifactAgent /* ? */ ); for (URI uri : sourceLocations) srcMetaRepo.addChild(uri); monitor.worked(1); monitor.setTaskName("Retrieving Installable Units"); @SuppressWarnings("unused") Collection ius = ProvisioningUtil.getInstallableUnits(srcMetaRepo); monitor.worked(1); monitor.setTaskName("Mirroring Metadata"); // Get all IUs from source IQueryResult allIUs = srcMetaRepo.query(QueryUtil.createIUAnyQuery(), monitor); // Put the IUs to dst dstMetaRepo.addInstallableUnits(allIUs.toUnmodifiableSet()); dstMetaRepo.addReferences(srcMetaRepo.getReferences()); monitor.worked(1); monitor.setTaskName("Mirroring Artifacts"); boolean compare = false; boolean failOnError = true; //boolean raw = true; boolean verbose = false; boolean validate = false; //boolean mirrorReferences = false; String comparatorID = ""; Mirroring mirror = new Mirroring(srcArtsRepo, dstArtsRepo, false); mirror.setCompare(compare); mirror.setComparatorId(comparatorID); // mirror.setBaseline(null); mirror.setValidate(validate); // mirror.setCompareExclusions(); IStatus result = mirror.run(failOnError, verbose); if (result.getException()!=null) throw new ProvisionException(result); init(); return result; } catch (IllegalArgumentException iae) { return new Status(IStatus.ERROR, "org.simantics.project", iae.getMessage(), iae); } } public IInstallableUnit toSingleInstallableUnit(IVersionedId id) throws ProvisionException { Set result = metadataRepository.query( QueryUtil.createIUQuery(id), null).toSet(); if (result.size() != 1) throw new RuntimeException("Unexpectedly got more than one latest IU for "+id); return result.iterator().next(); } public IArtifactKey toSingleArtifact(IVersionedId id) throws ProvisionException { IInstallableUnit iu = toSingleInstallableUnit(id); if (iu.getArtifacts().size() != 1) throw new RuntimeException("Unexpectedly got more than one artifact for "); return iu.getArtifacts().iterator().next(); } /** * Get file from an artifact. * * @param key * @param filename * @return inputstream or null. Inputstream must be closed. * @throws IOException */ public InputStream getFile(IArtifactKey key, String filename) throws IOException { return ProvisioningUtil.getFile(artifactRepository, key, filename); } /** * Checks whether there exists a file in an artifact * * @param key * @param filename * @return true file exists in the artifact * @throws IOException */ public boolean hasFile(IArtifactKey key, String filename) throws IOException { return ProvisioningUtil.hasFile(artifactRepository, key, filename); } /** * Get META-INF/MANIFEST.MF * * @param repo artifact repo * @param key key to artifact * @return manifest or null * @throws IOException */ public Manifest getManifest(IArtifactKey key) throws IOException { return ProvisioningUtil.getManifest(artifactRepository, key); } /** * Get META-INF/SIMANTICS.MF * * @param repo artifact repo * @param key key to artifact * @return manifest or null * @throws IOException */ public Manifest getSimanticsManifest(IArtifactKey key) throws IOException { return ProvisioningUtil.getManifest(artifactRepository, key); } /** * Get list of user installable bundles * * @param result * @throws IOException */ public void getUserInstallables(List result) throws IOException { if (userInstallables==null) { userInstallables = new ArrayList(); List topLevelBundles = new ArrayList(); ProvisioningUtil.getUserInstallables(artifactRepository, topLevelBundles); for (String bundleId : topLevelBundles) { IInstallableUnit ius[] = metadataRepository.query( QueryUtil.createIUQuery(bundleId) , null).toArray( IInstallableUnit.class ); for (IInstallableUnit iu : ius) { userInstallables.add( BundleInfo.read(iu) ); } } } result.addAll(userInstallables); } /////////// /////////// GRAPHS /////////// // /** // * Get graph bundles // * // * @param list to be populated with graph bundle ids // * @throws ProvisionException // * @throws IOException // */ // public void getGraphs(List graphs) throws ProvisionException, IOException { // Collection ius = ProvisioningUtil.getInstallableUnits(metadataRepository); // for (IInstallableUnit iu : ius) { // if (isGraph(iu)) { // BundleInfo b = BundleInfo.read(iu); // graphs.add( b ); // } // } // } /** * Get graph bundles * * @param list to be populated with graph bundle ids * @throws ProvisionException * @throws IOException * @throws TransferableGraphException */ public void getGraphBundles(List graphs) throws ProvisionException, IOException, TransferableGraphException { Collection ius = ProvisioningUtil.getInstallableUnits(metadataRepository); for (IInstallableUnit iu : ius) { for (IArtifactKey key : iu.getArtifacts()) { if (!ProvisioningUtil.isGraphArtifact(artifactRepository, key)) continue; TransferableGraph1 tg = ProvisioningUtil.getTransferableGraph( artifactRepository, key ); GraphBundleEx b = new GraphBundleEx(iu.getId(), tg, key); graphs.add( b ); } } } /** * Get a list of all features. Features are uris, they are versionless. * @return fetures * @throws TransferableGraphException * @throws IOException */ public Set getFeatures() throws IOException, TransferableGraphException { /* HashSet result = new HashSet(); Collection ius = ProvisioningUtil.getInstallableUnits(metadataRepository); for (IInstallableUnit iu : ius) { for (IArtifactKey key : iu.getArtifacts()) { if (!ProvisioningUtil.isGraphArtifact(artifactRepository, key)) continue; TransferableGraph1 tg = ProvisioningUtil.getTransferableGraph( artifactRepository, key ); IGraph g = Graphs.createGraph(tg); Res PublishedProjectFeatures = UriUtils.uriToPath( ProjectResource.URIs.PublishedProjectFeatures ); Path HasFeature = UriUtils.uriToPath( ProjectResource.URIs.HasFeature ); for(Res feature : g.getObjects(PublishedProjectFeatures, HasFeature)) { String uri = feature.toString(); String name = feature instanceof PathChild ? ((PathChild)feature).name : uri; FeatureInfo fi = new FeatureInfo(name, uri, null, null); result.add( fi ); } } } return result; */ return Collections.emptySet(); } /** * For a set of extact feature ids (id_version), find the set of graph bundles * required in the database. * * @param featureIds feature * @return graph bundles */ public Set getRequiredGraphBundles(Collection featureIds) { return null; } /** * Checks whether artifact is a graph bundle. * * @param key key to artifact * @return true if is a graph bundle * @throws IOException */ public boolean isGraphArtifact(IArtifactKey key) throws IOException { return ProvisioningUtil.isGraphArtifact(artifactRepository, key); } /** * Checks wheter iu is graph * * @param iu * @return * @throws IOException */ public boolean isGraph(IInstallableUnit iu) throws IOException { return ProvisioningUtil.isGraph(iu, metadataRepository, artifactRepository); } /** * Delete default repositories located in /P2 folder * @throws IOException */ public void delete() throws IOException { File location1 = new File(metadataAgentLocation); File location2 = new File(artifactAgentLocation); File location3 = new File(metadataRepository.getLocation()); File location4 = new File(artifactRepository.getLocation()); FileUtils.deleteDir(location1); FileUtils.deleteDir(location2); FileUtils.deleteDir(location3); FileUtils.deleteDir(location4); location1.mkdirs(); location2.mkdirs(); location3.mkdirs(); location4.mkdirs(); } }