/*
Copyright (C) 2007 Mobixess Inc. http://www.java-objects-database.com
This file is part of the JODB (Java Objects Database) open source project.
JODB is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation.
JODB 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 this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package com.mobixess.jodb.core;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URI;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Vector;
import com.mobixess.jodb.core.index.JODBIndexingAgent;
import com.mobixess.jodb.core.index.JODBIndexingRootAgent;
import com.mobixess.jodb.core.io.IOBase;
import com.mobixess.jodb.core.io.IOTicket;
import com.mobixess.jodb.core.io.JODBIOBase;
import com.mobixess.jodb.core.io.JODBOperationContext;
import com.mobixess.jodb.core.query.JODBQueryList;
import com.mobixess.jodb.core.query.QueryNode;
import com.mobixess.jodb.core.transaction.JODBSession;
import com.mobixess.jodb.core.transaction.TransactionContainer;
import com.mobixess.jodb.query.api.ObjectContainer;
import com.mobixess.jodb.query.api.ObjectSet;
import com.mobixess.jodb.query.api.Predicate;
import com.mobixess.jodb.soda.api.Query;
public class JODBSessionContainer implements ObjectContainer {
IOBase _base;
JODBSession _session;
TransactionContainer _transactionContainer;
int _openRequestsCounter;
Vector<ISessionCloseListener> _closedListener = new Vector<ISessionCloseListener>();
JODBSessionContainer() {
}
/*package*/void init(File file) throws IOException {
initIoBase(file);
_session = new JODBSession(_base);
_transactionContainer = new TransactionContainer(_session, null);
if(_base.isNewDatabase()){
JODBIndexingRootAgent agent = new JODBIndexingRootAgent();
try {
_transactionContainer.enableAgentMode();
_transactionContainer.set(agent, Integer.MAX_VALUE);
} catch (IllegalClassTypeException e) {
throw new JodbIOException(e);
}finally{
_transactionContainer.disableAgentMode();
}
commit(agent);
}
}
protected void initIoBase(File file) throws IOException{
_base = new JODBIOBase(file);
}
public void printFileMap() throws IOException{
_base.printFileMap(_session, System.err);
}
public ITransactionResolver getTransactionResolver() {
if(_transactionContainer==null){
return null;
}
return _transactionContainer.getTransactionResolver();
}
URI getDbIdentificator(){
return _base.getDbIdentificator();
}
IOBase getIoBase() {
return _base;
}
JODBSession getSession() {
return _session;
}
public void configureIndex(Class clazz, String fieldName, boolean enable) throws SecurityException, NoSuchFieldException, IOException{
Field field = clazz.getDeclaredField(fieldName);
configureIndex(field, enable);
}
public JODBIndexingAgent getIndexingAgent(Field field) throws IOException{
JODBIndexingRootAgent indexingRootAgent = _session.getIndexingRootAgent();
return indexingRootAgent.getIndexingAgent(field, _base);
}
public void configureIndex(Field field, boolean enable) throws IOException{
if(!_transactionContainer.isEmpty()){
throw new IllegalStateException("Cannot create index with transaction in progress");
}
JODBIndexingRootAgent indexingRootAgent = _session.getIndexingRootAgent();
JODBIndexingAgent indexingAgent = indexingRootAgent.getIndexingAgent(field, _base);
if((indexingAgent!=null && enable)|| (indexingAgent == null && !enable) ){
return;
}
IOTicket writeTicket = _base.getIOTicket(true, true);
try{
JODBOperationContext context = new JODBOperationContext(_session, writeTicket, null, _transactionContainer, indexingRootAgent);
writeTicket.lock(true);
if(!enable){
indexingRootAgent.removeAgent(field, context);
return;
}
indexingAgent = indexingRootAgent.enableIndex(field, context );
_base.applyTransaction(_transactionContainer, _session, writeTicket, indexingRootAgent, this);
}finally {
writeTicket.unlock();//should be already released in "applyTransaction()", just to play safe
}
}
public void setTransactionResolver(ITransactionResolver transactionResolver)
{
_transactionContainer.setTransactionResolver(transactionResolver);
}
public void activate(Object obj, int depth) throws IOException {
_session.activate(obj, depth);
}
public int getCachedObjectsCount(){
return _session.getCachedObjectsCount();
}
public synchronized boolean close() throws IOException {
if(_base.isClosed()){
return true;
}
try {
commit();
} finally {
_openRequestsCounter--;
if (_openRequestsCounter == 0) {
JodbSessionManager.removeSessionFromCache(_base.getDbIdentificator());//TODO better damage control over concurrent close/open
_base.close();
_session.close();
}
//System.err.println("_openRequestsCounter == "+_openRequestsCounter);
if(_openRequestsCounter == 0){
fireSessionClosed();
}
}
return _openRequestsCounter == 0;
}
public void addCloseListener(ISessionCloseListener closeListener){
_closedListener.add(closeListener);
}
public void removeCloseListener(ISessionCloseListener closeListener){
_closedListener.remove(closeListener);
}
private void fireSessionClosed(){
Enumeration<ISessionCloseListener> enumeration = _closedListener.elements();
while (enumeration.hasMoreElements()) {
ISessionCloseListener sessionCloseListener = enumeration.nextElement();
sessionCloseListener.sessionClosed(this);
}
}
public void commit() throws IOException {
commit(_session.getIndexingRootAgent());
}
public void forceResolve() throws IOException{
_transactionContainer.runResolve(this);
}
private void commit(JODBIndexingRootAgent indexingRootAgent) throws IOException {
if(_transactionContainer == null){
return;
}
_base.applyTransaction(_transactionContainer, _session, null, indexingRootAgent, this);
}
public Object getSyncObject(Object activeObject){
return _session.getHandleForActiveObject(activeObject);
}
public void deactivate(Object obj, int depth) {
_session.deactivate(obj, depth);
}
public void delete(Object obj) throws IOException {
delete(obj,JODBConfig.getDefaultDeleteDepth());
}
public void delete(Object obj, int depth) throws IOException {
if(_base.isClosed()){
throw new JodbIOException("Container closed");
}
try {
_transactionContainer.delete(obj, depth);
} catch (IllegalClassTypeException e) {
e.printStackTrace();//no reason to release this Exception
}
}
public <T> ObjectSet<T> get(Object template) throws IOException, IllegalClassTypeException {
if(template == null){
return _session.getAllObjects();
}else{
Query query = query();
query.constrain(template);
return query.execute();
}
}
public Query query() {
return new QueryNode("",_session, null);
}
public <Type> ObjectSet<Type> query(Class<Type> clazz) throws IOException, IllegalClassTypeException {
Query query = query();
query.constrain(clazz);
return query.execute();
}
public void rollback() {
_transactionContainer.reset();
}
public void set(Object obj) throws IllegalClassTypeException, IOException{
set(obj, JODBConfig.getDefaultSetDepth());
}
public void set(Object obj, int depth) throws IllegalClassTypeException, IOException {
if(_base.isClosed()){
throw new JodbIOException("Container closed");
}
if(_transactionContainer == null){
throw new JodbIOException("This container is Read Only!!!");
}
_transactionContainer.set(obj, depth);
}
public JODBQueryList getAllObjects() throws IOException{
return _session.getAllObjects();
}
public IPersistentObjectStatistics getPersistenceStatistics(Object object) throws IOException{
return _session.getPersistenceStatistics(object);
}
public IDatabaseStatistics getDatabaseStatistics() throws IOException {
return _base.getDatabaseStatistics(false);
}
public void setClassLoader(ClassLoader classLoader) {
_session.setClassLoader(classLoader);
}
@Override
protected void finalize() throws Throwable
{
if(!_base.isClosed()){
close();
}
}
synchronized void incOpenCounter(){
_openRequestsCounter++;
}
public <TargetType> ObjectSet<TargetType> query(
Predicate<TargetType> predicate) throws IOException
{
return query(predicate,null);
}
public <TargetType> ObjectSet<TargetType> query(
Predicate<TargetType> predicate, Comparator<TargetType> comparator) throws IOException
{
return _base.query(getSession(), predicate, comparator);
}
public <TargetType> boolean isOptimizedQuery(Predicate<TargetType> predicate, Comparator<TargetType> comparator) throws IOException{
return _base.isOptimizedQuery(getSession(), predicate, comparator);
}
}