1 /*
  2  *  Copyright (C) 2008-2009 WaveMaker Software, Inc.
  3  *
  4  *  This file is part of the WaveMaker Client Runtime.
  5  *
  6  *  Licensed under the Apache License, Version 2.0 (the "License");
  7  *  you may not use this file except in compliance with the License.
  8  *  You may obtain a copy of the License at
  9  *
 10  *      http://www.apache.org/licenses/LICENSE-2.0
 11  *
 12  *  Unless required by applicable law or agreed to in writing, software
 13  *  distributed under the License is distributed on an "AS IS" BASIS,
 14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  *  See the License for the specific language governing permissions and
 16  *  limitations under the License.
 17  */
 18 dojo.provide("wm.base.components.Service");
 19 dojo.require("wm.base.Component");
 20 
 21 /**
 22 	Component that can be configured to perform a task.
 23 	<br/><br/>
 24 	@name wm.Service
 25 	@class
 26 	@extends wm.Component
 27 */
 28 dojo.declare("wm.Service", wm.Component, {
 29 	/** @lends wm.Service.prototype */
 30 	_operations: {},
 31 	/**
 32 		Result data (if any) returned from the last invocation.
 33 	*/
 34 	result: null,
 35 	/**
 36 		Error data (if any) returned from the last invocation.
 37 	*/
 38 	error: null,
 39 	getOperationsList: function() {
 40 		var l = [];
 41 		for (var i in this._operations)
 42 			l.push(i);
 43 		l.sort();
 44 		return l;
 45 	},
 46 	getOperation: function(inOperation) {
 47 		return this._operations[inOperation];
 48 	},
 49 	initService: function() {
 50 	},
 51 	/**
 52 		Invoke a method on this service object with arguments.
 53 		<br/><br/>
 54 		Invocations may be asynchronous. Responses are available 
 55 		via the returned Deferred object or from the 
 56 		<a href="#onResult">onResult</a> and 
 57 		<a href="#onError">onError</a> events.
 58 		@param {String} inMethod The method to invoke on this object.
 59 		@param {Array} inArgs An array of parameters for the method.
 60 		@returns {dojo.Deferred} Response handler object.
 61 	*/
 62 	invoke: function(inMethod, inArgs) {
 63 		var
 64 			d = new dojo.Deferred(),
 65 			m = this[inMethod];
 66 		if (m) {
 67 			var result = m.apply(this, inArgs);
 68 			this.onResult();
 69 			wm.onidle(function() {
 70 				d.callback(result);
 71 			});
 72 		} else {
 73 			this.onError();
 74 			wm.onidle(function() {
 75 				d.errback("operation: " + inMethod + " does not exist.");
 76 			});
 77 		}
 78 		return d;
 79 	},
 80 	/**
 81 		Event that fires after a succesful service invocation.
 82 		@param {Any} inResult Any result data returned from the service.
 83 	*/
 84 	onResult: function(inResult) {
 85 		this.error = null;
 86 		return this.result = inResult;
 87 	},
 88 	/**
 89 		Event that fires after a service invocation has resulted in an error.
 90 		@param {Any} inError Any error data returned from the service.
 91 	*/
 92 	onError: function(inError) {
 93 		this.result = null;
 94 		return this.error = inError;
 95 	}
 96 });
 97 
 98 // FIXME: needs its own module
 99 // ==========================================================
100 // Services registry (provides info about available services)
101 // ==========================================================
102 
103 wm.services = {
104 	byName: {},
105 	_services: {},
106 	add: function(inService){
107 		return wm.services.byName[inService.name] = inService;
108 	},
109 	remove: function(inService){
110 		var n = inService.name;
111 		this._destroyService(n);
112 		delete wm.services.byName[n];
113 	},
114 	getNamesList: function() {
115 		var l = [], services = wm.services.byName, s;
116 		for (var i in services) {
117 			s = services[i];
118 			if (!s.clientHide) 
119 				l.push(i);
120 		}
121 		l.sort();
122 		return l;
123 	},
124 	forEach: function(inFunction) {
125 		wm.forEach(this.byName, function(s) {
126 			inFunction(s);
127 		});
128 	},
129 	clear: function() {
130 		var n = wm.services.byName, s;
131 		for (var i in n) {
132 			s = n[i];
133 			if (!s.isClientService)
134 				this.remove(s);
135 			else
136 				this._destroyService(s);
137 		}
138 	},
139 	getService: function(inName) {
140 		var s;
141 		if (inName) {
142 			s = this._services[inName] || this._createService(inName);
143 			if (!s._service)
144 				s.initService();
145 		}
146 		return s;
147 	},
148 	_createService: function(inName) {
149 		var
150 			defaultCtor = "wm.JsonRpcService",
151 			s = this.byName[inName];
152 		if (!s)
153 			s = this.add({name: inName, ctor: defaultCtor});
154 		var ctor = dojo.getObject(s.ctor || defaultCtor);
155 		// FIXME: we don't want to be streamed so don't include owner
156 		// otoh without owner, we don't know how to resolve paths at designTime
157 		var service = new ctor({name: inName, service: inName});
158 		service.owner = dojo.getObject("studio.wip.app") || app;
159 		return service;
160 	},
161 	_destroyService: function(inService) {
162 		wm.fire(this._services[inService.name], "destroy");
163 	}
164 };
165