/* * * 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; }