blob: 33c689963e7fb917e0a75c281733c0712ed29cf6 [file] [log] [blame]
/*
* 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);
}
}