001/*
002 * Stallion Core: A Modern Web Framework
003 *
004 * Copyright (C) 2015 - 2016 Stallion Software LLC.
005 *
006 * This program is free software: you can redistribute it and/or modify it under the terms of the
007 * GNU General Public License as published by the Free Software Foundation, either version 2 of
008 * the License, or (at your option) any later version. This program is distributed in the hope that
009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
011 * License for more details. You should have received a copy of the GNU General Public License
012 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
013 *
014 *
015 *
016 */
017
018package io.stallion.dataAccess.db.postgres;
019
020import io.stallion.dataAccess.db.DB;
021import io.stallion.dataAccess.Tickets;
022import io.stallion.services.Log;
023import org.apache.commons.dbutils.QueryRunner;
024import org.apache.commons.dbutils.handlers.ScalarHandler;
025
026import java.sql.SQLException;
027import java.util.Queue;
028import java.util.concurrent.ConcurrentLinkedQueue;
029
030
031public class PostgresTickets implements Tickets {
032    private Queue<Long> loadedIds;
033    private DB db;
034
035
036    public PostgresTickets(DB db) {
037        this.db = db;
038        loadedIds = new ConcurrentLinkedQueue<Long>();
039        createSequence();
040        try {
041            refillQueue();
042        } catch (SQLException e) {
043            throw new RuntimeException(e);
044        }
045    }
046
047    public Long nextId() {
048        for (int x=0; x<20; x++) {
049            Long id = loadedIds.poll();
050            if (id != null) {
051                return id;
052            } else {
053                try {
054                    refillQueue();
055                } catch (Exception e) {
056                    Log.exception(e, "Error refilling queue");
057                    try {
058                        Thread.sleep(500);
059                    } catch (Exception ex) {
060                        throw new RuntimeException(e);
061                    }
062                }
063            }
064        }
065        throw new RuntimeException("Could not load the next ticket");
066    }
067
068    public void createSequence() {
069        QueryRunner q = db.newQuery();
070        try {
071            q.update("CREATE SEQUENCE stallion_tickets_seq INCREMENT BY 300 MINVALUE 100000;");
072        } catch(Exception e) {
073            Log.info("Sequence already exists");
074        }
075    }
076
077    public void refillQueue() throws SQLException {
078        QueryRunner q = db.newQuery();
079        ScalarHandler<Long> scalar = new ScalarHandler<Long>();
080        Long nextId = q.query("SELECT nextval('stallion_tickets_seq')", scalar);
081        for (int x= 0; x < 300; x++ ) {
082            loadedIds.add(nextId + x);
083        }
084    }
085}