Skip to content

Commit

Permalink
Updating federated filesystem directories timestamp when their child …
Browse files Browse the repository at this point in the history
…resources change
  • Loading branch information
escowles committed Jul 10, 2014
1 parent e12bc00 commit b498f01
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 1 deletion.
Expand Up @@ -21,6 +21,7 @@
import static org.fcrepo.jcr.FedoraJcrTypes.FEDORA_DATASTREAM;
import static org.fcrepo.jcr.FedoraJcrTypes.FEDORA_RESOURCE;
import static org.fcrepo.jcr.FedoraJcrTypes.JCR_CREATED;
import static org.fcrepo.jcr.FedoraJcrTypes.JCR_LASTMODIFIED;
import static org.fcrepo.kernel.utils.ContentDigest.asURI;
import static org.modeshape.jcr.api.JcrConstants.JCR_DATA;
import static org.modeshape.jcr.api.JcrConstants.JCR_PRIMARY_TYPE;
Expand All @@ -39,6 +40,7 @@
import org.modeshape.connector.filesystem.FileSystemConnector;
import org.modeshape.jcr.api.value.DateTime;
import org.modeshape.jcr.api.nodetype.NodeTypeManager;
import org.modeshape.jcr.federation.spi.DocumentChanges;
import org.modeshape.jcr.federation.spi.DocumentReader;
import org.modeshape.jcr.federation.spi.DocumentWriter;
import org.modeshape.jcr.value.BinaryValue;
Expand Down Expand Up @@ -115,6 +117,9 @@ public Document getDocumentById(final String id) {

final DocumentReader docReader = readDocument(doc);
final DocumentWriter docWriter = writeDocument(doc);
final long lastmod = fileFor(id).lastModified();
LOGGER.debug("Adding lastModified={}", lastmod);
docWriter.addProperty(JCR_LASTMODIFIED, lastmod);

final String primaryType = docReader.getPrimaryTypeName();

Expand Down Expand Up @@ -259,4 +264,38 @@ private void saveProperties(final DocumentReader docReader) {
extraProperties.save();
}

/* Override write operations to also update the parent file's timestamp, so
its Last-Modified header correctly reflects changes to children. */
@Override
public boolean removeDocument( final String id ) {
if ( super.removeDocument(id) ) {
touchParent(id);
return true;
}
return false;
}

@Override
public void storeDocument( final Document document ) {
super.storeDocument( document );
touchParent(readDocument(document).getDocumentId());
}

@Override
public void updateDocument( final DocumentChanges changes ) {
super.updateDocument( changes );
touchParent( changes.getDocumentId() );
}

/**
* Find the parent file, and set its timestamp to the current time. This
* timestamp will be used for populating the Last-Modified header.
**/
private void touchParent( final String id ) {
if ( !isRoot(id) ) {
final File file = fileFor(id);
final File parent = file.getParentFile();
parent.setLastModified( System.currentTimeMillis() );
}
}
}
Expand Up @@ -32,6 +32,7 @@
import static org.apache.jena.riot.WebContent.contentTypeNTriples;
import static java.util.regex.Pattern.DOTALL;
import static java.util.regex.Pattern.compile;
import static java.util.TimeZone.getTimeZone;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.CONFLICT;
import static javax.ws.rs.core.Response.Status.CREATED;
Expand Down Expand Up @@ -71,14 +72,17 @@
import static org.junit.Assert.fail;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Iterator;

import javax.ws.rs.core.Variant;
Expand Down Expand Up @@ -1641,4 +1645,43 @@ public void testLinkedDeletion() throws Exception {
assertEquals("Linked to should still exist!", 200, getStatus(get));
}

/**
* When I make changes to a resource in a federated filesystem, the parent
* folder's Last-Modified header should be updated.
**/
@Test
public void testLastModifiedUpdatedAfterUpdates() throws Exception {
final SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
df.setTimeZone(getTimeZone("GMT"));

// create directory containing a file in filesystem
final File fed = new File("target/test-classes/test-objects");
final String id = getRandomUniquePid();
final File dir = new File( fed, id );
final File child = new File( dir, "child" );
final long timestamp1 = System.currentTimeMillis();
dir.mkdir();
child.mkdir();
Thread.sleep(2000);

// check Last-Modified header is current
final HttpHead head1 = new HttpHead(serverAddress + "files/" + id);
final HttpResponse resp1 = client.execute(head1);
assertEquals( 200, resp1.getStatusLine().getStatusCode() );
final long lastmod1 = df.parse(resp1.getFirstHeader("Last-Modified").getValue()).getTime();
assertTrue( (timestamp1 - lastmod1) < 1000 ); // because rounding

// remove the file and wait for the TTL to expire
final long timestamp2 = System.currentTimeMillis();
child.delete();
Thread.sleep(2000);

// check Last-Modified header is updated
final HttpHead head2 = new HttpHead(serverAddress + "files/" + id);
final HttpResponse resp2 = client.execute(head2);
assertEquals( 200, resp2.getStatusLine().getStatusCode() );
final long lastmod2 = df.parse(resp2.getFirstHeader("Last-Modified").getValue()).getTime();
assertTrue( (timestamp2 - lastmod2) < 1000 ); // because rounding
}

}
2 changes: 1 addition & 1 deletion fcrepo-http-api/src/test/resources/test_repository.json
Expand Up @@ -21,7 +21,7 @@
"directoryPath" : "target/test-classes/test-objects",
"readonly" : true,
"extraPropertiesStorage": "json",
"cacheTtlSeconds" : 5,
"cacheTtlSeconds" : 2,
"projections" : [ "default:/files => /" ]
}
},
Expand Down

0 comments on commit b498f01

Please sign in to comment.