org.broadleafcommerce.openadmin.server.service.persistence.module.FieldManager.java Source code

Java tutorial

Introduction

Here is the source code for org.broadleafcommerce.openadmin.server.service.persistence.module.FieldManager.java

Source

/*
 * #%L
 * BroadleafCommerce Open Admin Platform
 * %%
 * Copyright (C) 2009 - 2013 Broadleaf Commerce
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package org.broadleafcommerce.openadmin.server.service.persistence.module;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.common.persistence.EntityConfiguration;
import org.broadleafcommerce.common.util.HibernateUtils;
import org.broadleafcommerce.common.util.dao.DynamicDaoHelper;
import org.broadleafcommerce.common.util.dao.DynamicDaoHelperImpl;
import org.broadleafcommerce.openadmin.server.service.persistence.PersistenceManager;
import org.broadleafcommerce.openadmin.server.service.persistence.PersistenceManagerFactory;
import org.broadleafcommerce.openadmin.server.service.persistence.TargetModeType;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.persistence.EntityManager;

/**
 * 
 * @author jfischer
 *
 */
public class FieldManager {

    private static final Log LOG = LogFactory.getLog(FieldManager.class);

    public static final String MAPFIELDSEPARATOR = "---";

    protected EntityConfiguration entityConfiguration;
    protected EntityManager entityManager;
    protected DynamicDaoHelper helper = new DynamicDaoHelperImpl();
    protected List<SortableValue> middleFields = new ArrayList<SortableValue>(5);

    public FieldManager(EntityConfiguration entityConfiguration, EntityManager entityManager) {
        this.entityConfiguration = entityConfiguration;
        this.entityManager = entityManager;
    }

    public static Field getSingleField(Class<?> clazz, String fieldName) throws IllegalStateException {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException nsf) {
            // Try superclass
            if (clazz.getSuperclass() != null) {
                return getSingleField(clazz.getSuperclass(), fieldName);
            }

            return null;
        }
    }

    public Field getField(Class<?> clazz, String fieldName) throws IllegalStateException {
        PersistenceManager persistenceManager = getPersistenceManager();
        String[] tokens = fieldName.split("\\.");
        Field field = null;

        for (int j = 0; j < tokens.length; j++) {
            String propertyName = tokens[j];
            Class<?>[] myEntities = persistenceManager.getUpDownInheritance(clazz);
            Class<?> myClass;
            if (ArrayUtils.isEmpty(myEntities)) {
                myClass = clazz;
            } else {
                myClass = getClassForField(persistenceManager, propertyName, null, myEntities);
            }
            if (myClass == null) {
                LOG.debug(String.format(
                        "Unable to find the field (%s) anywhere in the inheritance hierarchy for (%s)",
                        propertyName, clazz.getName()));
                return null;
            }
            field = getSingleField(myClass, propertyName);
            if (field != null && j < tokens.length - 1) {
                Class<?>[] fieldEntities = persistenceManager.getUpDownInheritance(field.getType());
                if (!ArrayUtils.isEmpty(fieldEntities)) {
                    clazz = getClassForField(persistenceManager, tokens[j + 1], field, fieldEntities);
                    if (clazz == null) {
                        return null;
                    }
                } else {
                    //may be an embedded class - try the class directly
                    clazz = field.getType();
                }
            } else {
                break;
            }
        }

        if (field != null) {
            field.setAccessible(true);
        }
        return field;
    }

    protected Class<?> getClassForField(PersistenceManager persistenceManager, String token, Field field,
            Class<?>[] entities) {
        Class<?> clazz;
        List<Class<?>> matchedClasses = new ArrayList<Class<?>>();
        for (Class<?> entity : entities) {
            Field peekAheadField = null;
            try {
                peekAheadField = entity.getDeclaredField(token);
            } catch (NoSuchFieldException nsf) {
                //do nothing
            }
            if (peekAheadField != null) {
                matchedClasses.add(entity);
            }
        }
        if (matchedClasses.size() > 1) {
            LOG.warn("Found the property (" + token + ") in more than one class of an inheritance hierarchy. "
                    + "This may lead to unwanted behavior, as the system does not know which class was intended. Do not "
                    + "use the same property name in different levels of the inheritance hierarchy. Defaulting to the "
                    + "first class found (" + matchedClasses.get(0).getName() + ")");
        }
        if (matchedClasses.isEmpty()) {
            //probably an artificial field (i.e. passwordConfirm on AdminUserImpl)
            return null;
        }
        Class<?> myClass = field != null ? field.getType() : entities[0];
        if (getSingleField(matchedClasses.get(0), token) != null) {
            clazz = matchedClasses.get(0);
            Class<?>[] entities2 = persistenceManager.getUpDownInheritance(clazz);
            if (!ArrayUtils.isEmpty(entities2) && matchedClasses.size() == 1 && clazz.isInterface()) {
                try {
                    clazz = entityConfiguration.lookupEntityClass(myClass.getName());
                } catch (Exception e) {
                    // Do nothing - we'll use the matchedClass
                }
            }
        } else {
            clazz = myClass;
        }
        return clazz;
    }

    public Object getFieldValue(Object bean, String fieldName)
            throws IllegalAccessException, FieldNotAvailableException {
        StringTokenizer tokens = new StringTokenizer(fieldName, ".");
        Class<?> componentClass = bean.getClass();
        Field field;
        Object value = HibernateUtils.deproxy(bean);

        while (tokens.hasMoreTokens()) {
            String fieldNamePart = tokens.nextToken();
            String mapKey = null;
            if (fieldNamePart.contains(FieldManager.MAPFIELDSEPARATOR)) {
                mapKey = fieldNamePart.substring(fieldNamePart.indexOf(FieldManager.MAPFIELDSEPARATOR)
                        + FieldManager.MAPFIELDSEPARATOR.length(), fieldNamePart.length());
                fieldNamePart = fieldNamePart.substring(0, fieldNamePart.indexOf(FieldManager.MAPFIELDSEPARATOR));
            }
            field = getSingleField(componentClass, fieldNamePart);
            if (field != null) {
                field.setAccessible(true);
                value = field.get(value);
                if (value != null && mapKey != null) {
                    value = ((Map) value).get(mapKey);
                }
                if (value != null) {
                    componentClass = value.getClass();
                } else {
                    break;
                }
            } else {
                throw new FieldNotAvailableException(
                        "Unable to find field (" + fieldNamePart + ") on the class (" + componentClass + ")");
            }
        }

        return value;

    }

    public Object setFieldValue(Object bean, String fieldName, Object newValue)
            throws IllegalAccessException, InstantiationException {
        StringTokenizer tokens = new StringTokenizer(fieldName, ".");
        Class<?> componentClass = bean.getClass();
        Field field;
        bean = HibernateUtils.deproxy(bean);
        Object value = bean;

        int count = tokens.countTokens();
        int j = 0;
        StringBuilder sb = new StringBuilder();
        while (tokens.hasMoreTokens()) {
            String fieldNamePart = tokens.nextToken();
            sb.append(fieldNamePart);
            String mapKey = null;
            if (fieldNamePart.contains(FieldManager.MAPFIELDSEPARATOR)) {
                mapKey = fieldNamePart.substring(fieldNamePart.indexOf(FieldManager.MAPFIELDSEPARATOR)
                        + FieldManager.MAPFIELDSEPARATOR.length(), fieldNamePart.length());
                fieldNamePart = fieldNamePart.substring(0, fieldNamePart.indexOf(FieldManager.MAPFIELDSEPARATOR));
            }

            field = getSingleField(componentClass, fieldNamePart);
            field.setAccessible(true);
            if (j == count - 1) {
                if (mapKey != null) {
                    Map map = (Map) field.get(value);
                    if (newValue == null) {
                        map.remove(mapKey);
                    } else {
                        map.put(mapKey, newValue);
                    }
                } else {
                    field.set(value, newValue);
                }
            } else {
                Object myValue = field.get(value);
                if (myValue != null) {
                    componentClass = myValue.getClass();
                    value = myValue;
                } else {
                    //consult the entity configuration manager to see if there is a user
                    //configured entity for this class
                    try {
                        Object newEntity = entityConfiguration.createEntityInstance(field.getType().getName());
                        SortableValue val = new SortableValue(bean, (Serializable) newEntity, j, sb.toString());
                        middleFields.add(val);
                        field.set(value, newEntity);
                        componentClass = newEntity.getClass();
                        value = newEntity;
                    } catch (Exception e) {
                        //Use the most extended type based on the field type
                        PersistenceManager persistenceManager = getPersistenceManager();
                        Class<?>[] entities = persistenceManager.getUpDownInheritance(field.getType());
                        if (!ArrayUtils.isEmpty(entities)) {
                            Object newEntity = entities[entities.length - 1].newInstance();
                            SortableValue val = new SortableValue(bean, (Serializable) newEntity, j, sb.toString());
                            middleFields.add(val);
                            field.set(value, newEntity);
                            componentClass = newEntity.getClass();
                            value = newEntity;
                            LOG.info("Unable to find a reference to (" + field.getType().getName()
                                    + ") in the EntityConfigurationManager. "
                                    + "Using the most extended form of this class identified as ("
                                    + entities[0].getName() + ")");
                        } else {
                            //Just use the field type
                            Object newEntity = field.getType().newInstance();
                            field.set(value, newEntity);
                            componentClass = newEntity.getClass();
                            value = newEntity;
                            LOG.info("Unable to find a reference to (" + field.getType().getName()
                                    + ") in the EntityConfigurationManager. " + "Using the type of this class.");
                        }
                    }
                }
            }
            sb.append(".");
            j++;
        }

        return value;

    }

    public Class<?> getFieldType(Field field) {
        //consult the entity configuration manager to see if there is a user
        //configured entity for this class
        Class<?> response;
        try {
            response = entityConfiguration.lookupEntityClass(field.getType().getName());
        } catch (Exception e) {
            //Use the most extended type based on the field type
            PersistenceManager persistenceManager = getPersistenceManager();
            Class<?>[] entities = persistenceManager.getUpDownInheritance(field.getType());
            if (!ArrayUtils.isEmpty(entities)) {
                response = entities[entities.length - 1];
                LOG.info("Unable to find a reference to (" + field.getType().getName()
                        + ") in the EntityConfigurationManager. "
                        + "Using the most extended form of this class identified as (" + entities[0].getName()
                        + ")");
            } else {
                //Just use the field type
                response = field.getType();
                LOG.info("Unable to find a reference to (" + field.getType().getName()
                        + ") in the EntityConfigurationManager. " + "Using the type of this class.");
            }
        }
        return response;
    }

    public Map<String, Serializable> persistMiddleEntities() throws InstantiationException, IllegalAccessException {
        Map<String, Serializable> persistedEntities = new HashMap<String, Serializable>();

        Collections.sort(middleFields);
        for (SortableValue val : middleFields) {
            Serializable s = entityManager.merge(val.entity);
            persistedEntities.put(val.getContainingPropertyName(), s);
            setFieldValue(val.getBean(), val.getContainingPropertyName(), s);
        }

        return persistedEntities;
    }

    public EntityConfiguration getEntityConfiguration() {
        return entityConfiguration;
    }

    protected PersistenceManager getPersistenceManager() {
        PersistenceManager persistenceManager;
        try {
            persistenceManager = PersistenceManagerFactory.getPersistenceManager();
        } catch (IllegalStateException e) {
            persistenceManager = PersistenceManagerFactory.getPersistenceManager(TargetModeType.SANDBOX);
        }
        return persistenceManager;
    }

    private class SortableValue implements Comparable<SortableValue> {

        private Integer pos;
        private Serializable entity;
        private Class<?> entityClass;
        private String containingPropertyName;
        private Object bean;

        public SortableValue(Object bean, Serializable entity, Integer pos, String containingPropertyName) {
            this.bean = bean;
            this.entity = entity;
            this.pos = pos;
            this.entityClass = entity.getClass();
            this.containingPropertyName = containingPropertyName;
        }

        @Override
        public int compareTo(SortableValue o) {
            return pos.compareTo(o.pos) * -1;
        }

        public String getContainingPropertyName() {
            return containingPropertyName;
        }

        private Object getBean() {
            return bean;
        }

        @Override
        public int hashCode() {
            int prime = 31;
            int result = 1;
            result = prime * result + getOuterType().hashCode();
            result = prime * result + (entityClass == null ? 0 : entityClass.hashCode());
            result = prime * result + (pos == null ? 0 : pos.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (!getClass().isAssignableFrom(obj.getClass()))
                return false;
            SortableValue other = (SortableValue) obj;
            if (!getOuterType().equals(other.getOuterType()))
                return false;
            if (entityClass == null) {
                if (other.entityClass != null)
                    return false;
            } else if (!entityClass.equals(other.entityClass))
                return false;
            if (pos == null) {
                if (other.pos != null)
                    return false;
            } else if (!pos.equals(other.pos))
                return false;
            return true;
        }

        private FieldManager getOuterType() {
            return FieldManager.this;
        }

    }

}