Package org.fluxtream.core.connectors.dao

Source Code of org.fluxtream.core.connectors.dao.JPAFacetDao

package org.fluxtream.core.connectors.dao;

import org.fluxtream.core.TimeInterval;
import org.fluxtream.core.aspects.FlxLogger;
import org.fluxtream.core.connectors.Connector;
import org.fluxtream.core.connectors.ObjectType;
import org.fluxtream.core.connectors.annotations.ObjectTypeSpec;
import org.fluxtream.core.connectors.location.LocationFacet;
import org.fluxtream.core.domain.AbstractFacet;
import org.fluxtream.core.domain.AbstractRepeatableFacet;
import org.fluxtream.core.domain.ApiKey;
import org.fluxtream.core.domain.TagFilter;
import org.fluxtream.core.domain.metadata.VisitedCity;
import org.fluxtream.core.services.ConnectorUpdateService;
import org.fluxtream.core.services.GuestService;
import org.fluxtream.core.utils.JPAUtils;
import org.fluxtream.core.utils.TimeUtils;
import org.jetbrains.annotations.Nullable;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.*;
import java.lang.reflect.Method;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;

@Repository
@Component
public class JPAFacetDao implements FacetDao {

    private static final FlxLogger logger = FlxLogger.getLogger(JPAFacetDao.class);

    @Autowired
  GuestService guestService;

    @Autowired
  ConnectorUpdateService connectorUpdateService;

  @PersistenceContext
  private EntityManager em;

  public JPAFacetDao() {}

    @Override
    public List<AbstractFacet> getFacetsByDates(final ApiKey apiKey, ObjectType objectType, List<String> dates) {
        if (!objectType.isClientFacet())
            return new ArrayList<AbstractFacet>();
        ArrayList<AbstractFacet> facets = new ArrayList<AbstractFacet>();
        if (!apiKey.getConnector().hasFacets()) return facets;
        Class<? extends AbstractFacet> facetClass = getFacetClass(apiKey.getConnector(), objectType);
        final String facetName = getEntityName(facetClass);
        StringBuilder additionalWhereClause = new StringBuilder();
        if (objectType.visibleClause()!=null) additionalWhereClause.append(" AND ").append(objectType.visibleClause()).append(" ");
        String queryString = new StringBuilder("SELECT facet FROM ")
                .append(facetName)
                .append(" facet WHERE facet.apiKeyId=:apiKeyId AND facet.date IN :dates")
                .append(additionalWhereClause)
                .toString();
        final TypedQuery<? extends AbstractFacet> query = em.createQuery(queryString, AbstractFacet.class);
        query.setParameter("apiKeyId", apiKey.getId());
        query.setParameter("dates", dates);
        List<? extends AbstractFacet> found = query.getResultList();
        if (found!=null)
            facets.addAll(found);
        return facets;
    }

    @Override
    public List<AbstractRepeatableFacet> getFacetsBetweenDates(final ApiKey apiKey, final ObjectType objectType, final String startDateString, final String endDateString) {
        if (!objectType.isClientFacet())
            return new ArrayList<AbstractRepeatableFacet>();
        ArrayList<AbstractRepeatableFacet> facets = new ArrayList<AbstractRepeatableFacet>();
        if (!apiKey.getConnector().hasFacets()) return facets;
        Class<? extends AbstractRepeatableFacet> facetClass = (Class<? extends AbstractRepeatableFacet>)getFacetClass(apiKey.getConnector(), objectType);
        final String facetName = getEntityName(facetClass);
        StringBuilder additionalWhereClause = new StringBuilder();
        if (objectType.visibleClause()!=null) additionalWhereClause.append(" AND ").append(objectType.visibleClause()).append(" ");
        StringBuilder queryBuilder = new StringBuilder("SELECT facet FROM ")
                .append(facetName)
                .append(" facet WHERE facet.apiKeyId=:apiKeyId AND NOT(facet.endDate<:startDate) AND NOT(facet.startDate>:endDate)")
                .append(additionalWhereClause);
        String orderBy = objectType.orderBy();
        if (orderBy!=null)
            queryBuilder.append(" ORDER BY ").append(orderBy);
        String queryString = queryBuilder.toString();
        final TypedQuery<? extends AbstractFacet> query = em.createQuery(queryString, AbstractFacet.class);
        query.setParameter("apiKeyId", apiKey.getId());
        final DateTime time = TimeUtils.dateFormatterUTC.parseDateTime(startDateString);
        Date startDate = new Date(time.getMillis());
        final DateTime time2 = TimeUtils.dateFormatterUTC.parseDateTime(endDateString);
        Date endDate = new Date(time2.getMillis());
        query.setParameter("startDate", startDate, TemporalType.DATE);
        query.setParameter("endDate", endDate, TemporalType.DATE);
        List<? extends AbstractRepeatableFacet> found = (List<? extends AbstractRepeatableFacet>)query.getResultList();
        if (found!=null)
            facets.addAll(found);
        return facets;
    }

    @Cacheable("facetClasses")
    private String getEntityName(Class<? extends AbstractFacet> facetClass) {
        try {
            return facetClass.getAnnotation(Entity.class).name();
        } catch (Throwable t) {
            final String message = "Could not get Facet class for connector for " + facetClass.getName();
            logger.error(message);
            throw new RuntimeException(message);
        }
    }

    private Class<? extends AbstractFacet> getFacetClass(final Connector connector, final ObjectType objectType) {
        return objectType!=null
                        ? objectType.facetClass()
                        : connector.facetClass();
    }

  @Override
  public List<AbstractFacet> getFacetsBetween(final ApiKey apiKey, ObjectType objectType, TimeInterval timeInterval) {
        return getFacetsBetween(apiKey, objectType, timeInterval, null, null);
    }

    @Override
    public List<AbstractFacet> getFacetsBetween(ApiKey apiKey, ObjectType objectType, TimeInterval timeInterval, @Nullable TagFilter tagFilter) {
        return getFacetsBetween(apiKey, objectType, timeInterval, tagFilter, null);
    }

    @Override
    public List<AbstractFacet> getFacetsBetween(final ApiKey apiKey,
                                                final ObjectType objectType,
                                                final TimeInterval timeInterval,
                                                @Nullable final TagFilter tagFilter,
                                                @Nullable final String orderByString) {
        if (objectType==null) {
            return getFacetsBetween(apiKey, timeInterval, tagFilter);
        } else {
            if (!objectType.isClientFacet())
                return new ArrayList<AbstractFacet>();
            if (!apiKey.getConnector().hasFacets()) return new ArrayList<AbstractFacet>();
            Class<? extends AbstractFacet> facetClass = getFacetClass(apiKey.getConnector(), objectType);
            final String facetName = getEntityName(facetClass);
            StringBuilder additionalWhereClause = new StringBuilder();
            if (tagFilter != null) additionalWhereClause.append(" AND (").append(tagFilter.getWhereClause()).append(")");
            if (objectType.isMixedType()) additionalWhereClause.append(" AND facet.allDayEvent=false ");
            if (objectType.visibleClause()!=null) additionalWhereClause.append(" AND ").append(objectType.visibleClause()).append(" ");
            StringBuilder queryStringBuilder = new StringBuilder("SELECT facet FROM ")
                    .append(facetName)
                    .append(" facet WHERE facet.apiKeyId=? AND facet.end>=? AND facet.start<=?")
                    .append(additionalWhereClause);
            if (orderByString != null){
                queryStringBuilder.append(" ORDER BY ").append(orderByString);
            }
            String queryString= queryStringBuilder.toString();
            final TypedQuery<AbstractFacet> query = em.createQuery(queryString, AbstractFacet.class);
            query.setParameter(1, apiKey.getId());
            query.setParameter(2, timeInterval.getStart());
            query.setParameter(3, timeInterval.getEnd());
            List<AbstractFacet> facets = query.getResultList();
            return facets;
        }
    }

    private List<AbstractFacet> getFacetsBetween(final ApiKey apiKey, TimeInterval timeInterval, @Nullable final TagFilter tagFilter) {
        final ObjectType[] objectTypes = apiKey.getConnector().objectTypes();
        List<AbstractFacet> facets = new ArrayList<AbstractFacet>();
        for (ObjectType type : objectTypes) {
            if (!type.isClientFacet())
                continue;
            facets.addAll(getFacetsBetween(apiKey, type, timeInterval, tagFilter));
        }
        return facets;
    }

    @Override
    public AbstractFacet getOldestFacet(final ApiKey apiKey, final ObjectType objectType) {
        return getFacet(apiKey, objectType, "getOldestFacet");
    }

    @Override
    public AbstractFacet getLatestFacet(final ApiKey apiKey, final ObjectType objectType) {
        return getFacet(apiKey, objectType, "getLatestFacet");
    }

    @Override
    public List<AbstractFacet> getFacetsBefore(final ApiKey apiKey, final ObjectType objectType, final long timeInMillis, final int desiredCount) {
        return getFacetsBefore(apiKey, objectType, timeInMillis, desiredCount, null);
    }

    @Override
    public List<AbstractFacet> getFacetsAfter(final ApiKey apiKey, final ObjectType objectType, final long timeInMillis, final int desiredCount) {
        return getFacetsAfter(apiKey, objectType, timeInMillis, desiredCount, null);
    }

    @Override
    public List<AbstractFacet> getFacetsBefore(final ApiKey apiKey,
                                               final ObjectType objectType,
                                               final long timeInMillis,
                                               final int desiredCount,
                                               @Nullable final TagFilter tagFilter) {
        return getFacets(apiKey, objectType, timeInMillis, desiredCount, "getFacetsBefore", tagFilter);
    }

    @Override
    public List<AbstractFacet> getFacetsAfter(final ApiKey apiKey,
                                              final ObjectType objectType,
                                              final long timeInMillis,
                                              final int desiredCount,
                                              @Nullable final TagFilter tagFilter) {
        return getFacets(apiKey, objectType, timeInMillis, desiredCount, "getFacetsAfter", tagFilter);
    }

    @Override
    public AbstractFacet getFacetById(ApiKey apiKey, final ObjectType objectType, final long facetId) {
        final Class<? extends AbstractFacet> facetClass = objectType.facetClass();
        final Entity entity = facetClass.getAnnotation(Entity.class);
        final TypedQuery<? extends AbstractFacet> query = em.createQuery("SELECT facet FROM " + entity.name() + " facet WHERE facet.id = " + facetId + " AND facet.guestId = " + apiKey.getGuestId(), facetClass);
        query.setMaxResults(1);

        final List resultList = query.getResultList();
        if (resultList != null && resultList.size() > 0) {
            return (AbstractFacet)resultList.get(0);
        }
        return null;
    }

    private AbstractFacet getFacet(final ApiKey apiKey, final ObjectType objectType, final String methodName) {
        if (!apiKey.getConnector().hasFacets()) {
            return null;
        }

        AbstractFacet facet = null;
        if (objectType != null) {
            try {
                Class c = objectType.facetClass();
                Method m = c.getMethod(methodName, EntityManager.class, ApiKey.class, ObjectType.class);
                facet = (AbstractFacet)m.invoke(null, em, apiKey, objectType);
            }
            catch (Exception ignored) {
                if (logger.isInfoEnabled()) {
                    logger.info("JPAFacetDao.getFacet(): ignoring exception '" + ignored.getClass() + "' while trying to invoke method '" + methodName + "'");
                }
            }
        }
        else {
            if (apiKey.getConnector().objectTypes() != null) {
                for (ObjectType type : apiKey.getConnector().objectTypes()) {
                    AbstractFacet fac = null;
                    try {
                        Class c = type.facetClass();
                        Method m = c.getMethod(methodName, EntityManager.class, ApiKey.class, ObjectType.class);
                        fac = (AbstractFacet)m.invoke(null, em, apiKey, type);
                    }
                    catch (Exception ignored) {
                        if (logger.isInfoEnabled()) {
                            logger.info("JPAFacetDao.getFacet(): ignoring exception '" + ignored.getClass() + "' while trying to invoke method '" + methodName + "'");
                        }
                    }
                    if (facet == null || (fac != null && fac.end > facet.end)) {
                        facet = fac;
                    }
                }
            }
            else {
                try {
                    Class c = apiKey.getConnector().facetClass();
                    Method m = c.getMethod(methodName, EntityManager.class, ApiKey.class, ObjectType.class);
                    facet = (AbstractFacet)m.invoke(null, em, apiKey, null);
                }
                catch (Exception ignored) {
                    if (logger.isInfoEnabled()) {
                        logger.info("JPAFacetDao.getFacet(): ignoring exception '" + ignored.getClass() + "' while trying to invoke method '" + methodName + "'");
                    }
                }
            }
        }
        return facet;
    }

    private List<AbstractFacet> getFacets(final ApiKey apiKey,
                                          final ObjectType objectType,
                                          final long timeInMillis,
                                          final int desiredCount,
                                          final String methodName,
                                          @Nullable final TagFilter tagFilter) {
        if (!apiKey.getConnector().hasFacets()) {
            return null;
        }

        List<AbstractFacet> facets = null;
        if (objectType != null) {
            try {
                Class c = objectType.facetClass();
                Method m = c.getMethod(methodName, EntityManager.class, ApiKey.class, ObjectType.class, Long.class, Integer.class, TagFilter.class);
                facets = (List<AbstractFacet>)m.invoke(null, em, apiKey, objectType, timeInMillis, desiredCount, tagFilter);
            }
            catch (Exception ignored) {
                if (logger.isInfoEnabled()) {
                    logger.info("JPAFacetDao.getFacets(): ignoring exception '" + ignored.getClass() + "' while trying to invoke method '" + methodName + "'");
                }
            }
        }
        else {
            if (apiKey.getConnector().objectTypes() != null) {
                for (ObjectType type : apiKey.getConnector().objectTypes()) {
                    try {
                        Class c = type.facetClass();
                        Method m = c.getMethod(methodName, EntityManager.class, ApiKey.class, ObjectType.class, Long.class, Integer.class, TagFilter.class);
                        facets = (List<AbstractFacet>)m.invoke(null, em, apiKey, type, timeInMillis, desiredCount, tagFilter);
                    }
                    catch (Exception ignored) {
                        if (logger.isInfoEnabled()) {
                            logger.info("JPAFacetDao.getFacets(): ignoring exception '" + ignored.getClass() + "' while trying to invoke method '" + methodName + "'");
                        }
                    }
                }
            }
            else {
                try {
                    Class c = apiKey.getConnector().facetClass();
                    Method m = c.getMethod(methodName, EntityManager.class, ApiKey.class, ObjectType.class, Long.class, Integer.class, TagFilter.class);
                    facets = (List<AbstractFacet>)m.invoke(null, em, apiKey, null, timeInMillis, desiredCount, tagFilter);
                }
                catch (Exception ignored) {
                    if (logger.isInfoEnabled()) {
                        logger.info("JPAFacetDao.getFacets(): ignoring exception '" + ignored.getClass() + "' while trying to invoke method '" + methodName + "'");
                    }
                }
            }
        }
        return facets;
    }

    @Override
  public void deleteAllFacets(ApiKey apiKey) {
        final Connector connector = apiKey.getConnector();
        if (connector.hasDeleteOrder()){
            final int[] deleteOrder = connector.getDeleteOrder();
            for (int ot : deleteOrder) {
                ObjectType objectType = ObjectType.getObjectType(connector, ot);
                deleteAllFacets(apiKey, objectType);
            }
        } else {
            final ObjectType[] objectTypes = connector.objectTypes();
            for (ObjectType objectType : objectTypes) {
                deleteAllFacets(apiKey, objectType);
            }
        }
  }

  @Override
  public void deleteAllFacets(ApiKey apiKey, ObjectType objectType) {
        if (objectType==null) {
            deleteAllFacets(apiKey);
        } else {
            // if facet has joins delete each facet one-by-one (this is a limitation of JPA)
            Class<? extends AbstractFacet> facetClass = getFacetClass(apiKey.getConnector(), objectType);
            if (JPAUtils.hasRelation(facetClass)) {
               deleteFacetsOneByOne(apiKey, facetClass);
            } else {
                bulkDeleteFacets(apiKey, facetClass);
            }
            final LocationFacet.Source locationFacetSource = getLocationFacetSource(facetClass);
            if (locationFacetSource != LocationFacet.Source.NONE) {
                deleteLocationData(apiKey);
                deleteVisitedCitiesData(apiKey);
            }
        }
  }

    @Transactional(readOnly=false)
    private void deleteVisitedCitiesData(final ApiKey apiKey) {
        final String facetName = getEntityName(VisitedCity.class);
        String stmtString = "DELETE FROM " + facetName + " facet WHERE facet.apiKeyId=?";
        final Query query = em.createQuery(stmtString);
        query.setParameter(1, apiKey.getId());
        query.executeUpdate();
    }

    @Transactional(readOnly=false)
    private void deleteLocationData(final ApiKey apiKey) {
        final String facetName = getEntityName(LocationFacet.class);
        String stmtString = "DELETE FROM " + facetName + " facet WHERE facet.apiKeyId=?";
        final Query query = em.createQuery(stmtString);
        query.setParameter(1, apiKey.getId());
        query.executeUpdate();
    }

    private LocationFacet.Source getLocationFacetSource(final Class<? extends AbstractFacet> facetClass) {
        final ObjectTypeSpec objectTypeSpec = facetClass.getAnnotation(ObjectTypeSpec.class);
        final LocationFacet.Source locationFacetSource = objectTypeSpec.locationFacetSource();
        return locationFacetSource;
    }

    private void deleteFacetsOneByOne(final ApiKey apiKey, final Class<? extends AbstractFacet> facetClass) {
        List<? extends AbstractFacet> facets = getAllFacets(apiKey, facetClass);
        for (AbstractFacet facet : facets) {
            final AbstractFacet merged = em.merge(facet);
            em.remove(merged);
        }
    }

    private List<? extends AbstractFacet> getAllFacets(final ApiKey apiKey, final Class<? extends AbstractFacet> facetClass) {
        final String facetName = getEntityName(facetClass);
        String queryString = "SELECT facet FROM " + facetName + " facet WHERE facet.apiKeyId=?";
        final TypedQuery<? extends AbstractFacet> query = em.createQuery(queryString, AbstractFacet.class);
        query.setParameter(1, apiKey.getId());
        List<? extends AbstractFacet> found = query.getResultList();
        return found;
    }

    private void bulkDeleteFacets(final ApiKey apiKey, final Class<? extends AbstractFacet> facetClass) {
        final String facetName = getEntityName(facetClass);
        String stmtString = "DELETE FROM " + facetName + " facet WHERE facet.apiKeyId=?";
        final Query query = em.createQuery(stmtString);
        query.setParameter(1, apiKey.getId());
        query.executeUpdate();
    }

    @Override
  @Transactional(readOnly=false)
  public void persist(Object o) {
    em.persist(o);
  }

  @Override
  @Transactional(readOnly=false)
  public void merge(Object o) {
    em.merge(o);
  }

    @Override
    @Transactional(readOnly=false)
    public void delete(AbstractFacet facet) {
        AbstractFacet merged = em.merge(facet);
        em.remove(merged);
    }

}
TOP

Related Classes of org.fluxtream.core.connectors.dao.JPAFacetDao

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.