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.beans.Introspector;
024    import java.lang.reflect.Method;
025    import java.util.Collections;
026    import java.util.LinkedHashMap;
027    import java.util.List;
028    import java.util.Map;
029    import java.util.Set;
030    
031    import javax.validation.ConstraintViolation;
032    
033    import org.granite.client.persistence.LazyableCollection;
034    import org.granite.client.tide.collections.ManagedPersistentCollection;
035    import org.granite.client.tide.collections.ManagedPersistentMap;
036    import org.granite.client.tide.data.Identifiable;
037    import org.granite.client.tide.data.Transient;
038    import org.granite.client.tide.data.spi.EntityDescriptor;
039    
040    /**
041     * @author William DRAI
042     */
043    public class JavaBeanDataManager extends AbstractDataManager {
044    
045        @Override
046        public void setTrackingHandler(TrackingHandler trackingHandler) {
047        }
048    
049        @Override
050        public Object getProperty(Object object, String propertyName) {
051            try {
052                Method m = object.getClass().getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
053                return m.invoke(object);
054            }
055            catch (NoSuchMethodException e) {
056                try {
057                    Method m = object.getClass().getMethod("is" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
058                    return m.invoke(object);
059                }
060                catch (Exception f) {
061                    throw new RuntimeException("Could not get property " + propertyName + " on object " + object, f);
062                }
063            }
064            catch (Exception e) {
065                throw new RuntimeException("Could not get property " + propertyName + " on object " + object, e);
066            }
067        }
068    
069        @Override
070        public void setProperty(Object object, String propertyName, Object oldValue, Object newValue) {
071            try {
072                Method[] methods = object.getClass().getMethods();
073                String setter = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
074                for (Method m : methods) {
075                    if (m.getName().equals(setter) && m.getParameterTypes().length == 1 && m.getParameterTypes()[0].isInstance(newValue)) {
076                        m.invoke(object, newValue);
077                        break;
078                    }
079                }
080            }
081            catch (Exception e) {
082                throw new RuntimeException("Could not get property " + propertyName + " on object " + object, e);
083            }
084        }
085    
086        @Override
087        public void setInternalProperty(Object object, String propertyName, Object value) {
088            setProperty(object, propertyName, null, value);
089        }
090    
091        @SuppressWarnings("unchecked")
092            @Override
093        public Map<String, Object> getPropertyValues(Object object, boolean includeReadOnly, boolean includeTransient) {
094            return getPropertyValues(object, Collections.EMPTY_LIST, includeReadOnly, includeTransient);
095        }
096    
097        @Override
098        public Map<String, Object> getPropertyValues(Object object, List<String> excludedProperties, boolean includeReadOnly, boolean includeTransient) {
099            EntityDescriptor desc = getEntityDescriptor(object);
100            
101            Map<String, Object> values = new LinkedHashMap<String, Object>();
102            for (Method m : object.getClass().getMethods()) {
103                if (!m.getName().startsWith("get") && !m.getName().startsWith("is"))
104                    continue;
105                if (m.getDeclaringClass().equals(Object.class))
106                    continue;
107                
108                if (!includeTransient && m.isAnnotationPresent(Transient.class))
109                    continue;
110                
111                String pname = Introspector.decapitalize(m.getName().substring(m.getName().startsWith("get") ? 3 : 2));
112                
113                if (!includeReadOnly) {
114                    try {
115                            object.getClass().getMethod("set" + pname.substring(0, 1).toUpperCase() + pname.substring(1), m.getReturnType());
116                    }
117                    catch (NoSuchMethodException e) {
118                            continue;
119                    }               
120                }            
121                
122                if (desc.getDirtyPropertyName() != null && desc.getDirtyPropertyName().equals(pname))
123                    continue;
124                
125                try {
126                    if (excludedProperties.contains(pname))
127                        continue;
128                    
129                    Object value = m.invoke(object);
130                    
131                    values.put(pname, value);
132                }
133                catch (Exception e) {
134                    throw new RuntimeException("Could not get property " + m + " on object " + object, e);
135                }
136            }
137            return values;    
138        }
139    
140        @Override
141        public ManagedPersistentCollection<Object> newPersistentCollection(Identifiable parent, String propertyName, LazyableCollection nextList) {
142            return null;
143        }
144    
145        @Override
146        public ManagedPersistentMap<Object, Object> newPersistentMap(Identifiable parent, String propertyName, LazyableCollection nextMap) {
147            return null;
148        }
149    
150        @Override
151        public void startTracking(Object previous, Object parent) {
152        }
153    
154        @Override
155        public void stopTracking(Object previous, Object parent) {
156        }
157    
158        @Override
159        public void clear() {
160        }
161    
162        public boolean isDirty() {
163            return false;
164        }
165    
166        @Override
167        public void notifyDirtyChange(boolean oldDirty, boolean dirty) {            
168        }
169    
170        @Override
171        public void notifyEntityDirtyChange(Object entity, boolean oldDirtyEntity, boolean newDirtyEntity) {
172        }
173        
174        @Override
175        public void notifyConstraintViolations(Object entity, Set<ConstraintViolation<?>> violations) {         
176        }
177    
178    }