/******************************************************************************* * Copyright (c) 2000, 2017 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 * Thierry Lach (thierry.lach@bbdodetroit.com) - bug 40502 * Ericsson AB, Hamdan Msheik - Bug 389564 * Ericsson AB, Julian Enoch - Bug 389564 *******************************************************************************/ package org.eclipse.ant.core; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.eclipse.ant.internal.core.AntClasspathEntry; import org.eclipse.ant.internal.core.AntObject; import org.eclipse.ant.internal.core.IAntCoreConstants; import org.eclipse.ant.internal.core.InternalCoreAntMessages; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IContributor; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Preferences; import org.eclipse.core.runtime.Preferences.IPropertyChangeListener; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.URIUtil; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.core.variables.IDynamicVariable; import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.osgi.util.ManifestElement; import org.eclipse.osgi.util.NLS; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; import org.osgi.framework.namespace.BundleNamespace; import org.osgi.framework.namespace.HostNamespace; import org.osgi.framework.namespace.PackageNamespace; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWire; import org.osgi.framework.wiring.BundleWiring; import org.osgi.service.packageadmin.ExportedPackage; import org.osgi.service.packageadmin.PackageAdmin; import org.osgi.service.prefs.BackingStoreException; import org.osgi.util.tracker.ServiceTracker; /** * Represents the Ant Core plug-in's preferences providing utilities for extracting, changing and updating the underlying preferences. Clients may not * instantiate or subclass this class. * * @since 2.1 * @noinstantiate This class is not intended to be instantiated by clients. * @noextend This class is not intended to be subclassed by clients. */ @SuppressWarnings("deprecation") public class AntCorePreferences implements IPropertyChangeListener { class WrappedClassLoader extends ClassLoader { private Bundle bundle; public WrappedClassLoader(Bundle bundle) { super(); this.bundle = bundle; } /* * (non-Javadoc) * * @see java.lang.ClassLoader#findClass(java.lang.String) */ @Override public Class<?> findClass(String name) throws ClassNotFoundException { return bundle.loadClass(name); } /* * (non-Javadoc) * * @see java.lang.ClassLoader#findResource(java.lang.String) */ @Override public URL findResource(String name) { return bundle.getResource(name); } /* * (non-Javadoc) * * @see java.lang.ClassLoader#findResources(java.lang.String) */ @Override protected Enumeration<URL> findResources(String name) throws IOException { return bundle.getResources(name); } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (!(obj instanceof WrappedClassLoader)) { return false; } return bundle == ((WrappedClassLoader) obj).bundle; } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return bundle.hashCode(); } @Override public String toString() { return "WrappedClassLoader(" + bundle.toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } } static private class Relation { BundleRevision from; BundleRevision to; Relation(BundleRevision from, BundleRevision to) { this.from = from; this.to = to; } @Override public String toString() { return from.toString() + "->" + (to == null ? IAntCoreConstants.EMPTY_STRING : to.toString()); //$NON-NLS-1$ } } private IPreferenceChangeListener prefListener = new IPreferenceChangeListener() { @Override public void preferenceChange(PreferenceChangeEvent event) { String property = event.getKey(); if (property.equals(IAntCoreConstants.PREFERENCE_TASKS) || property.startsWith(IAntCoreConstants.PREFIX_TASK)) { restoreTasks(); } else if (property.equals(IAntCoreConstants.PREFERENCE_TYPES) || property.startsWith(IAntCoreConstants.PREFIX_TYPE)) { restoreTypes(); } else if (property.equals(IAntCoreConstants.PREFERENCE_ANT_HOME_ENTRIES)) { restoreAntHomeEntries(); } else if (property.equals(IAntCoreConstants.PREFERENCE_ADDITIONAL_ENTRIES)) { restoreAdditionalEntries(); } else if (property.equals(IAntCoreConstants.PREFERENCE_ANT_HOME)) { restoreAntHome(); } else if (property.equals(IAntCoreConstants.PREFERENCE_PROPERTIES) || property.startsWith(IAntCoreConstants.PREFIX_PROPERTY)) { restoreCustomProperties(); } else if (property.equals(IAntCoreConstants.PREFERENCE_PROPERTY_FILES)) { restoreCustomPropertyFiles(); } } }; private List<Task> defaultTasks; private List<Type> defaultTypes; private List<AntClasspathEntry> extraClasspathURLs; private List<Property> defaultProperties; private IAntClasspathEntry[] defaultAntHomeEntries; private Task[] customTasks; private Task[] oldCustomTasks; private Type[] customTypes; private Type[] oldCustomTypes; private IAntClasspathEntry[] antHomeEntries; private IAntClasspathEntry[] additionalEntries; private Property[] customProperties; private Property[] oldCustomProperties; private String[] customPropertyFiles; private List<WrappedClassLoader> pluginClassLoaders; private ClassLoader[] orderedPluginClassLoaders; private String antHome; private boolean runningHeadless = false; protected AntCorePreferences(List<IConfigurationElement> defaultTasks, List<IConfigurationElement> defaultExtraClasspath, List<IConfigurationElement> defaultTypes, boolean headless) { this(defaultTasks, defaultExtraClasspath, defaultTypes, Collections.<IConfigurationElement> emptyList(), headless); } protected AntCorePreferences(List<IConfigurationElement> defaultTasks, List<IConfigurationElement> defaultExtraClasspath, List<IConfigurationElement> defaultTypes, List<IConfigurationElement> defaultProperties, boolean headless) { runningHeadless = headless; initializePluginClassLoaders(); extraClasspathURLs = new ArrayList<>(20); this.defaultTasks = computeDefaultTasks(defaultTasks); this.defaultTypes = computeDefaultTypes(defaultTypes); computeDefaultExtraClasspathEntries(defaultExtraClasspath); computeDefaultProperties(defaultProperties); restoreCustomObjects(); } /** * When a preference changes, update the in-memory cache of the preference. * * @param event * The property change event that has occurred. * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent) */ @Override public void propertyChange(Preferences.PropertyChangeEvent event) { // does nothing any longer, see the IPreferenceChangedListener field } /** * Restores the in-memory model of the preferences from the preference store */ private void restoreCustomObjects() { restoreAntHome(); restoreTasks(); restoreTypes(); restoreAntHomeEntries(); restoreAdditionalEntries(); restoreCustomProperties(); restoreCustomPropertyFiles(); IEclipsePreferences node = InstanceScope.INSTANCE.getNode(AntCorePlugin.PI_ANTCORE); if (node != null) { node.addPreferenceChangeListener(prefListener); } } private void restoreTasks() { String tasks = Platform.getPreferencesService().getString(AntCorePlugin.PI_ANTCORE, IAntCoreConstants.PREFERENCE_TASKS, null, null); if (tasks == null || IAntCoreConstants.EMPTY_STRING.equals(tasks)) { customTasks = new Task[0]; } else { customTasks = extractTasks(AntCorePlugin.getPlugin().getPluginPreferences(), getArrayFromString(tasks)); } } private void restoreTypes() { String types = Platform.getPreferencesService().getString(AntCorePlugin.PI_ANTCORE, IAntCoreConstants.PREFERENCE_TYPES, null, null); if (types == null || IAntCoreConstants.EMPTY_STRING.equals(types)) { customTypes = new Type[0]; } else { customTypes = extractTypes(AntCorePlugin.getPlugin().getPluginPreferences(), getArrayFromString(types)); } } private void restoreAntHomeEntries() { String entries = Platform.getPreferencesService().getString(AntCorePlugin.PI_ANTCORE, "ant_urls", //$NON-NLS-1$ null, null); // old constant if (entries == null || IAntCoreConstants.EMPTY_STRING.equals(entries)) { entries = Platform.getPreferencesService().getString(AntCorePlugin.PI_ANTCORE, IAntCoreConstants.PREFERENCE_ANT_HOME_ENTRIES, null, null); } else { // torch the old pref IEclipsePreferences node = InstanceScope.INSTANCE.getNode(AntCorePlugin.PI_ANTCORE); if (node != null) { node.remove("ant_urls"); //$NON-NLS-1$ try { node.flush(); } catch (BackingStoreException e) { // do nothing } } antHomeEntries = migrateURLEntries(getArrayFromString(entries)); return; } if (entries == null || IAntCoreConstants.EMPTY_STRING.equals(entries)) { antHomeEntries = getDefaultAntHomeEntries(); } else { antHomeEntries = extractEntries(getArrayFromString(entries)); } } private void restoreAdditionalEntries() { String entries = Platform.getPreferencesService().getString(AntCorePlugin.PI_ANTCORE, "urls", //$NON-NLS-1$ null, null); // old constant if (entries == null || IAntCoreConstants.EMPTY_STRING.equals(entries)) { entries = Platform.getPreferencesService().getString(AntCorePlugin.PI_ANTCORE, IAntCoreConstants.PREFERENCE_ADDITIONAL_ENTRIES, null, null); } else { IEclipsePreferences node = InstanceScope.INSTANCE.getNode(AntCorePlugin.PI_ANTCORE); if (node != null) { node.remove("urls"); //$NON-NLS-1$ try { node.flush(); } catch (BackingStoreException e) { // do nothing } } additionalEntries = migrateURLEntries(getArrayFromString(entries)); return; } if (entries == null || IAntCoreConstants.EMPTY_STRING.equals(entries)) { IAntClasspathEntry toolsJarEntry = getToolsJarEntry(); List<IAntClasspathEntry> userLibs = getUserLibraries(); if (toolsJarEntry == null) { if (userLibs == null) { additionalEntries = new IAntClasspathEntry[0]; } else { additionalEntries = userLibs.toArray(new IAntClasspathEntry[userLibs.size()]); } } else { if (userLibs == null) { additionalEntries = new IAntClasspathEntry[] { toolsJarEntry }; } else { userLibs.add(toolsJarEntry); additionalEntries = userLibs.toArray(new IAntClasspathEntry[userLibs.size()]); } } } else { additionalEntries = extractEntries(getArrayFromString(entries)); } } /* * Migrates the persisted URL entries restored from a workspace older than 3.0 */ private IAntClasspathEntry[] migrateURLEntries(String[] urlEntries) { List<AntClasspathEntry> result = new ArrayList<>(urlEntries.length); for (int i = 0; i < urlEntries.length; i++) { URL url; try { url = new URL(urlEntries[i]); } catch (MalformedURLException e) { continue; } result.add(new AntClasspathEntry(url)); } return result.toArray(new IAntClasspathEntry[result.size()]); } private void restoreAntHome() { antHome = Platform.getPreferencesService().getString(AntCorePlugin.PI_ANTCORE, IAntCoreConstants.PREFERENCE_ANT_HOME, null, null); if (antHome == null || IAntCoreConstants.EMPTY_STRING.equals(antHome)) { antHome = getDefaultAntHome(); } } /** * Returns the absolute path of the default ant.home to use for the build. The default is the org.apache.ant plug-in folder provided with Eclipse. * * @return String absolute path of the default ant.home * @since 3.0 */ public String getDefaultAntHome() { IAntClasspathEntry[] entries = getDefaultAntHomeEntries(); if (entries.length > 0) { URL antjar = entries[entries.length - 1].getEntryURL(); IPath antHomePath = new Path(antjar.getFile()); // parent directory of the lib directory antHomePath = antHomePath.removeLastSegments(2); return antHomePath.toFile().getAbsolutePath(); } return null; } private void restoreCustomProperties() { String properties = Platform.getPreferencesService().getString(AntCorePlugin.PI_ANTCORE, IAntCoreConstants.PREFERENCE_PROPERTIES, null, null); if (properties == null || IAntCoreConstants.EMPTY_STRING.equals(properties)) { customProperties = new Property[0]; } else { customProperties = extractProperties(AntCorePlugin.getPlugin().getPluginPreferences(), getArrayFromString(properties)); } } private void restoreCustomPropertyFiles() { String propertyFiles = Platform.getPreferencesService().getString(AntCorePlugin.PI_ANTCORE, IAntCoreConstants.PREFERENCE_PROPERTY_FILES, null, null); if (propertyFiles == null || IAntCoreConstants.EMPTY_STRING.equals(propertyFiles)) { customPropertyFiles = new String[0]; } else { customPropertyFiles = getArrayFromString(propertyFiles); } } protected Task[] extractTasks(Preferences prefs, String[] tasks) { List<Task> result = new ArrayList<>(tasks.length); for (int i = 0; i < tasks.length; i++) { String taskName = tasks[i]; String[] values = getArrayFromString(prefs.getString(IAntCoreConstants.PREFIX_TASK + taskName)); if (values.length < 2) { continue; } Task task = new Task(); task.setTaskName(taskName); task.setClassName(values[0]); String library = values[1]; if (library.startsWith(IAntCoreConstants.FILE_PROTOCOL)) { // old format where URLs were persisted library = library.substring(5); } task.setLibraryEntry(new AntClasspathEntry(library)); result.add(task); } return result.toArray(new Task[result.size()]); } protected Type[] extractTypes(Preferences prefs, String[] types) { List<Type> result = new ArrayList<>(types.length); for (int i = 0; i < types.length; i++) { String typeName = types[i]; String[] values = getArrayFromString(prefs.getString(IAntCoreConstants.PREFIX_TYPE + typeName)); if (values.length < 2) { continue; } Type type = new Type(); type.setTypeName(typeName); type.setClassName(values[0]); String library = values[1]; if (library.startsWith(IAntCoreConstants.FILE_PROTOCOL)) { // old format where URLs were persisted library = library.substring(5); } type.setLibraryEntry(new AntClasspathEntry(library)); result.add(type); } return result.toArray(new Type[result.size()]); } protected Property[] extractProperties(Preferences prefs, String[] properties) { Property[] result = new Property[properties.length]; for (int i = 0; i < properties.length; i++) { String propertyName = properties[i]; String value = prefs.getString(IAntCoreConstants.PREFIX_PROPERTY + propertyName); Property property = new Property(); property.setName(propertyName); property.setValue(value); result[i] = property; } return result; } private IAntClasspathEntry[] extractEntries(String[] entries) { IAntClasspathEntry[] result = new IAntClasspathEntry[entries.length]; for (int i = 0; i < entries.length; i++) { result[i] = new AntClasspathEntry(entries[i]); } return result; } /** * Returns the array of URLs that is the default set of URLs defining the Ant classpath. * * Ant running through the command line tries to find tools.jar to help the user. Try emulating the same behavior here. * * @return the default set of URLs defining the Ant classpath * @deprecated use {@link #getDefaultAntHomeEntries()} instead */ @Deprecated public URL[] getDefaultAntURLs() { IAntClasspathEntry[] entries = getDefaultAntHomeEntries(); List<URL> result = new ArrayList<>(3); for (int i = 0; i < entries.length; i++) { IAntClasspathEntry entry = entries[i]; result.add(entry.getEntryURL()); } URL toolsURL = getToolsJarURL(); if (toolsURL != null) { result.add(toolsURL); } return result.toArray(new URL[result.size()]); } /** * Returns the array of classpath entries that is the default set of entries defining the Ant classpath. * * @return the default set of classpath entries defining the Ant classpath */ public synchronized IAntClasspathEntry[] getDefaultAntHomeEntries() { if (defaultAntHomeEntries == null) { ServiceTracker<?, ?> tracker = new ServiceTracker<>(AntCorePlugin.getPlugin().getBundle().getBundleContext(), PackageAdmin.class.getName(), null); tracker.open(); try { List<AntClasspathEntry> result = new ArrayList<>(29); PackageAdmin packageAdmin = (PackageAdmin) tracker.getService(); if (packageAdmin != null) { ExportedPackage[] packages = packageAdmin.getExportedPackages("org.apache.tools.ant"); //$NON-NLS-1$ Bundle bundle = findHighestAntVersion(packages); if (bundle == null) { for (int i = 0; i < packages.length; i++) { bundle = packages[i].getExportingBundle(); if (bundle == null) { continue; } try { addLibraries(bundle, result); if (result.size() > 0) { break; } } catch (IOException ioe) { AntCorePlugin.log(ioe); // maintain logging result.clear(); /* continue to try other providers if an exception occurs */ } } } else { try { addLibraries(bundle, result); } catch (IOException ioe) { AntCorePlugin.log(ioe); // maintain logging } } } defaultAntHomeEntries = result.toArray(new IAntClasspathEntry[result.size()]); } finally { tracker.close(); } } return defaultAntHomeEntries; } /** * Simple algorithm to find the highest version of <code>org.apache.ant</code> available. If there are other providers that are not * <code>org.apache.ant</code> they are ignored and all versions of <code>org.apache.ant</code> are considered. <br> * <br> * See the following bugs for related history: * <ul> * <li><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=282851">https://bugs.eclipse.org/bugs/show_bug.cgi?id=282851</a></li> * <li><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=325125">https://bugs.eclipse.org/bugs/show_bug.cgi?id=325125</a></li> * </ul> * * @param packages * the live list of {@link ExportedPackage}s to inspect * @return the bundle that represents the highest version of <code>org.apache.ant</code> or <code>null</code> if there are no * <code>org.apache.ant</code> providers of the <code>org.apache.ant.tools</code> package. */ Bundle findHighestAntVersion(ExportedPackage[] packages) { Bundle bundle = null; HashSet<Bundle> bundles = new HashSet<>(); for (int i = 0; i < packages.length; i++) { bundle = packages[i].getExportingBundle(); if (bundle == null) { continue; } if ("org.apache.ant".equals(bundle.getSymbolicName())) { //$NON-NLS-1$ bundles.add(bundle); } } Bundle highest = null; Bundle temp = null; for (Iterator<Bundle> iter = bundles.iterator(); iter.hasNext();) { temp = iter.next(); if (highest == null) { highest = temp; } else { if (highest.getVersion().compareTo(temp.getVersion()) < 0) { highest = temp; } } } return highest; } /** * Returns the array of URLs that is the set of URLs defining the Ant classpath. * * @return the set of URLs defining the Ant classpath * @deprecated use getAntHomeClasspathEntries and getToolsJarEntry */ @Deprecated public URL[] getAntURLs() { int extra = 0; IAntClasspathEntry entry = getToolsJarEntry(); if (entry != null) { extra++; } URL[] urls = new URL[antHomeEntries.length + extra]; int i; for (i = 0; i < antHomeEntries.length; i++) { URL url = antHomeEntries[i].getEntryURL(); if (url != null) { urls[i] = url; } } if (entry != null) { urls[i] = entry.getEntryURL(); } return urls; } /** * Returns the complete list of pre-configured {@link Task}s * * @param tasks * the {@link IConfigurationElement} handles for contributed {@link Task}s * @return the list of {@link Task}s */ protected List<Task> computeDefaultTasks(List<IConfigurationElement> tasks) { List<Task> result = new ArrayList<>(tasks.size()); for (Iterator<IConfigurationElement> iterator = tasks.iterator(); iterator.hasNext();) { IConfigurationElement element = iterator.next(); if (!relevantRunningHeadless(element)) { continue; } Task task = new Task(); task.setTaskName(element.getAttribute(IAntCoreConstants.NAME)); task.setClassName(element.getAttribute(AntCorePlugin.CLASS)); if (configureAntObject(element, task, task.getTaskName(), InternalCoreAntMessages.AntCorePreferences_No_library_for_task)) { result.add(task); } } return result; } private void addURLToExtraClasspathEntries(URL url, IConfigurationElement element) { String eclipseRuntime = element.getAttribute(AntCorePlugin.ECLIPSE_RUNTIME); boolean eclipseRuntimeRequired = true; if (eclipseRuntime != null) { eclipseRuntimeRequired = Boolean.valueOf(eclipseRuntime).booleanValue(); } Iterator<AntClasspathEntry> itr = extraClasspathURLs.iterator(); while (itr.hasNext()) { IAntClasspathEntry entry = itr.next(); if (entry.getEntryURL().equals(url)) { return; } } AntClasspathEntry entry = new AntClasspathEntry(url); entry.setEclipseRuntimeRequired(eclipseRuntimeRequired); extraClasspathURLs.add(entry); } /** * Returns the complete listing of pre-configured {@link Type}s * * @param types * the list of {@link IConfigurationElement} handles to contributed {@link Type}s * @return the list of {@link Type}s */ protected List<Type> computeDefaultTypes(List<IConfigurationElement> types) { List<Type> result = new ArrayList<>(types.size()); for (Iterator<IConfigurationElement> iterator = types.iterator(); iterator.hasNext();) { IConfigurationElement element = iterator.next(); if (!relevantRunningHeadless(element)) { continue; } Type type = new Type(); type.setTypeName(element.getAttribute(IAntCoreConstants.NAME)); type.setClassName(element.getAttribute(AntCorePlugin.CLASS)); if (configureAntObject(element, type, type.getTypeName(), InternalCoreAntMessages.AntCorePreferences_No_library_for_type)) { result.add(type); } } return result; } /* * Create a "file:" URL for the specified File making sure the URL ends with a slash if the File denotes a directory. */ private URL getClasspathEntryURL(Bundle bundle, String library) throws IOException { File urlFile = null; if (library.equals("/")) { //$NON-NLS-1$ urlFile = FileLocator.getBundleFile(bundle); } else { try { URL fileURL = FileLocator.toFileURL(bundle.getEntry(library)); urlFile = URIUtil.toFile(URIUtil.toURI(fileURL)); } catch (URISyntaxException e) { AntCorePlugin.log(e); } } if (urlFile == null || !urlFile.exists()) return null; String path = urlFile.getAbsolutePath(); return new URL(IAntCoreConstants.FILE_PROTOCOL + (urlFile.isDirectory() ? path + "/" : path)); //$NON-NLS-1$ } /** * Configures the given {@link AntObject} and returns if it should be retained * * @param element * @param antObject * @param objectName * @param errorMessage * @return <code>true</code> if the object configured and should be retained, <code>false</code> otherwise */ private boolean configureAntObject(IConfigurationElement element, AntObject antObject, String objectName, String errorMessage) { String runtime = element.getAttribute(AntCorePlugin.ECLIPSE_RUNTIME); if (runtime != null) { antObject.setEclipseRuntimeRequired(Boolean.valueOf(runtime).booleanValue()); } String uri = element.getAttribute(AntCorePlugin.URI); if (uri != null) { antObject.setURI(uri); } String library = element.getAttribute(AntCorePlugin.LIBRARY); if (library == null) { IStatus status = new Status(IStatus.ERROR, AntCorePlugin.PI_ANTCORE, AntCorePlugin.ERROR_LIBRARY_NOT_SPECIFIED, NLS.bind(InternalCoreAntMessages.AntCorePreferences_Library_not_specified_for___0__4, new String[] { objectName }), null); AntCorePlugin.getPlugin().getLog().log(status); return false; } try { IContributor contributor = element.getContributor(); antObject.setPluginLabel(contributor.getName()); Bundle bundle = Platform.getBundle(contributor.getName()); URL url = getClasspathEntryURL(bundle, library); if (url != null) { addURLToExtraClasspathEntries(url, element); addPluginClassLoader(bundle); antObject.setLibraryEntry(new AntClasspathEntry(url)); return true; } // type specifies a library that does not exist IStatus status = new Status(IStatus.ERROR, AntCorePlugin.PI_ANTCORE, AntCorePlugin.ERROR_LIBRARY_NOT_SPECIFIED, NLS.bind(errorMessage, new String[] { library, element.getContributor().getName() }), null); AntCorePlugin.getPlugin().getLog().log(status); return false; } catch (MalformedURLException e) { // if the URL does not have a valid format, just log and ignore the exception IStatus status = new Status(IStatus.ERROR, AntCorePlugin.PI_ANTCORE, AntCorePlugin.ERROR_MALFORMED_URL, InternalCoreAntMessages.AntCorePreferences_Malformed_URL__1, e); AntCorePlugin.getPlugin().getLog().log(status); } catch (Exception e) { // likely extra classpath entry library that does not exist IStatus status = new Status(IStatus.ERROR, AntCorePlugin.PI_ANTCORE, AntCorePlugin.ERROR_LIBRARY_NOT_SPECIFIED, NLS.bind(InternalCoreAntMessages.AntCorePreferences_8, new String[] { library, element.getContributor().getName() }), null); AntCorePlugin.getPlugin().getLog().log(status); } return false; } /* * Computes the extra classpath entries defined plug-ins and fragments. */ protected void computeDefaultExtraClasspathEntries(List<IConfigurationElement> entries) { for (Iterator<IConfigurationElement> iterator = entries.iterator(); iterator.hasNext();) { IConfigurationElement element = iterator.next(); if (!relevantRunningHeadless(element)) { continue; } String library = element.getAttribute(AntCorePlugin.LIBRARY); Bundle bundle = Platform.getBundle(element.getContributor().getName()); try { URL url = getClasspathEntryURL(bundle, library); if (url != null) { addURLToExtraClasspathEntries(url, element); addPluginClassLoader(bundle); } else { // extra classpath entry that does not exist IStatus status = new Status(IStatus.ERROR, AntCorePlugin.PI_ANTCORE, AntCorePlugin.ERROR_LIBRARY_NOT_SPECIFIED, NLS.bind(InternalCoreAntMessages.AntCorePreferences_6, new String[] { library, element.getContributor().getName() }), null); AntCorePlugin.getPlugin().getLog().log(status); continue; } } catch (MalformedURLException e) { // if the URL does not have a valid format, just log and ignore the exception IStatus status = new Status(IStatus.ERROR, AntCorePlugin.PI_ANTCORE, AntCorePlugin.ERROR_MALFORMED_URL, InternalCoreAntMessages.AntCorePreferences_Malformed_URL__1, e); AntCorePlugin.getPlugin().getLog().log(status); continue; } catch (Exception e) { // likely extra classpath entry that does not exist IStatus status = new Status(IStatus.ERROR, AntCorePlugin.PI_ANTCORE, AntCorePlugin.ERROR_LIBRARY_NOT_SPECIFIED, NLS.bind(InternalCoreAntMessages.AntCorePreferences_6, new String[] { library, element.getContributor().getName() }), null); AntCorePlugin.getPlugin().getLog().log(status); continue; } } } private boolean relevantRunningHeadless(IConfigurationElement element) { if (runningHeadless) { String headless = element.getAttribute(AntCorePlugin.HEADLESS); if (headless != null) { boolean headlessProperty = Boolean.valueOf(headless).booleanValue(); if (!headlessProperty) { return false; } } } return true; } /* * Scan the Ant property extensions for properties to set. * * @since 3.0 */ private void computeDefaultProperties(List<IConfigurationElement> properties) { defaultProperties = new ArrayList<>(properties.size()); for (Iterator<IConfigurationElement> iterator = properties.iterator(); iterator.hasNext();) { IConfigurationElement element = iterator.next(); if (!relevantRunningHeadless(element)) { continue; } String name = element.getAttribute(IAntCoreConstants.NAME); if (name == null) { continue; } String value = element.getAttribute(IAntCoreConstants.VALUE); Property property = null; if (value != null) { property = new Property(name, value); property.setPluginLabel(element.getContributor().getName()); } else { Bundle bundle = Platform.getBundle(element.getContributor().getName()); if (bundle == null) { continue; } property = new Property(); property.setName(name); property.setPluginLabel(element.getContributor().getName()); String className = element.getAttribute(AntCorePlugin.CLASS); property.setValueProvider(className, getClassLoader(bundle)); } defaultProperties.add(property); String runtime = element.getAttribute(AntCorePlugin.ECLIPSE_RUNTIME); if (runtime != null) { property.setEclipseRuntimeRequired(Boolean.valueOf(runtime).booleanValue()); } } } private WrappedClassLoader getClassLoader(Bundle b) { return new WrappedClassLoader(b); } /** * Returns the IAntClasspathEntry for the tools.jar associated with the path supplied. May return <code>null</code> if no tools.jar is found (e.g. * the path points to a JRE install). * * @param javaHomePath * path for Java home * @return IAntClasspathEntry tools.jar IAntClasspathEntry or <code>null</code> * @since 3.0 */ public IAntClasspathEntry getToolsJarEntry(IPath javaHomePath) { IPath newjh = javaHomePath; if ("jre".equalsIgnoreCase(newjh.lastSegment())) { //$NON-NLS-1$ newjh = newjh.removeLastSegments(1); } newjh = newjh.append("lib").append("tools.jar"); //$NON-NLS-1$ //$NON-NLS-2$ File tools = newjh.toFile(); if (!tools.exists()) { // attempt to find in the older 1.1.* newjh = newjh.removeLastSegments(1); newjh = newjh.append("classes.zip"); //$NON-NLS-1$ tools = newjh.toFile(); if (!tools.exists()) { return null; } } return new AntClasspathEntry(tools.getAbsolutePath()); } /** * Returns the URL for the tools.jar associated with the System property "java.home" location. If "java.home" has no associated tools.jar (such as * a JRE install), the environment variable "JAVA_HOME" is resolved to check for a tools.jar. May return <code>null</code> if no tools.jar is * found. * * @return URL tools.jar URL or <code>null</code> * @deprecated use getToolsJarEntry() */ @Deprecated public URL getToolsJarURL() { IPath path = new Path(System.getProperty("java.home")); //$NON-NLS-1$ IAntClasspathEntry entry = getToolsJarEntry(path); if (entry == null) { IDynamicVariable variable = VariablesPlugin.getDefault().getStringVariableManager().getDynamicVariable("env_var"); //$NON-NLS-1$ String javaHome = null; try { if (variable != null) { javaHome = variable.getValue("JAVA_HOME"); //$NON-NLS-1$ } if (javaHome != null) { path = new Path(javaHome); entry = getToolsJarEntry(path); } } catch (CoreException e) { AntCorePlugin.log(e); } } if (entry != null) { return entry.getEntryURL(); } return null; } /** * Returns the <code>IAntClasspathEntry</code> for the tools.jar associated with the System property "java.home" location. If "java.home" has no * associated tools.jar (such as a JRE install), the environment variable "JAVA_HOME" is resolved to check for a tools.jar. May return * <code>null</code> if no tools.jar is found. * * @return IAntClasspathEntry tools.jar IAntClasspathEntry or <code>null</code> */ public IAntClasspathEntry getToolsJarEntry() { IPath path = new Path(System.getProperty("java.home")); //$NON-NLS-1$ IAntClasspathEntry entry = getToolsJarEntry(path); if (entry == null) { IDynamicVariable variable = VariablesPlugin.getDefault().getStringVariableManager().getDynamicVariable("env_var"); //$NON-NLS-1$ String javaHome = null; try { if (variable != null) { javaHome = variable.getValue("JAVA_HOME"); //$NON-NLS-1$ } if (javaHome != null) { path = new Path(javaHome); entry = getToolsJarEntry(path); } } catch (CoreException e) { AntCorePlugin.log(e); } } return entry; } /** * Returns the <code>IAntClasspathEntry</code>s for the jars from ${user.home}/.ant/lib May return <code>null</code> if jars are found. * * TODO Should be promoted to API post 3.1 * * @return the collection of <code>IAntClasspathEntry</code> found at ${user.home}/.ant/lib or <code>null</code> if none found of location does * not exist */ private List<IAntClasspathEntry> getUserLibraries() { File libDir = new File(System.getProperty("user.home"), ".ant" + File.separatorChar + "lib"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ URL[] urls = null; try { urls = getLocationURLs(libDir); } catch (MalformedURLException e) { AntCorePlugin.log(e); } if (urls == null) { return null; } List<IAntClasspathEntry> entries = new ArrayList<>(urls.length); for (int i = 0; i < urls.length; i++) { AntClasspathEntry entry = new AntClasspathEntry(urls[i]); entries.add(entry); } return entries; } private URL[] getLocationURLs(File location) throws MalformedURLException { URL[] urls = null; if (!location.exists()) { return urls; } final String extension = ".jar"; //$NON-NLS-1$ if (!location.isDirectory()) { urls = new URL[1]; String path = location.getPath(); if (path.toLowerCase().endsWith(extension)) { // make sure the URL is properly escaped urls[0] = location.toURI().toURL(); } return urls; } File[] matches = location.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.toLowerCase().endsWith(extension); } }); urls = new URL[matches.length]; for (int i = 0; i < matches.length; ++i) { // make sure the URL is properly escaped urls[i] = matches[i].toURI().toURL(); } return urls; } /** * Add the libraries contributed by the Ant plug-in, to the classpath. * * @param source * @param destination * @throws IOException * @throws MalformedURLException */ private void addLibraries(Bundle source, List<AntClasspathEntry> destination) throws IOException, MalformedURLException { ManifestElement[] libraries = null; try { libraries = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, source.getHeaders(IAntCoreConstants.EMPTY_STRING).get(Constants.BUNDLE_CLASSPATH)); } catch (BundleException e) { IStatus status = new Status(IStatus.ERROR, AntCorePlugin.PI_ANTCORE, AntCorePlugin.ERROR_MALFORMED_URL, InternalCoreAntMessages.AntCorePreferences_0, e); AntCorePlugin.getPlugin().getLog().log(status); return; } if (libraries == null) { return; } URL url = null; for (int i = 0; i < libraries.length; i++) { url = source.getEntry(libraries[i].getValue()); if (url != null) { destination.add(new AntClasspathEntry(FileLocator.toFileURL(url))); } } } protected void addPluginClassLoader(Bundle bundle) { WrappedClassLoader loader = getClassLoader(bundle); if (!pluginClassLoaders.contains(loader)) { pluginClassLoaders.add(loader); } } /** * Returns the list of URLs added to the classpath by the extra classpath entries extension point. * * @return the list of extra classpath URLs */ public URL[] getExtraClasspathURLs() { URL[] urls = new URL[extraClasspathURLs.size()]; for (int i = 0; i < extraClasspathURLs.size(); i++) { IAntClasspathEntry entry = extraClasspathURLs.get(i); urls[i] = entry.getEntryURL(); } return urls; } /** * Returns the list of URLs added to the classpath by the extra classpath entries extension point for an Ant build that is occurring without the * Eclipse runtime. * * @return the list of extra classpath URLs * @since 3.0 */ public URL[] getRemoteExtraClasspathURLs() { List<URL> urls = new ArrayList<>(extraClasspathURLs.size()); for (int i = 0; i < extraClasspathURLs.size(); i++) { IAntClasspathEntry entry = extraClasspathURLs.get(i); if (!entry.isEclipseRuntimeRequired()) { urls.add(entry.getEntryURL()); } } return urls.toArray(new URL[urls.size()]); } /** * Returns the entire set of URLs that define the Ant runtime classpath. Includes the Ant URLs, the additional URLs and extra classpath URLs. * * @return the entire runtime classpath of URLs */ public URL[] getURLs() { List<URL> result = new ArrayList<>(60); if (antHomeEntries != null) { addEntryURLs(result, antHomeEntries); } if (additionalEntries != null && additionalEntries.length > 0) { addEntryURLs(result, additionalEntries); } for (int i = 0; i < extraClasspathURLs.size(); i++) { IAntClasspathEntry entry = extraClasspathURLs.get(i); URL url = entry.getEntryURL(); if (url != null) { result.add(url); } } return result.toArray(new URL[result.size()]); } private void addEntryURLs(List<URL> result, IAntClasspathEntry[] entries) { for (int i = 0; i < entries.length; i++) { IAntClasspathEntry entry = entries[i]; URL url = entry.getEntryURL(); if (url != null) { result.add(url); } } } protected ClassLoader[] getPluginClassLoaders() { if (orderedPluginClassLoaders == null) { Iterator<WrappedClassLoader> classLoaders = pluginClassLoaders.iterator(); Map<String, WrappedClassLoader> idToLoader = new HashMap<>(pluginClassLoaders.size()); List<BundleRevision> bundles = new ArrayList<>(pluginClassLoaders.size()); while (classLoaders.hasNext()) { WrappedClassLoader loader = classLoaders.next(); idToLoader.put(loader.bundle.getSymbolicName(), loader); BundleRevision revision = loader.bundle.adapt(BundleRevision.class); if (revision != null) { bundles.add(revision); } } List<BundleRevision> sorted = computePrerequisiteOrder(bundles); List<WrappedClassLoader> loaders = new ArrayList<>(sorted.size()); for (BundleRevision revision : sorted) { String id = revision.getSymbolicName(); loaders.add(idToLoader.get(id)); } orderedPluginClassLoaders = loaders.toArray(new ClassLoader[loaders.size()]); } return orderedPluginClassLoaders; } /* * Copied from org.eclipse.pde.internal.build.Utils */ private List<BundleRevision> computePrerequisiteOrder(List<BundleRevision> plugins) { List<Relation> prereqs = new ArrayList<>(plugins.size()); List<BundleRevision> fragments = new ArrayList<>(); // create a collection of directed edges from plugin to prereq for (BundleRevision current : plugins) { if ((current.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) { fragments.add(current); continue; } boolean found = false; BundleRevision[] prereqList = getDependentBundles(current); for (BundleRevision prereq : prereqList) { // ensure that we only include values from the original set. if (plugins.contains(prereq)) { found = true; prereqs.add(new Relation(current, prereq)); } } // if we didn't find any prereqs for this plugin, add a null prereq // to ensure the value is in the output if (!found) { prereqs.add(new Relation(current, null)); } } // The fragments needs to added relatively to their host and to their // own prerequisite (bug #43244) for (BundleRevision currentFrag : fragments) { if (plugins.contains(currentFrag)) { BundleWiring wiring = currentFrag.getWiring(); List<BundleWire> hostWires = wiring == null ? Collections.<BundleWire> emptyList() : wiring.getRequiredWires(HostNamespace.HOST_NAMESPACE); if (!hostWires.isEmpty()) { prereqs.add(new Relation(currentFrag, hostWires.get(0).getProvider())); } } else { AntCorePlugin.getPlugin().getLog().log(new Status(IStatus.ERROR, AntCorePlugin.PI_ANTCORE, AntCorePlugin.ERROR_MALFORMED_URL, NLS.bind(InternalCoreAntMessages.AntCorePreferences_1, new String[] { currentFrag.getSymbolicName() }), null)); } } // do a topological sort, insert the fragments into the sorted elements return computeNodeOrder(prereqs); } /* * Copied from org.eclipse.pde.internal.build.site.PDEState. */ private BundleRevision[] getDependentBundles(BundleRevision root) { BundleRevision[] imported = getImportedBundles(root); BundleRevision[] required = getRequiredBundles(root); BundleRevision[] dependents = new BundleRevision[imported.length + required.length]; System.arraycopy(imported, 0, dependents, 0, imported.length); System.arraycopy(required, 0, dependents, imported.length, required.length); return dependents; } /* * Copied from org.eclipse.pde.internal.build.site.PDEState. */ private BundleRevision[] getRequiredBundles(BundleRevision root) { return getDependantRequirements(root, BundleNamespace.BUNDLE_NAMESPACE); } /* * Copied from org.eclipse.pde.internal.build.site.PDEState. */ private BundleRevision[] getImportedBundles(BundleRevision root) { return getDependantRequirements(root, PackageNamespace.PACKAGE_NAMESPACE); } private BundleRevision[] getDependantRequirements(BundleRevision root, String namespace) { if (root == null) { return new BundleRevision[0]; } BundleWiring wiring = root.getWiring(); List<BundleWire> requiredWires = wiring == null ? Collections.<BundleWire> emptyList() : wiring.getRequiredWires(namespace); ArrayList<BundleRevision> requirementProviders = new ArrayList<>(requiredWires.size()); for (BundleWire requiredWire : requiredWires) { BundleRevision provider = requiredWire.getProvider(); if (!provider.equals(root) && !requirementProviders.contains(provider)) { requirementProviders.add(provider); } } return requirementProviders.toArray(new BundleRevision[requirementProviders.size()]); } /* * Copied from org.eclipse.pde.internal.build.Utils */ private void removeArcs(List<Relation> edges, List<BundleRevision> roots, Map<BundleRevision, Integer> counts) { for (Iterator<BundleRevision> j = roots.iterator(); j.hasNext();) { Object root = j.next(); for (int i = 0; i < edges.size(); i++) { if (root.equals(edges.get(i).to)) { BundleRevision input = edges.get(i).from; Integer count = counts.get(input); if (count != null) { counts.put(input, new Integer(count.intValue() - 1)); } } } } } /* * Copied from org.eclipse.pde.internal.build.Utils */ private List<BundleRevision> computeNodeOrder(List<Relation> edges) { Map<BundleRevision, Integer> counts = computeCounts(edges); List<BundleRevision> nodes = new ArrayList<>(counts.size()); while (!counts.isEmpty()) { List<BundleRevision> roots = findRootNodes(counts); if (roots.isEmpty()) { break; } for (Iterator<BundleRevision> i = roots.iterator(); i.hasNext();) { counts.remove(i.next()); } nodes.addAll(roots); removeArcs(edges, roots, counts); } return nodes; } /* * Copied from org.eclipse.pde.internal.build.Utils */ private Map<BundleRevision, Integer> computeCounts(List<Relation> mappings) { Map<BundleRevision, Integer> counts = new HashMap<>(5); for (int i = 0; i < mappings.size(); i++) { BundleRevision from = mappings.get(i).from; Integer fromCount = counts.get(from); BundleRevision to = mappings.get(i).to; if (to == null) counts.put(from, new Integer(0)); else { if (counts.get(to) == null) counts.put(to, new Integer(0)); fromCount = fromCount == null ? new Integer(1) : new Integer(fromCount.intValue() + 1); counts.put(from, fromCount); } } return counts; } /* * Copied from org.eclipse.pde.internal.build.Utils */ private List<BundleRevision> findRootNodes(Map<BundleRevision, Integer> counts) { List<BundleRevision> result = new ArrayList<>(5); for (Iterator<BundleRevision> i = counts.keySet().iterator(); i.hasNext();) { BundleRevision node = i.next(); int count = counts.get(node).intValue(); if (count == 0) { result.add(node); } } return result; } private void initializePluginClassLoaders() { pluginClassLoaders = new ArrayList<>(10); // ant.core should always be present pluginClassLoaders.add(getClassLoader(AntCorePlugin.getPlugin().getBundle())); } /** * Returns the default and custom tasks. * * @return the list of default and custom tasks. */ public List<Task> getTasks() { List<Task> result = new ArrayList<>(10); if (defaultTasks != null && !defaultTasks.isEmpty()) { result.addAll(defaultTasks); } if (customTasks != null && customTasks.length != 0) { result.addAll(Arrays.asList(customTasks)); } return result; } /** * Returns the default and custom tasks that are relevant when there is no Eclipse runtime context (an Ant build in a separate VM). * * @return the list of default and custom tasks. */ public List<Task> getRemoteTasks() { List<Task> result = new ArrayList<>(10); if (defaultTasks != null && !defaultTasks.isEmpty()) { Iterator<Task> iter = defaultTasks.iterator(); while (iter.hasNext()) { Task task = iter.next(); if (!task.isEclipseRuntimeRequired()) { result.add(task); } } } if (customTasks != null && customTasks.length != 0) { result.addAll(Arrays.asList(customTasks)); } return result; } /** * Returns the user defined custom tasks * * @return the user defined tasks */ public Task[] getCustomTasks() { return customTasks; } /** * Returns the user defined custom types * * @return the user defined types */ public Type[] getCustomTypes() { return customTypes; } /** * Returns the custom user properties specified for Ant builds. * * @return the properties defined for Ant builds. */ public Property[] getCustomProperties() { return customProperties; } /** * Returns the default and custom properties. * * @return the list of default and custom properties. * @since 3.0 */ public List<Property> getProperties() { List<Property> result = new ArrayList<>(10); if (defaultProperties != null && !defaultProperties.isEmpty()) { result.addAll(defaultProperties); } if (customProperties != null && customProperties.length != 0) { result.addAll(Arrays.asList(customProperties)); } return result; } /** * Returns the default and custom properties that are relevant when there is no Eclipse runtime context (Ant build in a separate VM). * * @return the list of default and custom properties. * @since 3.0 */ public List<Property> getRemoteAntProperties() { List<Property> result = new ArrayList<>(10); if (defaultProperties != null && !defaultProperties.isEmpty()) { Iterator<Property> iter = defaultProperties.iterator(); while (iter.hasNext()) { Property property = iter.next(); if (!property.isEclipseRuntimeRequired()) { result.add(property); } } } if (customProperties != null && customProperties.length != 0) { result.addAll(Arrays.asList(customProperties)); } return result; } /** * Returns the custom property files specified for Ant builds performing any required string substitution if indicated. * * @param performStringSubstition * whether or not to perform the string substitution on the property file strings * @return the property files defined for Ant builds. * @since 3.0 */ public String[] getCustomPropertyFiles(boolean performStringSubstition) { if (!performStringSubstition || customPropertyFiles == null || customPropertyFiles.length == 0) { return customPropertyFiles; } List<String> files = new ArrayList<>(customPropertyFiles.length); for (int i = 0; i < customPropertyFiles.length; i++) { String filename = customPropertyFiles[i]; try { filename = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(filename); files.add(filename); } catch (CoreException e) { // notify the user via the Ant console of the missing file files.add(filename); } } return files.toArray(new String[files.size()]); } /** * Returns the custom property files specified for Ant builds. * * @return the property files defined for Ant builds. */ public String[] getCustomPropertyFiles() { return getCustomPropertyFiles(true); } /** * Returns the custom URLs specified for the Ant classpath * * @return the URLs defining the Ant classpath * @deprecated */ @Deprecated public URL[] getCustomURLs() { URL[] urls = new URL[additionalEntries.length]; int i; for (i = 0; i < additionalEntries.length; i++) { URL url = additionalEntries[i].getEntryURL(); if (url != null) { urls[i] = url; } } return urls; } /** * Sets the user defined custom tasks. To commit the changes, updatePluginPreferences must be called. * * @param tasks */ public void setCustomTasks(Task[] tasks) { oldCustomTasks = customTasks; customTasks = tasks; } /** * Sets the user defined custom types. To commit the changes, updatePluginPreferences must be called. * * @param types * The custom types */ public void setCustomTypes(Type[] types) { oldCustomTypes = customTypes; customTypes = types; } /** * Sets the custom URLs specified for the Ant classpath. To commit the changes, updatePluginPreferences must be called. * * @param urls * the URLs defining the Ant classpath * @deprecated use setAdditionalEntries(IAntClasspathEntry)[] */ @Deprecated public void setCustomURLs(URL[] urls) { additionalEntries = new IAntClasspathEntry[urls.length]; for (int i = 0; i < urls.length; i++) { URL url = urls[i]; IAntClasspathEntry entry = new AntClasspathEntry(url); additionalEntries[i] = entry; } } /** * Sets the Ant URLs specified for the Ant classpath. To commit the changes, updatePluginPreferences must be called. * * @param urls * the URLs defining the Ant classpath * @deprecated use setAntHomeEntires(IAntClasspathEntry[]) */ @Deprecated public void setAntURLs(URL[] urls) { antHomeEntries = new IAntClasspathEntry[urls.length]; for (int i = 0; i < urls.length; i++) { URL url = urls[i]; IAntClasspathEntry entry = new AntClasspathEntry(url); antHomeEntries[i] = entry; } } /** * Sets the custom property files specified for Ant builds. To commit the changes, updatePluginPreferences must be called. * * @param paths * the absolute paths defining the property files to use. */ public void setCustomPropertyFiles(String[] paths) { customPropertyFiles = paths; } /** * Sets the custom user properties specified for Ant builds. To commit the changes, updatePluginPreferences must be called. * * @param properties * the properties defining the Ant properties */ public void setCustomProperties(Property[] properties) { oldCustomProperties = customProperties; customProperties = properties; } /** * Returns the default and custom types. * * @return all of the defined types */ public List<Type> getTypes() { List<Type> result = new ArrayList<>(10); if (defaultTypes != null && !defaultTypes.isEmpty()) { result.addAll(defaultTypes); } if (customTypes != null && customTypes.length != 0) { result.addAll(Arrays.asList(customTypes)); } return result; } /** * Returns the default and custom types that are relevant when there is no Eclipse runtime context (an Ant build in a separate VM). * * @return the list of default and custom types. */ public List<Type> getRemoteTypes() { List<Type> result = new ArrayList<>(10); if (defaultTypes != null && !defaultTypes.isEmpty()) { Iterator<Type> iter = defaultTypes.iterator(); while (iter.hasNext()) { Type type = iter.next(); if (!type.isEclipseRuntimeRequired()) { result.add(type); } } } if (customTypes != null && customTypes.length != 0) { result.addAll(Arrays.asList(customTypes)); } return result; } /** * Returns the default types defined via the type extension point * * @return all of the default types */ public List<Type> getDefaultTypes() { List<Type> result = new ArrayList<>(10); if (defaultTypes != null && !defaultTypes.isEmpty()) { result.addAll(defaultTypes); } return result; } /** * Returns the default tasks defined via the task extension point * * @return all of the default tasks */ public List<Task> getDefaultTasks() { List<Task> result = new ArrayList<>(10); if (defaultTasks != null && !defaultTasks.isEmpty()) { result.addAll(defaultTasks); } return result; } /** * Returns the default properties defined via the properties extension point * * @return all of the default properties * @since 3.0 */ public List<Property> getDefaultProperties() { List<Property> result = new ArrayList<>(10); if (defaultProperties != null && !defaultProperties.isEmpty()) { result.addAll(defaultProperties); } return result; } /* * Convert a list of tokens into an array using "," as the tokenizer. */ protected String[] getArrayFromString(String list) { String separator = ","; //$NON-NLS-1$ if (list == null || list.trim().equals(IAntCoreConstants.EMPTY_STRING)) { return new String[0]; } ArrayList<String> result = new ArrayList<>(); for (StringTokenizer tokens = new StringTokenizer(list, separator); tokens.hasMoreTokens();) { String token = tokens.nextToken().trim(); if (!token.equals(IAntCoreConstants.EMPTY_STRING)) { result.add(token); } } return result.toArray(new String[result.size()]); } /** * Updates the underlying plug-in preferences to the current state. */ public void updatePluginPreferences() { IEclipsePreferences node = InstanceScope.INSTANCE.getNode(AntCorePlugin.PI_ANTCORE); if (node != null) { node.removePreferenceChangeListener(prefListener); Preferences prefs = AntCorePlugin.getPlugin().getPluginPreferences(); updateTasks(prefs); updateTypes(prefs); updateAntHomeEntries(prefs); updateAdditionalEntries(prefs); updateProperties(prefs); updatePropertyFiles(prefs); boolean classpathChanged = AntCorePlugin.getPlugin().getPluginPreferences().needsSaving(); AntCorePlugin.getPlugin().savePluginPreferences(); if (classpathChanged) { prefs.setValue(IAntCoreConstants.PREFERENCE_CLASSPATH_CHANGED, true); } prefs.setValue(IAntCoreConstants.PREFERENCE_CLASSPATH_CHANGED, false); node.addPreferenceChangeListener(prefListener); } } protected void updateTasks(Preferences prefs) { if (oldCustomTasks != null) { for (int i = 0; i < oldCustomTasks.length; i++) { Task oldTask = oldCustomTasks[i]; prefs.setToDefault(IAntCoreConstants.PREFIX_TASK + oldTask.getTaskName()); } oldCustomTasks = null; } if (customTasks.length == 0) { prefs.setValue(IAntCoreConstants.PREFERENCE_TASKS, IAntCoreConstants.EMPTY_STRING); return; } StringBuffer tasks = new StringBuffer(); for (int i = 0; i < customTasks.length; i++) { tasks.append(customTasks[i].getTaskName()); tasks.append(','); prefs.setValue(IAntCoreConstants.PREFIX_TASK + customTasks[i].getTaskName(), customTasks[i].getClassName() + "," //$NON-NLS-1$ + customTasks[i].getLibraryEntry().getLabel()); } prefs.setValue(IAntCoreConstants.PREFERENCE_TASKS, tasks.toString()); } protected void updateTypes(Preferences prefs) { if (oldCustomTypes != null) { for (int i = 0; i < oldCustomTypes.length; i++) { Type oldType = oldCustomTypes[i]; prefs.setToDefault(IAntCoreConstants.PREFIX_TYPE + oldType.getTypeName()); } oldCustomTypes = null; } if (customTypes.length == 0) { prefs.setValue(IAntCoreConstants.PREFERENCE_TYPES, IAntCoreConstants.EMPTY_STRING); return; } StringBuffer types = new StringBuffer(); for (int i = 0; i < customTypes.length; i++) { types.append(customTypes[i].getTypeName()); types.append(','); prefs.setValue(IAntCoreConstants.PREFIX_TYPE + customTypes[i].getTypeName(), customTypes[i].getClassName() + "," //$NON-NLS-1$ + customTypes[i].getLibraryEntry().getLabel()); } prefs.setValue(IAntCoreConstants.PREFERENCE_TYPES, types.toString()); } protected void updateProperties(Preferences prefs) { if (oldCustomProperties != null) { for (int i = 0; i < oldCustomProperties.length; i++) { Property oldProperty = oldCustomProperties[i]; prefs.setToDefault(IAntCoreConstants.PREFIX_PROPERTY + oldProperty.getName()); } oldCustomProperties = null; } if (customProperties.length == 0) { prefs.setValue(IAntCoreConstants.PREFERENCE_PROPERTIES, IAntCoreConstants.EMPTY_STRING); return; } StringBuffer properties = new StringBuffer(); for (int i = 0; i < customProperties.length; i++) { properties.append(customProperties[i].getName()); properties.append(','); prefs.setValue(IAntCoreConstants.PREFIX_PROPERTY + customProperties[i].getName(), customProperties[i].getValue(false)); } prefs.setValue(IAntCoreConstants.PREFERENCE_PROPERTIES, properties.toString()); } protected void updateAdditionalEntries(Preferences prefs) { prefs.setValue("urls", IAntCoreConstants.EMPTY_STRING); // old constant removed //$NON-NLS-1$ String serialized = IAntCoreConstants.EMPTY_STRING; IAntClasspathEntry toolsJarEntry = getToolsJarEntry(); List<IAntClasspathEntry> userLibs = getUserLibraries(); if (userLibs == null) { userLibs = new ArrayList<>(); } if (toolsJarEntry != null) { userLibs.add(toolsJarEntry); } boolean changed = true; if (additionalEntries.length == userLibs.size()) { changed = false; for (int i = 0; i < additionalEntries.length; i++) { if (!additionalEntries[i].equals(userLibs.get(i))) { changed = true; break; } } } if (changed) { StringBuffer entries = new StringBuffer(); for (int i = 0; i < additionalEntries.length; i++) { entries.append(additionalEntries[i].getLabel()); entries.append(','); } serialized = entries.toString(); } prefs.setValue(IAntCoreConstants.PREFERENCE_ADDITIONAL_ENTRIES, serialized); String prefAntHome = IAntCoreConstants.EMPTY_STRING; if (antHome != null && !antHome.equals(getDefaultAntHome())) { prefAntHome = antHome; } prefs.setValue(IAntCoreConstants.PREFERENCE_ANT_HOME, prefAntHome); } protected void updateAntHomeEntries(Preferences prefs) { prefs.setValue("ant_urls", IAntCoreConstants.EMPTY_STRING); // old constant removed //$NON-NLS-1$ // see if the custom entries are just the default entries IAntClasspathEntry[] defaultEntries = getDefaultAntHomeEntries(); boolean dflt = false; if (defaultEntries.length == antHomeEntries.length) { dflt = true; for (int i = 0; i < antHomeEntries.length; i++) { if (!antHomeEntries[i].equals(defaultEntries[i])) { dflt = false; break; } } } if (dflt) { // always want to recalculate the default Ant urls // to pick up any changes in the default Ant classpath prefs.setValue(IAntCoreConstants.PREFERENCE_ANT_HOME_ENTRIES, IAntCoreConstants.EMPTY_STRING); return; } StringBuffer entries = new StringBuffer(); for (int i = 0; i < antHomeEntries.length; i++) { entries.append(antHomeEntries[i].getLabel()); entries.append(','); } prefs.setValue(IAntCoreConstants.PREFERENCE_ANT_HOME_ENTRIES, entries.toString()); } protected void updatePropertyFiles(Preferences prefs) { StringBuffer files = new StringBuffer(); for (int i = 0; i < customPropertyFiles.length; i++) { files.append(customPropertyFiles[i]); files.append(','); } prefs.setValue(IAntCoreConstants.PREFERENCE_PROPERTY_FILES, files.toString()); } /** * Sets the string that defines the Ant home set by the user. May be set to <code>null</code>. * * @param antHome * the fully qualified path to Ant home */ public void setAntHome(String antHome) { this.antHome = antHome; } /** * Returns the string that defines the Ant home set by the user or the location of the Eclipse Ant plug-in if Ant home has not been specifically * set by the user. Can return <code>null</code> * * @return the fully qualified path to Ant home */ public String getAntHome() { return antHome; } /** * Returns the set of classpath entries that compose the libraries added to the Ant runtime classpath from the Ant home location. * * @return the set of ant home classpath entries * @since 3.0 */ public IAntClasspathEntry[] getAntHomeClasspathEntries() { return antHomeEntries; } /** * Returns the set of classpath entries that the user has added to the Ant runtime classpath. * * @return the set of user classpath entries * @since 3.0 */ public IAntClasspathEntry[] getAdditionalClasspathEntries() { return additionalEntries; } /** * Sets the set of classpath entries that compose the libraries added to the Ant runtime classpath from the Ant home location. * * @param entries * the set of ant home classpath entries * @since 3.0 */ public void setAntHomeClasspathEntries(IAntClasspathEntry[] entries) { antHomeEntries = entries; } /** * Sets the set of classpath entries that the user has added to the Ant runtime classpath. * * @param entries * the set of user classpath entries * @since 3.0 */ public void setAdditionalClasspathEntries(IAntClasspathEntry[] entries) { additionalEntries = entries; } /** * Returns the list of URLs to added to the classpath for an Ant build that is occurring without the Eclipse runtime. * * @return the list of classpath entries * @since 3.0 */ public URL[] getRemoteAntURLs() { List<URL> result = new ArrayList<>(40); if (antHomeEntries != null) { for (int i = 0; i < antHomeEntries.length; i++) { IAntClasspathEntry entry = antHomeEntries[i]; result.add(entry.getEntryURL()); } } if (additionalEntries != null && additionalEntries.length > 0) { for (int i = 0; i < additionalEntries.length; i++) { IAntClasspathEntry entry = additionalEntries[i]; result.add(entry.getEntryURL()); } } if (extraClasspathURLs != null) { for (int i = 0; i < extraClasspathURLs.size(); i++) { IAntClasspathEntry entry = extraClasspathURLs.get(i); if (!entry.isEclipseRuntimeRequired()) { result.add(entry.getEntryURL()); } } } return result.toArray(new URL[result.size()]); } /** * Returns all contributed classpath entries via the <code>extraClasspathEntries</code> extension point. * * @return all contributed classpath entries via the <code>extraClasspathEntries</code> extension point * @since 3.0 */ public IAntClasspathEntry[] getContributedClasspathEntries() { return extraClasspathURLs.toArray(new IAntClasspathEntry[extraClasspathURLs.size()]); } }