1 /******************************************************************************* 2 * Copyright (c) 2008, 2018 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 * Karsten Thoms - Bug#535325 14 *******************************************************************************/ 15 package org.eclipse.pde.internal.core.target; 16 17 import java.io.File; 18 import java.util.ArrayList; 19 import java.util.Arrays; 20 import java.util.List; 21 import java.util.Objects; 22 import org.eclipse.core.runtime.CoreException; 23 import org.eclipse.core.runtime.IProgressMonitor; 24 import org.eclipse.core.runtime.IStatus; 25 import org.eclipse.core.runtime.Status; 26 import org.eclipse.core.runtime.SubMonitor; 27 import org.eclipse.osgi.util.NLS; 28 import org.eclipse.pde.core.target.ITargetDefinition; 29 import org.eclipse.pde.core.target.TargetBundle; 30 import org.eclipse.pde.core.target.TargetFeature; 31 import org.eclipse.pde.internal.build.IPDEBuildConstants; 32 import org.eclipse.pde.internal.core.PDECore; 33 34 /** 35 * A directory of bundles. 36 * 37 * @since 3.5 38 */ 39 public class DirectoryBundleContainer extends AbstractBundleContainer { 40 41 /** 42 * Constant describing the type of bundle container 43 */ 44 public static final String TYPE = "Directory"; //$NON-NLS-1$ 45 46 /** 47 * Path to this container's directory in the local file system. 48 * The path may contain string substitution variables. 49 */ 50 private final String fPath; 51 52 /** 53 * Constructs a directory bundle container at the given location. 54 * 55 * @param path directory location in the local file system, may contain string substitution variables 56 */ DirectoryBundleContainer(String path)57 public DirectoryBundleContainer(String path) { 58 fPath = path; 59 } 60 61 @Override getLocation(boolean resolve)62 public String getLocation(boolean resolve) throws CoreException { 63 if (resolve) { 64 return getDirectory().toString(); 65 } 66 return fPath; 67 } 68 69 @Override getType()70 public String getType() { 71 return TYPE; 72 } 73 74 @Override resolveBundles(ITargetDefinition definition, IProgressMonitor monitor)75 protected TargetBundle[] resolveBundles(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException { 76 File dir = getDirectory(); 77 if (dir.isDirectory()) { 78 File site = getSite(dir); 79 File[] files = site.listFiles(); 80 SubMonitor localMonitor = SubMonitor.convert(monitor, Messages.DirectoryBundleContainer_0, files.length); 81 return Arrays.stream(files).parallel() // 82 .map(file -> { 83 localMonitor.split(1); 84 try { 85 return new TargetBundle(file); 86 } catch (CoreException e) { 87 // Ignore non-bundle files 88 return null; 89 } 90 }).filter(Objects::nonNull) // 91 .toArray(TargetBundle[]::new); 92 } 93 throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.DirectoryBundleContainer_1, dir.toString()))); 94 } 95 96 @Override resolveFeatures(ITargetDefinition definition, IProgressMonitor monitor)97 protected TargetFeature[] resolveFeatures(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException { 98 File dir = getDirectory(); 99 if (!dir.isDirectory()) { 100 throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, 101 NLS.bind(Messages.DirectoryBundleContainer_1, dir.toString()))); 102 } 103 File site = getFeatureSite(dir); 104 File[] files = site.listFiles(); 105 SubMonitor localMonitor = SubMonitor.convert(monitor, Messages.DirectoryBundleContainer_0, files.length); 106 List<TargetFeature> features = new ArrayList<>(files.length); 107 Arrays.stream(files).parallel().forEach(file -> { 108 try { 109 TargetFeature rf = new TargetFeature(file); 110 synchronized (features) { 111 features.add(rf); 112 } 113 } catch (CoreException e) { 114 // Ignore non-feature files 115 } 116 localMonitor.split(1); 117 }); 118 return features.toArray(new TargetFeature[features.size()]); 119 } 120 121 /** 122 * Returns the directory to search for bundles in. 123 * 124 * @return directory if unable to resolve variables in the path 125 */ getDirectory()126 protected File getDirectory() throws CoreException { 127 String path = resolveVariables(fPath); 128 return new File(path); 129 } 130 131 @Override equals(Object o)132 public boolean equals(Object o) { 133 if (o instanceof DirectoryBundleContainer) { 134 DirectoryBundleContainer dbc = (DirectoryBundleContainer) o; 135 return fPath.equals(dbc.fPath); 136 } 137 return false; 138 } 139 140 @Override hashCode()141 public int hashCode() { 142 return fPath.hashCode(); 143 } 144 145 @Override toString()146 public String toString() { 147 return new StringBuilder("Directory ").append(fPath).toString(); //$NON-NLS-1$ 148 } 149 150 /** 151 * Returns the directory to scan for bundles - a "plug-ins" sub directory if present. 152 * 153 * @param root the location the container specifies as a root directory 154 * @return the given directory or its plug-ins sub directory if present 155 */ getSite(File root)156 private File getSite(File root) { 157 File file = new File(root, IPDEBuildConstants.DEFAULT_PLUGIN_LOCATION); 158 if (file.exists()) { 159 return file; 160 } 161 return root; 162 } 163 164 /** 165 * Returns the directory to scan for features - a "features" sub directory 166 * if present. 167 * 168 * @param root 169 * the location the container specifies as a root directory 170 * @return the given directory or its plug-ins sub directory if present 171 */ getFeatureSite(File root)172 private File getFeatureSite(File root) { 173 File file = new File(root, IPDEBuildConstants.DEFAULT_FEATURE_LOCATION); 174 if (file.exists()) { 175 return file; 176 } 177 return root; 178 } 179 180 } 181