es.sistedes.handle.generator.Conversor.java Source code

Java tutorial

Introduction

Here is the source code for es.sistedes.handle.generator.Conversor.java

Source

/*******************************************************************************
* Copyright (c) 2016 Sistedes
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Abel Gmez - initial API and implementation
*******************************************************************************/

package es.sistedes.handle.generator;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.lang3.text.StrSubstitutor;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * A {@link Conversor} class that transforms Wordpress XML dump into a Handle
 * batch text file.
 * 
 * The lifecycle of the {@link InputStream} and {@link OutputStream} used within
 * this class must be controlled by the caller. This class, does not perform any
 * close action in such streams. By default, this class uses <code>stdin</code>
 * and <code>stdout</code> as input and output streams.
 * 
 * @author agomez
 *
 */
public class Conversor {

    private static final Properties commands = new Properties();

    static {
        configureCommands(commands);
    }

    private String prefix;
    private InputStream input;
    private OutputStream output;
    private Map<ConversorOptions, Object> options;

    public Conversor(String prefix) {
        this.prefix = prefix;
        this.input = System.in;
        this.output = System.out;
        this.options = new HashMap<ConversorOptions, Object>();
    }

    /**
     * Changes the {@link InputStream} used by this {@link Conversor}
     * 
     * @param input
     */
    public void changeInput(InputStream input) {
        this.input = input;
    }

    /**
     * Changes the  {@link OutputStream} used by this {@link Conversor}
     * @param output
     */
    public void changeOutput(OutputStream output) {
        this.output = output;
    }

    /**
     * Changes the {@link ConversorOptions}
     * @param options
     */
    public void changeOptions(Map<ConversorOptions, Object> options) {
        this.options = options;
    }

    /**
     * Sets a new {@link ConversorOptions}
     * @param key
     * @param value
     */
    public void putOption(ConversorOptions key, Object value) {
        this.options.put(key, value);
    }

    /**
     * Removes the given {@link ConversorOptions}
     * 
     * @param key
     */
    public void removeOption(ConversorOptions key) {
        this.options.remove(key);
    }

    /**
     * Converts the XML data available in the <code>input</code>
     * {@link InputStream} and dumps the result in the <code>output</code>
     * {@link OutputStream}
     * 
     * @throws ConversionException
     *             If any error occurs, check
     *             {@link ConversionException#getCause()} to figure out the exact
     *             cause
     */
    public synchronized void generate() throws ConversionException {

        PrintWriter outputWriter = new PrintWriter(output);

        try {
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document doc = builder.parse(input);

            XPathFactory factory = XPathFactory.newInstance();
            XPath xpath = factory.newXPath();

            NodeList list = (NodeList) xpath.evaluate(
                    "//channel/item[link and guid and postmeta[meta_key/text()='handle']]", doc,
                    XPathConstants.NODESET);

            Boolean useGuid = useGuid();
            Boolean addDelete = addDelete();

            Map<String, String> vars = new HashMap<String, String>();
            vars.put(HandleVariables.prefix.toString(), prefix);

            for (int i = 0; i < list.getLength(); i++) {
                Node node = list.item(i);
                String handle = xpath.evaluate("postmeta[meta_key/text()='handle']/meta_value/text()", node);
                if (filter() != null) {
                    // We use a regex in the Node instead of a XPath filter in
                    // the NodeList because Java only supports XPath 1 and the
                    // "matches" function has been introduced in XPath 2
                    Pattern pattern = Pattern.compile(filter());
                    if (!pattern.matcher(handle).matches()) {
                        continue;
                    }
                }
                vars.put(HandleVariables.handle.toString(), handle);
                vars.put(HandleVariables.url.toString(),
                        useGuid ? xpath.evaluate("guid/text()", node) : xpath.evaluate("link/text()", node));

                if (addDelete) {
                    outputWriter.println(StrSubstitutor.replace(commands.get("command.delete"), vars));
                }
                outputWriter.println(StrSubstitutor.replace(commands.get("command.create"), vars));
                outputWriter.println(StrSubstitutor.replace(commands.get("command.admin"), vars));
                outputWriter.println(StrSubstitutor.replace(commands.get("command.url"), vars));
                outputWriter.println();
            }
        } catch (Exception e) {
            throw new ConversionException(e);
        } finally {
            outputWriter.flush();
        }
    }

    /**
     * Checks if {@link ConversorOptions#ADD_DELETE} option is set
     * 
     * @return
     */
    private Boolean addDelete() {
        return (Boolean) (options.get(ConversorOptions.ADD_DELETE) != null
                ? options.get(ConversorOptions.ADD_DELETE)
                : false);
    }

    /**
     * Checks if {@link ConversorOptions#USE_GUID} option is set
     * 
     * @return
     */
    private Boolean useGuid() {
        return (Boolean) (options.get(ConversorOptions.USE_GUID) != null ? options.get(ConversorOptions.USE_GUID)
                : false);
    }

    /**
     * Returns the {@link ConversorOptions#FILTER} option or <code>null</code>
     * if no filter has been specified
     * 
     * @return The filter or <code>null</code>
     */
    private String filter() {
        return (String) options.get(ConversorOptions.FILTER);
    }

    /**
     * Loads the properties file containing the command strings
     * 
     * @param commands
     *            The {@link Properties} containing the commands
     */
    private static void configureCommands(Properties commands) {
        try {
            commands.load(CliLauncher.class.getResourceAsStream("commands.properties"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}