dk.dma.ais.reader.AisReaders.java Source code

Java tutorial

Introduction

Here is the source code for dk.dma.ais.reader.AisReaders.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.reader;

import com.google.common.net.HostAndPort;
import org.apache.commons.lang3.StringUtils;

import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipInputStream;

import static java.util.Objects.requireNonNull;

/**
 * Factory and utility methods for {@link AisReader}, {@link AisTcpReader}, {@link AisUdpReader}, 
 * and {@link AisReaderGroup} classes defined in this package.
 * 
 * @author Kasper Nielsen
 */
public class AisReaders {

    /**
     * Equivalent to {@link #parseSource(String)} except that it will parse an array of sources. Returning a map making
     * sure there all source names are unique
     */
    public static AisReaderGroup createGroup(String name, List<String> sources) {
        Map<String, AisTcpReader> readers = new HashMap<>();
        for (String s : sources) {
            AisTcpReader r = parseSource(s);
            if (readers.put(r.getSourceId(), r) != null) {
                // Make sure its unique
                throw new Error("More than one reader specified with the same source id (id =" + r.getSourceId()
                        + "), source string = " + sources);
            }
        }
        AisReaderGroup g = new AisReaderGroup(name);
        for (AisTcpReader r : readers.values()) {
            g.add(r);
        }
        return g;
    }

    /**
     * Creates a default group from reader available in the system property ais.default.sources
     * 
     * @return a new reader group
     * @see #getDefaultSources()
     */
    public static AisReaderGroup createGroupFromDefaultsSource() {
        return createGroup("defaults", Arrays.asList(getDefaultSources()));
    }

    /**
     * Creates a {@link AisTcpReader} from a list of one or more hosts. On the form: host1:port1,...,hostN:portN
     * 
     * @param commaHostPort
     */
    public static AisTcpReader createReader(String commaHostPort) {
        AisTcpReader r = new AisTcpReader();
        String[] hostPorts = StringUtils.split(commaHostPort, ",");
        for (String hp : hostPorts) {
            r.addHostPort(HostAndPort.fromString(hp));
        }
        return r;
    }

    public static AisTcpReader createReader(String hostname, int port) {
        AisTcpReader r = new AisTcpReader();
        r.addHostPort(HostAndPort.fromParts(hostname, port));
        return r;
    }

    /**
     * Creates a {@link AisUdpReader} listening on port for any interface
     * 
     * @param port
     * @return
     */
    public static AisUdpReader createUdpReader(int port) {
        return createUdpReader(null, port);
    }

    /**
     * Creates a {@link AisUdpReader} listening on ip and port
     * 
     * @param address
     * @param port
     * @return
     */
    public static AisUdpReader createUdpReader(String address, int port) {
        return new AisUdpReader(address, port);
    }

    public static AisReader createReaderFromInputStream(InputStream inputStream) {
        return new AisStreamReader(inputStream);
    }

    /**
     * Creates a {@link AisReader} from a file. If the file has '.zip' or '.gz' suffix the file will treated as a zip file or 
     * gzip file respectively. 
     * @param filename
     * @return
     * @throws IOException
     */
    public static AisReader createReaderFromFile(String filename) throws IOException {
        return new AisStreamReader(createFileInputStream(requireNonNull(filename)));
    }

    /**
     * Reader that recursively reads files matching pattern in directories with root dir  
     * @param dir
     * @param pattern E.g. *.txt or *.gz
     * @param recursive Apply to all sub directories depth first
     * @return
     * @throws IOException 
     */
    public static AisDirectoryReader createDirectoryReader(String dir, String pattern, boolean recursive)
            throws IOException {
        return new AisDirectoryReader(dir, pattern, recursive);
    }

    /**
     * Returns the default sources configured for the system. The default sources can be set using enviroment variable
     * AIS_DEFAULT_SOURCES.
     * 
     * @return the default sources configured for the system
     */
    public static String[] getDefaultSources() {
        String p = System.getProperty("AIS_DEFAULT_SOURCES");
        if (p == null) {
            p = System.getenv("AIS_DEFAULT_SOURCES");
            if (p == null) {
                throw new IllegalStateException("The property AIS_DEFAULT_SOURCES has not been set");
            }
        }
        return p.split(";");
    }

    public static void manageGroup(AisReaderGroup group) throws JMException {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        ObjectName mxbeanName = new ObjectName("dk.dma.ais.readers.group." + group.name + ":name=Group");
        mbs.registerMBean(new AisReaderGroupMXBeanImpl(group), mxbeanName);
        for (AisTcpReader r : group.readers.values()) {
            mxbeanName = new ObjectName(
                    "dk.dma.ais.readers.group." + group.name + ":source=Source-" + r.getSourceId());
            mbs.registerMBean(new AisReaderMXBeanImpl(r), mxbeanName);

        }
    }

    /**
     * Parses the string and returns either an {@link AisTcpReader} if only one hostname is found or a
     * {@link RoundRobinAisTcpReader} if more than 1 host name is found. Example
     * "mySource=ais163.sealan.dk:65262,ais167.sealan.dk:65261" will return a RoundRobinAisTcpReader alternating between
     * the two sources if one is down.
     * 
     * @param fullSource
     *            the full source
     * @return a ais reader
     */
    static AisTcpReader parseSource(String fullSource) {
        try (Scanner s = new Scanner(fullSource);) {
            s.useDelimiter("\\s*=\\s*");
            if (!s.hasNext()) {
                throw new IllegalArgumentException(
                        "Source must be of the format src=host:port,host:port, was " + fullSource);
            }
            String src = s.next();
            if (!s.hasNext()) {
                throw new IllegalArgumentException(
                        "A list of hostname:ports must follow the source (format src=host:port,host:port), was "
                                + fullSource);
            }
            AisTcpReader r = new AisTcpReader();
            try (Scanner s1 = new Scanner(s.next())) {
                s1.useDelimiter("\\s*,\\s*");
                if (!s1.hasNext()) {
                    throw new IllegalArgumentException(
                            "Source must have at least one host:port (format src=host:port,host:port), was "
                                    + fullSource);
                }
                while (s1.hasNext()) {
                    r.addHostPort(HostAndPort.fromString(s1.next()));
                }
            }
            r.setSourceId(src);
            return r;
        }
    }

    static InputStream createFileInputStream(String filename) throws IOException {
        InputStream in = new FileInputStream(filename);
        if (filename.endsWith(".gz")) {
            in = new GZIPInputStream(in);
        } else if (filename.endsWith(".zip")) {
            // TODO: currently only reads the first zip entry
            in = new ZipInputStream(in);
            ((ZipInputStream) in).getNextEntry();
        }

        return in;
    }

}