1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 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  *******************************************************************************/
14 package org.eclipse.team.internal.core;
15 
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.OutputStream;
19 import java.util.ArrayList;
20 import java.util.Hashtable;
21 import java.util.List;
22 import java.util.StringTokenizer;
23 
24 import org.eclipse.core.resources.IStorage;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IConfigurationElement;
27 import org.eclipse.core.runtime.IExtension;
28 import org.eclipse.core.runtime.IExtensionPoint;
29 import org.eclipse.core.runtime.IPath;
30 import org.eclipse.core.runtime.IProgressMonitor;
31 import org.eclipse.core.runtime.IStatus;
32 import org.eclipse.core.runtime.Path;
33 import org.eclipse.core.runtime.Platform;
34 import org.eclipse.core.runtime.Plugin;
35 import org.eclipse.core.runtime.QualifiedName;
36 import org.eclipse.core.runtime.Status;
37 import org.eclipse.core.runtime.content.IContentDescription;
38 import org.eclipse.core.runtime.content.IContentTypeManager;
39 import org.eclipse.osgi.service.debug.DebugOptions;
40 import org.eclipse.osgi.service.debug.DebugOptionsListener;
41 import org.eclipse.team.core.RepositoryProvider;
42 import org.eclipse.team.core.RepositoryProviderType;
43 import org.eclipse.team.core.Team;
44 import org.eclipse.team.core.TeamException;
45 import org.eclipse.team.core.mapping.DelegatingStorageMerger;
46 import org.eclipse.team.internal.core.mapping.IStreamMergerDelegate;
47 import org.osgi.framework.BundleContext;
48 import org.osgi.framework.ServiceRegistration;
49 
50 /**
51  * <code>TeamPlugin</code> is the plug-in runtime class for the Team
52  * resource management plugin.
53  * <p>
54  *
55  * @see Team
56  * @see RepositoryProvider
57  *
58  * @since 2.0
59  */
60 final public class TeamPlugin extends Plugin {
61 
62 	// The id of the core team plug-in
63 	public static final String ID = "org.eclipse.team.core"; //$NON-NLS-1$
64 
65 	// The id of the providers extension point
66 	public static final String PROVIDER_EXTENSION = "repository-provider-type"; //$NON-NLS-1$
67 
68 	// The id of the file types extension point
69 	public static final String FILE_TYPES_EXTENSION = "fileTypes"; //$NON-NLS-1$
70 
71 	// The id of the global ignore extension point
72 	public static final String IGNORE_EXTENSION = "ignore"; //$NON-NLS-1$
73 	// The id of the project set extension point
74 	public static final String PROJECT_SET_EXTENSION = "projectSets"; //$NON-NLS-1$
75 	// The id of the repository extension point
76 	public static final String REPOSITORY_EXTENSION = "repository"; //$NON-NLS-1$
77 	// The id of the default file modification validator extension point
78 	public static final String DEFAULT_FILE_MODIFICATION_VALIDATOR_EXTENSION = "defaultFileModificationValidator"; //$NON-NLS-1$
79 
80 	// The id used to associate a provider with a project
81 	public final static QualifiedName PROVIDER_PROP_KEY =
82 		new QualifiedName("org.eclipse.team.core", "repository");  //$NON-NLS-1$  //$NON-NLS-2$
83 
84 	// The id for the Bundle Import extension point
85 	public static final String EXTENSION_POINT_BUNDLE_IMPORTERS = ID + ".bundleImporters"; //$NON-NLS-1$
86 
87 	// The one and only plug-in instance
88 	private static TeamPlugin plugin;
89 
90 	private ServiceRegistration debugRegistration;
91 	private IStreamMergerDelegate mergerDelegate;
92 
93 	/**
94 	 * Constructs a plug-in runtime class.
95 	 */
TeamPlugin()96 	public TeamPlugin() {
97 		super();
98 		plugin = this;
99 	}
100 
101 	@Override
start(BundleContext context)102 	public void start(BundleContext context) throws Exception {
103 		super.start(context);
104 
105 		// register debug options listener
106 		Hashtable<String, String> properties = new Hashtable<>(2);
107 		properties.put(DebugOptions.LISTENER_SYMBOLICNAME, ID);
108 		debugRegistration = context.registerService(DebugOptionsListener.class, Policy.DEBUG_OPTIONS_LISTENER, properties);
109 
110 		Team.startup();
111 	}
112 
113 	@Override
stop(BundleContext context)114 	public void stop(BundleContext context) throws Exception {
115 		try {
116 			// unregister debug options listener
117 			debugRegistration.unregister();
118 			debugRegistration = null;
119 
120 			Team.shutdown();
121 			ResourceVariantCache.shutdown();
122 		} finally {
123 			super.stop(context);
124 		}
125 	}
126 
127 	/**
128 	 * Returns the Team plug-in.
129 	 *
130 	 * @return the single instance of this plug-in runtime class
131 	 */
getPlugin()132 	public static TeamPlugin getPlugin() {
133 		return plugin;
134 	}
135 
136 	/**
137 	 * Log the given exception allowing with the provided message and severity indicator
138 	 * @param severity the severity
139 	 * @param message the message
140 	 * @param e the exception
141 	 */
log(int severity, String message, Throwable e)142 	public static void log(int severity, String message, Throwable e) {
143 		plugin.getLog().log(new Status(severity, ID, 0, message, e));
144 	}
145 
146 	/**
147 	 * Log the given CoreException in a manner that will include the stacktrace of
148 	 * the exception in the log.
149 	 * @param e the exception
150 	 */
log(CoreException e)151 	public static void log(CoreException e) {
152 		log(e.getStatus().getSeverity(), e.getMessage(), e);
153 	}
154 
155 	/*
156 	 * Static helper methods for creating exceptions
157 	 */
wrapException(CoreException e)158 	public static TeamException wrapException(CoreException e) {
159 		IStatus status = e.getStatus();
160 		return new TeamException(new Status(status.getSeverity(), ID, status.getCode(), status.getMessage(), e));
161 	}
162 
getCharset(String name, InputStream stream)163 	public static String getCharset(String name, InputStream stream) throws IOException {
164 		IContentDescription description = getContentDescription(name, stream);
165 		return description == null ? null : description.getCharset();
166 
167 	}
getContentDescription(String name, InputStream stream)168 	public static IContentDescription getContentDescription(String name, InputStream stream) throws IOException  {
169 		// tries to obtain a description for this file contents
170 		IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
171 		try {
172 			return contentTypeManager.getDescriptionFor(stream, name, IContentDescription.ALL);
173 		} finally {
174 			if (stream != null)
175 				try {
176 					stream.close();
177 				} catch (IOException e) {
178 					// Ignore exceptions on close
179 				}
180 		}
181 	}
182 
getAliasType(String id)183 	public static RepositoryProviderType getAliasType(String id) {
184 		IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(TeamPlugin.ID, TeamPlugin.REPOSITORY_EXTENSION);
185 		if (extension != null) {
186 			IExtension[] extensions =  extension.getExtensions();
187 			for (IExtension ext : extensions) {
188 				IConfigurationElement[] configElements = ext.getConfigurationElements();
189 				for (IConfigurationElement configElement : configElements) {
190 					String aliasId = configElement.getAttribute("canImportId"); //$NON-NLS-1$
191 					if (aliasId != null && aliasId.equals(id)) {
192 						String extensionId = configElement.getAttribute("id"); //$NON-NLS-1$
193 						if (extensionId != null) {
194 							return RepositoryProviderType.getProviderType(extensionId);
195 						}
196 					}
197 				}
198 			}
199 		}
200 		return null;
201 	}
202 
getMetaFilePaths(String id)203 	public static IPath[] getMetaFilePaths(String id) {
204 		IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(TeamPlugin.ID, TeamPlugin.REPOSITORY_EXTENSION);
205 		if (extension != null) {
206 			IExtension[] extensions =  extension.getExtensions();
207 			for (IExtension ext : extensions) {
208 				IConfigurationElement[] configElements = ext.getConfigurationElements();
209 				for (IConfigurationElement configElement : configElements) {
210 					String extensionId = configElement.getAttribute("id"); //$NON-NLS-1$
211 					String metaFilePaths = configElement.getAttribute("metaFilePaths"); //$NON-NLS-1$
212 					if (extensionId != null && extensionId.equals(id) && metaFilePaths != null) {
213 						return getPaths(metaFilePaths);
214 
215 					}
216 				}
217 			}
218 		}
219 		return null;
220 	}
221 
getPaths(String metaFilePaths)222 	private static IPath[] getPaths(String metaFilePaths) {
223 		List<IPath> result = new ArrayList<>();
224 		StringTokenizer t = new StringTokenizer(metaFilePaths, ","); //$NON-NLS-1$
225 		while (t.hasMoreTokens()) {
226 			String next = t.nextToken();
227 			IPath path = new Path(null, next);
228 			result.add(path);
229 		}
230 		return result.toArray(new IPath[result.size()]);
231 	}
232 
233 	/**
234 	 * Set the file merger that is used by the {@link DelegatingStorageMerger#merge(OutputStream, String, IStorage, IStorage, IStorage, IProgressMonitor)}
235 	 * method. It is the responsibility of subclasses to provide a merger.
236 	 * If a merger is not provided, subclasses must override <code>performThreeWayMerge</code>.
237 	 * @param merger the merger used to merge files
238 	 */
setMergerDelegate(IStreamMergerDelegate merger)239 	public void setMergerDelegate(IStreamMergerDelegate merger) {
240 		mergerDelegate = merger;
241 	}
242 
getMergerDelegate()243 	public IStreamMergerDelegate getMergerDelegate() {
244 		return mergerDelegate;
245 	}
246 
247 }
248