/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon; import java.io.File; import java.util.Arrays; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.cocoon.bean.CocoonBean; import org.apache.cocoon.bean.helpers.OutputStreamListener; import org.apache.cocoon.bean.helpers.BeanConfigurator; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.PosixParser; import org.apache.commons.lang.BooleanUtils; import org.w3c.dom.Document; /** * Command line entry point. Parses command line, create Cocoon bean and invokes it * with file destination. * * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a> * @author <a href="mailto:nicolaken@apache.org">Nicola Ken Barozzi</a> * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a> * @author <a href="mailto:uv@upaya.co.uk">Upayavira</a> * @version CVS $Id$ */ public class Main { protected static final String HELP_OPT = "h"; protected static final String VERSION_OPT = "v"; protected static final String VERBOSE_OPT = "V"; protected static final String LOG_KIT_OPT = "k"; protected static final String LOGGER_OPT = "l"; protected static final String LOG_LEVEL_OPT = "u"; protected static final String CONTEXT_DIR_OPT = "c"; protected static final String DEST_DIR_OPT = "d"; protected static final String WORK_DIR_OPT = "w"; protected static final String CONFIG_FILE_OPT = "C"; protected static final String BROKEN_LINK_FILE_OPT = "b"; protected static final String URI_FILE_OPT = "f"; protected static final String XCONF_OPT = "x"; protected static final String AGENT_OPT = "a"; protected static final String ACCEPT_OPT = "p"; protected static final String FOLLOW_LINKS_OPT = "r"; protected static final String PRECOMPILE_ONLY_OPT = "P"; protected static final String CONFIRM_EXTENSIONS_OPT = "e"; protected static final String LOAD_CLASS_OPT = "L"; protected static final String DEFAULT_FILENAME_OPT = "D"; protected static final String URI_GROUP_NAME_OPT = "n"; protected static final String HELP_LONG = "help"; protected static final String VERSION_LONG = "version"; protected static final String VERBOSE_LONG = "verbose"; protected static final String LOG_KIT_LONG = "logKitconfig"; protected static final String LOGGER_LONG = "Logger"; protected static final String LOG_LEVEL_LONG = "logLevel"; protected static final String CONTEXT_DIR_LONG = "contextDir"; protected static final String DEST_DIR_LONG = "destDir"; protected static final String WORK_DIR_LONG = "workDir"; protected static final String CONFIG_FILE_LONG = "configFile"; protected static final String BROKEN_LINK_FILE_LONG = "brokenLinkFile"; protected static final String URI_FILE_LONG = "uriFile"; protected static final String XCONF_LONG = "xconf"; protected static final String AGENT_LONG = "userAgent"; protected static final String ACCEPT_LONG = "accept"; protected static final String FOLLOW_LINKS_LONG = "followLinks"; protected static final String PRECOMPILE_ONLY_LONG = "precompileOnly"; protected static final String CONFIRM_EXTENSIONS_LONG = "confirmExtensions"; protected static final String LOAD_CLASS_LONG = "loadClass"; protected static final String DEFAULT_FILENAME_LONG = "defaultFilename"; protected static final String URI_LONG = "uri"; protected static final String URI_GROUP_NAME_LONG = "uris"; private static Options options; private static OutputStreamListener listener; private static void setOptions() { options = new Options(); options.addOption(new Option(HELP_OPT, HELP_LONG, false, "print this message and exit")); options.addOption(new Option(VERSION_OPT, VERSION_LONG, false, "print the version information and exit")); options.addOption(new Option(VERBOSE_OPT, VERBOSE_LONG, false, "enable verbose messages to System.out")); options.addOption(new Option(LOG_KIT_OPT, LOG_KIT_LONG, true, "use given file for LogKit Management configuration")); options.addOption(new Option(LOGGER_OPT, LOGGER_LONG, true, "use given logger category as default logger for the Cocoon engine")); options.addOption(new Option(LOG_LEVEL_OPT, LOG_LEVEL_LONG, true, "choose the minimum log level for logging (DEBUG, INFO, WARN, ERROR, FATAL_ERROR) for startup logging")); options.addOption(new Option(CONTEXT_DIR_OPT, CONTEXT_DIR_LONG, true, "use given dir as context")); options.addOption(new Option(DEST_DIR_OPT, DEST_DIR_LONG, true, "use given dir as destination")); options.addOption(new Option(WORK_DIR_OPT, WORK_DIR_LONG, true, "use given dir as working directory")); options.addOption(new Option(CONFIG_FILE_OPT, CONFIG_FILE_LONG, true, "specify alternate location of the configuration" + " file (default is ${contextDir}/cocoon.xconf)")); options.addOption(new Option(BROKEN_LINK_FILE_OPT, BROKEN_LINK_FILE_LONG, true, "send a list of broken links to a file (one URI per line)")); options.addOption(new Option(URI_FILE_OPT, URI_FILE_LONG, true, "use a text file with uris to process (one URI per line)")); options.addOption(new Option(XCONF_OPT, XCONF_LONG, true, "specify a file containing XML configuration details" + " for the command line interface")); options.addOption(new Option(AGENT_OPT, AGENT_LONG, true, "use given string for user-agent header")); options.addOption(new Option(ACCEPT_OPT, ACCEPT_LONG, true, "use given string for accept header")); options.addOption(new Option(FOLLOW_LINKS_OPT, FOLLOW_LINKS_LONG, true, "process pages linked from starting page or not" + " (boolean argument is expected, default is true)")); options.addOption(new Option(PRECOMPILE_ONLY_OPT, PRECOMPILE_ONLY_LONG, true, "generate java code for xsp and xmap files")); options.addOption(new Option(CONFIRM_EXTENSIONS_OPT, CONFIRM_EXTENSIONS_LONG, true, "confirm that file extensions match mime-type of" + " pages and amend filename accordingly (default" + " is true)")); options.addOption(new Option(LOAD_CLASS_OPT, LOAD_CLASS_LONG, true, "specify a class to be loaded at startup (specifically" + " for use with JDBC). Can be used multiple times")); options.addOption(new Option(DEFAULT_FILENAME_OPT, DEFAULT_FILENAME_LONG, true, "specify a filename to be appended to a URI when the" + " URI refers to a directory")); options.addOption(new Option(URI_GROUP_NAME_OPT, URI_GROUP_NAME_LONG, true, "specify which <uris> element to process in the configuration" + " file specified with the -x parameter")); } /** * The <code>main</code> method. * * @param args a <code>String[]</code> of arguments * @exception Exception if an error occurs */ public static void main(String[] args) throws Exception { Main.setOptions(); CommandLine line = new PosixParser().parse( options, args ); listener = new OutputStreamListener(System.out); CocoonBean cocoon = new CocoonBean(); cocoon.addListener(listener); if (line.hasOption(HELP_OPT)) { printUsage(); } else if (line.hasOption(VERSION_OPT)) { printVersion(); } else { String uriGroup = null; if (line.hasOption(URI_GROUP_NAME_OPT)) { uriGroup = line.getOptionValue(URI_GROUP_NAME_OPT); } String destDir = null; if (line.hasOption(XCONF_OPT)) { // destDir from command line overrides one in xconf file destDir = Main.processXConf(cocoon, line.getOptionValue(XCONF_OPT), destDir, uriGroup); } if (line.hasOption(DEST_DIR_OPT)) { destDir = line.getOptionValue(DEST_DIR_OPT); } if (line.hasOption(VERBOSE_OPT)) { cocoon.setVerbose(true); } if (line.hasOption(PRECOMPILE_ONLY_OPT)) { cocoon.setPrecompileOnly(true); } if (line.hasOption(WORK_DIR_OPT)) { String workDir = line.getOptionValue(WORK_DIR_OPT); if (workDir.length() == 0) { listener.messageGenerated( "Careful, you must specify a work dir when using the -w/--workDir argument"); System.exit(1); } else { cocoon.setWorkDir(line.getOptionValue(WORK_DIR_OPT)); } } if (line.hasOption(CONTEXT_DIR_OPT)) { String contextDir = line.getOptionValue(CONTEXT_DIR_OPT); if (contextDir.length() == 0) { listener.messageGenerated( "Careful, you must specify a configuration file when using the -c/--contextDir argument"); System.exit(1); } else { cocoon.setContextDir(contextDir); } } if (line.hasOption(CONFIG_FILE_OPT)) { cocoon.setConfigFile(line.getOptionValue(CONFIG_FILE_OPT)); } if (line.hasOption(LOG_KIT_OPT)) { cocoon.setLogKit(line.getOptionValue(LOG_KIT_OPT)); } if (line.hasOption(LOGGER_OPT)) { cocoon.setLogger(line.getOptionValue(LOGGER_OPT)); } if (line.hasOption(LOG_LEVEL_OPT)) { cocoon.setLogLevel(line.getOptionValue(LOG_LEVEL_OPT)); } if (line.hasOption(AGENT_OPT)) { cocoon.setAgentOptions(line.getOptionValue(AGENT_OPT)); } if (line.hasOption(ACCEPT_OPT)) { cocoon.setAcceptOptions(line.getOptionValue(ACCEPT_OPT)); } if (line.hasOption(DEFAULT_FILENAME_OPT)) { cocoon.setDefaultFilename(line.getOptionValue(DEFAULT_FILENAME_OPT)); } if (line.hasOption(BROKEN_LINK_FILE_OPT)) { listener.setReportFile(line.getOptionValue(BROKEN_LINK_FILE_OPT)); } if (line.hasOption(FOLLOW_LINKS_OPT)) { cocoon.setFollowLinks(BooleanUtils.toBoolean(line.getOptionValue(FOLLOW_LINKS_OPT))); } if (line.hasOption(CONFIRM_EXTENSIONS_OPT)) { cocoon.setConfirmExtensions(BooleanUtils.toBoolean(line.getOptionValue(CONFIRM_EXTENSIONS_OPT, "yes"))); } if (line.hasOption(LOAD_CLASS_OPT)){ cocoon.addLoadedClasses(Arrays.asList(line.getOptionValues(LOAD_CLASS_OPT))); } if (line.hasOption(URI_FILE_OPT)) { cocoon.addTargets(BeanConfigurator.processURIFile(line.getOptionValue(URI_FILE_OPT)), destDir); } cocoon.addTargets(line.getArgList(), destDir); listener.messageGenerated(CocoonBean.getProlog()); if (cocoon.getTargetCount() == 0 && cocoon.isPrecompileOnly()) { listener.messageGenerated("Please, specify at least one starting URI."); System.exit(1); } cocoon.initialize(); cocoon.process(); cocoon.dispose(); listener.complete(); int exitCode = (listener.isSuccessful() ? 0 : 1); System.exit(exitCode); } } private static String processXConf(CocoonBean cocoon, String filename, String destDir, String uriGroup) { try { final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); final Document xconf = builder.parse(new File(filename).toURL().toExternalForm()); return BeanConfigurator.configure(xconf, cocoon, destDir, uriGroup, listener); } catch (Exception e) { System.out.println("ERROR: " + e.getMessage()); return destDir; } } /** * Print the usage message and exit */ private static void printUsage() { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("cocoon cli [options] [targets]", CocoonBean.getProlog(), options, "Note: the context directory defaults to '"+ Constants.DEFAULT_CONTEXT_DIR + "'"); } /** * Print the version string and exit */ private static void printVersion() { System.out.println(Constants.VERSION); } }