/* ********************************************************************** ** ** Copyright notice ** ** ** ** (c) 2005-2009 RSSOwl Development Team ** ** http://www.rssowl.org/ ** ** ** ** 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.rssowl.org/legal/epl-v10.html ** ** ** ** A copy is found in the file epl-v10.html and important notices to the ** ** license from the team is found in the textfile LICENSE.txt distributed ** ** in this package. ** ** ** ** This copyright notice MUST APPEAR in all copies of the file! ** ** ** ** Contributors: ** ** RSSOwl Development Team - initial API and implementation ** ** ** ** ********************************************************************** */ package org.rssowl.core.internal.persist.service; import org.rssowl.core.persist.service.IDGenerator; import com.db4o.ObjectContainer; import java.util.List; /** * db4o implementation of IDGenerator. */ public class DB4OIDGenerator implements IDGenerator, DatabaseListener { private final static int BATCH_SIZE = 100; private long fCurrent = -1; private long fMax; private ObjectContainer fDb; private Counter fCounter; /** * Creates an instance of this class. */ public DB4OIDGenerator() { DBManager.getDefault().addEntityStoreListener(this); } /* * @see * org.rssowl.core.internal.persist.service.DatabaseListener#databaseClosed * (org.rssowl.core.internal.persist.service.DatabaseEvent) */ public void databaseClosed(DatabaseEvent event) { setObjectContainer(null); } /* * @see * org.rssowl.core.internal.persist.service.DatabaseListener#databaseOpened * (org.rssowl.core.internal.persist.service.DatabaseEvent) */ public void databaseOpened(DatabaseEvent event) { setObjectContainer(event.getObjectContainer()); } private synchronized void setObjectContainer(ObjectContainer db) { fDb = db; if (fDb == null) { fCurrent = -1; fCounter = null; fMax = 0; } else { fCounter = loadOrCreateCounter(); fCurrent = fCounter.getValue(); fMax = increaseMax(true); } } /* * @see org.rssowl.core.persist.service.IDGenerator#getNext() */ public long getNext() { return getNext(true); } /** * Implements the contract of {@link #getNext()} with additional control over * whether this method is allowed to commit a db4o transaction. This should be * set to <code>false</code> if this method is called from within a db4o * transaction. However, in the case the transaction is rolled back, the ids * provided during that transaction are invalid. * * @param commit * @return a long value that has not been returned from this method before. */ public synchronized long getNext(boolean commit) { checkCurrent(); ++fCurrent; if (fCurrent > fMax) { fMax = increaseMax(commit); } return fCurrent; } private void checkCurrent() { if (fCurrent == -1) { throw new IllegalStateException("current has not been initialised yet."); //$NON-NLS-1$ } } private long increaseMax(boolean commit) { fCounter.increment(BATCH_SIZE); fDb.set(fCounter); if (commit) fDb.commit(); return fCounter.getValue(); } public synchronized void shutdown() { if (fCounter != null) { //Could be NULL if DB never opened fMax = fCurrent; fCounter.setValue(fCurrent + 1); fDb.set(fCounter); fDb.commit(); } } private Counter loadCounter() { List<Counter> counters = fDb.ext().query(Counter.class); if (!counters.isEmpty()) return counters.iterator().next(); return null; } private Counter loadOrCreateCounter() { Counter counter = loadCounter(); if (counter == null) counter = new Counter(0L); return counter; } }