Package org.projectforge.database.xstream

Source Code of org.projectforge.database.xstream.HibernateXmlConverter

/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition 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; version 3 of the License.
//
// This community edition 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, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////

package org.projectforge.database.xstream;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.PredicateUtils;
import org.hibernate.EntityMode;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.proxy.HibernateProxyHelper;
import org.projectforge.database.HibernateEntities;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import com.thoughtworks.xstream.MarshallingStrategy;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
import com.thoughtworks.xstream.io.xml.CompactWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.mapper.MapperWrapper;

import de.micromata.hibernate.history.delta.AssociationPropertyDelta;
import de.micromata.hibernate.history.delta.CollectionPropertyDelta;
import de.micromata.hibernate.history.delta.PropertyDelta;
import de.micromata.hibernate.history.delta.SimplePropertyDelta;
import de.micromata.hibernate.spring.NullWriter;
import de.micromata.hibernate.spring.ProxyIdRefMarshallingStrategy;

/**
* Hilfsklasse zum Laden und Speichern einer gesamten Hibernate-Datenbank im XML-Format. Zur Darstellung der Daten in XML wird XStream zur
* Serialisierung eingesetzt. Alle Lazy-Objekte aus Hibernate werden vollständig initialisiert. http://jira.codehaus.org/browse/XSTR-377
*
* @author Wolfgang Jung (w.jung@micromata.de)
*
*/
public class HibernateXmlConverter
{
  /** The logger */
  private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(HibernateXmlConverter.class);

  /** the wrapper to hibernate */
  private HibernateTemplate hibernate;

  // Ignore these objects listing in the top level list saving because the are saved implicit by their parent objects.
  private final Set<Class< ? >> ignoreFromTopLevelListing = new HashSet<Class< ? >>();

  public HibernateXmlConverter()
  {
    this.ignoreFromTopLevelListing.add(PropertyDelta.class);
    this.ignoreFromTopLevelListing.add(SimplePropertyDelta.class);
    this.ignoreFromTopLevelListing.add(AssociationPropertyDelta.class);
    this.ignoreFromTopLevelListing.add(CollectionPropertyDelta.class);
  }

  /**
   * Initialisierung der Hibernate-verbindung.
   *
   * @param hibernate ein bereits initialisiertes HibernateTemplate
   */
  public void setHibernate(final HibernateTemplate hibernate)
  {
    this.hibernate = hibernate;
  }

  /**
   * Schreibt alle Objekte der Datenbank in den angegebenen Writer.<br/>
   * <b>Warnung!</b> Bei der Serialisierung von Collections wird derzeit nur {@link java.util.Set} sauber unterstützt.
   * @param writer Ziel für die XML-Datei.
   * @param includeHistory bei false werden die History Einträge nicht geschrieben
   */
  public void dumpDatabaseToXml(final Writer writer, final boolean includeHistory)
  {
    dumpDatabaseToXml(writer, includeHistory, true);
  }

  /**
   * Schreibt alle Objekte der Datenbank in den angegebenen Writer.<br/>
   * <b>Warnung!</b> Bei der Serialisierung von Collections wird derzeit nur {@link java.util.Set} sauber unterstützt.
   * @param writer Ziel für die XML-Datei.
   * @param includeHistory bei false werden die History Einträge nicht geschrieben
   * @param preserveIds If true, the object ids will be preserved, otherwise new ids will be assigned through xstream.
   */
  public void dumpDatabaseToXml(final Writer writer, final boolean includeHistory, final boolean preserveIds)
  {
    final TransactionTemplate tx = new TransactionTemplate(new HibernateTransactionManager(hibernate.getSessionFactory()));
    tx.execute(new TransactionCallback() {
      public Object doInTransaction(final TransactionStatus status)
      {
        hibernate.execute(new HibernateCallback() {
          public Object doInHibernate(final Session session) throws HibernateException
          {
            writeObjects(writer, includeHistory, session, preserveIds);
            status.setRollbackOnly();
            return null;
          }
        });
        return null;
      }
    });
  }

  public HibernateXmlConverter appendIgnoredTopLevelObjects(final Class< ? >... types)
  {
    if (types != null) {
      for (final Class< ? > type : types) {
        this.ignoreFromTopLevelListing.add(type);
      }
    }
    return this;
  }

  /**
   * @param writer
   * @param includeHistory
   * @param session
   * @throws DataAccessException
   * @throws HibernateException
   */
  private void writeObjects(final Writer writer, final boolean includeHistory, final Session session, final boolean preserveIds)
      throws DataAccessException, HibernateException
      {
    // Container für die Objekte
    final List<Object> all = new ArrayList<Object>();
    final XStream stream = initXStream(session, true);
    final XStream defaultXStream = initXStream(session, false);

    session.flush();
    // Alles laden
    final List<Class< ? >> entities = new ArrayList<Class< ? >>();
    entities.addAll(HibernateEntities.instance().getOrderedEntities());
    entities.addAll(HibernateEntities.instance().getOrderedHistoryEntities());
    for (final Class< ? > entityClass : entities) {
      final String entitySimpleName = entityClass.getSimpleName();
      final String entityType = entityClass.getName();
      if (includeHistory == false && entityType.startsWith("de.micromata.hibernate.history.") == true) {
        // Skip history entries.
        continue;
      }
      List< ? > list = session.createQuery("select o from " + entityType + " o").setReadOnly(true).list();
      list = (List< ? >) CollectionUtils.select(list, PredicateUtils.uniquePredicate());
      final int size = list.size();
      log.info("Writing " + size + " objects");
      for (final Iterator< ? > it = list.iterator(); it.hasNext();) {
        final Object obj = it.next();
        if (log.isDebugEnabled()) {
          log.debug("loaded object " + obj);
        }
        Hibernate.initialize(obj);
        final Class< ? > targetClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj);
        final ClassMetadata classMetadata = session.getSessionFactory().getClassMetadata(targetClass);
        if (classMetadata == null) {
          log.fatal("Can't init " + obj + " of type " + targetClass);
          continue;
        }
        // initalisierung des Objekts...
        defaultXStream.marshal(obj, new CompactWriter(new NullWriter()));

        if (preserveIds == false) {
          // Nun kann die ID gelöscht werden
          classMetadata.setIdentifier(obj, null, EntityMode.POJO);
        }
        if (log.isDebugEnabled()) {
          log.debug("loading evicted object " + obj);
        }
        if (this.ignoreFromTopLevelListing.contains(targetClass) == false) {
          all.add(obj);
        }
      }
    }
    // und schreiben
    try {
      writer.write("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
    } catch (final IOException ex) {
      // ignore, will fail on stream.marshal()
    }
    log.info("Wrote " + all.size() + " objects");
    final MarshallingStrategy marshallingStrategy = new ProxyIdRefMarshallingStrategy();
    stream.setMarshallingStrategy(marshallingStrategy);
    stream.marshal(all, new PrettyPrintWriter(writer));
      }

  /**
   * Overload this method if you need further initializations before reading xml stream. Does nothing at default.
   * @param xstream
   */
  protected void init(final XStream xstream)
  {
  }

  /**
   * @return
   */
  private XStream initXStream(final Session session, final boolean nullifyPk)
  {
    final XStream xstream = new XStream() {
      @Override
      protected MapperWrapper wrapMapper(final MapperWrapper next)
      {
        return new HibernateMapper(new HibernateCollectionsMapper(next));
      }
    };
    // Converter für die Hibernate-Collections
    xstream.registerConverter(new HibernateCollectionConverter(xstream.getConverterLookup()));
    xstream.registerConverter(
        new HibernateProxyConverter(xstream.getMapper(), new PureJavaReflectionProvider(), xstream.getConverterLookup()),
        XStream.PRIORITY_VERY_HIGH);
    xstream.setMarshallingStrategy(new XStreamMarshallingStrategy(XStreamMarshallingStrategy.RELATIVE));
    init(xstream);
    return xstream;
  }
}
TOP

Related Classes of org.projectforge.database.xstream.HibernateXmlConverter

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.