Package org.geotools.gce.imagepyramid

Source Code of org.geotools.gce.imagepyramid.Utils$NumericDirectoryFilter

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*
*    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;
*    version 2.1 of the License.
*
*    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.
*/
package org.geotools.gce.imagepyramid;

import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.geotools.data.DataUtilities;
import org.geotools.factory.Hints;
import org.geotools.gce.imagemosaic.ImageMosaicFormat;
import org.geotools.gce.imagemosaic.ImageMosaicReader;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.resources.coverage.CoverageUtilities;
import org.geotools.util.logging.Logging;
import org.opengis.referencing.datum.PixelInCell;

/**
* Code to build a pyramid from a gdal_retile output
*
* @author Andrea Aime - GeoSolutions SAS
* @author Simone Giannecchini, GeoSolutions SAS
*
*/
class Utils {

    static final Logger LOGGER = Logging.getLogger(Utils.class);
   
    static URL checkSource(Object source, Hints hints) {
        URL sourceURL = null;
        File sourceFile = null;

        //
        // Check source
        //
        // if it is a URL or a String let's try to see if we can get a file to
        // check if we have to build the index
        if (source instanceof File) {
            sourceFile = (File) source;
            sourceURL = DataUtilities.fileToURL(sourceFile);
        } else if (source instanceof URL) {
            sourceURL = (URL) source;
            if (sourceURL.getProtocol().equals("file")) {
                sourceFile = DataUtilities.urlToFile(sourceURL);
            }
        } else if (source instanceof String) {
            // is it a File?
            final String tempSource = (String) source;
            File tempFile = new File(tempSource);
            if (!tempFile.exists()) {
                // is it a URL
                try {
                    sourceURL = new URL(tempSource);
                    source = DataUtilities.urlToFile(sourceURL);
                } catch (MalformedURLException e) {
                    sourceURL = null;
                    source = null;
                }
            } else {
                sourceURL = DataUtilities.fileToURL(tempFile);
                sourceFile = tempFile;
            }
        } else {
            // we really don't know how to convert the thing... give up
            if(LOGGER.isLoggable(Level.WARNING)){
                LOGGER.warning("we really don't know how to convert the thing: "+source!=null?source.toString():"null");
            }
            return null;
        }

        // logging
        if(LOGGER.isLoggable(Level.FINE)){
            if(sourceFile!=null){
                final String message = fileStatus(sourceFile);
                LOGGER.fine(message);
            }
        }

        //
        // Handle cases where the pyramid descriptor file already exists
        //
        // can't do anything with it
        if(sourceFile == null || !sourceFile.exists()){
            return sourceURL;
        }
       
        // if it's already a file we don't need to adjust it, will try to open as is
        if(!sourceFile.isDirectory()){
            return sourceURL;
        }
       
        // it's a directory, let's see if it already has a pyramid description file inside
        File directory = sourceFile;
        sourceFile = new File(directory, directory.getName() + ".properties");
        // logging
        if(LOGGER.isLoggable(Level.FINE)){
            if(sourceFile!=null){
                final String message = fileStatus(sourceFile);
                LOGGER.fine(message);
            }
        }       
        if(sourceFile.exists()){
            return DataUtilities.fileToURL(sourceFile);
        }
       

        //
        // Try to build the sub-folders mosaics
        //
        // if the structure of the directories is gdal_retile like, move the root files in their
        // own sub directory
        File zeroLevelDirectory = new File(directory, "0");
        IOFileFilter directoryFilter = FileFilterUtils.directoryFileFilter();
        File[] numericDirectories = directory.listFiles(new NumericDirectoryFilter());
        File[] directories = directory.listFiles((FileFilter) directoryFilter);
       
        // do we have at least one numeric? sub-directory?
        if(numericDirectories.length == 0){
            if(LOGGER.isLoggable(Level.INFO)){
                LOGGER.info("I was unable to determine a structure similar to the GDAL Retile one for the provided path: "+directory);
            }
            return null;
        }
       
        // check the gdal case and move files if necessary
        if(!zeroLevelDirectory.exists() && numericDirectories.length == directories.length) {
            LOGGER.log(Level.INFO, "Detected gdal_retile file structure, " +
                "moving root files to the '0' subdirectory");
            if(zeroLevelDirectory.mkdir()) {
                if(LOGGER.isLoggable(Level.FINE)){
                    LOGGER.fine("Created '0' subidr, now moving files");
                }                  
                FileFilter notDirFilter = FileFilterUtils.notFileFilter(directoryFilter);
                for (File f : directory.listFiles(notDirFilter)) {
                    if(LOGGER.isLoggable(Level.FINE)){
                        LOGGER.fine("Moving file"+f.getAbsolutePath());
                   
                    if(LOGGER.isLoggable(Level.FINEST)){
                        LOGGER.finest(fileStatus(f));
                    }                     
                    if(!f.renameTo(new File(zeroLevelDirectory, f.getName())))
                        LOGGER.log(Level.WARNING, "Could not move " + f.getAbsolutePath() +
                                " to " + zeroLevelDirectory+ " check the permission inside the source directory "+f.getParent()+ " and target directory "+zeroLevelDirectory);
                }
                directories = directory.listFiles((FileFilter) directoryFilter);
            } else {
                if(LOGGER.isLoggable(Level.INFO)){
                    LOGGER.info("I was unable to create the 0 directory. check the file permission in the parent directory:"+sourceFile.getParent());
                }
                return null;
            }
        }
       
        // scan each subdirectory and try to build a mosaic in it, accumulate the resulting mosaics
        List<MosaicInfo> mosaics = new ArrayList<MosaicInfo>();
        ImageMosaicFormat mosaicFactory = new ImageMosaicFormat();
        for (File subdir : directories) {
            if(mosaicFactory.accepts(subdir, hints)) {
                if(LOGGER.isLoggable(Level.FINE)){
                    LOGGER.fine("Trying to build mosaic for the directory:"+subdir.getAbsolutePath());
                }               
                mosaics.add(new MosaicInfo(subdir, mosaicFactory.getReader(subdir, hints)));
            } else {
                if(LOGGER.isLoggable(Level.INFO)){
                    LOGGER.info("Unable to build mosaic for the directory:"+subdir.getAbsolutePath());
                }
            }
        }
       
        // do we have at least one level?
        if(mosaics.size() == 0){
            return null;
        }
    
        // sort the mosaics by resolution and check they are actually in ascending resolution order
        // for both X and Y resolutions
        Collections.sort(mosaics);
        for(int i = 1; i < mosaics.size(); i++) {
            double[] resprev = mosaics.get(i - 1).getResolutions();
            double[] res = mosaics.get(i).getResolutions();
            if(resprev[1] > res[1]) {
                LOGGER.log(Level.INFO, "Invalid mosaic, y resolution in "
                        + mosaics.get(i - 1).getPath() + " is greater than the one in "
                        + mosaics.get(i).getPath() + " whilst x resolutions " +
                            "have the opposite relationship");
                return null;
            }
        }
       
        //
        // We have everything we need, build the final pyramid descriptor info
        //       
        // build the property file
        Properties properties = new Properties();
        properties.put("Name", directory.getName());
        properties.put("LevelsNum", String.valueOf(mosaics.size()));
        StringBuilder sbDirNames = new StringBuilder();
        StringBuilder sbLevels = new StringBuilder();
        for(MosaicInfo mi : mosaics) {
            sbDirNames.append(mi.getName()).append(" ");
            double[] resolutions = mi.getResolutions();
            sbLevels.append(resolutions[0]).append(",").append(resolutions[1]).append(" ");
        }
        properties.put("LevelsDirs", sbDirNames.toString());
        properties.put("Levels", sbLevels.toString());
        GeneralEnvelope envelope = mosaics.get(0).getEnvelope();
        properties.put("Envelope2D", envelope.getMinimum(0) + "," + envelope.getMinimum(1) + " " +
                envelope.getMaximum(0) + "," + envelope.getMaximum(1));
        OutputStream os = null;
        try {
            os = new FileOutputStream(sourceFile);
            properties.store(os, "Automatically generated");
        } catch(IOException e) {
            LOGGER.log(Level.INFO, "We could not generate the pyramid propert file " +
                    sourceFile.getPath(), e);
            return null;
        } finally {
            if(os != null)
                IOUtils.closeQuietly(os);
        }
       
        // build the .prj file if possible
        if(envelope.getCoordinateReferenceSystem() != null) {
            File prjFile = new File(directory, directory.getName() + ".prj");
            PrintWriter pw = null;
            try {
                pw = new PrintWriter(new FileOutputStream(prjFile));
                pw.print(envelope.getCoordinateReferenceSystem().toString());
            } catch(IOException e) {
                LOGGER.log(Level.INFO, "We could not write out the projection file " +
                        prjFile.getPath(), e);
                return null;
            } finally {
                pw.close();
            }
        }
       
        return DataUtilities.fileToURL(sourceFile);
    }

    /**
     * Prepares a message with the status of the provided file.
     * @param sourceFile The {@link File} to provided the status message for
     * @return a status message for the provided {@link File} or a {@link NullPointerException} in case the {@link File}is <code>null</code>.
     */
    private static String fileStatus(File sourceFile) {
        if(sourceFile==null){
            throw new NullPointerException("Provided null input to fileStatus method");
        }
        final StringBuilder builder = new StringBuilder();
        builder.append("Checking file: ").append(FilenameUtils.getFullPath(sourceFile.getAbsolutePath())).append("\n");
        builder.append("exists: ").append(sourceFile.exists()).append("\n");
        builder.append("isFile: ").append(sourceFile.isFile()).append("\n");
        builder.append("canRead: ").append(sourceFile.canRead()).append("\n");
        builder.append("canWrite: ").append(sourceFile.canWrite()).append("\n");
        builder.append("canExecute: ").append(sourceFile.canExecute()).append("\n");       
        builder.append("isHidden: ").append(sourceFile.isHidden()).append("\n");
        builder.append("lastModified: ").append(sourceFile.lastModified()).append("\n");
       
        return builder.toString();
    }
   
   
    /**
     * Stores informations about a mosaic
     */
    static class MosaicInfo implements Comparable<MosaicInfo>{
        @Override
        public String toString() {
            return "MosaicInfo [directory=" + directory + ", resolutions="
                    + Arrays.toString(resolutions) + "]";
        }

        File directory;
        ImageMosaicReader reader;
        double[] resolutions;
       
        MosaicInfo(File directory, ImageMosaicReader reader) {
            this.directory = directory;
            this.reader = reader;
            this.resolutions = CoverageUtilities.getResolution((AffineTransform) reader.getOriginalGridToWorld(PixelInCell.CELL_CORNER));
        }
       
        double[] getResolutions() {
            return resolutions;
        }
       
        String getPath() {
            return directory.getPath();
        }
       
        String getName() {
            return directory.getName();
        }
       
        GeneralEnvelope getEnvelope() {
            return reader.getOriginalEnvelope();
        }
       
        public int compareTo(MosaicInfo other) {
            // we make an easy comparison against the x resolution, we'll do a sanity
            // check about the y resolution later
            return resolutions[0] > other.resolutions[0] ? 1 : -1;
        }
    }
   
    /**
     * A file filter that only returns directories whose name is an integer number
     * @author Andrea Aime - OpenGeo
     */
    static class NumericDirectoryFilter implements FileFilter {

        public boolean accept(File pathname) {
            if(!pathname.isDirectory())
                return false;
            try {
                Integer.parseInt(pathname.getName());
                return true;
            } catch(NumberFormatException e) {
                return false;
            }
        }
    }
    
}
TOP

Related Classes of org.geotools.gce.imagepyramid.Utils$NumericDirectoryFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.