001/**
002 *   GRANITE DATA SERVICES
003 *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 *   This file is part of the Granite Data Services Platform.
006 *
007 *   Granite Data Services is free software; you can redistribute it and/or
008 *   modify it under the terms of the GNU Lesser General Public
009 *   License as published by the Free Software Foundation; either
010 *   version 2.1 of the License, or (at your option) any later version.
011 *
012 *   Granite Data Services is distributed in the hope that it will be useful,
013 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 *   General Public License for more details.
016 *
017 *   You should have received a copy of the GNU Lesser General Public
018 *   License along with this library; if not, write to the Free Software
019 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 *   USA, or see <http://www.gnu.org/licenses/>.
021 */
022package org.granite.toplink;
023
024import java.lang.reflect.Field;
025import java.lang.reflect.Modifier;
026import java.util.ArrayList;
027import java.util.List;
028
029import javax.persistence.Entity;
030
031import org.granite.logging.Logger;
032import org.granite.messaging.amf.io.util.DefaultClassGetter;
033import org.granite.util.TypeUtil;
034
035import oracle.toplink.essentials.indirection.IndirectContainer;
036import oracle.toplink.essentials.indirection.ValueHolderInterface;
037
038/**
039 * @author William DRAI
040 */
041public class TopLinkClassGetter extends DefaultClassGetter {
042
043    public final static Logger log = Logger.getLogger(TopLinkClassGetter.class);
044
045    @Override
046    public Class<?> getClass(Object o) {
047
048        if (o instanceof ValueHolderInterface) {
049            ValueHolderInterface holder = (ValueHolderInterface)o;
050            
051            String className = (
052                holder.isInstantiated() ?
053                holder.getValue().getClass().getName() :
054                Object.class.getName()
055            ); 
056            
057            if (className != null && className.length() > 0) {
058                try {
059                    return TypeUtil.forName(className);
060                } catch (Exception e) {
061                    log.warn(e, "Could not get class with initializer: %s for: %s", className, className);
062                }
063            }
064            // fallback...
065            return Object.class;
066        }
067        else if (o instanceof TopLinkProxy) {
068            return ((TopLinkProxy)o).getProxiedClass();
069        }
070
071        return super.getClass(o);
072    }
073    
074    @Override
075    public boolean isEntity(Object o) {
076        return o.getClass().isAnnotationPresent(Entity.class);    
077    }
078
079    @Override
080    public boolean isInitialized(Object owner, String propertyName, Object propertyValue) {
081        if (propertyValue instanceof ValueHolderInterface)
082            return ((ValueHolderInterface)propertyValue).isInstantiated();
083        else if (propertyValue instanceof IndirectContainer)
084            return ((IndirectContainer)propertyValue).isInstantiated();
085        
086        return true;
087    }
088    
089    @Override
090    public void initialize(Object owner, String propertyName, Object propertyValue) {
091        if (propertyValue instanceof ValueHolderInterface)
092            ((ValueHolderInterface)propertyValue).getValue().toString();
093        else if (propertyValue instanceof IndirectContainer)
094            ((IndirectContainer)propertyValue).getValueHolder().getValue().toString();
095    }
096    
097    @Override
098    public List<Object[]> getFieldValues(Object obj, Object dest) {
099        List<Object[]> fieldValues = new ArrayList<Object[]>();
100        
101        List<String> topLinkVhs = new ArrayList<String>();
102        
103        // Merges field values
104        try {
105            Class<?> clazz = obj.getClass();
106            while (clazz != null) {
107                Field[] fields = clazz.getDeclaredFields();
108                for (Field field : fields) {
109                    if ((field.getModifiers() & Modifier.STATIC) != 0 
110                        || (field.getModifiers() & Modifier.FINAL) != 0 
111                        || (field.getModifiers() & Modifier.VOLATILE) != 0 
112                        || (field.getModifiers() & Modifier.NATIVE) != 0 
113                        || (field.getModifiers() & Modifier.TRANSIENT) != 0)
114                        continue;
115                    
116                    if (ValueHolderInterface.class.isAssignableFrom(field.getType())) {
117                        field.setAccessible(true);
118                        ValueHolderInterface vh = (ValueHolderInterface)field.get(obj);
119                        if (!vh.isInstantiated()) {
120                            topLinkVhs.add(field.getName());
121                            field.set(dest, vh);
122                        }
123                    }
124                    else if (!topLinkVhs.contains("_toplink_" + field.getName() + "_vh")) {
125                        field.setAccessible(true);
126                        Object o = field.get(obj);
127                        if (dest != null) {
128                            Object d = field.get(dest);
129                            fieldValues.add(new Object[] { field, o, d });
130                        }
131                        else
132                            fieldValues.add(new Object[] { field, o });
133                    }
134                }
135                clazz = clazz.getSuperclass();
136            }
137        }
138        catch (Exception e) {
139            throw new RuntimeException("Could not merge entity ", e);
140        }
141        
142        return fieldValues;
143    }
144}