| /******************************************************************************* |
| * Copyright (c) 2000, 2018 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.pde.internal.core; |
| |
| import java.io.*; |
| import java.net.URL; |
| import java.util.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.pde.core.IModelProviderEvent; |
| import org.eclipse.pde.core.IModelProviderListener; |
| import org.eclipse.pde.core.target.ITargetDefinition; |
| import org.eclipse.pde.core.target.TargetFeature; |
| import org.eclipse.pde.internal.core.feature.ExternalFeatureModel; |
| import org.eclipse.pde.internal.core.ifeature.IFeatureModel; |
| import org.eclipse.pde.internal.core.target.Messages; |
| |
| /** |
| * Manages the features known to the PDE state that come from the target platform. |
| * <p> |
| * Contains utility methods to create feature models for locations. |
| * </p> |
| */ |
| public class ExternalFeatureModelManager { |
| |
| /** |
| * Creates a feature model for the feature based on the given feature XML |
| * file. |
| * |
| * @param manifest feature XML file in the local file system |
| * @return {@link ExternalFeatureModel} containing information loaded from the xml |
| * @throws CoreException if there is a problem reading the feature xml |
| */ |
| public static IFeatureModel createModel(File manifest) throws CoreException { |
| ExternalFeatureModel model = new ExternalFeatureModel(); |
| model.setInstallLocation(manifest.getParent()); |
| InputStream stream = null; |
| try { |
| stream = new BufferedInputStream(new FileInputStream(manifest)); |
| model.load(stream, false); |
| return model; |
| } catch (FileNotFoundException e) { |
| throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.TargetFeature_FileDoesNotExist, manifest))); |
| } finally { |
| if (stream != null) { |
| try { |
| stream.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| } |
| |
| private ListenerList<IModelProviderListener> fListeners = new ListenerList<>(); |
| |
| private IFeatureModel[] fModels; |
| |
| public void addModelProviderListener(IModelProviderListener listener) { |
| fListeners.add(listener); |
| } |
| |
| private void fireModelProviderEvent(IModelProviderEvent e) { |
| for (IModelProviderListener listener : fListeners) { |
| listener.modelsChanged(e); |
| } |
| } |
| |
| /** |
| * Loads new feature models from preferences and notifies listeners. |
| */ |
| public void initialize() { |
| // Do the model loading in a synch block in case other changes cause the models to load |
| IFeatureModel[] oldModels = null; |
| synchronized (this) { |
| oldModels = fModels != null ? fModels : new IFeatureModel[0]; |
| long startTime = System.currentTimeMillis(); |
| fModels = getExternalModels(); |
| if (PDECore.DEBUG_MODEL) { |
| System.out.println("Time to load features from target platform (ms): " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$ |
| System.out.println("External features loaded: " + fModels.length); //$NON-NLS-1$ |
| } |
| } |
| // Release lock when notifying listeners. See bug 270891. |
| notifyListeners(oldModels, fModels); |
| } |
| |
| /** |
| * Returns a list of feature models from the target platform or an empty |
| * array if there is a problem. |
| * |
| * @return list of external feature models, possibly empty |
| */ |
| private IFeatureModel[] getExternalModels() { |
| // Plug-in resolution was cancelled by the user so skip resolving the target |
| if (PDECore.getDefault().getModelManager().isCancelled()) { |
| return new IFeatureModel[0]; |
| } |
| |
| ITargetDefinition target = null; |
| try { |
| target = TargetPlatformHelper.getWorkspaceTargetResolved(null); |
| } catch (CoreException e) { |
| PDECore.log(e); |
| return new IFeatureModel[0]; |
| } |
| |
| // Resolution cancelled |
| if (target == null) { |
| return new IFeatureModel[0]; |
| } |
| |
| List<IFeatureModel> result = new ArrayList<>(); |
| TargetFeature[] features = target.getAllFeatures(); |
| if (features != null) { |
| for (TargetFeature feature : features) { |
| String location = feature.getLocation(); |
| File manifest = new File(location, ICoreConstants.FEATURE_FILENAME_DESCRIPTOR); |
| if (!manifest.exists() || !manifest.isFile()) { |
| continue; |
| } |
| try { |
| IFeatureModel model = createModel(manifest); |
| if (model != null && model.isLoaded()) { |
| result.add(model); |
| } |
| } catch (CoreException e) { |
| PDECore.log(e); |
| } |
| } |
| } |
| return result.toArray(new IFeatureModel[result.size()]); |
| } |
| |
| private void notifyListeners(IFeatureModel[] oldModels, IFeatureModel[] newFeatureModels) { |
| if (oldModels.length > 0 || newFeatureModels.length > 0) { |
| int type = 0; |
| if (oldModels.length > 0) |
| type |= IModelProviderEvent.MODELS_REMOVED; |
| if (newFeatureModels.length > 0) |
| type |= IModelProviderEvent.MODELS_ADDED; |
| ModelProviderEvent replacedFeatures = new ModelProviderEvent(this, type, newFeatureModels, oldModels, null); |
| fireModelProviderEvent(replacedFeatures); |
| } |
| |
| } |
| |
| public void removeModelProviderListener(IModelProviderListener listener) { |
| fListeners.remove(listener); |
| } |
| |
| public IFeatureModel[] getModels() { |
| return fModels; |
| } |
| |
| public static TargetFeature[] createFeatures(String platformHome, ArrayList<?> additionalLocations, IProgressMonitor monitor) { |
| if (platformHome != null && platformHome.length() > 0) { |
| URL[] featureURLs = PluginPathFinder.getFeaturePaths(platformHome); |
| |
| if (additionalLocations.isEmpty()) |
| return createFeatures(featureURLs, monitor); |
| |
| File[] dirs = new File[additionalLocations.size()]; |
| for (int i = 0; i < dirs.length; i++) { |
| String directory = additionalLocations.get(i).toString(); |
| File dir = new File(directory, "features"); //$NON-NLS-1$ |
| if (!dir.exists()) |
| dir = new File(directory); |
| dirs[i] = dir; |
| } |
| |
| URL[] newUrls = PluginPathFinder.scanLocations(dirs); |
| |
| URL[] result = new URL[featureURLs.length + newUrls.length]; |
| System.arraycopy(featureURLs, 0, result, 0, featureURLs.length); |
| System.arraycopy(newUrls, 0, result, featureURLs.length, newUrls.length); |
| return createFeatures(result, monitor); |
| } |
| return new TargetFeature[0]; |
| } |
| |
| private static TargetFeature[] createFeatures(URL[] featurePaths, IProgressMonitor monitor) { |
| SubMonitor subMonitor = SubMonitor.convert(monitor, featurePaths.length); |
| Map<String, TargetFeature> uniqueFeatures = new LinkedHashMap<>(); |
| for (URL featurePath : featurePaths) { |
| File manifest = new File(featurePath.getFile(), ICoreConstants.FEATURE_FILENAME_DESCRIPTOR); |
| if (!manifest.exists() || !manifest.isFile()) { |
| subMonitor.split(1); |
| continue; |
| } |
| try { |
| TargetFeature model = new TargetFeature(manifest); |
| uniqueFeatures.put(model.getId() + "_" + model.getVersion(), model); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| // Ignore bad files in the collection |
| } |
| subMonitor.split(1); |
| } |
| Collection<TargetFeature> models = uniqueFeatures.values(); |
| return models.toArray(new TargetFeature[models.size()]); |
| } |
| } |