2013-10-06 12:32:57 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2012, Robert von Burg
|
|
|
|
*
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This file is part of the XXX.
|
|
|
|
*
|
|
|
|
* XXX 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, either version 3 of the License,
|
|
|
|
* or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* XXX 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 XXX. If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2013-10-15 22:26:58 +02:00
|
|
|
package ch.eitchnet.xmlpers.impl;
|
2013-10-06 12:32:57 +02:00
|
|
|
|
2013-10-15 22:26:58 +02:00
|
|
|
import java.text.MessageFormat;
|
2013-10-06 12:32:57 +02:00
|
|
|
import java.util.List;
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
import ch.eitchnet.utils.helper.StringHelper;
|
|
|
|
import ch.eitchnet.utils.objectfilter.ObjectFilter;
|
2013-10-15 22:26:58 +02:00
|
|
|
import ch.eitchnet.xmlpers.api.FileDao;
|
|
|
|
import ch.eitchnet.xmlpers.api.IoMode;
|
|
|
|
import ch.eitchnet.xmlpers.api.MetadataDao;
|
|
|
|
import ch.eitchnet.xmlpers.api.ObjectDao;
|
2013-10-06 12:32:57 +02:00
|
|
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
2013-10-15 22:26:58 +02:00
|
|
|
import ch.eitchnet.xmlpers.api.PersistenceRealm;
|
|
|
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
|
|
|
import ch.eitchnet.xmlpers.api.TransactionCloseStrategy;
|
|
|
|
import ch.eitchnet.xmlpers.api.XmlPersistenceException;
|
|
|
|
import ch.eitchnet.xmlpers.objref.ObjectReferenceCache;
|
2013-10-06 12:32:57 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public class DefaultPersistenceTransaction implements PersistenceTransaction {
|
|
|
|
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(DefaultPersistenceTransaction.class);
|
|
|
|
|
2013-10-15 22:26:58 +02:00
|
|
|
private final DefaultPersistenceRealm realm;
|
|
|
|
private final boolean verbose;
|
|
|
|
|
|
|
|
private final ObjectFilter objectFilter;
|
2013-10-06 12:32:57 +02:00
|
|
|
private final ObjectDao objectDao;
|
|
|
|
private final MetadataDao metadataDao;
|
2013-10-15 22:26:58 +02:00
|
|
|
|
|
|
|
private FileDao fileDao;
|
2013-10-06 12:32:57 +02:00
|
|
|
|
2013-10-06 18:42:55 +02:00
|
|
|
private boolean committed;
|
2013-10-06 12:32:57 +02:00
|
|
|
private boolean closed;
|
|
|
|
|
2013-10-15 22:26:58 +02:00
|
|
|
private IoMode ioMode;
|
2013-10-06 18:42:55 +02:00
|
|
|
|
2013-10-15 22:26:58 +02:00
|
|
|
private TransactionCloseStrategy closeStrategy;
|
|
|
|
|
|
|
|
public DefaultPersistenceTransaction(DefaultPersistenceRealm realm, boolean verbose) {
|
|
|
|
this.realm = realm;
|
2013-10-06 12:32:57 +02:00
|
|
|
this.verbose = verbose;
|
|
|
|
this.objectFilter = new ObjectFilter();
|
2013-10-15 22:26:58 +02:00
|
|
|
this.fileDao = new FileDao(this, realm.getPathBuilder(), verbose);
|
2013-10-06 12:32:57 +02:00
|
|
|
this.objectDao = new ObjectDao(this, this.fileDao, this.objectFilter);
|
2013-10-15 22:26:58 +02:00
|
|
|
this.metadataDao = new MetadataDao(realm.getPathBuilder(), this, verbose);
|
|
|
|
|
|
|
|
this.closeStrategy = TransactionCloseStrategy.COMMIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public PersistenceRealm getRealm() {
|
|
|
|
return this.realm;
|
2013-10-06 12:32:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ObjectDao getObjectDao() {
|
|
|
|
return this.objectDao;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public MetadataDao getMetadataDao() {
|
|
|
|
return this.metadataDao;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2013-10-15 22:26:58 +02:00
|
|
|
public ObjectReferenceCache getObjectRefCache() {
|
|
|
|
return this.realm.getObjectRefCache();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setCloseStrategy(TransactionCloseStrategy closeStrategy) {
|
|
|
|
this.closeStrategy = closeStrategy;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void close() throws XmlPersistenceException {
|
|
|
|
this.closeStrategy.close(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void autoCloseableRollback() {
|
2013-10-06 18:42:55 +02:00
|
|
|
if (this.committed)
|
|
|
|
throw new IllegalStateException("Transaction has already been committed!"); //$NON-NLS-1$
|
2013-10-15 22:26:58 +02:00
|
|
|
|
2013-10-06 18:42:55 +02:00
|
|
|
if (!this.closed) {
|
2013-10-20 01:14:59 +02:00
|
|
|
unlockObjectRefs();
|
2013-10-06 18:42:55 +02:00
|
|
|
this.closed = true;
|
|
|
|
this.objectFilter.clearCache();
|
|
|
|
}
|
2013-10-06 12:32:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2013-10-15 22:26:58 +02:00
|
|
|
public void autoCloseableCommit() throws XmlPersistenceException {
|
2013-10-06 12:32:57 +02:00
|
|
|
|
2013-10-15 22:26:58 +02:00
|
|
|
long start = System.nanoTime();
|
2013-10-06 12:32:57 +02:00
|
|
|
|
2013-10-15 22:26:58 +02:00
|
|
|
try {
|
2013-10-06 12:32:57 +02:00
|
|
|
|
2013-10-15 22:26:58 +02:00
|
|
|
if (this.verbose) {
|
|
|
|
String msg = "Committing {0} operations in TX...";//$NON-NLS-1$
|
2013-10-20 01:14:59 +02:00
|
|
|
logger.info(MessageFormat.format(msg, this.objectFilter.sizeCache()));
|
2013-10-15 22:26:58 +02:00
|
|
|
}
|
|
|
|
|
2013-10-20 01:14:59 +02:00
|
|
|
Set<String> keySet = this.objectFilter.keySet();
|
2013-10-06 12:32:57 +02:00
|
|
|
for (String key : keySet) {
|
|
|
|
|
|
|
|
List<Object> removed = this.objectFilter.getRemoved(key);
|
|
|
|
if (removed.isEmpty()) {
|
|
|
|
if (this.verbose)
|
|
|
|
logger.info("No objects removed in this tx."); //$NON-NLS-1$
|
|
|
|
} else {
|
|
|
|
if (this.verbose)
|
|
|
|
logger.info(removed.size() + " objects removed in this tx."); //$NON-NLS-1$
|
|
|
|
|
|
|
|
for (Object object : removed) {
|
2013-10-19 17:43:36 +02:00
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
PersistenceContext<Object> ctx = (PersistenceContext<Object>) object;
|
2013-10-15 22:26:58 +02:00
|
|
|
this.fileDao.performDelete(ctx);
|
2013-10-06 12:32:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
List<Object> updated = this.objectFilter.getUpdated(key);
|
|
|
|
if (updated.isEmpty()) {
|
|
|
|
if (this.verbose)
|
|
|
|
logger.info("No objects updated in this tx."); //$NON-NLS-1$
|
|
|
|
} else {
|
|
|
|
if (this.verbose)
|
|
|
|
logger.info(updated.size() + " objects updated in this tx."); //$NON-NLS-1$
|
|
|
|
|
|
|
|
for (Object object : updated) {
|
2013-10-19 17:43:36 +02:00
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
PersistenceContext<Object> ctx = (PersistenceContext<Object>) object;
|
2013-10-15 22:26:58 +02:00
|
|
|
this.fileDao.performUpdate(ctx);
|
2013-10-06 12:32:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
List<Object> added = this.objectFilter.getAdded(key);
|
|
|
|
if (added.isEmpty()) {
|
|
|
|
if (this.verbose)
|
|
|
|
logger.info("No objects added in this tx."); //$NON-NLS-1$
|
|
|
|
} else {
|
|
|
|
if (this.verbose)
|
|
|
|
logger.info(added.size() + " objects added in this tx."); //$NON-NLS-1$
|
|
|
|
|
|
|
|
for (Object object : added) {
|
2013-10-19 17:43:36 +02:00
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
PersistenceContext<Object> ctx = (PersistenceContext<Object>) object;
|
2013-10-15 22:26:58 +02:00
|
|
|
this.fileDao.performCreate(ctx);
|
2013-10-06 12:32:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
long end = System.nanoTime();
|
2013-10-15 22:26:58 +02:00
|
|
|
logger.info("TX completed in " + StringHelper.formatNanoDuration(end - start)); //$NON-NLS-1$
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
long end = System.nanoTime();
|
|
|
|
logger.info("TX failed after " + StringHelper.formatNanoDuration(end - start)); //$NON-NLS-1$
|
|
|
|
|
|
|
|
throw e;
|
2013-10-06 12:32:57 +02:00
|
|
|
|
|
|
|
} finally {
|
|
|
|
// clean up
|
2013-10-20 01:14:59 +02:00
|
|
|
unlockObjectRefs();
|
2013-10-06 12:32:57 +02:00
|
|
|
this.objectFilter.clearCache();
|
2013-10-06 18:42:55 +02:00
|
|
|
this.committed = true;
|
2013-10-06 12:32:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-20 01:14:59 +02:00
|
|
|
@SuppressWarnings("rawtypes")
|
|
|
|
private void unlockObjectRefs() {
|
|
|
|
List<PersistenceContext> lockedObjects = this.objectFilter.getAll(PersistenceContext.class);
|
|
|
|
for (PersistenceContext lockedObject : lockedObjects) {
|
|
|
|
lockedObject.getObjectRef().unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-06 12:32:57 +02:00
|
|
|
@Override
|
2013-10-06 18:42:55 +02:00
|
|
|
public boolean isOpen() {
|
|
|
|
return !this.closed && !this.committed;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2013-10-15 22:26:58 +02:00
|
|
|
public void setIoMode(IoMode ioMode) {
|
2013-10-06 18:42:55 +02:00
|
|
|
this.ioMode = ioMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2013-10-15 22:26:58 +02:00
|
|
|
public IoMode getIoMode() {
|
2013-10-06 18:42:55 +02:00
|
|
|
return this.ioMode;
|
2013-10-06 12:32:57 +02:00
|
|
|
}
|
|
|
|
}
|