]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/framework/Util/TRpcClient.php
baculum: New Baculum API and Baculum Web
[bacula/bacula] / gui / baculum / framework / Util / TRpcClient.php
1 <?php
2
3 /**
4  * @author Robin J. Rogge <rrogge@bigpoint.net>
5  * @link https://github.com/pradosoft/prado
6  * @copyright 2010 Bigpoint GmbH
7  * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
8  * @since 3.2
9  * @package System.Util
10  */
11
12 /**
13  * TRpcClient class
14  *
15  * Note: When using setIsNotification(true), *every* following request is also
16  * considered to be a notification until you use setIsNotification(false).
17  *
18  * Usage:
19  *
20  * First, you can use the factory:
21  * <pre>
22  * $_rpcClient = TRpcClient::create('xml', 'http://host/server');
23  * $_result = $_rpcClient->remoteMethodName($param, $otherParam);
24  * </pre>
25  *
26  * or as oneliner:
27  * <pre>
28  * $_result = TRpcClient::create('json', 'http://host/server')->remoteMethod($param, ...);
29  * </pre>
30  *
31  * Second, you can also use the specific implementation directly:
32  * <pre>
33  * $_rpcClient = new TXmlRpcClient('http://host/server');
34  * $_result = $_rpcClient->remoteMethod($param, ...);
35  * </pre>
36  *
37  * or as oneliner:
38  * <pre>
39  * $_result = TXmlRpcClient('http://host/server')->hello();
40  * </pre>
41  *
42  * @author Robin J. Rogge <rrogge@bigpoint.net>
43  * @version $Id$
44  * @package System.Util
45  * @since 3.2
46  */
47
48 class TRpcClient extends TApplicationComponent
49 {
50         /**
51          * @var string url of the RPC server
52          */
53         private $_serverUrl;
54
55         /**
56          * @var boolean whether the request is a notification and therefore should not care about the result (default: false)
57          */
58         private $_isNotification = false;
59
60         // magics
61
62         /**
63          * @param string url to RPC server
64          * @param boolean whether requests are considered to be notifications (completely ignoring the response) (default: false)
65          */
66         public function __construct($serverUrl, $isNotification = false)
67         {
68                 $this->_serverUrl = $serverUrl;
69                 $this->_isNotification = TPropertyValue::ensureBoolean($isNotification);
70         }
71
72         // methods
73
74         /**
75          * Creates an instance of the requested RPC client type
76          * @return TRpcClient instance
77          * @throws TApplicationException if an unsupported RPC client type was specified
78          */
79         public static function create($type, $serverUrl, $isNotification = false)
80         {
81                 if(($_handler = constant('TRpcClientTypesEnumerable::'.strtoupper($type))) === null)
82                         throw new TApplicationException('rpcclient_unsupported_handler');
83
84                 return new $_handler($serverUrl, $isNotification);
85         }
86
87         /**
88          * Creates a stream context resource
89          * @param mixed $content
90          * @param string $contentType mime type
91          */
92         protected function createStreamContext($content, $contentType)
93         {
94                 return stream_context_create(array(
95                         'http' => array(
96                                 'method' => 'POST',
97                                 'header' => "Content-Type: {$contentType}",
98                                 'content' => $content
99                         )
100                 ));
101         }
102
103         /**
104          * Performs the actual request
105          * @param string RPC server URL
106          * @param array payload data
107          * @param string request mime type
108          */
109         protected function performRequest($serverUrl, $payload, $mimeType)
110         {
111                 if(($_response = @file_get_contents($serverUrl, false, $this->createStreamContext($payload, $mimeType))) === false)
112                         throw new TRpcClientRequestException('Request failed ("'.$http_response_header[0].'")');
113
114                 return $_response;
115         }
116
117         // getter/setter
118
119         /**
120          * @return boolean whether requests are considered to be notifications (completely ignoring the response)
121          */
122         public function getIsNotification()
123         {
124                 return $this->_isNotification;
125         }
126
127         /**
128          * @param string boolean whether the requests are considered to be notifications (completely ignoring the response) (default: false)
129          */
130         public function setIsNotification($bool)
131         {
132                 $this->_isNotification = TPropertyValue::ensureBoolean($bool);
133         }
134
135         /**
136          * @return string url of the RPC server
137          */
138         public function getServerUrl()
139         {
140                 return $this->_serverUrl;
141         }
142
143         /**
144          * @param string url of the RPC server
145          */
146         public function setServerUrl($value)
147         {
148                 $this->_serverUrl = $value;
149         }
150 }
151
152 /**
153  * TRpcClientTypesEnumerable class
154  *
155  * @author Robin J. Rogge <rrogge@bigpoint.net>
156  * @version $Id$
157  * @package System.Util
158  * @since 3.2
159  */
160
161 class TRpcClientTypesEnumerable extends TEnumerable
162 {
163         const JSON = 'TJsonRpcClient';
164         const XML = 'TXmlRpcClient';
165 }
166
167 /**
168  * TRpcClientRequestException class
169  *
170  * This Exception is fired if the RPC request fails because of transport problems e.g. when
171  * there is no RPC server responding on the given remote host.
172  *
173  * @author Robin J. Rogge <rrogge@bigpoint.net>
174  * @version $Id$
175  * @package System.Util
176  * @since 3.2
177  */
178
179 class TRpcClientRequestException extends TApplicationException
180 {
181 }
182
183 /**
184  * TRpcClientResponseException class
185  *
186  * This Exception is fired when the
187  *
188  * @author Robin J. Rogge <rrogge@bigpoint.net>
189  * @version $Id$
190  * @package System.Util
191  * @since 3.2
192  */
193
194 class TRpcClientResponseException extends TApplicationException
195 {
196         /**
197          * @param string error message
198          * @param integer error code (optional)
199          */
200         public function __construct($errorMessage, $errorCode = null)
201         {
202                 $this->setErrorCode($errorCode);
203
204                 parent::__construct($errorMessage);
205         }
206 }
207
208 /**
209  * TJsonRpcClient class
210  *
211  * Note: When using setIsNotification(true), *every* following request is also
212  * considered to be a notification until you use setIsNotification(false).
213  *
214  * Usage:
215  * <pre>
216  * $_rpcClient = new TJsonRpcClient('http://host/server');
217  * $_result = $_rpcClient->remoteMethod($param, $otherParam);
218  * // or
219  * $_result = TJsonRpcClient::create('http://host/server')->remoteMethod($param, $otherParam);
220  * </pre>
221  *
222  * @author Robin J. Rogge <rrogge@bigpoint.net>
223  * @version $Id$
224  * @package System.Util
225  * @since 3.2
226  */
227
228 class TJsonRpcClient extends TRpcClient
229 {
230         // magics
231
232         /**
233          * @param string RPC method name
234          * @param array RPC method parameters
235          * @return mixed RPC request result
236          * @throws TRpcClientRequestException if the client fails to connect to the server
237          * @throws TRpcClientResponseException if the response represents an RPC fault
238          */
239         public function __call($method, $parameters)
240         {
241                 // send request
242                 $_response = $this->performRequest($this->getServerUrl(), $this->encodeRequest($method, $parameters), 'application/json');
243
244                 // skip response handling if the request was just a notification request
245                 if($this->isNotification)
246                         return true;
247
248                 // decode response
249                 if(($_response = json_decode($_response, true)) === null)
250                         throw new TRpcClientResponseException('Empty response received');
251
252                 // handle error response
253                 if(!is_null($_response['error']))
254                         throw new TRpcClientResponseException($_response['error']);
255
256                 return $_response['result'];
257         }
258
259         // methods
260
261         /**
262          * @param string method name
263          * @param array method parameters
264          */
265         public function encodeRequest($method, $parameters)
266         {
267                 static $_requestId;
268                 $_requestId = ($_requestId === null) ? 1 : $_requestId + 1;
269
270                 return json_encode(array(
271                         'method' => $method,
272                         'params' => $parameters,
273                         'id' => $this->isNotification ? null : $_requestId
274                 ));
275         }
276
277         /**
278          * Creates an instance of TJsonRpcClient
279          * @param string url of the rpc server
280          * @param boolean whether the requests are considered to be notifications (completely ignoring the response) (default: false)
281          */
282         public static function create($type, $serverUrl, $isNotification = false)
283         {
284                 return new self($serverUrl, $isNotification);
285         }
286 }
287
288 /**
289  * TXmlRpcClient class
290  *
291  * Note: When using setIsNotification(true), *every* following request is also
292  * considered to be a notification until you use setIsNotification(false).
293  *
294  * Usage:
295  * <pre>
296  * $_rpcClient = new TXmlRpcClient('http://remotehost/rpcserver');
297  * $_rpcClient->remoteMethod($param, $otherParam);
298  * </pre>
299  *
300  * @author Robin J. Rogge <rrogge@bigpoint.net>
301  * @version $Id$
302  * @package System.Util
303  * @since 3.2
304  */
305
306 class TXmlRpcClient extends TRpcClient
307 {
308         // magics
309
310         /**
311          * @param string RPC method name
312          * @param array RPC method parameters
313          * @return mixed RPC request result
314          * @throws TRpcClientRequestException if the client fails to connect to the server
315          * @throws TRpcClientResponseException if the response represents an RPC fault
316          */
317         public function __call($method, $parameters)
318         {
319                 // send request
320                 $_response = $this->performRequest($this->getServerUrl(), $this->encodeRequest($method, $parameters), 'text/xml');
321
322                 // skip response handling if the request was just a notification request
323                 if($this->isNotification)
324                         return true;
325
326                 // decode response
327                 if(($_response = xmlrpc_decode($_response)) === null)
328                         throw new TRpcClientResponseException('Empty response received');
329
330                 // handle error response
331                 if(xmlrpc_is_fault($_response))
332                         throw new TRpcClientResponseException($_response['faultString'], $_response['faultCode']);
333
334                 return $_response;
335         }
336
337         // methods
338
339         /**
340          * @param string method name
341          * @param array method parameters
342          */
343         public function encodeRequest($method, $parameters)
344         {
345                 return xmlrpc_encode_request($method, $parameters);
346         }
347
348         /**
349          * Creates an instance of TXmlRpcClient
350          * @param string url of the rpc server
351          * @param boolean whether the requests are considered to be notifications (completely ignoring the response) (default: false)
352          */
353         public static function create($type, $serverUrl, $isNotification = false)
354         {
355                 return new self($serverUrl, $isNotification);
356         }
357 }