blob: a945b4cfe7727e4cc218a7eb5a5e91e8e32390d4 [file] [log] [blame]
<?php
/** @package org.wookie.php */
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @ignore */
require("WookieConnectorExceptions.php");
require("WookieServerConnection.php");
require("WidgetInstances.php");
require("Widget.php");
require("WidgetInstance.php");
require("WidgetProperties.php");
require("User.php");
require("HTTP_Response.php");
require("Logger.php");
require("WookieConnectorServiceInterface.php");
/**
* Wookie connector service, handles all the data requests and responses
* @package org.wookie.php
*/
class WookieConnectorService implements WookieConnectorServiceInterface {
private $conn;
public $WidgetInstances;
private $user;
private $httpStreamCtx;
private $logger;
private $locale;
/** Create new connector
*
* @param String url to Wookie host
* @param String Wookie API key
* @param String shareddatakey to use
* @param String user login name
* @param String user display name
*/
function __construct($url, $apiKey, $sharedDataKey, $loginName, $screenName = null) {
$this->setConnection(new WookieServerConnection($url, $apiKey, $sharedDataKey));
$this->setWidgetInstancesHolder();
$this->setUser($loginName, $screenName);
$this->setHttpStreamContext(array('http' => array('timeout' => 15)));
$this->logger = new Logger("");
}
/** Initiate logger
* @param String path to writeable folder
*/
public function setLogPath($path) {
$this->getLogger()->setPath($path);
}
/** Get logger
* @return Logger Simple logger for ConnectorService
*/
private function getLogger() {
return $this->logger;
}
/** Set locale */
public function setLocale($locale) {
$this->locale = (string) $locale;
}
/** Get locale */
public function getLocale() {
return $this->locale;
}
/** Set Wookie connection
*
* @param WookieServerConnection new WookieServerConnection instance
*/
private function setConnection($newConn) {
$this->conn = $newConn;
}
/** Get current Wookie connection
* @return WookieServerConnection current Wookie server connection
*/
public function getConnection() {
return $this->conn;
}
/** Set WidgetInstances holder */
private function setWidgetInstancesHolder() {
$this->WidgetInstances = new WidgetInstances();
}
/** Set user for connection
*
* @param String username
* @param String optional display name
*/
public function setUser($loginName, $screenName = null) {
if($screenName == null) {
$screenName = $loginName;
}
$this->user = new User($loginName, $screenName);
}
/** Get current user
* @return User current connection user
*/
public function getUser() {
return $this->user;
}
/** Set HttpStreamContext parameters
*
* @param Array array of context parameters
*/
private function setHttpStreamContext($params) {
$this->httpStreamCtx = @stream_context_create($params);
}
/** Get HttpStreamContext
* @return StreamContextResource HttpStreamContext resource
*/
private function getHttpStreamContext() {
return $this->httpStreamCtx;
}
/** Do HTTP request
* @param String url to request
* @param String data to send
* @param String method to use
* @return HTTP_Response new HTTP_Response instance
*/
private function do_request($url, $data, $method = 'POST')
{
if(is_array($data)) {
// convert variables array to string:
$_data = array();
while(list($n,$v) = each($data)){
$_data[] = urlencode($n)."=".urlencode($v);
}
$data = implode('&', $_data);
}
$params = array('http' => array(
'method' => $method,
'content' => $data,
'timeout' => 15
));
$this->setHttpStreamContext($params);
$response = @file_get_contents($url, false, $this->getHttpStreamContext());
//revert back to default value for other requests
$this->setHttpStreamContext(array('http' => array('timeout' => 15)));
return new HTTP_Response($response, $http_response_header);
}
/**
*
* @param String $widgetFile - full path on disk where the widget is located
* @param unknown $adminUsername - wookie admin username
* @param unknown $adminPassword - wookie admin password
* @return HTTP_Response - new HTTP_Response instance
*/
public function postWidget($widgetFile, $adminUsername, $adminPassword){
$file = basename($widgetFile); //actual filename without the path
$fileContents = file_get_contents($widgetFile);
//Boundary definition
$boundary = substr(md5(rand(0,32000)), 0, 20);
$data = "--".$boundary . "\r\n";
$data .= "Content-Disposition: form-data; name=\"upload\"; filename=\"" . $file . "\"\r\n";
$data .= "Content-Type: application/octet-stream; charset=ISO-8859-1\r\n";
$data .= "Content-Transfer-Encoding: binary\r\n\r\n";
$data .= $fileContents."\r\n";
$data .= "--".$boundary. "--" . "\r\n";
//Construct params
$params = array('http' => array(
'method' => 'POST',
'header' => "Authorization: Basic " . base64_encode("$adminUsername:$adminPassword") . "\r\n" .
//"Connection: Keep-Alive" . "\r\n" .
"Content-Type: multipart/form-data;boundary=".$boundary ."\r\n",
'content' => $data,
'timeout' => 30
));
$this->setHttpStreamContext($params);
$requestUrl = $this->getConnection()->getURL().'widgets';
$response = @file_get_contents($requestUrl, false, $this->getHttpStreamContext());
//revert back to default value for other requests
$this->setHttpStreamContext(array('http' => array('timeout' => 15)));
return new HTTP_Response($response, $http_response_header);
}
/**
*
* @param String $requestUrl - a string url of where the widget is online
* @param unknown $adminUsername - wookie admin username
* @param unknown $adminPassword - wookie admin password
* @throws WookieConnectorException
* @return string - *should be the xml representation of the widget* - but for now a raw dump of the response by wookie
*/
public function postWidgetByUrl($requestUrl, $adminUsername, $adminPassword){
if(!isset($adminUsername) || !isset($adminUsername)){
throw new WookieConnectorException("Wookie admin username and password missing.");
}
$response = $this->do_request($requestUrl, null, 'GET');
if($response->getStatusCode() == 200) {
$filename = uniqid(rand(), true) . '.wgt';
$handle = fopen(sys_get_temp_dir() . $filename, "w");
fwrite($handle, $response->getResponseText());
$widgetResponse = $this->postWidget(sys_get_temp_dir() . $filename, $adminUsername, $adminPassword);
fclose($handle);
unlink(sys_get_temp_dir() . $filename);
if($response->getStatusCode() == 200 || $response->getStatusCode() == 201){
return simplexml_load_string($widgetResponse->getResponseText());
}
else{
throw new WookieConnectorException("Problem uploading the widget to " . $this->getConnection()->getURL().'widgets');
}
}
else{
throw new WookieConnectorException("Problem downloading the original widget from " . $requestUrl);
}
}
/**
* Get or create an instance of a widget.
*
* @param Widget|String instance of widget or guid
* @return WidgetInstance WidgetInstance if successful, otherwise false
* @throws WookieConnectorException
*/
public function getOrCreateInstance($Widget_or_GUID) {
try {
if($Widget_or_GUID instanceof Widget) {
$guid = $Widget_or_GUID->getIdentifier();
} else {
$guid = $Widget_or_GUID;
}
if($guid == '') {
throw new WookieConnectorException("No GUID nor Widget object");
}
$requestUrl = $this->getConnection()->getURL().'widgetinstances';
$request.= '&api_key='.$this->getConnection()->getApiKey();
$request.= '&userid='.$this->getUser()->getLoginName();
$request.= '&shareddatakey='.$this->getConnection()->getSharedDataKey();
$request.= '&widgetid='.$guid;
if($locale = $this->getLocale()) {
$request .= '&locale='.$locale;
}
if(!$this->checkURL($requestUrl)) {
throw new WookieConnectorException("URL for supplied Wookie Server is malformed: ".$requestUrl);
}
$response = $this->do_request($requestUrl, $request);
//if instance was created, perform second request to get widget instance
if($response->getStatusCode() == 201) {
$response = $this->do_request($requestUrl, $request);
}
if($response->getStatusCode() == 401) { throw new WookieConnectorException("Invalid API key"); }
$instance = $this->parseInstance($guid, $response->getResponseText());
if($instance) {
$this->WidgetInstances->put($instance);
//add current user as participant
$this->addParticipant($instance, $this->getUser());
}
return $instance;
} catch (WookieConnectorException $e) {
$this->getLogger()->write($e->toString());
}
return false;
}
/**
* Record an instance of the given widget.
*
* @param String widget guid
* @param String xml description of the instance as returned by the widget server when the widget was instantiated.
* @return new Widget instance or false
*/
private function parseInstance($widgetGuid, $xml) {
$xmlWidgetData = @simplexml_load_string($xml);
if($xmlWidgetData instanceof SimpleXMLElement) {
$url = (string) $xmlWidgetData->url;
$title = (string) $xmlWidgetData->title;
$height = (string) $xmlWidgetData->height;
$width = (string) $xmlWidgetData->width;
$instance = new WidgetInstance($url, $widgetGuid, $title, $height, $width);
return $instance;
}
return false;
}
/**
* Check if URL is parsable.
*
* @param String url to parse
* @return boolean true if parseable, otherwise false
*/
private function checkURL($url) {
$UrlCheck = @parse_url($url);
if($UrlCheck['scheme'] != 'http' || $UrlCheck['host'] == null || $UrlCheck['path'] == null) {
return false;
}
return true;
}
/**
* Add new participant
* @param WidgetInstance instance of WidgetInstance
* @param User instance of User
* @return boolean true - if added/exists - false if some error
* @throws WookieConnectorException
* @throws WookieWidgetInstanceException
*/
public function addParticipant($widgetInstance, $User) {
$Url = $this->getConnection()->getURL().'participants';
try {
if(!$widgetInstance instanceof WidgetInstance) throw new WookieWidgetInstanceException('No Widget instance');
if(!$User instanceof User) throw new WookieConnectorException('No User object');
$data = array(
'api_key' => $this->getConnection()->getApiKey(),
'shareddatakey' => $this->getConnection()->getSharedDataKey(),
'userid' => $this->getUser()->getLoginName(),
'widgetid' => $widgetInstance->getIdentifier(),
'participant_id' => $this->getUser()->getLoginName(),
'participant_display_name' => $User->getScreenName(),
'participant_thumbnail_url' => $User->getThumbnailUrl(),
'participant_role' => '' // TODO fix actual roles - (API change) Uncomment this to use wookie 0.13.1 onwards
);
if(!$this->checkURL($Url)) {
throw new WookieConnectorException("Participants rest URL is incorrect: ".$Url);
}
$response = $this->do_request($Url, $data);
$statusCode = $response->getStatusCode();
switch($statusCode) {
case 200: //participant already exists
return true;
break;
case 201:
return true; //new participant added
break;
case ($statusCode > 201):
throw new WookieConnectorException($response->headerToString().'<br />'.$response->getResponseText());
break;
}
} catch (WookieConnectorException $e) {
$this->getLogger()->write($e->toString());
} catch (WookieWidgetInstanceException $e) {
$this->getLogger()->write($e->toString());
}
return false;
}
/**
* Delete participant
* @param WidgetInstance instance of WidgetInstance
* @param User instance of User
* @return boolean true - if deleted, false - if not found
* @throws WookieConnectorException
* @throws WookieWidgetInstanceException
*/
public function deleteParticipant($widgetInstance, $User) {
$Url = $this->getConnection()->getURL().'participants';
try {
if(!$widgetInstance instanceof WidgetInstance) throw new WookieWidgetInstanceException('No Widget instance');
if(!$User instanceof User) throw new WookieConnectorException('No User object');
$request = '?api_key='.$this->getConnection()->getApiKey();
$request .= '&shareddatakey='.$this->getConnection()->getSharedDataKey();
$request .= '&userid='.$this->getUser()->getLoginName();
$request .= '&widgetid='.$widgetInstance->getIdentifier();
$request .= '&participant_id='.$User->getLoginName();
if(!$this->checkURL($Url)) {
throw new WookieConnectorException("Participants rest URL is incorrect: ".$Url);
}
$response = $this->do_request($Url.$request, false, 'DELETE');
$statusCode = $response->getStatusCode();
switch($statusCode) {
case 200: //participant deleted
return true;
break;
case 404:
return false; //participant not found
break;
case ($statusCode > 201):
throw new WookieConnectorException($response->headerToString().'<br />'.$response->getResponseText());
break;
}
} catch (WookieConnectorException $e) {
$this->getLogger()->write($e->toString());
} catch (WookieWidgetInstanceException $e) {
$this->getLogger()->write($e->toString());
}
return false;
}
/**
* Get the array of users for a widget instance
* @param WidgetInstance instance of WidgetInstance
* @return Array an array of users
* @throws WookieConnectorException
* @throws WookieWidgetInstanceException
*/
public function getUsers($widgetInstance) {
$Url = $this->getConnection()->getURL().'participants';
$Users = array();
try {
if(!$widgetInstance instanceof WidgetInstance) throw new WookieWidgetInstanceException('No Widget instance');
$request = '?api_key='.$this->getConnection()->getApiKey();
$request .= '&shareddatakey='.$this->getConnection()->getSharedDataKey();
$request .= '&userid='.$this->getUser()->getLoginName();
$request .= '&widgetid='.$widgetInstance->getIdentifier();
if(!$this->checkURL($Url)) {
throw new WookieConnectorException("Participants rest URL is incorrect: ".$Url);
}
$response = new HTTP_Response(@file_get_contents($Url.$request, false, $this->getHttpStreamContext()), $http_response_header);
if($response->getStatusCode() > 200) throw new WookieConnectorException($response->headerToString().'<br />'.$response->getResponseText());
$xmlObj = @simplexml_load_string($response->getResponseText());
if($xmlObj instanceof SimpleXMLElement) {
foreach($xmlObj->children() as $participant) {
$participantAttr = $participant->attributes();
$id = (string) $participantAttr->id;
$name = (string) $participantAttr->display_name;
$thumbnail_url = (string) $participantAttr->thumbnail_url;
$newUser = new User($id, $name, $thumbnail_url);
array_push($Users, $newUser);
}
} else {
throw new WookieConnectorException('Problem getting participants');
}
} catch (WookieWidgetInstanceException $e) {
$this->getLogger()->write($e->toString());
} catch (WookieConnectorException $e) {
$this->getLogger()->write($e->toString());
}
return $Users;
}
/**
* Get a set of all the available widgets in the server. If there is an error
* communicating with the server return an empty set, or the set received so
* far in order to allow the application to proceed. The application should
* display an appropriate message in this case.
*
* @return array array of available widgets
* @throws WookieConnectorException
*/
public function getAvailableWidgets() {
$widgets = array();
try {
$request = $this->getConnection()->getURL().'widgets?all=true';
if($locale = $this->getLocale()) {
$request .= '&locale='.$locale;
}
if(!$this->checkURL($request)) {
throw new WookieConnectorException("URL for Wookie is malformed");
}
$response = new HTTP_Response(@file_get_contents($request, false, $this->getHttpStreamContext()), $http_response_header);
$xmlObj = @simplexml_load_string($response->getResponseText());
if($xmlObj instanceof SimpleXMLElement) {
foreach($xmlObj->children() as $widget) {
$id = (string) $widget->attributes()->id;
$title = (string) $widget->title;
$description = (string) $widget->description;
$iconURL = (string) $widget->attributes()->icon;
if($iconURL == '') {
$iconURL = (string) 'http://www.oss-watch.ac.uk/images/logo2.gif';
}
$Widget = new Widget($id, $title, $description, $iconURL);
$widgets[$id] = $Widget;
}
} else {
throw new WookieConnectorException('Problem getting available widgets');
}
} catch(WookieConnectorException $e) {
$this->getLogger()->write($e->toString());
}
return $widgets;
}
/**
* Set property for Widget instance
* @param WidgetInstance instance of WidgetInstance
* @param Propety instance of Property
* @return Property new Property instance
* @throws WookieConnectorException, WookieWidgetInstanceException
*/
public function setProperty($widgetInstance, $propertyInstance) {
$Url = $this->getConnection()->getURL().'properties';
try {
if(!$widgetInstance instanceof WidgetInstance) throw new WookieWidgetInstanceException('No Widget instance');
if(!$propertyInstance instanceof Property) throw new WookieConnectorException('No properties instance');
$data = array(
'api_key' => $this->getConnection()->getApiKey(),
'shareddatakey' => $this->getConnection()->getSharedDataKey(),
'userid' => $this->getUser()->getLoginName(),
'widgetid' => $widgetInstance->getIdentifier(),
'propertyname' => $propertyInstance->getName(),
'propertyvalue' => $propertyInstance->getValue(),
'is_public' => $propertyInstance->getIsPublic(),
);
if(!$this->checkURL($Url)) {
throw new WookieConnectorException("Properties rest URL is incorrect: ".$Url);
}
$response = $this->do_request($Url, $data);
$statusCode = $response->getStatusCode();
switch($statusCode) {
case 201:
return $propertyInstance; //new property added, let's return initial Property instance
break;
case ($statusCode != 201):
throw new WookieConnectorException($response->headerToString().'<br />'.$response->getResponseText());
break;
}
} catch (WookieConnectorException $e) {
$this->getLogger()->write($e->toString());
} catch (WookieWidgetInstanceException $e) {
$this->getLogger()->write($e->toString());
}
return false;
}
/**
* Get property for Widget instance
* @param WidgetInstance instance of WidgetInstance
* @param Propety instance of Property
* @return Property if request fails, return false;
* @throws WookieConnectorException, WookieWidgetInstanceException
*/
public function getProperty($widgetInstance, $propertyInstance) {
$Url = $this->getConnection()->getURL().'properties';
try {
if(!$widgetInstance instanceof WidgetInstance) throw new WookieWidgetInstanceException('No Widget instance');
if(!$propertyInstance instanceof Property) throw new WookieConnectorException('No properties instance');
$data = array(
'api_key' => $this->getConnection()->getApiKey(),
'shareddatakey' => $this->getConnection()->getSharedDataKey(),
'userid' => $this->getUser()->getLoginName(),
'widgetid' => $widgetInstance->getIdentifier(),
'propertyname' => $propertyInstance->getName()
);
$request = @http_build_query($data);
if(!$this->checkURL($Url)) {
throw new WookieConnectorException("Properties rest URL is incorrect: ".$Url);
}
$response = new HTTP_Response(@file_get_contents($Url.'?'.$request, false, $this->getHttpStreamContext()), $http_response_header);
$statusCode = $response->getStatusCode();
if($statusCode != 200) {
throw new WookieConnectorException($response->headerToString().'<br />'.$response->getResponseText());
}
return new Property($propertyInstance->getName(), $response->getResponseText());
} catch (WookieConnectorException $e) {
$this->getLogger()->write($e->toString());
} catch (WookieWidgetInstanceException $e) {
$this->getLogger()->write($e->toString());
}
return false;
}
/**
* Delete property for Widget instance
* @param WidgetInstance instance of WidgetInstance
* @param Propety instance of Property
* @return boolean true/false -- true if deleted, false if doesnt exist
* @throws WookieConnectorException, WookieWidgetInstanceException
*/
public function deleteProperty($widgetInstance, $propertyInstance) {
$Url = $this->getConnection()->getURL().'properties';
try {
if(!$widgetInstance instanceof WidgetInstance) throw new WookieWidgetInstanceException('No Widget instance');
if(!$propertyInstance instanceof Property) throw new WookieConnectorException('No properties instance');
$request = '?api_key='.$this->getConnection()->getApiKey();
$request .= '&shareddatakey='.$this->getConnection()->getSharedDataKey();
$request .= '&userid='.$this->getUser()->getLoginName();
$request .= '&widgetid='.$widgetInstance->getIdentifier();
$request .= '&propertyname='.$propertyInstance->getName();
if(!$this->checkURL($Url)) {
throw new WookieConnectorException("Properties rest URL is incorrect: ".$Url);
}
$response = $this->do_request($Url.$request, false, 'DELETE');
$statusCode = $response->getStatusCode();
if($statusCode != 200 && $statusCode != 404) {
throw new WookieConnectorException($response->headerToString().'<br />'.$response->getResponseText());
}
if($statusCode == 404) {
return false;
}
return true;
} catch (WookieConnectorException $e) {
$this->getLogger()->write($e->toString());
} catch (WookieWidgetInstanceException $e) {
$this->getLogger()->write($e->toString());
}
return false;
}
}
?>