/** * *************************************************************************** * Copyright (c) 2010 Qcadoo Limited * Project: Qcadoo Framework * Version: 1.4 * * 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 com.google.common.base.Preconditions; import com.qcadoo.model.api.DataDefinition; import com.qcadoo.model.api.DataDefinitionService; import com.qcadoo.model.api.types.FieldType; import com.qcadoo.model.internal.api.HibernateService; import com.qcadoo.model.internal.api.InternalDataDefinition; import com.qcadoo.model.internal.types.BelongsToEntityType; import com.qcadoo.model.internal.types.DateTimeType; import com.qcadoo.model.internal.types.DecimalType; import com.qcadoo.model.internal.types.StringType; import org.apache.commons.lang3.StringUtils; import org.hibernate.Criteria; import org.hibernate.Query; import org.hibernate.SessionFactory; import org.hibernate.classic.Session; import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionImplementor; import org.hibernate.impl.CriteriaImpl; import org.hibernate.loader.criteria.CriteriaJoinWalker; import org.hibernate.loader.criteria.CriteriaQueryTranslator; import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.type.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Locale; @Service public class HibernateServiceImpl implements HibernateService { private static final Logger LOG = LoggerFactory.getLogger(HibernateServiceImpl.class); @Autowired private DataDefinitionService dataDefinitionService; @Autowired private SessionFactory sessionFactory; @Override public Session getCurrentSession() { return sessionFactory.getCurrentSession(); } @Override public int getTotalNumberOfEntities(final Criteria criteria) { final CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; final SessionImplementor session = (SessionImplementor) getCurrentSession(); SessionFactoryImplementor factory = session.getFactory(); CriteriaQueryTranslator translator = new CriteriaQueryTranslator(factory, criteriaImpl, criteriaImpl.getEntityOrClassName(), CriteriaQueryTranslator.ROOT_SQL_ALIAS); String[] implementors = factory.getImplementors(criteriaImpl.getEntityOrClassName()); CriteriaJoinWalker walker = new CriteriaJoinWalker((OuterJoinLoadable) factory.getEntityPersister(implementors[0]), translator, factory, criteriaImpl, criteriaImpl.getEntityOrClassName(), session.getLoadQueryInfluencers()); final String sql = "select count(*) as cnt from (" + walker.getSQLString() + ") sq"; getCurrentSession().flush(); // is this safe? return ((Number) getCurrentSession() .createSQLQuery(sql) .setParameters(translator.getQueryParameters().getPositionalParameterValues(), translator.getQueryParameters().getPositionalParameterTypes()).uniqueResult()).intValue(); } @Override public InternalDataDefinition resolveDataDefinition(final Criteria criteria) { final CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; final SessionImplementor session = (SessionImplementor) getCurrentSession(); SessionFactoryImplementor factory = session.getFactory(); CriteriaQueryTranslator translator = new CriteriaQueryTranslator(factory, criteriaImpl, criteriaImpl.getEntityOrClassName(), CriteriaQueryTranslator.ROOT_SQL_ALIAS); String[] aliases = criteriaImpl.getProjection().getAliases(); Type[] types = criteriaImpl.getProjection().getTypes(criteriaImpl, translator); return resolveDataDefinition(types, aliases); } @Override public InternalDataDefinition resolveDataDefinition(final Query query) { return resolveDataDefinition(query.getReturnTypes(), query.getReturnAliases()); } private InternalDataDefinition resolveDataDefinition(final Type[] types, final String[] aliases) { if (types.length == 1 && types[0] instanceof EntityType) { return resolveDataDefinitionFromEntityType((EntityType) types[0]); } else { DynamicDataDefinitionImpl dataDefinition = new DynamicDataDefinitionImpl(); for (int i = 0; i < types.length; i++) { dataDefinition.addField(aliases[i] == null ? Integer.toString(i) : aliases[i], convertHibernateType(types[i])); } return dataDefinition; } } private InternalDataDefinition resolveDataDefinitionFromEntityType(final EntityType entityType) { return resolveDataDefinitionFromClassType(entityType.getName()); } private InternalDataDefinition resolveDataDefinitionFromClassType(final String classType) { String[] tmp = classType.replaceFirst("com.qcadoo.model.beans.", "").split("\\."); String model = tmp[1].replaceFirst(tmp[0].substring(0, 1).toUpperCase(Locale.ENGLISH) + tmp[0].substring(1), ""); Preconditions.checkState(StringUtils.isNotBlank(model), "Can't parse model name from class' binary name."); model = model.substring(0, 1).toLowerCase(Locale.ENGLISH) + model.substring(1); return (InternalDataDefinition) dataDefinitionService.get(tmp[0], model); } private FieldType convertHibernateType(final Type type) { if (type instanceof BigDecimalType || type instanceof DoubleType || type instanceof FloatType) { return new DecimalType(); } if (type instanceof FloatType || type instanceof BigIntegerType || type instanceof IntegerType || type instanceof ShortType || type instanceof LongType) { return new com.qcadoo.model.internal.types.IntegerType(); } if (type instanceof BooleanType) { return new com.qcadoo.model.internal.types.BooleanType(); } if (type instanceof DateType) { return new com.qcadoo.model.internal.types.DateType(); } if (type instanceof TimestampType || type instanceof TimeType) { return new DateTimeType(); } if (type instanceof org.hibernate.type.StringType || type instanceof CharacterType) { return new StringType(); } if (type instanceof TextType) { return new com.qcadoo.model.internal.types.TextType(); } if (type instanceof EntityType) { DataDefinition dataDefinition = resolveDataDefinitionFromEntityType((EntityType) type); if (dataDefinition == null) { LOG.warn("Cannot find dataDefinition for class " + ((EntityType) type).getName()); } else { return new BelongsToEntityType(dataDefinition.getPluginIdentifier(), dataDefinition.getName(), dataDefinitionService, false, true); } } LOG.warn("Cannot map hibernate's type " + type.getClass().getCanonicalName() + ", using string type"); return new StringType(); } protected void setDataDefinitionService(final DataDefinitionService dataDefinitionService) { this.dataDefinitionService = dataDefinitionService; } protected void setSessionFactory(final SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } @Override public List<?> list(final Query query) { return query.list(); } @Override public List<?> list(final Criteria criteria) { return criteria.list(); } }