      1 // The Antville Project
      2 // http://code.google.com/p/antville
      3 //
      4 // Copyright 2007-2011 by Tobi Schäfer.
      5 //
      6 // Copyright 2001–2007 Robert Gaggl, Hannes Wallnöfer, Tobi Schäfer,
      7 // Matthias & Michael Platzer, Christoph Lincke.
      8 //
      9 // Licensed under the Apache License, Version 2.0 (the ``License'');
     10 // you may not use this file except in compliance with the License.
     11 // You may obtain a copy of the License at
     12 //
     13 //    http://www.apache.org/licenses/LICENSE-2.0
     14 //
     15 // Unless required by applicable law or agreed to in writing, software
     16 // distributed under the License is distributed on an ``AS IS'' BASIS,
     17 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     18 // See the License for the specific language governing permissions and
     19 // limitations under the License.
     20 //
     21 // $Revision$
     22 // $LastChangedBy$
     23 // $LastChangedDate$
     24 // $URL$
     25
     26 /**
     27  * @fileoverview Defines the Metadata prototype (version 2).
     28  */
     29
     30 /**
     31  * Get an object representing the type properties settings suitable for
     32  * defining prototypes with the definePrototype() method.
     33  * @returns {Object} The type properties settings as object.
     34  * @see <a href="http://helma.org/wiki/Defining+HopObject+mappings+programmatically">Helma documentation</a>
     35  */
     36 Metadata.getTypeProperties = function() {
     37    return {
     38       collection: "Metadata",
     39       "local.1": "$id",
     40       "foreign.1": "parent_id",
     41       "local.2": "$prototype",
     42       "foreign.2": "parent_type",
     43       accessName: "name"
     44    }
     45 }
     46
     47 /**
     48  * Prepare a value for writing it to the metadata database table.
     49  * The type of each metadata is stored along with its value.
     50  * The normalize() method determines the type and possibly modifies
     51  * the value accordingly.
     52  * @param {Object} value
     53  * @returns {Array} Compound value consisting of two elements,
     54  * the (normalized) metadata value and its type.
     55  */
     56 Metadata.normalize = function(value) {
     57    if (value === null || value === undefined) {
     58       return [null, null];
     59    }
     60
     61    if (!value.constructor) {
     62       value = String(value);
     63    }
     64
     65    var Constructor = value.constructor;
     66    switch (Constructor) {
     67       case Boolean:
     68       case String:
     69       case Number:
     70       value = String(value);
     71       break;
     72
     73       case Date:
     74       value = Number(value);
     75       break;
     76
     77       default:
     78       value = value.toSource();
     79    }
     80    return [value, Constructor.name];
     81 }
     82
     83 /**
     84  * @name Metadata
     85  * @constructor
     86  * @description The Metadata prototype provides means to store one metadata key-value
     87  * pair per record in the metadata database table. Each record is assigned to a
     88  * parent HopObject which is fitted with convenient methods to easily retrieve
     89  * and modify the attached metadata objects.
     90  * @see HopObject#handleMetadata
     91  * @property {HopObject} parent The HopObject the metadata belongs to.
     92  * @property {String} name The name (key) of the metadata object.
     93  * @property {Object} value The value of the metadata object.
     94  * @property {String} type The type of the metadata object.
     95  */
     96 Metadata.prototype.constructor = function(parent, name, value) {
     97    if (parent && name && value) {
     98       this.parent = parent;
     99       this.name = name;
    100       this.setValue(value);
    101    }
    102    return this;
    103 }
    104
    105 /**
    106  * Set the value of a metadata object. If the value equals null
    107  * the metadata object will be removed.
    108  * @param {Object} value The desired metadata value.
    109  */
    110 Metadata.prototype.setValue = function(value) {
    111    [this.value, this.type] = Metadata.normalize(value);
    112    if (this.value === null) {
    113       this.remove();
    114    }
    115    return;
    116 }
    117
    118 /**
    119  * Get the value of a metadata object.
    120  * @returns {Object} The value of the metadata object.
    121  */
    122 Metadata.prototype.getValue = function() {
    123    var Constructor = global[this.type];
    124    switch (Constructor) {
    125       case null:
    126       case undefined:
    127       return null;
    128
    129       case Boolean:
    130       return eval(this.value).valueOf();
    131
    132       case Date:
    133       return new Date(Number(this.value));
    134
    135       case Number:
    136       case String:
    137       return (new Constructor(this.value)).valueOf();
    138
    139       default:
    140       return eval(this.value);
    141    }
    142 }
    143
    144 /**
    145  * Get a textual representation of the metadata object.
    146  * @returns {String} A textual representation of the metadata object.
    147  */
    148 Metadata.prototype.toString = function() {
    149    return "Metadata of " + this.parent + " (" + this.name + " = " + this.value + ")";
    150 }
    151
    152 /**
    153  * Handle macros which are not defined elsewhere.
    154  * @param {String} name The name of the macro.
    155  * @returns {Object} The resulting value.
    156  */
    157 // FIXME: Is this obsolete?
    158 Metadata.prototype.onUnhandledMacro = function(name) {
    159    return this.get(name);
    160 }
    161