com.ning.metrics.collector.processing.db.DatabaseFeedEventStorage.java Source code

Java tutorial

Introduction

Here is the source code for com.ning.metrics.collector.processing.db.DatabaseFeedEventStorage.java

Source

/*
 * Copyright 2010-2013 Ning, Inc.
 *
 * Ning licenses this file to you 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.ning.metrics.collector.processing.db;

import com.ning.metrics.collector.binder.config.CollectorConfig;
import com.ning.metrics.collector.processing.db.model.FeedEvent;
import com.ning.metrics.collector.processing.db.util.InClauseExpander;
import com.ning.metrics.collector.processing.db.util.MySqlLock;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.inject.Inject;

import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.joda.time.DateTimeZone;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.IDBI;
import org.skife.jdbi.v2.PreparedBatch;
import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.tweak.HandleCallback;
import org.skife.jdbi.v2.tweak.ResultSetMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.locks.Lock;

public class DatabaseFeedEventStorage implements FeedEventStorage {
    private static final Logger log = LoggerFactory.getLogger(DatabaseFeedEventStorage.class);
    private final IDBI dbi;
    private final CollectorConfig config;
    private final Lock dbLock;
    private static final ObjectMapper mapper = new ObjectMapper();

    @Inject
    public DatabaseFeedEventStorage(final IDBI dbi, final CollectorConfig config) {
        this.dbi = dbi;
        this.config = config;
        this.dbLock = new MySqlLock("feed-event-deletion", dbi);
    }

    @Override
    public List<String> insert(final Collection<FeedEvent> feedEvents) {
        return dbi.withHandle(new HandleCallback<List<String>>() {

            @Override
            public List<String> withHandle(Handle handle) throws Exception {
                final List<String> idList = Lists.newArrayListWithCapacity(feedEvents.size());
                PreparedBatch batch = handle.prepareBatch(
                        "insert into feed_events (id, channel, created_at, metadata, event, subscription_id) values (:id, :channel, :now, :metadata, :event, :subscription_id)");

                for (FeedEvent feedEvent : feedEvents) {
                    String id = UUID.randomUUID().toString();
                    idList.add(id);
                    batch.bind("id", id).bind("channel", feedEvent.getChannel())
                            .bind("metadata", mapper.writeValueAsString(feedEvent.getMetadata()))
                            .bind("event", mapper.writeValueAsString(feedEvent.getEvent()))
                            .bind("now", DateTimeUtils.getInstantMillis(new DateTime(DateTimeZone.UTC)))
                            .bind("subscription_id", feedEvent.getSubscriptionId()).add();
                }

                batch.execute();

                return idList;
            }
        });
    }

    @Override
    public List<FeedEvent> load(final String channel, final List<String> idList, final int count) {
        return dbi.withHandle(new HandleCallback<List<FeedEvent>>() {

            @Override
            public List<FeedEvent> withHandle(Handle handle) throws Exception {
                InClauseExpander in = new InClauseExpander(idList);

                return ImmutableList.copyOf(handle.createQuery(
                        "select id, channel, metadata, event, subscription_id from feed_events where channel = :channel and id in ("
                                + in.getExpansion() + ") limit :count")
                        .bind("channel", channel).bindNamedArgumentFinder(in).bind("count", count)
                        .setFetchSize(count).setMaxRows(count).map(new FeedEventRowMapper()).list());
            }

        });
    }

    public int cleanOldFeedEvents() {
        //if(dbLock.tryLock()){
        int deleted = dbi.withHandle(new HandleCallback<Integer>() {

            @Override
            public Integer withHandle(Handle handle) throws Exception {
                return handle.createStatement(
                        "delete from feed_events where created_at < :tillTimePeriod LIMIT :deleteFeedEventLimit")
                        .bind("tillTimePeriod",
                                DateTimeUtils.currentTimeMillis()
                                        - config.getFeedEventRetentionPeriod().getMillis())
                        .bind("deleteFeedEventLimit", config.getFeedEventCleanUpLimit()).execute();
            }
        });

        log.info(String.format("%d Feed events deleted successfully", deleted));

        return deleted;
        //}
    }

    public static class FeedEventRowMapper implements ResultSetMapper<FeedEvent> {

        @Override
        public FeedEvent map(int index, ResultSet r, StatementContext ctx) throws SQLException {
            try {
                return new FeedEvent(r.getString("id"), r.getString("channel"), r.getString("metadata"),
                        r.getString("event"), r.getLong("subscription_id"));
            } catch (IOException e) {
                throw new UnsupportedOperationException("Not Yet Implemented!", e);
            }
        }

    }

    @Override
    public void cleanUp() {
        dbLock.unlock();
    }

}