1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.globalse.arena.server;
22
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileNotFoundException;
26 import java.io.IOException;
27 import java.lang.reflect.InvocationTargetException;
28 import java.net.MalformedURLException;
29 import java.rmi.Naming;
30 import java.rmi.RMISecurityManager;
31 import java.rmi.RemoteException;
32 import java.rmi.registry.LocateRegistry;
33 import java.rmi.server.RMIClassLoader;
34 import java.util.logging.LogManager;
35 import java.util.logging.Logger;
36
37 import org.globalse.arena.remote.LeagueInfo;
38 import org.globalse.arena.remote.MatchPanelFactory;
39 import org.globalse.arena.remote.RemoteLeague;
40 import org.globalse.arena.remote.RemoteTournament;
41 import org.globalse.arena.remote.TournamentInfo;
42 import org.globalse.arena.remote.exceptions.ArenaException;
43 import org.globalse.arena.remote.exceptions.GameAlreadyExistsException;
44 import org.globalse.arena.remote.exceptions.GameNotFoundException;
45 import org.globalse.arena.user.DefaultAccessPolicy;
46 import org.globalse.arena.user.User;
47 import org.globalse.arena.util.PropertyLoader;
48
49 /***
50 * This class provides the main method for starting an arena server. It takes an
51 * optional argument on the command line which specified a filename or a URL for
52 * a properties file. The properties understood by StartArena include:
53 * <UL>
54 * <LI><code>ArenaPort</code> (default 1099) The TCP/IP port on which the arena server should accept RMI connections</LI>
55 * <LI><code>CodeBase</code> (no default) A list of space-separated URLs specifying where to load game-specified and tournament style specific classes.</LI>
56 * <LI><code>TournamentStyles</code> (no default) A space-separated list of fully qualified class names of tournament styles to be loaded into this arena.</LI>
57 * <LI><code>Games</code> (no default) A space-separated list of fully qualified class names of games to be loaded into this arena.</LI>
58 * <LI><code>SetupDemo</code> (default false) A flag specifying whether test users, leagues, tournaments, and matches should be created.</LI>
59 * </UL>
60 * <P>In addition, this class will use the properties file to initialize the loggers. See the
61 * documentation on java.util.logging for information about logging properties.</P>
62 *
63 * <P>Once it creates and intializes the arena, this class dynamically loads the specified tournament styles
64 * and games and registers them. If at any point the initialization or loading fails, the main method
65 * exists with status 1.</P>
66 *
67 * @author Allen Dutoit
68 */
69 public class StartArena {
70
71 private static Logger logger = Logger.getLogger("org.globalse.arena.server");
72
73 private static Arena arena = Arena.getInstance();
74 private static String codeBase = null;
75
76
77 private static final String TICTACTOE = "TicTacToe";
78 private static final String TICTACTOE_CLASSNAME = "org.globalse.arena.ttt.TicTacToe";
79 private static final String TICTACTOEFACTORY_CLASSNAME = TICTACTOE_CLASSNAME + "MatchPanelFactory";
80 private static final String KNOCK_OUT = "KnockOutStyle";
81 private static final String KNOCKOUT_CLASSNAME = "org.globalse.arena.styles.KnockOutStyle";
82
83 private static void tellUser(String message) {
84 System.out.println(message);
85 }
86
87 private static PropertyLoader loadProperties(String fileName) {
88 PropertyLoader propertyLoader = null;
89 try {
90 propertyLoader = new PropertyLoader(fileName);
91 } catch (FileNotFoundException e) {
92 tellUser("Properties file \"" + fileName + "\" not found.");
93 System.exit(1);
94 } catch (IOException e) {
95 tellUser("An exception occured while reading from properties file \"" + fileName + "\": " + e.getMessage());
96 e.printStackTrace();
97 System.exit(1);
98 }
99 return propertyLoader;
100 }
101
102 private static void initLogger(String fileName) {
103 if (fileName != null) {
104 LogManager logManager = LogManager.getLogManager();
105 try {
106 logManager.readConfiguration(new FileInputStream(new File(fileName)));
107 } catch (Exception e) {
108 tellUser("An exception occured while configuring the logger from properties file \"" + fileName + "\": " + e.getMessage());
109 }
110 }
111 }
112
113 private static void initArena(PropertyLoader propertyLoader) {
114 try {
115 Arena.init();
116 arena = Arena.getInstance();
117
118 arena.setAccessPolicy(new DefaultAccessPolicy());
119
120 String operatorName = propertyLoader.getStringProperty("Operator", "admin");
121 String operatorPassword = propertyLoader.getStringProperty("OperatorPassword", "adminpass");
122 User operator = arena.createUser(operatorName, operatorPassword);
123 arena.setOperator(operator);
124 int serverPort = propertyLoader.getIntProperty("ArenaPort", 1099);
125 LocateRegistry.createRegistry(serverPort);
126 tellUser("Registering arena on port " + serverPort + " ...");
127 Naming.rebind("//localhost:" + serverPort + "/ArenaServer", arena);
128 tellUser("... arena successfully registered as a remote object.");
129 } catch (Exception e) {
130 tellUser("Failed to initialize arena: " + e.getMessage());
131 e.printStackTrace();
132 }
133 }
134
135 private static Object getInstanceOfClass(String className) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, SecurityException, IllegalAccessException, IllegalArgumentException, MalformedURLException {
136 Class result = null;
137 try {
138 tellUser("Loading class " + className + " from classpath.");
139 result = Class.forName(className);
140 } catch (ClassNotFoundException e) {
141 tellUser(className + " not found in classpath, trying remote loading from codebase (" + codeBase + ").");
142 result = RMIClassLoader.loadClass(codeBase, className);
143 }
144 return result.getMethod("getInstance", null).invoke(null, null);
145 }
146
147 private static void registerTournamentStyles(PropertyLoader propertyLoader) {
148 String [] styleClassNames = propertyLoader.getStringArrayProperty("TournamentStyles");
149 String styleClassName = null;
150 boolean loadingSucceeded = false;
151 try {
152 for (int i = 0; i < styleClassNames.length; i++) {
153 styleClassName = styleClassNames[i];
154 String defaultStyleName = styleClassName.substring(styleClassName.lastIndexOf(".")+1);
155 String styleName = propertyLoader.getStringProperty(styleClassName + ".name", defaultStyleName);
156 TournamentStyle style = (TournamentStyle)getInstanceOfClass(styleClassName);
157 arena.registerTournamentStyle(styleName, style);
158 }
159 loadingSucceeded = true;
160 } catch (ClassNotFoundException e) {
161 tellUser("Tournament style class \"" + styleClassName + "\" not found (neither in class path nor in codebase).");
162 } catch (MalformedURLException e) {
163 tellUser("Failed to remotely load tournament style class \"" + styleClassName +
164 "\" because codebase URL is not well-formed (\"" + codeBase + "\").");
165 } catch (NoSuchMethodException e) {
166 tellUser("Tournament style class \"" + styleClassName +
167 "\" does not define a public static method getInstance().");
168 } catch (Exception e) {
169 tellUser("Tournament style class \"" + styleClassName +
170 "\" static method getInstance() threw exception: " + e.getMessage());
171 e.printStackTrace();
172 }
173 if (!loadingSucceeded) {
174 System.exit(1);
175 }
176 }
177
178 private static String registerOneGame(PropertyLoader propertyLoader, String gameClassName) throws MalformedURLException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, GameAlreadyExistsException {
179 String defaultStyleName = gameClassName.substring(gameClassName.lastIndexOf(".")+1);
180 String gameName = propertyLoader.getStringProperty(gameClassName + ".name", defaultStyleName);
181 String gameDescription = propertyLoader.getStringProperty(gameClassName + ".description", "");
182 Game game = (Game)getInstanceOfClass(gameClassName);
183 String panelFactoryClassName = propertyLoader.getStringProperty(gameClassName + ".factory", null);
184 if (panelFactoryClassName == null) {
185 panelFactoryClassName = gameClassName + "MatchPanelFactory";
186 }
187 MatchPanelFactory matchPanelFactory = (MatchPanelFactory)getInstanceOfClass(panelFactoryClassName);
188 arena.registerGame(game, gameName, gameDescription, matchPanelFactory);
189 return gameName;
190 }
191
192 private static void registerGames(PropertyLoader propertyLoader) {
193 String [] gameClassNames = propertyLoader.getStringArrayProperty("Games");
194 String gameClassName = null;
195 boolean loadingSucceeded = false;
196 try {
197 for (int i = 0; i < gameClassNames.length; i++) {
198 gameClassName = gameClassNames[i];
199 registerOneGame(propertyLoader, gameClassName);
200 }
201 loadingSucceeded = true;
202 } catch (ClassNotFoundException e) {
203 tellUser("Failed to load game class or associated match panel factory \"" + gameClassName + "\":" + e.getMessage());
204 } catch (NoSuchMethodException e) {
205 tellUser("Game class \"" + gameClassName + "\" does not define a static method getInstance().\n" + e.getMessage());
206 } catch (Exception e) {
207 tellUser("Game class \"" + gameClassName + "\" static method getInstance() threw exception: " + e.getMessage());
208 }
209 if (!loadingSucceeded) {
210 System.exit(1);
211 }
212 }
213
214
215 private static void setupDemo(PropertyLoader propertyLoader) {
216 if (!propertyLoader.getBooleanProperty("SetupDemo", false)) {
217 return;
218 }
219 String gameName = propertyLoader.getStringProperty("DemoGameName", "TicTacToe");
220 tellUser("Setting up demo for game " + gameName);
221
222 try {
223 arena.getGameByName(gameName);
224 } catch (GameNotFoundException e) {
225 tellUser("Demo game \"" + gameName + "\" is not registered with arena.");
226 tellUser("The Games and <game class>.name properties should be set for each game. For example:");
227 tellUser("Games=org.globalse.arena.ttt.TicTacToe");
228 tellUser("org.globalse.arena.ttt.TicTacToe.name=TicTacToe");
229 System.exit(1);
230 }
231
232 User alice = null, joe = null, mike = null, mark = null, mary = null, bob = null;
233 try {
234
235 alice = arena.createUser("alice", "alicepass");
236 joe = arena.createUser("joe", "joepass");
237 mike = arena.createUser("mike", "mikepass");
238 mark = arena.createUser("mark", "markpass");
239 mary = arena.createUser("mary", "marypass");
240 bob = arena.createUser("bob", "bobpass");
241
242 } catch (Exception e) {
243 tellUser("Failed to create demo users.");
244 e.printStackTrace();
245 System.exit(1);
246 }
247
248
249 try {
250 if (arena.getTournamentStyleByName(KNOCK_OUT) == null) {
251 TournamentStyle ko = (TournamentStyle)getInstanceOfClass(KNOCKOUT_CLASSNAME);
252 arena.registerTournamentStyle(KNOCK_OUT, ko);
253 }
254 } catch (Exception e) {
255 tellUser("Failed to load knock out tournament style.");
256 e.printStackTrace();
257 System.exit(1);
258 }
259
260 try {
261 String operatorName = propertyLoader.getStringProperty("Operator", "admin");
262 String operatorPassword = propertyLoader.getStringProperty("OperatorPassword", "adminpass");
263 String operatorTicket = arena.login(operatorName, operatorPassword);
264 tellUser("Operator logged in with ticket: " + operatorTicket);
265
266 String bobTicket = arena.login("bob", "bobpass");
267 tellUser("Bob logged in with ticket: " + bobTicket);
268 LeagueInfo linfo;
269 RemoteLeague l;
270 TournamentInfo tinfo;
271 RemoteTournament t;
272
273 linfo = arena.createLeague(operatorTicket, bob, "Expert " + gameName + " League", "A restricted league for insiders.", gameName, KNOCK_OUT);
274 l = linfo.getLeague();
275 l.addPlayer(bobTicket, alice);
276 l.addPlayer(bobTicket, joe);
277 tinfo = linfo.getLeague().createTournament(bobTicket, "2003 Championship", "");
278 t = tinfo.getTournament();
279 t.openRegistration(bobTicket);
280 t.acceptPlayer(bobTicket, alice);
281 t.acceptPlayer(bobTicket, joe);
282 t.closeRegistration(bobTicket);
283 t.launch(bobTicket);
284 tinfo = linfo.getLeague().createTournament(bobTicket, "2004 Championship", "");
285 t = tinfo.getTournament();
286 t.openRegistration(bobTicket);
287
288 linfo = arena.createLeague(operatorTicket, bob, "Novice " + gameName + " League", "A simple, unrestricted league for beginners.", gameName, KNOCK_OUT);
289 linfo.getLeague().unrestrict(bobTicket);
290 tinfo = linfo.getLeague().createTournament(bobTicket, "Paper Cup", "An adhoc knockout tournament.");
291 t = tinfo.getTournament();
292 t.openRegistration(bobTicket);
293 t.acceptPlayer(bobTicket, joe);
294 t.acceptPlayer(bobTicket, mike);
295 t.acceptPlayer(bobTicket, alice);
296 t.acceptPlayer(bobTicket, mark);
297 t.acceptPlayer(bobTicket, mary);
298 t.closeRegistration(bobTicket);
299 t.launch(bobTicket);
300 } catch (RemoteException e) {
301 e.printStackTrace();
302 } catch (ArenaException e) {
303 e.printStackTrace();
304 }
305 tellUser("Demo setup finished.");
306 }
307
308 public static void main(String[] args) {
309
310
311 String propertiesFileName = null;
312 if (args.length > 0) {
313 propertiesFileName = args[0];
314 }
315 PropertyLoader propertyLoader = loadProperties(propertiesFileName);
316
317
318
319
320
321 codeBase = propertyLoader.getStringProperty("CodeBase", null);
322 if (codeBase != null) {
323 System.setProperty("java.rmi.server.codebase", codeBase);
324 }
325
326
327 initLogger(propertiesFileName);
328
329
330
331
332
333 System.setSecurityManager(new RMISecurityManager() {
334
335
336 public void checkAccept(String host, int port) {}
337
338
339 public void checkConnect (String host, int port) {}
340 public void checkConnect (String host, int port, Object context) {}
341 });
342
343
344 initArena(propertyLoader);
345
346
347 registerTournamentStyles(propertyLoader);
348
349
350 registerGames(propertyLoader);
351
352
353 setupDemo(propertyLoader);
354
355
356
357 while (true) {
358 try { Thread.sleep(5000); } catch (InterruptedException e) {}
359 }
360 }
361 }
362