1 /** 2 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15 * 16 */ 17 18 package org.gudy.azureus2.ui.common; 19 20 import java.io.FileReader; 21 import java.io.OutputStreamWriter; 22 import java.io.PrintStream; 23 import java.io.PrintWriter; 24 import java.io.Reader; 25 import java.io.StringReader; 26 import java.lang.reflect.Constructor; 27 import java.lang.reflect.Method; 28 import java.net.Socket; 29 import java.text.SimpleDateFormat; 30 import java.util.Date; 31 import java.util.HashMap; 32 import java.util.Iterator; 33 import java.util.StringTokenizer; 34 35 import org.apache.commons.cli.CommandLine; 36 import org.apache.commons.cli.CommandLineParser; 37 import org.apache.commons.cli.HelpFormatter; 38 import org.apache.commons.cli.OptionBuilder; 39 import org.apache.commons.cli.Options; 40 import org.apache.commons.cli.ParseException; 41 import org.apache.commons.cli.PosixParser; 42 import org.apache.log4j.Appender; 43 import org.apache.log4j.ConsoleAppender; 44 import org.apache.log4j.Logger; 45 import org.apache.log4j.PatternLayout; 46 import org.apache.log4j.varia.DenyAllFilter; 47 48 import com.aelitis.azureus.core.*; 49 import com.aelitis.azureus.core.impl.AzureusCoreSingleInstanceClient; 50 import com.aelitis.azureus.launcher.Launcher; 51 52 import org.gudy.azureus2.core3.config.COConfigurationManager; 53 import org.gudy.azureus2.core3.util.Constants; 54 import org.gudy.azureus2.ui.common.IUserInterface; 55 import org.gudy.azureus2.ui.common.UserInterfaceFactory; 56 /** 57 * 58 * @author Tobias Minich 59 */ 60 public class Main { 61 62 public static String DEFAULT_UI = "swt"; 63 64 public static StartServer start = null; 65 66 protected static AzureusCore core; 67 parseCommands(String[] args, boolean constart)68 private static CommandLine parseCommands(String[] args, boolean constart) { 69 70 if (args==null) 71 return null; 72 73 CommandLineParser parser = new PosixParser(); 74 Options options = new Options(); 75 options.addOption("h", "help", false, "Show this help."); 76 77 OptionBuilder.withLongOpt("exec"); 78 OptionBuilder.hasArg(); 79 OptionBuilder.withArgName("file"); 80 OptionBuilder.withDescription("Execute script file. The file should end with 'logout', otherwise the parser thread doesn't stop."); 81 options.addOption( OptionBuilder.create('e')); 82 83 OptionBuilder.withLongOpt("command"); 84 OptionBuilder.hasArg(); 85 OptionBuilder.withArgName("command"); 86 OptionBuilder.withDescription("Execute single script command. Try '-c help' for help on commands."); 87 options.addOption(OptionBuilder.create('c')); 88 89 OptionBuilder.withLongOpt("ui"); 90 OptionBuilder.withDescription("Run <uis>. ',' separated list of user interfaces to run. The first one given will respond to requests without determinable source UI (e.g. further torrents added via command line)."); 91 OptionBuilder.withArgName("uis"); 92 OptionBuilder.hasArg(); 93 options.addOption(OptionBuilder.create('u')); 94 95 CommandLine commands = null; 96 try { 97 commands = parser.parse(options, args, true); 98 } catch( ParseException exp ) { 99 Logger.getLogger("azureus2").error("Parsing failed. Reason: " + exp.getMessage(), exp); 100 if (constart) 101 System.exit(2); 102 } 103 if ( commands != null && commands.hasOption('h')) { 104 if (constart) { 105 HelpFormatter hf = new HelpFormatter(); 106 hf.printHelp("java org.gudy.azureus2.ui.common.Main", "Optionally you can put torrent files to add to the end of the command line.\r\n", options, "Available User Interfaces: swt (default), web, console\r\nThe default interface is not started if you give either the '-e' or '-c' option (But you can start it by hand with '-u').", true); 107 System.exit(0); 108 } 109 } 110 return commands; 111 } 112 initRootLogger()113 public static void initRootLogger() { 114 if (Logger.getRootLogger().getAppender("ConsoleAppender")==null) { 115 Appender app; 116 app = new ConsoleAppender(new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)); 117 app.setName("ConsoleAppender"); 118 app.addFilter( new DenyAllFilter() ); //'log off' by default 119 Logger.getRootLogger().addAppender(app); 120 } 121 } 122 main(String[] args)123 public static void main(String[] args) { 124 if(Launcher.checkAndLaunch(Main.class, args)) 125 return; 126 127 // This *has* to be done first as it sets system properties that are read and cached by Java 128 129 COConfigurationManager.preInitialise(); 130 131 String mi_str = System.getProperty( "MULTI_INSTANCE" ); 132 133 boolean mi = mi_str != null && mi_str.equalsIgnoreCase("true"); 134 135 initRootLogger(); 136 137 try{ 138 CommandLine commands = parseCommands(args, true); 139 140 if ( commands != null && directLaunch( args, commands )){ 141 142 return; 143 } 144 145 // don't create core until we know we really need it 146 147 if( mi ){ 148 149 System.out.println( "MULTI_INSTANCE enabled" ); 150 151 core = AzureusCoreFactory.create(); 152 153 processArgs(args, core, commands); 154 155 return; 156 } 157 158 start = new StartServer(); 159 160 if ((start == null) || (start.getServerState()==StartServer.STATE_FAULTY)) { 161 162 163 new StartSocket( args ); 164 165 }else{ 166 167 168 core = AzureusCoreFactory.create(); 169 170 171 start.start(); 172 173 processArgs(args, core, commands); 174 } 175 }catch( AzureusCoreException e ){ 176 177 System.out.println( "Start fails:" ); 178 179 e.printStackTrace(); 180 } 181 } 182 shutdown()183 public static void shutdown() { 184 if (start!=null){ 185 186 start.stopIt(); 187 } 188 189 if ( core != null ){ 190 try{ 191 core.stop(); 192 193 }catch( AzureusCoreException e ){ 194 195 System.out.println( "Stop fails:" ); 196 197 e.printStackTrace(); 198 } 199 } 200 201 SimpleDateFormat temp = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss"); 202 Logger.getLogger("azureus2").fatal("Azureus stopped at "+temp.format(new Date())); 203 //System.exit(0); - we don't want to force quit, wait until other threads have completed 204 // so that resume data etc is saved.... 205 } 206 207 public static boolean directLaunch( String[] args, CommandLine commands)208 directLaunch( 209 String[] args, 210 CommandLine commands) 211 { 212 // frig to support launch of SWT ui via this means pending a proper rewrite 213 // of this stuff 214 215 if ( commands.hasOption('u')) { 216 217 String uinames = commands.getOptionValue('u'); 218 219 if ( uinames.indexOf(',') != -1 ){ 220 221 return( false ); 222 } 223 224 if ( !uinames.equalsIgnoreCase( DEFAULT_UI )){ 225 226 return( false ); 227 } 228 } 229 230 try{ 231 String uiclass = "org.gudy.azureus2.ui." + DEFAULT_UI + ".Main"; 232 233 Class main_class = Class.forName( uiclass ); 234 235 Method main_method = main_class.getMethod( "main", new Class[]{ String[].class }); 236 237 main_method.invoke( null, new Object[]{ commands.getArgs()}); 238 239 return( true ); 240 241 }catch( Throwable e ){ 242 243 e.printStackTrace(); 244 245 return( false ); 246 } 247 } 248 249 public static void processArgs( String[] args, AzureusCore new_core, CommandLine commands)250 processArgs( 251 String[] args, 252 AzureusCore new_core, 253 CommandLine commands) 254 { 255 if (commands==null) { 256 commands = parseCommands(args, false); 257 } 258 if (commands!=null && ( args.length > 0 || new_core != null)) { 259 if (UIConst.UIS == null) { 260 UIConst.UIS = new HashMap(); 261 } 262 if (commands.hasOption('u')) { 263 String uinames = commands.getOptionValue('u'); 264 if (uinames.indexOf(',')==-1) { 265 if (!UIConst.UIS.containsKey(uinames)) 266 UIConst.UIS.put(uinames,UserInterfaceFactory.getUI(uinames)); 267 } else { 268 StringTokenizer stok = new StringTokenizer(uinames, ","); 269 while (stok.hasMoreTokens()) { 270 String uin = stok.nextToken(); 271 if (!UIConst.UIS.containsKey(uin)) 272 UIConst.UIS.put(uin,UserInterfaceFactory.getUI(uin)); 273 } 274 } 275 } else { 276 if (UIConst.UIS.isEmpty() && !commands.hasOption('c') && !commands.hasOption('e')) 277 UIConst.UIS.put(DEFAULT_UI, UserInterfaceFactory.getUI(DEFAULT_UI)); 278 } 279 280 Iterator uis = UIConst.UIS.values().iterator(); 281 boolean isFirst = true; 282 String [] theRest = commands.getArgs(); 283 while (uis.hasNext()) { 284 IUserInterface ui = (IUserInterface) uis.next(); 285 ui.init(isFirst, (UIConst.UIS.size()>1)); 286 theRest = ui.processArgs(theRest); 287 isFirst = false; 288 } 289 290 if ( new_core != null ){ 291 292 SimpleDateFormat temp = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss"); 293 294 UIConst.startTime = new Date(); 295 296 Logger.getLogger("azureus2").fatal("Azureus started at "+temp.format(UIConst.startTime)); 297 298 UIConst.setAzureusCore( new_core ); 299 } 300 301 uis = UIConst.UIS.values().iterator(); 302 while (uis.hasNext()) 303 ((IUserInterface) uis.next()).startUI(); 304 305 Class clConsoleInput; 306 Constructor conConsoleInput =null; 307 try { 308 clConsoleInput = Class.forName("org.gudy.azureus2.ui.console.ConsoleInput"); 309 310 // change this and you'll need to change the parameters below.... 311 312 Class params[] = {String.class, AzureusCore.class, Reader.class, PrintStream.class, Boolean.class}; 313 314 conConsoleInput=clConsoleInput.getConstructor(params); 315 } catch (Exception e) { 316 e.printStackTrace(); 317 } 318 if (commands.hasOption('e')) { 319 if (conConsoleInput != null) { 320 try { 321 Object params[] = {commands.getOptionValue('e'), new_core, new FileReader(commands.getOptionValue('e')), System.out, Boolean.FALSE}; 322 conConsoleInput.newInstance(params); 323 } catch (java.io.FileNotFoundException e) { 324 Logger.getLogger("azureus2").error("Script file not found: "+e.toString()); 325 } catch (Exception e) { 326 Logger.getLogger("azureus2").error("Error invocating the script processor: "+e.toString()); 327 } 328 } else 329 Logger.getLogger("azureus2").error("ConsoleInput class not found. You need the console ui package to use '-e'"); 330 } 331 332 if (commands.hasOption('c')) { 333 if (conConsoleInput != null) { 334 String comm = commands.getOptionValue('c'); 335 comm+="\nlogout\n"; 336 Object params[] = {commands.getOptionValue('c'), UIConst.getAzureusCore(), new StringReader(comm), System.out, Boolean.FALSE}; 337 try { 338 conConsoleInput.newInstance(params); 339 } catch (Exception e) { 340 Logger.getLogger("azureus2").error("Error invocating the script processor: "+e.toString()); 341 } 342 } else 343 Logger.getLogger("azureus2").error("ConsoleInput class not found. You need the console ui package to use '-e'"); 344 } 345 346 openTorrents(theRest); 347 } else { 348 Logger.getLogger("azureus2").error("No commands to process"); 349 } 350 } 351 openTorrents(String[] torrents)352 public static void openTorrents(String[] torrents) { 353 if ((UIConst.UIS!=null) && (!UIConst.UIS.isEmpty()) && (torrents.length>0)) { 354 for(int l=0; l<torrents.length; l++) { 355 ((IUserInterface) UIConst.UIS.values().toArray()[0]).openTorrent(torrents[l]); 356 } 357 } 358 } 359 360 public static class StartSocket { StartSocket(String args[])361 public StartSocket(String args[]) { 362 Socket sck = null; 363 PrintWriter pw = null; 364 try { 365 System.out.println("StartSocket: passing startup args to already-running process."); 366 367 // NOTE - this formatting is also used by AzureusCoreSingleInstanceClient and other org.gudy.azureus2.ui.swt.StartSocket 368 369 sck = new Socket("127.0.0.1", Constants.INSTANCE_PORT ); 370 pw = new PrintWriter(new OutputStreamWriter(sck.getOutputStream())); 371 StringBuffer buffer = new StringBuffer(AzureusCoreSingleInstanceClient.ACCESS_STRING+";args;"); 372 for(int i = 0 ; i < args.length ; i++) { 373 String arg = args[i].replaceAll("&","&&").replaceAll(";","&;"); 374 buffer.append(arg); 375 buffer.append(';'); 376 } 377 pw.println(buffer.toString()); 378 pw.flush(); 379 } catch(Exception e) { 380 e.printStackTrace(); 381 } finally { 382 try { 383 if (pw != null) 384 pw.close(); 385 } catch (Exception e) { 386 } 387 try { 388 if (sck != null) 389 sck.close(); 390 } catch (Exception e) { 391 } 392 } 393 } 394 } 395 } 396