com.springsource.greenhouse.events.JdbcEventRepository.java Source code

Java tutorial

Introduction

Here is the source code for com.springsource.greenhouse.events.JdbcEventRepository.java

Source

/*
 /*
 * Copyright 2010 the original author or authors.
 *
 * 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 com.springsource.greenhouse.events;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

import javax.inject.Inject;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.joda.time.MutableDateTime;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.JoinRowMapper;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.springsource.greenhouse.utils.Location;
import com.springsource.greenhouse.utils.ResourceReference;
import com.springsource.greenhouse.utils.SubResourceReference;

/**
 * EventRepository implementation that stores Event data in a relational database using the JDBC API.
 * @author Keith Donald
 */
@Repository
public class JdbcEventRepository implements EventRepository {

    private final JdbcTemplate jdbcTemplate;

    @Inject
    public JdbcEventRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public List<Event> findUpcomingEvents(Long afterMillis) {
        return jdbcTemplate.query(SELECT_UPCOMING_EVENTS, eventMapper.list(),
                new Date(afterMillis != null ? afterMillis : System.currentTimeMillis()));
    }

    public Event findEventBySlug(String groupSlug, Integer year, Integer month, String slug) {
        return jdbcTemplate.queryForObject(SELECT_EVENT_BY_SLUG, eventMapper.single(), groupSlug, year, month,
                slug);
    }

    public String findEventSearchString(Long eventId) {
        return jdbcTemplate.queryForObject(
                "select g.hashtag from Event e, MemberGroup g where e.id = ? and e.memberGroup = g.id",
                String.class, eventId);
    }

    public String findSessionSearchString(Long eventId, Integer sessionId) {
        return jdbcTemplate.queryForObject(
                "select (select g.hashtag from Event e, MemberGroup g where e.id = ? and e.memberGroup = g.id) || ' ' || hashtag from EventSession where event = ? and id = ?",
                String.class, eventId, eventId, sessionId);
    }

    @Transactional
    public List<EventSession> findSessionsOnDay(Long eventId, LocalDate day, Long attendeeId) {
        DateTimeZone eventTimeZone = DateTimeZone.forID(
                jdbcTemplate.queryForObject("select timezone from Event where id = ?", String.class, eventId));
        DateTime dayStart = day.toDateTimeAtStartOfDay(eventTimeZone);
        DateTime dayEnd = dayStart.plusDays(1);
        return jdbcTemplate.query(SELECT_SESSIONS_ON_DAY, eventSessionMapper.list(), attendeeId, eventId,
                dayStart.toDate(), dayEnd.toDate());
    }

    public List<EventSession> findEventFavorites(Long eventId, Long attendeeId) {
        return jdbcTemplate.query(SELECT_EVENT_FAVORITES, eventSessionMapper.list(), eventId, attendeeId, eventId);
    }

    public List<EventSession> findAttendeeFavorites(Long eventId, Long attendeeId) {
        return jdbcTemplate.query(SELECT_ATTENDEE_FAVORITES, eventSessionMapper.list(), attendeeId, eventId);
    }

    @Transactional
    public boolean toggleFavorite(Long eventId, Integer sessionId, Long attendeeId) {
        boolean favorite = jdbcTemplate.queryForObject(
                "select exists(select 1 from EventSessionFavorite where event = ? and session = ? and attendee = ?)",
                Boolean.class, eventId, sessionId, attendeeId);
        if (favorite) {
            jdbcTemplate.update("delete from EventSessionFavorite where event = ? and session = ? and attendee = ?",
                    eventId, sessionId, attendeeId);
        } else {
            jdbcTemplate.update("insert into EventSessionFavorite (event, session, attendee) values (?, ?, ?)",
                    eventId, sessionId, attendeeId);
        }
        return !favorite;
    }

    @Transactional
    public Float rate(Long eventId, Integer sessionId, Long attendeeId, Rating rating)
            throws RatingPeriodClosedException {
        if (!isSessionEnded(eventId, sessionId)) {
            throw new RatingPeriodClosedException(eventId, sessionId);
        }
        boolean rated = jdbcTemplate.queryForObject(
                "select exists(select 1 from EventSessionRating where event = ? and session = ? and attendee = ?)",
                Boolean.class, eventId, sessionId, attendeeId);
        if (rated) {
            jdbcTemplate.update(
                    "update EventSessionRating set rating = ?, comment = ? where event = ? and session = ? and attendee = ?",
                    rating.getValue(), rating.getComment(), eventId, sessionId, attendeeId);
        } else {
            jdbcTemplate.update(
                    "insert into EventSessionRating (event, session, attendee, rating, comment) values (?, ?, ?, ?, ?)",
                    eventId, sessionId, attendeeId, rating.getValue(), rating.getComment());
        }
        Float newAvgRating = jdbcTemplate.queryForObject(
                "select round(avg(cast(rating as double)) * 2, 0) / 2 from EventSessionRating where event = ? and session = ? group by event, session",
                Float.class, eventId, sessionId);
        jdbcTemplate.update("update EventSession set rating = ? where event = ? and id = ?", newAvgRating, eventId,
                sessionId);
        return newAvgRating;
    }

    @Transactional
    public long addEvent() {
        return 0;
    }

    // internal helpers

    private boolean isSessionEnded(Long eventId, Integer sessionId) {
        Date endTime = jdbcTemplate.queryForObject(
                "select ts.endTime from EventTimeSlot ts, EventSession s where s.event = ? and s.id = ? and ts.id = s.timeSlot",
                Date.class, eventId, sessionId);
        return new Date().after(endTime);
    }

    private final JoinRowMapper<Event, Long> eventMapper = new JoinRowMapper<Event, Long>() {
        protected Long mapId(ResultSet rs) throws SQLException {
            return rs.getLong("id");
        }

        protected Event mapRoot(Long id, ResultSet rs) throws SQLException {
            String eventTimeZone = rs.getString("timeZone");
            return new Event(id, rs.getString("title"), DateTimeZone.forID(eventTimeZone),
                    adjustEventTimeToUTC(rs.getTimestamp("startTime"), eventTimeZone),
                    adjustEventTimeToUTC(rs.getTimestamp("endTime"), eventTimeZone), rs.getString("slug"),
                    rs.getString("description"), rs.getString("hashtag"),
                    new ResourceReference<String>(rs.getString("groupSlug"), rs.getString("groupName")));
        }

        protected void addChild(Event event, ResultSet rs) throws SQLException {
            event.addVenue(
                    new Venue(rs.getLong("venueId"), rs.getString("venueName"), rs.getString("venuePostalAddress"),
                            new Location(rs.getDouble("venueLatitude"), rs.getDouble("venueLongitude")),
                            rs.getString("venueLocationHint")));
        }
    };

    private final JoinRowMapper<EventSession, Integer> eventSessionMapper = new JoinRowMapper<EventSession, Integer>() {
        protected Integer mapId(ResultSet rs) throws SQLException {
            return rs.getInt("id");
        }

        protected EventSession mapRoot(Integer id, ResultSet rs) throws SQLException {
            String eventTimeZone = "America/New_York"; // HACK: For now hard-code to S2GX 2012's value while sorting this out.         
            return new EventSession(id, rs.getString("title"),
                    adjustEventTimeToUTC(rs.getTimestamp("startTime"), eventTimeZone),
                    adjustEventTimeToUTC(rs.getTimestamp("endTime"), eventTimeZone), rs.getString("description"),
                    rs.getString("hashtag"), rs.getFloat("rating"),
                    new SubResourceReference<Long, Integer>(rs.getLong("venue"), rs.getInt("room"),
                            rs.getString("roomName")),
                    rs.getBoolean("favorite"));
        }

        protected void addChild(EventSession session, ResultSet rs) throws SQLException {
            session.addLeader(new EventSessionLeader(rs.getString("name")));
        }
    };

    private static DateTime adjustEventTimeToUTC(Timestamp timestamp, String eventTimeZone) {
        MutableDateTime mutableDateTime = new DateTime(timestamp).toMutableDateTime();
        mutableDateTime.setZoneRetainFields(DateTimeZone.forID(eventTimeZone));
        DateTime utcAdjustedDateTime = mutableDateTime.toDateTime().toDateTime(DateTimeZone.UTC);
        return utcAdjustedDateTime;
    }

    private static final String SELECT_FROM_EVENT_SESSION = "select s.id, s.title, ts.startTime, ts.endTime, s.description, s.hashtag, s.rating, s.venue, s.room, r.name as roomName, (f.attendee is not null) as favorite, l.name from EventSession s ";

    private static final String SELECT_EVENT = "select e.id, e.title, e.timeZone, e.startTime, e.endTime, e.slug, e.description, g.hashtag, g.slug as groupSlug, g.name as groupName, "
            + "v.id as venueId, v.name as venueName, v.postalAddress as venuePostalAddress, v.latitude as venueLatitude, v.longitude as venueLongitude, v.locationHint as venueLocationHint from Event e "
            + "inner join MemberGroup g on e.memberGroup = g.id " + "inner join EventVenue ev on e.id = ev.event "
            + "inner join Venue v on ev.venue = v.id";

    private static final String SELECT_UPCOMING_EVENTS = SELECT_EVENT + " where e.endTime > ? order by e.startTime";

    private static final String SELECT_EVENT_BY_SLUG = SELECT_EVENT
            + " where g.slug = ? and extract(year from e.startTime) = ? and extract(month from e.startTime) = ? and e.slug = ?";

    private static final String SELECT_SESSIONS_ON_DAY = SELECT_FROM_EVENT_SESSION
            + "left outer join VenueRoom r on s.venue = r.venue and s.room = r.id "
            + "left outer join EventSessionFavorite f on s.event = f.event and s.id = f.session and f.attendee = ? "
            + "inner join EventSessionLeader sl on s.event = sl.event and s.id = sl.session "
            + "inner join Leader l on sl.leader = l.id " + "inner join EventTimeSlot ts on ts.id = s.timeSlot "
            + "where s.event = ? and ts.startTime >= ? and ts.endTime <= ? "
            + "order by ts.startTime, s.id, sl.rank";

    private static final String SELECT_EVENT_FAVORITES = SELECT_FROM_EVENT_SESSION
            + "inner join (select top 10 session, count(*) as favoriteCount from EventSessionFavorite where event = ? group by session) top on s.id = top.session "
            + "left outer join VenueRoom r on s.venue = r.venue and s.room = r.id "
            + "left outer join EventSessionFavorite f on s.event = f.event and s.id = f.session and f.attendee = ? "
            + "inner join EventSessionLeader sl on s.event = sl.event and s.id = sl.session "
            + "inner join Leader l on sl.leader = l.id " + "inner join EventTimeSlot ts on ts.id = s.timeSlot "
            + "where s.event = ? " + "order by top.favoriteCount desc, s.id, sl.rank";

    private static final String SELECT_ATTENDEE_FAVORITES = SELECT_FROM_EVENT_SESSION
            + "left outer join VenueRoom r on s.venue = r.venue and s.room = r.id "
            + "inner join EventSessionFavorite f on s.event = f.event and s.id = f.session and f.attendee = ? "
            + "inner join EventSessionLeader sl on s.event = sl.event and s.id = sl.session "
            + "inner join Leader l on sl.leader = l.id " + "inner join EventTimeSlot ts on ts.id = s.timeSlot "
            + "where s.event = ? " + "order by f.rank, s.id, sl.rank";

}