moos.ssds.dao.EventDAO.java Source code

Java tutorial

Introduction

Here is the source code for moos.ssds.dao.EventDAO.java

Source

/*
 * Copyright 2009 MBARI
 *
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 2.1 
 * (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.gnu.org/copyleft/lesser.html
 *
 * 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 moos.ssds.dao;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;

import moos.ssds.dao.util.MetadataAccessException;
import moos.ssds.metadata.DataProducer;
import moos.ssds.metadata.Event;
import moos.ssds.metadata.IMetadataObject;
import moos.ssds.metadata.util.MetadataException;
import moos.ssds.util.DateUtils;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

public class EventDAO extends MetadataDAO {

    /**
     * The Log4J Logger
     */
    static Logger logger = Logger.getLogger(EventDAO.class);

    /**
     * This is the constructor that calls the super constructor and sets the
     * proper class and Hibernate Session
     * 
     * @param session
     *            is the <code>Session</code> that will be used in the
     *            persistent operations
     * @throws MetadataAccessException
     *             if something goes weird
     */
    public EventDAO(Session session) throws MetadataAccessException {
        super(Event.class, session);
    }

    /**
     * @see IMetadataDAO#findEquivalentPersistentObject(IMetadataObject)
     */
    public IMetadataObject findEquivalentPersistentObject(IMetadataObject metadataObject,
            boolean returnFullObjectGraph) throws MetadataAccessException {
        logger.debug("findEquivalentPersistentObject called");

        // First try to cast to a Event
        Event event = this.checkIncomingMetadataObject(metadataObject);

        // The Event that will be returned
        Event eventToReturn = null;

        // If the ID was specified, use that for the search
        if (event.getId() != null)
            eventToReturn = (Event) this.findById(event.getId(), false);

        // If nothing found, try to find by alternate primary key which is event
        // name and start and end dates
        if (eventToReturn == null)
            eventToReturn = this.findByNameAndDates(event.getName(), event.getStartDate(), event.getEndDate(),
                    false);

        // Double check that if the incoming event has an ID, it matches
        // the one that was found with the matching URI string
        if ((event.getId() != null) && (eventToReturn != null)) {
            if (event.getId().longValue() != eventToReturn.getId().longValue()) {
                logger.error(
                        "The ID and the dates of the incoming Event " + "did not match a ID/dates combination of "
                                + "anything in the persistent store, this should " + "not happen");
                throw new MetadataAccessException(
                        "The ID and the dates of the incoming Event " + "did not match a ID/dates combination of "
                                + "anything in the persistent store, this should " + "not happen");
            }
        }

        if ((returnFullObjectGraph) && (eventToReturn != null))
            eventToReturn = (Event) this.getMetadataObjectGraph(eventToReturn);

        logger.debug("OK, returning the persistent event: " + eventToReturn);
        return eventToReturn;
    }

    /**
     * @see IMetadataDAO#findAllIDs()
     */
    @SuppressWarnings("unchecked")
    public Collection<Long> findAllIDs() throws MetadataAccessException {
        // Create an empty array in case nothing is found
        Collection<Long> eventIDs = new ArrayList<Long>();

        // Create the query and run it
        try {
            Query query = getSession()
                    .createQuery("select distinct event.id from " + "Event event order by event.id");
            eventIDs = query.list();
        } catch (HibernateException e) {
            throw new MetadataAccessException(e.getMessage());
        }
        return eventIDs;
    }

    /**
     * @see IMetadataDAO#countFindAllIDs()
     */
    public int countFindAllIDs() throws MetadataAccessException {
        // The count
        int count = 0;
        try {
            Long longCount = (Long) getSession()
                    .createQuery("select count(distinct event.id) from " + "Event event").uniqueResult();
            if (longCount != null)
                count = longCount.intValue();
        } catch (HibernateException e) {
            throw new MetadataAccessException(e.getMessage());
        }

        // Return the result
        return count;
    }

    /**
     * This method search for an <code>Event</code> that matches the name
     * supplied and the start and end date supplied. If the name is not
     * specified, an empty collection is returned. If the start and/or end dates
     * are null, they will simply not be used in the query.
     * 
     * @param name
     * @param exactMatch
     * @param orderByPropertyName
     * @param ascendingOrDescending
     * @param returnFullObjectGraph
     * @return
     * @throws MetadataAccessException
     */
    @SuppressWarnings("unchecked")
    public Collection<Event> findByName(String name, boolean exactMatch, String orderByPropertyName,
            String ascendingOrDescending, boolean returnFullObjectGraph) throws MetadataAccessException {

        // An empty collection to be returned in case nothing is found
        Collection<Event> results = new ArrayList<Event>();

        // Make sure argument is not null
        if ("".equals(name)) {
            return results;
        }

        // Construct and run the query
        try {
            Criteria criteria = this.formulatePropertyCriteria(false, null, name, exactMatch, null, false, null,
                    false, orderByPropertyName, ascendingOrDescending);
            results = criteria.list();
        } catch (HibernateException e) {
            throw new MetadataAccessException(e.getMessage());
        }

        // If the full object graphs are requested
        if (returnFullObjectGraph)
            results = (Collection<Event>) getRealObjectsAndRelationships(results);

        // Return the results
        return results;
    }

    /**
     * This method searches for an <code>Event</code> whose name is like (in the
     * SQL sense) the name supplied
     * 
     * @param likeName
     * @param orderByPropertyName
     * @param ascendingOrDescending
     * @param returnFullObjectGraph
     * @return
     * @throws MetadataAccessException
     */
    public Collection<Event> findByLikeName(String likeName, String orderByPropertyName,
            String ascendingOrDescending, boolean returnFullObjectGraph) throws MetadataAccessException {
        return this.findByName(likeName, false, orderByPropertyName, ascendingOrDescending, returnFullObjectGraph);
    }

    /**
     * TODO kgomes document this
     * 
     * @return
     * @throws MetadataAccessException
     */
    @SuppressWarnings("unchecked")
    public Collection<String> findAllNames() throws MetadataAccessException {
        // An empty collection in case nothing is found
        Collection<String> eventNames = new ArrayList<String>();

        // Create the query and run it
        try {
            Query query = getSession()
                    .createQuery("select distinct event.name from " + "Event event order by event.name");
            eventNames = query.list();
        } catch (HibernateException e) {
            throw new MetadataAccessException(e);
        }
        return eventNames;
    }

    /**
     * TODO kgomes document this
     * 
     * @param name
     * @param startDate
     * @param endDate
     * @param returnFullObjectGraph
     * @return
     * @throws MetadataAccessException
     */
    public Event findByNameAndDates(String name, Date startDate, Date endDate, boolean returnFullObjectGraph)
            throws MetadataAccessException {

        // The event to return
        Event eventToReturn = null;

        // First check to see if the parameters are OK
        if ((name == null) || (name.equals("")) || (startDate == null) || (endDate == null))
            return null;

        // Check to make sure they are in correct sequence
        if (endDate.before(startDate))
            throw new MetadataAccessException("End date specified is before the start date. "
                    + "Now that just doesn't make sense now does it?");

        // Create of window around the start and end dates to effectively remove
        // the milliseconds from the query (which are unreliable in storing in
        // the DB)
        Date startDateRoundDown = DateUtils.roundDateDownToSeconds(startDate);
        Date startDateNextSecond = new Date(startDateRoundDown.getTime() + 1000);
        Date endDateRoundDown = DateUtils.roundDateDownToSeconds(endDate);
        Date endDateNextSecond = new Date(endDateRoundDown.getTime() + 1000);

        // Now build and perform the query
        eventToReturn = (Event) this.getSession().createCriteria(Event.class).add(Restrictions.eq("name", name))
                .add(Restrictions.lt("startDate", startDateNextSecond))
                .add(Restrictions.ge("startDate", startDateRoundDown))
                .add(Restrictions.lt("endDate", endDateNextSecond))
                .add(Restrictions.ge("endDate", endDateRoundDown)).uniqueResult();

        // Check for objectgraph
        if (returnFullObjectGraph)
            eventToReturn = (Event) getRealObjectAndRelationships(eventToReturn);

        // Return the result
        return eventToReturn;
    }

    /**
     * TODO kgomes document this
     * 
     * @param startDate
     * @param endDate
     * @param orderByPropertyName
     * @param ascendingOrDescending
     * @param returnFullObjectGraph
     * @return
     * @throws MetadataAccessException
     */
    @SuppressWarnings("unchecked")
    public Collection<Event> findWithinDateRange(Date startDate, Date endDate, String orderByPropertyName,
            String ascendingOrDescending, boolean returnFullObjectGraph) throws MetadataAccessException {
        // An empty collection to be returned in case nothing is found
        Collection<Event> results = new ArrayList<Event>();

        // Construct and run the query
        try {
            Criteria criteria = this.formulatePropertyCriteria(false, null, null, false, startDate, false, endDate,
                    false, orderByPropertyName, ascendingOrDescending);
            results = criteria.list();
        } catch (HibernateException e) {
            throw new MetadataAccessException(e.getMessage());
        }

        // If the full object graphs are requested
        if (returnFullObjectGraph)
            results = (Collection<Event>) getRealObjectsAndRelationships(results);

        // Return the results
        return results;
    }

    /**
     * @see IMetadataDAO#makePersistent(IMetadataObject)
     */
    public Long makePersistent(IMetadataObject metadataObject) throws MetadataAccessException {

        logger.debug("makePersistent called");

        // The flag to indicate if this was previously persisted
        boolean persistedBefore = false;

        // Check incoming object
        Event event = this.checkIncomingMetadataObject(metadataObject);

        // Check the persistent store for the matching object
        Event persistentEvent = (Event) this.findEquivalentPersistentObject(event, false);

        // The handle to the event to really be persisted
        Event eventToPersist = null;

        // Since one already exists, copy over any non-null, changed fields and
        // assign to the handle
        if (persistentEvent != null) {
            this.updateDestinationObject(event, persistentEvent);

            // Set the flag
            persistedBefore = true;

            // Assign to the handle
            eventToPersist = persistentEvent;
        } else {
            // Since this will be a new Event, make sure alternate business key
            // is there. Actually for event the alternate business key is name,
            // start and end date, but name is the critical one and is the only
            // enforced key in the data store
            if ((event.getName() == null) || (event.getName().equals(""))) {
                try {
                    event.setName("Event_" + getUniqueNameSuffix());
                } catch (MetadataException e) {
                    logger.error("MetadataException caught trying to set " + "an auto-generated event " + "name: "
                            + e.getMessage());
                }
                addMessage(ssdsAdminEmailToAddress,
                        "An incoming event did not have a name, " + "so SSDS auto-generated one:<br><ul><li>"
                                + event.toStringRepresentation("<li>") + "</ul><br>");
            }

            // Set the flag
            persistedBefore = false;

            // Attach to handle
            eventToPersist = event;
        }

        // If it was not persisted before, save it
        if (!persistedBefore)
            getSession().save(eventToPersist);

        // Return the ID
        if (eventToPersist != null) {
            return eventToPersist.getId();
        } else {
            return null;
        }
    }

    /**
     * @see IMetadataDAO#makeTransient(IMetadataObject)
     */
    public void makeTransient(IMetadataObject metadataObject) throws MetadataAccessException {

        logger.debug("makeTransient called");

        // Check incoming object
        Event event = this.checkIncomingMetadataObject(metadataObject);

        // Check the persistent store for the matching object
        Event persistentEvent = (Event) this.findEquivalentPersistentObject(event, false);

        // If no matching event was found, do nothing
        if (persistentEvent == null) {
            logger.debug("No matching event could be found in the persistent store, " + "no delete performed");
        } else {

            // Make sure the event is removed from any DataProducers
            DataProducerDAO dataProducerDAO = new DataProducerDAO(getSession());
            Collection<DataProducer> dataProducersByEvent = dataProducerDAO.findByEvent(persistentEvent, null, null,
                    false);
            if (dataProducersByEvent != null) {
                Iterator<DataProducer> iterator = dataProducersByEvent.iterator();
                while (iterator.hasNext()) {
                    DataProducer dataProducer = iterator.next();
                    dataProducer.removeEvent(persistentEvent);
                }
            }

            logger.debug("Existing object was found, " + "so we will try to delete it");
            try {
                getSession().delete(persistentEvent);
            } catch (HibernateException e) {
                logger.error("HibernateException caught (will be re-thrown):" + e.getMessage());
                throw new MetadataAccessException(e);
            }
        }
    }

    /**
     * This method checks to make sure an incoming <code>MetadataObject</code>
     * is not null and is in fact of the correct class. It then converts it to
     * the correct class and returns it
     * 
     * @param metadataObject
     *            the <code>MetadataObject</code> to check and return as a
     *            <code>Event</code>
     * @return a <code>Event</code> that is same object that came in
     * @throws MetadataAccessException
     *             if something is wrong
     */
    private Event checkIncomingMetadataObject(IMetadataObject metadataObject) throws MetadataAccessException {

        // Check for null argument
        if (metadataObject == null) {
            throw new MetadataAccessException("Failed: incoming Event was null");
        }

        // Try to cast the incoming object into the correct class
        Event event = null;
        try {
            event = (Event) metadataObject;
        } catch (ClassCastException cce) {
            throw new MetadataAccessException("Could not cast the incoming object into a Event");
        }
        return event;
    }

    /**
     * 
     * @param countQuery
     * @param id
     * @param name
     * @param exactNameMatch
     * @param startDate
     * @param boundedByStartDate
     * @param endDate
     * @param boundedByEndDate
     * @param orderByProperty
     * @param ascendOrDescend
     * @return
     * @throws MetadataAccessException
     */
    private Criteria formulatePropertyCriteria(boolean countQuery, Long id, String name, boolean exactNameMatch,
            Date startDate, boolean boundedByStartDate, Date endDate, boolean boundedByEndDate,
            String orderByProperty, String ascendOrDescend) throws MetadataAccessException {

        // The Criteria to return
        Criteria criteria = getSession().createCriteria(Event.class);

        // Make it distinct
        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

        // Check for exceptional conditions on the query
        if ((startDate != null) && (endDate != null) && (endDate.before(startDate)))
            throw new MetadataAccessException("The end date specified (" + endDate
                    + ") is before the start date specified (" + startDate + ")");

        // Now build the Criteria
        if (id != null) {
            criteria.add(Restrictions.eq("id", id));
        } else {
            if ((name != null) && (!name.equals(""))) {
                if (exactNameMatch) {
                    criteria.add(Restrictions.eq("name", name));
                } else {
                    criteria.add(Restrictions.like("name", "%" + name + "%"));
                }
            }
            if (startDate != null) {
                criteria.add(
                        Restrictions.or(Restrictions.gt("endDate", startDate), Restrictions.isNull("endDate")));
                if (boundedByStartDate) {
                    criteria.add(Restrictions.gt("startDate", startDate));
                }
            }
            if (endDate != null) {
                criteria.add(
                        Restrictions.or(Restrictions.lt("startDate", endDate), Restrictions.isNull("startDate")));
                if (boundedByEndDate) {
                    criteria.add(Restrictions.lt("endDate", endDate));
                }
            }
        }

        // Setup if a count query, if not add fetching and ordering
        if (countQuery) {
            criteria.setProjection(Projections.rowCount());
        } else {
            addOrderByCriteria(criteria, orderByProperty, ascendOrDescend);
        }

        // Now return the Criteria
        return criteria;
    }
}