/***************************************************************************** * Copyright (c) 2006-2013, Cloudsmith Inc. * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the copyright holder * listed above, as the Initial Contributor under such license. The text of * such license is available at www.eclipse.org. *****************************************************************************/ package org.eclipse.buckminster.pde.internal; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.eclipse.buckminster.core.CorePlugin; import org.eclipse.buckminster.core.ITargetPlatform; import org.eclipse.buckminster.core.cspec.model.ComponentIdentifier; import org.eclipse.buckminster.core.ctype.IComponentType; import org.eclipse.buckminster.core.helpers.AbstractExtension; import org.eclipse.buckminster.core.resolver.NodeQuery; import org.eclipse.buckminster.core.resolver.ResolverDecisionType; import org.eclipse.buckminster.pde.Messages; import org.eclipse.buckminster.runtime.Buckminster; import org.eclipse.buckminster.runtime.Logger; import org.eclipse.buckminster.runtime.MonitorUtils; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.equinox.frameworkadmin.BundleInfo; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; import org.eclipse.osgi.util.NLS; import org.eclipse.pde.core.plugin.TargetPlatform; import org.eclipse.pde.core.target.ITargetDefinition; import org.eclipse.pde.core.target.ITargetHandle; import org.eclipse.pde.core.target.ITargetLocation; import org.eclipse.pde.core.target.ITargetPlatformService; import org.eclipse.pde.core.target.LoadTargetDefinitionJob; import org.eclipse.pde.core.target.TargetBundle; import org.eclipse.pde.core.target.TargetFeature; import org.eclipse.pde.internal.core.ExternalFeatureModelManager; import org.eclipse.pde.internal.core.ICoreConstants; import org.eclipse.pde.internal.core.ifeature.IFeatureModel; import org.eclipse.pde.internal.core.target.DirectoryBundleContainer; import org.eclipse.pde.internal.core.target.TargetPlatformService; /** * @author Thomas Hallgren */ @SuppressWarnings("restriction") public class PDETargetPlatform extends AbstractExtension implements ITargetPlatform { private static interface ITargetDefinitionOperation<T> { T run(ITargetDefinition target) throws CoreException; } private static final String defaultTP = "Buckminster Default TP"; //$NON-NLS-1$ private static ITargetDefinition currentDefinition; private static ITargetHandle currentHandle; public static IFeatureModel getBestFeature(final String componentName, final VersionRange versionDesignator, final NodeQuery query) { return doWithActivePlatform(new ITargetDefinitionOperation<IFeatureModel>() { @Override public IFeatureModel run(ITargetDefinition target) throws CoreException { TargetFeature[] allFeatures = target.getAllFeatures(); if (allFeatures == null) return null; TargetFeature candidate = null; Version candidateVersion = null; for (TargetFeature targetFeature : allFeatures) { if (!componentName.equals(targetFeature.getId())) continue; Version v = Version.create(targetFeature.getVersion()); if (v == null) { if (candidate == null && versionDesignator == null) candidate = targetFeature; continue; } if (!(versionDesignator == null || versionDesignator.isIncluded(v))) { if (query != null) query.logDecision(ResolverDecisionType.VERSION_REJECTED, v, NLS.bind(Messages.not_designated_by_0, versionDesignator)); continue; } if (candidateVersion == null || candidateVersion.compareTo(v) < 0) { candidate = targetFeature; candidateVersion = v; } } IFeatureModel model = null; if (candidate != null) { // candidate.getLocation() // can't be <code>null</code> after passing // org.eclipse.pde.core.target.TargetFeature.initialize(File) model = ExternalFeatureModelManager.createModel(new File(candidate.getLocation(), ICoreConstants.FEATURE_FILENAME_DESCRIPTOR)); } return model; } }); } public static BundleInfo getBestPlugin(final String componentName, final VersionRange versionDesignator, final NodeQuery query) { return doWithActivePlatform(new ITargetDefinitionOperation<BundleInfo>() { @Override public BundleInfo run(ITargetDefinition target) throws CoreException { TargetBundle[] allBundles = target.getAllBundles(); if (allBundles == null) return null; BundleInfo candidate = null; Version candidateVersion = null; for (TargetBundle targetBundle : allBundles) { BundleInfo bi = targetBundle.getBundleInfo(); if (!componentName.equals(bi.getSymbolicName())) continue; Version v = Version.create(bi.getVersion()); if (v == null) { if (candidate == null && versionDesignator == null) candidate = bi; continue; } if (!(versionDesignator == null || versionDesignator.isIncluded(v))) { if (query != null) query.logDecision(ResolverDecisionType.VERSION_REJECTED, v, NLS.bind(Messages.not_designated_by_0, versionDesignator)); continue; } if (candidateVersion == null || candidateVersion.compareTo(v) < 0) { candidate = bi; candidateVersion = v; } } return candidate; } }); } public static void setTargetActive(ITargetDefinition target, IProgressMonitor monitor) throws CoreException { MonitorUtils.begin(monitor, 100); target.resolve(MonitorUtils.subMonitor(monitor, 50)); LoadTargetDefinitionJob job = new LoadTargetDefinitionJob(target); IStatus status = job.run(MonitorUtils.subMonitor(monitor, 50)); if (status.getSeverity() == IStatus.ERROR) throw new CoreException(status); currentDefinition = target; currentHandle = target.getHandle(); MonitorUtils.done(monitor); } private static <T> T doWithActivePlatform(ITargetDefinitionOperation<T> operation) { Buckminster bucky = Buckminster.getDefault(); ITargetPlatformService service = null; try { service = bucky.getService(ITargetPlatformService.class); synchronized (service) { ITargetHandle activeHandle = service.getWorkspaceTargetHandle(); if (activeHandle == null) return null; // We need to cache the definition. If we don't, it will need to // resolve each time since it's created from scratch. if (currentDefinition == null || currentHandle == null || !activeHandle.equals(currentHandle)) { currentDefinition = activeHandle.getTargetDefinition(); currentHandle = activeHandle; } if (!currentDefinition.isResolved()) { IStatus status = currentDefinition.resolve(new NullProgressMonitor()); if (status.getSeverity() == IStatus.ERROR) throw new CoreException(status); } } return operation.run(currentDefinition); } catch (CoreException e) { Buckminster.getLogger().warning(e, e.getLocalizedMessage()); return null; } finally { bucky.ungetService(service); } } private static File getLocation(ITargetDefinition target) throws CoreException { ITargetLocation[] containers = target.getTargetLocations(); if (containers == null) return null; for (ITargetLocation container : containers) { // bug 285449: the directory bundle container is actually the only // we one we can use if (container instanceof DirectoryBundleContainer) { return new File(((DirectoryBundleContainer) container).getLocation(true)); } } return null; } @Override public String getArch() { String arch = doWithActivePlatform(new ITargetDefinitionOperation<String>() { @Override public String run(ITargetDefinition target) { return target.getArch(); } }); return arch == null ? TargetPlatform.getOSArch() : arch; } @Override public List<ComponentIdentifier> getComponents() throws CoreException { return doWithActivePlatform(new ITargetDefinitionOperation<List<ComponentIdentifier>>() { @Override public List<ComponentIdentifier> run(ITargetDefinition target) { if (!target.isResolved()) target.resolve(new NullProgressMonitor()); List<ComponentIdentifier> result = new ArrayList<ComponentIdentifier>(); for (TargetFeature feature : target.getAllFeatures()) { result.add(new ComponentIdentifier(feature.getId(), IComponentType.ECLIPSE_FEATURE, Version.parseVersion(feature.getVersion()))); } for (TargetBundle bundle : target.getBundles()) { BundleInfo b = bundle.getBundleInfo(); result.add(new ComponentIdentifier(b.getSymbolicName(), IComponentType.OSGI_BUNDLE, Version.parseVersion(b.getVersion()))); } return result; } }); } public ITargetDefinition getDefaultPlatform(boolean asActive) throws CoreException { Buckminster bucky = Buckminster.getDefault(); ITargetPlatformService service = bucky.getService(ITargetPlatformService.class); ITargetDefinition dflt = null; for (ITargetHandle handle : service.getTargets(null)) { ITargetDefinition target = handle.getTargetDefinition(); if (defaultTP.equals(target.getName())) { if (!asActive) return target; ITargetHandle activeHandle = service.getWorkspaceTargetHandle(); if (activeHandle != null && activeHandle.equals(handle)) return target; dflt = target; break; } } if (dflt == null) { // Create a default target platform under the buckminster folder // IProject buckyProj = CorePlugin.getDefault().getBuckminsterProject(true, null); IFolder tpFolder = buckyProj.getFolder("tp"); //$NON-NLS-1$ if (!tpFolder.exists()) tpFolder.create(true, false, null); dflt = ((TargetPlatformService) service).newDefaultTarget(); ITargetLocation runningInstance = dflt.getTargetLocations()[0]; ITargetLocation directory = service.newDirectoryLocation(tpFolder.getLocation().toOSString()); dflt.setTargetLocations(new ITargetLocation[] { directory, runningInstance }); dflt.setName(defaultTP); service.saveTargetDefinition(dflt); } if (asActive) { LoadTargetDefinitionJob job = new LoadTargetDefinitionJob(dflt); IStatus status = job.run(new NullProgressMonitor()); if (status.getSeverity() == IStatus.ERROR) throw new CoreException(status); } return dflt; } @Override public File getDefaultPlatformLocation(boolean asActive) throws CoreException { return getLocation(getDefaultPlatform(asActive)); } @Override public File getLocation() { File location = doWithActivePlatform(new ITargetDefinitionOperation<File>() { @Override public File run(ITargetDefinition target) throws CoreException { return getLocation(target); } }); // bug 285449: don't fall back on deprecated // TargetPlatform.getLocation() setting return location; } @Override public String getNL() { String nl = doWithActivePlatform(new ITargetDefinitionOperation<String>() { @Override public String run(ITargetDefinition target) { return target.getNL(); } }); return nl == null ? TargetPlatform.getNL() : nl; } @Override public String getOS() { String os = doWithActivePlatform(new ITargetDefinitionOperation<String>() { @Override public String run(ITargetDefinition target) { return target.getOS(); } }); return os == null ? TargetPlatform.getOS() : os; } @Override public String getWS() { String ws = doWithActivePlatform(new ITargetDefinitionOperation<String>() { @Override public String run(ITargetDefinition target) { return target.getWS(); } }); return ws == null ? TargetPlatform.getWS() : ws; } @Override public void locationsChanged(Set<File> locations) { // Check if the given location is contained in the active TP. If that's // the case, refresh. // Logger log = Buckminster.getLogger(); Buckminster bucky = Buckminster.getDefault(); ITargetPlatformService service = null; try { log.debug("Processing changes in target platform locations..."); //$NON-NLS-1$ service = bucky.getService(ITargetPlatformService.class); ITargetHandle activeHandle = service.getWorkspaceTargetHandle(); if (activeHandle == null) { log.debug("Found no active target handle"); //$NON-NLS-1$ return; } ITargetDefinition target = activeHandle.getTargetDefinition(); ITargetLocation[] containers = target.getTargetLocations(); if (containers == null || containers.length == 0) { log.debug("Active target handle has no containers"); //$NON-NLS-1$ return; } boolean found = false; for (ITargetLocation container : containers) { if (container instanceof DirectoryBundleContainer && locations.contains(new File(((DirectoryBundleContainer) container).getLocation(true)))) { found = true; break; } } if (!found) { log.debug("Active target handle has no containers of type DirectoryBundleContainer that matches the given locations"); //$NON-NLS-1$ return; } refresh(target); } catch (CoreException e) { log.warning(e, e.getLocalizedMessage()); } finally { bucky.ungetService(service); log.debug("Done processing changes in target platform locations"); //$NON-NLS-1$ } } @Override public void refresh() { doWithActivePlatform(new ITargetDefinitionOperation<Object>() { @Override public Object run(ITargetDefinition target) throws CoreException { refresh(target); return null; } }); } private void refresh(ITargetDefinition target) throws CoreException { Logger log = Buckminster.getLogger(); log.info(NLS.bind(Messages.resetting_target_platform_0, target.getName())); setTargetActive(target, new NullProgressMonitor()); } }