/* * Copyright (c) 2008-2012, 2016 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); } }