ramblings/oxygen/js-options/options.js

269 lines
7.3 KiB
JavaScript

/*
*
* Shortcuts
*
*/
const out = Packages.java.lang.System.out;
/*
* Main features
*
*/
Options = function (authorAccess, namespace, lifetime, dontUpdateNsExpiration) {
this.namespace = namespace;
this.authorAccess = authorAccess;
this.optionsStorage = this.authorAccess.getOptionsStorage();
this.lifetime = lifetime;
this.expiration = Options.getExpiration(lifetime);
// Create an Options object in the SYSTEM namespace for internal use
if (this.namespace != Options.SYSTEM) {
this.systemOptions = new Options(authorAccess, Options.SYSTEM, null, true);
}
// Update NS expiration unless told otherwise (used for cleanup)
if (dontUpdateNsExpiration != true) {
this.__cleanup__();
this.systemOptions.setValueInOption(Options.NAMESPACES, this.namespace, this.expiration);
}
}
Options.SYSTEM = '__system__';
Options.NAMESPACES = '__namespaces__';
Options.HOUSEKEEPING = '__housekeeping__';
Options.HOUSEKEEPING_PERIOD = 1;
/*
* Static method to convert a lifetime into an expiration date
*
*/
Options.getExpiration = function (lifetime) {
if (lifetime == undefined) {
return null;
} else {
var d = new Date();
d.setDate(d.getDate() + lifetime);
return d.toISOString();
}
}
/*
* Setter, getter and friends
*
*/
Options.prototype.getOption = function (key, defaultValue) {
this.optionsStorage.setOptionsDoctypePrefix(this.namespace);
return this.optionsStorage.getOption(key, defaultValue);
}
Options.prototype.getOptionObject = function (key) {
return JSON.parse(this.getOption(key, '{}'));
}
Options.prototype.setValueInOption = function (key, objectKey, value) {
var object = this.getOptionObject(key);
if (value == null) {
delete object[objectKey];
} else {
object[objectKey] = value;
}
if (Object.keys(object).length == 0) {
object = null;
}
this.setOptionObject(key, object);
return object;
}
Options.prototype.setOption = function (key, value) {
if (this.namespace != Options.SYSTEM) {
this.systemOptions.setValueInOption(this.namespace, key, value == null ? null: this.expiration)
}
this.optionsStorage.setOptionsDoctypePrefix(this.namespace);
this.optionsStorage.setOption(key, value);
}
Options.prototype.setOptionObject = function (key, value) {
this.setOption(key, value == null ? null: JSON.stringify(value));
}
Options.prototype.deleteOption = function (key) {
this.setOption(key, null);
}
Options.prototype.getOptionKeys = function () {
this.optionsStorage.setOptionsDoctypePrefix(Options.SYSTEM);
return JSON.parse(this.optionsStorage.getOption(this.namespace, '{}'));
}
Options.prototype.getOptions = function () {
var results = {
};
var options = this.getOptionKeys();
for (var key in options) {
results[key] = this.getOption(key, '');
}
return results;
}
/*
* Per file extensions
*
* Setting a systemID creates a new namespace that concatenates the current namespace
* and the SHA1 of the document ID.
*
* Access to the options of this namespace is done through specific methods.
*
* The reverse mapping (SHA1 to system ID) is stored using the __systemIds__ namespace.
*
*/
Options.SYSTEMIDS = '__systemIds__';
/*
* Set the system Id (current file by default, current lifetime by default)
*
*/
Options.prototype.setSystemId = function (systemID, lifetime) {
if (systemID == undefined) {
this.systemId = String(this.authorAccess.getDocumentController().getAuthorDocumentNode().getSystemID());
} else {
this.systemId = String(systemID);
}
if (lifetime == undefined) {
this.systemIdLifetime = this.lifetime;
} else {
this.systemIdLifetime = lifetime;
}
var md = java.security.MessageDigest.getInstance("SHA-1");
var digestBytes = md.digest(java.lang.String(this.systemId).getBytes(java.nio.charset.Charset.forName("UTF-8")));
this.systemIdDigest = javax.xml.bind.DatatypeConverter.printHexBinary(digestBytes);
// Uncomment to store inverse matching
// var systemIds = JSON.parse(this.systemOptions.getOption(Options.SYSTEMIDS, '{}'));
// systemIds[ this.systemIdDigest] = {
// date: (new Date()).toISOString(),
// systemId: this.systemId
// }
// this.systemOptions.setOption(Options.SYSTEMIDS, JSON.stringify(systemIds));
this.systemIdOptions = new Options(this.authorAccess, this.namespace + '.' + this.systemIdDigest, this.systemIdLifetime);
}
/*
* Setter, getter and friends
*
*/
Options.prototype.getSystemIdOption = function (key, defaultValue) {
if (this.systemIdOptions == undefined) {
this.setSystemId();
}
return this.systemIdOptions.getOption(key, defaultValue);
}
Options.prototype.getSystemIdOptionObject = function (key) {
if (this.systemIdOptions == undefined) {
this.setSystemId();
}
return this.systemIdOptions.getOptionObject(key);
}
Options.prototype.setSystemIdValueInOption = function (key, objectKey, value) {
if (this.systemIdOptions == undefined) {
this.setSystemId();
}
return this.systemIdOptions.setValueInOption(key, objectKey, value);
}
Options.prototype.setSystemIdOption = function (key, value) {
if (this.systemIdOptions == undefined) {
this.setSystemId();
}
this.systemIdOptions.setOption(key, value);
}
Options.prototype.setSystemIdOptionObject = function (key, value) {
if (this.systemIdOptions == undefined) {
this.setSystemId();
}
this.systemIdOptions.setOptionObject(key, value);
}
Options.prototype.deleteSystemIdOption = function (key) {
if (this.systemIdOptions == undefined) {
this.setSystemId();
}
this.systemIdOptions.deleteOption(key);
}
Options.prototype.getSystemIdOptions = function () {
if (this.systemIdOptions == undefined) {
this.setSystemId();
}
return this.systemIdOptions.getOptions();
}
Options.prototype.getSystemOptionKeys = function () {
if (this.systemIdOptions == undefined) {
this.setSystemId();
}
return this.systemIdOptions.getSystemOptionKeys();
}
Options.prototype.getSystemOptions = function () {
if (this.systemIdOptions == undefined) {
this.setSystemId();
}
return this.systemIdOptions.getSystemOptions();
}
/*
*
* Housekeeping
*
*/
/*
*
* General cleanup
*
*/
Options.prototype.__cleanup__ = function () {
var nextCleanup = this.systemOptions.getOption(Options.HOUSEKEEPING, null);
if (nextCleanup == null) {
this.systemOptions.setOption(Options.HOUSEKEEPING, Options.getExpiration(Options.HOUSEKEEPING_PERIOD));
} else {
this.currentDate = Options.getExpiration(0);
if (nextCleanup <= this.currentDate) {
var namespaces = JSON.parse(this.systemOptions.getOption(Options.NAMESPACES, '{}'));
for (var name in namespaces) {
if (! this.__cleanupNamespace__(name, namespaces[name])) {
delete namespaces[name];
};
}
this.systemOptions.setOption(Options.NAMESPACES, JSON.stringify(namespaces));
this.systemOptions.setOption(Options.HOUSEKEEPING, Options.getExpiration(Options.HOUSEKEEPING_PERIOD));
}
}
}
/*
*
* Cleanup a namespace, return true if there are still keys in the namespace
*
*/
Options.prototype.__cleanupNamespace__ = function (name, namespaceExpiration, currentDate) {
var namespaceExpired = namespaceExpiration != null && namespaceExpiration <= this.currentDate;
var options = new Options(this.authorAccess, name, undefined, true);
var nsOptions = options.getOptionKeys();
for (var key in nsOptions) {
var keyExpiration = nsOptions[key];
if (namespaceExpired || (keyExpiration != null && keyExpiration <= this.currentDate)) {
options.deleteOption(key);
}
}
nsOptions = options.getOptionKeys();
return Object.keys(nsOptions).length > 0;
}