Package cz.mp.k3bg.core

Source Code of cz.mp.k3bg.core.KindlegenRunner

/*
* KindlegenRunner.java
*
*  created: 30.8.2011
*  charset: UTF-8
*  license: MIT (X11) (See LICENSE file for full license)
*/
package cz.mp.k3bg.core;

import static cz.mp.k3bg.Application.EOL;
import cz.mp.k3bg.log.LoggerManager;
import cz.mp.util.Stopwatch;
import cz.mp.util.StringUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;

/**
* Třída {@code KindlegenRunner} slouží pro vykonání programu {@code kindlegen}.
* <p>
* Testováno s {@code kindlegen} ve verzích: 1.1, 1.2, 2.3, 2.5.
* Soubory knihy by měly být kódovány v {@code UTF-8}.
* <p>
* Příklad použití:
* <tt><pre>
* Kindlegen kindlegen = Kindlegen.getKindlegen("kindlegen");
* if (kindlegen != null) {
*     KindlegenRunner kindlegenRunner = new KindlegenRunner();
*     kindlegenRunner.setKindlegen(kindlegen);
*     kindlegenRunner.setOpfFileNamePath("mybook" + file.separator + "book.opf");
*     kindlegenRunner.setOutputFileName("mybook.mobi");
*     kindlegenRunner.setKindlegenCommandOutputStream(System.out);
*     kindlegenRunner.run();
*     System.err.println("kindlegen result: " +
*             (kindlegenRunner.isInErrorState() ? "ERROR" : "OK"));
* }
* </pre></tt>
*
* @author Martin Pokorný
* @version 0.6.1
*/
public class KindlegenRunner {
   
    private static final boolean DEBUG = false;
    private static final Logger logger =
            LoggerManager.getLogger(KindlegenRunner.class, DEBUG);
   
    private Kindlegen kindlegen;
   
    /** Příznak zda {@code kindlegen} skončil s chybou
     * (řádek obsahuje text "{@code Error}"). */
    private boolean inErrorState = false;

    /** Doba běhu samotného programu {@code kindlegen}. */
    private long runtime = -1;
       
    /** */
    private String opfFileNamePath;
   
    /** */
    private String outputFileName;
   
    /** Na tento proud se zapisuje výstup programu {@code kindlegen}. */
    private OutputStream kindlegenCommandOutputStream;
   
    /** Přítomnost přepínače {@literal -c2}. */
    private boolean c2compress = false;
   
    /** Proces OS, který vykonává {@code kindlegen} se zadanými parametry. */
    private Process process;

    // -----
   
    /**
     *
     */
    public KindlegenRunner() {       
    }
   
    /**
     *
     * @param opfFileNamePath
     * @param outputFileName
     */
    public KindlegenRunner(String opfFileNamePath, String outputFileName) {
        setOpfFileNamePathImpl(opfFileNamePath);
        setOutputFileNameImpl(outputFileName);
    }
   
    /**
     *
     * @param opfFileNamePath
     * @param outputFileName
     */
    public KindlegenRunner(Kindlegen kindlegen,
            String opfFileNamePath, String outputFileName) {
        setKindlegenImpl(kindlegen);
        setOpfFileNamePathImpl(opfFileNamePath);
        setOutputFileNameImpl(outputFileName);
    }
   
    /**
     * Vykoná {@code kindlegen} s parametry.
     *
     * @return  řádky s výstupem programu {@code kindlegen}; viz
     *      {@linkplain #setKindlegenCommandOutputStream(java.io.OutputStream)}.
     * @throws IOException
     * @throws IllegalStateException
     */
    public String[] run() throws IOException {
        logger.info("");
        testStateForRun();
       
        // Sem se také zapisuje výstup programu {@code kindlegen}.
        List<String> outputLines = new ArrayList<String>();
        inErrorState = false;
        Stopwatch runtimeStopwatch = new Stopwatch();
        runtimeStopwatch.start();

        try {
            String[] realCommandArray = assembleKindlegenCommandArray();
            logger.info("command:  " + Arrays.toString(realCommandArray));
           
            String readableCommand = createReadableCommand(realCommandArray);
            // (zde možno zapsat readableCommand do skriptu ...)
            writeToCommandOut("> " + readableCommand);

            process = Runtime.getRuntime().exec(realCommandArray);

            InputStream istream = process.getInputStream();
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(istream));

            String line;           
            while ((line = br.readLine()) != null) {
                checkErrorState(line);
                outputLines.add(line);
                logger.fine(line);
                writeToCommandOut(line);
            }

            try {
                process.waitFor();
            } catch (InterruptedException e) {
                setInErrorState(true);
                writeToCommandOut(EOL+"Error: InterruptedException!");
            }
//            if (proc.exitValue() != 0) {}      // nejde, protože kindlegen (v1.2) vrátí vždy 0
          
            br.close();
           
            logger.fine("finished!");
        } catch (IOException ex) {
            logger.warning(ex.toString());
            setInErrorState(true);
            runtime = runtimeStopwatch.stop();
           
            throw ex;
        }      
        runtime = runtimeStopwatch.stop();       
        logger.info("kindlegen runtime = " +
                runtimeStopwatch.getTimeSec() + " s");
       
        return (String[]) outputLines.toArray(new String[0])
    }

    /**
     *
     * @throws IllegalStateException
     * @see #run()
     */
    private void testStateForRun() {
        if (StringUtils.isBlank(opfFileNamePath)) {
            logger.warning("opfFileNamePath is empty!");
            throw new IllegalStateException("opfFileNamePath is empty!");
        }
        if (StringUtils.isBlank(outputFileName)) {
            logger.warning("outputFileName is empty!");
            throw new IllegalStateException("outputFileName is empty!");
       
        if (kindlegen == null) {
            logger.warning("kindlegen = null");
            throw new IllegalStateException("kindlegen = null");
        }       
    }
   
    /**
     * Zastaví vykonávání {@code kindlegen}, pokud běží.
     *
     * @see #run()
     */
    public void stop() {
        if (process == null) {
            logger.fine("process=null; skip");
        }
        else {
            logger.info("");
            process.destroy();
            setInErrorState(true);
        }
    }

    /**
     *
     * @return  Doba běhu programu {@code kindlegen}, nebo -1,
     *      pokud nebyl spuštěn.
     */
    public long getRuntime() {
        return runtime;
    }

    /**
     *
     * @param line
     */
    private void checkErrorState(String line) {
        if (line == null) {
            throw new IllegalStateException("line is null!");
        }
        if (line.toLowerCase().startsWith("error")) {
            setInErrorState(true);
        }
    }
   
    /**
     *
     * @return
     */
    public boolean isInErrorState() {
        return inErrorState;
    }

    /**
     *
     */
    private void setInErrorState(boolean inErrorState) {
        logger.fine("inErrorState = " + inErrorState);
        this.inErrorState = inErrorState;
    }
   

    /**
     *
     * @param line
     * @throws IOException
     */
    private void writeToCommandOut(String line) throws IOException {
        if (kindlegenCommandOutputStream != null) {
            kindlegenCommandOutputStream.write(line.trim().getBytes("UTF-8"));
            kindlegenCommandOutputStream.write(EOL.getBytes("UTF-8"));
        }
    }
   
    /**
     *
     * @param kindlegen
     * @throws IllegalArgumentException
     */
    public void setKindlegen(Kindlegen kindlegen) {
        setKindlegenImpl(kindlegen);
    }
   
    /**
     *
     * @param kindlegen
     * @throws IllegalArgumentException
     */   
    private void setKindlegenImpl(Kindlegen kindlegen) {
        if (kindlegen == null) {
            throw new IllegalArgumentException("kindlegen = null");
        }
        this.kindlegen = kindlegen;
    }   

    /**
     *
     * @return
     */
    public Kindlegen getKindlegen() {
        return kindlegen;
    }

    /**
     * Sestaví příkaz pro spuštění programu {@code kindlegen} s
     * parametry podle této třídy.
     *
     * @return
     */
    private String[] assembleKindlegenCommandArray() {
        if (kindlegen == null) {
            logger.warning("kindlegen = null");
            throw new IllegalArgumentException("kindlegen = null");
        }
       
        logger.fine("");

        ArrayList<String> cmds = new ArrayList<String>();
        cmds.add(kindlegen.getCommand());

        if (opfFileNamePath != null && ! opfFileNamePath.isEmpty()) {
            if (c2compress) {
                cmds.add(Kindlegen.C2_OPT);
            }
            if (kindlegen.isNoUnicodeVersion()) {
                cmds.add(Kindlegen.FORCE_UNICODE_OPT);
            }
            cmds.add(opfFileNamePath);
            if (outputFileName != null && ! outputFileName.isEmpty()) {
                cmds.add(Kindlegen.O_OPT);
                cmds.add(outputFileName);
            }
        }
        else {
            return new String[0];
        }

        return cmds.toArray(new String[0]);
    }
   
    /**
     * Části příkazu sloučí do jednoho textu.
     * Tento text lze zkopírovat do příkazové řádky, zalogovat, a pod.
     *
     * @param array
     * @return  příkaz v podobě, kterou lze předat příkazovému řádku, nebo
     *      prázdný řetězec
     * @see #assembleKindlegenCommandArray()
     */
    private static String createReadableCommand(String[] array) {
        StringBuilder sb = new StringBuilder();
        for (String cmdPart : array) {
            if (cmdPart.contains(" ")) {
                sb.append("\"").append(cmdPart).append("\"");
            }
            else {
                sb.append(cmdPart);
            }
            sb.append(" ");
        }
        return sb.toString();
    }
   
    /**
     *
     * @return
     */
    public String getOutputFileName() {
        return outputFileName;
    }
   
    /**
     *
     */
    public void setOutputFileName(String outputFileName) {
        setOutputFileNameImpl(outputFileName);
    }

    /**
     *
     */
    private void setOutputFileNameImpl(String outputFileName) {
        if (outputFileName == null) {
            throw new IllegalArgumentException("outputFileName=null");
        }
        logger.config("outputFileName = " + outputFileName);
        this.outputFileName = outputFileName;
    }

    /**
     *
     * @return
     */
    public String getOpfFileNamePath() {
        return opfFileNamePath;
    }

    /**
     *
     * @param opfFileNamePath
     */
    public void setOpfFileNamePath(String opfFileNamePath) {
        setOpfFileNamePathImpl(opfFileNamePath);
    }

    /**
     *
     * @param opfFileNamePath
     */
    private void setOpfFileNamePathImpl(String opfFileNamePath) {
        if (opfFileNamePath == null) {
            throw new IllegalArgumentException("opfFileNamePath=null");
        }       
        logger.config("opfFileNamePath = " + opfFileNamePath);
        this.opfFileNamePath = opfFileNamePath;
    }   
   
    /**
     *
     * @return
     */
    public boolean isC2compress() {
        return c2compress;
    }

    /**
     * Nastavit vyšší kompresi. Odpovídá parametru {@literal -c2}
     * programu {@code kindlegen}.
     * Způsobí pomalé sestavení.
     *
     * @param c2compress
     */
    public void setC2compress(boolean c2compress) {
        this.c2compress = c2compress;
    }

    /**
     *
     * @return
     */
    public OutputStream getKindlegenCommandOutputStream() {
        return kindlegenCommandOutputStream;
    }

    /**
     * Nastaví výstupní proud do něhož se bude průběžně zapisovat
     * std výstup programu {@code kindlegen} během vykonávání.
     *
     * @param kindlegenCommandOutputStream  (může být např. System.out)
     */
    public void setKindlegenCommandOutputStream(
            OutputStream kindlegenCommandOutputStream) {
        if (kindlegenCommandOutputStream == null) {
            throw new IllegalArgumentException(
                    "kindlegenCommandOutputStream=null");
        }          
        this.kindlegenCommandOutputStream = kindlegenCommandOutputStream;
    }
   
}   // KindlegenRunner
TOP

Related Classes of cz.mp.k3bg.core.KindlegenRunner

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.