dk.dma.ais.store.AisStoreSchema.java Source code

Java tutorial

Introduction

Here is the source code for dk.dma.ais.store.AisStoreSchema.java

Source

/* Copyright (c) 2011 Danish Maritime Authority.
 *
 * 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 dk.dma.ais.store;

import com.google.common.hash.Hashing;
import com.google.common.primitives.Ints;
import dk.dma.ais.packet.AisPacket;

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

/**
 * This file contains the schema that is being used to store data in AisStore. It also contains various utility methods.
 * 
 * @author Kasper Nielsen
 */
public class AisStoreSchema {

    /** Identifiers of the columns in use (names are shared across tables). */
    public enum Column {
        /** Common name of column holding time block (i.e. no. of 10 minute blocks since the epoch. */
        COLUMN_TIMEBLOCK("timeblock"),

        /** Common name of column holding timestamp with millisecond precision. */
        COLUMN_TIMESTAMP("time"),

        /** Common name of column holding cellid (geographical area) */
        COLUMN_CELLID("cellid"),

        /** Common name of column holding MMSI no. */
        COLUMN_MMSI("mmsi"),

        /** Common name of column holding aisdata message digest (to avoid storing duplicates) */
        COLUMN_AISDATA_DIGEST("digest"),

        /** We store the actual AIS message in this column. */
        COLUMN_AISDATA("aisdata");

        private final String columnName;

        private Column(String columnName) {
            this.columnName = columnName;
        }

        public String toString() {
            return this.columnName;
        }
    }

    /** Identifiers of the different tables in use. */
    public enum Table {
        /**
         * This table holds all packets stored in row with the number of 10 minute blocks since the
         * epoch as the key. Within each 10 minute blocks, packets are store ordered by timestamp (and a message
         * digest to avoid duplicates).
         */
        TABLE_PACKETS_TIME("packets_time"),

        /**
         * This table holds all packets (with a valid message) stored in row with the MMSI number as the key. The columns
         * are ordered by timestamp and a message digest to avoid duplicates.
         */
        TABLE_PACKETS_MMSI("packets_mmsi"),

        /** This table contains AIS packets ordered by timeblock and geographic cells of size 1 degree. */
        TABLE_PACKETS_AREA_CELL1("packets_area_cell1"),

        /** This table contains AIS packets ordered by timeblock and geographic cells of size 10 degrees. */
        TABLE_PACKETS_AREA_CELL10("packets_area_cell10"),

        /** This table holds AIS packets ordered by MMSI number with an unknown position. */
        TABLE_PACKETS_AREA_UNKNOWN("packets_area_unknown");

        private final String tableName;

        private Table(String tableName) {
            this.tableName = tableName;
        }

        public String toString() {
            return this.tableName;
        }
    }

    /** True if queries should use packets_area_cell10 when relevant; false if always use packets_area_cell1 */
    public final static boolean TABLE_PACKETS_AREA_CELL10_ENABLED = false;

    /**
     * Converts a milliseconds since epoch to a 10-minute blocks since epoch.
     *
     * @param timestamp the timestamp to convert
     * @return the converted value
     */
    public static final int timeBlock(Table table, Instant timestamp) {
        int timeblock = -1;
        switch (table) {
        case TABLE_PACKETS_TIME:
        case TABLE_PACKETS_AREA_CELL1:
        case TABLE_PACKETS_AREA_CELL10:
            timeblock = getTimeBlock(timestamp, Duration.ofMinutes(10));
            break;
        case TABLE_PACKETS_MMSI:
        case TABLE_PACKETS_AREA_UNKNOWN:
            timeblock = getTimeBlock(timestamp, Duration.ofDays(30));
            break;
        default:
            throw new IllegalArgumentException(table.toString());
        }
        return timeblock;
    }

    public static Integer[] timeBlocks(Table table, Instant timeStart, Instant timeStop) {
        int timeBlockMin = timeBlock(table, timeStart);
        int timeBlockMax = timeBlock(table, timeStop);

        List<Integer> timeBlocks = new ArrayList<>(timeBlockMax - timeBlockMin + 1);
        for (int timeBlock = timeBlockMin; timeBlock <= timeBlockMax; timeBlock++)
            timeBlocks.add(timeBlock);

        return timeBlocks.toArray(new Integer[timeBlocks.size()]);
    }

    private static final int getTimeBlock(Instant timestamp, Duration unit) {
        return Ints.checkedCast(timestamp.getEpochSecond() / unit.getSeconds());
    }

    /**
     * Calculates a message digest for the given messages (AisPackets).
     */
    public static final byte[] digest(AisPacket packet) {
        return Hashing.murmur3_128().hashUnencodedChars(packet.getStringMessage()).asBytes();
    }
}