org.snipsnap.snip.XMLSnipImport.java Source code

Java tutorial

Introduction

Here is the source code for org.snipsnap.snip.XMLSnipImport.java

Source

/*
 * This file is part of "SnipSnap Wiki/Weblog".
 *
 * Copyright (c) 2002 Stephan J. Schmidt, Matthias L. Jugel
 * All Rights Reserved.
 *
 * Please visit http://snipsnap.org/ for updates and contact.
 *
 * --LICENSE NOTICE--
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 * --LICENSE NOTICE--
 */
package org.snipsnap.snip;

import org.apache.commons.codec.binary.Base64;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.ElementHandler;
import org.dom4j.ElementPath;
import org.dom4j.io.SAXReader;
import org.radeox.util.logging.Logger;
import snipsnap.api.app.Application;
import snipsnap.api.config.Configuration;
import snipsnap.api.container.Components;
import org.snipsnap.jdbc.IntHolder;
import org.snipsnap.snip.storage.SnipSerializer;
import org.snipsnap.snip.storage.UserSerializer;
import snipsnap.api.user.User;
import org.snipsnap.user.UserManager;
import org.snipsnap.versioning.VersionManager;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import snipsnap.api.snip.*;
import snipsnap.api.snip.SnipSpace;
import snipsnap.api.snip.Snip;

/**
 * Helper class for importing serialized database backups.
 *
 * @author Matthias L. Jugel
 * @version $Id$
 */
public class XMLSnipImport {
    public final static int IMPORT_USERS = 0x01;
    public final static int IMPORT_SNIPS = 0x02;
    public final static int OVERWRITE = 0x04;

    private static ThreadLocal instance = new ThreadLocal() {
        protected synchronized Object initialValue() {
            return new HashMap();
        }
    };

    public static IntHolder getStatus() {
        IntHolder current = (IntHolder) ((Map) instance.get()).get("current");
        if (null == current) {
            current = new IntHolder(0);
            ((Map) instance.get()).put("current", current);
        }
        return current;
    }

    private static long charErrCount = 0;

    /**
     * Load snips and users into the SnipSpace from an xml document out of a stream.
     *
     * @param in    the input stream to load from
     * @param flags whether or not to overwrite existing content
     */
    public static void load(InputStream in, final int flags) throws IOException {
        SAXReader saxReader = new SAXReader();
        try {
            saxReader.addHandler("/snipspace/user", new ElementHandler() {
                public void onStart(ElementPath elementPath) {
                    // nothing to do here ...
                }

                public void onEnd(ElementPath elementPath) {
                    Element userElement = elementPath.getCurrent();
                    if ((flags & IMPORT_USERS) != 0) {
                        try {
                            XMLSnipImport.loadUser(elementPath.getCurrent(), flags);
                        } catch (Exception e) {
                            Logger.fatal("XMLSnipImport: error importing user: " + userElement.elementText("name"));
                        }
                        getStatus().inc();
                    }
                    // prune the element to save memory
                    userElement.detach();
                }
            });

            saxReader.addHandler("/snipspace/snip", new ElementHandler() {
                public void onStart(ElementPath elementPath) {
                    // nothing to do here ...
                }

                public void onEnd(ElementPath elementPath) {
                    Element snipElement = elementPath.getCurrent();
                    if ((flags & IMPORT_SNIPS) != 0) {
                        try {
                            XMLSnipImport.loadSnip(snipElement, flags);
                        } catch (Exception e) {
                            Logger.fatal("XMLSnipImport: error importing snip: " + snipElement.elementText("name"));
                        }
                        getStatus().inc();
                    }
                    // prune the element to save memory
                    snipElement.detach();
                }
            });

            // add a reader wrapper to remove illegal characters from input stream
            // it looks like the database export (XMLWriter) allows these to get through
            InputStreamReader reader = new InputStreamReader(in, "UTF-8") {
                public int read(char[] chars) throws IOException {
                    int n = super.read(chars);
                    for (int i = 0; i < n; i++) {
                        chars[i] = replaceIfIllegal(chars[i]);
                    }
                    return n;
                }

                public int read(char[] chars, int start, int length) throws IOException {
                    int n = super.read(chars, start, length);
                    for (int i = 0; i < n; i++) {
                        chars[i] = replaceIfIllegal(chars[i]);
                    }
                    return n;
                }

                private char replaceIfIllegal(char c) {
                    if (c < 0x20 && !(c == 0x09 || c == 0x0a || c == 0x0d)) {
                        charErrCount++;
                        return (char) 0x20;
                    }
                    return c;
                }
            };

            saxReader.read(reader);
            Logger.warn("XMLSnipImport: corrected " + charErrCount + " characters in input");
            Logger.log("XMLSnipImport: imported " + getStatus().getValue() + " data records");
        } catch (DocumentException e) {
            Logger.warn("XMLSnipImport: unable to parse document", e);
            throw new IOException("Error parsing document: " + e);
        }
    }

    /**
     * Load a user object from a serialized xml element
     *
     * @param userElement the xml user element
     * @param flags       flags indicating overwriting any existing users or not
     */
    public static void loadUser(Element userElement, int flags) {
        Map userMap = UserSerializer.getInstance().getElementMap(userElement);
        userMap.remove(UserSerializer.USER_APPLICATION);

        String login = (String) userMap.get(UserSerializer.USER_NAME);
        String passwd = (String) userMap.get(UserSerializer.USER_PASSWORD);
        String email = (String) userMap.get(UserSerializer.USER_EMAIL);

        UserManager userManager = (UserManager) Components.getComponent(UserManager.class);
        snipsnap.api.user.User user = null;
        if (userManager.exists(login)) {
            if ((flags & OVERWRITE) == 0) {
                Logger.log("ignoring to import user '" + login + "'");
                return;
            }
            Logger.log("loading existing user '" + login + "'");
            user = userManager.load(login);
        } else {
            Logger.log("creating user '" + login + "'");
            user = userManager.create(login, passwd, email);
        }

        user = UserSerializer.getInstance().deserialize(userMap, user);
        userManager.systemStore(user);
    }

    public static void loadSnip(Element snipElement, int flags) {
        Map snipMap = SnipSerializer.getInstance().getElementMap(snipElement);
        snipMap.remove(SnipSerializer.SNIP_APPLICATION);

        String name = (String) snipMap.get(SnipSerializer.SNIP_NAME);
        String content = (String) snipMap.get(SnipSerializer.SNIP_CONTENT);

        SnipSpace space = (snipsnap.api.snip.SnipSpace) snipsnap.api.container.Components
                .getComponent(SnipSpace.class);
        Snip snip = null;
        if (space.exists(name)) {
            Logger.log("loading existing snip '" + name + "'");
            snip = space.load(name);
            if ((flags & OVERWRITE) == 0) {
                snip.setContent(snip.getContent() + content);
                snipMap.remove(SnipSerializer.SNIP_CONTENT);
            }
        } else {
            Logger.log("creating snip '" + name + "'");
            snip = space.create(name, content);
        }

        UserManager um = (UserManager) snipsnap.api.container.Components.getComponent(UserManager.class);
        snipsnap.api.user.User importUser = snipsnap.api.app.Application.get().getUser();

        // check existing users
        if (!um.exists((String) snipMap.get(SnipSerializer.SNIP_CUSER))) {
            snipMap.put(SnipSerializer.SNIP_CUSER, importUser.getLogin());
        }
        if (!um.exists((String) snipMap.get(SnipSerializer.SNIP_MUSER))) {
            snipMap.put(SnipSerializer.SNIP_MUSER, importUser.getLogin());
        }
        if (!um.exists((String) snipMap.get(SnipSerializer.SNIP_OUSER))) {
            snipMap.put(SnipSerializer.SNIP_OUSER, importUser.getLogin());
        }

        // first restore attached files, then remove the data element
        restoreAttachments(snipElement);
        snip = SnipSerializer.getInstance().deserialize(snipMap, snip);
        restoreVersions(snipElement, snip, (flags & OVERWRITE) != 0);
        snip.getBackLinks().getSize();
        // ensure that the configuration snip is stored normally
        // so the configuration is updated
        if (snipsnap.api.config.Configuration.SNIPSNAP_CONFIG.equals(snip.getName())) {
            space.store(snip);
        } else {
            space.systemStore(snip);
        }
    }

    private static void restoreAttachments(Element snipEl) {
        Configuration config = snipsnap.api.app.Application.get().getConfiguration();
        File attRoot = config.getFilePath();
        Element attachmentsEl = snipEl.element("attachments");
        if (null != attachmentsEl) {
            Iterator attIt = attachmentsEl.elements("attachment").iterator();
            while (attIt.hasNext()) {
                Element att = (Element) attIt.next();
                if (att.element("data") != null) {
                    File attFile = new File(attRoot, att.elementText("location"));
                    try {
                        // make sure the directory hierarchy exists
                        attFile.getParentFile().mkdirs();
                        byte buffer[] = Base64.decodeBase64(att.elementText("data").getBytes("UTF-8"));
                        BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(attFile));
                        os.write(buffer);
                        os.flush();
                        os.close();
                    } catch (Exception e) {
                        Logger.fatal("unable to store attachment: " + e);
                        e.printStackTrace();
                    }
                    att.element("data").detach();
                }
            }
        }
    }

    private static void restoreVersions(Element snipEl, Snip snip, boolean overwrite) {
        VersionManager versionManager = (VersionManager) Components.getComponent(VersionManager.class);
        List currentVersions = versionManager.getHistory(snip);
        if (currentVersions.size() > 0 && overwrite) {
            // TODO missing in version manager
            // versionManager.removeHistory();
        }

        currentVersions = versionManager.getHistory(snip);
        int versionNo = currentVersions.size();

        SnipSerializer serializer = SnipSerializer.getInstance();
        Element versionsEl = snipEl.element("versions");
        if (versionsEl != null) {
            Iterator versionsElIt = versionsEl.elementIterator("snip");
            while (versionsElIt.hasNext()) {
                Element versionSnipEl = (Element) versionsElIt.next();
                Snip versionSnip = serializer.deserialize(versionSnipEl, SnipFactory.createSnip("", ""));
                if (versionNo > 0) {
                    versionSnip.setVersion(versionNo++);
                }
                versionManager.storeVersion(versionSnip);
            }
        }
    }
}