org.eclipse.emf.cdo.server.internal.hibernate.HibernatePackageHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.cdo.server.internal.hibernate.HibernatePackageHandler.java

Source

/*
 * Copyright (c) 2008-2012 Eike Stepper (Berlin, Germany) and others.
 * 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:
 *    Eike Stepper - initial API and implementation
 *    Martin Taal  - moved code from HibernateStore to this class
 */
package org.eclipse.emf.cdo.server.internal.hibernate;

import org.eclipse.emf.cdo.common.model.CDOModelUtil;
import org.eclipse.emf.cdo.common.model.EMFUtil;
import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;
import org.eclipse.emf.cdo.server.internal.hibernate.bundle.OM;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
import org.eclipse.emf.cdo.spi.server.InternalRepository;

import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.io.IOUtil;
import org.eclipse.net4j.util.lifecycle.Lifecycle;
import org.eclipse.net4j.util.om.trace.ContextTracer;

import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.ResourceSet;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * Delegate which stores and retrieves cdo packages.
 * <p>
 * TODO extend {@link Lifecycle}. See {@link #doActivate()} and {@link #doDeactivate()}.
 *
 * @author Eike Stepper
 * @author Martin Taal
 */
public class HibernatePackageHandler extends Lifecycle {
    private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, HibernatePackageHandler.class);

    private static final boolean ZIP_PACKAGE_BYTES = true;

    private static final String CDO_PACKAGE_UNIT_ENTITY_NAME = "CDOPackageUnit"; //$NON-NLS-1$

    private static final String META_HBM_PATH = "mappings/meta.hbm.xml"; //$NON-NLS-1$

    private static final String HBM2DLL_UPDATE = "update"; //$NON-NLS-1$

    private static final String HBM2DLL_CREATE = "create"; //$NON-NLS-1$

    // made static and synchronized because apparently there can be multiple package handlers
    // in some test cases: TestExternalReferenceTest.testOneXMIResourceManyViewsOnOneResourceSet
    private static synchronized boolean writePackageUnits(InternalCDOPackageUnit[] packageUnits,
            SessionFactory sessionFactory, EPackage.Registry registry) {
        if (TRACER.isEnabled()) {
            TRACER.trace("Persisting new EPackages"); //$NON-NLS-1$
        }

        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        boolean err = true;
        boolean updated = false;

        try {
            // first store and update the packageunits and the epackages
            for (InternalCDOPackageUnit packageUnit : packageUnits) {
                final HibernateCDOPackageUnitDTO hbPackageUnitDTO = new HibernateCDOPackageUnitDTO(packageUnit);

                if (packageUnit.getPackageInfos().length > 0) {
                    final String rootNSUri = packageUnit.getTopLevelPackageInfo().getPackageURI();
                    final EPackage rootEPackage = registry.getEPackage(rootNSUri);
                    hbPackageUnitDTO.setEPackageByteArray(session,
                            EMFUtil.getEPackageBytes(rootEPackage, true, registry));
                }

                session.saveOrUpdate(CDO_PACKAGE_UNIT_ENTITY_NAME, hbPackageUnitDTO);

                updated = true;
            }

            tx.commit();
            err = false;
        } catch (Exception e) {
            e.printStackTrace(System.err);
            throw WrappedException.wrap(e);
        } finally {
            if (err) {
                tx.rollback();
            }

            session.close();
        }

        return updated;
    }

    private Configuration configuration;

    private SessionFactory sessionFactory;

    private int nextPackageID;

    private int nextClassID;

    private int nextFeatureID;

    private Collection<InternalCDOPackageUnit> packageUnits;

    private Map<String, byte[]> ePackageBlobsByRootUri = new HashMap<String, byte[]>();

    private Map<String, EPackage[]> ePackagesByRootUri = new HashMap<String, EPackage[]>();

    private HibernateStore hibernateStore;

    private boolean doDropSchema;

    /**
     * TODO Necessary to pass/store/dump the properties from the store?
     */
    public HibernatePackageHandler(HibernateStore store) {
        hibernateStore = store;
    }

    /**
     * @return the full list of EPackages registered in the PackageRegistry of the commit context as well as the EPackages
     *         registered earlier.
     * @see CommitContext#getPackageRegistry()
     * @see InternalRepository#getPackageRegistry()
     */
    public List<EPackage> getEPackages() {
        List<EPackage> ePackages = new ArrayList<EPackage>();
        final InternalRepository localRepository = hibernateStore.getRepository();

        for (EPackage ePackage : localRepository.getPackageRegistry(false).getEPackages()) {
            ePackages.add(ePackage);
        }

        for (EPackage ePackage : localRepository.getPackageRegistry(true).getEPackages()) {
            boolean alreadyPresent = false;
            for (EPackage ePackagePresent : ePackages) {
                if (ePackagePresent.getNsURI().equals(ePackage.getNsURI())) {
                    alreadyPresent = true;
                    break;
                }
            }

            if (!alreadyPresent) {
                ePackages.add(ePackage);
            }
        }

        return ePackages;
    }

    private InternalCDOPackageRegistry getPackageRegistry() {
        return hibernateStore.getRepository().getPackageRegistry();
    }

    public void writePackageUnits(InternalCDOPackageUnit[] packageUnits) {
        final boolean updated = writePackageUnits(packageUnits, getSessionFactory(), getPackageRegistry());
        if (updated) {
            reset();
            hibernateStore.reInitialize();
        }
    }

    public Collection<InternalCDOPackageUnit> getPackageUnits() {
        readPackageUnits();
        return packageUnits;
    }

    public EPackage[] loadPackageUnit(InternalCDOPackageUnit packageUnit) {
        final String nsUri = packageUnit.getTopLevelPackageInfo().getPackageURI();
        if (TRACER.isEnabled()) {
            TRACER.trace("Reading EPackages with root uri " + nsUri + " from db"); //$NON-NLS-1$ //$NON-NLS-2$
        }

        EPackage[] epacks = ePackagesByRootUri.get(nsUri);
        if (epacks == null) {
            final byte[] ePackageBlob = ePackageBlobsByRootUri.get(nsUri);
            if (ePackageBlob == null) {
                throw new IllegalArgumentException("EPackages with root uri " + nsUri + " not found"); //$NON-NLS-1$ //$NON-NLS-2$
            }

            ResourceSet resourceSet = EMFUtil.newEcoreResourceSet(getPackageRegistry());
            final EPackage rootEPackage = EMFUtil.createEPackage(nsUri, ePackageBlob, ZIP_PACKAGE_BYTES,
                    resourceSet, false);
            epacks = EMFUtil.getAllPackages(rootEPackage);
            ePackagesByRootUri.put(nsUri, epacks);
        }

        return epacks;
    }

    @SuppressWarnings("unchecked")
    protected void readPackageUnits() {
        if (packageUnits == null || packageUnits.size() == 0) {
            if (TRACER.isEnabled()) {
                TRACER.trace("Reading Package Units from db"); //$NON-NLS-1$
            }

            Session session = getSessionFactory().openSession();

            try {
                Criteria criteria = session.createCriteria(CDO_PACKAGE_UNIT_ENTITY_NAME);
                List<?> list = criteria.list();
                if (TRACER.isEnabled()) {
                    TRACER.trace("Found " + list.size() + " CDOPackageUnits in DB"); //$NON-NLS-1$ //$NON-NLS-2$
                }

                CDOModelUtil.createPackageUnit();

                packageUnits = new ArrayList<InternalCDOPackageUnit>();
                for (HibernateCDOPackageUnitDTO dto : (Collection<HibernateCDOPackageUnitDTO>) list) {
                    packageUnits.add(dto.createCDOPackageUnit(getPackageRegistry()));
                    // cache the blob because resolving the epackages right away gives errors
                    ePackageBlobsByRootUri.put(dto.getNsUri(), dto.getEPackageByteArray());
                }
            } finally {
                session.close();
            }
        }

        if (TRACER.isEnabled()) {
            TRACER.trace("Finished reading Package Units"); //$NON-NLS-1$
        }
    }

    @SuppressWarnings("deprecation")
    public synchronized SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            sessionFactory = configuration.buildSessionFactory();
        }

        return sessionFactory;
    }

    public synchronized int getNextPackageID() {
        return nextPackageID++;
    }

    public synchronized int getNextClassID() {
        return nextClassID++;
    }

    public synchronized int getNextFeatureID() {
        return nextFeatureID++;
    }

    public void reset() {
        packageUnits = null;
    }

    @Override
    protected void doActivate() throws Exception {
        super.doActivate();
        initConfiguration();
        initSchema();
    }

    @Override
    protected void doDeactivate() throws Exception {
        if (sessionFactory != null) {
            sessionFactory.close();
            sessionFactory = null;
        }

        if (doDropSchema) {
            final SchemaExport se = new SchemaExport(configuration);
            se.drop(false, true);
        }

        configuration = null;
        super.doDeactivate();
    }

    protected void initConfiguration() {
        if (TRACER.isEnabled()) {
            TRACER.trace("Initializing configuration for CDO metadata"); //$NON-NLS-1$
        }

        InputStream in = null;

        try {
            in = OM.BUNDLE.getInputStream(META_HBM_PATH);
            configuration = new Configuration();
            configuration.addInputStream(in);

            // note this store adapts the properties so create a copy from the
            // one received from the hibernate store
            final Properties props = new Properties();
            props.putAll(hibernateStore.getProperties());
            configuration.setProperties(props);

            // prevent the drop at session factory close...
            // the drop is done by the de-activate
            if (configuration.getProperty(Environment.HBM2DDL_AUTO) != null
                    && configuration.getProperty(Environment.HBM2DDL_AUTO).startsWith(HBM2DLL_CREATE)) {
                doDropSchema = true;
                // note that the value create also re-creates the db and drops the old one
                configuration.setProperty(Environment.HBM2DDL_AUTO, HBM2DLL_UPDATE);
            } else {
                doDropSchema = false;
            }
        } catch (Exception ex) {
            throw WrappedException.wrap(ex);
        } finally {
            IOUtil.close(in);
        }
    }

    SystemInformation getSystemInformation() {
        Session session = getSessionFactory().openSession();
        session.beginTransaction();
        try {
            final Criteria c = session.createCriteria(SystemInformation.class);
            List<?> l = c.list();
            int records = l.size();

            final SystemInformation systemInformation;
            if (records == 0) {
                systemInformation = new SystemInformation();
                systemInformation.setFirstTime(true);
                systemInformation.setCreationTime(System.currentTimeMillis());
                session.save(systemInformation);
            } else if (records == 1) {
                systemInformation = (SystemInformation) l.get(0);
                systemInformation.setFirstTime(false);
            } else {
                throw new IllegalStateException("More than one record in the cdo_system_information table");
            }

            return systemInformation;
        } finally {
            session.getTransaction().commit();
            session.close();
        }
    }

    Map<String, String> getSystemProperties() {
        Session session = getSessionFactory().openSession();
        session.beginTransaction();

        try {
            final Map<String, String> result = new HashMap<String, String>();
            final Criteria c = session.createCriteria(SystemProperty.class);
            for (Object o : c.list()) {
                final SystemProperty systemProperty = (SystemProperty) o;
                result.put(systemProperty.getName(), systemProperty.getValue());
            }

            return result;
        } finally {
            session.getTransaction().commit();
            session.close();
        }
    }

    void setSystemProperties(Map<String, String> properties) {
        Session session = getSessionFactory().openSession();
        session.beginTransaction();

        try {
            final Map<String, SystemProperty> currentValues = new HashMap<String, SystemProperty>();
            final Criteria c = session.createCriteria(SystemProperty.class);
            for (Object o : c.list()) {
                final SystemProperty systemProperty = (SystemProperty) o;
                currentValues.put(systemProperty.getName(), systemProperty);
            }

            // update remove currentones
            final Map<String, String> newValues = new HashMap<String, String>();
            for (String key : properties.keySet()) {
                if (currentValues.containsKey(key)) {
                    final SystemProperty systemProperty = currentValues.get(key);
                    if (properties.get(key) == null) {
                        session.delete(systemProperty);
                    } else {
                        systemProperty.setValue(properties.get(key));
                        session.update(systemProperty);
                    }
                } else {
                    newValues.put(key, properties.get(key));
                }
            }

            // store the new ones
            for (String key : newValues.keySet()) {
                final SystemProperty systemProperty = new SystemProperty();
                systemProperty.setName(key);
                systemProperty.setValue(newValues.get(key));
                session.save(systemProperty);
            }
        } finally {
            session.getTransaction().commit();
            session.close();
        }
    }

    protected void initSchema() {
        if (TRACER.isEnabled()) {
            TRACER.trace("Updating db schema for Hibernate PackageHandler"); //$NON-NLS-1$
        }

        new SchemaUpdate(configuration).execute(true, true);
    }
}