org.deegree.tools.coverage.converter.RasterConverter.java Source code

Java tutorial

Introduction

Here is the source code for org.deegree.tools.coverage.converter.RasterConverter.java

Source

//$HeadURL$
/*----------------------------------------------------------------------------
 This file is part of deegree, http://deegree.org/
 Copyright (C) 2001-2010 by:
 - Department of Geography, University of Bonn -
 and
 - lat/lon GmbH -
    
 This library is free software; you can redistribute it and/or modify it under
 the terms of the GNU Lesser General Public License as published by the Free
 Software Foundation; either version 2.1 of the License, or (at your option)
 any later version.
 This library is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 details.
 You should have received a copy of the GNU Lesser General Public License
 along with this library; if not, write to the Free Software Foundation, Inc.,
 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    
 Contact information:
    
 lat/lon GmbH
 Aennchenstr. 19, 53177 Bonn
 Germany
 http://lat-lon.de/
    
 Department of Geography, University of Bonn
 Prof. Dr. Klaus Greve
 Postfach 1147, 53001 Bonn
 Germany
 http://www.geographie.uni-bonn.de/deegree/
    
 e-mail: info@deegree.org
 ----------------------------------------------------------------------------*/
package org.deegree.tools.coverage.converter;

import static org.deegree.commons.tools.CommandUtils.OPT_VERBOSE;
import static org.deegree.commons.tools.CommandUtils.getIntOption;
import static org.deegree.coverage.tools.RasterOptionsParser.OPT_OUTPUT_TYPE;
import static org.deegree.coverage.tools.RasterOptionsParser.OPT_OUTPUT_TYPE_ABBREV;
import static org.deegree.coverage.tools.RasterOptionsParser.OPT_RASTER_OUT_LOC;
import static org.deegree.coverage.tools.RasterOptionsParser.OPT_TYPE_DESC;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.deegree.commons.annotations.Tool;
import org.deegree.commons.tools.CommandUtils;
import org.deegree.commons.utils.FileUtils;
import org.deegree.coverage.AbstractCoverage;
import org.deegree.coverage.raster.AbstractRaster;
import org.deegree.coverage.raster.MultiResolutionRaster;
import org.deegree.coverage.raster.SimpleRaster;
import org.deegree.coverage.raster.TiledRaster;
import org.deegree.coverage.raster.container.TileContainer;
import org.deegree.coverage.raster.data.nio.ByteBufferRasterData;
import org.deegree.coverage.raster.io.RasterIOOptions;
import org.deegree.coverage.raster.io.RasterReader;
import org.deegree.coverage.raster.utils.RasterFactory;
import org.deegree.coverage.tools.RasterOptionsParser;
import org.deegree.cs.exceptions.TransformationException;
import org.deegree.cs.exceptions.UnknownCRSException;

/**
 * Takes a raster file, or a number of raster files and convert it/them to another raster type.
 * 
 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
 * @author last edited by: $Author$
 * 
 * @version $Revision$, $Date$
 */
@Tool("Converts a raster from one type into another.")
public class RasterConverter {

    private static final String OPT_NUM_THREADS = "num_threads";

    /**
     * a starter method to transform a given point or a serie of points read from a file.
     * 
     * @param args
     * @throws UnknownCRSException
     * @throws IOException
     *             if the buffered reader could not read from the file
     */
    public static void main(String[] args) throws UnknownCRSException, IOException {
        CommandLineParser parser = new PosixParser();

        Options options = initOptions();
        boolean verbose = false;

        // for the moment, using the CLI API there is no way to respond to a help argument; see
        // https://issues.apache.org/jira/browse/CLI-179
        if (args != null && args.length > 0) {
            for (String a : args) {
                if (a != null && a.toLowerCase().contains("help") || "-?".equals(a)) {
                    printHelp(options);
                }
            }
        }
        CommandLine line = null;
        try {
            line = parser.parse(options, args);
            verbose = line.hasOption(OPT_VERBOSE);
            System.exit(init(line));
        } catch (ParseException exp) {
            System.err.println("ERROR: Invalid command line: " + exp.getMessage());
            printHelp(options);
        } catch (Throwable e) {
            System.err.println(
                    "An Exception occurred while converting your raster data, error message: " + e.getMessage());
            if (verbose) {
                e.printStackTrace();
            }
            System.exit(1);
        }
    }

    /**
     * add crs and point here if using eclipse to start.
     * 
     * @throws TransformationException
     * @throws IllegalArgumentException
     * @throws UnknownCRSException
     * @throws IOException
     * @throws ParseException
     * @throws InterruptedException
     */
    private static int init(CommandLine line) throws IllegalArgumentException, TransformationException,
            UnknownCRSException, IOException, ParseException, InterruptedException {

        RasterIOOptions options = RasterOptionsParser.parseRasterIOOptions(line);

        int numThreads = getIntOption(line, OPT_NUM_THREADS, 4);

        File f = RasterOptionsParser.getRasterLocation(line);
        if (f.isFile()) {
            numThreads = 1;
        }
        String outputLoc = line.getOptionValue(OPT_RASTER_OUT_LOC);
        String ext = line.getOptionValue(OPT_OUTPUT_TYPE);
        AbstractCoverage raster = RasterOptionsParser.loadCoverage(line, options);
        RasterConverter converter = new RasterConverter();
        return converter.convert(raster, outputLoc, numThreads, ext, line.hasOption(OPT_VERBOSE));
    }

    /**
     * @param numThreads
     * @param outLoc
     * @throws InterruptedException
     * @throws IOException
     * 
     */
    private int convert(AbstractCoverage source, String outLoc, int numThreads, String outputFormat,
            final boolean verbose) throws InterruptedException, IOException {
        List<SimpleRaster> tiles = new LinkedList<SimpleRaster>();
        getTiles(source, tiles);
        if (tiles.isEmpty()) {
            System.err.println("Found no raster tiles in source: " + source + ", hence nothing to convert.");
            return 1;
        }
        ExecutorService executor = Executors.newFixedThreadPool(numThreads);
        SimpleRaster simpleRaster = tiles.get(0);
        RasterReader rasterReader = ((ByteBufferRasterData) simpleRaster.getRasterData()).getReader();
        File file = rasterReader.file();
        File outputLocation = getOutputLocation(file, outLoc, outputFormat, tiles.size() == 1);

        for (final SimpleRaster tile : tiles) {
            File outFile = null;
            ByteBufferRasterData data = (ByteBufferRasterData) tile.getRasterData();
            RasterReader origReader = data.getReader();
            final String tileName = origReader.getDataLocationId();
            if (tiles.size() == 1) {
                if (outputLocation.isFile()) {
                    outFile = outputLocation.getAbsoluteFile();
                } else {
                    outFile = createNewFile(outputLocation, tileName, outputFormat);
                }
            } else {
                outFile = createNewFile(outputLocation, tileName, outputFormat);
            }
            final File absTileFilename = outFile;
            System.out.println("Converting: " + tileName + " -> file: " + absTileFilename);

            Runnable command = new Runnable() {
                public void run() {
                    try {
                        String thread = Thread.currentThread().getName();
                        System.out.println(thread + " saving... " + tileName);
                        RasterFactory.saveRasterToFile(tile, absTileFilename);
                        tile.dispose();
                        System.out.println(thread + " done... " + tileName);
                    } catch (Exception e) {
                        System.err.println("Ar error occurred while processing tile: " + tileName + ": "
                                + e.getLocalizedMessage());
                        if (verbose) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            executor.execute(command);

        }
        shutdownExecutorAndWaitForFinish(executor);
        return 0;
    }

    private File getOutputLocation(File tileFile, String reqOutputLocation, String outputFormat, boolean singleTile)
            throws IOException {
        String outDir = reqOutputLocation;
        if (tileFile == null) {
            if (outDir == null) {
                String tmpDir = System.getProperty("java.io.tmpdir");
                outDir = tmpDir;
                System.out.println(
                        "No output location given and no file url to load from, writing result in tmp dir: "
                                + tmpDir);
            }
        } else {
            if (outDir == null) {
                // use file dir.
                outDir = tileFile.getParent();
            }
        }
        File outputLocation = null;
        File testFile = new File(outDir);
        if (!testFile.exists()) {
            if (testFile.getParentFile().exists()) {
                // the parent exists, are we requesting a file?
                if (singleTile) {
                    // only one file, maybe the parent exists?
                    File parent = testFile.getParentFile();
                    String ext = FileUtils.getFileExtension(testFile);
                    if (ext == null) {
                        ext = outputFormat;
                    }
                    String fName = FileUtils.getFilename(testFile);
                    outputLocation = createNewFile(parent, fName, ext);
                } else {
                    outputLocation = testFile.getParentFile();
                }
            }
        } else {
            // file exists
            if (testFile.isFile()) {
                if (!singleTile) {
                    System.out.println(
                            "Only one output file was given, but multiple input files were selected, using parent directory instead.");
                } else {
                    outputLocation = testFile.getAbsoluteFile();
                }
            } else {
                outputLocation = testFile;
                // file naming is done while converting.
            }
        }
        if (outputLocation == null) {
            // stranger things happened :-)
            outputLocation = new File(System.getProperty("java.io.tmpdir"));
            System.out.println("Could not determine the output directory. Using: "
                    + outputLocation.getAbsolutePath() + " as base directory for output.");
        }
        return outputLocation;
    }

    private File createNewFile(File outputDirectory, String fName, String ext) throws IOException {

        File outputFile = new File(outputDirectory, fName + "." + ext);

        int i = 1;

        while (outputFile.exists()) {
            outputFile = new File(outputDirectory, fName + "-" + (i++) + "." + ext);
        }
        boolean suc = outputFile.createNewFile();
        if (!suc) {
            throw new IOException("Could not create new raster file at location:" + outputDirectory);
        }
        return outputFile;
    }

    /**
     * @param source
     * @param tiles
     */
    private void getTiles(AbstractCoverage source, List<SimpleRaster> tiles) {
        if (source != null) {
            if (source instanceof AbstractRaster) {
                AbstractRaster rast = (AbstractRaster) source;
                if (rast.isSimpleRaster()) {
                    tiles.add((SimpleRaster) source);
                } else if (rast instanceof TiledRaster) {
                    TiledRaster tr = (TiledRaster) rast;
                    TileContainer container = tr.getTileContainer();
                    List<AbstractRaster> origTiles = container.getTiles(tr.getEnvelope());
                    for (AbstractRaster r : origTiles) {
                        if (r != null) {
                            getTiles(r, tiles);
                        }
                    }
                } else {
                    System.err.println("Unknown raster type: " + rast);
                }
            } else {
                if (source instanceof MultiResolutionRaster) {
                    MultiResolutionRaster mrr = (MultiResolutionRaster) source;
                    List<Double> resolutions = mrr.getResolutions();
                    if (resolutions != null && !resolutions.isEmpty()) {
                        for (Double res : resolutions) {
                            AbstractRaster raster = mrr.getRaster(res);
                            getTiles(raster, tiles);
                        }
                    }
                } else {
                    System.err.println("Unknown coverage type: " + source);
                }
            }
        }
    }

    private void shutdownExecutorAndWaitForFinish(ExecutorService executor) throws InterruptedException {
        executor.shutdown();
        /** oh them tonny */
        executor.awaitTermination(42, TimeUnit.DAYS);

    }

    private static Options initOptions() {
        Options options = new Options();

        Option option = new Option(RasterOptionsParser.OPT_RASTER_OUT_LOC_ABBREV, OPT_RASTER_OUT_LOC, true,
                "the output directory for the raster tree, defaults to input dir");
        option.setArgs(1);
        option.setArgName("dir|file");
        options.addOption(option);

        option = new Option(OPT_OUTPUT_TYPE_ABBREV, OPT_OUTPUT_TYPE, true, "The output type of the rasters.");
        option.setArgs(1);
        option.setArgName(OPT_TYPE_DESC);
        option.setRequired(true);
        options.addOption(option);

        option = new Option(OPT_NUM_THREADS, "the number of threads used.");
        option.setArgs(1);
        option.setArgName("threads");
        options.addOption(option);

        RasterOptionsParser.addRasterIOLineOptions(options);

        CommandUtils.addDefaultOptions(options);

        return options;

    }

    private static void printHelp(Options options) {
        CommandUtils.printHelp(options, RasterConverter.class.getCanonicalName(), null, null);
    }

}