Author: chabotc
Date: Fri Jul 18 15:47:41 2008
New Revision: 678068

URL: http://svn.apache.org/viewvc?rev=678068&view=rev
Log:
Initial support for the batch proxy request type.

The url is /social/rest/batchProxy and it uses the http multipart 
format as described in the RESTful API specification.

It only supports ONE output format for a set of requests (which
is determined by the main url ?format=foo param, and defaults to
json). Input however will support mixing json and atom.

Atom input is still missing (has a debug dump right now) but support
for that will follow quickly.

OAuth and Atom input is still missing, but once their done PHP
Shindig will have full RESTful spec support, we're getting there!


Modified:
    
incubator/shindig/trunk/php/src/social-api/converters/OutputAtomConverter.php
    incubator/shindig/trunk/php/src/social-api/converters/OutputConverter.php
    
incubator/shindig/trunk/php/src/social-api/converters/OutputJsonConverter.php
    incubator/shindig/trunk/php/src/social-api/dataservice/PeopleHandler.php
    incubator/shindig/trunk/php/src/social-api/dataservice/RestRequestItem.php
    incubator/shindig/trunk/php/src/social-api/http/RestServlet.php
    
incubator/shindig/trunk/php/src/social-api/samplecontainer/BasicAppDataService.php
    
incubator/shindig/trunk/php/src/social-api/samplecontainer/BasicPeopleService.php

Modified: 
incubator/shindig/trunk/php/src/social-api/converters/OutputAtomConverter.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/social-api/converters/OutputAtomConverter.php?rev=678068&r1=678067&r2=678068&view=diff
==============================================================================
--- 
incubator/shindig/trunk/php/src/social-api/converters/OutputAtomConverter.php 
(original)
+++ 
incubator/shindig/trunk/php/src/social-api/converters/OutputAtomConverter.php 
Fri Jul 18 15:47:41 2008
@@ -1,4 +1,5 @@
 <?php
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements. See the NOTICE file
@@ -19,7 +20,7 @@
 
 /**
  * Format = atom output converter, for format definition see:
- * 
http://www.opensocial.org/Technical-Resources/opensocial-specification----implementation-version-08/restful-api-specification
+ * 
http://sites.google.com/a/opensocial.org/opensocial/Technical-Resources/opensocial-spec-v08/restful-api-specification
  */
 class OutputAtomConverter extends OutputConverter {
        private static $nameSpace = 'http://www.w3.org/2005/Atom';
@@ -40,7 +41,7 @@
                $data = $responseItem->getResponse();
                $userId = 
$requestItem->getUser()->getUserId($requestItem->getToken());
                $guid = 'urn:guid:' . $userId;
-               $authorName = $_SERVER['HTTP_HOST'].':'.$userId;
+               $authorName = $_SERVER['HTTP_HOST'] . ':' . $userId;
                $updatedAtom = date(DATE_ATOM);
                
                // Check to see if this is a single entry, or a collection, and 
construct either an atom 
@@ -52,20 +53,18 @@
                        
                        // The root Feed element
                        $entry = $this->addNode($doc, 'feed', '', false, 
self::$nameSpace);
-
+                       
                        // Required Atom fields
                        $endPos = ($startIndex + $itemsPerPage) > $totalResults 
? $totalResults : ($startIndex + $itemsPerPage);
-                       $this->addNode($entry, 'title', $requestType.' feed for 
id '.$authorName.' ('.$startIndex. ' - '. ($endPos - 1).' of 
'.$totalResults.')');
+                       $this->addNode($entry, 'title', $requestType . ' feed 
for id ' . $authorName . ' (' . $startIndex . ' - ' . ($endPos - 1) . ' of ' . 
$totalResults . ')');
                        $author = $this->addNode($entry, 'author');
                        $this->addNode($author, 'uri', $guid);
-                       $this->addNode($author, 'name', $authorName);           
        
+                       $this->addNode($author, 'name', $authorName);
                        $this->addNode($entry, 'updated', $updatedAtom);
                        $this->addNode($entry, 'id', $guid);
-                       $this->addNode($entry, 'link', '', array('rel' => 
'self', 'href' => 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']));
-                       
+                       $this->addNode($entry, 'link', '', array('rel' => 
'self', 'href' => 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']));
                        // Add osearch & next link to the entry
                        $this->addPagingFields($entry, $startIndex, 
$itemsPerPage, $totalResults);
-                       
                        // Add response entries to feed
                        $responses = $responseItem->getResponse()->getEntry();
                        foreach ($responses as $response) {
@@ -79,11 +78,10 @@
                                $this->addNode($author, 'uri', $guid);
                                $this->addNode($author, 'name', $authorName);
                                // Special hoisting rules for activities
-                               
                                if ($response instanceof Activity) {
                                        $this->addNode($feedEntry, 'category', 
'', array('term' => 'status'));
                                        $this->addNode($feedEntry, 'updated', 
date(DATE_ATOM, $response->postedTime));
-                                       $this->addNode($feedEntry, 'id', 
'urn:guid:'.$response->id);
+                                       $this->addNode($feedEntry, 'id', 
'urn:guid:' . $response->id);
                                        //FIXME should add a link field but 
don't have URL's available yet:
                                        // <link rel="self" 
type="application/atom+xml" 
href="http://api.example.org/activity/feeds/.../af3778"/>
                                        $this->addNode($feedEntry, 'title', 
strip_tags($response->title));
@@ -94,43 +92,49 @@
                                        unset($response->title);
                                        unset($response->body);
                                } else {
-                                       $this->addNode($feedEntry, 'id', 
'urn:guid:'.$idField);
-                                       $this->addNode($feedEntry, 'title', 
$requestType.' feed entry for id '.$idField);
+                                       $this->addNode($feedEntry, 'id', 
'urn:guid:' . $idField);
+                                       $this->addNode($feedEntry, 'title', 
$requestType . ' feed entry for id ' . $idField);
                                        $this->addNode($feedEntry, 'updated', 
$updatedAtom);
                                }
                                
                                // recursively add responseItem data to the xml 
structure
                                $this->addData($content, $requestType, 
$response, self::$osNameSpace);
                        }
-                       
                } else {
-                       
                        // Single entry = Atom:Entry    
                        $entry = 
$doc->appendChild($doc->createElementNS(self::$nameSpace, "entry"));
-                       
                        // Atom fields
-                       $this->addNode($entry, 'title', $requestType.' entry 
for '.$authorName);
+                       $this->addNode($entry, 'title', $requestType . ' entry 
for ' . $authorName);
                        $author = $this->addNode($entry, 'author');
                        $this->addNode($author, 'uri', $guid);
                        $this->addNode($author, 'name', $authorName);
                        $this->addNode($entry, 'id', $guid);
                        $this->addNode($entry, 'updated', $updatedAtom);
                        $content = $this->addNode($entry, 'content', '', 
array('type' => 'application/xml'));
-                       
                        // addData loops through the responseItem data 
recursively creating a matching XML structure
                        $this->addData($content, $requestType, $data, 
self::$osNameSpace);
                }
                $xml = $doc->saveXML();
-               if (self::$includeOsearch && $responseItem->getResponse() 
instanceof RestFulCollection) {
+               if ($responseItem->getResponse() instanceof RestFulCollection) {
                        //FIXME dirty hack until i find a way to add multiple 
name spaces using DomXML functions
-                       $xml = str_replace('<feed 
xmlns="http://www.w3.org/2005/Atom";>', '<feed 
xmlns="http://www.w3.org/2005/Atom"; 
xmlos:osearch="http://a9.com/-/spec/opensearch/1.1";>' ,$xml);
+                       $xml = str_replace('<feed 
xmlns="http://www.w3.org/2005/Atom";>', '<feed 
xmlns="http://www.w3.org/2005/Atom"; 
xmlns:osearch="http://a9.com/-/spec/opensearch/1.1";>', $xml);
                }
                echo $xml;
        }
 
        function outputBatch(Array $responses, SecurityToken $token)
        {
-               //TODO once we support spec compliance batching, this needs to 
be added too
+               $this->boundryHeaders();
+               foreach ($responses as $response) {
+                       $request = $response['request'];
+                       $response = $response['response'];
+                       // output buffering supports multiple levels of it.. 
it's a nice feature to abuse :)
+                       ob_start();
+                       $this->outputResponse($response, $request);
+                       $part = ob_get_contents();
+                       ob_end_clean();
+                       $this->outputPart($part, $response->getError());
+               }
        }
 
        /**
@@ -174,11 +178,9 @@
         */
        private function addPagingFields($entry, $startIndex, $itemsPerPage, 
$totalResults)
        {
-               if (self::$includeOsearch) {
-                       $this->addNode($entry, 'osearch:totalResults', 
$totalResults);
-                       $this->addNode($entry, 'osearch:startIndex', 
$startIndex ? $startIndex : '0');
-                       $this->addNode($entry, 'osearch:itemsPerPage', 
$itemsPerPage);
-               }
+               $this->addNode($entry, 'osearch:totalResults', $totalResults);
+               $this->addNode($entry, 'osearch:startIndex', $startIndex ? 
$startIndex : '0');
+               $this->addNode($entry, 'osearch:itemsPerPage', $itemsPerPage);
                // Create a 'next' link based on our current url if this is a 
pageable collection & there is more to display
                if (($startIndex + $itemsPerPage) < $totalResults) {
                        $nextStartIndex = ($startIndex + $itemsPerPage) - 1;
@@ -255,6 +257,9 @@
                                        }
                                        $this->addData($newElement, $key, $val);
                                } else {
+                                       if (is_numeric($key)) {
+                                               $key = is_object($val) ? 
get_class($val) : $key = $name;
+                                       }                                       
                                        $elm = 
$newElement->appendChild($this->doc->createElement($key));
                                        
$elm->appendChild($this->doc->createTextNode($val));
                                }

Modified: 
incubator/shindig/trunk/php/src/social-api/converters/OutputConverter.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/social-api/converters/OutputConverter.php?rev=678068&r1=678067&r2=678068&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/social-api/converters/OutputConverter.php 
(original)
+++ incubator/shindig/trunk/php/src/social-api/converters/OutputConverter.php 
Fri Jul 18 15:47:41 2008
@@ -22,6 +22,50 @@
  *
  */
 abstract class OutputConverter {
+       private $boundry;
+       
        abstract function outputResponse(ResponseItem $responseItem, 
RestRequestItem $requestItem);
        abstract function outputBatch(Array $responses, SecurityToken $token);
+       
+       /**
+        * Output the multipart/mixed headers and returns the boundry token used
+        *
+        */
+       public function boundryHeaders()
+       {
+               $this->boundry = '--batch-'.md5(rand(0,32000));
+               header("HTTP/1.1 200 OK", true);
+               header("Content-Type: multipart/mixed; 
boundary=$this->boundry", true);
+       }
+       
+       public function outputPart($part, $code)
+       {
+               $boundryHeader = "{$this->boundry}\n".
+                               "Content-Type: application/http;version=1.1\n".
+                               "Content-Transfer-Encoding: binary\n\n";
+               echo $boundryHeader;
+               switch ($code) {
+                       case BAD_REQUEST:
+                               $code = '400 Bad Request';
+                               break;
+                       case UNAUTHORIZED:
+                               $code = '401 Unauthorized';
+                               break;
+                       case FORBIDDEN:
+                               $code = '403 Forbidden';
+                               break;
+                       case FORBIDDEN:
+                               $code = '404 Not Found';
+                               break;
+                       case NOT_IMPLEMENTED:
+                               $code = '501 Not Implemented';
+                               break;
+                       case INTERNAL_ERROR:
+                       default:
+                               $code = '200 OK';
+                               break;
+               }
+               echo "$code\n\n";
+               echo $part."\n";
+       }
 }

Modified: 
incubator/shindig/trunk/php/src/social-api/converters/OutputJsonConverter.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/social-api/converters/OutputJsonConverter.php?rev=678068&r1=678067&r2=678068&view=diff
==============================================================================
--- 
incubator/shindig/trunk/php/src/social-api/converters/OutputJsonConverter.php 
(original)
+++ 
incubator/shindig/trunk/php/src/social-api/converters/OutputJsonConverter.php 
Fri Jul 18 15:47:41 2008
@@ -30,6 +30,17 @@
        
        function outputBatch(Array $responses, SecurityToken $token)
        {
+               $this->boundryHeaders();
+               foreach ($responses as $response) {
+                       $request = $response['request'];
+                       $response = $response['response'];
+                       $part = json_encode($response);
+                       $this->outputPart($part, $response->getError());
+               }
+       }
+       
+       function outputJsonBatch(Array $responses, SecurityToken $token)
+       {
                echo json_encode(array("responses" => $responses, "error" => 
false));
        }
 }

Modified: 
incubator/shindig/trunk/php/src/social-api/dataservice/PeopleHandler.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/social-api/dataservice/PeopleHandler.php?rev=678068&r1=678067&r2=678068&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/social-api/dataservice/PeopleHandler.php 
(original)
+++ incubator/shindig/trunk/php/src/social-api/dataservice/PeopleHandler.php 
Fri Jul 18 15:47:41 2008
@@ -20,7 +20,9 @@
 class PeopleHandler extends DataRequestHandler {
        private $service;
        private static $PEOPLE_PATH = "/people/{userId}/{groupId}/{personId}";
-       protected static $DEFAULT_PERSON_FIELDS = array("id", "name", 
"thumbnailUrl");
+       //FIXME change this back to array("id", "name", "thumbnailUrl") once 
the dust settles
+       // on the spec discussion related to this
+       protected static $DEFAULT_PERSON_FIELDS = array('all' => 'all');
 
        public function __construct()
        {

Modified: 
incubator/shindig/trunk/php/src/social-api/dataservice/RestRequestItem.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/social-api/dataservice/RestRequestItem.php?rev=678068&r1=678067&r2=678068&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/social-api/dataservice/RestRequestItem.php 
(original)
+++ incubator/shindig/trunk/php/src/social-api/dataservice/RestRequestItem.php 
Fri Jul 18 15:47:41 2008
@@ -45,12 +45,12 @@
 
        public function createRequestItemWithRequest($request, $token)
        {
-               $this->url = $request->url;
-               $this->parameters = $this->createParameterMap($request->url);
+               $this->url = $request['url'];
+               $this->parameters = $this->createParameterMap($request['url']);
                $this->token = $token;
-               $this->method = $request->method;
-               if (isset($request->postData)) {
-                       $this->postData = $request->postData;
+               $this->method = $request['method'];
+               if (isset($request['postData'])) {
+                       $this->postData = $request['postData'];
                }
        }
 

Modified: incubator/shindig/trunk/php/src/social-api/http/RestServlet.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/social-api/http/RestServlet.php?rev=678068&r1=678067&r2=678068&view=diff
==============================================================================
--- incubator/shindig/trunk/php/src/social-api/http/RestServlet.php (original)
+++ incubator/shindig/trunk/php/src/social-api/http/RestServlet.php Fri Jul 18 
15:47:41 2008
@@ -51,8 +51,6 @@
 require 'src/social-api/converters/OutputAtomConverter.php';
 require 'src/social-api/converters/OutputJsonConverter.php';
 
-//FIXME Delete should respond with a 204 No Content to indicate success
-
 class RestException extends Exception {}
 
 /*
@@ -64,42 +62,80 @@
 define('FORBIDDEN', "forbidden");
 define('BAD_REQUEST', "badRequest");
 define('INTERNAL_ERROR', "internalError");
+//FIXME Delete should respond with a 204 No Content to indicate success
 
 class RestServlet extends HttpServlet {
        
+       // The json Batch Route is used by the gadgets 
        private static $JSON_BATCH_ROUTE = "jsonBatch";
+       // The Batch Proxy route is used the one defined in the RESTful API 
specification
+       private static $BATCH_PROXY_ROUTE = "batchProxy";
+
+       public function doGet()
+       {
+               $this->doPost('GET');
+       }
 
+       public function doPut()
+       {
+               $this->doPost('PUT');
+       }
+
+       public function doDelete()
+       {
+               $this->doPost('DELETE');
+       }
+               
        public function doPost($method = 'POST')
        {
-               $this->setNoCache(true);
-               // if oauth, create a token from it's values instead of one 
based on $_get['st']/$_post['st']
-               // NOTE : if no token is provided an anonymous one is created 
(owner = viewer = appId = modId = 0)
-               // keep this in mind when creating your data services.. 
-               $token = $this->getSecurityToken();
-               $outputFormat = $this->getOutputFormat();
-               switch ($outputFormat) {
-                       case 'json':
-                               $this->setContentType('application/json');
-                               $outputConverter = new OutputJsonConverter();
-                               break;
-                       case 'atom':
-                               $this->setContentType('application/atom+xml');
-                               $outputConverter = new OutputAtomConverter();
-                               break;
-                       default:
-                               $this->outputError(new 
ResponseItem(NOT_IMPLEMENTED, "Invalid output format"));
-                               break;
-               }
-               if ($this->isBatchUrl()) {
-                       $responses = $this->handleBatchRequest($token);
-                       $outputConverter->outputBatch($responses, $token);
-               } else {
-                       $response = $this->handleSingleRequest($token, $method);
-                       $outputConverter->outputResponse($response['response'], 
$response['request']);
+               try {
+                       $this->setNoCache(true);
+                       // if oauth, create a token from it's values instead of 
one based on $_get['st']/$_post['st']
+                       // NOTE : if no token is provided an anonymous one is 
created (owner = viewer = appId = modId = 0)
+                       // keep this in mind when creating your data services.. 
+                       $token = $this->getSecurityToken();
+                       $outputFormat = $this->getOutputFormat();
+                       switch ($outputFormat) {
+                               case 'json':
+                                       
$this->setContentType('application/json');
+                                       $outputConverter = new 
OutputJsonConverter();
+                                       break;
+                               case 'atom':
+                                       
$this->setContentType('application/atom+xml');
+                                       $outputConverter = new 
OutputAtomConverter();
+                                       break;
+                               default:
+                                       $this->outputError(new 
ResponseItem(NOT_IMPLEMENTED, "Invalid output format"));
+                                       break;
+                       }
+                       if ($this->isJsonBatchUrl()) {
+                               // custom json batch format used by the gadgets
+                               $responses = 
$this->handleJsonBatchRequest($token);
+                               $outputConverter->outputJsonBatch($responses, 
$token);
+                       } elseif ($this->isBatchProxyUrl()) {
+                               // spec compliant batch proxy
+                               $this->noHeaders = true;
+                               $responses = 
$this->handleBatchProxyRequest($token);
+                               $outputConverter->outputBatch($responses, 
$token);
+                       } else {
+                               // single rest request
+                               $response = $this->handleRequest($token, 
$method);
+                               
$outputConverter->outputResponse($response['response'], $response['request']);
+                       }
+               } catch (Exception $e) {
+                       header("HTTP/1.0 500 Internal Server Error");
+                       echo "<html><body><h1>500 Internal Server Error</h1>";
+                       if (Config::get('debug')) {
+                               echo "Message: ".$e->getMessage()."<br />\n";
+                               echo "<pre>\n";
+                               print_r(debug_backtrace());
+                               echo "\n</pre>";
+                       }
+                       echo "</body></html>";
                }
        }
 
-       private function handleSingleRequest($token, $method)
+       private function handleRequest($token, $method)
        {
                $params = $this->getListParams();
                $requestItem = new RestRequestItem();
@@ -109,14 +145,115 @@
                $responseItem = $this->getResponseItem($requestItem);
                return array('request' => $requestItem, 'response' => 
$responseItem);
        }
-
-       private function getRouteFromParameter($pathInfo)
+       
+       private function handleJsonBatchRequest($token)
        {
-               $pathInfo = substr($pathInfo, 1);
-               $indexOfNextPathSeparator = strpos($pathInfo, "/");
-               return $indexOfNextPathSeparator != - 1 ? substr($pathInfo, 0, 
$indexOfNextPathSeparator) : $pathInfo;
+               // we support both a raw http post (without 
application/x-www-form-urlencoded headers) like java does
+               // and a more php / curl safe version of a form post with 
'request' as the post field that holds the request json data
+               if (isset($GLOBALS['HTTP_RAW_POST_DATA']) || 
isset($_POST['request'])) {
+                       $requests = $this->getRequestParams();
+                       $responses = array();
+                       foreach ($requests as $key => $value) {
+                               $requestItem = new RestRequestItem();
+                               
$requestItem->createRequestItemWithRequest($value, $token);
+                               $responses[$key] = 
$this->getResponseItem($requestItem);
+                       }
+                       return $responses;
+               } else {
+                       throw new Exception("No post data set");
+               }
+       }
+       
+       private function handleBatchProxyRequest($token)
+       {
+               // Is this is a multipath/mixed post? Check content type:
+               if (isset($GLOBALS['HTTP_RAW_POST_DATA']) && 
strpos($_SERVER['CONTENT_TYPE'], 'multipart/mixed') !== false && 
strpos($_SERVER['CONTENT_TYPE'],'boundary=') !== false) {
+                       // Ok looks swell, see what our boundry is..
+                       $boundry = substr($_SERVER['CONTENT_TYPE'], 
strpos($_SERVER['CONTENT_TYPE'],'boundary=') + strlen('boundary='));
+                       // Split up requests per boundry
+                       $requests = explode($boundry, 
$GLOBALS['HTTP_RAW_POST_DATA']);
+                       $responses = array();
+                       foreach ($requests as $request) {
+                               $request = trim($request);
+                               if (!empty($request)) {
+                                       // extractBatchRequest() does the magic 
parsing of the raw post data to a meaninful request array
+                                       $request = 
$this->extractBatchRequest($request);
+                                       $requestItem = new RestRequestItem();
+                                       
$requestItem->createRequestItemWithRequest($request, $token);
+                                       $responses[] = array('request' => 
$requestItem, 'response' => $this->getResponseItem($requestItem));
+                               }
+                       }
+               } else {
+                       $this->outputError(new ResponseItem(BAD_REQUEST, 
"Invalid multipart/mixed request"));
+               }
+               return $responses;
        }
 
+       private function extractBatchRequest($request)
+       {
+               /* Multipart request is formatted like:
+                * -batch-a73hdj3dy3mm347ddjjdf
+                * Content-Type: application/http;version=1.1
+                * Content-Transfer-Encoding: binary
+                * 
+                * GET /people/@me/@friends?startPage=5&count=10&format=json
+                * Host: api.example.org
+                * If-None-Match: "837dyfkdi39df"
+                * 
+                * but we only want to have the last bit (the actual request), 
this filters that down first
+                */
+               $emptyFound = false;
+               $requestLines = explode("\n", $request);
+               $request = '';
+               foreach ($requestLines as $line) {
+                       if ($emptyFound) {
+                               $request .= $line."\n";
+                       } elseif (empty($line)) {
+                               $emptyFound = true;
+                       }
+               }
+               // Now that we have the basic request in $request, split that 
up again & parse it into a meaningful representation
+               $firstFound = $emptyFound = false;
+               $requestLines = explode("\n", $request);
+               $request = array();
+               $request['headers'] = array();
+               $request['postData'] = '';
+               foreach ($requestLines as $line) {
+                       if (!$firstFound) {
+                               $firstFound = true;
+                               $parts = explode(' ', trim($line));
+                               if (count($parts) != 2) {
+                                       throw new Exception("Mallshaped request 
uri in multipart block");
+                               }
+                               $request['method'] = 
strtoupper(trim($parts[0]));
+                               // cut it down to an actual meaningful url 
without the prefix/social/rest part right away 
+                               $request['url'] = substr(trim($parts[1]), 
strlen(Config::get('web_prefix') . '/social/rest'));
+                       } elseif (!$emptyFound && !empty($line)) {
+                               // convert the key to the PHP 'CONTENT_TYPE' 
style naming convention.. it's ugly but consitent
+                               $key = str_replace('-', '_', 
strtoupper(trim(substr($line, 0, strpos($line, ':')))));
+                               $val = trim(substr($line, strpos($line, ':') + 
1));
+                               $request['headers'][$key] = $val;
+                       } elseif (!$emptyFound && empty($line)) {
+                               $emptyFound = true;
+                       } else {
+                               if (get_magic_quotes_gpc()) {
+                                       $line = stripslashes($line);
+                               }
+                               $request['postData'] .= $line."\n";
+                       }
+               }
+               if (empty($request['postData'])) {
+                       // don't trip the requestItem into thinking there is 
postData when there's not
+                       unset($request['postData']);
+               } else {
+                       // if there was a post data blob present, decode it 
into an array, the format is based on the 
+                       // content type header, which is either 
application/json or 
+                       $format = isset($request['headers']['CONTENT_TYPE']) && 
strtolower($request['headers']['CONTENT_TYPE']) == 'application/atom+xml' ? 
'atom' : 'json';
+                       $request['postData'] = 
$this->decodeRequests($request['postData'], $format);
+               }
+               return $request;
+       }
+       
        private function getResponseItem(RestRequestItem $requestItem)
        {
                $path = $this->getRouteFromParameter($requestItem->getUrl());
@@ -140,12 +277,26 @@
                        $class = new $class(null);
                        $response = $class->handleMethod($requestItem);
                }
-               if ($response->getError() != null && !$this->isBatchUrl()) {
+               if ($response->getError() != null && !$this->isJsonBatchUrl() 
&& !$this->isBatchProxyUrl()) {
                        // Can't use http error codes in batch mode, instead we 
return the error code in the response item
                        $this->outputError($response);
                }
                return $response;
        }
+       
+       private function decodeRequests($requestParam, $format = 'json')
+       {
+               // temp hack until i know what the intended way to detect 
format is
+               if ($format == 'json') {
+                       return json_decode($requestParam, true);
+               } elseif ($format == 'atom') {
+                       $xml = simplexml_load_string($requestParam);
+                       print_r($xml);
+                       return $xml;
+               } else {
+                       throw Exception("Invalid or unsupported input format");
+               }
+       }
 
        private function getRequestParams()
        {
@@ -154,44 +305,14 @@
                if (get_magic_quotes_gpc()) {
                        $requestParam = stripslashes($requestParam);
                }
-               $requests = json_decode($requestParam);
-               if ($requests == (isset($GLOBALS['HTTP_RAW_POST_DATA']) ? 
$GLOBALS['HTTP_RAW_POST_DATA'] : $post)) {
-                       return new ResponseItem(BAD_REQUEST, "Malformed json 
string");
-               }
-               return $requests;
-       }
-
-       private function handleBatchRequest($token)
-       {
-               // we support both a raw http post (without 
application/x-www-form-urlencoded headers) like java does
-               // and a more php / curl safe version of a form post with 
'request' as the post field that holds the request json data
-               if (isset($GLOBALS['HTTP_RAW_POST_DATA']) || 
isset($_POST['request'])) {
-                       $requests = $this->getRequestParams();
-                       $responses = array();
-                       foreach ($requests as $key => $value) {
-                               $requestItem = new RestRequestItem();
-                               
$requestItem->createRequestItemWithRequest($value, $token);
-                               $responses[$key] = 
$this->getResponseItem($requestItem);
-                       }
-                       return $responses;
-               } else {
-                       throw new Exception("No post data set");
-               }
-       }
-
-       public function doGet()
-       {
-               $this->doPost('GET');
-       }
-
-       public function doPut()
-       {
-               $this->doPost('PUT');
+               return $this->decodeRequests($requestParam);
        }
 
-       public function doDelete()
+       private function getRouteFromParameter($pathInfo)
        {
-               $this->doPost('DELETE');
+               $pathInfo = substr($pathInfo, 1);
+               $indexOfNextPathSeparator = strpos($pathInfo, "/");
+               return $indexOfNextPathSeparator != - 1 ? substr($pathInfo, 0, 
$indexOfNextPathSeparator) : $pathInfo;
        }
 
        private function outputError(ResponseItem $response)
@@ -217,7 +338,6 @@
                        default:
                                $code = '500 Internal Server Error';
                                break;
-               
                }
                header("HTTP/1.0 $code", true);
                echo "$code - $errorMessage";
@@ -265,8 +385,13 @@
                return substr($_SERVER["REQUEST_URI"], 
strlen(Config::get('web_prefix') . '/social/rest'));
        }
 
-       public function isBatchUrl()
+       public function isJsonBatchUrl()
        {
                return strrpos($_SERVER["REQUEST_URI"], 
RestServlet::$JSON_BATCH_ROUTE) > 0;
        }
+
+       public function isBatchProxyUrl()
+       {
+               return strrpos($_SERVER["REQUEST_URI"], 
RestServlet::$BATCH_PROXY_ROUTE) > 0;
+       }
 }

Modified: 
incubator/shindig/trunk/php/src/social-api/samplecontainer/BasicAppDataService.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/social-api/samplecontainer/BasicAppDataService.php?rev=678068&r1=678067&r2=678068&view=diff
==============================================================================
--- 
incubator/shindig/trunk/php/src/social-api/samplecontainer/BasicAppDataService.php
 (original)
+++ 
incubator/shindig/trunk/php/src/social-api/samplecontainer/BasicAppDataService.php
 Fri Jul 18 15:47:41 2008
@@ -85,7 +85,7 @@
                switch($groupId->getType()) {
                        case 'self':
                                foreach ($fields as $key) {
-                                       $value = isset($values->$key) ? 
$values->$key : (@isset($values[$key]) ? @$values[$key] : null);
+                                       $value = isset($values[$key]) ? 
@$values[$key] : null;
                                        
XmlStateFileFetcher::get()->setAppData($userId->getUserId($token), $key, 
$value);       
                                }
                                break;

Modified: 
incubator/shindig/trunk/php/src/social-api/samplecontainer/BasicPeopleService.php
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/src/social-api/samplecontainer/BasicPeopleService.php?rev=678068&r1=678067&r2=678068&view=diff
==============================================================================
--- 
incubator/shindig/trunk/php/src/social-api/samplecontainer/BasicPeopleService.php
 (original)
+++ 
incubator/shindig/trunk/php/src/social-api/samplecontainer/BasicPeopleService.php
 Fri Jul 18 15:47:41 2008
@@ -76,7 +76,7 @@
                                if ($id == $token->getOwnerId()) {
                                        $person->setIsOwner(true);
                                }
-                               if (is_array($profileDetails) && 
count($profileDetails)) {
+                               if (is_array($profileDetails) && 
count($profileDetails) && !in_array('all', $profileDetails)) {
                                        $newPerson = array();
                                        $newPerson['isOwner'] = 
$person->isOwner;
                                        $newPerson['isViewer'] = 
$person->isViewer;


Reply via email to