View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.xnap.loader;
21  
22  // this class is only allowed to access XNap classes in its own package
23  
24  import java.io.BufferedReader;
25  import java.io.File;
26  import java.io.FileInputStream;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.io.InputStreamReader;
30  import java.lang.reflect.Method;
31  import java.net.URL;
32  import java.net.URLDecoder;
33  import java.util.*;
34  
35  /***
36   * Checks if a version of XNap is available in the users preferences
37   * directory and launches the newest version found.
38   */
39  public class XNapLoader {
40  
41      //--- Constant(s) ---
42  
43      /***
44       * Current version of the core distribution. This version needs to
45       * be in sync with the version of the xnap-core package in the
46       * control file.
47  	 *
48       * <p><pre>
49       * Format: '$MAJOR.$MINOR[-$EXTRA(1-9)]'
50       * $EXTRA can be 'alpha', 'beta' or 'pre'
51       *
52       * Examples: 1.3-alpha1, 2.1-pre1, 2.4
53       * </pre>
54       *
55       * <p>Security fix related releases should append 'r(1-9)' to the version,
56       * like this 2.4r1 .
57       */
58      public static final String VERSION = "3.0-pre1";
59  
60  	public static final String LOADER_FILENAME
61  		= XNapClassLoader.getHomeDir() + "loader";
62  
63      //--- Data field(s) ---
64  
65      //--- Method(s) ---
66  
67      /***
68       *
69       */
70      public static void main(String[] argv) 
71      {
72  		if (!invoke(LOADER_FILENAME, true, argv)) {
73  
74  			err("Using default class path");
75  			if (!invoke("default_loader", false, argv)) {
76  
77  				err("Could not find suitable loader file, giving up");
78  				System.exit(1);
79  			}
80  		}	
81      }
82  
83      /***
84       * Prints <code>o.toString()</code> to stderr.
85       */
86      public static void err(Object o)
87      {
88  		System.err.println(o);
89      }
90  
91  	public static URL[] getStartupClassPath
92  		(InputStream inStream, File parent, boolean requireVersion)
93  		throws IOException
94  	{
95  		boolean versionFound = false;
96  		LinkedList list = new LinkedList();
97  
98  		BufferedReader in 
99  			= new BufferedReader(new InputStreamReader(inStream));
100 		try {
101 			String s;
102 			while ((s = in.readLine()) != null) {
103 				if (s.startsWith("#")) {
104 					continue;
105 				}
106 				else if (s.startsWith("Loader-Version: ")) {
107 					StringTokenizer t = new StringTokenizer(s, ":");
108 					t.nextToken();
109 					if (t.hasMoreTokens()) {
110 						versionFound = true;
111 						String loaderVersion = t.nextToken().trim();
112 						if (!VERSION.equals(loaderVersion)) {
113 							throw new IOException
114 								("Mismatch of loader versions");
115 						}
116 					}
117 					continue;
118 				}
119 				
120 				list.add(new File(parent, s).toURL());
121 			}
122 		}
123 		finally {
124 			try {
125 				in.close();
126 			}
127 			catch (IOException e) {
128 			}
129 		}
130 
131 		if (requireVersion && !versionFound) {
132 			throw new IOException("Loader version information is missing");
133 		}
134 
135 		return (URL[])list.toArray(new URL[0]);
136 	}
137 
138     /***
139      * Returns the jar that contains the XNapLoader class.
140      *
141      * @return null, if path can not be determined; the jar, otherwise
142      */
143     public static File getJar()
144     {
145 		URL url = ClassLoader.getSystemClassLoader().getResource
146 			("org/xnap/loader/XNapLoader.class");
147 		if (url != null) {
148 			String path = url.getFile();
149 			if (path != null) {
150 				int index = path.lastIndexOf("!/");
151 				if (index > 0) {
152 					// remove URL stuff
153 					path = "//" + URLDecoder.decode(path.substring(5, index));
154 					return new File(path);
155 				}
156 			}
157 		}
158 
159 		return null;
160     }
161 
162     /***
163      * Returns path of the jar that contains the XNapLoader class.
164      *
165      * @return null, if path can not be determined; the path, otherwise
166      * @see #getJar()
167      */
168     public static File getJarPath()
169     {
170 		File f = getJar();
171 		return (f != null) ? f.getParentFile() : null;
172     }
173 
174 	public static boolean invoke
175 		(String filename, 
176 		 boolean requireVersion,
177 		 String[] argv) 
178 	{
179 		URL[] urls;
180 		try {
181 			File parent = getJarPath();
182 			InputStream in 
183 				= XNapClassLoader.getInstance().getResourceAsStream(filename);
184 			if (in == null) {
185 				in = new FileInputStream(filename);
186 				parent = null;
187 			}
188 			urls = getStartupClassPath(in, parent, requireVersion);
189 		}
190 		catch (IOException e) {
191 			err("Could not read startup classpath from " + filename
192 				+ " (" + e.getLocalizedMessage() + ")");
193 			return false;
194 		}
195 
196 		try {
197 			// add jar files to loader
198 			for (int i = 0; i < urls.length; i++) {
199 				XNapClassLoader.getInstance().add(urls[i]);
200 			}
201 
202 			// load main class
203 			Class c = XNapClassLoader.getInstance().loadClass("org.xnap.XNap");
204 			Object app = c.newInstance();
205 			Method m = c.getMethod("main", new Class[] { String[].class });
206 			m.invoke(app, new Object[] { argv });
207 			return true;
208 		}
209 		catch (Throwable e) {
210 			err("Could not load XNap");
211 			e.printStackTrace(System.err);
212 			return false;
213 		}
214 	}
215 
216 }