View Javadoc

1   /*
2    * Created on 10.12.2004 by Juergen Mayrbaeurl
3    *
4    */
5   package org.apache.commons.jelly.eclipse.ui;
6   
7   import java.io.File;
8   import java.io.IOException;
9   import java.net.URL;
10  import java.util.ArrayList;
11  import java.util.Iterator;
12  import java.util.List;
13  import java.util.Vector;
14  import java.util.jar.JarFile;
15  
16  import org.eclipse.core.resources.IFile;
17  import org.eclipse.core.resources.IProject;
18  import org.eclipse.core.runtime.CoreException;
19  import org.eclipse.core.runtime.IPath;
20  import org.eclipse.core.runtime.Path;
21  import org.eclipse.core.runtime.Platform;
22  import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
23  import org.eclipse.jdt.core.IJavaProject;
24  import org.eclipse.jdt.core.JavaCore;
25  import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
26  import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
27  import org.eclipse.jdt.launching.JavaRuntime;
28  import org.osgi.framework.Bundle;
29  
30  /***
31   * Utility class with static methods for launch support of Jelly
32   * @author Juergen Mayrbaeurl
33   * @since 0.9
34   */
35  public class JellyLaunchUtils 
36  {
37  	/***
38  	 * Tries to find the libary folder of the base Jelly Plugin (org.apache.jelly)
39  	 * and returns the absolute path to the library
40  	 * @return the absolute path to the library directory of the base Jelly Plugin, can be null if not found
41  	 */
42  	static public String getJellyPlugInLibDir()
43  	{
44  		String result = null;
45  		
46  		// Get the plugin
47  		Bundle baseBundle = Platform.getBundle(
48  				JellyLauncherPlugin.getResourceString("jelly.basePlugInName"));
49  		
50  		// If the base Jelly PlugIn is installed, continue
51  		if( baseBundle != null)
52  		{
53  			// Get the URL of the library directory of the base Jelly PlugIn
54  			URL libURL = baseBundle.getEntry(JellyLauncherPlugin.
55  									getResourceString("jelly.basePlugInLibPath"));
56  			if(libURL != null)
57  			{
58  				String libDirFilename = null;
59  				try {
60  					libDirFilename = Platform.resolve(libURL).getFile();
61  				} catch (IOException e) {
62  					e.printStackTrace();
63  					return null;
64  				}
65  				
66  				// Finally check, if the found path is a directory
67  				if(libDirFilename != null)
68  				{
69  					File libDir = new File(libDirFilename);
70  					if( (libDir != null) && libDir.isDirectory())
71  					{
72  						result = libDirFilename;
73  					}
74  				}
75  			}
76  		}
77  
78  		return result;
79  	}
80  	
81  	/***
82  	 * Tries to find the Jelly jar library in the library directory of the base
83  	 * Jelly PlugIn and returns the absolute path to the jar library file
84  	 * @return absolute path to the jar file, that contains the main class of Jelly (may be null)
85  	 */
86  	static public String getJellyPlugInLibMainClassJar()
87  	{
88  		String result = null;
89  		
90  		// First get the libary directory of the base Jelly PlugIn
91  		String libDirFilename = JellyLaunchUtils.getJellyPlugInLibDir();
92  		if(libDirFilename != null)
93  		{
94  			File libdir = new File(libDirFilename);
95  			File[] jellyLibs = libdir.listFiles();
96  			if(jellyLibs != null)
97  			{
98  				// Iterate over the entries in the library directory
99  				for(int i = 0; i < jellyLibs.length; i++)
100 				{
101 					// Only files, no directories and deep searches
102 					if(jellyLibs[i].isFile() && jellyLibs[i].getName().endsWith(".jar"))
103 					{
104 						JarFile aJar = null;
105 						
106 						try {
107 							aJar = new JarFile(jellyLibs[i]);
108 						} catch (IOException e) {
109 							e.printStackTrace();
110 							// No jar file or no access, just skip it
111 							continue;
112 						}
113 						
114 						// if the jar library contains the 'Jelly' class, we're done
115 						if( (aJar != null) && 
116 								(aJar.getJarEntry("org/apache/commons/jelly/Jelly.class")!= null))
117 						{
118 							result = jellyLibs[i].getAbsolutePath();
119 							break;
120 						}
121 					}
122 				}
123 			}
124 		}
125 		
126 		return result;
127 	}
128 	
129 	/***
130 	 * Returns the list of jar libraries, currently installed in the library directory
131 	 * of the base Jelly PlugIn
132 	 * @return the list of Jelly libraries (all tag libraries and the jelly main library)
133 	 */
134 	static public List getJellyPlugInLibs()
135 	{
136 		Vector resultVector = new Vector();
137 		
138 		String libDirFilename = getJellyPlugInLibDir();
139 		if(libDirFilename != null)
140 		{
141 			File libdir = new File(libDirFilename);
142 			File[] jellyLibs = libdir.listFiles();
143 			if(jellyLibs != null)
144 			{
145 				for(int i = 0; i < jellyLibs.length; i++)
146 				{
147 					if(jellyLibs[i].isFile() && jellyLibs[i].getName().endsWith(".jar"))
148 					{
149 						JarFile aJar = null;
150 						
151 						try {
152 							aJar = new JarFile(jellyLibs[i]);
153 						} catch (IOException e) {
154 							// Simple skip in the case of an exception
155 							continue;
156 						}
157 						
158 						if(aJar != null)
159 							resultVector.add(jellyLibs[i].getAbsolutePath());
160 					}
161 				}
162 			}
163 		}
164 		
165 		return resultVector;
166 	}
167 	
168 	/***
169 	 * Sets the defaults of the launch configuration by initalizing the classpath 
170 	 * (including jar libraries of the base Jelly plugin) and setting the working
171 	 * directory to the <code>scriptFile</code> eclipse project
172 	 * @param config the working copy of the launch configuration, must not be null
173 	 * @param scriptFile the Jelly script file, may be null
174 	 */
175 	public static void setDefaults(ILaunchConfigurationWorkingCopy config, 
176 				IFile scriptFile) throws CoreException
177 	{
178 //		 Don't do anything, if have no launch configuration object
179 		if(config == null)
180 			return;
181 		
182 		// Initialize the classpath
183 		JellyLaunchUtils.initializeClasspath(config, scriptFile);
184 		
185 		// Get the jar library file of the main class
186 		JellyLaunchUtils.initializeJellyInstallpath(config, scriptFile);
187 		
188 		// Initialize the working directory
189 		JellyLaunchUtils.initializeWorkingDir(config, scriptFile);
190 	}
191 	
192 
193 	/***
194 	 * Initializes the runtime classpath by adding all jar libraries of the library
195 	 * directory of the base Jelly PlugIn, the default JRE, the working directory and
196 	 * the class path entries of the project of the <code>scriptFile</code> (if not null)
197 	 * @param config working copy of the launch configuration
198 	 * @param scriptFile Jelly script file as member of a project
199 	 * @throws CoreException if no Java Runtime can't be found
200 	 */
201 	public static void initializeClasspath(ILaunchConfigurationWorkingCopy config, 
202 											IFile scriptFile) throws CoreException
203 	{
204 		// Don't do anything, if have no launch configuration object
205 		if(config == null)
206 			return; 
207 		
208 		// First get the list of libraries of the base Jelly PlugIn libary directory
209 		List libs = JellyLaunchUtils.getJellyPlugInLibs();
210 		if( (libs != null) && (libs.size() > 0))
211 		{
212 			List classpath = new ArrayList();
213 			Iterator iter = libs.iterator();
214 			
215 			// Add the base JellyPlugIn libraries to the classpath as user classes
216 			while(iter.hasNext())
217 			{
218 				IRuntimeClasspathEntry libEntry = 
219 					JavaRuntime.newArchiveRuntimeClasspathEntry(new Path((String)iter.next()));
220 				libEntry.setClasspathProperty(IRuntimeClasspathEntry.USER_CLASSES);
221 				try {
222 					classpath.add(libEntry.getMemento());
223 				} catch (CoreException e) {
224 					// If the runtime classpath entry can't be added, just skip it
225 					continue;
226 				}
227 			}
228 			
229 			// Next add the JRE libraries to the classpath
230 			IRuntimeClasspathEntry stdLibs = JavaRuntime.newRuntimeContainerClasspathEntry(
231 												new Path(JavaRuntime.JRE_CONTAINER),
232 												IRuntimeClasspathEntry.STANDARD_CLASSES);
233 			classpath.add(stdLibs.getMemento());
234 						
235 			// If we're doing this for a Jelly script file (as member of a project),
236 			// add the class path entries of the owning project
237 			if(JellyLauncherPlugin.getDefault().isDoAddProjectClassPathEntries())
238 			{
239 				if(scriptFile != null)
240 					addUserClassPathOfProject(scriptFile.getProject(), classpath);
241 				else
242 					addUserClassPathOfProject(null, classpath);
243 			}
244 			
245 			// Set the attributes in the launch configuration
246 			config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH, classpath);
247 			config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH, false);
248 		}
249 	}
250 	
251 	/***
252 	 * Initializes the attribute in the launch configuration, that stores the absolute
253 	 * path to the Jelly runtime jar library
254 	 * @param config working copy of the launch configuration
255 	 * @param scriptFile Jelly script file (as project member)
256 	 */
257 	protected static void initializeJellyInstallpath(ILaunchConfigurationWorkingCopy config
258 														, IFile scriptFile)
259 	{
260 		// Don't do anything, if have no launch configuration object
261 		if(config != null)
262 		{
263 			String mainJar = JellyLaunchUtils.getJellyPlugInLibMainClassJar();
264 			if(mainJar != null)
265 				config.setAttribute(JellyLaunchConfigurationConstants.ATTR_JELLYINSTALL_PATH, mainJar);		
266 			else
267 				config.setAttribute(JellyLaunchConfigurationConstants.ATTR_JELLYINSTALL_PATH, "");		
268 		}
269 	}
270 
271 	/***
272 	 * Initalizes the working directory setup in the launch configuration, by setting
273 	 * the working directory to the project's working directory the <code>scriptFile</code>
274 	 * belongs to
275 	 * @param config working copy of the launch configuration
276 	 * @param scriptFile Jelly script file (as project member)
277 	 */
278 	public static void initializeWorkingDir(ILaunchConfigurationWorkingCopy config
279 			, IFile scriptFile)
280 	{
281 		// Don't do anything, if have no launch configuration object or script File
282 		if( (scriptFile == null) || (config == null) )
283 			return;
284 		
285 		// if the scriptFile doesn't belong to a project, don't continue
286 		IProject scriptsProject = scriptFile.getProject();
287 		if(scriptsProject == null)
288 			return;
289 		
290 		// Set the working directory in the launch configuration attribute
291 		String workDirPath = scriptsProject.getLocation().toString();
292 		if(workDirPath != null)
293 			config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
294 										workDirPath);
295 	}
296 	
297 	/***
298 	 * Returns the full path of the project, the <code>aFile</code> is owned
299 	 * @param aFile a file owned by a project
300 	 * @return the <code>IPath</code> object of the project (can be null)
301 	 */
302 	public static IPath getFilesProjectPath(IFile aFile)
303 	{
304 		if(aFile == null)
305 			return null;
306 		
307 		IProject theProj = aFile.getProject();
308 		if(theProj != null)
309 			return theProj.getFullPath();
310 		else
311 			return null;
312 	}
313 	
314 	/***
315 	 * Adds the user class path entries of a Java project or the working directory
316 	 * of a non Java project to the list of class path entries, stored in <code> classPathEntryList</code>
317 	 * @param theProject the project
318 	 * @param classPathEntryList the list of class path entries
319 	 */
320 	public static void addUserClassPathOfProject(IProject theProject, 
321 														List classPathEntryList)
322 	{
323 		// If we don't have a collection for the class path entries or a project,
324 		// don't do anything
325 		if( (classPathEntryList == null) || (theProject == null) )
326 			return;
327 		
328 		// Check, if the 'theProject' is a Java project
329 		IJavaProject javaProject = JavaCore.create(theProject);
330 		if(javaProject == null)
331 		{
332 			// It's not a Java project. Simply add the working directory of the project
333 			IPath workDirPath = theProject.getFullPath();
334 			if(workDirPath != null)
335 			{
336 				IRuntimeClasspathEntry stdLibs = JavaRuntime.newArchiveRuntimeClasspathEntry(workDirPath);
337 				try {
338 					classPathEntryList.add(stdLibs.getMemento());
339 				} catch (CoreException e) {
340 					// However, we can't add the working directory of the owning project
341 				}
342 			}
343 		} else {
344 			// It's a Java project. Add all runtime class path entries of the Java project
345 			try {
346 				IRuntimeClasspathEntry[] entries = JavaRuntime.computeUnresolvedRuntimeClasspath(javaProject);
347 				if( (entries != null) && (entries.length > 0))
348 				{
349 					for(int i = 0; i < entries.length; i++)
350 					{
351 						// Only add the user class path entries of the Java project
352 						if(entries[i].getClasspathProperty() == 
353 									IRuntimeClasspathEntry.USER_CLASSES)
354 						{
355 							try {
356 								IRuntimeClasspathEntry[] resolvedEntries = JavaRuntime.resolveRuntimeClasspathEntry(entries[i], javaProject);
357 								if(resolvedEntries != null)
358 								{
359 									for(int j = 0; j < resolvedEntries.length; j++)
360 									{
361 										classPathEntryList.add(resolvedEntries[j].getMemento());
362 									}
363 								}
364 							} catch (CoreException e1) {
365 								continue;
366 							}
367 						}
368 					}
369 				}
370 			} catch (CoreException e) {
371 				// However
372 			}
373 		}
374 	}
375 }