summaryrefslogtreecommitdiff
path: root/framework/Web/Services/TJsonRpcProtocol.php
diff options
context:
space:
mode:
Diffstat (limited to 'framework/Web/Services/TJsonRpcProtocol.php')
-rw-r--r--framework/Web/Services/TJsonRpcProtocol.php180
1 files changed, 180 insertions, 0 deletions
diff --git a/framework/Web/Services/TJsonRpcProtocol.php b/framework/Web/Services/TJsonRpcProtocol.php
new file mode 100644
index 00000000..b3196b13
--- /dev/null
+++ b/framework/Web/Services/TJsonRpcProtocol.php
@@ -0,0 +1,180 @@
+<?php
+/**
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @link http://www.pradosoft.com/
+ * @copyright 2010 Bigpoint GmbH
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @since 3.2
+ * @package System.Web.Services
+ */
+
+/**
+ * TJsonRpcProtocol class
+ *
+ * TJsonRpcProtocol is a class that implements JSON-Rpc protocol in {@link TRpcService}.
+ * Both version 1.0 and 2.0 of the specification are implemented, and the server will try
+ * to answer using the same version of the protocol used by the requesting client.
+ *
+ * @author Robin J. Rogge <rrogge@bigpoint.net>
+ * @author Fabio Bas <ctrlaltca@gmail.com>
+ * @version $Id$
+ * @package System.Web.Services
+ * @since 3.2
+ */
+class TJsonRpcProtocol extends TRpcProtocol
+{
+ protected $_id=null;
+ protected $_specificationVersion=1.0;
+
+ /**
+ * Handles the RPC request
+ * @param string $requestPayload
+ * @return string JSON RPC response
+ */
+ public function callMethod($requestPayload)
+ {
+ try
+ {
+ $_request = $this->decode($requestPayload);
+
+ if(isset($_request['jsonrpc']))
+ {
+ $this->_specificationVersion=$_request['jsonrpc'];
+ if($this->_specificationVersion > 2.0)
+ throw new TRpcException('Unsupported specification version', '-32600');
+ }
+
+ if(isset($_request['id']))
+ $this->_id=$_request['id'];
+
+ if(!isset($_request['method']))
+ throw new TRpcException('Missing request method', '-32600');
+
+ if(!isset($_request['params']))
+ $parameters = array();
+ else
+ $parameters = $_request['params'];
+
+ if(!is_array($parameters))
+ $parameters = array($parameters);
+
+ // a request without an id is a notification that doesn't need a response
+ if($this->_id !== null)
+ {
+ if($this->_specificationVersion==2.0)
+ {
+ return $this->encode(array(
+ 'jsonrpc' => '2.0',
+ 'id' => $this->_id,
+ 'result' => $this->callApiMethod($_request['method'], $parameters),
+ ));
+ } else {
+ return $this->encode(array(
+ 'id' => $this->_id,
+ 'result' => $this->callApiMethod($_request['method'], $_request['params']),
+ 'error' => null
+ ));
+ }
+ }
+ }
+ catch(TRpcException $e)
+ {
+ return $this->createErrorResponse($e);
+ }
+ catch(THttpException $e)
+ {
+ throw $e;
+ }
+ catch(Exception $e)
+ {
+ return $this->createErrorResponse(new TRpcException('An internal error occured', '-32603'));
+ }
+ }
+
+ /**
+ * Turns the given exception into an JSON RPC fault
+ * @param TRpcException $exception
+ * @return string JSON RPC fault
+ */
+ public function createErrorResponse(TRpcException $exception)
+ {
+ if($this->_specificationVersion==2.0)
+ {
+ return $this->encode(array(
+ 'id' => $this->_id,
+ 'result' => null,
+ 'error'=> array(
+ 'code' => $exception->getCode(),
+ 'message'=> $exception->getMessage(),
+ 'data' => null,
+ )
+ ));
+ } else {
+ return $this->encode(array(
+ 'id' => $this->_id,
+ 'error'=> array(
+ 'code' => $exception->getCode(),
+ 'message'=> $exception->getMessage(),
+ 'data' => null,
+ )
+ ));
+ }
+ }
+
+ /**
+ * Sets the correct response headers
+ * @param THttpResponse $response
+ */
+ public function createResponseHeaders($response)
+ {
+ $response->setContentType('application/json');
+ $response->setCharset('UTF-8');
+ }
+
+ /**
+ * Decodes JSON encoded data into PHP data
+ * @param string $data in JSON format
+ * @return array PHP data
+ */
+ public function decode($data)
+ {
+ $s = json_decode($data, true);
+ self::checkJsonError();
+ return $s;
+ }
+
+ /**
+ * Encodes PHP data into JSON data
+ * @param mixed PHP data
+ * @return string JSON encoded PHP data
+ */
+ public function encode($data)
+ {
+ $s = json_encode($data);
+ self::checkJsonError();
+ return $s;
+ }
+
+ private static function checkJsonError()
+ {
+ $errnum = json_last_error();
+ if($errnum != JSON_ERROR_NONE)
+ throw new Exception("JSON error: $msg", $err);
+ }
+
+ /**
+ * Calls the callback handler for the given method
+ * Overrides parent implementation to correctly handle error codes
+ * @param string $methodName of the RPC
+ * @param array $parameters for the callback handler as provided by the client
+ * @return mixed whatever the callback handler returns
+ */
+ public function callApiMethod($methodName, $parameters)
+ {
+ if(!isset($this->rpcMethods[$methodName]))
+ throw new TRpcException('Method "'.$methodName.'" not found', '-32601');
+
+ return call_user_func_array($this->rpcMethods[$methodName]['method'], $parameters);
+ }
+} \ No newline at end of file