Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
added sync/4
  • Loading branch information
sten1ee committed Nov 5, 2019
commit 5bba21a5541403adbc58fb318f04f9dbc71fcdba
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ public class FileModule extends AbstractInternalModule
new FunctionDef( FileMove.signatures[0], FileMove.class ),
new FunctionDef( DirectoryCreate.signatures[0], DirectoryCreate.class ),
new FunctionDef( DirectoryCreate.signatures[1], DirectoryCreate.class ),
new FunctionDef( Sync.signature, Sync.class)
new FunctionDef( Sync.signature3, Sync.class),
new FunctionDef( Sync.signature4, Sync.class),
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.value.DateTimeValue;
import org.exist.xquery.value.BooleanValue;
import org.exist.xquery.value.FunctionParameterSequenceType;
import org.exist.xquery.value.FunctionReturnSequenceType;
import org.exist.xquery.value.Sequence;
Expand All @@ -54,36 +53,58 @@

public class Sync extends BasicFunction {

public final static FunctionSignature signature =
new FunctionSignature(
public final static FunctionSignature signature3 =
new FunctionSignature(
new QName("sync", FileModule.NAMESPACE_URI, FileModule.PREFIX),
"Synchronize a collection with a directory hierarchy. Compares last modified time stamps. " +
"If $dateTime is given, only resources modified after this time stamp are taken into account. " +
"This method is only available to the DBA role.",
"Synchronize a collection with a directory hierarchy. Compares last modified time stamps. " +
"If $dateTime is given, only resources modified after this time stamp are taken into account. " +
"Note: there's a sync/4 method that will also prune target directory. " +
"This method is only available to the DBA role.",
new SequenceType[]{
new FunctionParameterSequenceType("collection", Type.STRING,
new FunctionParameterSequenceType("collection", Type.STRING,
Cardinality.EXACTLY_ONE, "The collection to sync."),
new FunctionParameterSequenceType("targetPath", Type.ITEM,
Cardinality.EXACTLY_ONE, "The full path or URI to the directory"),
new FunctionParameterSequenceType("dateTime", Type.DATE_TIME,
Cardinality.ZERO_OR_ONE,
"Optional: only resources modified after the given date/time will be synchronized."),
new FunctionParameterSequenceType("prune", Type.BOOLEAN,
},
new FunctionReturnSequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE, "true if successful, false otherwise")
);


public final static FunctionSignature signature4 =
new FunctionSignature(
new QName("sync", FileModule.NAMESPACE_URI, FileModule.PREFIX),
"Synchronize a collection with a directory hierarchy. Compares last modified time stamps. " +
"If $dateTime is given, only resources modified after this time stamp are taken into account. " +
"If $mode is 'prune', delete any file/dir that does not correspond to a doc/collection in the DB. " +
"This method is only available to the DBA role.",
new SequenceType[]{
new FunctionParameterSequenceType("collection", Type.STRING,
Cardinality.EXACTLY_ONE, "The collection to sync."),
new FunctionParameterSequenceType("targetPath", Type.ITEM,
Cardinality.EXACTLY_ONE, "The full path or URI to the directory"),
new FunctionParameterSequenceType("dateTime", Type.DATE_TIME,
Cardinality.ZERO_OR_ONE,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Cardinality for this should be EXACTLY_ONE. It doesn't really make sense for this to be optional as it is a boolean value.

Copy link
Contributor Author

@sten1ee sten1ee Nov 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made it "optional" with the single purpose that the API remains backward compatible.
Old style invocations of file:sync(...) will still work.
If the prune param is made non-optional, then:

  1. Old-style invocations of that function will be rendered broken (i.e. will have to be revised)
  2. The previous (3rd) param of the function will also need to become non-optional, because (to the best of my understanding) you can't have optional param, followed by non-optional, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not backwards compatible. There is no polymorphism in XQuery. You have to keep the original function signature, and then define additional function signatures with additional arities.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, wait, wait.
Then (in order not to break existing code) this extended 'prune' functionality has to come together with a new function, e.g. file:sync_ex(...) or file:sync_prune(...) or something.
Is it not so?

Copy link
Contributor

@adamretter adamretter Nov 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need a new named function as they are on different arities. But you have to design two signatures, the original signature, and the new signature which has an additional argument. The new signature should then be added to the FileModule.java

"Optional: delete any file/dir that does not correspond to a doc/collection currently in the DB.")
"Optional: only resources modified after the given date/time will be synchronized."),
new FunctionParameterSequenceType("mode", Type.STRING,
Cardinality.EXACTLY_ONE,
"Delete any file/dir that does not correspond to a doc/collection in the DB.")
},
new FunctionReturnSequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE, "true if successful, false otherwise")
);



private final static Properties DEFAULT_PROPERTIES = new Properties();
static {
DEFAULT_PROPERTIES.put(OutputKeys.INDENT, "yes");
DEFAULT_PROPERTIES.put(OutputKeys.OMIT_XML_DECLARATION, "no");
DEFAULT_PROPERTIES.put(EXistOutputKeys.EXPAND_XINCLUDES, "no");
DEFAULT_PROPERTIES.put(EXistOutputKeys.EXPAND_XINCLUDES, "no");
}
public Sync(final XQueryContext context) {
super(context, signature);

public Sync(final XQueryContext context, final FunctionSignature sig) {
super(context, sig);
}

@Override
Expand All @@ -104,11 +125,12 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro
startDate = dtv.getDate();
}

boolean prune = false;
if (args[3].hasOne()) {
final BooleanValue bv = (BooleanValue) args[3].itemAt(0);
prune = bv.getValue();
final String mode = args.length > 3 ? args[3].getStringValue() : "no_prune";
if (!mode.equals("prune") && !mode.equals("no_prune")) {
throw new XPathException("Argument $mode in call to function file:sync is '" + mode + "' " +
" (must be 'prune' or 'no_prune')");
}
final boolean prune = mode.equals("prune");

context.pushDocumentContext();
final MemTreeBuilder output = context.getDocumentBuilder();
Expand Down Expand Up @@ -160,8 +182,8 @@ private void saveCollection(final XmldbURI collectionPath, Path targetDir, final
}
for (final Iterator<DocumentImpl> i = collection.iterator(context.getBroker()); i.hasNext(); ) {
final DocumentImpl doc = i.next();
try (final ManagedLock lock = context.getBroker().getBrokerPool()
.getLockManager().acquireDocumentReadLock(doc.getURI())) {
try (final ManagedLock lock = context.getBroker().getBrokerPool().getLockManager()
.acquireDocumentReadLock(doc.getURI())) {
if (startDate == null || doc.getMetadata().getLastModified() > startDate.getTime()) {
if (doc.getResourceType() == DocumentImpl.BINARY_FILE) {
saveBinary(targetDir, (BinaryDocument) doc, output);
Expand Down