/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2008, Open Source Geospatial Foundation (OSGeo)
* (C) 2010, Geomatys
*
* 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.geotoolkit.data.shapefile.lock;
import org.geotoolkit.nio.IOUtilities;
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Level;
import static java.nio.file.StandardOpenOption.*;
import static java.nio.file.StandardOpenOption.CREATE;
import static org.geotoolkit.data.shapefile.ShapefileFeatureStoreFactory.*;
/**
* Encapsulates the idea of a file for writing data to and then later updating the original.
*
* @author jesse
* @module
*/
public final class StorageFile implements Comparable<StorageFile> {
private final ShpFiles shpFiles;
private final Path tempFile;
private final ShpFileType type;
@Deprecated
StorageFile(final ShpFiles shpFiles, final File tempFile, final ShpFileType type) {
this(shpFiles, tempFile.toPath(), type);
}
StorageFile(final ShpFiles shpFiles, final Path tempFile, final ShpFileType type) {
this.shpFiles = shpFiles;
this.tempFile = tempFile;
this.type = type;
}
/**
* Returns the storage file
*
* @return the storage file
*/
public Path getFile() {
return tempFile;
}
public FileChannel getWriteChannel() throws IOException {
return FileChannel.open(tempFile, READ, CREATE, WRITE);
}
/**
* Replaces the file that the temporary file is acting as a transactional type cache for. Acts
* similar to a commit.
*
* @see #replaceOriginals(StorageFile...)
* @throws IOException
*/
void replaceOriginal() throws IOException {
replaceOriginals(this);
}
/**
* Takes a collection of StorageFiles and performs the replace functionality described in
* {@link #replaceOriginal()}. However, all files that are part of the same {@link ShpFiles}
* are done within a lock so all of the updates for all the Files of a Shapefile can be updated
* within a single lock.
*
* @param storageFiles files to execute the replace functionality.
* @throws IOException
*/
static void replaceOriginals( final StorageFile... storageFiles ) throws IOException {
SortedSet<StorageFile> files = new TreeSet<>(Arrays.asList(storageFiles));
ShpFiles currentShpFiles = null;
for( StorageFile storageFile : files ) {
if (currentShpFiles != storageFile.shpFiles) {
// there's a new set of files so unlock old and lock new.
currentShpFiles = storageFile.shpFiles;
}
final Path storage = storageFile.getFile();
final Path dest = storageFile.shpFiles.getPath(storageFile.type);
try {
if (storage.equals(dest))
return;
if (Files.exists(storage)) {
try {
Files.move(storage, dest, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException | UnsupportedOperationException e) {
LOGGER.log(Level.FINER, "Unable to replace temporary file to the file: " + dest +
" when attempting to replace with temporary copy", e);
IOUtilities.copy(storage, dest, StandardCopyOption.REPLACE_EXISTING);
}
}
} finally {
Files.deleteIfExists(storage);
}
}
}
/**
* Just groups together files that have the same ShpFiles instance
*/
@Override
public int compareTo( final StorageFile o ) {
// group togheter files that have the same shpefile instance
if (this == o) {
return 0;
}
// assume two StorageFile that do not share the same ShpFiles
// are not given the same temp file
return getFile().compareTo(o.getFile());
}
@Override
public String toString() {
return getClass().getSimpleName() + ": " + tempFile.getFileName().toString();
}
}