1 /*******************************************************************************
2  * Copyright (c) 2010, 2013 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.pde.internal.core.project;
15 
16 import org.eclipse.core.resources.IContainer;
17 import org.eclipse.core.resources.IFile;
18 import org.eclipse.core.resources.IFolder;
19 import org.eclipse.core.resources.IProject;
20 import org.eclipse.core.resources.ProjectScope;
21 import org.eclipse.core.runtime.CoreException;
22 import org.eclipse.core.runtime.IPath;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.Path;
25 import org.eclipse.core.runtime.Status;
26 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
27 import org.eclipse.pde.core.plugin.IPluginModelBase;
28 import org.eclipse.pde.core.plugin.PluginRegistry;
29 import org.eclipse.pde.internal.core.ICoreConstants;
30 import org.eclipse.pde.internal.core.PDECore;
31 import org.eclipse.pde.internal.core.PDEManager;
32 import org.osgi.service.prefs.BackingStoreException;
33 
34 /**
35  * Utility class to resolve plug-in and bundle files relative to a project
36  * specific bundle root location.
37  *
38  * @since 3.6
39  */
40 public class PDEProject {
41 
42 	/**
43 	 * Preference key for the project relative bundle root path
44 	 */
45 	public static final String BUNDLE_ROOT_PATH = "BUNDLE_ROOT_PATH"; //$NON-NLS-1$
46 
47 	/**
48 	 * Returns the container in the specified project that corresponds to the
49 	 * root of bundle related artifacts. May return the project itself
50 	 * or a folder within the project.
51 	 *
52 	 * @param project project
53 	 * @return container corresponding to the bundle root
54 	 */
getBundleRoot(IProject project)55 	public static IContainer getBundleRoot(IProject project) {
56 		ProjectScope scope = new ProjectScope(project);
57 		IEclipsePreferences node = scope.getNode(PDECore.PLUGIN_ID);
58 		if (node != null) {
59 			String string = node.get(BUNDLE_ROOT_PATH, null);
60 			if (string != null) {
61 				IPath path = Path.fromPortableString(string);
62 				return project.getFolder(path);
63 			}
64 		}
65 		return project;
66 	}
67 
68 	/**
69 	 * Returns the launch shortcuts configured for this project
70 	 * or <code>null</code> if default launchers should be used.
71 	 *
72 	 * @param project project
73 	 * @return configured launch shortcuts or <code>null</code>
74 	 */
getLaunchShortcuts(IProject project)75 	public static String[] getLaunchShortcuts(IProject project) {
76 		ProjectScope scope = new ProjectScope(project);
77 		IEclipsePreferences node = scope.getNode(PDECore.PLUGIN_ID);
78 		if (node != null) {
79 			String list = node.get(ICoreConstants.MANIFEST_LAUNCH_SHORTCUTS, (String) null);
80 			if (list != null) {
81 				return list.split(","); //$NON-NLS-1$
82 			}
83 		}
84 		return null;
85 	}
86 
87 	/**
88 	 * Returns the export wizard configured for this project or <code>null</code>
89 	 * if default.
90 	 *
91 	 * @param project project
92 	 * @return export wizard identifier or <code>null</code>
93 	 */
getExportWizard(IProject project)94 	public static String getExportWizard(IProject project) {
95 		ProjectScope scope = new ProjectScope(project);
96 		IEclipsePreferences node = scope.getNode(PDECore.PLUGIN_ID);
97 		if (node != null) {
98 			return node.get(ICoreConstants.MANIFEST_EXPORT_WIZARD, (String) null);
99 		}
100 		return null;
101 	}
102 
103 	/**
104 	 * Sets the root of the bundle related artifacts in the specified project
105 	 * to the specified container. When <code>null</code> is specified, the
106 	 * bundle root will be the project itself. The container must be within
107 	 * the specified project.
108 	 *
109 	 * @param project project
110 	 * @param root project relative bundle root path, or <code>null</code> (or an empty path)
111 	 *  to indicate the root of the bundle is the root of the project
112 	 * @exception CoreException if unable to set the bundle root to the specified container
113 	 */
setBundleRoot(IProject project, IContainer root)114 	public static void setBundleRoot(IProject project, IContainer root) throws CoreException {
115 		if (root != null && !root.getProject().equals(project)) {
116 			throw new IllegalArgumentException("root must be contained in the given project"); //$NON-NLS-1$
117 		}
118 		ProjectScope scope = new ProjectScope(project);
119 		IEclipsePreferences node = scope.getNode(PDECore.PLUGIN_ID);
120 		if (node != null) {
121 			IPath path = null;
122 			if (root != null) {
123 				path = root.getProjectRelativePath();
124 			}
125 			if (path != null && path.isEmpty()) {
126 				path = null;
127 			}
128 			String value = null;
129 			if (path != null) {
130 				value = path.toPortableString();
131 			}
132 			if (value == null) {
133 				node.remove(BUNDLE_ROOT_PATH);
134 			} else {
135 				node.put(BUNDLE_ROOT_PATH, value);
136 			}
137 			try {
138 				node.flush();
139 				// update model manager
140 				PDECore.getDefault().getModelManager().bundleRootChanged(project);
141 			} catch (BackingStoreException e) {
142 				throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, e.getMessage(), e));
143 			}
144 		} else {
145 			throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, "Failed to retrieve project scope preference settings")); //$NON-NLS-1$
146 		}
147 	}
148 
149 	/**
150 	 * Returns the resource in the specified project corresponding to its
151 	 * <code>MANIFEST.MF</code> file.
152 	 *
153 	 * @param project project
154 	 * @return <code>MANIFEST.MF</code> file that may or may not exist
155 	 */
getManifest(IProject project)156 	public static IFile getManifest(IProject project) {
157 		return getBundleRelativeFile(project, ICoreConstants.MANIFEST_PATH);
158 	}
159 
160 	/**
161 	 * Returns the resource in the specified project corresponding to its
162 	 * <code>build.properties</code>file.
163 	 *
164 	 * @param project project
165 	 * @return <code>build.properties</code> file that may or may not exist
166 	 */
getBuildProperties(IProject project)167 	public static IFile getBuildProperties(IProject project) {
168 		return getBundleRelativeFile(project, ICoreConstants.BUILD_PROPERTIES_PATH);
169 	}
170 
171 	/**
172 	 * Returns the resource in the specified project corresponding to its
173 	 * <code>plugin.xml</code>file.
174 	 *
175 	 * @param project project
176 	 * @return <code>plugin.xml</code> file that may or may not exist
177 	 */
getPluginXml(IProject project)178 	public static IFile getPluginXml(IProject project) {
179 		return getBundleRelativeFile(project, ICoreConstants.PLUGIN_PATH);
180 	}
181 
182 	/**
183 	 * Returns the resource in the specified project corresponding to its
184 	 * <code>fragment.xml</code>file.
185 	 *
186 	 * @param project project
187 	 * @return <code>fragment.xml</code> file that may or may not exist
188 	 */
getFragmentXml(IProject project)189 	public static IFile getFragmentXml(IProject project) {
190 		return getBundleRelativeFile(project, ICoreConstants.FRAGMENT_PATH);
191 	}
192 
193 	/**
194 	 * Returns the resource in the specified project corresponding to its
195 	 * <code>feature.xml</code>file.
196 	 *
197 	 * @param project project
198 	 * @return <code>feature.xml</code> file that may or may not exist
199 	 */
getFeatureXml(IProject project)200 	public static IFile getFeatureXml(IProject project) {
201 		return getBundleRelativeFile(project, ICoreConstants.FEATURE_PATH);
202 	}
203 
204 	/**
205 	 * Returns the resource in the specified project corresponding to its
206 	 * <code>.options</code>file.
207 	 *
208 	 * @param project project
209 	 * @return <code>.options</code> file that may or may not exist
210 	 */
getOptionsFile(IProject project)211 	public static IFile getOptionsFile(IProject project) {
212 		return getBundleRelativeFile(project, new Path(ICoreConstants.OPTIONS_FILENAME));
213 	}
214 
215 	/**
216 	 * Returns the resource in the specified project corresponding to its
217 	 * <code>OSGI-INF/</code>folder.
218 	 *
219 	 * @param project project
220 	 * @return <code>OSGI-INF/</code> folder that may or may not exist
221 	 */
getOSGiInf(IProject project)222 	public static IFolder getOSGiInf(IProject project) {
223 		return getBundleRelativeFolder(project, ICoreConstants.OSGI_INF_PATH);
224 	}
225 
226 	/**
227 	 * Returns the resource in the specified project corresponding to its
228 	 * <code>META-INF/</code>folder.
229 	 *
230 	 * @param project project
231 	 * @return <code>META-INF/</code> folder that may or may not exist
232 	 */
getMetaInf(IProject project)233 	public static IFolder getMetaInf(IProject project) {
234 		return getBundleRelativeFolder(project, new Path(ICoreConstants.MANIFEST_FOLDER_NAME));
235 	}
236 
237 	/**
238 	 * Returns a file relative to the bundle root of the specified project.
239 	 *
240 	 * @param project project
241 	 * @param path bundle root relative path
242 	 * @return file that may or may not exist
243 	 */
getBundleRelativeFile(IProject project, IPath path)244 	public static IFile getBundleRelativeFile(IProject project, IPath path) {
245 		return getBundleRoot(project).getFile(path);
246 	}
247 
248 	/**
249 	 * Returns a folder relative to the bundle root of the specified project.
250 	 *
251 	 * @param project project
252 	 * @param path bundle root relative path
253 	 * @return folder that may or may not exist
254 	 */
getBundleRelativeFolder(IProject project, IPath path)255 	public static IFolder getBundleRelativeFolder(IProject project, IPath path) {
256 		return getBundleRoot(project).getFolder(path);
257 	}
258 
259 	/**
260 	 * Returns the bundle localization file for the specified bundle project.
261 	 * The file may or may not exist.
262 	 *
263 	 * @param project
264 	 * @return bunlde localization file which may or may not exist
265 	 */
getLocalizationFile(IProject project)266 	public static IFile getLocalizationFile(IProject project) {
267 		IPluginModelBase model = PluginRegistry.findModel(project);
268 		String localization = PDEManager.getBundleLocalization(model);
269 		return getBundleRelativeFile(project, new Path(localization + ".properties")); //$NON-NLS-1$
270 	}
271 
272 	// TODO: schema folder?
273 
274 	// TODO: plugin_customization.ini ?
275 
276 }
277