/*
* Copyright 2010 Impetus Infotech.
*
* 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 com.impetus.kundera.ejb;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceException;
import javax.persistence.PostPersist;
import javax.persistence.PostRemove;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;
import javax.persistence.Query;
import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.impetus.kundera.CassandraEntityManager;
import com.impetus.kundera.Client;
import com.impetus.kundera.db.DataManager;
import com.impetus.kundera.ejb.event.EntityEventDispatcher;
import com.impetus.kundera.index.IndexManager;
import com.impetus.kundera.metadata.EntityMetadata;
import com.impetus.kundera.metadata.MetadataManager;
import com.impetus.kundera.proxy.EnhancedEntity;
import com.impetus.kundera.query.LuceneQuery;
/**
* The Class EntityManagerImpl.
*
* @author animesh.kumar
*/
public class EntityManagerImpl implements CassandraEntityManager {
/** The Constant log. */
private static final Log log = LogFactory.getLog(EntityManagerImpl.class);
/** The factory. */
private EntityManagerFactoryImpl factory;
/** The closed. */
private boolean closed = false;
/** The client. */
private Client client;
/** The data manager. */
private DataManager dataManager;
/** The index manager. */
private IndexManager indexManager;
/** The metadata manager. */
private MetadataManager metadataManager;
/** The persistence unit name. */
private String persistenceUnitName;
/** The entity resolver. */
private EntityResolver entityResolver;
/** The session. */
private EntityManagerSession session;
/** The event dispatcher. */
private EntityEventDispatcher eventDispatcher;
/**
* Instantiates a new entity manager impl.
*
* @param factory
* the factory
* @param client
* the client
*/
public EntityManagerImpl(EntityManagerFactoryImpl factory) {
this.factory = factory;
this.metadataManager = factory.getMetadataManager();
// this.client = client;
this.persistenceUnitName = factory.getPersistenceUnitName();
dataManager = new DataManager(this);
//indexManager = new IndexManager(this);
entityResolver = new EntityResolver(this);
session = new EntityManagerSession(this);
eventDispatcher = new EntityEventDispatcher();
}
/**
* Gets the factory.
*
* @return the factory
*/
public EntityManagerFactoryImpl getFactory() {
return factory;
}
/*
* @see javax.persistence.EntityManager#find(java.lang.Class,
* java.lang.Object)
*/
@Override
public final <E> E find(Class<E> entityClass, Object primaryKey) {
if (closed) {
throw new PersistenceException("EntityManager already closed.");
}
if (primaryKey == null) {
throw new IllegalArgumentException(
"primaryKey value must not be null.");
}
// Validate
metadataManager.validate(entityClass);
E e = null;
e = session.lookup(entityClass, primaryKey);
if (null != e) {
log.debug(entityClass.getName() + "_" + primaryKey
+ " is loaded from cache!");
return e;
}
return immediateLoadAndCache(entityClass, primaryKey);
}
/**
* Immediate load and cache.
*
* @param <E>
* the element type
* @param entityClass
* the entity class
* @param primaryKey
* the primary key
* @return the e
*/
protected <E> E immediateLoadAndCache(Class<E> entityClass, Object primaryKey) {
try {
EntityMetadata m = metadataManager.getEntityMetadata(entityClass);
m.setDBType(this.client.getType());
E e = dataManager.find(entityClass, m, primaryKey.toString());
if(e != null) {
session.store(primaryKey, e, m.isCacheable());
}
return e;
} catch (Exception exp) {
throw new PersistenceException(exp);
}
}
/*
* @see com.impetus.kundera.CassandraEntityManager#find(java.lang.Class,
* java.lang.Object[])
*/
@Override
public final <E> List<E> find(Class<E> entityClass, Object... primaryKeys) {
if (closed) {
throw new PersistenceException("EntityManager already closed.");
}
if (primaryKeys == null) {
throw new IllegalArgumentException(
"primaryKey value must not be null.");
}
// Validate
metadataManager.validate(entityClass);
if (null == primaryKeys || primaryKeys.length == 0) {
return new ArrayList<E>();
}
// TODO: load from cache first
try {
String[] ids = Arrays.asList(primaryKeys).toArray(new String[] {});
EntityMetadata m = metadataManager.getEntityMetadata(entityClass);
m.setDBType(this.client.getType());
List<E> entities = dataManager.find(entityClass, m, ids);
// TODO: cache entities for future lookup
return entities;
} catch (Exception e) {
throw new PersistenceException(e);
}
}
/* @see javax.persistence.EntityManager#remove(java.lang.Object) */
@Override
public final void remove(Object e) {
if (e == null) {
throw new IllegalArgumentException("Entity must not be null.");
}
// Validate
metadataManager.validate(e.getClass());
try {
List<EnhancedEntity> reachableEntities = entityResolver
.resolve(e, CascadeType.REMOVE, this.client.getType());
// remove each one
for (EnhancedEntity o : reachableEntities) {
log.debug("Removing @Entity >> " + o);
EntityMetadata m = metadataManager.getEntityMetadata(o
.getEntity().getClass());
m.setDBType(this.client.getType());
// fire PreRemove events
eventDispatcher.fireEventListeners (m, o, PreRemove.class);
session.remove(o.getEntity().getClass(), o.getId());
dataManager.remove(o, m);
getIndexManager().remove(m, o.getEntity(), o.getId());
// fire PostRemove events
eventDispatcher.fireEventListeners (m, o, PostRemove.class);
}
} catch (Exception exp) {
throw new PersistenceException(exp);
}
}
/* @see javax.persistence.EntityManager#merge(java.lang.Object) */
@Override
public final <E> E merge(E e) {
if (e == null) {
throw new IllegalArgumentException("Entity must not be null.");
}
// Validate
metadataManager.validate(e.getClass());
try {
List<EnhancedEntity> reachableEntities = entityResolver
.resolve(e, CascadeType.MERGE, this.client.getType());
// save each one
for (EnhancedEntity o : reachableEntities) {
log.debug("Merging @Entity >> " + o);
EntityMetadata metadata = metadataManager.getEntityMetadata(o
.getEntity().getClass());
metadata.setDBType(this.client.getType());
// TODO: throw OptisticLockException if wrong version and optimistic locking enabled
// fire PreUpdate events
eventDispatcher.fireEventListeners(metadata, o, PreUpdate.class);
dataManager.merge(o, metadata);
getIndexManager().update(metadata, o.getEntity());
// fire PreUpdate events
eventDispatcher.fireEventListeners(metadata, o, PostUpdate.class);
}
} catch (Exception exp) {
throw new PersistenceException(exp);
}
return e;
}
/* @see javax.persistence.EntityManager#persist(java.lang.Object) */
@Override
public final void persist(Object e) {
if (e == null) {
throw new IllegalArgumentException("Entity must not be null.");
}
try {
// validate
metadataManager.validate(e.getClass());
List<EnhancedEntity> reachableEntities = entityResolver
.resolve(e, CascadeType.PERSIST, this.client.getType());
// save each one
for (EnhancedEntity o : reachableEntities) {
log.debug("Persisting @Entity >> " + o);
EntityMetadata metadata = metadataManager.getEntityMetadata(o
.getEntity().getClass());
metadata.setDBType(this.client.getType());
// TODO: throw EntityExistsException if already exists
// fire pre-persist events
eventDispatcher.fireEventListeners(metadata, o, PrePersist.class);
//TODO uncomment
dataManager.persist(o, metadata);
getIndexManager().write(metadata, o.getEntity());
// fire post-persist events
eventDispatcher.fireEventListeners(metadata, o, PostPersist.class);
}
} catch (Exception exp) {
throw new PersistenceException(exp);
}
}
/* @see javax.persistence.EntityManager#clear() */
@Override
public final void clear() {
checkClosed();
session.clear();
client.shutdown();
}
/* @see javax.persistence.EntityManager#close() */
@Override
public final void close() {
closed = true;
session = null;
}
/* @see javax.persistence.EntityManager#contains(java.lang.Object) */
@Override
public final boolean contains(Object entity) {
return false;
}
/* @see javax.persistence.EntityManager#createNamedQuery(java.lang.String) */
@Override
public final Query createNamedQuery(String name) {
throw new NotImplementedException("TODO");
}
/* @see javax.persistence.EntityManager#createNativeQuery(java.lang.String) */
@Override
public final Query createNativeQuery(String sqlString) {
throw new NotImplementedException("TODO");
}
/*
* @see javax.persistence.EntityManager#createNativeQuery(java.lang.String,
* java.lang.Class)
*/
@Override
public final Query createNativeQuery(String sqlString, Class resultClass) {
throw new NotImplementedException("TODO");
}
/*
* @see javax.persistence.EntityManager#createNativeQuery(java.lang.String,
* java.lang.String)
*/
@Override
public final Query createNativeQuery(String sqlString,
String resultSetMapping) {
throw new NotImplementedException("TODO");
}
/* @see javax.persistence.EntityManager#createQuery(java.lang.String) */
@Override
public final Query createQuery(String ejbqlString) {
return new LuceneQuery(this, metadataManager, ejbqlString);
}
/* @see javax.persistence.EntityManager#flush() */
@Override
public final void flush() {
// always flushed to cassandra anyway! relax.
}
/* @see javax.persistence.EntityManager#getDelegate() */
@Override
public final Object getDelegate() {
return null;
}
/* @see javax.persistence.EntityManager#getFlushMode() */
@Override
public final FlushModeType getFlushMode() {
throw new NotImplementedException("TODO");
}
/*
* @see javax.persistence.EntityManager#getReference(java.lang.Class,
* java.lang.Object)
*/
@Override
public final <T> T getReference(Class<T> entityClass, Object primaryKey) {
throw new NotImplementedException("TODO");
}
/* @see javax.persistence.EntityManager#getTransaction() */
@Override
public final EntityTransaction getTransaction() {
return new EntityTransactionImpl();
}
/* @see javax.persistence.EntityManager#isOpen() */
@Override
public final boolean isOpen() {
return !closed;
}
/* @see javax.persistence.EntityManager#joinTransaction() */
@Override
public final void joinTransaction() {
// TODO Auto-generated method stub
}
/*
* @see javax.persistence.EntityManager#lock(java.lang.Object,
* javax.persistence.LockModeType)
*/
@Override
public final void lock(Object entity, LockModeType lockMode) {
throw new NotImplementedException("TODO");
}
/* @see javax.persistence.EntityManager#refresh(java.lang.Object) */
@Override
public final void refresh(Object entity) {
throw new NotImplementedException("TODO");
}
/*
* @see
* javax.persistence.EntityManager#setFlushMode(javax.persistence.FlushModeType
* )
*/
/* @see javax.persistence.EntityManager#setFlushMode(javax.persistence.FlushModeType) */
@Override
public final void setFlushMode(FlushModeType flushMode) {
throw new NotImplementedException("TODO");
}
/**
* Check closed.
*/
private void checkClosed() {
if (!isOpen()) {
throw new IllegalStateException("EntityManager has been closed.");
}
}
/**
* Gets the metadata manager.
*
* @return the metadataManager
*/
public final MetadataManager getMetadataManager() {
return metadataManager;
}
/**
* Gets the data manager.
*
* @return the dataManager
*/
public final DataManager getDataManager() {
return dataManager;
}
/**
* Gets the index manager.
*
* @return the indexManager
*/
public final IndexManager getIndexManager() {
if(indexManager ==null) {
indexManager = new IndexManager(this);
}
return indexManager;
}
/**
* Gets the client.
*
* @return the client
*/
@Override
public final Client getClient() {
return client;
}
/**
* Gets the persistence unit name.
*
* @return the persistence unit name
*/
public final String getPersistenceUnitName() {
return persistenceUnitName;
}
/**
* Gets the session.
*
* @return the session
*/
protected EntityManagerSession getSession() {
return session;
}
/**
* Gets the entity resolver.
*
* @return the reachabilityResolver
*/
public EntityResolver getEntityResolver() {
return entityResolver;
}
}