Show:

File: a20_config.js

/**
@module breeze
**/

var __config = (function () {

  // alias for within fns with a config param
  var __config = {};

  __config.functionRegistry = {};
  __config.typeRegistry = {};
  __config.objectRegistry = {};
  __config.interfaceInitialized = new Event("interfaceInitialized", __config);

  var InterfaceDef = function (name) {
    this.name = name;
    this.defaultInstance = null;
    this._implMap = {};
  };

  InterfaceDef.prototype.registerCtor = function (adapterName, ctor) {
    this._implMap[adapterName.toLowerCase()] = { ctor: ctor, defaultInstance: null };
  };
  InterfaceDef.prototype.getImpl = function (adapterName) {
    return this._implMap[adapterName.toLowerCase()];
  };
  InterfaceDef.prototype.getFirstImpl = function () {
    var kv = __objectFirst(this._implMap, function () {
      return true;
    });
    return kv ? kv.value : null;
  };

  __config.interfaceRegistry = {
    ajax: new InterfaceDef("ajax"),
    modelLibrary: new InterfaceDef("modelLibrary"),
    dataService: new InterfaceDef("dataService"),
    uriBuilder: new InterfaceDef("uriBuilder")
  };

  __config.interfaceRegistry.modelLibrary.getDefaultInstance = function () {
    if (!this.defaultInstance) {
      throw new Error("Unable to locate the default implementation of the '" + this.name +
          "' interface.  Possible options are 'ko', 'backingStore' or 'backbone'. See the breeze.config.initializeAdapterInstances method.");
    }
    return this.defaultInstance;
  };

  /**
  A singleton object that is the repository of all configuration options.
  @example
      config.initializeAdapterInstance( {
          modelLibrary: "ko",
          dataService: "webApi"
      });

  @class config
  **/

  /**
  This method is now OBSOLETE.  Use the "initializeAdapterInstances" to accomplish the same result.
  @method setProperties
  @deprecated
  @param config {Object}
  @param [config.remoteAccessImplementation] { implementation of remoteAccess-interface }
  @param [config.trackingImplementation] { implementation of entityTracking-interface }
  @param [config.ajaxImplementation] {implementation of ajax-interface }
  **/
  __config.setProperties = function (config) {
    assertConfig(config)
        .whereParam("remoteAccessImplementation").isOptional()
        .whereParam("trackingImplementation").isOptional()
        .whereParam("ajaxImplementation").isOptional()
        .applyAll(config);
    if (config.remoteAccessImplementation) {
      __config.initializeAdapterInstance("dataService", config.remoteAccessImplementation);
    }
    if (config.trackingImplementation) {
      // note the name change
      __config.initializeAdapterInstance("modelLibrary", config.trackingImplementation);
    }
    if (config.ajaxImplementation) {
      __config.initializeAdapterInstance("ajax", config.ajaxImplementation);
    }
  };

  /**
  Method use to register implementations of standard breeze interfaces.  Calls to this method are usually
  made as the last step within an adapter implementation.
  @method registerAdapter
  @param interfaceName {String} - one of the following interface names "ajax", "dataService" or "modelLibrary"
  @param adapterCtor {Function} - an ctor function that returns an instance of the specified interface.
  **/
  __config.registerAdapter = function (interfaceName, adapterCtor) {
    assertParam(interfaceName, "interfaceName").isNonEmptyString().check();
    assertParam(adapterCtor, "adapterCtor").isFunction().check();
    // this impl will be thrown away after the name is retrieved.
    var impl = new adapterCtor();
    var implName = impl.name;
    if (!implName) {
      throw new Error("Unable to locate a 'name' property on the constructor passed into the 'registerAdapter' call.");
    }
    var idef = getInterfaceDef(interfaceName);
    idef.registerCtor(implName, adapterCtor);

  };

  /**
  Returns the ctor function used to implement a specific interface with a specific adapter name.
  @method getAdapter
  @param interfaceName {String} One of the following interface names "ajax", "dataService" or "modelLibrary"
  @param [adapterName] {String} The name of any previously registered adapter. If this parameter is omitted then
  this method returns the "default" adapter for this interface. If there is no default adapter, then a null is returned.
  @return {Function|null} Returns either a ctor function or null.
  **/
  __config.getAdapter = function (interfaceName, adapterName) {
    var idef = getInterfaceDef(interfaceName);
    if (adapterName) {
      var impl = idef.getImpl(adapterName);
      return impl ? impl.ctor : null;
    } else {
      return idef.defaultInstance ? idef.defaultInstance._$impl.ctor : null;
    }
  };

  /**
  Initializes a collection of adapter implementations and makes each one the default for its corresponding interface.
  @method initializeAdapterInstances
  @param config {Object}
  @param [config.ajax] {String} - the name of a previously registered "ajax" adapter
  @param [config.dataService] {String} - the name of a previously registered "dataService" adapter
  @param [config.modelLibrary] {String} - the name of a previously registered "modelLibrary" adapter
  @param [config.uriBuilder] {String} - the name of a previously registered "uriBuilder" adapter
  @return [array of instances]
  **/
  __config.initializeAdapterInstances = function (config) {
    assertConfig(config)
        .whereParam("dataService").isOptional()
        .whereParam("modelLibrary").isOptional()
        .whereParam("ajax").isOptional()
        .whereParam("uriBuilder").isOptional()
        .applyAll(this, false);
    return __objectMap(config, __config.initializeAdapterInstance);

  };

  /**
  Initializes a single adapter implementation. Initialization means either newing a instance of the
  specified interface and then calling "initialize" on it or simply calling "initialize" on the instance
  if it already exists.
  @method initializeAdapterInstance
  @param interfaceName {String} The name of the interface to which the adapter to initialize belongs.
  @param adapterName {String} - The name of a previously registered adapter to initialize.
  @param [isDefault=true] {Boolean} - Whether to make this the default "adapter" for this interface.
  @return {an instance of the specified adapter}
  **/
  __config.initializeAdapterInstance = function (interfaceName, adapterName, isDefault) {
    isDefault = isDefault === undefined ? true : isDefault;
    assertParam(interfaceName, "interfaceName").isNonEmptyString().check();
    assertParam(adapterName, "adapterName").isNonEmptyString().check();
    assertParam(isDefault, "isDefault").isBoolean().check();

    var idef = getInterfaceDef(interfaceName);
    var impl = idef.getImpl(adapterName);
    if (!impl) {
      throw new Error("Unregistered adapter.  Interface: " + interfaceName + " AdapterName: " + adapterName);
    }

    return initializeAdapterInstanceCore(idef, impl, isDefault);
  };

  /**
  Returns the adapter instance corresponding to the specified interface and adapter names.
  @method getAdapterInstance
  @param interfaceName {String} The name of the interface.
  @param [adapterName] {String} - The name of a previously registered adapter.  If this parameter is
  omitted then the default implementation of the specified interface is returned. If there is
  no defaultInstance of this interface, then the first registered instance of this interface is returned.
  @return {an instance of the specified adapter}
  **/
  __config.getAdapterInstance = function (interfaceName, adapterName) {
    var idef = getInterfaceDef(interfaceName);
    var impl;

    var isDefault = adapterName == null || adapterName == "";
    if (isDefault) {
      if (idef.defaultInstance) return idef.defaultInstance;
      impl = idef.getFirstImpl();
    } else {
      impl = idef.getImpl(adapterName);
    }
    if (!impl) return null;
    if (impl.defaultInstance) {
      return impl.defaultInstance;
    } else {
      return initializeAdapterInstanceCore(idef, impl, isDefault);
    }
  };

  // this is needed for reflection purposes when deserializing an object that needs a fn or ctor
  // used to register validators.
  __config.registerFunction = function (fn, fnName) {
    assertParam(fn, "fn").isFunction().check();
    assertParam(fnName, "fnName").isString().check();
    fn.prototype._$fnName = fnName;
    __config.functionRegistry[fnName] = fn;
  };

  __config.getRegisteredFunction = function (fnName) {
    return __config.functionRegistry[fnName];
  };

  __config._storeObject = function (obj, type, name) {
    // uncomment this if we make this public.
    //assertParam(obj, "obj").isObject().check();
    //assertParam(name, "objName").isString().check();
    var key = (typeof(type) === "string" ? type : type.prototype._$typeName) + "." + name;
    __config.objectRegistry[key] = obj;
  };

  __config._fetchObject = function (type, name) {
    if (!name) return undefined;
    var key = (typeof(type) === "string" ? type : type.prototype._$typeName) + "." + name;
    var result = __config.objectRegistry[key];
    if (!result) {
      throw new Error("Unable to locate a registered object by the name: " + key);
    }
    return result;
  };

  __config.registerType = function (ctor, typeName) {
    assertParam(ctor, "ctor").isFunction().check();
    assertParam(typeName, "typeName").isString().check();
    ctor.prototype._$typeName = typeName;
    __config.typeRegistry[typeName] = ctor;
  };

  __config.stringifyPad = '';

  function initializeAdapterInstanceCore(interfaceDef, impl, isDefault) {
    var instance = impl.defaultInstance;
    if (!instance) {
      instance = new (impl.ctor)();
      impl.defaultInstance = instance;
      instance._$impl = impl;
    }

    instance.initialize();

    if (isDefault) {
      // next line needs to occur before any recomposition
      interfaceDef.defaultInstance = instance;
    }

    // recomposition of other impls will occur here.
    __config.interfaceInitialized.publish({ interfaceName: interfaceDef.name, instance: instance, isDefault: true });

    if (instance.checkForRecomposition) {
      // now register for own dependencies.
      __config.interfaceInitialized.subscribe(function (interfaceInitializedArgs) {
        instance.checkForRecomposition(interfaceInitializedArgs);
      });
    }

    return instance;
  }

  function getInterfaceDef(interfaceName) {
    var lcName = interfaceName.toLowerCase();
    // source may be null
    var kv = __objectFirst(__config.interfaceRegistry || {}, function (k, v) {
      return k.toLowerCase() === lcName;
    });
    if (!kv) {
      throw new Error("Unknown interface name: " + interfaceName);
    }
    return kv.value;
  }

  return __config;
})();

var __modelLibraryDef = __config.interfaceRegistry.modelLibrary;

// legacy
core.config = __config;

breeze.config = __config;