com.qcadoo.model.internal.EntityServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.qcadoo.model.internal.EntityServiceImpl.java

Source

/**
 * ***************************************************************************
 * Copyright (c) 2010 Qcadoo Limited
 * Project: Qcadoo Framework
 * Version: 1.2.0
 *
 * This file is part of Qcadoo.
 *
 * Qcadoo is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation; either version 3 of the License,
 * or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 * ***************************************************************************
 */
package com.qcadoo.model.internal;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.proxy.HibernateProxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.qcadoo.model.api.Entity;
import com.qcadoo.model.api.ExpressionService;
import com.qcadoo.model.api.FieldDefinition;
import com.qcadoo.model.api.types.BelongsToType;
import com.qcadoo.model.api.types.HasManyType;
import com.qcadoo.model.api.types.ManyToManyType;
import com.qcadoo.model.api.types.TreeType;
import com.qcadoo.model.internal.api.EntityService;
import com.qcadoo.model.internal.api.HibernateService;
import com.qcadoo.model.internal.api.InternalDataDefinition;
import com.qcadoo.model.internal.api.InternalFieldDefinition;
import com.qcadoo.model.internal.types.PasswordType;

@Service
public final class EntityServiceImpl implements EntityService {

    @Autowired
    private HibernateService hibernateService;

    @Autowired
    private ExpressionService expressionService;

    @Override
    public Long getId(final Object databaseEntity) {
        return (Long) getField(databaseEntity, FIELD_ID);
    }

    public Boolean getActive(final Object databaseEntity) {
        return (Boolean) getField(databaseEntity, FIELD_ACTIVE);
    }

    public void setActive(final Object databaseEntity, final boolean active) {
        setField(databaseEntity, FIELD_ACTIVE, active);
    }

    @Override
    public void setId(final Object databaseEntity, final Long id) {
        setField(databaseEntity, FIELD_ID, id);
    }

    @Override
    public void setField(final Object databaseEntity, final FieldDefinition fieldDefinition, final Object value) {
        if (!shouldAllowToSetField(fieldDefinition, value)) {
            return;
        }

        if (fieldDefinition.getType() instanceof BelongsToType && value != null) {
            Object belongsToValue = getBelongsToFieldValue(
                    (InternalDataDefinition) ((BelongsToType) fieldDefinition.getType()).getDataDefinition(),
                    value);
            setField(databaseEntity, fieldDefinition.getName(), belongsToValue);
        } else if (fieldDefinition.getType() instanceof HasManyType) {
            setField(databaseEntity, fieldDefinition.getName(), null);
        } else if (fieldDefinition.getType() instanceof TreeType) {
            setField(databaseEntity, fieldDefinition.getName(), null);
        } else {
            setField(databaseEntity, fieldDefinition.getName(), value);
        }
    }

    private boolean shouldAllowToSetField(final FieldDefinition fieldDefinition, final Object value) {
        return ((InternalFieldDefinition) fieldDefinition).isEnabled()
                && !(fieldDefinition.getType() instanceof PasswordType && value == null);
    }

    private Object getBelongsToFieldValue(final InternalDataDefinition dataDefinition, final Object value) {
        Long id = null;

        if (value instanceof Long) {
            id = (Long) value;
        } else if (value instanceof Entity) {
            id = ((Entity) value).getId();
        } else {
            id = Long.parseLong(value.toString());
        }

        Class<?> referencedClass = dataDefinition.getClassForEntity();
        return hibernateService.getCurrentSession().load(referencedClass, id);
    }

    @Override
    public Object getField(final Object databaseEntity, final FieldDefinition fieldDefinition) {
        return getField(databaseEntity, fieldDefinition, null);
    }

    public Object getField(final Object databaseEntity, final FieldDefinition fieldDefinition,
            final Entity performer) {
        if (!((InternalFieldDefinition) fieldDefinition).isEnabled()) {
            return null;
        }
        if (fieldDefinition.getType() instanceof BelongsToType) {
            return getBelongsToField(databaseEntity, fieldDefinition, performer);
        }
        if (fieldDefinition.getType() instanceof HasManyType) {
            return getHasManyField(databaseEntity, fieldDefinition);
        }
        if (fieldDefinition.getType() instanceof ManyToManyType) {
            return getManyToManyField(databaseEntity, fieldDefinition);
        }
        if (fieldDefinition.getType() instanceof TreeType) {
            return getTreeField(databaseEntity, fieldDefinition);
        }

        return getPrimitiveField(databaseEntity, fieldDefinition);
    }

    @Override
    public Entity convertToGenericEntity(final InternalDataDefinition dataDefinition, final Object databaseEntity) {
        return convertToGenericEntity(dataDefinition, databaseEntity, null);
    }

    public Entity convertToGenericEntity(final InternalDataDefinition dataDefinition, final Object databaseEntity,
            final Entity performer) {
        Entity genericEntity = null;

        if (databaseEntity instanceof Object[]) {
            genericEntity = dataDefinition.create();
            Object[] databaseArray = (Object[]) databaseEntity;

            List<String> fields = new ArrayList<String>(dataDefinition.getFields().keySet());

            for (int i = 0; i < fields.size(); i++) {
                if (dataDefinition.getField(fields.get(i)).getType() instanceof BelongsToType) {
                    InternalDataDefinition referencedDataDefinition = (InternalDataDefinition) ((BelongsToType) dataDefinition
                            .getField(fields.get(i)).getType()).getDataDefinition();
                    genericEntity.setField(fields.get(i),
                            convertToGenericEntity(referencedDataDefinition, databaseArray[i]));
                } else {
                    genericEntity.setField(fields.get(i), databaseArray[i]);
                }
            }
        } else if (databaseEntity.getClass().getName().startsWith("com.qcadoo.model.beans")) {
            genericEntity = dataDefinition.create(getId(databaseEntity));

            if (dataDefinition.isActivable()) {
                genericEntity.setActive(getActive(databaseEntity));
            }

            for (Entry<String, FieldDefinition> fieldDefinitionEntry : dataDefinition.getFields().entrySet()) {
                if (fieldDefinitionEntry.getValue().isPersistent()
                        && ((InternalFieldDefinition) fieldDefinitionEntry.getValue()).isEnabled()) {
                    Entity currentPerformer = performer;
                    if (currentPerformer == null) {
                        currentPerformer = genericEntity;
                    }
                    genericEntity.setField(fieldDefinitionEntry.getKey(),
                            getField(databaseEntity, fieldDefinitionEntry.getValue(), currentPerformer));
                }
            }

            if (dataDefinition.isPrioritizable()) {
                genericEntity.setField(dataDefinition.getPriorityField().getName(),
                        getField(databaseEntity, dataDefinition.getPriorityField()));
            }

            for (Entry<String, FieldDefinition> fieldDefinitionEntry : dataDefinition.getFields().entrySet()) {
                if (fieldDefinitionEntry.getValue().getExpression() != null
                        && ((InternalFieldDefinition) fieldDefinitionEntry.getValue()).isEnabled()) {
                    genericEntity.setField(fieldDefinitionEntry.getKey(), expressionService.getValue(genericEntity,
                            fieldDefinitionEntry.getValue().getExpression(), Locale.ENGLISH));
                }
            }

            dataDefinition.callViewHook(genericEntity);
        } else {
            genericEntity = new DefaultEntity(dataDefinition);
            genericEntity.setField(dataDefinition.getFields().keySet().iterator().next(), databaseEntity);
        }

        return genericEntity;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object convertToDatabaseEntity(final InternalDataDefinition dataDefinition, final Entity genericEntity,
            final Object existingDatabaseEntity) {
        Object databaseEntity = getDatabaseEntity(dataDefinition, genericEntity, existingDatabaseEntity);

        for (Entry<String, FieldDefinition> fieldDefinitionEntry : dataDefinition.getFields().entrySet()) {
            FieldDefinition fieldDefinition = fieldDefinitionEntry.getValue();

            if (fieldDefinition.isPersistent() && ((InternalFieldDefinition) fieldDefinition).isEnabled()) {
                Object fieldValue = genericEntity.getField(fieldDefinitionEntry.getKey());

                if (fieldDefinition.getType() instanceof ManyToManyType && fieldValue instanceof Iterable) {
                    Set<Object> innerDatabaseEntities = Sets.newHashSet();
                    for (Entity innerGenericEntity : (Iterable<Entity>) fieldValue) {
                        innerDatabaseEntities.add(
                                getDatabaseEntity((InternalDataDefinition) innerGenericEntity.getDataDefinition(),
                                        innerGenericEntity, null));
                    }
                    setField(databaseEntity, fieldDefinitionEntry.getValue(), innerDatabaseEntities);
                } else {
                    setField(databaseEntity, fieldDefinitionEntry.getValue(), fieldValue);
                }
            }
        }

        if (dataDefinition.isPrioritizable()
                && genericEntity.getField(dataDefinition.getPriorityField().getName()) != null) {
            setField(databaseEntity, dataDefinition.getPriorityField(),
                    genericEntity.getField(dataDefinition.getPriorityField().getName()));
        }

        if (dataDefinition.isActivable()) {
            setActive(databaseEntity, genericEntity.isActive());
        }

        return databaseEntity;
    }

    private Object getDatabaseEntity(final InternalDataDefinition dataDefinition, final Entity genericEntity,
            final Object existingDatabaseEntity) {
        Object databaseEntity = null;

        if (existingDatabaseEntity == null) {
            databaseEntity = dataDefinition.getInstanceForEntity();
            setId(databaseEntity, genericEntity.getId());
        } else {
            databaseEntity = existingDatabaseEntity;
        }
        return databaseEntity;
    }

    private Object getPrimitiveField(final Object databaseEntity, final FieldDefinition fieldDefinition) {
        return getField(databaseEntity, fieldDefinition.getName());
    }

    private Object getHasManyField(final Object databaseEntity, final FieldDefinition fieldDefinition) {
        Long parentId = getId(databaseEntity);
        HasManyType hasManyFieldType = (HasManyType) fieldDefinition.getType();
        InternalDataDefinition referencedDataDefinition = (InternalDataDefinition) hasManyFieldType
                .getDataDefinition();

        return new EntityListImpl(referencedDataDefinition, hasManyFieldType.getJoinFieldName(), parentId);
    }

    private Object getManyToManyField(final Object databaseEntity, final FieldDefinition fieldDefinition) {
        @SuppressWarnings("unchecked")
        Set<Object> databaseEntities = (Set<Object>) getPrimitiveField(databaseEntity, fieldDefinition);
        if (databaseEntities == null) {
            return null;
        }
        List<Entity> genericEntities = Lists.newArrayList();
        InternalDataDefinition referencedDataDefinition = (InternalDataDefinition) ((ManyToManyType) fieldDefinition
                .getType()).getDataDefinition();

        @SuppressWarnings("unchecked")
        final Iterable<Object> fieldValues = (Iterable<Object>) getField(databaseEntity, fieldDefinition.getName());
        for (Object innerDatabaseEntity : fieldValues) {
            Entity innerEntity = null;
            Long id = getId(innerDatabaseEntity);
            if (id == null) {
                innerEntity = convertToGenericEntity(referencedDataDefinition, innerDatabaseEntity);
            } else {
                innerEntity = new ProxyEntity(referencedDataDefinition, id);
            }
            genericEntities.add(innerEntity);
        }
        return genericEntities;
    }

    private Object getTreeField(final Object databaseEntity, final FieldDefinition fieldDefinition) {
        Long parentId = getId(databaseEntity);
        TreeType treeFieldType = (TreeType) fieldDefinition.getType();
        InternalDataDefinition referencedDataDefinition = (InternalDataDefinition) treeFieldType
                .getDataDefinition();

        return new EntityTreeImpl(referencedDataDefinition, treeFieldType.getJoinFieldName(), parentId);
    }

    private Object getBelongsToField(final Object databaseEntity, final FieldDefinition fieldDefinition,
            final Entity performer) {
        BelongsToType belongsToFieldType = (BelongsToType) fieldDefinition.getType();
        InternalDataDefinition referencedDataDefinition = (InternalDataDefinition) belongsToFieldType
                .getDataDefinition();

        Object value = getField(databaseEntity, fieldDefinition.getName());

        if (value == null) {
            return null;
        }

        if (performer != null && referencedDataDefinition.equals(performer.getDataDefinition())
                && performer.getId() != null && performer.getId().equals(getId(value))) {
            return performer;
        }

        if (belongsToFieldType.isLazyLoading()) {
            Long id = null;

            if (value instanceof HibernateProxy) {
                id = (Long) ((HibernateProxy) value).getHibernateLazyInitializer().getIdentifier();
            } else {
                id = getId(getField(databaseEntity, fieldDefinition.getName()));
            }

            if (id == null) {
                return null;
            }

            return new ProxyEntity(referencedDataDefinition, id);
        } else {
            Entity currentPerformer = performer;
            if (performer == null || performer.getId() == null
                    && referencedDataDefinition.equals(performer.getDataDefinition())) {
                currentPerformer = new ProxyEntity(referencedDataDefinition, getId(value));
            }
            return convertToGenericEntity(referencedDataDefinition, value, currentPerformer);
        }
    }

    private void setField(final Object databaseEntity, final String fieldName, final Object value) {
        try {
            PropertyUtils.setProperty(databaseEntity, fieldName, value);
        } catch (Exception e) {
            throw new IllegalStateException("cannot set value of the property: "
                    + databaseEntity.getClass().getSimpleName() + ", " + fieldName, e);
        }
    }

    private Object getField(final Object databaseEntity, final String fieldName) {
        try {
            return PropertyUtils.getProperty(databaseEntity, fieldName);
        } catch (Exception e) {
            throw new IllegalStateException("cannot get value of the property: "
                    + databaseEntity.getClass().getSimpleName() + ", " + fieldName, e);
        }
    }

}