/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* Granite Data Services 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 2.1 of the License, or (at your option) any later version.
*
* Granite Data Services 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA, or see <http://www.gnu.org/licenses/>.
*/
package org.granite.client.persistence;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.granite.client.persistence.collection.PersistentCollection;
import org.granite.messaging.reflect.Property;
import org.granite.messaging.reflect.PropertyAccessException;
import org.granite.messaging.reflect.PropertyNotFoundException;
import org.granite.messaging.reflect.Reflection;
/**
* @author Franck WOLFF
*/
public class Persistence {
private static final String INITIALIZED_FIELD_NAME = "__initialized__";
private static final String DETACHED_STATE_FIELD_NAME = "__detachedState__";
private final Reflection reflection;
///////////////////////////////////////////////////////////////////////////
// Constructor
public Persistence(Reflection reflection) {
this.reflection = reflection;
}
///////////////////////////////////////////////////////////////////////////
// Entity
public boolean isEntity(Class<?> cls) {
return cls != null && cls.isAnnotationPresent(Entity.class);
}
protected void checkEntity(Class<?> entityClass) {
if (!isEntity(entityClass))
throw new PropertyNotFoundException("Not annotated with @" + Entity.class.getName() + ": " + entityClass);
}
///////////////////////////////////////////////////////////////////////////
// Initialized
protected Property getInitializedProperty(Class<?> entityClass, boolean throwIfNotFound) {
checkEntity(entityClass);
Property property = reflection.findProperty(entityClass, INITIALIZED_FIELD_NAME, Boolean.TYPE);
if (property == null && throwIfNotFound)
throw new PropertyNotFoundException("No boolean " + INITIALIZED_FIELD_NAME + " property in " + entityClass);
return property;
}
public Property getInitializedProperty(Class<?> entityClass) {
return getInitializedProperty(entityClass, false);
}
public boolean hasInitializedProperty(Class<?> entityClass) {
return getInitializedProperty(entityClass, false) != null;
}
public boolean isInitialized(Object o) {
if (o instanceof PersistentCollection)
return ((PersistentCollection<?>)o).wasInitialized();
Class<?> cls = o.getClass();
if (!isEntity(cls))
return true;
Property property = getInitializedProperty(cls, false);
if (property == null)
return true;
try {
return property.getBoolean(o);
}
catch (Exception e) {
throw new PropertyAccessException("Could not get " + property + " of object " + o, e);
}
}
public void setInitialized(Object entity, boolean value) {
Property property = getInitializedProperty(entity.getClass(), true);
try {
property.setBoolean(entity, value);
}
catch (Exception e) {
throw new PropertyAccessException("Could not set " + property + " of object " + entity + " to value " + value, e);
}
}
///////////////////////////////////////////////////////////////////////////
// Detached state
protected Property getDetachedStateProperty(Class<?> entityClass, boolean throwIfNotFound) {
checkEntity(entityClass);
Property property = reflection.findProperty(entityClass, DETACHED_STATE_FIELD_NAME, String.class);
if (property == null && throwIfNotFound)
throw new PropertyNotFoundException("No String " + DETACHED_STATE_FIELD_NAME + " property in " + entityClass);
return property;
}
public Property getDetachedStateProperty(Class<?> entityClass) {
return getDetachedStateProperty(entityClass, false);
}
public boolean hasDetachedStateProperty(Class<?> entityClass) {
return getDetachedStateProperty(entityClass, false) != null;
}
public String getDetachedState(Object entity) {
Property property = getDetachedStateProperty(entity.getClass(), true);
try {
return (String)property.getObject(entity);
}
catch (Exception e) {
throw new PropertyAccessException("Could not get " + property + " of object " + entity, e);
}
}
public void setDetachedState(Object entity, String value) {
Property property = getDetachedStateProperty(entity.getClass(), true);
try {
property.setObject(entity, value);
}
catch (Exception e) {
throw new PropertyAccessException("Could not set " + property + " of object " + entity + " to value " + value, e);
}
}
///////////////////////////////////////////////////////////////////////////
// Id
protected Property getIdProperty(Class<?> entityClass, boolean throwIfNotFound) {
checkEntity(entityClass);
Property property = reflection.findProperty(entityClass, Id.class);
if (property == null && throwIfNotFound)
throw new PropertyNotFoundException("No property annotated with " + Id.class.getName() + " in " + entityClass);
return property;
}
public Property getIdProperty(Class<?> entityClass) {
return getIdProperty(entityClass, false);
}
public boolean hasIdProperty(Class<?> entityClass) {
return getIdProperty(entityClass, false) != null;
}
@SuppressWarnings("unchecked")
public <T> T getId(Object entity) {
Property property = getIdProperty(entity.getClass(), true);
try {
return (T)property.getObject(entity);
}
catch (Exception e) {
throw new PropertyAccessException("Could not get " + property + " of object " + entity, e);
}
}
public void setId(Object entity, Object value) {
Property property = getIdProperty(entity.getClass(), true);
try {
property.setObject(entity, value);
}
catch (Exception e) {
throw new PropertyAccessException("Could not set " + property + " of object " + entity + " to value " + value, e);
}
}
///////////////////////////////////////////////////////////////////////////
// Uid
protected Property getUidProperty(Class<?> entityClass, boolean throwIfNotFound) {
checkEntity(entityClass);
Property property = reflection.findProperty(entityClass, Uid.class);
if (property == null && throwIfNotFound)
throw new PropertyNotFoundException("No property annotated with " + Uid.class.getName() + " in " + entityClass);
return property;
}
public Property getUidProperty(Class<?> entityClass) {
return getUidProperty(entityClass, false);
}
public boolean hasUidProperty(Class<?> entityClass) {
return getUidProperty(entityClass, false) != null;
}
public String getUid(Object entity) {
Property property = getUidProperty(entity.getClass(), true);
try {
return (String)property.getObject(entity);
}
catch (Exception e) {
throw new PropertyAccessException("Could not get " + property + " of object " + entity, e);
}
}
public void setUid(Object entity, String value) {
Property property = getUidProperty(entity.getClass(), true);
try {
property.setObject(entity, value);
}
catch (Exception e) {
throw new PropertyAccessException("Could not set " + property + " of object " + entity + " to value " + value, e);
}
}
///////////////////////////////////////////////////////////////////////////
// Version
protected Property getVersionProperty(Class<?> entityClass, boolean throwIfNotFound) {
checkEntity(entityClass);
Property property = reflection.findProperty(entityClass, Version.class);
if (property == null && throwIfNotFound)
throw new PropertyNotFoundException("No property annotated with " + Version.class.getName() + " in " + entityClass);
return property;
}
public Property getVersionProperty(Class<?> entityClass) {
return getVersionProperty(entityClass, false);
}
public boolean hasVersionProperty(Class<?> entityClass) {
return getVersionProperty(entityClass, false) != null;
}
@SuppressWarnings("unchecked")
public <T> T getVersion(Object entity) {
Property property = getVersionProperty(entity.getClass(), true);
try {
return (T)property.getObject(entity);
}
catch (Exception e) {
throw new PropertyAccessException("Could not get " + property + " of object " + entity, e);
}
}
public List<Property> getLazyProperties(Class<?> entityClass) {
List<Property> properties = reflection.findSerializableProperties(entityClass);
List<Property> lazyProperties = new ArrayList<Property>();
for (Property property : properties) {
if (property.isAnnotationPresent(Lazy.class))
lazyProperties.add(property);
}
return lazyProperties;
}
public List<Property> getProperties(Class<?> entityClass) {
return reflection.findSerializableProperties(entityClass);
}
public Object getPropertyValue(Object entity, String name, boolean raw) {
Property property = reflection.findSerializableProperty(entity.getClass(), name);
if (property == null)
throw new RuntimeException("Property " + name + " not found on object " + entity);
try {
return raw ? property.getRawObject(entity) : property.getObject(entity);
}
catch (Exception e) {
throw new RuntimeException("Could not get " + property + " of object " + entity, e);
}
}
public void setPropertyValue(Object entity, String name, Object value) {
Property property = reflection.findSerializableProperty(entity.getClass(), name);
if (property == null)
throw new RuntimeException("Property " + name + " not found on object " + entity);
try {
property.setObject(entity, value);
}
catch (Exception e) {
throw new RuntimeException("Could not set " + property + " of object " + entity, e);
}
}
public Map<String, Object> getPropertyValues(Object entity, boolean raw, boolean excludeIdUid, boolean excludeVersion, boolean includeReadOnly) {
Map<String, Object> values = new LinkedHashMap<String, Object>();
List<Property> properties = reflection.findSerializableProperties(entity.getClass());
List<Property> excludedProperties = new ArrayList<Property>();
if (isEntity(entity.getClass())) {
excludedProperties.add(getInitializedProperty(entity.getClass()));
excludedProperties.add(getDetachedStateProperty(entity.getClass()));
if (excludeIdUid && hasIdProperty(entity.getClass()))
excludedProperties.add(getIdProperty(entity.getClass()));
if (excludeIdUid && hasUidProperty(entity.getClass()))
excludedProperties.add(getUidProperty(entity.getClass()));
if (excludeVersion && hasVersionProperty(entity.getClass()))
excludedProperties.add(getVersionProperty(entity.getClass()));
}
for (Property property : properties) {
if (excludedProperties.contains(property))
continue;
if (!includeReadOnly && !property.isWritable())
continue;
try {
values.put(property.getName(), raw ? property.getRawObject(entity) : property.getObject(entity));
}
catch (Exception e) {
throw new RuntimeException("Could not get property " + property.getName() + " on entity " + entity, e);
}
}
return values;
}
}