/*
* Copyright (c) 2005-2016 Vincent Vandenschrick. All rights reserved.
*
* This file is part of the Jspresso framework.
*
* Jspresso is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Jspresso 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Jspresso. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jspresso.framework.model.persistence.hibernate;
import java.io.Serializable;
import java.util.Collection;
import org.hibernate.EmptyInterceptor;
import org.hibernate.EntityMode;
import org.hibernate.Hibernate;
import org.hibernate.type.Type;
import org.jspresso.framework.model.component.ILifecycleCapable;
import org.jspresso.framework.model.entity.EntityException;
import org.jspresso.framework.model.entity.IEntity;
import org.jspresso.framework.model.entity.IEntityFactory;
import org.jspresso.framework.model.entity.IEntityLifecycleHandler;
import org.jspresso.framework.security.UserPrincipal;
import org.jspresso.framework.util.bean.PropertyHelper;
/**
* This hibernate interceptor enables hibernate to handle entities which are
* implemented by proxies. Its main goal is to provide hibernate with new
* instances of entities based on their core interface contract.
*
* @author Vincent Vandenschrick
*/
public class EntityProxyInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = -7357726538191018694L;
private IEntityFactory entityFactory;
/**
* Returns the fully qualified name of the entity passed as parameter.
* <p/>
* {@inheritDoc}
*/
@Override
public String getEntityName(Object object) {
if (object instanceof IEntity) {
return ((IEntity) object).getComponentContract().getName();
}
return null;
}
/**
* Instantiates a new entity (proxy) based on the entityDescriptor returned
* from the bean factory. The entityName which is the fully qualified name of
* the entity interface contract is used as the lookup key in the bean
* factory.
* <p/>
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
try {
return entityFactory.createEntityInstance((Class<? extends IEntity>) Class.forName(entityName), id);
} catch (ClassNotFoundException ex) {
throw new EntityException(ex);
}
}
/**
* {@inheritDoc}
*/
@Override
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
if (entity instanceof ILifecycleCapable) {
((ILifecycleCapable) entity).onDelete(getEntityFactory(), getPrincipal(), getEntityLifecycleHandler());
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
boolean stateUpdated = false;
if (entity instanceof IEntity && entity instanceof ILifecycleCapable) {
if (((ILifecycleCapable) entity).onPersist(getEntityFactory(), getPrincipal(), getEntityLifecycleHandler())) {
extractState((IEntity) entity, propertyNames, state);
stateUpdated = true;
}
}
return stateUpdated;
}
/**
* {@inheritDoc}
*/
@Override
public Boolean isTransient(Object entity) {
if (!Hibernate.isInitialized(entity)) {
return Boolean.FALSE;
}
return super.isTransient(entity);
}
/**
* Sets the entityFactory.
*
* @param entityFactory
* the entityFactory to set.
*/
public void setEntityFactory(IEntityFactory entityFactory) {
this.entityFactory = entityFactory;
}
/**
* Gets the entityFactory.
*
* @return the entityFactory.
*/
protected IEntityFactory getEntityFactory() {
return entityFactory;
}
/**
* Gets the lifecycle handler.
*
* @return the entity lifecycle handler.
*/
protected IEntityLifecycleHandler getEntityLifecycleHandler() {
return null;
}
/**
* Gets the principal owning the session.
*
* @return the principal owning the session.
*/
protected UserPrincipal getPrincipal() {
return null;
}
/**
* Hibernate uses "extra" properties to cope with relationships e.g.
* _[collectionName]BackRef or _[collectionName]IndexBackRef Those properties
* are not known by the entity and thus cannot be extracted.
*
* @param propertyName
* the property name to test.
* @return true if this property is an Hibernate internal managed one.
*/
protected boolean isHibernateInternal(String propertyName) {
return propertyName.startsWith("_");
}
private void extractState(IEntity entity, String[] propertyNames, Object... state) {
for (int i = 0; i < propertyNames.length; i++) {
String propertyName = propertyNames[i];
if (!isHibernateInternal(propertyName)) {
Object property = entity.straightGetProperty(PropertyHelper.fromJavaBeanPropertyName(propertyName));
if (!(property instanceof Collection<?>)) {
state[i] = property;
}
}
}
}
}