com.google.flightmap.parsing.faa.nasr.CommParser.java Source code

Java tutorial

Introduction

Here is the source code for com.google.flightmap.parsing.faa.nasr.CommParser.java

Source

/* 
 * Copyright (C) 2010 Google Inc.
 *
 * 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.google.flightmap.parsing.faa.nasr;

import com.google.flightmap.common.io.StreamUtils;
import com.google.flightmap.db.JdbcAviationDbAdapter;
import com.google.flightmap.db.JdbcAviationDbWriter;
import com.google.flightmap.parsing.data.AirportComm;
import com.google.flightmap.parsing.db.AviationDbReader;
import com.google.flightmap.parsing.db.AviationDbWriter;
import com.google.flightmap.parsing.util.IcaoUtils;

import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

import java.io.*;
import java.sql.*;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.*;

/**
 * Parses airports from compiled AFD file.
 */
public class CommParser {
    // Commandline options
    private final static Options OPTIONS = new Options();
    private final static String HELP_OPTION = "help";
    private final static String TWR_OPTION = "twr";
    private final static String IATA_TO_ICAO_OPTION = "iata_to_icao";
    private final static String FREQ_USES_NORMALIZATION_OPTION = "freq_uses_normalization";
    private final static String AVIATION_DB_OPTION = "aviation_db";

    private final static Pattern freqPattern = Pattern.compile("^(\\d+\\.\\d+\\S?)((?: |\\().*)?$");

    static {
        OPTIONS.addOption("h", "help", false, "Print this message.");
        OPTIONS.addOption(OptionBuilder.withLongOpt(TWR_OPTION)
                .withDescription("Terminal Communications Services (TWR) file.").hasArg().isRequired()
                .withArgName("TWR.txt").create());
        OPTIONS.addOption(
                OptionBuilder.withLongOpt(IATA_TO_ICAO_OPTION).withDescription("IATA to ICAO codes text file.")
                        .hasArg().isRequired().withArgName("iata_to_icao.txt").create());
        OPTIONS.addOption(OptionBuilder.withLongOpt(FREQ_USES_NORMALIZATION_OPTION)
                .withDescription("Normalized frequency uses csv file.").hasArg().isRequired()
                .withArgName("distinct_freq_uses.csv").create());
        OPTIONS.addOption(
                OptionBuilder.withLongOpt(AVIATION_DB_OPTION).withDescription("FlightMap aviation database")
                        .hasArg().isRequired().withArgName("aviation.db").create());
    }

    private final AviationDbWriter dbWriter;
    private final AviationDbReader dbReader;
    private final Map<String, String> iataToIcao;
    private final Map<String, NormalizedFrequencyUseBean> normalizedFreqUses;
    private final String data;

    /**
     * @param twrFile NASR Terminal Communications Services database file.
     * @param iataToIcaoFile IATA to ICAO codes file
     * @param dbFile Aviation database file
     */
    public CommParser(final String twrFile, final String iataToIcaoFile, final String freqUsesNormalizationFile,
            final String dbFile) throws ClassNotFoundException, IOException, SQLException {
        dbWriter = new JdbcAviationDbWriter(new File(dbFile));
        dbWriter.open();
        dbReader = new JdbcAviationDbAdapter(dbWriter.getConnection());
        data = StreamUtils.read(new File(twrFile));
        iataToIcao = IcaoUtils.parseIataToIcao(iataToIcaoFile);
        normalizedFreqUses = NormalizedFrequencyUseUtils.parse(freqUsesNormalizationFile);
    }

    private void execute() throws Exception {
        dbWriter.beginTransaction();
        try {
            addCommData();
            dbWriter.commit();
        } catch (Exception ex) {
            dbWriter.rollback();
            throw ex;
        } finally {
            dbWriter.close();
        }
    }

    private void addCommData() throws IOException, SQLException {
        final BufferedReader in = new BufferedReader(new StringReader(data));
        String line;

        while ((line = in.readLine()) != null) {
            if (Twr3.matches(line)) {
                final Twr3 record = new Twr3(line);
                final List<AirportComm> comms = new LinkedList<AirportComm>();
                comms.addAll(getCommFromTwr3(record.facilityIdentifier, record.frequency1, record.sectorization1));
                comms.addAll(getCommFromTwr3(record.facilityIdentifier, record.frequency2, record.sectorization2));
                comms.addAll(getCommFromTwr3(record.facilityIdentifier, record.frequency3, record.sectorization3));
                comms.addAll(getCommFromTwr3(record.facilityIdentifier, record.frequency4, record.sectorization4));
                comms.addAll(getCommFromTwr3(record.facilityIdentifier, record.frequency5, record.sectorization5));
                comms.addAll(getCommFromTwr3(record.facilityIdentifier, record.frequency6, record.sectorization6));
                comms.addAll(getCommFromTwr3(record.facilityIdentifier, record.frequency7, record.sectorization7));
                comms.addAll(getCommFromTwr3(record.facilityIdentifier, record.frequency8, record.sectorization8));
                comms.addAll(getCommFromTwr3(record.facilityIdentifier, record.frequency9, record.sectorization9));
                for (AirportComm comm : comms) {
                    addAirportCommToDb(comm);
                }
            } else if (Twr7.matches(line)) {
                final Twr7 record = new Twr7(line);
                final AirportComm comm = getCommFromTwr7(record);
                addAirportCommToDb(comm);
            }
        }
    }

    private List<AirportComm> getCommFromTwr3(final String ident, final String frequencyAndRemarks,
            final String sectorization) {
        final List<AirportComm> airportComms = new LinkedList<AirportComm>();
        if (frequencyAndRemarks == null || frequencyAndRemarks.isEmpty() || sectorization == null
                || sectorization.isEmpty()) {
            return airportComms;
        }
        final int airportId = getAirportId(ident);
        if (airportId == -1) {
            return airportComms;
        }
        final String[] freqRemarks = getFrequencyAndRemarks(frequencyAndRemarks);
        if (freqRemarks != null) {
            airportComms.add(new AirportComm(airportId, sectorization, freqRemarks[0], freqRemarks[1]));
        }
        return airportComms;
    }

    private AirportComm getCommFromTwr7(final Twr7 record) {
        final int airportId = getAirportId(record.satelliteIdentifier);
        if (airportId == -1) {
            return null;
        }
        final String[] freqRemarks = getFrequencyAndRemarks(record.frequency);
        if (freqRemarks == null) {
            return null;
        }
        return new AirportComm(airportId, record.frequencyUse, freqRemarks[0], freqRemarks[1]);
    }

    /**
     * Extract frequency and remarks from input.
     * @param input Raw input (eg. {@code 132.8(241-269)})
     */
    private static String[] getFrequencyAndRemarks(final String input) {
        final Matcher freqMatcher = freqPattern.matcher(input);
        if (!freqMatcher.matches()) {
            return null;
        }
        final String frequency = freqMatcher.group(1);
        final String remarks = freqMatcher.group(2);
        return new String[] { frequency, remarks != null ? remarks.trim() : null };
    }

    private int getAirportId(final String iata) {
        final String icao = iataToIcao.get(iata);
        return dbReader.getAirportIdByIcao(icao == null ? iata : icao);
    }

    private void addAirportCommToDb(AirportComm comm) throws SQLException {
        if (comm == null) {
            return;
        }
        try {
            final int frequency = Integer.parseInt(comm.frequency.split("\\.")[0]);
            if (frequency < 108 || frequency > 137) { // Skip (military?) frequency
                return;
            }
            // Normalize frequency use ("APP/P DEP/P" -> "APP/DEP")
            comm = getNormalizedAirportComm(comm);
            // Merge identical CTAF, TWR records
            final int id = comm.airportId;
            if ("TWR".equals(comm.identifier) && comm.frequency.equals(dbReader.getCtaf(id))) {
                final StringBuilder sb = new StringBuilder();
                if (comm.remarks != null && !comm.remarks.isEmpty()) {
                    sb.append(comm.remarks);
                    sb.append(" ");
                }
                sb.append("(also CTAF)");
                comm = new AirportComm(id, comm.identifier, comm.frequency, sb.toString());
                dbWriter.deleteCtaf(id);
            }
            dbWriter.insertAirportComm(comm.airportId, comm.identifier, comm.frequency, comm.remarks);
        } catch (NumberFormatException nfe) {
            System.err.println("Could not parse frequency: " + comm.frequency);
        }
    }

    private AirportComm getNormalizedAirportComm(final AirportComm comm) {
        final NormalizedFrequencyUseBean normalizedFreq = normalizedFreqUses.get(comm.identifier);
        if (normalizedFreq == null) {
            return comm;
        }
        final String identifier = normalizedFreq.getNormalizedUse();
        final String originalRemarks = comm.remarks;
        final String normalizedRemarks = normalizedFreq.getRemarks();
        String remarks = "";
        if (originalRemarks != null && !originalRemarks.isEmpty()) {
            remarks = originalRemarks;
        }
        if (normalizedRemarks != null && !normalizedRemarks.isEmpty()) {
            if (remarks.isEmpty()) {
                remarks = normalizedRemarks;
            } else {
                remarks += " " + normalizedRemarks;
            }
        }

        final AirportComm normalizedComm = new AirportComm(comm.airportId, identifier, comm.frequency, remarks);
        return normalizedComm;
    }

    private static void printHelp(final CommandLine line) {
        final HelpFormatter formatter = new HelpFormatter();
        formatter.setWidth(100);
        formatter.printHelp("CommParser", OPTIONS, true);
    }

    public static void main(String args[]) {
        CommandLine line = null;
        try {
            final CommandLineParser parser = new PosixParser();
            line = parser.parse(OPTIONS, args);
        } catch (ParseException pEx) {
            System.err.println(pEx.getMessage());
            printHelp(line);
            System.exit(1);
        }

        if (line.hasOption(HELP_OPTION)) {
            printHelp(line);
            System.exit(0);
        }

        final String twrFile = line.getOptionValue(TWR_OPTION);
        final String iataToIcaoFile = line.getOptionValue(IATA_TO_ICAO_OPTION);
        final String freqUsesNormalizationFile = line.getOptionValue(FREQ_USES_NORMALIZATION_OPTION);
        final String dbFile = line.getOptionValue(AVIATION_DB_OPTION);

        try {
            (new CommParser(twrFile, iataToIcaoFile, freqUsesNormalizationFile, dbFile)).execute();
        } catch (Exception ex) {
            ex.printStackTrace();
            System.exit(1);
        }
    }

}