001: // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
002: // Released under the terms of the GNU General Public License version 2 or later.
003: package fitnesse;
004:
005: import fitnesse.socketservice.SocketService;
006: import fitnesse.wiki.*;
007: import fitnesse.responders.ResponderFactory;
008: import fitnesse.components.*;
009: import fitnesse.updates.Updater;
010: import fitnesse.html.HtmlPageFactory;
011: import fitnesse.authentication.*;
012: import java.net.BindException;
013: import java.io.File;
014:
015: public class FitNesse {
016: public static final String FITNESSE_VERSION = "20050405";
017: public static final String STIQ_VERSION = "2.0 RC4";
018:
019: private FitNesseContext context = new FitNesseContext();
020:
021: private SocketService theService;
022:
023: private static String extraOutput;
024:
025: public static FitNesse startFitNesse(String[] args)
026: throws Exception {
027: Arguments arguments = parseCommandLine(args);
028: if (arguments == null) {
029: printUsage();
030: return null;
031: }
032: FitNesseContext context = loadContext(arguments);
033: PageVersionPruner.daysTillVersionsExpire = arguments
034: .getDaysTillVersionsExpire();
035: FitNesse fitnesse = new FitNesse(context);
036: boolean started = fitnesse.start();
037: if (started)
038: printStartMessage(arguments, context);
039: return fitnesse;
040: }
041:
042: public static void main(String[] args) throws Exception {
043: FitNesse fitnesse = startFitNesse(args);
044: if (fitnesse == null) {
045: System.exit(1);
046: }
047: }
048:
049: private static FitNesseContext loadContext(Arguments arguments)
050: throws Exception {
051: FitNesseContext context = new FitNesseContext();
052: ComponentFactory componentFactory = new ComponentFactory(
053: context.rootPath);
054: context.port = arguments.getPort();
055: context.rootPath = arguments.getRootPath();
056: context.rootPageName = arguments.getRootDirectory();
057: context.rootPagePath = context.rootPath + "/"
058: + context.rootPageName;
059: context.root = componentFactory.getRootPage(FileSystemPage
060: .makeRoot(context.rootPath, context.rootPageName));
061: context.responderFactory = new ResponderFactory(
062: context.rootPagePath);
063: context.logger = makeLogger(arguments);
064: context.authenticator = makeAuthenticator(arguments
065: .getUserpass(), componentFactory);
066: context.htmlPageFactory = componentFactory
067: .getHtmlPageFactory(new HtmlPageFactory());
068:
069: extraOutput = componentFactory
070: .loadResponderPlugins(context.responderFactory);
071: extraOutput += componentFactory.loadWikiWidgetPlugins();
072:
073: return context;
074: }
075:
076: public static Arguments parseCommandLine(String[] args) {
077: CommandLine commandLine = new CommandLine(
078: "[-p port][-d dir][-r root][-l logDir][-e days][-o][-a userpass]");
079: Arguments arguments = null;
080: if (commandLine.parse(args)) {
081: arguments = new Arguments();
082: if (commandLine.hasOption("p"))
083: arguments.setPort(commandLine.getOptionArgument("p",
084: "port"));
085: if (commandLine.hasOption("d"))
086: arguments.setRootPath(commandLine.getOptionArgument(
087: "d", "dir"));
088: if (commandLine.hasOption("r"))
089: arguments.setRootDirectory(commandLine
090: .getOptionArgument("r", "root"));
091: if (commandLine.hasOption("l"))
092: arguments.setLogDirectory(commandLine
093: .getOptionArgument("l", "logDir"));
094: if (commandLine.hasOption("e"))
095: arguments.setDaysTillVersionsExpire(commandLine
096: .getOptionArgument("e", "days"));
097: if (commandLine.hasOption("a"))
098: arguments.setUserpass(commandLine.getOptionArgument(
099: "a", "userpass"));
100: arguments.setOmitUpdates(commandLine.hasOption("o"));
101: }
102: return arguments;
103: }
104:
105: private static Logger makeLogger(Arguments arguments) {
106: String logDirectory = arguments.getLogDirectory();
107: return logDirectory != null ? new Logger(logDirectory) : null;
108: }
109:
110: public static Authenticator makeAuthenticator(
111: String authenticationParameter,
112: ComponentFactory componentFactory) throws Exception {
113: Authenticator authenticator = new PromiscuousAuthenticator();
114: if (authenticationParameter != null) {
115: if (new File(authenticationParameter).exists())
116: authenticator = new MultiUserAuthenticator(
117: authenticationParameter);
118: else {
119: String[] values = authenticationParameter.split(":");
120: authenticator = new OneUserAuthenticator(values[0],
121: values[1]);
122: }
123: }
124:
125: return componentFactory.getAuthenticator(authenticator);
126: }
127:
128: private static void printUsage() {
129: System.err.println("Usage: java fitnesse.FitNesse [-pdrleoa]");
130: System.err.println("\t-p <port number> {"
131: + Arguments.DEFAULT_PORT + "}");
132: System.err.println("\t-d <working directory> {"
133: + Arguments.DEFAULT_PATH + "}");
134: System.err.println("\t-r <page root directory> {"
135: + Arguments.DEFAULT_ROOT + "}");
136: System.err.println("\t-l <log directory> {no logging}");
137: System.err.println("\t-e <days> {"
138: + Arguments.DEFAULT_VERSION_DAYS
139: + "} Number of days before page versions expire");
140: System.err.println("\t-o omit updates");
141: System.err
142: .println("\t-a {user:pwd | user-file-name} enable authentication.");
143: }
144:
145: private static void printStartMessage(Arguments args,
146: FitNesseContext context) {
147: System.out.println("StoryTestIQ Server (" + STIQ_VERSION
148: + ") started...");
149: System.out.print(context.toString());
150: System.out.print(getStiqUrl(context.port));
151: //System.out.print(extraOutput);
152: }
153:
154: private static String getStiqUrl(int port) {
155: String endl = System.getProperty("line.separator");
156: StringBuffer buffer = new StringBuffer();
157: String url = "http://localhost:" + String.valueOf(port)
158: + "/stiq/runner.hta";
159: buffer.append("\t").append("Base URL: ").append(url).append(
160: endl);
161: return buffer.toString();
162: }
163:
164: private static void printBadPortMessage(int port) {
165: System.err.println("StoryTestIQ Server cannot be started...");
166: System.err.println("Port " + port + " is already in use.");
167: System.err
168: .println("Use the -p <port#> command line argument to use a different port.");
169: }
170:
171: private static void establishDirectory(String path) {
172: File filesDir = new File(path);
173: if (!filesDir.exists())
174: filesDir.mkdir();
175: }
176:
177: public FitNesse(FitNesseContext context) throws Exception {
178: this (context, true);
179: }
180:
181: // TODO MdM. This boolean agument is annoying... please fix.
182: public FitNesse(FitNesseContext context, boolean makeDirs) {
183: this .context = context;
184: context.fitnesse = this ;
185: if (makeDirs)
186: establishRequiredDirectories();
187: }
188:
189: public boolean start() {
190: try {
191: theService = new SocketService(context.port,
192: new FitNesseServer(context));
193: return true;
194: } catch (BindException e) {
195: printBadPortMessage(context.port);
196: } catch (Exception e) {
197: e.printStackTrace();
198: }
199: return false;
200: }
201:
202: public void stop() throws Exception {
203: if (theService != null) {
204: theService.close();
205: theService = null;
206: }
207: }
208:
209: private void establishRequiredDirectories() {
210: establishDirectory(context.rootPagePath);
211: establishDirectory(context.rootPagePath + "/files");
212: }
213:
214: public void applyUpdates() throws Exception {
215: Updater updater = new Updater(context);
216: updater.update();
217: }
218:
219: public boolean isRunning() {
220: return theService != null;
221: }
222: }
|