001: /*
002: * Copyright 2004 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.tools.importexport.export.cli;
017:
018: import org.outerj.daisy.repository.clientimpl.RemoteRepositoryManager;
019: import org.outerj.daisy.repository.Credentials;
020: import org.outerj.daisy.repository.Repository;
021: import org.outerj.daisy.tools.importexport.export.config.ExportOptions;
022: import org.outerj.daisy.tools.importexport.export.config.ExportOptionsFactory;
023: import org.outerj.daisy.tools.importexport.export.ExportSetFactory;
024: import org.outerj.daisy.tools.importexport.export.ExportSet;
025: import org.outerj.daisy.tools.importexport.export.Exporter;
026: import org.outerj.daisy.tools.importexport.export.tm.TMExporter;
027: import org.outerj.daisy.tools.importexport.export.fs.ExportFile;
028: import org.outerj.daisy.tools.importexport.export.fs.ExportFileFactory;
029: import org.outerj.daisy.tools.importexport.util.ImportExportUtil;
030: import org.outerj.daisy.tools.importexport.ImportExportException;
031: import org.outerj.daisy.tools.importexport.ImpExpFormat;
032: import org.outerj.daisy.tools.importexport.tm.TMConfig;
033: import org.outerj.daisy.tools.importexport.tm.TMConfigFactory;
034: import org.outerj.daisy.util.VersionHelper;
035: import org.outerj.daisy.util.CliUtil;
036: import org.outerj.daisy.xmlutil.XmlSerializer;
037: import org.apache.commons.cli.*;
038:
039: import javax.xml.transform.OutputKeys;
040: import java.io.*;
041: import java.util.*;
042: import java.text.SimpleDateFormat;
043: import java.text.DateFormat;
044:
045: /**
046: * Command-line interface of the export tool.
047: */
048: public class ExportCli {
049: private boolean exportRunning = false;
050:
051: public static void main(String[] args) throws Exception {
052: new ExportCli().run(args);
053: }
054:
055: private ExportCli() {
056:
057: }
058:
059: private void run(String[] args) throws Exception {
060: Options cliOptions = new Options();
061:
062: Option optionsOption = new Option("o", "options", true,
063: "Specifies path to options XML file (use -d to get a template)");
064: cliOptions.addOption(optionsOption);
065:
066: Option dumpOptionsOption = new Option("d",
067: "dump-sample-options", false,
068: "Shows sample options to provide via -o");
069: cliOptions.addOption(dumpOptionsOption);
070:
071: Option exportPathOption = new Option("e", "export", true,
072: "Path to the export location (dir or zip)");
073: cliOptions.addOption(exportPathOption);
074:
075: Option exportSetOption = new Option("f", "exportset", true,
076: "File specifying docs to export");
077: cliOptions.addOption(exportSetOption);
078:
079: Option repoURLOption = new Option("l", "repo-url", true,
080: "Repository server URL, e.g. http://localhost:9263");
081: cliOptions.addOption(repoURLOption);
082:
083: Option repoUserOption = new Option("u", "repo-user", true,
084: "Daisy repository login");
085: cliOptions.addOption(repoUserOption);
086:
087: Option repoPwdOption = new Option("p", "repo-pwd", true,
088: "Daisy repository password");
089: cliOptions.addOption(repoPwdOption);
090:
091: Option repoRolesOption = new Option("r", "repo-roles", true,
092: "Daisy repository role/s (comma separated)");
093: cliOptions.addOption(repoRolesOption);
094:
095: Option skipVersionCheckOption = new Option("s",
096: "skip-version-check", false, "Skip version check");
097: cliOptions.addOption(skipVersionCheckOption);
098:
099: Option versionOption = new Option("v", "version", false,
100: "Print version and exit");
101: cliOptions.addOption(versionOption);
102:
103: Option helpOption = new Option("h", "help", false, "Shows help");
104: cliOptions.addOption(helpOption);
105:
106: Option formatOption = new Option("t", "format", true,
107: "Export format: 'default' or 'tm'");
108: cliOptions.addOption(formatOption);
109:
110: Option tmConfigOption = new Option("g", "tm-config", true,
111: "Only for tm (translation management) import: tm-specific config file");
112: cliOptions.addOption(tmConfigOption);
113:
114: CommandLineParser parser = new PosixParser();
115: CommandLine cmd = null;
116: boolean showHelp = false;
117: try {
118: cmd = parser.parse(cliOptions, args);
119: } catch (ParseException e) {
120: showHelp = true;
121: }
122:
123: if (showHelp || cmd.hasOption(helpOption.getOpt())) {
124: printHelp(cliOptions);
125: System.exit(1);
126: }
127:
128: Properties versionProperties = ImportExportUtil
129: .getVersionProperties();
130: if (cmd.hasOption(versionOption.getOpt())) {
131: System.out.println(VersionHelper
132: .formatVersionString(versionProperties));
133: System.exit(0);
134: }
135:
136: if (cmd.hasOption(dumpOptionsOption.getOpt())) {
137: System.out.println(ExportOptionsFactory
138: .toXml(ExportOptionsFactory
139: .getDefaultExportOptions()));
140: return;
141: }
142:
143: if (!cmd.hasOption(exportPathOption.getOpt())) {
144: System.out.println("Missing -" + exportPathOption.getOpt()
145: + " argument");
146: System.exit(1);
147: }
148:
149: String repositoryURL = "http://localhost:9263";
150: if (!cmd.hasOption(repoURLOption.getOpt())) {
151: System.out
152: .println("-"
153: + repoURLOption.getOpt()
154: + " not specified, assuming repository is listening at "
155: + repositoryURL);
156: } else {
157: repositoryURL = cmd.getOptionValue(repoURLOption.getOpt());
158: }
159:
160: String user;
161: if (!cmd.hasOption(repoUserOption.getOpt())) {
162: System.out.println("Missing -" + repoUserOption.getOpt()
163: + " argument");
164: System.exit(1);
165: }
166: user = cmd.getOptionValue(repoUserOption.getOpt());
167:
168: String pwd;
169: if (!cmd.hasOption(repoPwdOption.getOpt())) {
170: pwd = CliUtil.promptPassword("Daisy password for " + user
171: + ": ", false);
172: if (pwd == null) {
173: System.out.println("No password specified, exiting.");
174: System.exit(1);
175: }
176: } else {
177: pwd = cmd.getOptionValue(repoPwdOption.getOpt());
178: }
179:
180: if (!cmd.hasOption(exportSetOption.getOpt())) {
181: System.out.println("Missing -" + exportSetOption.getOpt()
182: + " argument");
183: System.exit(1);
184: }
185:
186: CliExportListener listener = null;
187: int exitCode = 0;
188: try {
189: System.out.println("\nConnecting to the repository.");
190: RemoteRepositoryManager repositoryManager = new RemoteRepositoryManager(
191: repositoryURL, new Credentials(user, pwd));
192: Repository repository = repositoryManager
193: .getRepository(new Credentials(user, pwd));
194:
195: if (cmd.hasOption(repoRolesOption.getOpt())) {
196: long[] roles = ImportExportUtil.parseRoles(cmd
197: .getOptionValue(repoRolesOption.getOpt()),
198: repository);
199: repository.setActiveRoleIds(roles);
200: }
201:
202: ExportOptions options;
203: if (cmd.hasOption(optionsOption.getOpt())) {
204: String optionsPath = cmd.getOptionValue(optionsOption
205: .getOpt());
206: InputStream is = null;
207: try {
208: is = new FileInputStream(optionsPath);
209: options = ExportOptionsFactory.parseFromXml(is,
210: repository);
211: } finally {
212: if (is != null)
213: try {
214: is.close();
215: } catch (Exception e) { /* ignore */
216: }
217: }
218: } else {
219: options = ExportOptionsFactory
220: .getDefaultExportOptions();
221: }
222:
223: listener = new CliExportListener(getOut(), options);
224:
225: ExportFile exportFile = ExportFileFactory.getExportFile(
226: new File(cmd.getOptionValue(exportPathOption
227: .getOpt())), listener);
228:
229: if (!cmd.hasOption(skipVersionCheckOption.getOpt())) {
230: String serverVersion = repository.getServerVersion();
231: String exportToolVersion = versionProperties
232: .getProperty("artifact.version");
233: if (!serverVersion.equals(exportToolVersion)) {
234: System.out
235: .println("Version of export tool and repository server do not match.");
236: System.out.println("Version of export tool: "
237: + exportToolVersion);
238: System.out.println("Version of server : "
239: + serverVersion);
240: System.out.println();
241: System.out
242: .println("It is recommended to use a corresponding version. To skip the version check, use -"
243: + skipVersionCheckOption.getOpt());
244: System.exit(1);
245: }
246: }
247:
248: String formatName = cmd.getOptionValue(formatOption
249: .getOpt());
250: ImpExpFormat format = formatName == null ? ImpExpFormat.DEFAULT
251: : ImpExpFormat.fromString(formatName);
252:
253: TMConfig tmConfig = null;
254: if (format == ImpExpFormat.TRANSLATION_MANAGEMENT) {
255: if (cmd.hasOption(tmConfigOption.getOpt())) {
256: String tmConfigFile = cmd
257: .getOptionValue(tmConfigOption.getOpt());
258: tmConfig = TMConfigFactory.parseFromXml(
259: tmConfigFile, repository);
260: } else {
261: tmConfig = new TMConfig();
262: }
263: }
264:
265: Date exportTime = new Date();
266: ExportSet exportSet;
267: InputStream is = null;
268: try {
269: is = new FileInputStream(cmd
270: .getOptionValue(exportSetOption.getOpt()));
271: exportSet = ExportSetFactory.parseFromXml(is,
272: repository);
273: } catch (Throwable e) {
274: throw new ImportExportException(
275: "Error reading export document set.", e);
276: } finally {
277: if (is != null)
278: is.close();
279: }
280:
281: final Thread mainThread = Thread.currentThread();
282: Runtime.getRuntime().addShutdownHook(
283: new ExportCliShutdownHook(listener, mainThread));
284:
285: try {
286: setExportRunning(true);
287: switch (format) {
288: case DEFAULT:
289: Exporter.run(exportSet, exportFile, exportTime,
290: repository, options, listener);
291: break;
292: case TRANSLATION_MANAGEMENT:
293: TMExporter.run(exportSet, exportFile, exportTime,
294: repository, options, listener, tmConfig);
295: break;
296: default:
297: throw new RuntimeException("Unrecognized format: "
298: + format);
299: }
300: exportFile.finish();
301: } finally {
302: setExportRunning(false);
303: printExportSummary(listener);
304: }
305: } catch (Throwable e) {
306: ImportExportUtil.logError(e, "exporterror", getOut());
307: exitCode = 1;
308: }
309:
310: if (listener == null || !listener.isInterrupted()) {
311: // Only call System.exit when the export was not interrupted, otherwise
312: // the ExportCliShutdownHook will keep waiting
313: System.exit(exitCode);
314: }
315: }
316:
317: private PrintStream getOut() {
318: return System.out;
319: }
320:
321: private synchronized void setExportRunning(boolean running) {
322: this .exportRunning = running;
323: }
324:
325: private synchronized boolean isExportRunning() {
326: return exportRunning;
327: }
328:
329: private void printExportSummary(CliExportListener listener) {
330: List failed = listener.getFailed();
331: List succeeded = listener.getSucceeded();
332: List skippedBecauseRetired = listener
333: .getSkippedBecauseRetired();
334: List skippedBecauseNoLiveVersion = listener
335: .getSkippedBecauseNoLiveVersion();
336: List brokenLinks = listener.getBrokenLinks();
337: List failedItems = listener.getFailedItems();
338:
339: getOut().println();
340: getOut().println("Export summary");
341: getOut().println("--------------");
342: getOut().println("Succeeded: " + succeeded.size());
343: getOut().println("Failed: " + failed.size());
344: getOut().println(
345: "Skipped because retired: "
346: + skippedBecauseRetired.size());
347: getOut().println(
348: "Skipped because no live version: "
349: + skippedBecauseNoLiveVersion.size());
350: getOut().println(
351: "Number of docs that are not included and cause broken links: "
352: + brokenLinks.size());
353: getOut().println(
354: "Non-document failures (optional schema types etc.): "
355: + failedItems.size());
356:
357: try {
358: File summaryFile;
359: SimpleDateFormat dateFormat = (SimpleDateFormat) DateFormat
360: .getDateTimeInstance();
361: dateFormat.applyPattern("yyyyMMddHHmmss");
362: String baseName = "exportsummary_"
363: + dateFormat.format(new Date());
364: int c = 1;
365: while (true) {
366: File file = new File(baseName + c + ".xml");
367: if (file.createNewFile()) {
368: summaryFile = file;
369: break;
370: }
371: c++;
372: }
373:
374: FileOutputStream fos = new FileOutputStream(summaryFile);
375: PrintWriter writer = new PrintWriter(fos);
376:
377: Properties props = new Properties();
378: props.put(OutputKeys.INDENT, "yes");
379: XmlSerializer xmlSerializer = new XmlSerializer(fos, props);
380: listener.generateSax(xmlSerializer);
381: fos.close();
382:
383: writer.close();
384: fos.close();
385: getOut().println(
386: "Detailed document listing written to "
387: + summaryFile.getAbsolutePath());
388: getOut().println();
389: } catch (Exception e) {
390: getOut().println(
391: "Error writing summary file: " + e.getMessage());
392: e.printStackTrace();
393: }
394: }
395:
396: private void printHelp(Options cliOptions) {
397: HelpFormatter help = new HelpFormatter();
398: help.printHelp("daisy-export", cliOptions, true);
399: System.out.println();
400: System.out.println("To export, you need at least:");
401: System.out.println();
402: System.out
403: .println("daisy-export -u <username> -e /path/to/export[.zip] -f exportset.xml");
404: System.out.println();
405: System.out
406: .println("exportset.xml is an XML file specifying the files to export, using a query or manually listed.");
407: System.out.println("");
408: System.out.println("Example:");
409: System.out.println("");
410: System.out.println("<documents>");
411: System.out.println(" <!--");
412: System.out
413: .println(" List <query> and/or <document> elements.");
414: System.out
415: .println(" On <document>, branch and language are optional (defaults to main resp. default)");
416: System.out.println(" -->");
417: System.out.println(" <query>select id where true</query>");
418: System.out
419: .println(" <document id=\"123-DSY\" branch=\"somebranch\" language=\"somelanguage\"/>");
420: System.out.println("</documents>");
421: System.out.println();
422: System.out
423: .println("Use -o you can control various options, again specified in an XML file.");
424: System.out
425: .println("Use -d to see an example of such a file, showing the default configuration.");
426: System.out.println();
427: }
428:
429: class ExportCliShutdownHook extends Thread {
430: CliExportListener listener;
431: Thread exportThread;
432:
433: public ExportCliShutdownHook(CliExportListener listener,
434: Thread exportThread) {
435: this .listener = listener;
436: this .exportThread = exportThread;
437: }
438:
439: public void run() {
440: if (!isExportRunning())
441: return;
442: listener.interrupt();
443: try {
444: exportThread.join();
445: } catch (InterruptedException e) {
446: // ignore
447: }
448: }
449: }
450: }
|