Skip to content

Commit

Permalink
Handle detecting changes to include files
Browse files Browse the repository at this point in the history
Signed-off-by: applenick <[email protected]>
  • Loading branch information
applenick committed Jul 17, 2022
1 parent 77bdf6a commit 360ddb5
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 25 deletions.
8 changes: 8 additions & 0 deletions core/src/main/java/tc/oc/pgm/api/map/MapLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Iterator;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Nullable;
import tc.oc.pgm.api.map.includes.MapIncludeProcessor;

/** A library of {@link MapInfo}s and {@link MapContext}s. */
public interface MapLibrary {
Expand Down Expand Up @@ -45,4 +46,11 @@ public interface MapLibrary {
* @return A {@link MapContext}.
*/
CompletableFuture<MapContext> loadExistingMap(String id);

/**
* Get the {@link MapIncludeProcessor}.
*
* @return A {@link MapIncludeProcessor}
*/
MapIncludeProcessor getIncludeProcessor();
}
11 changes: 11 additions & 0 deletions core/src/main/java/tc/oc/pgm/api/map/MapSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.File;
import java.io.InputStream;
import tc.oc.pgm.api.map.exception.MapMissingException;
import tc.oc.pgm.api.map.includes.StoredMapInclude;

/** A source where {@link MapInfo} documents and files are downloaded. */
public interface MapSource {
Expand Down Expand Up @@ -38,4 +39,14 @@ public interface MapSource {
* @throws MapMissingException If the document can no longer be found.
*/
boolean checkForUpdates() throws MapMissingException;

/**
* Adds a {@link StoredMapInclude} which holds information about a {@link MapInclude}
*
* @param include The {@link StoredMapInclude}
*/
void addMapInclude(StoredMapInclude include);

/** Remove all associated {@link StoredMapInclude}, used when reloading document. */
void clearIncludes();
}
7 changes: 7 additions & 0 deletions core/src/main/java/tc/oc/pgm/api/map/includes/MapInclude.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ public interface MapInclude {
*/
String getId();

/**
* Get the system file time from when this MapInclude file was last modified.
*
* @return Time of last file modification
*/
long getLastModified();

/**
* Get a collection of {@link Content} which can be merged into an existing {@link Document}
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
package tc.oc.pgm.api.map.includes;

import java.util.Collection;
import javax.annotation.Nullable;
import org.jdom2.Document;
import tc.oc.pgm.api.Config;
import tc.oc.pgm.util.xml.InvalidXMLException;

/** A processor to determine which {@link MapInclude}s should be included when loading a map * */
public interface MapIncludeProcessor {

/**
* Get a {@link MapInclude} which should be included on all maps or null if none.
*
* @return a {@link MapInclude}
*/
@Nullable
MapInclude getGlobalInclude();

/**
* Process the given {@link Document} and return a collection of {@link MapInclude}s.
*
Expand All @@ -26,6 +17,14 @@ public interface MapIncludeProcessor {
*/
Collection<MapInclude> getMapIncludes(Document document) throws InvalidXMLException;

/**
* Get a {@link MapInclude} by its id
*
* @param includeId ID of the map include
* @return A {@link MapInclude}
*/
MapInclude getMapIncludeById(String includeId);

/**
* Reload the processor to fetch new map includes or reload existing ones.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package tc.oc.pgm.api.map.includes;

/**
* A snapshot of {@link MapInclude} info, used to determine when include files have been updated. *
*/
public interface StoredMapInclude {

/**
* Gets the unique include id, used to reference a {@link MapInclude}.
*
* @return A unique include id
*/
String getIncludeId();

/**
* Gets whether the associated {@link MapInclude} files have changed since last loading.
*
* @param time The current system time
* @return True if given time is newer than last modified time
*/
boolean hasBeenModified(long time);
}
13 changes: 8 additions & 5 deletions core/src/main/java/tc/oc/pgm/map/MapFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import tc.oc.pgm.kits.FeatureKitParser;
import tc.oc.pgm.kits.KitParser;
import tc.oc.pgm.kits.LegacyKitParser;
import tc.oc.pgm.map.includes.StoredMapIncludeImpl;
import tc.oc.pgm.regions.FeatureRegionParser;
import tc.oc.pgm.regions.LegacyRegionParser;
import tc.oc.pgm.regions.RegionParser;
Expand Down Expand Up @@ -76,26 +77,28 @@ protected MapModule createModule(MapModuleFactory factory) throws ModuleLoadExce
}
}

private void storeInclude(MapInclude include) {
this.source.addMapInclude(new StoredMapIncludeImpl(include.getId(), include.getLastModified()));
}

private void preLoad()
throws IOException, JDOMException, InvalidXMLException, MapMissingException {
if (document != null && !source.checkForUpdates()) {
return; // If a document is present and there are no updates, skip loading again
}

source.clearIncludes();

try (final InputStream stream = source.getDocument()) {
document = DOCUMENT_FACTORY.get().build(stream);
document.setBaseURI(source.getId());
}

// Add global include file to the document if present
if (includes.getGlobalInclude() != null) {
document.getRootElement().addContent(0, includes.getGlobalInclude().getContent());
}

// Check for any included map sources, appending them to the document if present
Collection<MapInclude> mapIncludes = includes.getMapIncludes(document);
for (MapInclude include : mapIncludes) {
document.getRootElement().addContent(0, include.getContent());
storeInclude(include);
}

info = new MapInfoImpl(document.getRootElement());
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/tc/oc/pgm/map/MapLibraryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ public long getSize() {
return maps.size();
}

@Override
public MapIncludeProcessor getIncludeProcessor() {
return includes;
}

private void logMapError(MapException err) {
logger.log(Level.WARNING, err.getMessage(), err);
}
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/java/tc/oc/pgm/map/includes/MapIncludeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicLong;
import org.jdom2.Content;
import org.jdom2.Document;
import org.jdom2.JDOMException;
Expand All @@ -16,6 +17,7 @@ public class MapIncludeImpl implements MapInclude {

private final String id;
private final Document source;
private final AtomicLong lastModified;

public MapIncludeImpl(File file) throws MapMissingException, JDOMException, IOException {
try {
Expand All @@ -24,6 +26,8 @@ public MapIncludeImpl(File file) throws MapMissingException, JDOMException, IOEx
this.source = MapIncludeProcessorImpl.DOCUMENT_FACTORY.get().build(fileStream);
} catch (FileNotFoundException e) {
throw new MapMissingException(file.getPath(), "Unable to read map include document", e);
} finally {
lastModified = new AtomicLong(file.lastModified());
}
}

Expand All @@ -42,4 +46,9 @@ public boolean equals(Object other) {
if (other == null || !(other instanceof MapInclude)) return false;
return ((MapInclude) other).getId().equalsIgnoreCase(getId());
}

@Override
public long getLastModified() {
return lastModified.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
Expand Down Expand Up @@ -38,22 +37,27 @@ public MapIncludeProcessorImpl(Logger logger) {
this.includes = Sets.newHashSet();
}

@Nullable
private MapInclude getIncludeById(String id) {
return includes.stream()
.filter(include -> include.getId().equalsIgnoreCase(id))
.findAny()
.orElse(null);
public MapInclude getGlobalInclude() {
return getMapIncludeById("global");
}

@Override
public MapInclude getGlobalInclude() {
return getIncludeById("global");
public MapInclude getMapIncludeById(String includeId) {
return includes.stream()
.filter(include -> include.getId().equalsIgnoreCase(includeId))
.findAny()
.orElse(null);
}

@Override
public Collection<MapInclude> getMapIncludes(Document document) throws InvalidXMLException {
Set<MapInclude> mapIncludes = Sets.newHashSet();

// Always add global include if present
if (getGlobalInclude() != null) {
mapIncludes.add(getGlobalInclude());
}

List<Element> elements = document.getRootElement().getChildren("include");
for (Element element : elements) {

Expand All @@ -69,7 +73,7 @@ public Collection<MapInclude> getMapIncludes(Document document) throws InvalidXM
}

String id = XMLUtils.getRequiredAttribute(element, "id").getValue();
MapInclude include = getIncludeById(id);
MapInclude include = getMapIncludeById(id);
if (include == null)
throw new InvalidXMLException(
"The provided include id '" + id + "' could not be found!", element);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package tc.oc.pgm.map.includes;

import java.util.concurrent.atomic.AtomicLong;
import tc.oc.pgm.api.map.includes.StoredMapInclude;

public class StoredMapIncludeImpl implements StoredMapInclude {

private final String includeId;
private final AtomicLong lastModified;

public StoredMapIncludeImpl(String includeId, long lastModified) {
this.includeId = includeId;
this.lastModified = new AtomicLong(lastModified);
}

@Override
public String getIncludeId() {
return includeId;
}

@Override
public boolean hasBeenModified(long time) {
return time > lastModified.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.collect.Sets;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
Expand All @@ -10,11 +11,16 @@
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;
import org.apache.commons.lang3.builder.ToStringBuilder;
import tc.oc.pgm.api.PGM;
import tc.oc.pgm.api.map.MapSource;
import tc.oc.pgm.api.map.exception.MapMissingException;
import tc.oc.pgm.api.map.includes.MapInclude;
import tc.oc.pgm.api.map.includes.MapIncludeProcessor;
import tc.oc.pgm.api.map.includes.StoredMapInclude;
import tc.oc.pgm.util.FileUtils;

public class SystemMapSourceFactory extends PathMapSourceFactory {
Expand Down Expand Up @@ -44,10 +50,14 @@ protected static class SystemMapSource implements MapSource {

private final String dir;
private final AtomicLong modified;
private final Set<StoredMapInclude> storedIncludes;
private final MapIncludeProcessor includes;

private SystemMapSource(String dir) {
this.dir = checkNotNull(dir);
this.modified = new AtomicLong(-1);
this.storedIncludes = Sets.newHashSet();
this.includes = PGM.get().getMapLibrary().getIncludeProcessor();
}

private File getDirectory() throws MapMissingException {
Expand Down Expand Up @@ -118,7 +128,7 @@ public boolean checkForUpdates() throws MapMissingException {
final File file = getFile();

final long mod = modified.get();
return mod > 0 && file.lastModified() > mod;
return (mod > 0 && file.lastModified() > mod) || checkForIncludeUpdates();
}

@Override
Expand All @@ -139,5 +149,25 @@ public String toString() {
.append("modified", modified.get())
.build();
}

@Override
public void addMapInclude(StoredMapInclude include) {
this.storedIncludes.add(include);
}

@Override
public void clearIncludes() {
this.storedIncludes.clear();
}

private boolean checkForIncludeUpdates() {
for (StoredMapInclude stored : storedIncludes) {
MapInclude include = includes.getMapIncludeById(stored.getIncludeId());
if (stored.hasBeenModified(include.getLastModified())) {
return true;
}
}
return false;
}
}
}

0 comments on commit 360ddb5

Please sign in to comment.