1 /******************************************************************************* 2 * Copyright (c) 2009, 2017 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Manumitting Technologies Inc - bug 437726: wrong error messages opening target definition 14 *******************************************************************************/ 15 package org.eclipse.pde.internal.core.target; 16 17 import java.io.File; 18 import java.io.IOException; 19 import java.util.HashMap; 20 import java.util.Map.Entry; 21 import org.eclipse.core.runtime.CoreException; 22 import org.eclipse.core.runtime.IProgressMonitor; 23 import org.eclipse.core.runtime.IStatus; 24 import org.eclipse.core.runtime.Platform; 25 import org.eclipse.core.runtime.PlatformObject; 26 import org.eclipse.core.runtime.Status; 27 import org.eclipse.core.runtime.SubMonitor; 28 import org.eclipse.core.variables.IStringVariableManager; 29 import org.eclipse.core.variables.VariablesPlugin; 30 import org.eclipse.equinox.internal.provisional.frameworkadmin.ConfigData; 31 import org.eclipse.equinox.internal.provisional.frameworkadmin.FrameworkAdmin; 32 import org.eclipse.equinox.internal.provisional.frameworkadmin.Manipulator; 33 import org.eclipse.pde.core.target.ITargetDefinition; 34 import org.eclipse.pde.core.target.ITargetLocation; 35 import org.eclipse.pde.core.target.TargetBundle; 36 import org.eclipse.pde.core.target.TargetFeature; 37 import org.eclipse.pde.internal.core.PDECore; 38 import org.osgi.framework.Bundle; 39 import org.osgi.framework.BundleException; 40 41 /** 42 * Common function for bundle containers. 43 * 44 * @since 3.5 45 */ 46 public abstract class AbstractBundleContainer extends PlatformObject implements ITargetLocation { 47 48 /** 49 * Resolved bundles or <code>null</code> if unresolved 50 */ 51 protected TargetBundle[] fBundles; 52 53 /** 54 * List of target features contained in this bundle container or <code>null</code> if unresolved 55 */ 56 protected TargetFeature[] fFeatures; 57 58 /** 59 * Status generated when this container was resolved, possibly <code>null</code> 60 */ 61 protected IStatus fResolutionStatus; 62 63 /** 64 * The Java VM Arguments specified by this bundle container 65 */ 66 private String[] fVMArgs; 67 68 static private HashMap<AbstractBundleContainer, String[]> hash = new HashMap<>(); 69 70 /** 71 * Resolves any string substitution variables in the given text returning 72 * the result. 73 * 74 * @param text text to resolve 75 * @return result of the resolution 76 * @throws CoreException if unable to resolve 77 */ resolveVariables(String text)78 protected String resolveVariables(String text) throws CoreException { 79 IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager(); 80 return manager.performStringSubstitution(text); 81 } 82 83 @Override isResolved()84 public final boolean isResolved() { 85 return fResolutionStatus != null && fResolutionStatus.getSeverity() != IStatus.CANCEL; 86 } 87 88 @Override resolve(ITargetDefinition definition, IProgressMonitor monitor)89 public final IStatus resolve(ITargetDefinition definition, IProgressMonitor monitor) { 90 int resolveBundlesWork = getResolveBundlesWork(); 91 int resolveFeaturesWork = getResolveFeaturesWork(); 92 93 SubMonitor subMonitor = SubMonitor.convert(monitor, resolveBundlesWork + resolveFeaturesWork); 94 try { 95 fResolutionStatus = Status.OK_STATUS; 96 fBundles = resolveBundles(definition, subMonitor.split(resolveBundlesWork)); 97 fFeatures = resolveFeatures(definition, subMonitor.split(resolveFeaturesWork)); 98 if (subMonitor.isCanceled()) { 99 fBundles = null; 100 fResolutionStatus = Status.CANCEL_STATUS; 101 } 102 } catch (CoreException e) { 103 fBundles = new TargetBundle[0]; 104 fFeatures = new TargetFeature[0]; 105 fResolutionStatus = e.getStatus(); 106 } finally { 107 subMonitor.done(); 108 if (monitor != null) { 109 monitor.done(); 110 } 111 } 112 return fResolutionStatus; 113 } 114 115 /** 116 * Can be overridden in subclasses to redistribute the work between {@link #resolveBundles(ITargetDefinition, IProgressMonitor)} 117 * and {@link #resolveFeatures(ITargetDefinition, IProgressMonitor)}. 118 * 119 * @return the value 100, making {@link #resolveFeatures(ITargetDefinition, IProgressMonitor)} consume two thirds of 120 * the overall work being done in {@link #resolve(ITargetDefinition, IProgressMonitor)}. 121 * @see #getResolveFeaturesWork() 122 */ getResolveBundlesWork()123 protected int getResolveBundlesWork() { 124 return 100; 125 } 126 127 /** 128 * Can be overridden in subclasses to redistribute the work between {@link #resolveBundles(ITargetDefinition, IProgressMonitor)} 129 * and {@link #resolveFeatures(ITargetDefinition, IProgressMonitor)}. 130 * 131 * @return the value 50, making {@link #resolveFeatures(ITargetDefinition, IProgressMonitor)} consume one third of 132 * the overall work being done in {@link #resolve(ITargetDefinition, IProgressMonitor)}. 133 * @see #getResolveBundlesWork() 134 */ getResolveFeaturesWork()135 protected int getResolveFeaturesWork() { 136 return 50; 137 } 138 139 @Override getStatus()140 public IStatus getStatus() { 141 if (!isResolved()) { 142 return null; 143 } 144 return fResolutionStatus; 145 } 146 147 @Override getBundles()148 public final TargetBundle[] getBundles() { 149 if (isResolved()) { 150 return fBundles; 151 } 152 return null; 153 } 154 155 @Override getFeatures()156 public TargetFeature[] getFeatures() { 157 if (isResolved()) { 158 return fFeatures; 159 } 160 return null; 161 } 162 163 /** 164 * Resolves all source and executable bundles in this container 165 * <p> 166 * Subclasses must implement this method. 167 * </p><p> 168 * <code>beginTask()</code> and <code>done()</code> will be called on the given monitor by the caller. 169 * </p> 170 * @param definition target context 171 * @param monitor progress monitor 172 * @return all source and executable bundles in this container 173 * @throws CoreException if an error occurs 174 */ resolveBundles(ITargetDefinition definition, IProgressMonitor monitor)175 protected abstract TargetBundle[] resolveBundles(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException; 176 177 /** 178 * Collects all of the features in this container. May return an empty array if {@link #resolveBundles(ITargetDefinition, IProgressMonitor)} 179 * has not been called previously. 180 * <p> 181 * Subclasses must implement this method. 182 * </p><p> 183 * <code>beginTask()</code> and <code>done()</code> will be called on the given monitor by the caller. 184 * </p> 185 * @param definition target context 186 * @param monitor progress monitor 187 * @return all features in this container 188 * @throws CoreException if an error occurs 189 */ resolveFeatures(ITargetDefinition definition, IProgressMonitor monitor)190 protected abstract TargetFeature[] resolveFeatures(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException; 191 192 /** 193 * Returns a string that identifies the type of bundle container. This type is persisted to xml 194 * so that the correct bundle container is created when deserializing the xml. This type is also 195 * used to alter how the containers are presented to the user in the UI. 196 * 197 * @return string identifier for the type of bundle container. 198 */ 199 @Override getType()200 public abstract String getType(); 201 202 /** 203 * Returns a path in the local file system to the root of the bundle container. 204 * <p> 205 * TODO: Ideally we won't need this method. Currently the PDE target platform preferences are 206 * based on a home location and additional locations, so we need the information. 207 * </p> 208 * @param resolve whether to resolve variables in the path 209 * @return home location 210 * @exception CoreException if unable to resolve the location 211 */ 212 @Override getLocation(boolean resolve)213 public abstract String getLocation(boolean resolve) throws CoreException; 214 215 /** 216 * Sets the resolution status to null. This container will be considered unresolved. 217 */ clearResolutionStatus()218 protected void clearResolutionStatus() { 219 fResolutionStatus = null; 220 } 221 222 @Override getVMArguments()223 public String[] getVMArguments() { 224 for (Entry<AbstractBundleContainer, String[]> entry : hash.entrySet()) { 225 if (entry.getKey().equals(this)) { 226 return entry.getValue(); 227 } 228 } 229 String FWK_ADMIN_EQ = "org.eclipse.equinox.frameworkadmin.equinox"; //$NON-NLS-1$ 230 if (fVMArgs == null) { 231 try { 232 FrameworkAdmin fwAdmin = PDECore.getDefault().acquireService(FrameworkAdmin.class); 233 if (fwAdmin == null) { 234 Bundle fwAdminBundle = Platform.getBundle(FWK_ADMIN_EQ); 235 if (fwAdminBundle != null) { 236 fwAdminBundle.start(); 237 fwAdmin = PDECore.getDefault().acquireService(FrameworkAdmin.class); 238 } 239 } 240 if (fwAdmin != null) { 241 Manipulator manipulator = fwAdmin.getManipulator(); 242 ConfigData configData = new ConfigData(null, null, null, null); 243 244 String home = getLocation(true); 245 manipulator.getLauncherData().setLauncher(new File(home, "eclipse")); //$NON-NLS-1$ 246 File installDirectory = new File(home); 247 // if (Platform.getOS().equals(Platform.OS_MACOSX)) 248 // installDirectory = new File(installDirectory, "Eclipse.app/Contents/MacOS"); //$NON-NLS-1$ 249 manipulator.getLauncherData().setLauncherConfigLocation(new File(installDirectory, "eclipse.ini")); //$NON-NLS-1$ 250 manipulator.getLauncherData().setHome(new File(home)); 251 252 manipulator.setConfigData(configData); 253 manipulator.load(); 254 fVMArgs = manipulator.getLauncherData().getJvmArgs(); 255 } 256 } catch (BundleException | CoreException | IOException e) { 257 PDECore.log(e); 258 } 259 260 } 261 if (fVMArgs == null || fVMArgs.length == 0) { 262 hash.put(this, null); 263 return null; 264 } 265 hash.put(this, fVMArgs); 266 return fVMArgs; 267 } 268 269 /** 270 * Associate this bundle container with the given target. This allows for the container and 271 * the target to share configuration information etc. 272 * 273 * @param target the target to which this container is being added. 274 */ associateWithTarget(ITargetDefinition target)275 protected void associateWithTarget(ITargetDefinition target) { 276 // Do nothing by default 277 } 278 279 @Override serialize()280 public String serialize() { 281 // The default implementation returns null as most containers do not use the new UI 282 return null; 283 } 284 285 } 286