Package com.documents4j.standalone

Source Code of com.documents4j.standalone.StandaloneClient$LoggingFileConsumer

package com.documents4j.standalone;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.jul.LevelChangePropagator;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.OutputStreamAppender;
import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.api.IFileConsumer;
import com.documents4j.job.RemoteConverter;
import joptsimple.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;

import java.io.Console;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.google.common.base.Preconditions.checkArgument;

/**
* A standalone client for communicating with a conversion server via command line.
*/
public class StandaloneClient {

    private static final Map<DocumentType, String> FILE_NAME_EXTENSIONS;

    static {
        FILE_NAME_EXTENSIONS = new HashMap<DocumentType, String>();
        FILE_NAME_EXTENSIONS.put(DocumentType.DOC, "doc");
        FILE_NAME_EXTENSIONS.put(DocumentType.DOCX, "docx");
        FILE_NAME_EXTENSIONS.put(DocumentType.XLS, "xls");
        FILE_NAME_EXTENSIONS.put(DocumentType.XLSX, "xlsx");
        FILE_NAME_EXTENSIONS.put(DocumentType.ODS, "ods");
        FILE_NAME_EXTENSIONS.put(DocumentType.PDF, "pdf");
        FILE_NAME_EXTENSIONS.put(DocumentType.PDFA, "pdf");
        FILE_NAME_EXTENSIONS.put(DocumentType.MHTML, "mhtml");
        FILE_NAME_EXTENSIONS.put(DocumentType.RTF, "rtf");
        FILE_NAME_EXTENSIONS.put(DocumentType.XML, "xml");
        FILE_NAME_EXTENSIONS.put(DocumentType.TEXT, "txt");
        FILE_NAME_EXTENSIONS.put(DocumentType.CSV, "csv");
    }

    private StandaloneClient() {
        throw new UnsupportedOperationException();
    }

    /**
     * Starts a standalone conversion client. Detailed documentation can be retrieved by invoking
     * the application via the command line with the {@code -?} option.
     *
     * @param args The parameters for configuring this server.
     */
    public static void main(String[] args) {
        try {
            Console console = System.console();
            if (console == null) {
                System.out.println("This application can only be used from the command line.");
                System.exit(-1);
            }
            IConverter converter = asConverter(args);
            try {
                Logger logger = LoggerFactory.getLogger(StandaloneClient.class);
                sayHello(converter, logger, console);
                DocumentType[] documentTypes = configureConversion(console, converter.getSupportedConversions());
                console.printf("Enter '<source> [-> <target>]' for converting a file. Enter '\\q' for exiting this application.%n");
                String argument;
                do {
                    console.printf("> ");
                    argument = console.readLine();
                    if (argument != null) {
                        if (argument.equals("\\q")) {
                            break;
                        } else if (argument.equals("\\f")) {
                            documentTypes = configureConversion(console, converter.getSupportedConversions());
                        } else if (argument.trim().equals("")) {
                            continue;
                        }
                        int targetIndex = argument.indexOf("->");
                        String source = targetIndex == -1 ? argument : argument.substring(0, targetIndex);
                        File sourceFile = normalize(source);
                        if (!sourceFile.isFile()) {
                            console.printf("Input file does not exist: %s%n", sourceFile);
                            continue;
                        }
                        String target = targetIndex == -1 ? source + "." + extensionFor(documentTypes[1]) : argument.substring(targetIndex + 1);
                        File targetFile = normalize(target);
                        converter.convert(sourceFile).as(documentTypes[0])
                                .to(targetFile, new LoggingFileConsumer(sourceFile, logger)).as(documentTypes[1])
                                .schedule();
                        console.printf("Scheduled conversion: %s -> %s%n", sourceFile, targetFile);
                        logger.info("Converting {} to {}", sourceFile, targetFile);
                    } else {
                        logger.error("Error when reading from console.");
                    }
                } while (argument != null);
                sayGoodbye(converter, logger);
            } finally {
                converter.shutDown();
            }
            console.printf("The connection was successfully closed. Goodbye!%n");
        } catch (Exception e) {
            LoggerFactory.getLogger(StandaloneClient.class).error("The document conversion client terminated with an unexpected error", e);
            System.err.println(String.format("Error: %s", e.getMessage()));
            System.err.println("Use option -? to display a list of legal commands.");
            System.exit(-1);
        }
    }

    private static DocumentType[] configureConversion(Console console, Map<DocumentType, Set<DocumentType>> supportedConversions) {
        console.printf("The connected converter supports the following conversion formats:%n");
        Map<Integer, DocumentType[]> conversionsByIndex = new HashMap<Integer, DocumentType[]>();
        int index = 0;
        for (Map.Entry<DocumentType, Set<DocumentType>> entry : supportedConversions.entrySet()) {
            for (DocumentType targetType : entry.getValue()) {
                conversionsByIndex.put(index, new DocumentType[]{entry.getKey(), targetType});
                console.printf("  | [%d]: '%s' -> '%s'%n", index++, entry.getKey(), targetType);
            }
        }
        do {
            console.printf("Enter the number of the conversion you want to perform: ");
            try {
                int choice = Integer.parseInt(console.readLine());
                DocumentType[] conversion = conversionsByIndex.get(choice);
                if (conversion != null) {
                    console.printf("Converting '%s' to '%s'. You can change this setup by entering '\\f'.%n", conversion[0], conversion[1]);
                    return conversion;
                }
                console.printf("The number you provided is not among the legal choices%n");
            } catch (RuntimeException e) {
                console.printf("You did not provide a number%n");
            }
        } while (true);
    }

    private static String extensionFor(DocumentType documentType) {
        String fileNameExtension = FILE_NAME_EXTENSIONS.get(documentType);
        return fileNameExtension == null ? "converted" : fileNameExtension;
    }

    private static File normalize(String path) {
        File absolute = new File(path);
        if (absolute.isAbsolute()) {
            return absolute;
        } else {
            return new File(System.getProperty("user.dir"), path);
        }
    }

    private static IConverter asConverter(String[] args) throws IOException {

        OptionParser optionParser = new OptionParser();

        OptionSpec<?> helpSpec = makeHelpSpec(optionParser);

        NonOptionArgumentSpec<URI> baseUriSpec = makeBaseUriSpec(optionParser);

        ArgumentAcceptingOptionSpec<Long> requestTimeoutSpec = makeRequestTimeoutSpec(optionParser);

        ArgumentAcceptingOptionSpec<File> logFileSpec = makeLogFileSpec(optionParser);
        ArgumentAcceptingOptionSpec<Level> logLevelSpec = makeLogLevelSpec(optionParser);

        OptionSet optionSet;
        try {
            optionSet = optionParser.parse(args);
        } catch (OptionException e) {
            System.out.println("The converter was started with unknown arguments: " + e.options());
            optionParser.printHelpOn(System.out);
            System.exit(-1);
            throw e; // System.exit does not guarantee a JVM exit.
        }

        if (optionSet.has(helpSpec)) {
            optionParser.printHelpOn(System.out);
            System.exit(0);
        }

        URI baseUri = baseUriSpec.value(optionSet);
        if (baseUri == null) {
            System.out.println("No base URI parameter specified. (Use: <command> <base URI>)");
            System.exit(-1);
        }

        long requestTimeout = requestTimeoutSpec.value(optionSet);
        checkArgument(requestTimeout >= 0L, "The request timeout timeout must not be negative");

        File logFile = logFileSpec.value(optionSet);
        Level level = logLevelSpec.value(optionSet);
        configureLogging(logFile, level);

        System.out.println("Connecting to: " + baseUri);

        return RemoteConverter.builder()
                .requestTimeout(requestTimeout, TimeUnit.MILLISECONDS)
                .baseUri(baseUri)
                .build();
    }

    private static void configureLogging(File logFile, Level level) {
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        OutputStreamAppender<ILoggingEvent> appender;
        if (logFile == null) {
            appender = configureConsoleLogging(loggerContext);
        } else {
            appender = configureFileLogging(logFile, loggerContext);
        }
        System.out.println("Logging: The log level is set to " + level);
        PatternLayoutEncoder patternLayoutEncoder = new PatternLayoutEncoder();
        patternLayoutEncoder.setPattern(LogDescription.LOG_PATTERN);
        patternLayoutEncoder.setContext(loggerContext);
        patternLayoutEncoder.start();
        appender.setEncoder(patternLayoutEncoder);
        appender.start();
        ch.qos.logback.classic.Logger rootLogger = loggerContext.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
        loggerContext.stop();
        rootLogger.detachAndStopAllAppenders();
        rootLogger.addAppender(appender);
        rootLogger.setLevel(level);
        SLF4JBridgeHandler.removeHandlersForRootLogger();
        SLF4JBridgeHandler.install();
        LevelChangePropagator levelChangePropagator = new LevelChangePropagator();
        levelChangePropagator.setResetJUL(true);
        levelChangePropagator.setContext(loggerContext);
        levelChangePropagator.start();
        loggerContext.addListener(levelChangePropagator);
        loggerContext.start();
    }

    private static OutputStreamAppender<ILoggingEvent> configureConsoleLogging(LoggerContext loggerContext) {
        ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<ILoggingEvent>();
        consoleAppender.setName("com.documents4j.logger.client.console");
        consoleAppender.setContext(loggerContext);
        System.out.println("Logging: The log is printed to the console");
        return consoleAppender;
    }

    private static OutputStreamAppender<ILoggingEvent> configureFileLogging(File logFile, LoggerContext loggerContext) {
        RollingFileAppender<ILoggingEvent> rollingFileAppender = new RollingFileAppender<ILoggingEvent>();
        rollingFileAppender.setFile(logFile.getAbsolutePath());
        rollingFileAppender.setName("com.documents4j.logger.client.file");
        rollingFileAppender.setContext(loggerContext);
        FixedWindowRollingPolicy fixedWindowRollingPolicy = new FixedWindowRollingPolicy();
        fixedWindowRollingPolicy.setFileNamePattern(logFile.getAbsolutePath() + ".%i.gz");
        fixedWindowRollingPolicy.setMaxIndex(LogDescription.MAXIMUM_LOG_HISTORY_INDEX);
        fixedWindowRollingPolicy.setContext(loggerContext);
        fixedWindowRollingPolicy.setParent(rollingFileAppender);
        SizeBasedTriggeringPolicy<ILoggingEvent> sizeBasedTriggeringPolicy = new SizeBasedTriggeringPolicy<ILoggingEvent>();
        sizeBasedTriggeringPolicy.setMaxFileSize(LogDescription.MAXIMUM_LOG_FILE_SIZE);
        sizeBasedTriggeringPolicy.setContext(loggerContext);
        rollingFileAppender.setRollingPolicy(fixedWindowRollingPolicy);
        rollingFileAppender.setTriggeringPolicy(sizeBasedTriggeringPolicy);
        sizeBasedTriggeringPolicy.start();
        fixedWindowRollingPolicy.start();
        System.out.println("Logging: The log is written to " + logFile);
        return rollingFileAppender;
    }

    private static NonOptionArgumentSpec<URI> makeBaseUriSpec(OptionParser optionParser) {
        return optionParser.nonOptions(CommandDescription.DESCRIPTION_BASE_URI).ofType(URI.class);
    }

    private static ArgumentAcceptingOptionSpec<Long> makeRequestTimeoutSpec(OptionParser optionParser) {
        return optionParser
                .acceptsAll(Arrays.asList(
                                CommandDescription.ARGUMENT_LONG_REQUEST_TIMEOUT,
                                CommandDescription.ARGUMENT_SHORT_REQUEST_TIMEOUT),
                        CommandDescription.DESCRIPTION_CONTEXT_REQUEST_TIMEOUT
                )
                .withRequiredArg()
                .describedAs(CommandDescription.DESCRIPTION_ARGUMENT_REQUEST_TIMEOUT)
                .ofType(Long.class)
                .defaultsTo(RemoteConverter.Builder.DEFAULT_REQUEST_TIMEOUT);
    }

    private static ArgumentAcceptingOptionSpec<File> makeLogFileSpec(OptionParser optionParser) {
        return optionParser
                .acceptsAll(Arrays.asList(
                                CommandDescription.ARGUMENT_LONG_LOG_TO_FILE,
                                CommandDescription.ARGUMENT_SHORT_LOG_TO_FILE),
                        CommandDescription.DESCRIPTION_CONTEXT_LOG_TO_FILE
                )
                .withRequiredArg()
                .describedAs(CommandDescription.DESCRIPTION_ARGUMENT_LOG_TO_FILE)
                .ofType(File.class);
        // defaults to null such that all log information is written to the console
    }

    private static ArgumentAcceptingOptionSpec<Level> makeLogLevelSpec(OptionParser optionParser) {
        return optionParser
                .acceptsAll(Arrays.asList(
                                CommandDescription.ARGUMENT_LONG_LOG_LEVEL,
                                CommandDescription.ARGUMENT_SHORT_LOG_LEVEL),
                        CommandDescription.DESCRIPTION_CONTEXT_LOG_LEVEL
                )
                .withRequiredArg()
                .describedAs(CommandDescription.DESCRIPTION_ARGUMENT_LOG_LEVEL)
                .withValuesConvertedBy(new LogLevelValueConverter())
                .defaultsTo(Level.WARN);
    }

    private static OptionSpec<Void> makeHelpSpec(OptionParser optionParser) {
        return optionParser
                .acceptsAll(Arrays.asList(
                                CommandDescription.ARGUMENT_LONG_HELP,
                                CommandDescription.ARGUMENT_SHORT_HELP),
                        CommandDescription.DESCRIPTION_CONTEXT_HELP
                )
                .forHelp();
    }

    private static void sayHello(IConverter converter, Logger logger, Console console) {
        console.printf("Welcome to the documents4j client!%n");
        boolean operational = converter.isOperational();
        if (operational) {
            logger.info("Converter {} is operational", converter);
        } else {
            logger.warn("Converter {} is not operational", converter);
        }
    }

    private static void sayGoodbye(IConverter converter, Logger logger) {
        System.out.println("Disconnecting converter client...");
        logger.info("Converter {} is disconnecting", converter);
    }

    private static class LoggingFileConsumer implements IFileConsumer {

        private final File sourceFile;
        private final Logger logger;

        private LoggingFileConsumer(File sourceFile, Logger logger) {
            this.sourceFile = sourceFile;
            this.logger = logger;
        }

        @Override
        public void onComplete(File file) {
            logger.info("Successfully converted {} to {}", sourceFile, file);
        }

        @Override
        public void onCancel(File file) {
            logger.warn("Conversion from {} to {} was cancelled", sourceFile, file);
        }

        @Override
        public void onException(File file, Exception e) {
            logger.error("Could not convert {} to {}", sourceFile, file, e);
        }
    }
}
TOP

Related Classes of com.documents4j.standalone.StandaloneClient$LoggingFileConsumer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.