package org.compass.core.impl;
import java.util.ArrayList;
import java.util.List;
import org.compass.core.CompassAnalyzerHelper;
import org.compass.core.CompassException;
import org.compass.core.CompassHits;
import org.compass.core.CompassQuery;
import org.compass.core.CompassQueryBuilder;
import org.compass.core.CompassQueryFilterBuilder;
import org.compass.core.CompassSession;
import org.compass.core.CompassSessionFactory;
import org.compass.core.Resource;
import org.compass.core.cache.first.FirstLevelCache;
import org.compass.core.cascade.CascadingManager;
import org.compass.core.config.CompassSettings;
import org.compass.core.config.RuntimeCompassSettings;
import org.compass.core.engine.SearchEngine;
import org.compass.core.engine.SearchEngineAnalyzerHelper;
import org.compass.core.engine.SearchEngineQueryBuilder;
import org.compass.core.events.FilterOperation;
import org.compass.core.mapping.Cascade;
import org.compass.core.mapping.CompassMapping;
import org.compass.core.marshall.DefaultMarshallingStrategy;
import org.compass.core.marshall.MarshallingContext;
import org.compass.core.marshall.MarshallingException;
import org.compass.core.marshall.MarshallingStrategy;
import org.compass.core.metadata.CompassMetaData;
import org.compass.core.spi.DirtyOperationContext;
import org.compass.core.spi.InternalCompass;
import org.compass.core.spi.InternalCompassSession;
import org.compass.core.spi.InternalResource;
import org.compass.core.spi.InternalSessionDelegateClose;
import org.compass.core.spi.ResourceKey;
import org.hibernate.SessionFactory;
public class DefaultCompassSession implements InternalCompassSession {
private InternalCompass compass;
private CompassMapping mapping;
private CompassMetaData compassMetaData;
private RuntimeCompassSettings runtimeSettings;
private SearchEngine searchEngine;
private FirstLevelCache firstLevelCache;
private DefaultMarshallingStrategy marshallingStrategy;
private boolean closed;
private CascadingManager cascadingManager;
private final List<InternalSessionDelegateClose> delegateClose = new ArrayList<InternalSessionDelegateClose>();
public DefaultCompassSession(RuntimeCompassSettings runtimeSettings, InternalCompass compass, SearchEngine searchEngine, FirstLevelCache firstLevelCache) {
this.compass = compass;
this.mapping = compass.getMapping();
this.compassMetaData = compass.getMetaData();
this.runtimeSettings = runtimeSettings;
this.searchEngine = searchEngine;
this.firstLevelCache = firstLevelCache;
this.marshallingStrategy = new DefaultMarshallingStrategy(mapping, searchEngine, compass.getConverterLookup(), this);
this.cascadingManager = new CascadingManager(this);
}
public void create(String alias, Object object) throws CompassException {
checkClosed();
create(alias, object, new DirtyOperationContext());
}
public void create(String alias, Object object, DirtyOperationContext context) throws CompassException {
if (context.alreadyPerformedOperation(object)) {
return;
}
if (compass.getEventManager().onPreCreate(alias, object) == FilterOperation.YES) {
return;
}
Resource resource = marshallingStrategy.marshall(alias, object);
if (resource != null) {
if (compass.getEventManager().onPreCreate(resource) == FilterOperation.YES) {
return;
}
searchEngine.create(resource);
ResourceKey key = ((InternalResource) resource).getResourceKey();
firstLevelCache.set(key, object);
firstLevelCache.setResource(key, resource);
}
context.addOperatedObjects(object);
boolean performedCascading = cascadingManager
.cascade(alias, object, Cascade.CREATE, context);
if (resource == null && !performedCascading) {
throw new MarshallingException("Alias [" + alias
+ "] has no root mappings and no cascading defined, no operation was perfomed");
}
if (resource != null) {
compass.getEventManager().onPostCreate(resource);
}
compass.getEventManager().onPostCreate(alias, object);
}
@Override
public void create(Object object) {
checkClosed();
create(object, new DirtyOperationContext());
}
public void create(Object object, DirtyOperationContext context) {
if (context.alreadyPerformedOperation(object)) {
return;
}
if (compass.getEventManager().onPreCreate(null, object) == FilterOperation.YES) {
return;
}
boolean performedCascading;
Resource resource = marshallingStrategy.marshall(object);
if (resource != null) {
if (compass.getEventManager().onPreCreate(resource) == FilterOperation.YES) {
return;
}
searchEngine.create(resource);
ResourceKey key = ((InternalResource) resource).getResourceKey();
firstLevelCache.set(key, object);
firstLevelCache.setResource(key, resource);
context.addOperatedObjects(object);
// if we found a resource, we perform the cascading based on its
// alias
performedCascading = cascadingManager
.cascade(key.getAlias(), object, Cascade.CREATE, context);
} else {
context.addOperatedObjects(object);
// actuall, no root mapping to create a resource, try and create one
// based on the object
performedCascading = cascadingManager.cascade(object, Cascade.CREATE, context);
}
if (resource == null && !performedCascading) {
throw new MarshallingException("Object [" + object.getClass().getName()
+ "] has no root mappings and no cascading defined, no operation was perfomed");
}
if (resource != null) {
compass.getEventManager().onPostCreate(resource);
compass.getEventManager().onPostCreate(resource.getAlias(), object);
} else {
compass.getEventManager().onPostCreate(null, object);
}
}
public void save(String alias, Object object) throws CompassException {
checkClosed();
save(alias, object, new DirtyOperationContext());
}
public void save(String alias, Object object, DirtyOperationContext context) throws CompassException {
if (context.alreadyPerformedOperation(object)) {
return;
}
if (compass.getEventManager().onPreSave(alias, object) == FilterOperation.YES) {
return;
}
Resource resource = marshallingStrategy.marshall(alias, object);
if (resource != null) {
if (compass.getEventManager().onPreSave(resource) == FilterOperation.YES) {
return;
}
searchEngine.save(resource);
ResourceKey key = ((InternalResource) resource).getResourceKey();
firstLevelCache.set(key, object);
firstLevelCache.setResource(key, resource);
}
context.addOperatedObjects(object);
boolean performedCascading = cascadingManager.cascade(alias, object, Cascade.SAVE, context);
if (resource == null && !performedCascading) {
throw new MarshallingException("Alias [" + alias
+ "] has no root mappings and no cascading defined, no operation was perfomed");
}
if (resource != null) {
compass.getEventManager().onPostSave(resource);
}
compass.getEventManager().onPostSave(alias, object);
}
public void save(Object object) throws CompassException {
checkClosed();
save(object, new DirtyOperationContext());
}
public void save(Object object, DirtyOperationContext context) throws CompassException {
if (context.alreadyPerformedOperation(object)) {
return;
}
if (compass.getEventManager().onPreSave(null, object) == FilterOperation.YES) {
return;
}
boolean performedCascading;
Resource resource = marshallingStrategy.marshall(object);
if (resource != null) {
if (compass.getEventManager().onPreSave(resource) == FilterOperation.YES) {
return;
}
searchEngine.save(resource);
ResourceKey key = ((InternalResource) resource).getResourceKey();
firstLevelCache.setResource(key, resource);
firstLevelCache.set(key, object);
context.addOperatedObjects(object);
performedCascading = cascadingManager
.cascade(key.getAlias(), object, Cascade.SAVE, context);
} else {
context.addOperatedObjects(object);
performedCascading = cascadingManager.cascade(object, Cascade.SAVE, context);
}
if (resource == null && !performedCascading) {
throw new MarshallingException("Object [" + object.getClass().getName()
+ "] has no root mappings and no cascading defined, no operation was perfomed");
}
if (resource != null) {
compass.getEventManager().onPostSave(resource);
compass.getEventManager().onPostSave(resource.getAlias(), object);
} else {
compass.getEventManager().onPostSave(null, object);
}
}
public <T> T get(Class<T> clazz, Object... ids) throws CompassException {
return get(clazz, (Object) ids);
}
public <T> T get(Class<T> clazz, Object id) throws CompassException {
Resource resource = getResource(clazz, id);
if (resource == null) {
return null;
}
// noinspection unchecked
return clazz.cast(getByResource(resource));
}
public Object get(String alias, Object... ids) throws CompassException {
return get(alias, (Object) ids);
}
public Object get(String alias, Object id) throws CompassException {
checkClosed();
Resource resource = getResource(alias, id);
if (resource == null) {
return null;
}
return getByResource(resource);
}
public Object get(String alias, Object id, MarshallingContext context) throws CompassException {
checkClosed();
Resource resource = getResource(alias, id);
if (resource == null) {
return null;
}
return getByResource(resource, context);
}
public Object getByResource(Resource resource) {
checkClosed();
return getByResource(resource, null);
}
public Object getByResource(Resource resource, MarshallingContext context) {
checkClosed();
ResourceKey key = ((InternalResource) resource).getResourceKey();
Object cachedValue = firstLevelCache.get(key);
if (cachedValue != null) {
return cachedValue;
}
Object value;
if (context == null) {
value = marshallingStrategy.unmarshall(resource);
} else {
value = marshallingStrategy.unmarshall(resource, context);
}
firstLevelCache.set(key, value);
return value;
}
public void addDelegateClose(InternalSessionDelegateClose delegateClose) {
this.delegateClose.add(delegateClose);
}
public void setReadOnly() {
searchEngine.setReadOnly();
}
public boolean isReadOnly() {
return searchEngine.isReadOnly();
}
public void flush() throws CompassException {
checkClosed();
searchEngine.flush();
}
@Override
public InternalCompass getCompass() {
return compass;
}
@Override
public FirstLevelCache getFirstLevelCache() {
return firstLevelCache;
}
@Override
public CompassSettings getSettings() {
return runtimeSettings;
}
@Override
public SearchEngine getSearchEngine() {
return searchEngine;
}
@Override
public CompassMapping getMapping() {
return mapping;
}
@Override
public CompassMetaData getMetaData() {
return compassMetaData;
}
public CompassQueryBuilder queryBuilder() throws CompassException {
checkClosed();
SearchEngineQueryBuilder searchEngineQueryBuilder = searchEngine.queryBuilder();
return new DefaultCompassQueryBuilder(searchEngineQueryBuilder, compass, this);
}
public CompassQueryFilterBuilder queryFilterBuilder() throws CompassException {
checkClosed();
return compass.queryFilterBuilder();
}
public <T> T load(Class<T> clazz, Object... ids) throws CompassException {
return load(clazz, (Object) ids);
}
public <T> T load(Class<T> clazz, Object id) throws CompassException {
checkClosed();
Resource resource = loadResource(clazz, id);
return clazz.cast(getByResource(resource));
}
public Object load(String alias, Object... ids) throws CompassException {
return load(alias, (Object) ids);
}
public Object load(String alias, Object id) throws CompassException {
checkClosed();
Resource resource = loadResource(alias, id);
return getByResource(resource);
}
public Resource loadResource(Class<?> clazz, Object... ids) throws CompassException {
return loadResource(clazz, (Object) ids);
}
public Resource loadResource(Class<?> clazz, Object id) throws CompassException {
checkClosed();
Resource idResource = marshallingStrategy.marshallIds(clazz, id);
return loadResourceByIdResource(idResource);
}
public Resource loadResource(String alias, Object... ids) throws CompassException {
return loadResource(alias, (Object) ids);
}
public Resource loadResource(String alias, Object id) throws CompassException {
checkClosed();
Resource idResource = marshallingStrategy.marshallIds(alias, id);
return loadResourceByIdResource(idResource);
}
public Resource loadResourceByIdResource(Resource idResource) {
checkClosed();
ResourceKey key = ((InternalResource) idResource).getResourceKey();
Resource cachedValue = firstLevelCache.getResource(key);
if (cachedValue != null) {
return cachedValue;
}
Resource value = searchEngine.load(idResource);
firstLevelCache.setResource(key, value);
return value;
}
@Override
public boolean isClosed() {
return closed;
}
@Override
public void close() {
if (closed) {
return;
}
for (InternalSessionDelegateClose delegateClose : this.delegateClose) {
delegateClose.close();
}
CompassSession transactionBoundSession = compass.getCompassSessionFactory().getTransactionBoundSession();
if (transactionBoundSession == this) {
compass.getCompassSessionFactory().setTransactionBoundSession(null);
}
evictAll();
closed = true;
}
public CompassHits find(String query) throws CompassException {
checkClosed();
return queryBuilder().queryString(query).toQuery().hits();
}
public Resource getResource(String alias, Object... ids) throws CompassException {
return getResource(alias, (Object) ids);
}
public Resource getResource(Class<?> clazz, Object... ids) throws CompassException {
return getResource(clazz, (Object) ids);
}
public Resource getResource(Class<?> clazz, Object id) throws CompassException {
checkClosed();
Resource idResource = marshallingStrategy.marshallIds(clazz, id);
if (idResource == null) {
return null;
}
return getResourceByIdResource(idResource);
}
public Resource getResource(String alias, Object id) throws CompassException {
checkClosed();
Resource idResource = marshallingStrategy.marshallIds(alias, id);
if (idResource == null) {
return null;
}
return getResourceByIdResource(idResource);
}
public Resource getResourceByIdResource(Resource idResource) {
checkClosed();
ResourceKey key = ((InternalResource) idResource).getResourceKey();
Resource cachedValue = firstLevelCache.getResource(key);
if (cachedValue != null) {
return cachedValue;
}
Resource value = searchEngine.get(idResource);
if (value != null) {
firstLevelCache.setResource(key, value);
}
return value;
}
public Resource getResourceByIdResourceNoCache(Resource idResource) {
checkClosed();
return searchEngine.get(idResource);
}
public void delete(String alias, Object... ids) throws CompassException {
delete(alias, (Object) ids);
}
public void delete(String alias, Object obj) throws CompassException {
checkClosed();
delete(alias, obj, new DirtyOperationContext(marshallingStrategy));
}
public void delete(String alias, Object obj, DirtyOperationContext context) throws CompassException {
if (context.alreadyPerformedOperation(obj)) {
return;
}
if (compass.getEventManager().onPreDelete(alias, obj) == FilterOperation.YES) {
return;
}
boolean performedCascading = false;
Resource idResource = marshallingStrategy.marshallIds(alias, obj);
if (idResource != null) {
if (compass.getEventManager().onPreDelete(idResource) == FilterOperation.YES) {
return;
}
Object cascadeObj = null;
// in case we need to do cascading, we need to load the object to we
// can delete its cascaded objects
if (cascadingManager.shouldCascade(idResource.getAlias(), obj, Cascade.DELETE)) {
Resource resouce = getResourceByIdResource(idResource);
if (resouce != null) {
cascadeObj = getByResource(resouce);
}
}
delete(idResource);
if (cascadeObj != null) {
context.addOperatedObjects(cascadeObj);
performedCascading = cascadingManager
.cascade(idResource.getAlias(), cascadeObj, Cascade.DELETE, context);
}
} else {
context.addOperatedObjects(obj);
performedCascading = cascadingManager.cascade(alias, obj, Cascade.DELETE, context);
}
if (idResource == null && !performedCascading) {
throw new MarshallingException("Alias [" + alias
+ "] has no root mappings and no cascading defined, no operation was perfomed");
}
if (idResource != null) {
compass.getEventManager().onPostDelete(idResource);
}
compass.getEventManager().onPostDelete(alias, obj);
}
public void delete(Class<?> clazz, Object... ids) throws CompassException {
delete(clazz, (Object) ids);
}
public void delete(Class<?> clazz, Object obj) throws CompassException {
checkClosed();
delete(clazz, obj, new DirtyOperationContext(marshallingStrategy));
}
public void delete(Class<?> clazz, Object obj, DirtyOperationContext context) throws CompassException {
if (context.alreadyPerformedOperation(obj)) {
return;
}
if (compass.getEventManager().onPreDelete(clazz, obj) == FilterOperation.YES) {
return;
}
boolean performedCascading = false;
Resource idResource = marshallingStrategy.marshallIds(clazz, obj);
if (idResource != null) {
if (compass.getEventManager().onPreDelete(idResource) == FilterOperation.YES) {
return;
}
Object cascadeObj = null;
// in case we need to do cascading, we need to load the object to we
// can delete its cascaded objects
if (cascadingManager.shouldCascade(idResource.getAlias(), obj, Cascade.DELETE)) {
Resource resouce = getResourceByIdResource(idResource);
if (resouce != null) {
cascadeObj = getByResource(resouce);
}
}
delete(idResource);
if (cascadeObj != null) {
context.addOperatedObjects(cascadeObj);
performedCascading = cascadingManager
.cascade(idResource.getAlias(), cascadeObj, Cascade.DELETE, context);
}
} else {
context.addOperatedObjects(obj);
performedCascading = cascadingManager.cascade(clazz, obj, Cascade.DELETE, context);
}
if (idResource == null && !performedCascading) {
throw new MarshallingException("Object [" + clazz
+ "] has no root mappings and no cascading defined, no operation was perfomed");
}
if (idResource != null) {
compass.getEventManager().onPostDelete(idResource);
compass.getEventManager().onPostDelete(idResource.getAlias(), obj);
} else {
compass.getEventManager().onPostDelete(clazz, obj);
}
}
public void delete(Object obj) throws CompassException {
checkClosed();
delete(obj, new DirtyOperationContext(marshallingStrategy));
}
public void delete(Object obj, DirtyOperationContext context) throws CompassException {
if (context.alreadyPerformedOperation(obj)) {
return;
}
if (compass.getEventManager().onPreDelete((String) null, obj) == FilterOperation.YES) {
return;
}
boolean performedCascading = false;
Resource idResource = marshallingStrategy.marshallIds(obj);
if (idResource != null) {
if (compass.getEventManager().onPreDelete(idResource) == FilterOperation.YES) {
return;
}
Object cascadeObj = null;
// in case we need to do cascading, we need to load the object to we
// can delete its cascaded objects
if (cascadingManager.shouldCascade(idResource.getAlias(), obj, Cascade.DELETE)) {
Resource resouce = getResourceByIdResource(idResource);
if (resouce != null) {
cascadeObj = getByResource(resouce);
}
}
delete(idResource);
if (cascadeObj != null) {
context.addOperatedObjects(cascadeObj);
performedCascading = cascadingManager
.cascade(idResource.getAlias(), cascadeObj, Cascade.DELETE, context);
}
} else {
context.addOperatedObjects(obj);
performedCascading = cascadingManager.cascade(obj, Cascade.DELETE, context);
}
if (idResource == null && !performedCascading) {
throw new MarshallingException("Object [" + obj.getClass().getName()
+ "] has no root mappings and no cascading defined, no operation was perfomed");
}
if (idResource != null) {
compass.getEventManager().onPostDelete(idResource);
compass.getEventManager().onPostDelete(idResource.getAlias(), obj);
} else {
compass.getEventManager().onPostDelete((String) null, obj);
}
}
public void delete(Resource resource) throws CompassException {
checkClosed();
firstLevelCache.evict(((InternalResource) resource).getResourceKey());
if (compass.getEventManager().onPreDelete(resource) == FilterOperation.YES) {
return;
}
searchEngine.delete(resource);
compass.getEventManager().onPostDelete(resource);
}
public void delete(CompassQuery query) throws CompassException {
checkClosed();
query.delete();
}
public void evict(Object obj) {
checkClosed();
Resource idResource = marshallingStrategy.marshallIds(obj.getClass(), obj);
ResourceKey key = ((InternalResource) idResource).getResourceKey();
firstLevelCache.evict(key);
}
public void evict(String alias, Object id) {
checkClosed();
Resource idResource = marshallingStrategy.marshallIds(alias, id);
ResourceKey key = ((InternalResource) idResource).getResourceKey();
firstLevelCache.evict(key);
}
public void evict(Resource resource) {
checkClosed();
ResourceKey key = ((InternalResource) resource).getResourceKey();
firstLevelCache.evict(key);
}
public void evictAll() {
checkClosed();
firstLevelCache.evictAll();
}
private void checkClosed() throws IllegalStateException {
if (closed) {
throw new IllegalStateException("CompassSession already closed");
}
}
@Override
public MarshallingStrategy getMarshallingStrategy() {
return marshallingStrategy;
}
public CompassAnalyzerHelper analyzerHelper() throws CompassException {
checkClosed();
SearchEngineAnalyzerHelper analyzerHelper = searchEngine.analyzerHelper();
return new DefaultCompassAnalyzerHelper(analyzerHelper, this);
}
@Override
public final void beginTransaction() {
bindSession();
}
@Override
public void bindSession() {
CompassSessionFactory sessionFactory = compass.getCompassSessionFactory();
CompassSession boundSession = sessionFactory.getTransactionBoundSession();
if (boundSession == null || boundSession != this) {
sessionFactory.setTransactionBoundSession(this);
}
}
}