1 /*******************************************************************************
2  * Copyright (c) 2006, 2019 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  *     Christian Dietrich (itemis AG) - fix for bug #549409
14  *     Alexander Fedorov <alexander.fedorov@arsysop.ru> - Bug 549409
15  ******************************************************************************/
16 
17 package org.eclipse.ui.internal.ide.filesystem;
18 
19 import java.io.File;
20 import java.net.URI;
21 import java.util.Collection;
22 import java.util.HashSet;
23 import java.util.stream.Stream;
24 
25 import org.eclipse.core.filesystem.IFileInfo;
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.core.runtime.IConfigurationElement;
28 import org.eclipse.core.runtime.IExtension;
29 import org.eclipse.core.runtime.IExtensionPoint;
30 import org.eclipse.core.runtime.ISafeRunnable;
31 import org.eclipse.core.runtime.Platform;
32 import org.eclipse.core.runtime.SafeRunner;
33 import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
34 import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
35 import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
36 import org.eclipse.swt.SWT;
37 import org.eclipse.swt.widgets.DirectoryDialog;
38 import org.eclipse.swt.widgets.Shell;
39 import org.eclipse.ui.PlatformUI;
40 import org.eclipse.ui.ide.fileSystem.FileSystemContributor;
41 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
42 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
43 import org.eclipse.ui.internal.ide.dialogs.IDEResourceInfoUtils;
44 
45 /**
46  * @since 3.2
47  *
48  */
49 public class FileSystemSupportRegistry implements IExtensionChangeHandler {
50 
51 	private static final String FILESYSTEM_SUPPORT = "filesystemSupport";//$NON-NLS-1$
52 
53 	protected static final String ATT_CLASS = "class"; //$NON-NLS-1$
54 
55 	private static final String LABEL = "label";//$NON-NLS-1$
56 
57 	private static final String SCHEME = "scheme";//$NON-NLS-1$
58 
59 	private static FileSystemSupportRegistry singleton;
60 
61 	/**
62 	 * Get the instance of the registry.
63 	 *
64 	 * @return MarkerSupportRegistry
65 	 */
getInstance()66 	public static FileSystemSupportRegistry getInstance() {
67 		if (singleton == null) {
68 			singleton = new FileSystemSupportRegistry();
69 		}
70 		return singleton;
71 	}
72 
73 	private Collection<FileSystemConfiguration> registeredContributions = new HashSet<>(0);
74 
75 	FileSystemConfiguration defaultConfiguration = new FileSystemConfiguration(
76 			FileSystemMessages.DefaultFileSystem_name, new FileSystemContributor() {
77 				@Override
78 				public URI browseFileSystem(String initialPath, Shell shell) {
79 
80 					DirectoryDialog dialog = new DirectoryDialog(shell, SWT.SHEET);
81 					dialog
82 							.setMessage(IDEWorkbenchMessages.ProjectLocationSelectionDialog_directoryLabel);
83 
84 					if (!initialPath.equals(IDEResourceInfoUtils.EMPTY_STRING)) {
85 						IFileInfo info = IDEResourceInfoUtils
86 								.getFileInfo(initialPath);
87 						if (info != null && info.exists()) {
88 							dialog.setFilterPath(initialPath);
89 						}
90 					}
91 
92 					String selectedDirectory = dialog.open();
93 					if (selectedDirectory == null) {
94 						return null;
95 					}
96 					return new File(selectedDirectory).toURI();
97 
98 				}
99 			}, null);
100 
101 	/**
102 	 * Create a new instance of the receiver.
103 	 */
FileSystemSupportRegistry()104 	public FileSystemSupportRegistry() {
105 		IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
106 		IExtensionPoint point = Platform.getExtensionRegistry()
107 				.getExtensionPoint(IDEWorkbenchPlugin.IDE_WORKBENCH,
108 						FILESYSTEM_SUPPORT);
109 		if (point == null) {
110 			return;
111 		}
112 		// initial population
113 		for (IExtension extension : point.getExtensions()) {
114 			processExtension(tracker, extension);
115 		}
116 		tracker.registerHandler(this, ExtensionTracker.createExtensionPointFilter(point));
117 	}
118 
119 	@Override
addExtension(IExtensionTracker tracker, IExtension extension)120 	public void addExtension(IExtensionTracker tracker, IExtension extension) {
121 		processExtension(tracker, extension);
122 	}
123 
124 	@Override
removeExtension(IExtension extension, Object[] objects)125 	public void removeExtension(IExtension extension, Object[] objects) {
126 		for (Object object : objects) {
127 			registeredContributions.remove(object);
128 		}
129 	}
130 
131 	/**
132 	 * Process the extension and register the result with the tracker.
133 	 *
134 	 * @param tracker
135 	 * @param extension
136 	 */
processExtension(IExtensionTracker tracker, IExtension extension)137 	private void processExtension(IExtensionTracker tracker, IExtension extension) {
138 		for (IConfigurationElement configElement : extension.getConfigurationElements()) {
139 			FileSystemConfiguration contribution = newConfiguration(configElement);
140 			if (contribution != null) {
141 				registeredContributions.add(contribution);
142 				tracker.registerObject(extension, contribution, IExtensionTracker.REF_STRONG);
143 			}
144 		}
145 	}
146 
147 	/**
148 	 * Return a new FileSystemContribution.
149 	 *
150 	 * @param element
151 	 * @return FileSystemContribution or <code>null</code> if there is an
152 	 *         exception.
153 	 */
newConfiguration( final IConfigurationElement element)154 	private FileSystemConfiguration newConfiguration(
155 			final IConfigurationElement element) {
156 
157 		final FileSystemContributor[] contributors = new FileSystemContributor[1];
158 		final CoreException[] exceptions = new CoreException[1];
159 
160 		SafeRunner.run(new ISafeRunnable() {
161 			@Override
162 			public void run() {
163 				try {
164 					contributors[0] = (FileSystemContributor) IDEWorkbenchPlugin
165 							.createExtension(element, ATT_CLASS);
166 
167 				} catch (CoreException exception) {
168 					exceptions[0] = exception;
169 					IDEWorkbenchPlugin.getDefault().getLog().log(exception.getStatus());
170 				}
171 			}
172 
173 			@Override
174 			public void handleException(Throwable e) {
175 				IDEWorkbenchPlugin.log(FileSystemMessages.FileSystemSupportRegistry_e_creating_extension, e);
176 			}
177 		});
178 
179 		if (exceptions[0] != null) {
180 			return null;
181 		}
182 		String name = element.getAttribute(LABEL);
183 		String fileSystem = element.getAttribute(SCHEME);
184 		return new FileSystemConfiguration(name,
185 				contributors[0], fileSystem);
186 
187 	}
188 
189 	/**
190 	 * Return the FileSystemConfiguration defined in the receiver.
191 	 *
192 	 * @return FileSystemConfiguration[]
193 	 */
getConfigurations()194 	public FileSystemConfiguration[] getConfigurations() {
195 		return Stream.concat(Stream.of(defaultConfiguration), registeredContributions.stream())
196 				.toArray(FileSystemConfiguration[]::new);
197 	}
198 
199 	/**
200 	 * Return the default file system configuration (the local file system
201 	 * extension in the ide plug-in).
202 	 *
203 	 * @return FileSystemConfiguration
204 	 */
getDefaultConfiguration()205 	public FileSystemConfiguration getDefaultConfiguration() {
206 		return defaultConfiguration;
207 	}
208 
209 	/**
210 	 * Return whether or not there is only one file system registered.
211 	 *
212 	 * @return <code>true</code> if there is only one file system.
213 	 */
hasOneFileSystem()214 	public boolean hasOneFileSystem() {
215 		return registeredContributions.isEmpty();
216 	}
217 }
218