com.xpn.xwiki.store.XWikiHibernateVersioningStore.java Source code

Java tutorial

Introduction

Here is the source code for com.xpn.xwiki.store.XWikiHibernateVersioningStore.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.xpn.xwiki.store;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.suigeneris.jrcs.rcs.Version;
import org.xwiki.component.annotation.Component;

import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.doc.XWikiDocumentArchive;
import com.xpn.xwiki.doc.rcs.XWikiRCSNodeContent;
import com.xpn.xwiki.doc.rcs.XWikiRCSNodeId;
import com.xpn.xwiki.doc.rcs.XWikiRCSNodeInfo;

/**
 * Realization of {@link XWikiVersioningStoreInterface} for Hibernate-based storage.
 * 
 * @version $Id: ecc5cb37ad85e1589df3173feb59ed8a1af544cb $
 */
@Component
public class XWikiHibernateVersioningStore extends XWikiHibernateBaseStore
        implements XWikiVersioningStoreInterface {
    /** Logger. */
    private static final Log LOG = LogFactory.getLog(XWikiHibernateVersioningStore.class);

    /** Colon symbol. */
    private static final String COLON = ":";

    /**
     * This allows to initialize our storage engine. The hibernate config file path is taken from xwiki.cfg or directly
     * in the WEB-INF directory.
     * 
     * @param xwiki The xwiki object
     * @param context The current context
     * @deprecated 1.6M1. use ComponentManager.lookup(XWikiVersioningStoreInterface.class) instead.
     */
    @Deprecated
    public XWikiHibernateVersioningStore(XWiki xwiki, XWikiContext context) {
        super(xwiki, context);
    }

    /**
     * Initialize the storage engine with a specific path This is used for tests.
     * 
     * @param hibpath path to hibernate.hbm.xml file
     * @deprecated 1.6M1. use ComponentManager.lookup(XWikiVersioningStoreInterface.class) instead.
     */
    @Deprecated
    public XWikiHibernateVersioningStore(String hibpath) {
        super(hibpath);
    }

    /**
     * @see #XWikiHibernateVersioningStore(XWiki, XWikiContext)
     * @param context The current context
     * @deprecated 1.6M1. use ComponentManager.lookup(XWikiVersioningStoreInterface.class) instead.
     */
    @Deprecated
    public XWikiHibernateVersioningStore(XWikiContext context) {
        this(context.getWiki(), context);
    }

    /**
     * Empty constructor needed for component manager.
     */
    public XWikiHibernateVersioningStore() {
    }

    /**
     * {@inheritDoc}
     */
    public Version[] getXWikiDocVersions(XWikiDocument doc, XWikiContext context) throws XWikiException {
        try {
            XWikiDocumentArchive archive = getXWikiDocumentArchive(doc, context);
            if (archive == null) {
                return new Version[0];
            }
            Collection<XWikiRCSNodeInfo> nodes = archive.getNodes();
            Version[] versions = new Version[nodes.size()];
            Iterator<XWikiRCSNodeInfo> it = nodes.iterator();
            for (int i = 0; i < versions.length; i++) {
                XWikiRCSNodeInfo node = it.next();
                versions[versions.length - 1 - i] = node.getId().getVersion();
            }
            return versions;
        } catch (Exception e) {
            Object[] args = { doc.getFullName() };
            throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
                    XWikiException.ERROR_XWIKI_STORE_HIBERNATE_READING_REVISIONS,
                    "Exception while reading document {0} revisions", e, args);
        }
    }

    /**
     * {@inheritDoc}
     */
    public XWikiDocumentArchive getXWikiDocumentArchive(XWikiDocument doc, XWikiContext context)
            throws XWikiException {
        XWikiDocumentArchive archiveDoc = doc.getDocumentArchive();
        if (archiveDoc != null) {
            return archiveDoc;
        }
        String key = ((doc.getDatabase() == null) ? "xwiki" : doc.getDatabase()) + COLON + doc.getFullName();
        if (!"".equals(doc.getLanguage())) {
            key = key + COLON + doc.getLanguage();
        }

        synchronized (key) {
            archiveDoc = context.getDocumentArchive(key);
            if (archiveDoc == null) {
                String db = context.getDatabase();
                try {
                    if (doc.getDatabase() != null) {
                        context.setDatabase(doc.getDatabase());
                    }
                    archiveDoc = new XWikiDocumentArchive(doc.getId());
                    loadXWikiDocArchive(archiveDoc, true, context);
                    doc.setDocumentArchive(archiveDoc);
                } finally {
                    context.setDatabase(db);
                }
                // This will also make sure that the Archive has a strong reference
                // and will not be discarded as long as the context exists.
                context.addDocumentArchive(key, archiveDoc);
            }
            return archiveDoc;
        }
    }

    /**
     * {@inheritDoc}
     */
    public void loadXWikiDocArchive(XWikiDocumentArchive archivedoc, boolean bTransaction, XWikiContext context)
            throws XWikiException {
        try {
            List<XWikiRCSNodeInfo> nodes = loadAllRCSNodeInfo(context, archivedoc.getId(), bTransaction);
            archivedoc.setNodes(nodes);
        } catch (Exception e) {
            Object[] args = { new Long(archivedoc.getId()) };
            throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
                    XWikiException.ERROR_XWIKI_STORE_HIBERNATE_LOADING_OBJECT,
                    "Exception while loading archive {0}", e, args);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void saveXWikiDocArchive(final XWikiDocumentArchive archivedoc, boolean bTransaction,
            XWikiContext context) throws XWikiException {
        executeWrite(context, bTransaction, new HibernateCallback<Object>() {
            public Object doInHibernate(Session session) throws HibernateException {
                for (XWikiRCSNodeInfo ni : archivedoc.getDeletedNodeInfo()) {
                    session.delete(ni);
                }
                archivedoc.getDeletedNodeInfo().clear();
                for (XWikiRCSNodeInfo ni : archivedoc.getUpdatedNodeInfos()) {
                    session.saveOrUpdate(ni);
                }
                archivedoc.getUpdatedNodeInfos().clear();
                for (XWikiRCSNodeContent nc : archivedoc.getUpdatedNodeContents()) {
                    session.update(nc);
                }
                archivedoc.getUpdatedNodeContents().clear();
                return null;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    public XWikiDocument loadXWikiDoc(XWikiDocument basedoc, String sversion, XWikiContext context)
            throws XWikiException {
        XWikiDocumentArchive archive = getXWikiDocumentArchive(basedoc, context);
        Version version = new Version(sversion);

        XWikiDocument doc = archive.loadDocument(version, context);
        if (doc == null) {
            Object[] args = { basedoc.getFullName(), version.toString() };
            throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
                    XWikiException.ERROR_XWIKI_STORE_HIBERNATE_UNEXISTANT_VERSION,
                    "Version {1} does not exist while reading document {0}", null, args);
        }
        // Make sure the document has the same name
        // as the new document (in case there was a name change
        doc.setName(basedoc.getName());
        doc.setSpace(basedoc.getSpace());

        doc.setDatabase(basedoc.getDatabase());
        doc.setStore(basedoc.getStore());
        return doc;
    }

    /**
     * {@inheritDoc}
     */
    public void resetRCSArchive(final XWikiDocument doc, boolean bTransaction, final XWikiContext context)
            throws XWikiException {
        executeWrite(context, true, new HibernateCallback<Object>() {
            public Object doInHibernate(Session session) throws HibernateException, XWikiException {
                XWikiDocumentArchive archive = getXWikiDocumentArchive(doc, context);
                archive.resetArchive();
                archive.getDeletedNodeInfo().clear();
                doc.setMinorEdit(false);
                deleteArchive(doc, false, context);
                updateXWikiDocArchive(doc, false, context);
                return null;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    public void updateXWikiDocArchive(XWikiDocument doc, boolean bTransaction, XWikiContext context)
            throws XWikiException {
        try {
            XWikiDocumentArchive archiveDoc = getXWikiDocumentArchive(doc, context);
            archiveDoc.updateArchive(doc, doc.getAuthor(), doc.getDate(), doc.getComment(), doc.getRCSVersion(),
                    context);
            doc.setRCSVersion(archiveDoc.getLatestVersion());
            saveXWikiDocArchive(archiveDoc, bTransaction, context);
        } catch (Exception e) {
            Object[] args = { doc.getFullName() };
            throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
                    XWikiException.ERROR_XWIKI_STORE_HIBERNATE_SAVING_OBJECT,
                    "Exception while updating archive {0}", e, args);
        }
    }

    /**
     * {@inheritDoc}
     */
    protected List<XWikiRCSNodeInfo> loadAllRCSNodeInfo(XWikiContext context, final long id, boolean bTransaction)
            throws XWikiException {
        return executeRead(context, bTransaction, new HibernateCallback<List<XWikiRCSNodeInfo>>() {
            @SuppressWarnings("unchecked")
            public List<XWikiRCSNodeInfo> doInHibernate(Session session) throws HibernateException {
                try {
                    return session.createCriteria(XWikiRCSNodeInfo.class)
                            .add(Restrictions.eq("id.docId", Long.valueOf(id))).add(Restrictions.isNotNull("diff"))
                            .list();
                } catch (IllegalArgumentException ex) {
                    // This happens when the database has wrong values...
                    LOG.warn("Invalid history for document " + id);
                    return Collections.emptyList();
                }
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    public XWikiRCSNodeContent loadRCSNodeContent(final XWikiRCSNodeId id, boolean bTransaction,
            XWikiContext context) throws XWikiException {
        return executeRead(context, bTransaction, new HibernateCallback<XWikiRCSNodeContent>() {
            public XWikiRCSNodeContent doInHibernate(Session session) throws HibernateException {
                XWikiRCSNodeContent content = new XWikiRCSNodeContent(id);
                session.load(content, content.getId());
                return content;
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    public void deleteArchive(final XWikiDocument doc, boolean bTransaction, XWikiContext context)
            throws XWikiException {
        executeWrite(context, bTransaction, new HibernateCallback<Object>() {
            public Object doInHibernate(Session session) throws HibernateException, XWikiException {
                session.createQuery("delete from " + XWikiRCSNodeInfo.class.getName() + " where id.docId=?")
                        .setLong(0, doc.getId()).executeUpdate();
                return null;
            }
        });
    }
}