Package org.eurekastreams.server.persistence

Source Code of org.eurekastreams.server.persistence.TabMapper

/*
* Copyright (c) 2009-2010 Lockheed Martin Corporation
*
* 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.
*/
package org.eurekastreams.server.persistence;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eurekastreams.commons.hibernate.QueryOptimizer;
import org.eurekastreams.server.domain.Gadget;
import org.eurekastreams.server.domain.Tab;
import org.eurekastreams.server.domain.TabTemplate;
import org.eurekastreams.server.persistence.exceptions.GadgetDeletionException;
import org.eurekastreams.server.persistence.exceptions.GadgetUndeletionException;

/**
* This class provides the mapper functionality for Tab entities.
*/
public class TabMapper
{
    /**
     * Constructor.
     *
     * @param inQueryOptimizer
     *            the QueryOptimizer to use for specialized functions.
     */
    public TabMapper(final QueryOptimizer inQueryOptimizer)
    {
        queryOptimizer = inQueryOptimizer;
    }

    /**
     * The QueryOptimizer to use for specialized functions.
     */
    private QueryOptimizer queryOptimizer;

    /**
     * The entity manager to use for all ORM operations.
     */
    private EntityManager entityManager;

    /**
     * Default value for undeleteGadgetWindowInMinutes.
     */
    private final int defaultUndeleteGadgetWindowInMinutes = 20;

    /**
     * The number of minutes to allow a gadget to be undeleted in, defaults to 20 minutes.
     */
    private int undeleteGadgetWindowInMinutes = defaultUndeleteGadgetWindowInMinutes;

    /**
     * Logger instance for this class.
     */
    private Log logger = LogFactory.getLog(TabMapper.class);

    /**
     * Temp Method to get templates based on type. Note: this method only returns a single result, but queries all tab
     * templates. There is no way for the query to distinguish which tab template comes back.
     *
     * @param type
     *            The TabType.
     * @return the TabTemplate.
     */
    public TabTemplate getTabTemplate(final String type)
    {
        Query q = entityManager.createQuery("FROM TabTemplate t where t.type=:tabTemplateType").setParameter(
                "tabTemplateType", type);
        return (TabTemplate) q.getSingleResult();
    }

    /**
     * Set the number of minutes to allow a gadget to be undeleted in.
     *
     * @param undeleteWindowInMinutes
     *            the number of minutes to allow a tab to be undeleted in.
     */
    public void setUndeleteGadgetWindowInMinutes(final int undeleteWindowInMinutes)
    {
        this.undeleteGadgetWindowInMinutes = undeleteWindowInMinutes;
    }

    /**
     * Set the entity manager to use for all ORM operations.
     *
     * @param inEntityManager
     *            the entity manager to use for all ORM operations.
     */
    @PersistenceContext
    public void setEntityManager(final EntityManager inEntityManager)
    {
        this.entityManager = inEntityManager;
    }

    /**
     * Find the Tab by id and eagerly load the gadget collection.
     *
     * @param tabId
     *            ID of the Tab to look up.
     *
     * @return the entity with the input
     */
    public Tab findById(final Long tabId)
    {
        Query q = entityManager.createQuery(
                "from Tab t left join fetch t.template where t.id = :tabId and t.deleted = 'false'").setParameter(
                "tabId", tabId);
        Tab tab = (Tab) q.getSingleResult();

        // Touch the gadgets so that they will be eagerly loaded.
        tab.getGadgets().size();

        return tab;
    }

    /**
     * Find the parent Tab of the input Gadget id.
     *
     * @param gadgetId
     *            the Gadget id to find the parent Tab for.
     * @return the parent Tab
     */
    public TabTemplate findByGadgetId(final Long gadgetId)
    {
        return getTabTemplateByGadgetId(gadgetId, false);
    }

    /**
     * This method retrieves a tab with only a gadget id to start with.
     *
     * @param gadgetId
     *            - id of the gadget used to retrieve the container tab.
     * @return - container tab of the gadget id passed in.
     */
    public Tab findTabByGadgetId(final Long gadgetId)
    {
        Query q = entityManager.createQuery(
                "SELECT t FROM Tab t, Gadget g " + "WHERE g.id = :gadgetId " + "AND g.template.id = t.template.id")
                .setParameter("gadgetId", gadgetId);

        Tab tab = (Tab) q.getSingleResult();

        // Touch the gadgets so that they will be eagerly loaded.
        tab.getGadgets().size();

        return tab;
    }

    /**
     * Find the Tab by id.
     *
     * @param tabId
     *            ID of the Tab to look up
     * @return the entity with the input
     */
    public Tab findById(final Integer tabId)
    {
        return findById(tabId.longValue());
    }

    /**
     * Update all entities that have changed since they were loaded within the same context.
     */
    public void flush()
    {
        entityManager.flush();
    }

    /**
     * Mark the input gadget as deleted so that it may be undeleted later on.
     *
     * @param gadgetToDelete
     *            The gadget to delete.
     * @throws GadgetDeletionException
     *             thrown when the caller tries to delete a gadget from a tab that doesn't own the input gadget.
     */
    public void deleteGadget(final Gadget gadgetToDelete) throws GadgetDeletionException
    {

        // find the tab to which the input gadget belongs
        TabTemplate tab = null;
        try
        {
            tab = getTabTemplateByGadgetId(gadgetToDelete.getId(), false);
        }
        catch (Exception ex)
        {
            throw new GadgetDeletionException("Could not find either the specified Gadget or Tab", gadgetToDelete
                    .getId());
        }

        // remove the gadget from the collection
        if (tab.getGadgets().size() > 1)
        {
            tab.getGadgets().remove(gadgetToDelete);
            tab.getGadgets().add(gadgetToDelete);
        }

        // rearrange the gadgetIndexes of the other gadgets
        for (Gadget currentGadget : tab.getGadgets())
        {
            if (currentGadget.getZoneNumber() == gadgetToDelete.getZoneNumber()
                    && currentGadget.getZoneIndex() > gadgetToDelete.getZoneIndex())
            {
                currentGadget.setZoneIndex(currentGadget.getZoneIndex() - 1);
            }
        }

        // mark gadget as deleted, and re-attach it to the tab, because the
        // previous statement detatched it.
        markGadgetAsDeleted(tab, gadgetToDelete);

        // clean up all previously deleted gadgets that are no longer in the
        // undelete time frame.
        cleanUpDeletedGadgets();

    }

    /**
     * Implementation of the undelete method from the TabMapper interface.
     *
     * @param gadgetId
     *            id of the gadget to be undeleted.
     * @return gadget object represented by the gadget id.
     * @throws GadgetUndeletionException
     *             thrown when error undeleting a gadget.
     */

    public Gadget undeleteGadget(final long gadgetId) throws GadgetUndeletionException
    {
        // make sure the gadget exists in the input tab
        TabTemplate template = null;
        try
        {
            template = getTabTemplateByGadgetId(gadgetId, true);
        }
        catch (Exception ex)
        {
            throw new GadgetUndeletionException("Could not find either the specified gadget or tab for gadgetId="
                    + gadgetId, gadgetId);
        }

        /* get the deleted gadget from the database */
        Gadget gadgetToUndelete = (Gadget) entityManager.createQuery(
                "from Gadget where id = :gadgetId and deleted = true").setParameter("gadgetId", gadgetId)
                .getSingleResult();

        if (gadgetToUndelete == null)
        {
            throw new GadgetUndeletionException("Failure when trying to get gadget with id=" + gadgetId, gadgetId);
        }

        try
        {
            /*
             * bump up the zone index of each gadget in the same zone as the gadget to be undeleted
             */
            for (Gadget currentGadget : template.getGadgets())
            {

                if (currentGadget.getZoneNumber() == gadgetToUndelete.getZoneNumber()
                        && currentGadget.getZoneIndex() >= gadgetToUndelete.getZoneIndex())
                {
                    currentGadget.setZoneIndex(currentGadget.getZoneIndex() + 1);
                }
            }

            /* add the gadget back into the collection */
            template.getGadgets().add(gadgetToUndelete);

            /* update the status of the undeleted gadget in the database */
            entityManager.createQuery(
                    "update versioned Gadget set deleted = false, " + "dateDeleted = null, tabTemplateId = :tabId "
                            + "where id = :gadgetId").setParameter("gadgetId", gadgetToUndelete.getId()).setParameter(
                    "tabId", template.getId()).executeUpdate();

            return gadgetToUndelete;
        }
        catch (Exception ex)
        {
            throw new GadgetUndeletionException("An error occurred while trying to undelete the gadget with gadgetId="
                    + gadgetId, gadgetId);
        }
    }

    /**
     * Get the tab by gadget id.
     *
     * @param gadgetId
     *            The id of the gadget to find the tab for.
     *
     * @param isDeleted
     *            whether to look for deleted or undeleted gadget.
     *
     * @return the TabGroup that owns the input tabId.
     */
    private TabTemplate getTabTemplateByGadgetId(final long gadgetId, final boolean isDeleted)
    {
        return (TabTemplate) entityManager.createQuery(
                "select g.template from Gadget g where g.id = :gadgetId and g.deleted = :isDeleted").setParameter(
                "gadgetId", gadgetId).setParameter("isDeleted", isDeleted).getSingleResult();
    }

    /**
     * Mark the input gadget as deleted so that it's no longer returned in queries but can be undeleted later on. The
     * gadget would have just been removed from the gadget, so we need to set the tabId back to the gadget so that it's
     * ignored by the collection.
     *
     * @param template
     *            The TabTemplate that contains the gadget.
     * @param gadget
     *            The gadget to mark as deleted.
     */
    private void markGadgetAsDeleted(final TabTemplate template, final Gadget gadget)
    {
        GregorianCalendar currentDateTime = new GregorianCalendar();

        entityManager.createQuery(
                "update versioned Gadget set deleted = true, "
                        + "dateDeleted = :deletedTimestamp, tabTemplateId = :tabTemplateId " + "where id = :gadgetId")
                .setParameter("deletedTimestamp", currentDateTime.getTime()).setParameter("gadgetId", gadget.getId())
                .setParameter("tabTemplateId", template.getId()).executeUpdate();
    }

    /**
     * Clean up deleted gadgets here using the expired date set earlier. Currently this is hard-coded to be at least 20
     * (configurable) minutes since the gadget was originally deleted, but could be much longer because it is dependent
     * on the next gadget that is deleted. If one gadget is deleted on Jan 1st and the next gadget is deleted on March
     * 1st, the 1st gadget will remain flagged as deleted in the database until March 1st so we definitely need a full
     * timestamp for this object.
     */
    private void cleanUpDeletedGadgets()
    {
        GregorianCalendar expiredDateTime = new GregorianCalendar();
        expiredDateTime.add(Calendar.MINUTE, -undeleteGadgetWindowInMinutes);

        entityManager.createQuery(
                "delete from Gadget de where de.deleted = true " + "and de.dateDeleted < :expiredTimestamp")
                .setParameter("expiredTimestamp", expiredDateTime.getTime()).executeUpdate();
    }

    /**
     * This method is responsible for moving a gadget from one location to another on the any gadget page.
     *
     * @param gadgetId
     *            - id of the gadget that is being moved.
     * @param sourceTabTemplateId
     *            - id of the tab template where the gadget is moving from.
     * @param sourceZoneIndex
     *            - index of the position in the zone that the gadget is moving from.
     * @param sourceZoneNumber
     *            - number of the zone that the gadget is moving from.
     * @param targetTabTemplateId
     *            - id of the tab template where the gadget is moving to.
     * @param targetZoneIndex
     *            - index of the position in the zone that the gadget is moving to.
     * @param targetZoneNumber
     *            - number of the zone that the gadget is moving to.
     */
    @SuppressWarnings("unchecked")
    public void moveGadget(final Long gadgetId, final Long sourceTabTemplateId, final Integer sourceZoneIndex,
            final Integer sourceZoneNumber, final Long targetTabTemplateId, final Integer targetZoneIndex,
            final Integer targetZoneNumber)
    {
        logger.debug("Moving gadget: " + gadgetId + " from tab templateid: " + sourceTabTemplateId + " zoneNumber: "
                + sourceZoneNumber + " zoneIndex: " + sourceZoneIndex + " To " + " tab templateid: "
                + targetTabTemplateId + " zoneNumber: " + targetZoneNumber + " zoneIndex: " + targetZoneIndex);

        // Source
        List<Gadget> sourceGadgets = (List<Gadget>) entityManager.createQuery(
                "FROM Gadget g " + "WHERE g.template.id =:sourceTabTemplateId "
                        + "AND g.zoneNumber =:sourceZoneNumber AND g.deleted = false ORDER BY g.zoneIndex")
                .setParameter("sourceTabTemplateId", sourceTabTemplateId).setParameter("sourceZoneNumber",
                        sourceZoneNumber).getResultList();

        Gadget movingGadget = null;

        for (int i = 0; i < sourceGadgets.size(); i++)
        {
            if (sourceGadgets.get(i).getId() == gadgetId)
            {
                movingGadget = sourceGadgets.get(i);
                sourceGadgets.remove(i);
            }
        }

        // Target
        List<Gadget> targetGadgets = (List<Gadget>) entityManager.createQuery(
                "FROM Gadget g " + "WHERE g.template.id =:targetTabTemplateId "
                        + "AND g.zoneNumber =:targetZoneNumber AND g.deleted = false ORDER BY g.zoneIndex")
                .setParameter("targetTabTemplateId", targetTabTemplateId).setParameter("targetZoneNumber",
                        targetZoneNumber).getResultList();

        // Remove from target as well
        for (int i = 0; i < targetGadgets.size(); i++)
        {
            if (targetGadgets.get(i).getId() == gadgetId)
            {
                targetGadgets.remove(i);
            }
        }

        if (targetZoneIndex < targetGadgets.size())
        {
            targetGadgets.add(targetZoneIndex, movingGadget);
        }
        else
        {
            targetGadgets.add(movingGadget);
        }

        // Renumber Source gadgets
        for (int i = 0; i < sourceGadgets.size(); i++)
        {
            Gadget g = sourceGadgets.get(i);
            entityManager.createQuery(
                    "UPDATE versioned Gadget g SET g.zoneIndex = :newZoneIndex WHERE g.id = :gadgetId").setParameter(
                    "newZoneIndex", i).setParameter("gadgetId", g.getId()).executeUpdate();
        }

        // Renumber target gadgets
        for (int i = 0; i < targetGadgets.size(); i++)
        {
            Gadget g = targetGadgets.get(i);
            entityManager.createQuery(
                    "UPDATE versioned Gadget g SET g.zoneIndex = :newZoneIndex, "
                            + "g.template.id =:targetTabTemplateId, g.zoneNumber =:targetZoneNumber "
                            + "WHERE g.id = :gadgetId").setParameter("newZoneIndex", i).setParameter("gadgetId",
                    g.getId()).setParameter("targetTabTemplateId", targetTabTemplateId).setParameter(
                    "targetZoneNumber", targetZoneNumber).executeUpdate();
        }
    }
}
TOP

Related Classes of org.eurekastreams.server.persistence.TabMapper

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.