/** * Handle * * @param string $calling_component_filename Filename * @param string $service_description Service description * * @return mixed */ public function handle($calling_component_filename, $service_description) { SCA::$logger->log("Entering"); SCA::$logger->log("_handleXmlRpcRequest - {$calling_component_filename}\n"); try { $wsdl_filename = null; // create a wrapper, which in turn creates a service // instance and fills in all of the references $class_name = SCA_Helper::guessClassName($calling_component_filename); $instance = SCA::createInstance($class_name); $service_proxy = new SCA_Bindings_Xmlrpc_Wrapper($instance, $class_name, $wsdl_filename); // create the xmlrpc server that will process the input message // and generate the result message $xmlrpc_server = new SCA_Bindings_Xmlrpc_Server($service_proxy); // handle the current request $xmlrpc_server->handle(); } catch (Exception $ex) { // A catch all exception just in case something drastic goes wrong // This can often be the case in constructors of the XML infrastructure // classes where XMLRPC info can be read over remote connections. We // still want to send a sensible error back to the client $response = "{\"error\":\"" . $ex->getMessage(); $response = $response . "\",\"version\":\"1.0\"}"; // some debugging //file_put_contents("xmlrpc_messages.txt", //"Response at XMLRPC server = " . $response . "\n", //FILE_APPEND); header('Content-type: text/xml'); echo $response; } return; }
/** * Handle * * @param string $calling_component_filename Filename * @param string $service_description Service description * * @return mixed */ public function handle($calling_component_filename, $service_description) { SCA::$logger->log('Entering'); $class_name = SCA_Helper::guessClassName($calling_component_filename); $wsdl_filename = str_replace('.php', '.wsdl', $calling_component_filename); if (!file_exists($wsdl_filename)) { file_put_contents($wsdl_filename, SCA_Bindings_Soap_ServiceDescriptionGenerator::generateDocumentLiteralWrappedWsdl($service_description)); } $handler = new SCA_Bindings_soap_Mapper("SoapServer"); try { SCA::$logger->log("Wsdl Type = {$wsdl_filename}"); $handler->setWSDLTypes($wsdl_filename); } catch (SCA_RuntimeException $wsdlerror) { echo $wsdlerror->exceptionString() . "\n"; } if (SCA_Helper::wsdlWasGeneratedForAnScaComponent($wsdl_filename)) { $options = $service_description->binding_config; $options['typemap'] = $handler->getTypeMap(); $server = new SoapServer($wsdl_filename, $options); } else { $server = new SoapServer($wsdl_filename, $service_description->binding_config); } $class_name = SCA_Helper::guessClassName($calling_component_filename); $service_wrapper = new SCA_Bindings_Soap_Wrapper($class_name, $handler); $server->setObject($service_wrapper); global $HTTP_RAW_POST_DATA; $server->handle($HTTP_RAW_POST_DATA); }
/** * Handle * * @param string $calling_component_filename Filename * @param string $service_description Service description * * @return mixed */ public function handle($calling_component_filename, $service_description) { SCA::$logger->log('Entering'); $class_name = SCA_Helper::guessClassName($calling_component_filename); $service_wrapper = new SCA_Bindings_restresource_Wrapper($class_name); $server = new SCA_Bindings_restresource_Server($service_wrapper); $server->handle(); }
/** * Create the local proxy to the service given as an argument. * * @param string $target Target URI * @param string $base_path_for_relative_paths Path * @param mixed $binding_config Config */ public function __construct($target, $base_path_for_relative_paths, $binding_config) { $absolute_path_to_component = SCA_Helper::constructAbsoluteTarget($target, $base_path_for_relative_paths); $this->component_class_name = SCA_Helper::guessClassName($absolute_path_to_component); if (!class_exists($this->component_class_name, false)) { include_once "{$absolute_path_to_component}"; } $this->instance_of_the_component = SCA::createInstance($this->component_class_name); SCA::fillInReferences($this->instance_of_the_component); }
/** * Handle * * @param string $calling_component_filename Filename * @param string $service_description Service description * * @return mixed */ public function handle($calling_component_filename, $service_description) { SCA::$logger->log("Entering"); SCA::$logger->log("calling from {$calling_component_filename}"); //var_dump($service_description); // Guess a queue name if (!isset($service_description->binding_config['destination'])) { $service_description->binding_config['destination'] = 'queue://' . $service_description->class_name; SCA::$logger->log("Target queue not specified, SCA will use class name as default queue name"); } //Generate a Message Provider Description file. $mpd_filename = str_replace('.php', '.msd', $calling_component_filename); if (!file_exists($mpd_filename)) { file_put_contents($mpd_filename, SCA_Bindings_message_ServiceDescriptionGenerator::generateMSD($service_description)); } /*do we use WSDL schema?*/ if (isset($service_description->binding_config['wsdl']) && $service_description->binding_config['wsdl'] == 'disabled') { /*No!*/ $mapper = null; } else { /*Yes, then we'll also need a wsdl file, this is generated by the ServiceDescriptionGenerator class of the soap binding*/ $wsdl_filename = str_replace('.php', '.wsdl', $calling_component_filename); if (!file_exists($wsdl_filename)) { file_put_contents($wsdl_filename, SCA_Bindings_soap_ServiceDescriptionGenerator::generateDocumentLiteralWrappedWsdl($service_description)); } $mapper = new SCA_Bindings_message_Mapper(); try { SCA::$logger->log("Wsdl Type = {$wsdl_filename}"); $mapper->setWSDLTypes($wsdl_filename); } catch (SCA_RuntimeException $wsdlerror) { echo $wsdlerror->exceptionString() . "\n"; } } $class_name = SCA_Helper::guessClassName($calling_component_filename); //create a wapper $service_wrapper = new SCA_Bindings_message_Wrapper($class_name, $service_description, $mapper); // create the message listener $listener = new SCA_Bindings_message_SAMClient($service_wrapper); $msd_config = SCA_Bindings_message_ServiceDescriptionGenerator::parseBindingConfig($service_description->binding_config); $listener->config($msd_config); $listener->start(); echo ">> Test END <<"; SCA::$logger->log("exiting"); return; }
/** * Handle * * @param string $calling_component_filename Filename * @param string $service_description Service description * * @return mixed */ public function handle($calling_component_filename, $service_description) { SCA::$logger->log("Entering"); try { $smd_filename = str_replace('.php', '.smd', $calling_component_filename); if (!file_exists($smd_filename)) { file_put_contents($smd_filename, SCA_GenerateSmd::generateSmd($service_description)); // ,self::generateSMD($calling_component_filename) // ); } $wsdl_filename = null; // create a wrapper, which in turn creates a service // instance and fills in all of the references $class_name = SCA_Helper::guessClassName($calling_component_filename); $instance = SCA::createInstance($class_name); $service_wrapper = new SCA_ServiceWrapperJson($instance, $class_name, $wsdl_filename); // create the jsonrpc server that will process the input message // and generate the result message $jsonrpc_server = new SCA_JsonRpcServer($service_wrapper); $jsonrpc_server->handle(); } catch (Exception $ex) { // A catch all exception just in case something drastic goes wrong // This can often be the case in constructors of the JSON infsatructure // classes where SMD files can be read over remote connections. We // still want to send a sensible error back to the client // TODO extend the JSON service to expose this kind of function // through public methods $response = "{\"id\":\""; $response = $response . SCA_JsonRpcServer::getRequest()->id; $response = $response . "\",\"error\":\"" . $ex->getMessage(); $response = $response . "\",\"version\":\"1.0\"}"; // TODO what to do about id? We can catch errors before the // input is parsed // some debugging // file_put_contents("json_messages.txt", // "Response at JSONRPC server = " . $response . "\n", // FILE_APPEND); header('Content-type: application/json-rpc'); echo $response; } return; }
/** * Handle * * @param string $calling_component_filename Filename * * @return null */ public function handle($calling_component_filename) { SCA::$logger->log("Entering"); $actions = array('POST' => array('create', 1), 'GET' => array('retrieve', 1), 'PUT' => array('update', 2), 'DELETE' => array('delete', 1)); if (array_key_exists($_SERVER['REQUEST_METHOD'], $actions)) { $methodWithNumberOfParams = $actions[$_SERVER['REQUEST_METHOD']]; $method = $methodWithNumberOfParams[0]; } else { //TODO find out correct response header("HTTP/1.1 404 "); echo $_SERVER['REQUEST_METHOD'] . " Not Supported."; return; } //*handle situations where we have the id in the url.*/ /** These look like the variables to use: [REQUEST_URI] => /Samples/RSS/Contact.php/12 [SCRIPT_NAME] => /Samples/RSS/Contact.php [PATH_INFO] => /12 */ /* * Note, if the PATH_INFO is not working, and you are using Apache 2.0, * check the AcceptPathInfo directive for php files. * See http://httpd.apache.org/docs/2.0/mod/core.html#acceptpathinfo */ //Set $id - works for non-selector style, but not for selector style. if (isset($_SERVER['PATH_INFO'])) { $param = $_SERVER['PATH_INFO']; //test different length of param //$param = "/344656"; //TODO: is there a case where there will not be a slash in [PATH_INFO]? //strip slash $lengthOfParam = strlen($param); $id = substr($param, 1, $lengthOfParam); } else { if (isset($_GET['id'])) { $id = $_GET['id']; //left so that our rewrite test still works } else { $id = null; } } try { //always give the component an sdo, but handle sdo or xml back from it. if ($method === 'create') { SCA::$logger->log("{$method} == create"); // Can only do GET (retrieve) on RSS // return http method not allowed status header("HTTP/1.1 405"); } else { if ($method === 'retrieve') { $call_response = null; try { if ($id === null) { $method = 'enumerate'; } SCA::$logger->log("Calling {$method} on the RSS service wrapper, passing in the id {$id}"); $class_name = SCA_Helper::guessClassName($calling_component_filename); $service_component = SCA::createInstance($class_name); SCA::fillInReferences($service_component); $call_response = call_user_func_array(array(&$service_component, $method), $id); SCA::$logger->log("Response from calling the method {$method} is: {$call_response}"); //TODO: make sure these tests reflect the correct return values. if ($call_response !== null) { $response_xml; // Handle the different types of response (SDO, PHP Class, Raw XML) if ($call_response instanceof SDO_DataObjectImpl) { //if the thing received is an sdo... //convert it to xml $response_xml = SCA_Bindings_Rss_RssDas::toXml($call_response); } else { if ($call_response instanceof Channel) { // TODO: write the mapping from php classes to XML... SCA::$logger->log("TODO: write the mapping from php rss classes to xml."); $response_xml = null; } else { if (is_string($call_response)) { $response_xml = $call_response; } } } header("HTTP/1.1 200"); header("Content-Type: application/xml"); echo $response_xml; } else { SCA::$logger->log("Caught call_response is null exception in RSSServer"); //TODO find out the right response header("HTTP/1.1 500"); //echo "The requested resource <em>$id</em> does not exist on this database"; } } catch (SCA_ServiceUnavailableException $ex) { header("HTTP/1.1 503"); } catch (SCA_ConflictException $ex) { header("HTTP/1.1 409"); } catch (SCA_AuthenticationException $ex) { header("HTTP/1.1 407"); } catch (SCA_BadRequestException $ex) { header("HTTP/1.1 400"); } catch (SCA_InternalServerErrorException $ex) { SCA::$logger->log("Caught SCA_InternalServerErrorException in RSSServer"); header("HTTP/1.1 500"); } catch (SCA_MethodNotAllowedException $ex) { //note - this one is more likely to be thrown by the server code than the component code. header("HTTP/1.1 405"); } catch (SCA_UnauthorizedException $ex) { header("HTTP/1.1 401"); } catch (SCA_RuntimeException $ex) { SCA::$logger->log("Caught SCA_RuntimeException in RSSServer\n"); header("HTTP/1.1 500"); } catch (Exception $ex) { SCA::$logger->log("Caught an exception in RSSServer: " . $ex->getMessage() . "\n"); $call_response['error'] = $ex->getMessage(); //TODO find out the right response header("HTTP/1.1 500"); } } else { if ($method === 'update') { // Can only do GET (retrieve) on RSS // return http method not allowed status header("HTTP/1.1 405"); } else { if ($method === 'delete') { // Can only do GET (retrieve) on RSS // return http method not allowed status header("HTTP/1.1 405"); } } } } } catch (SCA_MethodNotAllowedException $ex) { //catch problem finding the method encountered by the service wrapper. header("HTTP/1.1 405"); } catch (SCA_RuntimeException $ex) { //TODO: output exceptions correctly. header("HTTP/1.1 500"); } return; }
/** * This function can be called directly by a component to * create a dataobject from the namespaces defined in the @types annotations. * * @param string $namespace_uri Namespace identifying the xsd * @param string $type_name Element being reference in the xsd * * @return object Empty Data Object structure */ public static function createDataObject($namespace_uri, $type_name) { // Find out who/what called this function so that the type annotations // that define the xml used to create a 'das' can be scanned. $backtrace = debug_backtrace(); $caller = $backtrace[0]; $filepath = $caller['file']; $keyname = md5(serialize($filepath)); // Check if there is a matching xsd in the xmldas array if (array_key_exists($keyname, self::$xml_das_array)) { $xmldas = self::$xml_das_array[$keyname]; } else { // The trap will only trigger if the Annotations cannot be found // normally this is because a SCA Client Component has incorrectly // attempted to use this method, rather than the 'createDataObject' // method of either the 'Proxy, or LocalProxy. try { $class_name = SCA_Helper::guessClassName($filepath); $xmldas = SCA_Helper::getXmldas($class_name, null); self::$xml_das_array[$keyname] = $xmldas; } catch (ReflectionException $e) { $msg = $e->getMessage(); throw new SCA_RuntimeException("A PHP ReflectionException was thrown with message {$msg}. " . "This is usually the result of calling SCA::createDataObject from a user script. " . "User scripts should only call createDataObject on an SCA Proxy object."); } } return $xmldas->createDataObject($namespace_uri, $type_name); }
public function testDeleteRequestAndResponse() { //DELETE requests are translated to 'delete()' calls $_SERVER['REQUEST_METHOD'] = 'DELETE'; $_SERVER['PATH_INFO'] = 'TEST_ID'; //set up the service wrapper and atom server $file_name = dirname(__FILE__) . '/ComponentDeleteReturnTrueResponse.php'; include $file_name; $class_name = SCA_Helper::guessClassName($file_name); $sw = new SCA_ServiceWrapperAtom($class_name); $as = new SCA_AtomServer($sw); $input = dirname(__FILE__) . '/AtomInputFile3.txt'; $as->setInputStream($input); //Not expecting a body $as->handle(); $this->assertContains("HTTP/1.1 200 OK", $this->http_header_catcher->headers); }
/** * Handle * * @param string $calling_component_filename Filename * @param string $service_description Service description * * @return mixed */ public function handle($calling_component_filename, $service_description) { SCA::$logger->log("Entering"); $class_name = SCA_Helper::guessClassName($calling_component_filename); $this->service_wrapper = new SCA_ServiceWrapperAtom($class_name); $this->xml_das = $this->service_wrapper->getXmlDas(); $actions = array('POST' => array('create', 1), 'GET' => array('retrieve', 1), 'PUT' => array('update', 2), 'DELETE' => array('delete', 1)); if (array_key_exists($_SERVER['REQUEST_METHOD'], $actions)) { $methodWithNumberOfParams = $actions[$_SERVER['REQUEST_METHOD']]; $method = $methodWithNumberOfParams[0]; SCA::$logger->log("Request received: {$method}"); } else { //TODO find out correct response SCA::sendHttpHeader("HTTP/1.1 404 Not Found"); echo $_SERVER['REQUEST_METHOD'] . " Not Supported."; return; } //*handle situations where we have the id in the url.*/ /** These look like the variables to use: [REQUEST_URI] => /Samples/Atom/Contact.php/12 [SCRIPT_NAME] => /Samples/Atom/Contact.php [PATH_INFO] => /12 */ /* * Note, if the PATH_INFO is not working, and you are using Apache 2.0, * check the AcceptPathInfo directive for php files. * See http://httpd.apache.org/docs/2.0/mod/core.html#acceptpathinfo */ //Set $id - works for non-selector style, but not for selector style. if (isset($_SERVER['PATH_INFO'])) { $param = $_SERVER['PATH_INFO']; //test different length of param //$param = "/344656"; //TODO: is there a case where there will not be a slash in [PATH_INFO]? //strip slash $lengthOfParam = strlen($param); $id = substr($param, 1, $lengthOfParam); SCA::$logger->log("Resource id: {$id}"); } else { $id = null; } //TODO should also check at this stage whether we have invalid combos such as PUT with null $id // POST // Get the request body $rawHTTPContents = file_get_contents($this->input_stream); SCA::$logger->log("raw http contents = " . $rawHTTPContents); try { //Get (and check) the service description for the class. $param_description = $this->service_wrapper->getParametersForMethod($method); //NOTE: we always give the component an sdo, but handle sdo or xml back from it. if ($method === 'create') { SCA::$logger->log("The method is create()"); $sdo = $this->_fromXml($rawHTTPContents); //should now have an atom format sdo if (!$sdo instanceof SDO_DataObjectImpl) { SCA::sendHttpHeader("HTTP/1.1 400 Bad Request"); echo "Request did not contain valid atom format xml"; } SCA::$logger->log("Created an sdo from the xml input: {$sdo}"); $params_array = array($sdo); $call_response = null; $call_response = $this->service_wrapper->__call($method, $params_array); if ($call_response !== null) { if (!$call_response instanceof SDO_DataObjectImpl) { //if the thing received is xml... //convert it to sdo $call_response = $this->_fromXml($call_response); } /* only add a trailing slash if there isn't one already */ $slash_if_needed = preg_match('/\\/$/', $_SERVER['REQUEST_URI']) ? '' : '/'; $port_if_needed = isset($_SERVER['SERVER_PORT']) ? '' : ':' . $_SERVER['SERVER_PORT']; //TODO: Ideally we'd Use http host to get the right scheme part //problem with this is it could pick up the wrong port //for some setups. $created_uri = 'http://' . $_SERVER['SERVER_NAME'] . $port_if_needed . $_SERVER['REQUEST_URI'] . $slash_if_needed . $call_response->id[0]->value; //convert response to xml to send back $response = $this->_toXml($call_response); //Is the 'false' param required? //It is for sending headers of the same type and //these are different types? //SCA::sendHttpHeader("Status: 201 Created", false, 201); SCA::sendHttpHeader("HTTP/1.1 201 Created", false, 201); SCA::sendHttpHeader("Location:{$created_uri}"); SCA::sendHttpHeader("Content-Type: application/atom+xml"); echo $response; } else { //TODO sort out what we will flow back: //at the moment, only send back the message in the body //if the http code spec says a body can be present. //if the call response is null, then the create() method on the //component did not return the body of the entry to be returned to //the user. This would mean that they have not conformed to the spec //but will it always mean that the create failed? SCA::$logger->log("According to the Atompub Spec, expected create() on the component to return a copy of the successfully created resource but it has returned nothing."); SCA::sendHttpHeader("HTTP/1.1 500 Internal Server Error"); //echo "Failed to create resource. \n"; } } else { if ($method === 'retrieve') { SCA::$logger->log("The method is retrieve()"); $call_response = null; if ($id === null) { $method = 'enumerate'; } SCA::$logger->log("Calling {$method} on the Atom service wrapper"); $call_response = $this->service_wrapper->__call($method, $id); SCA::$logger->log("Response from calling the method {$method} is: {$call_response}"); if ($call_response !== null) { if ($call_response instanceof SDO_DataObjectImpl) { //if the thing received is an sdo... //convert it to xml $response_sdo = $this->_toXml($call_response); } else { $response_sdo = $call_response; } SCA::sendHttpHeader("HTTP/1.1 200 OK"); SCA::sendHttpHeader("Content-Type: application/atom+xml"); echo $response_sdo; } else { SCA::$logger->log("Call response was null"); SCA::sendHttpHeader("HTTP/1.1 500 Internal Server Error"); } } else { if ($method === 'update') { SCA::$logger->log("The method is update()"); $sdo = $this->_fromXml($rawHTTPContents); $params_array = array($id, $sdo); $call_response = null; $call_response = $this->service_wrapper->__call($method, $params_array); if ($call_response === true) { SCA::$logger->log("The update was successful"); SCA::sendHttpHeader("HTTP/1.1 200 OK"); //NOTE: should not be returning a body. } else { //TODO find out the right response code SCA::sendHttpHeader("HTTP/1.1 500 Internal Server Error"); } } else { if ($method === 'delete') { SCA::$logger->log("The method is delete()"); $call_response = null; $call_response = $this->service_wrapper->__call($method, $id); if ($call_response === true) { SCA::$logger->log("The delete was successful"); SCA::sendHttpHeader("HTTP/1.1 200 OK"); //should not be returning a body } // TODO - looks a bit odd - what if none of the above tests succeed? } } } } } catch (SCA_ServiceUnavailableException $ex) { SCA::$logger->log("caught SCA_ServiceUnavailableException when calling method {$method}"); //TODO: log more info, class the method was called on, msg. SCA::sendHttpHeader("HTTP/1.1 503 Service Unavailable"); } catch (SCA_ConflictException $ex) { SCA::$logger->log("caught SCA_ConflictException when calling method {$method}"); //TODO: log more info, class the method was called on, msg. SCA::sendHttpHeader("HTTP/1.1 409 Conflict"); } catch (SCA_AuthenticationException $ex) { SCA::$logger->log("caught SCA_AuthenticationException when calling method {$method}"); //TODO: log more info, class the method was called on, msg. SCA::sendHttpHeader("HTTP/1.1 407 Proxy Authentication Required"); } catch (SCA_BadRequestException $ex) { SCA::$logger->log("caught SCA_BadRequestException when calling method {$method}"); //TODO: log more info, class the method was called on, msg. SCA::sendHttpHeader("HTTP/1.1 400 Bad Request"); } catch (SCA_InternalServerErrorException $ex) { SCA::$logger->log("caught SCA_InternalServerErrorException when calling method {$method}"); //TODO: log more info, class the method was called on, msg. SCA::sendHttpHeader("HTTP/1.1 500 Internal Server Error"); } catch (SCA_UnauthorizedException $ex) { SCA::$logger->log("caught SCA_UnauthorizedException when calling method {$method}"); //TODO: log more info, class the method was called on, msg. SCA::sendHttpHeader("HTTP/1.1 401 Unauthorized"); } catch (SCA_NotFoundException $ex) { //catch problem finding the requested resource thrown by the component SCA::$logger->log("caught SCA_NotFoundException when calling method {$method}"); //TODO: log more info, class the method was called on, msg. SCA::sendHttpHeader("HTTP/1.1 404 Not Found"); } catch (SCA_MethodNotAllowedException $ex) { //catch problem finding the method encountered by the service wrapper. SCA::$logger->log("caught SCA_MethodNotAllowedException when calling method {$method}"); //TODO: log more info, class the method was called on, msg. SCA::sendHttpHeader("HTTP/1.1 405 Method Not Allowed"); } catch (SCA_RuntimeException $ex) { SCA::$logger->log("Caught SCA_RuntimeException in AtomServer: " . $ex->getMessage() . "\n"); //TODO: output exceptions correctly. SCA::sendHttpHeader("HTTP/1.1 500 Internal Server Error"); } catch (Exception $ex) { $call_response['error'] = $ex->getMessage(); SCA::$logger->log("Found exception in AtomServer: " . $ex->getMessage() . "\n"); //TODO sort out how we want to do this: //at the moment, only send back the message in the body //if the http code spec says a body can be present. SCA::sendHttpHeader("HTTP/1.1 500 Internal Server Error"); } return; }