/*
* Copyright 2005-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springextensions.db4o;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Comparator;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.ext.Db4oDatabase;
import com.db4o.ext.Db4oException;
import com.db4o.ext.Db4oUUID;
import com.db4o.ext.ExtClient;
import com.db4o.ext.ExtObjectContainer;
import com.db4o.ext.ObjectInfo;
import com.db4o.ext.StoredClass;
import com.db4o.ext.SystemInfo;
import com.db4o.io.Storage;
import com.db4o.query.Predicate;
import com.db4o.query.Query;
import com.db4o.query.QueryComparator;
import com.db4o.reflect.ReflectClass;
import com.db4o.reflect.generic.GenericReflector;
import org.springframework.dao.DataAccessException;
/**
* @author Costin Leau
* @author olli
*/
public class Db4oTemplate extends Db4oAccessor implements Db4oOperations {
private boolean exposeNativeContainer = false;
public Db4oTemplate() {
}
public Db4oTemplate(ObjectContainer container) {
setObjectContainer(container);
afterPropertiesSet();
}
/**
* @param exposeNativeContainer The exposeNativeContainer to set.
*/
public void setExposeNativeContainer(boolean exposeNativeContainer) {
this.exposeNativeContainer = exposeNativeContainer;
}
/**
* @return Returns the exposeNativeContainer.
*/
public boolean isExposeNativeContainer() {
return exposeNativeContainer;
}
/**
* @see org.springextensions.db4o.Db4oOperations#execute(org.springextensions.db4o.Db4oCallback)
*/
public Object execute(Db4oCallback callback) throws DataAccessException {
return execute(callback, isExposeNativeContainer());
}
/**
* @see org.springextensions.db4o.Db4oOperations#execute(org.springextensions.db4o.Db4oCallback, boolean)
*/
public Object execute(Db4oCallback callback, boolean exposeNativeContainer) throws DataAccessException {
ObjectContainer cont = getObjectContainer();
try {
ObjectContainer container = (exposeNativeContainer ? cont : createContainerProxy(cont));
return callback.doInDb4o(container);
} catch (Db4oException ex) {
throw convertDb4oAccessException(ex);
} catch (RuntimeException ex) {
RuntimeException convEx = convertDb4oAccessException(ex);
// it's user specific
if (convEx instanceof Db4oSystemException)
throw ex;
// it's a converted exception
throw convEx;
}
}
//
// ObjectContainer interface methods
//
/**
* @see org.springextensions.db4o.Db4oOperations#activate(java.lang.Object, int)
*/
public void activate(final Object object, final int depth) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
container.activate(object, depth);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#deactivate(java.lang.Object, int)
*/
public void deactivate(final Object object, final int depth) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
container.deactivate(object, depth);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#delete(java.lang.Object)
*/
public void delete(final Object object) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
container.delete(object);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#queryByExample(java.lang.Object)
*/
public <T> ObjectSet<T> queryByExample(final Object template) {
return (ObjectSet<T>) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return container.queryByExample(template);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#query()
*/
public Query query() {
return (Query) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return container.query();
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#query(java.lang.Class)
*/
public <TargetType> ObjectSet<TargetType> query(final Class<TargetType> clazz) {
return (ObjectSet<TargetType>) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return container.query(clazz);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#query(com.db4o.query.Predicate)
*/
public <TargetType> ObjectSet<TargetType> query(final Predicate<TargetType> predicate) {
return (ObjectSet<TargetType>) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return container.query(predicate);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#query(com.db4o.query.Predicate, com.db4o.query.QueryComparator)
*/
public <TargetType> ObjectSet<TargetType> query(final Predicate<TargetType> predicate, final QueryComparator<TargetType> comparator) {
return (ObjectSet<TargetType>) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return container.query(predicate, comparator);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#query(com.db4o.query.Predicate, java.util.Comparator)
*/
public <TargetType> ObjectSet<TargetType> query(final Predicate<TargetType> predicate, final Comparator<TargetType> comparator) {
return (ObjectSet<TargetType>) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return container.query(predicate, comparator);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#store(java.lang.Object)
*/
public void store(final Object object) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
container.store(object);
return null;
}
}, true);
}
//
// ExtObjectContainer interface methods
//
/**
* @see org.springextensions.db4o.Db4oOperations#activate(java.lang.Object)
*/
public void activate(final Object object) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
((ExtObjectContainer) container).activate(object);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#deactivate(java.lang.Object)
*/
public void deactivate(final Object object) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
((ExtObjectContainer) container).deactivate(object);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#backup(java.lang.String)
*/
public void backup(final String path) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
((ExtObjectContainer) container).backup(path);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#backup(com.db4o.io.Storage, java.lang.String)
*/
public void backup(final Storage targetStorage, final String path) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
((ExtObjectContainer) container).backup(targetStorage, path);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#bind(java.lang.Object, long)
*/
public void bind(final Object object, final long id) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
((ExtObjectContainer) container).bind(object, id);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#descend(java.lang.Object, java.lang.String[])
*/
public Object descend(final Object object, final String[] path) {
return execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).descend(object, path);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#getByID(long)
*/
public Object getByID(final long id) {
return execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).getByID(id);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#getByUUID(com.db4o.ext.Db4oUUID)
*/
public Object getByUUID(final Db4oUUID uuid) {
return execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).getByUUID(uuid);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#getID(java.lang.Object)
*/
public long getID(final Object object) {
return (Long) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).getID(object);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#getObjectInfo(java.lang.Object)
*/
public ObjectInfo getObjectInfo(final Object object) {
return (ObjectInfo) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).getObjectInfo(object);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#identity()
*/
public Db4oDatabase identity() {
return (Db4oDatabase) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).identity();
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#isActive(java.lang.Object)
*/
public boolean isActive(final Object object) {
return (Boolean) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).isActive(object);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#isCached(long)
*/
public boolean isCached(final long id) {
return (Boolean) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).isCached(id);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#isClosed()
*/
public boolean isClosed() {
return (Boolean) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).isClosed();
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#isStored(java.lang.Object)
*/
public boolean isStored(final Object object) {
return (Boolean) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).isStored(object);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#knownClasses()
*/
public ReflectClass[] knownClasses() {
return (ReflectClass[]) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).knownClasses();
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#lock()
*/
public Object lock() {
return execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).lock();
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#openSession()
*/
public ObjectContainer openSession() {
return (ObjectContainer) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).openSession();
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#peekPersisted(java.lang.Object, int, boolean)
*/
public <T> T peekPersisted(final T object, final int depth, final boolean committed) {
return (T) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).peekPersisted(object, depth, committed);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#purge()
*/
public void purge() {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
((ExtObjectContainer) container).purge();
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#purge(java.lang.Object)
*/
public void purge(final Object object) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
((ExtObjectContainer) container).purge(object);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#reflector()
*/
public GenericReflector reflector() {
return (GenericReflector) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).reflector();
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#refresh(java.lang.Object, int)
*/
public void refresh(final java.lang.Object object, final int depth) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
((ExtObjectContainer) container).refresh(object, depth);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#releaseSemaphore(java.lang.String)
*/
public void releaseSemaphore(final String name) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
((ExtObjectContainer) container).releaseSemaphore(name);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#store(java.lang.Object, int)
*/
public void store(final Object object, final int depth) {
execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
((ExtObjectContainer) container).store(object, depth);
return null;
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#setSemaphore(java.lang.String, int)
*/
public boolean setSemaphore(final String name, final int waitForAvailability) {
return (Boolean) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).setSemaphore(name, waitForAvailability);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#storedClass(java.lang.Object)
*/
public StoredClass storedClass(final Object clazz) {
return (StoredClass) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).storedClass(clazz);
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#storedClasses()
*/
public StoredClass[] storedClasses() {
return (StoredClass[]) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).storedClasses();
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#systemInfo()
*/
public SystemInfo systemInfo() {
return (SystemInfo) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).systemInfo();
}
}, true);
}
/**
* @see org.springextensions.db4o.Db4oOperations#version()
*/
public long version() {
return (Long) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtObjectContainer) container).version();
}
}, true);
}
//
// ExtClient interface methods
//
public boolean isAlive() {
return (Boolean) execute(new Db4oCallback() {
public Object doInDb4o(ObjectContainer container) throws RuntimeException {
return ((ExtClient) container).isAlive();
}
}, true);
}
//
// Proxy
//
/**
* Create a close-suppressing proxy for the given ObjectContainer.
*
* @param container the Db4o ObjectContainer to create a proxy for
* @return the ObjectContainer proxy
* @see com.db4o.ObjectContainer#close()
*/
protected ObjectContainer createContainerProxy(ObjectContainer container) {
// every db4o ObjectContainer always is an ExtObjectContainer
Class intrface = ExtObjectContainer.class;
if (container instanceof ExtClient) {
// both Db4oClientServer.openClient() methods always return an ExtClient object
intrface = ExtClient.class;
}
return (ObjectContainer) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{intrface}, new CloseSuppressingInvocationHandler(container));
}
/**
* Invocation handler that suppresses close calls on ObjectContainer.
*
* @see com.db4o.ObjectContainer#close()
*/
private class CloseSuppressingInvocationHandler implements InvocationHandler {
private final ObjectContainer target;
public CloseSuppressingInvocationHandler(ObjectContainer target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("equals")) {
// Only consider equal when proxies are identical.
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
} else if (method.getName().equals("hashCode")) {
// Use hashCode of session proxy.
return hashCode();
} else if (method.getName().equals("close")) {
// Handle close method: suppress, not valid.
// tell the truth when returning the value.
return Boolean.FALSE;
}
// invoke method on target container
try {
return method.invoke(this.target, args);
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
}