Bug 364068 - Variable fails to be resolved in features folder for
Target Platform definition
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/target/TargetFeature.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/target/TargetFeature.java
index c18711b..7537837 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/target/TargetFeature.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/target/TargetFeature.java
@@ -11,11 +11,12 @@
 package org.eclipse.pde.core.target;

 

 import java.io.File;

+import java.util.ArrayList;

+import java.util.List;

 import org.eclipse.core.runtime.*;

 import org.eclipse.osgi.util.NLS;

 import org.eclipse.pde.internal.core.*;

-import org.eclipse.pde.internal.core.ifeature.IFeatureModel;

-import org.eclipse.pde.internal.core.ifeature.IFeaturePlugin;

+import org.eclipse.pde.internal.core.ifeature.*;

 import org.eclipse.pde.internal.core.target.Messages;

 

 /**

@@ -89,6 +90,28 @@
 	}

 

 	/**

+	 * Returns a list of name version descriptors that describe the set of features

+	 * that this feature depends on as imports or included features.

+	 * 

+	 * @return a list of name version descriptors, possibly empty

+	 */

+	public NameVersionDescriptor[] getDependentFeatures() {

+		List result = new ArrayList();

+		IFeature feature = featureModel.getFeature();

+		IFeatureImport[] featureImports = feature.getImports();

+		for (int i = 0; i < featureImports.length; i++) {

+			if (featureImports[i].getType() == IFeatureImport.FEATURE) {

+				result.add(new NameVersionDescriptor(featureImports[i].getId(), null, NameVersionDescriptor.TYPE_FEATURE));

+			}

+		}

+		IFeatureChild[] featureIncludes = feature.getIncludedFeatures();

+		for (int i = 0; i < featureIncludes.length; i++) {

+			result.add(new NameVersionDescriptor(featureIncludes[i].getId(), null, NameVersionDescriptor.TYPE_FEATURE));

+		}

+		return (NameVersionDescriptor[]) result.toArray(new NameVersionDescriptor[result.size()]);

+	}

+

+	/**

 	 * Initializes the content of this target feature by reading the feature.xml

 	 * 

 	 * @param file feature.xml or directory containing it

diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PluginPathFinder.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PluginPathFinder.java
index 662aa5b..85bcd7b 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PluginPathFinder.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PluginPathFinder.java
@@ -82,6 +82,15 @@
 				}
 			}
 		}
+
+		// If there is no features/plugins folder and no linked files, try the home location
+		if (sites.isEmpty()) {
+			file = new File(platformHome);
+			if (file.exists()) {
+				sites.add(file);
+			}
+		}
+
 		return (File[]) sites.toArray(new File[sites.size()]);
 	}
 
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/FeatureBundleContainer.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/FeatureBundleContainer.java
index 07e1bdd..9758508 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/FeatureBundleContainer.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/FeatureBundleContainer.java
@@ -139,15 +139,15 @@
 			if (service == null) {
 				throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.FeatureBundleContainer_4));
 			}
-			File dir = new File(manifest.getParentFile().getParentFile().getParentFile(), "plugins"); //$NON-NLS-1$
-			if (!dir.exists() || !dir.isDirectory()) {
-				throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.FeatureBundleContainer_5, fId)));
-			}
+//			File dir = new File(manifest.getParentFile().getParentFile().getParentFile(), "plugins"); //$NON-NLS-1$
+//			if (!dir.exists() || !dir.isDirectory()) {
+//				throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.FeatureBundleContainer_5, fId)));
+//			}
 			if (monitor.isCanceled()) {
 				return new TargetBundle[0];
 			}
 
-			ITargetLocation container = service.newDirectoryLocation(dir.getAbsolutePath());
+			ITargetLocation container = service.newDirectoryLocation(getLocation(false));
 			container.resolve(definition, monitor);
 			TargetBundle[] bundles = container.getBundles();
 			IFeature feature = model.getFeature();
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java
index b171dc3..d46558c 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java
@@ -25,8 +25,6 @@
 import org.eclipse.pde.core.target.*;
 import org.eclipse.pde.internal.core.ExternalFeatureModelManager;
 import org.eclipse.pde.internal.core.PDECore;
-import org.eclipse.pde.internal.core.ifeature.IFeatureModel;
-import org.eclipse.pde.internal.core.ifeature.IFeaturePlugin;
 import org.xml.sax.SAXException;
 
 /**
@@ -72,7 +70,6 @@
 
 	// internal cache for features.  A target managed by features will contain a set of features as well as a set of plug-ins that don't belong to a feature
 	private TargetFeature[] fFeatures;
-	private IFeatureModel[] fFeatureModels;
 	private TargetBundle[] fOtherBundles;
 
 	private int fSequenceNumber = -1;
@@ -205,7 +202,7 @@
 	public void setTargetLocations(ITargetLocation[] locations) {
 		incrementSequenceNumber();
 		// Clear the feature model cache as it is based on the bundle container locations
-		fFeatureModels = null;
+		fFeatures = null;
 		fOtherBundles = null;
 
 		if (locations != null && locations.length == 0) {
@@ -232,7 +229,7 @@
 	 */
 	public void flushCaches(String location) {
 		// Clear the feature model cache as it is based on the bundle container locations
-		fFeatureModels = null;
+		fFeatures = null;
 		fOtherBundles = null;
 		if (location == null) {
 			fFeaturesInLocation.clear();
@@ -898,22 +895,9 @@
 		}
 
 		fFeatures = (TargetFeature[]) result.values().toArray(new TargetFeature[result.size()]);
-		fFeatureModels = new IFeatureModel[fFeatures.length];
-		for (int i = 0; i < fFeatures.length; i++) {
-
-		}
 		return fFeatures;
 	}
 
-	public IFeatureModel[] getAllFeatureModels() {
-		if (fFeatureModels != null) {
-			return fFeatureModels;
-		}
-
-		getAllFeatures();
-		return fFeatureModels;
-	}
-
 	/**
 	 * Returns the set of IResolvedBundle available in this target that are not part of any features, will return a cached copy if available
 	 * 
@@ -935,9 +919,9 @@
 			remaining.put(allBundles[i].getBundleInfo().getSymbolicName(), allBundles[i]);
 		}
 
-		IFeatureModel[] features = getAllFeatureModels();
+		TargetFeature[] features = getAllFeatures();
 		for (int i = 0; i < features.length; i++) {
-			IFeaturePlugin[] plugins = features[i].getFeature().getPlugins();
+			NameVersionDescriptor[] plugins = features[i].getPlugins();
 			for (int j = 0; j < plugins.length; j++) {
 				remaining.remove(plugins[j].getId());
 			}
@@ -963,7 +947,7 @@
 			return null;
 		}
 
-		IFeatureModel[] allFeatures = getAllFeatureModels();
+		TargetFeature[] allFeatures = getAllFeatures();
 		TargetBundle[] allExtraBundles = getOtherBundles();
 
 		NameVersionDescriptor[] included = getIncluded();
@@ -985,7 +969,7 @@
 				}
 			} else if (included[i].getType() == NameVersionDescriptor.TYPE_FEATURE) {
 				for (int j = 0; j < allFeatures.length; j++) {
-					if (allFeatures[j].getFeature().getId().equals(included[i].getId())) {
+					if (allFeatures[j].getId().equals(included[i].getId())) {
 						result.add(allFeatures[j]);
 					}
 				}
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/StyledBundleLabelProvider.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/StyledBundleLabelProvider.java
index 97153e0..36d2732 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/StyledBundleLabelProvider.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/StyledBundleLabelProvider.java
@@ -19,7 +19,6 @@
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.viewers.*;
 import org.eclipse.pde.core.target.*;
-import org.eclipse.pde.internal.core.ifeature.IFeatureModel;
 import org.eclipse.pde.internal.core.target.*;
 import org.eclipse.pde.internal.ui.PDEPlugin;
 import org.eclipse.pde.internal.ui.PDEPluginImages;
@@ -92,9 +91,9 @@
 			styledString.append(((IStatus) element).getMessage());
 		} else if (element instanceof IPath) {
 			styledString.append(((IPath) element).removeFirstSegments(1).toString());
-		} else if (element instanceof IFeatureModel) {
+		} else if (element instanceof TargetFeature) {
 			// Use a bundle info to reuse existing code
-			appendBundleInfo(styledString, new BundleInfo(((IFeatureModel) element).getFeature().getId(), ((IFeatureModel) element).getFeature().getVersion(), null, BundleInfo.NO_LEVEL, false));
+			appendBundleInfo(styledString, new BundleInfo(((TargetFeature) element).getId(), ((TargetFeature) element).getVersion(), null, BundleInfo.NO_LEVEL, false));
 		} else if (element instanceof FeatureBundleContainer) {
 			FeatureBundleContainer container = (FeatureBundleContainer) element;
 			styledString.append(container.getFeatureId());
@@ -256,7 +255,7 @@
 			}
 		} else if (element instanceof IPath) {
 			return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);
-		} else if (element instanceof IFeatureModel) {
+		} else if (element instanceof TargetFeature) {
 			return PDEPlugin.getDefault().getLabelProvider().get(PDEPluginImages.DESC_FEATURE_OBJ);
 		} else if (element instanceof ITargetLocation) {
 			int flag = 0;
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/TargetContentsGroup.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/TargetContentsGroup.java
index 46b2944..7d5fbd5 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/TargetContentsGroup.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/TargetContentsGroup.java
@@ -31,7 +31,6 @@
 import org.eclipse.pde.core.target.*;
 import org.eclipse.pde.internal.core.DependencyManager;
 import org.eclipse.pde.internal.core.PDEState;
-import org.eclipse.pde.internal.core.ifeature.*;
 import org.eclipse.pde.internal.core.target.TargetDefinition;
 import org.eclipse.pde.internal.ui.PDEPlugin;
 import org.eclipse.pde.internal.ui.SWTFactory;
@@ -495,7 +494,7 @@
 				Object[] allChecked = fTree.getCheckedLeafElements();
 				Collection required = null;
 				if (fFeaureModeButton.getSelection()) {
-					required = getRequiredFeatures(fTargetDefinition.getAllFeatureModels(), allChecked);
+					required = getRequiredFeatures(fTargetDefinition.getAllFeatures(), allChecked);
 				} else {
 					required = getRequiredPlugins(fAllBundles, allChecked);
 				}
@@ -811,47 +810,31 @@
 	 * @param checkedFeatures list of features to get requirements for
 	 * @return set of features to be checked
 	 */
-	private Set getRequiredFeatures(final IFeatureModel[] allFeatures, final Object[] checkedFeatures) {
+	private Set getRequiredFeatures(final TargetFeature[] allFeatures, final Object[] checkedFeatures) {
 		Set required = new HashSet();
 		for (int j = 0; j < checkedFeatures.length; j++) {
-			if (checkedFeatures[j] instanceof IFeatureModel) {
-				getFeatureDependencies((IFeatureModel) checkedFeatures[j], allFeatures, required);
+			if (checkedFeatures[j] instanceof TargetFeature) {
+				getFeatureDependencies((TargetFeature) checkedFeatures[j], allFeatures, required);
 			}
 		}
 		return required;
 	}
 
 	/**
-	 * Recursively gets the ID of required features of this feature and adds them to the list
-	 * @param model feature model to get requirements of
-	 * @param requiredFeatures collector for the required features
+	 * Recursively gets the ID of required features of this feature and adds them to the required features list
+	 * @param model target feature to get requirements of
+	 * @param requiredFeatures collector for the required target features {@link TargetFeature}
 	 */
-	private void getFeatureDependencies(IFeatureModel model, IFeatureModel[] allFeatures, Set/*<IFeatureModel>*/requiredFeatures) {
-		IFeature feature = model.getFeature();
-		IFeatureImport[] featureImports = feature.getImports();
-		for (int i = 0; i < featureImports.length; i++) {
-			if (featureImports[i].getType() == IFeatureImport.FEATURE) {
-				for (int j = 0; j < allFeatures.length; j++) {
-					if (allFeatures[j].getFeature().getId().equals(featureImports[i].getId())) {
-						if (!requiredFeatures.contains(allFeatures[j])) {
-							requiredFeatures.add(allFeatures[j]);
-							getFeatureDependencies(allFeatures[j], allFeatures, requiredFeatures);
-							break;
-						}
-					}
-				}
-
-			}
-		}
-		IFeatureChild[] featureIncludes = feature.getIncludedFeatures();
-		for (int i = 0; i < featureIncludes.length; i++) {
+	private void getFeatureDependencies(TargetFeature feature, TargetFeature[] allFeatures, Set/*<TargetFeature>*/requiredFeatures) {
+		NameVersionDescriptor[] dependents = feature.getDependentFeatures();
+		for (int i = 0; i < dependents.length; i++) {
 			for (int j = 0; j < allFeatures.length; j++) {
-				if (allFeatures[j].getFeature().getId().equals(featureIncludes[i].getId())) {
+				if (allFeatures[j].getId().equals(dependents[i].getId())) {
 					if (!requiredFeatures.contains(allFeatures[j])) {
 						requiredFeatures.add(allFeatures[j]);
 						getFeatureDependencies(allFeatures[j], allFeatures, requiredFeatures);
-						break;
 					}
+					break;
 				}
 			}
 		}
@@ -1092,8 +1075,8 @@
 			int missingCount = 0;
 			Object[] checked = fTree.getCheckedLeafElements();
 			for (int i = 0; i < checked.length; i++) {
-				if (checked[i] instanceof IFeatureModel) {
-					included.add(new NameVersionDescriptor(((IFeatureModel) checked[i]).getFeature().getId(), null, NameVersionDescriptor.TYPE_FEATURE));
+				if (checked[i] instanceof TargetFeature) {
+					included.add(new NameVersionDescriptor(((TargetFeature) checked[i]).getId(), null, NameVersionDescriptor.TYPE_FEATURE));
 				}
 				if (checked[i] instanceof TargetBundle) {
 					// Missing features are included as TargetBundles, save them as features instead
@@ -1201,11 +1184,11 @@
 				}
 
 				if (fFeaureModeButton.getSelection()) {
-					IFeatureModel[] features = fTargetDefinition.getAllFeatureModels();
+					TargetFeature[] features = fTargetDefinition.getAllFeatures();
 					result.addAll(Arrays.asList(features));
 
 					// Check if we need the other category
-					if (((TargetDefinition) fTargetDefinition).getOtherBundles().length > 0) {
+					if (fTargetDefinition.getOtherBundles().length > 0) {
 						result.add(OTHER_CATEGORY);
 					}
 				} else if (fGrouping == GROUP_BY_CONTAINER) {