ProjectAres/PGM/src/main/java/tc/oc/pgm/rotation/FileRotationProvider.java

152 lines
5.2 KiB
Java
Raw Normal View History

2017-01-30 01:43:34 +01:00
package tc.oc.pgm.rotation;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.time.Instant;
import tc.oc.commons.core.logging.ClassLogger;
import tc.oc.commons.core.util.Joiners;
import tc.oc.pgm.PGM;
import tc.oc.pgm.map.MapLibrary;
import tc.oc.pgm.map.PGMMap;
public class FileRotationProvider extends AbstractRotationProvider {
public static final String FILE_NEXTID_SUFFIX = ".next";
public static final int DEFAULT_NEXTID = 0;
private final Logger logger;
private final Logger mapLogger;
private final MapLibrary mapLibrary;
private final String name;
private final Path rotationFile;
private final Path dataPath;
public FileRotationProvider(MapLibrary mapLibrary, String name, Path rotationFile, Path dataPath) {
Preconditions.checkNotNull(mapLibrary, "map manager");
Preconditions.checkNotNull(rotationFile, "rotation path");
Preconditions.checkNotNull(dataPath, "data path");
Preconditions.checkArgument(Files.isRegularFile(rotationFile), "rotation path must be a file");
Preconditions.checkArgument(Files.isDirectory(dataPath), "data path must be a directory");
this.logger = ClassLogger.get(PGM.get().getLogger(), getClass());
this.mapLogger = PGM.get().getRootMapLogger();
this.mapLibrary = mapLibrary;
this.name = name;
this.rotationFile = rotationFile;
this.dataPath = dataPath;
}
Path nextIdFile() {
return dataPath.resolve(name + FILE_NEXTID_SUFFIX);
}
@Override
public @Nonnull Future<?> loadRotations() {
return getExecutorService().submit((Runnable) () -> {
try {
setRotation(name, loadRotationFromDisk(), Instant.now());
} catch(IOException e) {
mapLogger.log(Level.SEVERE, "Failed to load file rotation", e);
}
});
}
private RotationState loadRotationFromDisk() throws IOException {
int nextId = this.parseNextId();
List<PGMMap> maps = this.parseRotationNames();
if(maps.isEmpty()) {
throw new IOException(String.format("Rotation '%s' was empty!", name));
}
if(!RotationState.isNextIdValid(maps, nextId)) {
nextId = 0;
}
logger.info("Loaded rotation '" + name + "' with " + maps.size() + " maps: " + Joiners.onCommaSpace.join(maps));
return new RotationState(maps, nextId);
}
private int parseNextId() {
List<String> lines;
try {
lines = Files.readAllLines(nextIdFile(), Charsets.UTF_8);
} catch (IOException e) {
this.logger.warning("Failed to read next id from " + nextIdFile().toString());
return DEFAULT_NEXTID;
}
for(String line : lines) {
try {
return Integer.parseInt(line);
} catch (NumberFormatException e) {
continue;
}
}
this.logger.warning("Failed to parse next id from " + nextIdFile().toString());
return DEFAULT_NEXTID;
}
private List<PGMMap> parseRotationNames() throws IOException {
List<String> lines = Files.readAllLines(rotationFile, Charsets.UTF_8);
ImmutableList.Builder<PGMMap> maps = ImmutableList.builder();
for(String line : lines) {
line = line.trim();
if(line.isEmpty()) {
continue;
}
Optional<PGMMap> map = this.mapLibrary.getMapByNameOrId(line);
if(map.isPresent()) {
maps.add(map.get());
} else {
mapLogger.severe("Unknown map '" + line + "' when parsing " + rotationFile.toString());
}
}
return maps.build();
}
@Override
public Future<?> saveRotation(@Nonnull final String name, @Nonnull final RotationState rotation) {
this.setRotation(name, rotation);
return getExecutorService().submit(new Runnable() {
@Override public void run() {
FileRotationProvider.this.saveRotationToDisk(name, rotation);
}
});
}
private void saveRotationToDisk(@Nonnull String name, @Nonnull RotationState rotation) {
List<String> nextIdSerialized = ImmutableList.of(Integer.toString(rotation.getNextId()));
try {
Files.write(nextIdFile(), nextIdSerialized, Charsets.UTF_8);
} catch (IOException e) {
this.logger.log(Level.SEVERE, "Failed to save next id for rotation: " + name, e);
}
}
private static @Nonnull ExecutorService getExecutorService() {
if(fileExecutorService == null) {
fileExecutorService = Executors.newSingleThreadExecutor();
}
return fileExecutorService;
}
private static ExecutorService fileExecutorService;
}