awesome assets from gffs code
[feisty_meow.git] / kona / src / org / gffs / application / ProgramTools.java
1 package org.gffs.application;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.URISyntaxException;
6 import java.net.URL;
7
8 import org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogFactory;
10 import org.gffs.filesystem.FileSystemHelper;
11
12 /**
13  * Some utility functions for getting information about the running application.
14  * 
15  * @author Chris Koeritz
16  */
17 public class ProgramTools
18 {
19         public static Log _logger = LogFactory.getLog(ProgramTools.class);
20         
21         /**
22          * produces a list of the stack for a certain number of its elements, called stack frames. this will ignore the fact that this function is
23          * invoked, and start counting stack frames from the immediate caller's perspective (including it).
24          */
25         public static String showLastFewOnStack(int howManyFrames)
26         {
27                 StackTraceElement[] elements = Thread.currentThread().getStackTrace();
28                 StringBuilder toReturn = new StringBuilder();
29                 /*
30                  * don't start at the very first frame; we want to skip backwards to the direct caller of this function.
31                  */
32                 int startFrame = 3;
33                 int endFrame = Math.min(howManyFrames + 3, elements.length - 1);
34                 for (int i = startFrame; i < endFrame; i++) {
35                         if (toReturn.length() != 0) {
36                                 toReturn.append("\n<= ");
37                         }
38                         toReturn.append(getStackFrame(i));
39                 }
40                 return toReturn.toString();
41         }
42
43         /**
44          * returns the Nth frame backwards starting from this function. 0 is this method, 1 is the invoker, 2 is the invoker's invoker, etc.
45          */
46         public static String getStackFrame(int which)
47         {
48                 StackTraceElement[] elements = Thread.currentThread().getStackTrace();
49                 /* a little self-protection to avoid accessing missing parts of the array. */
50                 if (which >= elements.length)
51                         which = elements.length - 1;
52                 return elements[which].toString();
53         }
54
55         /**
56          * returns the location where the code is running, as best as can be determined. finds the running location based on our jar files, or if
57          * that's not available, on the assumption of app path being within an appropriate installation (even if not at the top). this method
58          * cannot use standard genesis properties to look up the path, because this function needs to operate before anything else is loaded (for
59          * OSGi usage).
60          */
61         static public String getInstallationDirectory()
62         {
63                 String appPath = null;
64                 // see if we can intuit our location from living in a jar.
65                 URL url = ProgramTools.class.getProtectionDomain().getCodeSource().getLocation();
66                 try {
67                         // get the app path but switch back slashes to forward ones.
68                         appPath = new File(url.toURI().getSchemeSpecificPart()).toString().replace('\\', '/');
69                 } catch (URISyntaxException e) {
70                         String msg = "failed to convert code source url to app path: " + url;
71                         _logger.error(msg);
72                         throw new RuntimeException(msg);
73                 }
74                 if (_logger.isTraceEnabled())
75                         _logger.trace("got source path as: " + appPath);
76                 if (appPath.endsWith(".jar")) {
77                         // we need to chop off the jar file part of the name.
78                         int lastSlash = appPath.lastIndexOf("/");
79                         // if (lastSlash < 0)
80                         // lastSlash = appPath.lastIndexOf("\\");
81                         if (lastSlash < 0) {
82                                 String msg = "could not find a slash character in the path: " + appPath;
83                                 _logger.error(msg);
84                                 throw new RuntimeException(msg);
85                         }
86                         appPath = appPath.substring(0, lastSlash);
87                         if (_logger.isTraceEnabled())
88                                 _logger.trace("truncated path since inside jar: " + appPath);
89                 }
90                 appPath = appPath.concat("/..");
91
92                 if (_logger.isTraceEnabled())
93                         _logger.trace("jar-intuited startup bundle path: " + appPath);
94
95                 File startupDir = new File(appPath);
96                 if (!startupDir.exists() || !startupDir.isDirectory()) {
97                         throw new RuntimeException(
98                                 "the location where we believe the installation is running from does not actually exist as a directory.");
99                 }
100
101                 //hmmm: below may not be very general since it does osgi?  but it will work if people use a bundles dir.
102                 
103                 /*
104                  * make sure we can find our own bundles directory, which is a crucial thing for osgi. if we can't find it, then we really don't know
105                  * where home is.
106                  */
107                 File testingBundlesDir = new File(startupDir, "bundles");
108                 File testingExtDir = new File(startupDir, "ext");
109                 String lastStartupDirState = "not-equal"; // a string we should never see as a full path.
110
111                 while (!testingBundlesDir.exists() || !testingExtDir.exists()) {
112                         if (_logger.isDebugEnabled()) {
113                                 if (_logger.isTraceEnabled())
114                                         _logger.debug("failed to find bundles directory at '" + startupDir.getAbsolutePath() + "', popping up a level.");
115                         }
116
117                         if (lastStartupDirState.equals(FileSystemHelper.sanitizeFilename(startupDir.getAbsolutePath()))) {
118                                 throw new RuntimeException(
119                                         "caught the startup directory not changing, which means we have hit the root and failed to find our bundles and ext directories.");
120                         }
121                         // reset for next time.
122                         lastStartupDirState = FileSystemHelper.sanitizeFilename(startupDir.getAbsolutePath());
123
124                         // pop up a level, since we didn't find our bundles directory.
125                         startupDir = new File(startupDir, "..");
126                         testingBundlesDir = new File(startupDir, "bundles");
127                         testingExtDir = new File(startupDir, "ext");
128
129                         if (startupDir.getParent() == null) {
130                                 throw new RuntimeException("failed to find the bundles and ext directories after hitting top of file system paths.");
131                         }
132                 }
133
134                 // we successfully found the bundles directory, even if we may have had to jump a few hoops.
135                 if (_logger.isTraceEnabled()) {
136                         _logger.debug("successfully found bundles directory under path: " + appPath);
137                 }
138
139                 // now resolve the path to an absolute location without relative components.
140                 try {
141                         appPath = FileSystemHelper.sanitizeFilename(startupDir.getCanonicalPath());
142                 } catch (IOException e) {
143                         _logger.error("could not open osgi directory: " + appPath);
144                 }
145                 if (_logger.isTraceEnabled())
146                         _logger.debug("startup path after resolution with File: " + appPath);
147                 return appPath;
148         }
149 }