001 /*
002 GRANITE DATA SERVICES
003 Copyright (C) 2012 GRANITE DATA SERVICES S.A.S.
004
005 This file is part of Granite Data Services.
006
007 Granite Data Services is free software; you can redistribute it and/or modify
008 it under the terms of the GNU Library General Public License as published by
009 the Free Software Foundation; either version 2 of the License, or (at your
010 option) any later version.
011
012 Granite Data Services is distributed in the hope that it will be useful, but
013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015 for more details.
016
017 You should have received a copy of the GNU Library General Public License
018 along with this library; if not, see <http://www.gnu.org/licenses/>.
019 */
020
021 package org.granite.client.tide.data.impl;
022
023 import java.lang.annotation.ElementType;
024 import java.lang.reflect.Field;
025 import java.lang.reflect.Method;
026 import java.util.HashMap;
027 import java.util.Map;
028
029 import javax.validation.Path;
030 import javax.validation.Path.Node;
031 import javax.validation.TraversableResolver;
032
033 import org.granite.client.tide.data.Dirty;
034 import org.granite.client.tide.data.Id;
035 import org.granite.client.tide.data.Lazy;
036 import org.granite.client.tide.data.Version;
037 import org.granite.client.tide.data.spi.DataManager;
038 import org.granite.client.tide.data.spi.EntityDescriptor;
039 import org.granite.messaging.amf.RemoteClass;
040 import org.granite.util.Introspector;
041
042 /**
043 * @author William DRAI
044 */
045 public abstract class AbstractDataManager implements DataManager {
046
047 private static Map<Class<?>, EntityDescriptor> entityDescriptors = new HashMap<Class<?>, EntityDescriptor>(50);
048
049
050 public EntityDescriptor getEntityDescriptor(Object entity) {
051 EntityDescriptor desc = entityDescriptors.get(entity.getClass());
052 if (desc != null)
053 return desc;
054
055 String className;
056 if (entity.getClass().isAnnotationPresent(RemoteClass.class))
057 className = entity.getClass().getAnnotation(RemoteClass.class).value();
058 else
059 className = entity.getClass().getName();
060
061 String idPropertyName = null, versionPropertyName = null, dirtyPropertyName = null;
062 @SuppressWarnings("unused")
063 boolean hasDirty = false;
064 Field dsField = null, initField = null;
065
066 Map<String, Boolean> lazy = new HashMap<String, Boolean>();
067 for (Method m : entity.getClass().getMethods()) {
068 if (m.getName().startsWith("get") && m.getParameterTypes().length == 0 && m.getReturnType() != Void.class) {
069 if (m.isAnnotationPresent(Id.class))
070 idPropertyName = Introspector.decapitalize(m.getName().substring(3));
071 else if (m.isAnnotationPresent(Version.class))
072 versionPropertyName = Introspector.decapitalize(m.getName().substring(3));
073 else if (m.isAnnotationPresent(Lazy.class))
074 lazy.put(Introspector.decapitalize(m.getName().substring(3)), true);
075 }
076 else if (m.getName().startsWith("is") && m.getParameterTypes().length == 0 && m.getReturnType() == boolean.class) {
077 if (m.isAnnotationPresent(Dirty.class))
078 dirtyPropertyName = Introspector.decapitalize(m.getName().substring(2));
079 }
080 }
081
082 Class<?> clazz = entity.getClass();
083 while (clazz != null && clazz != Object.class) {
084 for (Field f : clazz.getDeclaredFields()) {
085 if (f.isAnnotationPresent(Id.class) && idPropertyName == null) {
086 idPropertyName = f.getName();
087 }
088 else if (f.isAnnotationPresent(Version.class) && versionPropertyName == null) {
089 versionPropertyName = f.getName();
090 }
091 else if (f.isAnnotationPresent(Dirty.class) && dirtyPropertyName == null) {
092 dirtyPropertyName = f.getName();
093 }
094 else if (f.getName().equals("__detachedState") && dsField == null)
095 dsField = f;
096 else if (f.getName().equals("__initialized") && initField == null)
097 initField = f;
098 else if (f.isAnnotationPresent(Lazy.class))
099 lazy.put(Introspector.decapitalize(f.getName().substring(3)), true);
100 }
101 clazz = clazz.getSuperclass();
102 }
103
104 desc = new EntityDescriptor(className, idPropertyName, versionPropertyName, dirtyPropertyName, dsField, initField, lazy);
105 entityDescriptors.put(entity.getClass(), desc);
106
107 return desc;
108 }
109
110
111 private TraversableResolver traversableResolver = new TraversableResolverImpl();
112
113 public TraversableResolver getTraversableResolver() {
114 return traversableResolver;
115 }
116
117 public class TraversableResolverImpl implements TraversableResolver {
118
119 public boolean isReachable(Object bean, Node propertyPath, Class<?> rootBeanType, Path pathToTraversableObject, ElementType elementType) {
120 return true;
121 }
122
123 public boolean isCascadable(Object bean, Node propertyPath, Class<?> rootBeanType, Path pathToTraversableObject, ElementType elementType) {
124 return true;
125 }
126
127 }
128 }