diff --git a/webservice/classes/rest/Abstract.php b/webservice/classes/rest/Abstract.php
new file mode 100644
index 0000000..7658a6d
--- /dev/null
+++ b/webservice/classes/rest/Abstract.php
@@ -0,0 +1,221 @@
+_table = new Rest_Definition();
+ $this->_table->setOverwriteExistingMethods($this->_overwriteExistingMethods);
+ }
+
+ /**
+ * Returns a list of registered methods
+ *
+ * Returns an array of method definitions.
+ *
+ * @return Rest_Definition
+ */
+ public function getFunctions()
+ {
+ return $this->_table;
+ }
+
+ /**
+ * Lowercase a string
+ *
+ * Lowercase's a string by reference
+ *
+ * @deprecated
+ * @param string $string value
+ * @param string $key
+ * @return string Lower cased string
+ */
+ public static function lowerCase(&$value, &$key)
+ {
+ trigger_error(__CLASS__ . '::' . __METHOD__ . '() is deprecated and will be removed in a future version', E_USER_NOTICE);
+ return $value = strtolower($value);
+ }
+
+ /**
+ * Build callback for method signature
+ *
+ * @param Rest_Reflection_Function_Abstract $reflection
+ * @return Rest_Method_Callback
+ */
+ protected function _buildCallback(Rest_Reflection_Function_Abstract $reflection)
+ {
+ $callback = new Rest_Method_Callback();
+ if ($reflection instanceof Rest_Reflection_Method) {
+ $callback->setType($reflection->isStatic() ? 'static' : 'instance')
+ ->setClass($reflection->getDeclaringClass()->getName())
+ ->setMethod($reflection->getName());
+ } elseif ($reflection instanceof Rest_Reflection_Function) {
+ $callback->setType('function')
+ ->setFunction($reflection->getName());
+ }
+ return $callback;
+ }
+
+ /**
+ * Build a method signature
+ *
+ * @param Rest_Reflection_Function_Abstract $reflection
+ * @param null|string|object $class
+ * @return Rest_Method_Definition
+ * @throws Rest_Exception on duplicate entry
+ */
+ protected function _buildSignature(Rest_Reflection_Function_Abstract $reflection, $class = null)
+ {
+ $ns = $reflection->getNamespace();
+ $name = $reflection->getName();
+ $method = empty($ns) ? $name : $ns . '.' . $name;
+
+ if (!$this->_overwriteExistingMethods && $this->_table->hasMethod($method)) {
+ require_once 'Exception.php';
+ throw new Rest_Exception('Duplicate method registered: ' . $method);
+ }
+
+ $definition = new Rest_Method_Definition();
+ $definition->setName($method)
+ ->setCallback($this->_buildCallback($reflection))
+ ->setMethodHelp($reflection->getDescription())
+ ->setInvokeArguments($reflection->getInvokeArguments());
+
+ foreach ($reflection->getPrototypes() as $proto) {
+ $prototype = new Rest_Method_Prototype();
+ $prototype->setReturnType($this->_fixType($proto->getReturnType()));
+ foreach ($proto->getParameters() as $parameter) {
+ $param = new Rest_Method_Parameter(array(
+ 'type' => $this->_fixType($parameter->getType()),
+ 'name' => $parameter->getName(),
+ 'optional' => $parameter->isOptional(),
+ ));
+ if ($parameter->isDefaultValueAvailable()) {
+ $param->setDefaultValue($parameter->getDefaultValue());
+ }
+ $prototype->addParameter($param);
+ }
+ $definition->addPrototype($prototype);
+ }
+ if (is_object($class)) {
+ $definition->setObject($class);
+ }
+ $this->_table->addMethod($definition);
+ return $definition;
+ }
+
+ /**
+ * Dispatch method
+ *
+ * @param Rest_Method_Definition $invocable
+ * @param array $params
+ * @return mixed
+ */
+ protected function _dispatch(Rest_Method_Definition $invocable, array $params)
+ {
+ $callback = $invocable->getCallback();
+ $type = $callback->getType();
+
+ if ('function' == $type) {
+ $function = $callback->getFunction();
+ return call_user_func_array($function, $params);
+ }
+
+ $class = $callback->getClass();
+ $method = $callback->getMethod();
+
+ if ('static' == $type) {
+ return call_user_func_array(array($class, $method), $params);
+ }
+
+ $object = $invocable->getObject();
+ if (!is_object($object)) {
+ $invokeArgs = $invocable->getInvokeArguments();
+ if (!empty($invokeArgs)) {
+ $reflection = new ReflectionClass($class);
+ $object = $reflection->newInstanceArgs($invokeArgs);
+ } else {
+ $object = new $class;
+ }
+ }
+ return call_user_func_array(array($object, $method), $params);
+ }
+
+ /**
+ * Map PHP type to protocol type
+ *
+ * @param string $type
+ * @return string
+ */
+ abstract protected function _fixType($type);
+}
diff --git a/webservice/classes/rest/Definition.php b/webservice/classes/rest/Definition.php
new file mode 100644
index 0000000..c271de3
--- /dev/null
+++ b/webservice/classes/rest/Definition.php
@@ -0,0 +1,243 @@
+setMethods($methods);
+ }
+ }
+
+ /**
+ * Set flag indicating whether or not overwriting existing methods is allowed
+ *
+ * @param mixed $flag
+ * @return void
+ */
+ public function setOverwriteExistingMethods($flag)
+ {
+ $this->_overwriteExistingMethods = (bool) $flag;
+ return $this;
+ }
+
+ /**
+ * Add method to definition
+ *
+ * @param array|Rest_Method_Definition $method
+ * @param null|string $name
+ * @return Rest_Definition
+ * @throws Rest_Exception if duplicate or invalid method provided
+ */
+ public function addMethod($method, $name = null)
+ {
+ if (is_array($method)) {
+ require_once 'classes/rest/method/Definition.php';
+ $method = new Rest_Method_Definition($method);
+ } elseif (!$method instanceof Rest_Method_Definition) {
+ require_once 'Exception.php';
+ throw new Rest_Exception('Invalid method provided');
+ }
+
+ if (is_numeric($name)) {
+ $name = null;
+ }
+ if (null !== $name) {
+ $method->setName($name);
+ } else {
+ $name = $method->getName();
+ }
+ if (null === $name) {
+ require_once 'Exception.php';
+ throw new Rest_Exception('No method name provided');
+ }
+
+ if (!$this->_overwriteExistingMethods && array_key_exists($name, $this->_methods)) {
+ require_once 'Exception.php';
+ throw new Rest_Exception(sprintf('Method by name of "%s" already exists', $name));
+ }
+ $this->_methods[$name] = $method;
+ return $this;
+ }
+
+ /**
+ * Add multiple methods
+ *
+ * @param array $methods Array of Rest_Method_Definition objects or arrays
+ * @return Rest_Definition
+ */
+ public function addMethods(array $methods)
+ {
+ foreach ($methods as $key => $method) {
+ $this->addMethod($method, $key);
+ }
+ return $this;
+ }
+
+ /**
+ * Set all methods at once (overwrite)
+ *
+ * @param array $methods Array of Rest_Method_Definition objects or arrays
+ * @return Rest_Definition
+ */
+ public function setMethods(array $methods)
+ {
+ $this->clearMethods();
+ $this->addMethods($methods);
+ return $this;
+ }
+
+ /**
+ * Does the definition have the given method?
+ *
+ * @param string $method
+ * @return bool
+ */
+ public function hasMethod($method)
+ {
+ return array_key_exists($method, $this->_methods);
+ }
+
+ /**
+ * Get a given method definition
+ *
+ * @param string $method
+ * @return null|Rest_Method_Definition
+ */
+ public function getMethod($method)
+ {
+ if ($this->hasMethod($method)) {
+ return $this->_methods[$method];
+ }
+ return false;
+ }
+
+ /**
+ * Get all method definitions
+ *
+ * @return array Array of Rest_Method_Definition objects
+ */
+ public function getMethods()
+ {
+ return $this->_methods;
+ }
+
+ /**
+ * Remove a method definition
+ *
+ * @param string $method
+ * @return Rest_Definition
+ */
+ public function removeMethod($method)
+ {
+ if ($this->hasMethod($method)) {
+ unset($this->_methods[$method]);
+ }
+ return $this;
+ }
+
+ /**
+ * Clear all method definitions
+ *
+ * @return Rest_Definition
+ */
+ public function clearMethods()
+ {
+ $this->_methods = array();
+ return $this;
+ }
+
+ /**
+ * Cast definition to an array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $methods = array();
+ foreach ($this->getMethods() as $key => $method) {
+ $methods[$key] = $method->toArray();
+ }
+ return $methods;
+ }
+
+ /**
+ * Countable: count of methods
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->_methods);
+ }
+
+ /**
+ * Iterator: current item
+ *
+ * @return mixed
+ */
+ public function current()
+ {
+ return current($this->_methods);
+ }
+
+ /**
+ * Iterator: current item key
+ *
+ * @return int|string
+ */
+ public function key()
+ {
+ return key($this->_methods);
+ }
+
+ /**
+ * Iterator: advance to next method
+ *
+ * @return void
+ */
+ public function next()
+ {
+ return next($this->_methods);
+ }
+
+ /**
+ * Iterator: return to first method
+ *
+ * @return void
+ */
+ public function rewind()
+ {
+ return reset($this->_methods);
+ }
+
+ /**
+ * Iterator: is the current index valid?
+ *
+ * @return bool
+ */
+ public function valid()
+ {
+ return (bool) $this->current();
+ }
+}
diff --git a/webservice/classes/rest/Exception.php b/webservice/classes/rest/Exception.php
new file mode 100644
index 0000000..d497f47
--- /dev/null
+++ b/webservice/classes/rest/Exception.php
@@ -0,0 +1,14 @@
+.
+*
+* You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
+* California 94120-7775, or email info@knowledgetree.com.
+*
+* The interactive user interfaces in modified source and object code versions
+* of this program must display Appropriate Legal Notices, as required under
+* Section 5 of the GNU General Public License version 3.
+*
+* In accordance with Section 7(b) of the GNU General Public License version 3,
+* these Appropriate Legal Notices must retain the display of the "Powered by
+* KnowledgeTree" logo and retain the original copyright notice. If the display of the
+* logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
+* must display the words "Powered by KnowledgeTree" and retain the original
+* copyright notice.
+*
+* @copyright 2008-2009, KnowledgeTree Inc.
+* @license GNU General Public License version 3
+* @author KnowledgeTree Team
+* @package Webservice
+* @version Version 0.1
+*/
+
+/**
+ * Rest_Interface
+ */
+require_once 'classes/rest/Interface.php';
+
+/**
+ * Rest_Reflection
+ */
+require_once 'classes/rest/Reflection.php';
+
+/**
+ * Rest_Abstract
+ */
+require_once 'classes/rest/Abstract.php';
+
+/**
+ * Rest_Exception
+ *
+ */
+require_once 'classes/rest/Exception.php';
+
+class Rest_Server implements Rest_Interface
+{
+ /**
+ * Class Constructor Args
+ * @var array
+ */
+ protected $_args = array();
+
+ /**
+ * @var string Encoding
+ */
+ protected $_encoding = 'UTF-8';
+
+ /**
+ * @var array An array of Rest_Reflect_Method
+ */
+ protected $_functions = array();
+
+ /**
+ * @var array Array of headers to send
+ */
+ protected $_headers = array();
+
+ /**
+ * @var array PHP's Magic Methods, these are ignored
+ */
+ protected static $magicMethods = array(
+ '__construct',
+ '__destruct',
+ '__get',
+ '__set',
+ '__call',
+ '__sleep',
+ '__wakeup',
+ '__isset',
+ '__unset',
+ '__tostring',
+ '__clone',
+ '__set_state',
+ );
+
+ /**
+ * @var string Current Method
+ */
+ protected $_method;
+
+ /**
+ * @var Rest_Reflection
+ */
+ protected $_reflection = null;
+
+ /**
+ * Whether or not {@link handle()} should send output or return the response.
+ * @var boolean Defaults to false
+ */
+ protected $_returnResponse = false;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ set_exception_handler(array($this, "fault"));
+ $this->_reflection = new Rest_Reflection();
+ }
+
+ /**
+ * Set XML encoding
+ *
+ * @param string $encoding
+ * @return Rest_Server
+ */
+ public function setEncoding($encoding)
+ {
+ $this->_encoding = (string) $encoding;
+ return $this;
+ }
+
+ /**
+ * Get XML encoding
+ *
+ * @return string
+ */
+ public function getEncoding()
+ {
+ return $this->_encoding;
+ }
+
+ /**
+ * Lowercase a string
+ *
+ * Lowercase's a string by reference
+ *
+ * @param string $value
+ * @param string $key
+ * @return string Lower cased string
+ */
+ public static function lowerCase(&$value, &$key)
+ {
+ return $value = strtolower($value);
+ }
+
+ /**
+ * Whether or not to return a response
+ *
+ * If called without arguments, returns the value of the flag. If called
+ * with an argument, sets the flag.
+ *
+ * When 'return response' is true, {@link handle()} will not send output,
+ * but will instead return the response from the dispatched function/method.
+ *
+ * @param boolean $flag
+ * @return boolean|Rest_Server Returns Rest_Server when used to set the flag; returns boolean flag value otherwise.
+ */
+ public function returnResponse($flag = null)
+ {
+ if (null == $flag) {
+ return $this->_returnResponse;
+ }
+
+ $this->_returnResponse = ($flag) ? true : false;
+ return $this;
+ }
+
+ /**
+ * Implement Rest_Interface::handle()
+ *
+ * @param array $request
+ * @throws Rest_Server_Exception
+ * @return string|void
+ */
+ public function handle($request = false)
+ {
+ $this->_headers = array('Content-Type: text/xml');
+ if (!$request) {
+ $request = $_REQUEST;
+ }
+ if (isset($request['method'])) {
+ $this->_method = $request['method'];
+ if (isset($this->_functions[$this->_method])) {
+ if ($this->_functions[$this->_method] instanceof Rest_Reflection_Function || $this->_functions[$this->_method] instanceof Rest_Reflection_Method && $this->_functions[$this->_method]->isPublic()) {
+ $request_keys = array_keys($request);
+ array_walk($request_keys, array(__CLASS__, "lowerCase"));
+ $request = array_combine($request_keys, $request);
+
+ $func_args = $this->_functions[$this->_method]->getParameters();
+
+ $calling_args = array();
+ foreach ($func_args as $arg) {
+ if (isset($request[strtolower($arg->getName())])) {
+ $calling_args[] = $request[strtolower($arg->getName())];
+ } elseif ($arg->isOptional()) {
+ $calling_args[] = $arg->getDefaultValue();
+ }
+ }
+
+ foreach ($request as $key => $value) {
+ if (substr($key, 0, 3) == 'arg') {
+ $key = str_replace('arg', '', $key);
+ $calling_args[$key] = $value;
+ }
+ }
+
+ // Sort arguments by key -- @see ZF-2279
+ ksort($calling_args);
+
+ $result = false;
+ if (count($calling_args) < count($func_args)) {
+ $result = $this->fault(new Rest_Exception('Invalid Method Call to ' . $this->_method . '. Requires ' . count($func_args) . ', ' . count($calling_args) . ' given.'), 400);
+ }
+
+ if (!$result && $this->_functions[$this->_method] instanceof Rest_Reflection_Method) {
+ // Get class
+ $class = $this->_functions[$this->_method]->getDeclaringClass()->getName();
+
+ if ($this->_functions[$this->_method]->isStatic()) {
+ // for some reason, invokeArgs() does not work the same as
+ // invoke(), and expects the first argument to be an object.
+ // So, using a callback if the method is static.
+ $result = $this->_callStaticMethod($class, $calling_args);
+ } else {
+ // Object method
+ $result = $this->_callObjectMethod($class, $calling_args);
+ }
+ } elseif (!$result) {
+ try {
+ $result = call_user_func_array($this->_functions[$this->_method]->getName(), $calling_args); //$this->_functions[$this->_method]->invokeArgs($calling_args);
+ } catch (Exception $e) {
+ $result = $this->fault($e);
+ }
+ }
+ } else {
+
+ $result = $this->fault(
+ new Rest_Exception("Unknown Method '$this->_method'."),
+ 404
+ );
+ }
+ } else {
+ $result = $this->fault(
+ new Rest_Exception("Unknown Method '$this->_method'."),
+ 404
+ );
+ }
+ } else {
+ $result = $this->fault(
+ new Rest_Exception("No Method Specified."),
+ 404
+ );
+ }
+
+ if ($result instanceof SimpleXMLElement) {
+ $response = $result->asXML();
+ } elseif ($result instanceof DOMDocument) {
+ $response = $result->saveXML();
+ } elseif ($result instanceof DOMNode) {
+ $response = $result->ownerDocument->saveXML($result);
+ } elseif (is_array($result) || is_object($result)) {
+ $response = $this->_handleStruct($result);
+ } else {
+ $response = $this->_handleScalar($result);
+ }
+
+ if (!$this->returnResponse()) {
+ if (!headers_sent()) {
+ foreach ($this->_headers as $header) {
+ header($header);
+ }
+ }
+
+ echo $response;
+ return;
+ }
+
+ return $response;
+ }
+
+ /**
+ * Implement Rest_Interface::setClass()
+ *
+ * @param string $classname Class name
+ * @param string $namespace Class namespace (unused)
+ * @param array $argv An array of Constructor Arguments
+ */
+ public function setClass($classname, $namespace = '', $argv = array())
+ {
+ $this->_args = $argv;
+ foreach ($this->_reflection->reflectClass($classname, $argv)->getMethods() as $method) {
+ $this->_functions[$method->getName()] = $method;
+ }
+ }
+
+ /**
+ * Handle an array or object result
+ *
+ * @param array|object $struct Result Value
+ * @return string XML Response
+ */
+ protected function _handleStruct($struct)
+ {
+ $function = $this->_functions[$this->_method];
+ if ($function instanceof Rest_Reflection_Method) {
+ $class = $function->getDeclaringClass()->getName();
+ } else {
+ $class = false;
+ }
+
+ $method = $function->getName();
+
+ $dom = new DOMDocument('1.0', $this->getEncoding());
+ if ($class) {
+ $root = $dom->createElement($class);
+ $method = $dom->createElement($method);
+ $root->appendChild($method);
+ } else {
+ $root = $dom->createElement($method);
+ $method = $root;
+ }
+ $root->setAttribute('generator', 'Knowledgetree');
+ $root->setAttribute('version', '1.0');
+ $dom->appendChild($root);
+
+ $this->_structValue($struct, $dom, $method);
+
+ $struct = (array) $struct;
+ if (!isset($struct['status'])) {
+ $status = $dom->createElement('status', 'success');
+ $method->appendChild($status);
+ }
+
+ return $dom->saveXML();
+ }
+
+ /**
+ * Recursively iterate through a struct
+ *
+ * Recursively iterates through an associative array or object's properties
+ * to build XML response.
+ *
+ * @param mixed $struct
+ * @param DOMDocument $dom
+ * @param DOMElement $parent
+ * @return void
+ */
+ protected function _structValue($struct, DOMDocument $dom, DOMElement $parent)
+ {
+ $struct = (array) $struct;
+
+ foreach ($struct as $key => $value) {
+ if ($value === false) {
+ $value = 0;
+ } elseif ($value === true) {
+ $value = 1;
+ }
+
+ if (ctype_digit((string) $key)) {
+ $key = 'key_' . $key;
+ }
+
+ if (is_array($value) || is_object($value)) {
+ $element = $dom->createElement($key);
+ $this->_structValue($value, $dom, $element);
+ } else {
+ $element = $dom->createElement($key);
+ $element->appendChild($dom->createTextNode($value));
+ }
+
+ $parent->appendChild($element);
+ }
+ }
+
+ /**
+ * Handle a single value
+ *
+ * @param string|int|boolean $value Result value
+ * @return string XML Response
+ */
+ protected function _handleScalar($value)
+ {
+ $function = $this->_functions[$this->_method];
+ if ($function instanceof Rest_Reflection_Method) {
+ $class = $function->getDeclaringClass()->getName();
+ } else {
+ $class = false;
+ }
+
+ $method = $function->getName();
+
+ $dom = new DOMDocument('1.0', $this->getEncoding());
+ if ($class) {
+ $xml = $dom->createElement($class);
+ $methodNode = $dom->createElement($method);
+ $xml->appendChild($methodNode);
+ } else {
+ $xml = $dom->createElement($method);
+ $methodNode = $xml;
+ }
+ $xml->setAttribute('generator', 'KnowledgeTree');
+ $xml->setAttribute('version', '1.0');
+ $dom->appendChild($xml);
+
+ if ($value === false) {
+ $value = 0;
+ } elseif ($value === true) {
+ $value = 1;
+ }
+
+ if (isset($value)) {
+ $element = $dom->createElement('response');
+ $element->appendChild($dom->createTextNode($value));
+ $methodNode->appendChild($element);
+ } else {
+ $methodNode->appendChild($dom->createElement('response'));
+ }
+
+ $methodNode->appendChild($dom->createElement('status', 'success'));
+
+ return $dom->saveXML();
+ }
+
+ /**
+ * Implement Rest_Interface::fault()
+ *
+ * Creates XML error response, returning DOMDocument with response.
+ *
+ * @param string|Exception $fault Message
+ * @param int $code Error Code
+ * @return DOMDocument
+ */
+ public function fault($exception = null, $code = null)
+ {
+ if (isset($this->_functions[$this->_method])) {
+ $function = $this->_functions[$this->_method];
+ } elseif (isset($this->_method)) {
+ $function = $this->_method;
+ } else {
+ $function = 'rest';
+ }
+
+ if ($function instanceof Rest_Reflection_Method) {
+ $class = $function->getDeclaringClass()->getName();
+ } else {
+ $class = false;
+ }
+
+ if ($function instanceof Rest_Reflection_Function_Abstract) {
+ $method = $function->getName();
+ } else {
+ $method = $function;
+ }
+
+ $dom = new DOMDocument('1.0', $this->getEncoding());
+ if ($class) {
+ $xml = $dom->createElement($class);
+ $xmlMethod = $dom->createElement($method);
+ $xml->appendChild($xmlMethod);
+ } else {
+ $xml = $dom->createElement($method);
+ $xmlMethod = $xml;
+ }
+ $xml->setAttribute('generator', 'KnowledgeTree');
+ $xml->setAttribute('version', '1.0');
+ $dom->appendChild($xml);
+
+ $xmlResponse = $dom->createElement('response');
+ $xmlMethod->appendChild($xmlResponse);
+
+ if ($exception instanceof Exception) {
+ $element = $dom->createElement('message');
+ $element->appendChild($dom->createTextNode($exception->getMessage()));
+ $xmlResponse->appendChild($element);
+ $code = $exception->getCode();
+ } elseif (($exception !== null) || 'rest' == $function) {
+ $xmlResponse->appendChild($dom->createElement('message', 'An unknown error occured. Please try again.'));
+ } else {
+ $xmlResponse->appendChild($dom->createElement('message', 'Call to ' . $method . ' failed.'));
+ }
+
+ $xmlMethod->appendChild($xmlResponse);
+ $xmlMethod->appendChild($dom->createElement('status', 'failed'));
+
+ // Headers to send
+ if ($code === null || (404 != $code)) {
+ $this->_headers[] = 'HTTP/1.0 400 Bad Request';
+ } else {
+ $this->_headers[] = 'HTTP/1.0 404 File Not Found';
+ }
+
+ return $dom;
+ }
+
+ /**
+ * Retrieve any HTTP extra headers set by the server
+ *
+ * @return array
+ */
+ public function getHeaders()
+ {
+ return $this->_headers;
+ }
+
+ /**
+ * Implement Rest_Interface::addFunction()
+ *
+ * @param string $function Function Name
+ * @param string $namespace Function namespace (unused)
+ */
+ public function addFunction($function, $namespace = '')
+ {
+ if (!is_array($function)) {
+ $function = (array) $function;
+ }
+
+ foreach ($function as $func) {
+ if (is_callable($func) && !in_array($func, self::$magicMethods)) {
+ $this->_functions[$func] = $this->_reflection->reflectFunction($func);
+ } else {
+ throw new Rest_Exception("Invalid Method Added to Service.");
+ }
+ }
+ }
+
+ /**
+ * Implement Rest_Interface::getFunctions()
+ *
+ * @return array An array of Rest_Reflection_Method's
+ */
+ public function getFunctions()
+ {
+ return $this->_functions;
+ }
+
+ /**
+ * Implement Rest_Interface::loadFunctions()
+ *
+ * @todo Implement
+ * @param array $functions
+ */
+ public function loadFunctions($functions)
+ {
+ }
+
+ /**
+ * Implement Rest_Interface::setPersistence()
+ *
+ * @todo Implement
+ * @param int $mode
+ */
+ public function setPersistence($mode)
+ {
+ }
+
+ /**
+ * Call a static class method and return the result
+ *
+ * @param string $class
+ * @param array $args
+ * @return mixed
+ */
+ protected function _callStaticMethod($class, array $args)
+ {
+ try {
+ $result = call_user_func_array(array($class, $this->_functions[$this->_method]->getName()), $args);
+ } catch (Exception $e) {
+ $result = $this->fault($e);
+ }
+ return $result;
+ }
+
+ /**
+ * Call an instance method of an object
+ *
+ * @param string $class
+ * @param array $args
+ * @return mixed
+ * @throws Rest_Exception For invalid class name
+ */
+ protected function _callObjectMethod($class, array $args)
+ {
+ try {
+ if ($this->_functions[$this->_method]->getDeclaringClass()->getConstructor()) {
+ $object = $this->_functions[$this->_method]->getDeclaringClass()->newInstanceArgs($this->_args);
+ } else {
+ $object = $this->_functions[$this->_method]->getDeclaringClass()->newInstance();
+ }
+ } catch (Exception $e) {
+ echo $e->getMessage();
+ throw new Rest_Exception('Error instantiating class ' . $class . ' to invoke method ' . $this->_functions[$this->_method]->getName(), 500);
+ }
+
+ try {
+ $result = $this->_functions[$this->_method]->invokeArgs($object, $args);
+ } catch (Exception $e) {
+ $result = $this->fault($e);
+ }
+
+ return $result;
+ }
+}
diff --git a/webservice/classes/rest/method/Callback.php b/webservice/classes/rest/method/Callback.php
new file mode 100644
index 0000000..e3b808a
--- /dev/null
+++ b/webservice/classes/rest/method/Callback.php
@@ -0,0 +1,179 @@
+setOptions($options);
+ }
+ }
+
+ /**
+ * Set object state from array of options
+ *
+ * @param array $options
+ * @return Rest_Method_Callback
+ */
+ public function setOptions(array $options)
+ {
+ foreach ($options as $key => $value) {
+ $method = 'set' . ucfirst($key);
+ if (method_exists($this, $method)) {
+ $this->$method($value);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set callback class
+ *
+ * @param string $class
+ * @return Rest_Method_Callback
+ */
+ public function setClass($class)
+ {
+ if (is_object($class)) {
+ $class = get_class($class);
+ }
+ $this->_class = $class;
+ return $this;
+ }
+
+ /**
+ * Get callback class
+ *
+ * @return string|null
+ */
+ public function getClass()
+ {
+ return $this->_class;
+ }
+
+ /**
+ * Set callback function
+ *
+ * @param string $function
+ * @return Rest_Method_Callback
+ */
+ public function setFunction($function)
+ {
+ $this->_function = (string) $function;
+ $this->setType('function');
+ return $this;
+ }
+
+ /**
+ * Get callback function
+ *
+ * @return null|string
+ */
+ public function getFunction()
+ {
+ return $this->_function;
+ }
+
+ /**
+ * Set callback class method
+ *
+ * @param string $method
+ * @return Rest_Method_Callback
+ */
+ public function setMethod($method)
+ {
+ $this->_method = $method;
+ return $this;
+ }
+
+ /**
+ * Get callback class method
+ *
+ * @return null|string
+ */
+ public function getMethod()
+ {
+ return $this->_method;
+ }
+
+ /**
+ * Set callback type
+ *
+ * @param string $type
+ * @return Rest_Method_Callback
+ * @throws Exception
+ */
+ public function setType($type)
+ {
+ if (!in_array($type, $this->_types)) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid method callback type passed to ' . __CLASS__ . '::' . __METHOD__);
+ }
+ $this->_type = $type;
+ return $this;
+ }
+
+ /**
+ * Get callback type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Cast callback to array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $type = $this->getType();
+ $array = array(
+ 'type' => $type,
+ );
+ if ('function' == $type) {
+ $array['function'] = $this->getFunction();
+ } else {
+ $array['class'] = $this->getClass();
+ $array['method'] = $this->getMethod();
+ }
+ return $array;
+ }
+}
diff --git a/webservice/classes/rest/method/Definition.php b/webservice/classes/rest/method/Definition.php
new file mode 100644
index 0000000..17720e5
--- /dev/null
+++ b/webservice/classes/rest/method/Definition.php
@@ -0,0 +1,267 @@
+setOptions($options);
+ }
+ }
+
+ /**
+ * Set object state from options
+ *
+ * @param array $options
+ * @return Rest_Method_Definition
+ */
+ public function setOptions(array $options)
+ {
+ foreach ($options as $key => $value) {
+ $method = 'set' . ucfirst($key);
+ if (method_exists($this, $method)) {
+ $this->$method($value);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set method name
+ *
+ * @param string $name
+ * @return Rest_Method_Definition
+ */
+ public function setName($name)
+ {
+ $this->_name = (string) $name;
+ return $this;
+ }
+
+ /**
+ * Get method name
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Set method callback
+ *
+ * @param array|Rest_Method_Callback $callback
+ * @return Rest_Method_Definition
+ */
+ public function setCallback($callback)
+ {
+ if (is_array($callback)) {
+ $callback = new Rest_Method_Callback($callback);
+ } elseif (!$callback instanceof Rest_Method_Callback) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid method callback provided');
+ }
+ $this->_callback = $callback;
+ return $this;
+ }
+
+ /**
+ * Get method callback
+ *
+ * @return Rest_Method_Callback
+ */
+ public function getCallback()
+ {
+ return $this->_callback;
+ }
+
+ /**
+ * Add prototype to method definition
+ *
+ * @param array|Rest_Method_Prototype $prototype
+ * @return Rest_Method_Definition
+ */
+ public function addPrototype($prototype)
+ {
+ if (is_array($prototype)) {
+ require_once 'Prototype.php';
+ $prototype = new Rest_Method_Prototype($prototype);
+ } elseif (!$prototype instanceof Rest_Method_Prototype) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid method prototype provided');
+ }
+ $this->_prototypes[] = $prototype;
+ return $this;
+ }
+
+ /**
+ * Add multiple prototypes at once
+ *
+ * @param array $prototypes Array of Rest_Method_Prototype objects or arrays
+ * @return Rest_Method_Definition
+ */
+ public function addPrototypes(array $prototypes)
+ {
+ foreach ($prototypes as $prototype) {
+ $this->addPrototype($prototype);
+ }
+ return $this;
+ }
+
+ /**
+ * Set all prototypes at once (overwrites)
+ *
+ * @param array $prototypes Array of Rest_Method_Prototype objects or arrays
+ * @return Rest_Method_Definition
+ */
+ public function setPrototypes(array $prototypes)
+ {
+ $this->_prototypes = array();
+ $this->addPrototypes($prototypes);
+ return $this;
+ }
+
+ /**
+ * Get all prototypes
+ *
+ * @return array $prototypes Array of Rest_Method_Prototype objects or arrays
+ */
+ public function getPrototypes()
+ {
+ return $this->_prototypes;
+ }
+
+ /**
+ * Set method help
+ *
+ * @param string $methodHelp
+ * @return Rest_Method_Definition
+ */
+ public function setMethodHelp($methodHelp)
+ {
+ $this->_methodHelp = (string) $methodHelp;
+ return $this;
+ }
+
+ /**
+ * Get method help
+ *
+ * @return string
+ */
+ public function getMethodHelp()
+ {
+ return $this->_methodHelp;
+ }
+
+ /**
+ * Set object to use with method calls
+ *
+ * @param object $object
+ * @return Rest_Method_Definition
+ */
+ public function setObject($object)
+ {
+ if (!is_object($object) && (null !== $object)) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid object passed to ' . __CLASS__ . '::' . __METHOD__);
+ }
+ $this->_object = $object;
+ return $this;
+ }
+
+ /**
+ * Get object to use with method calls
+ *
+ * @return null|object
+ */
+ public function getObject()
+ {
+ return $this->_object;
+ }
+
+ /**
+ * Set invoke arguments
+ *
+ * @param array $invokeArguments
+ * @return Rest_Method_Definition
+ */
+ public function setInvokeArguments(array $invokeArguments)
+ {
+ $this->_invokeArguments = $invokeArguments;
+ return $this;
+ }
+
+ /**
+ * Retrieve invoke arguments
+ *
+ * @return array
+ */
+ public function getInvokeArguments()
+ {
+ return $this->_invokeArguments;
+ }
+
+ /**
+ * Serialize to array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $prototypes = $this->getPrototypes();
+ $signatures = array();
+ foreach ($prototypes as $prototype) {
+ $signatures[] = $prototype->toArray();
+ }
+
+ return array(
+ 'name' => $this->getName(),
+ 'callback' => $this->getCallback()->toArray(),
+ 'prototypes' => $signatures,
+ 'methodHelp' => $this->getMethodHelp(),
+ 'invokeArguments' => $this->getInvokeArguments(),
+ 'object' => $this->getObject(),
+ );
+ }
+}
diff --git a/webservice/classes/rest/method/Parameter.php b/webservice/classes/rest/method/Parameter.php
new file mode 100644
index 0000000..6abaf20
--- /dev/null
+++ b/webservice/classes/rest/method/Parameter.php
@@ -0,0 +1,191 @@
+setOptions($options);
+ }
+ }
+
+ /**
+ * Set object state from array of options
+ *
+ * @param array $options
+ * @return Rest_Method_Parameter
+ */
+ public function setOptions(array $options)
+ {
+ foreach ($options as $key => $value) {
+ $method = 'set' . ucfirst($key);
+ if (method_exists($this, $method)) {
+ $this->$method($value);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set default value
+ *
+ * @param mixed $defaultValue
+ * @return Rest_Method_Parameter
+ */
+ public function setDefaultValue($defaultValue)
+ {
+ $this->_defaultValue = $defaultValue;
+ return $this;
+ }
+
+ /**
+ * Retrieve default value
+ *
+ * @return mixed
+ */
+ public function getDefaultValue()
+ {
+ return $this->_defaultValue;
+ }
+
+ /**
+ * Set description
+ *
+ * @param string $description
+ * @return Rest_Method_Parameter
+ */
+ public function setDescription($description)
+ {
+ $this->_description = (string) $description;
+ return $this;
+ }
+
+ /**
+ * Retrieve description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->_description;
+ }
+
+ /**
+ * Set name
+ *
+ * @param string $name
+ * @return Rest_Method_Parameter
+ */
+ public function setName($name)
+ {
+ $this->_name = (string) $name;
+ return $this;
+ }
+
+ /**
+ * Retrieve name
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Set optional flag
+ *
+ * @param bool $flag
+ * @return Rest_Method_Parameter
+ */
+ public function setOptional($flag)
+ {
+ $this->_optional = (bool) $flag;
+ return $this;
+ }
+
+ /**
+ * Is the parameter optional?
+ *
+ * @return bool
+ */
+ public function isOptional()
+ {
+ return $this->_optional;
+ }
+
+ /**
+ * Set parameter type
+ *
+ * @param string $type
+ * @return Rest_Method_Parameter
+ */
+ public function setType($type)
+ {
+ $this->_type = (string) $type;
+ return $this;
+ }
+
+ /**
+ * Retrieve parameter type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Cast to array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return array(
+ 'type' => $this->getType(),
+ 'name' => $this->getName(),
+ 'optional' => $this->isOptional(),
+ 'defaultValue' => $this->getDefaultValue(),
+ 'description' => $this->getDescription(),
+ );
+ }
+}
diff --git a/webservice/classes/rest/method/Prototype.php b/webservice/classes/rest/method/Prototype.php
new file mode 100644
index 0000000..ca67d8e
--- /dev/null
+++ b/webservice/classes/rest/method/Prototype.php
@@ -0,0 +1,184 @@
+setOptions($options);
+ }
+ }
+
+ /**
+ * Set return value
+ *
+ * @param string $returnType
+ * @return Rest_Method_Prototype
+ */
+ public function setReturnType($returnType)
+ {
+ $this->_returnType = $returnType;
+ return $this;
+ }
+
+ /**
+ * Retrieve return type
+ *
+ * @return string
+ */
+ public function getReturnType()
+ {
+ return $this->_returnType;
+ }
+
+ /**
+ * Add a parameter
+ *
+ * @param string $parameter
+ * @return Rest_Method_Prototype
+ */
+ public function addParameter($parameter)
+ {
+ if ($parameter instanceof Rest_Method_Parameter) {
+ $this->_parameters[] = $parameter;
+ if (null !== ($name = $parameter->getName())) {
+ $this->_parameterNameMap[$name] = count($this->_parameters) - 1;
+ }
+ } else {
+ $parameter = new Rest_Method_Parameter(array(
+ 'type' => (string) $parameter,
+ ));
+ $this->_parameters[] = $parameter;
+ }
+ return $this;
+ }
+
+ /**
+ * Add parameters
+ *
+ * @param array $parameter
+ * @return Rest_Method_Prototype
+ */
+ public function addParameters(array $parameters)
+ {
+ foreach ($parameters as $parameter) {
+ $this->addParameter($parameter);
+ }
+ return $this;
+ }
+
+ /**
+ * Set parameters
+ *
+ * @param array $parameters
+ * @return Rest_Method_Prototype
+ */
+ public function setParameters(array $parameters)
+ {
+ $this->_parameters = array();
+ $this->_parameterNameMap = array();
+ $this->addParameters($parameters);
+ return $this;
+ }
+
+ /**
+ * Retrieve parameters as list of types
+ *
+ * @return array
+ */
+ public function getParameters()
+ {
+ $types = array();
+ foreach ($this->_parameters as $parameter) {
+ $types[] = $parameter->getType();
+ }
+ return $types;
+ }
+
+ /**
+ * Get parameter objects
+ *
+ * @return array
+ */
+ public function getParameterObjects()
+ {
+ return $this->_parameters;
+ }
+
+ /**
+ * Retrieve a single parameter by name or index
+ *
+ * @param string|int $index
+ * @return null Rest_Server_Method_Parameter
+ */
+ public function getParameter($index)
+ {
+ if (!is_string($index) && !is_numeric($index)) {
+ return null;
+ }
+ if (array_key_exists($index, $this->_parameterNameMap)) {
+ $index = $this->_parameterNameMap[$index];
+ }
+ if (array_key_exists($index, $this->_parameters)) {
+ return $this->_parameters[$index];
+ }
+ return null;
+ }
+
+ /**
+ * Set object state from array
+ *
+ * @param array $options
+ * @return Rest_Method_Prototype
+ */
+ public function setOptions(array $options)
+ {
+ foreach ($options as $key => $value) {
+ $method = 'set' . ucfirst($key);
+ if (method_exists($this, $method)) {
+ $this->$method($value);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Serialize to array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return array(
+ 'returnType' => $this->getReturnType(),
+ 'parameters' => $this->getParameters(),
+ );
+ }
+}
diff --git a/webservice/classes/rest/model/RestService.class.php b/webservice/classes/rest/model/RestService.class.php
new file mode 100755
index 0000000..50b2ac1
--- /dev/null
+++ b/webservice/classes/rest/model/RestService.class.php
@@ -0,0 +1,162 @@
+.
+*
+* You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
+* California 94120-7775, or email info@knowledgetree.com.
+*
+* The interactive user interfaces in modified source and object code versions
+* of this program must display Appropriate Legal Notices, as required under
+* Section 5 of the GNU General Public License version 3.
+*
+* In accordance with Section 7(b) of the GNU General Public License version 3,
+* these Appropriate Legal Notices must retain the display of the "Powered by
+* KnowledgeTree" logo and retain the original copyright notice. If the display of the
+* logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
+* must display the words "Powered by KnowledgeTree" and retain the original
+* copyright notice.
+*
+* @copyright 2008-2009, KnowledgeTree Inc.
+* @license GNU General Public License version 3
+* @author KnowledgeTree Team
+* @package Webservice
+* @version Version 0.1
+*/
+
+
+/**
+ * Class Service - will act as a switch between
+ * SOAP requests and REST requests
+ *@author KnowledgeTree Team
+ *@package Webservice
+ *@version Version 0.9
+ */
+class RestService
+{
+ /**
+ * Class construct
+ *
+ * @param object_type $object
+ * @return jason encoded string
+ */
+ public function __construct($object)
+ {
+ try {
+
+ $result = $this->runAsService($object);
+ echo jason_encode(array('status_code' => 0,'result' => $result));
+
+ } catch (Exception $e) {
+ echo json_encode(array('status_code' => 1,'result' => $e->getMessage()));
+ }
+ }
+
+ /**
+ * Constructor for invoking a reflection object
+ * Initiates the object as a service
+ * @param class $object
+ * @access private
+ * @return class instance
+ */
+
+ public function getJason()
+ {
+ $result = $this->runAsService($object);
+ return $result;
+
+ }
+
+ private function runAsService($object)
+ {
+
+ if (!isset($_GET['class'])) {
+
+ throw new Exception('Method name not specified.');
+ }
+
+ $reflObject = new ReflectionObject($object);
+
+ if (!$reflObject->hasMethod($_GET['class'])) {
+
+ throw new Exception('There is no method with this name.');
+
+ }
+
+ $reflMethod = $reflObject->getMethod($_GET['method']);
+
+ if ( !$reflMethod->isPublic() || $reflMethod->isStatic() || $reflMethod->isInternal() ) {
+
+ throw new Exception('Invalid method name specified.');
+
+ }
+
+ $reflParameters = $reflMethod->getParameters();
+
+ $args = array();
+
+
+ foreach ($reflParameters as $param) {
+
+ $paramName = $param->getName();
+
+ if (!isset($_GET[$paramName])) {
+
+ if ($param->isDefaultValueAvailable()) {
+
+ $paramValue = $param->getDefaultValue();
+
+ } else {
+
+ throw new Exception('Required parameter "'.$paramName.'" is not specified.');
+
+ }
+
+ } else {
+
+ $paramValue = $_GET[$paramName];
+
+ }
+
+
+ if ($param->getClass()) {
+
+ throw new Exception('The method contains unsupported parameter type: class object.');
+
+ }
+
+
+ if ($param->isArray() && !is_array($paramValue)) {
+
+ throw new Exception('Array expected for parameter "'.$paramName.'", but scalar found.');
+
+ }
+
+
+ $args[$param->getPosition()] = $paramValue;
+
+ }
+
+ return $reflMethod->invokeArgs($object, $args);
+
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/webservice/classes/rest/model/address.class.php b/webservice/classes/rest/model/address.class.php
new file mode 100755
index 0000000..116069d
--- /dev/null
+++ b/webservice/classes/rest/model/address.class.php
@@ -0,0 +1,24 @@
+
\ No newline at end of file
diff --git a/webservice/classes/rest/model/contact.class.php b/webservice/classes/rest/model/contact.class.php
new file mode 100755
index 0000000..74e0ae8
--- /dev/null
+++ b/webservice/classes/rest/model/contact.class.php
@@ -0,0 +1,34 @@
+
\ No newline at end of file
diff --git a/webservice/classes/rest/model/contactManager.class.php b/webservice/classes/rest/model/contactManager.class.php
new file mode 100755
index 0000000..53b8003
--- /dev/null
+++ b/webservice/classes/rest/model/contactManager.class.php
@@ -0,0 +1,61 @@
+address = new Address();
+ $contact->address->city ="sesamcity";
+ $contact->address->street ="sesamstreet";
+ $contact->email = "me@you.com";
+ $contact->id = 1;
+ $contact->name ="me";
+
+ $ret[] = $contact;
+ return $ret;
+ }
+
+ /**
+ * Gets the contact with the given id.
+ * @param int The id
+ * @return contact
+ */
+ public function getContact($id) {
+ //get contact from db
+ //might wanna throw an exception when it does not exists
+ throw new Exception("Contact '$id' not found");
+ }
+ /**
+ * Generates an new, empty contact template
+ * @return contact
+ */
+ public function newContact() {
+ return new contact();
+ }
+
+ /**
+ * Saves a given contact
+ * @param contact
+ * @return void
+ */
+ public function saveContact(contact $contact) {
+ $contact->save();
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/rest/reflection/Class.php b/webservice/classes/rest/reflection/Class.php
new file mode 100644
index 0000000..fe7dec6
--- /dev/null
+++ b/webservice/classes/rest/reflection/Class.php
@@ -0,0 +1,171 @@
+_reflection = $reflection;
+ $this->setNamespace($namespace);
+
+ foreach ($reflection->getMethods() as $method) {
+ // Don't aggregate magic methods
+ if ('__' == substr($method->getName(), 0, 2)) {
+ continue;
+ }
+
+ if ($method->isPublic()) {
+ // Get signatures and description
+ $this->_methods[] = new Rest_Reflection_Method($this, $method, $this->getNamespace(), $argv);
+ }
+ }
+ }
+
+ /**
+ * Proxy reflection calls
+ *
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ */
+ public function __call($method, $args)
+ {
+ if (method_exists($this->_reflection, $method)) {
+ return call_user_func_array(array($this->_reflection, $method), $args);
+ }
+
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid reflection method');
+ }
+
+ /**
+ * Retrieve configuration parameters
+ *
+ * Values are retrieved by key from {@link $_config}. Returns null if no
+ * value found.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function __get($key)
+ {
+ if (isset($this->_config[$key])) {
+ return $this->_config[$key];
+ }
+
+ return null;
+ }
+
+ /**
+ * Set configuration parameters
+ *
+ * Values are stored by $key in {@link $_config}.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function __set($key, $value)
+ {
+ $this->_config[$key] = $value;
+ }
+
+ /**
+ * Return array of dispatchable {@link Rest_Reflection_Method}s.
+ *
+ * @access public
+ * @return array
+ */
+ public function getMethods()
+ {
+ return $this->_methods;
+ }
+
+ /**
+ * Get namespace for this class
+ *
+ * @return string
+ */
+ public function getNamespace()
+ {
+ return $this->_namespace;
+ }
+
+ /**
+ * Set namespace for this class
+ *
+ * @param string $namespace
+ * @return void
+ */
+ public function setNamespace($namespace)
+ {
+ if (empty($namespace)) {
+ $this->_namespace = '';
+ return;
+ }
+
+ if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid namespace');
+ }
+
+ $this->_namespace = $namespace;
+ }
+
+ /**
+ * Wakeup from serialization
+ *
+ * Reflection needs explicit instantiation to work correctly. Re-instantiate
+ * reflection object on wakeup.
+ *
+ * @return void
+ */
+ public function __wakeup()
+ {
+ $this->_reflection = new ReflectionClass($this->getName());
+ }
+}
diff --git a/webservice/classes/rest/reflection/Function.php b/webservice/classes/rest/reflection/Function.php
new file mode 100644
index 0000000..e818ef8
--- /dev/null
+++ b/webservice/classes/rest/reflection/Function.php
@@ -0,0 +1,15 @@
+_classReflection = $class;
+ $this->_reflection = $r;
+
+ $classNamespace = $class->getNamespace();
+
+ // Determine namespace
+ if (!empty($namespace)) {
+ $this->setNamespace($namespace);
+ } elseif (!empty($classNamespace)) {
+ $this->setNamespace($classNamespace);
+ }
+
+ // Determine arguments
+ if (is_array($argv)) {
+ $this->_argv = $argv;
+ }
+
+ // If method call, need to store some info on the class
+ $this->_class = $class->getName();
+
+ // Perform some introspection
+ $this->_reflect();
+ }
+
+ /**
+ * Return the reflection for the class that defines this method
+ *
+ * @return Rest_Reflection_Class
+ */
+ public function getDeclaringClass()
+ {
+ return $this->_classReflection;
+ }
+
+ /**
+ * Wakeup from serialization
+ *
+ * Reflection needs explicit instantiation to work correctly. Re-instantiate
+ * reflection object on wakeup.
+ *
+ * @return void
+ */
+ public function __wakeup()
+ {
+ $this->_classReflection = new Rest_Reflection_Class(new ReflectionClass($this->_class), $this->getNamespace(), $this->getInvokeArguments());
+ $this->_reflection = new ReflectionMethod($this->_classReflection->getName(), $this->getName());
+ }
+
+}
diff --git a/webservice/classes/rest/reflection/Node.php b/webservice/classes/rest/reflection/Node.php
new file mode 100644
index 0000000..4cb7236
--- /dev/null
+++ b/webservice/classes/rest/reflection/Node.php
@@ -0,0 +1,178 @@
+_value = $value;
+ if (null !== $parent) {
+ $this->setParent($parent, true);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set parent node
+ *
+ * @param Rest_Reflection_Node $node
+ * @param boolean $new Whether or not the child node is newly created
+ * and should always be attached
+ * @return void
+ */
+ public function setParent(Rest_Reflection_Node $node, $new = false)
+ {
+ $this->_parent = $node;
+
+ if ($new) {
+ $node->attachChild($this);
+ return;
+ }
+ }
+
+ /**
+ * Create and attach a new child node
+ *
+ * @param mixed $value
+ * @access public
+ * @return Rest_Reflection_Node New child node
+ */
+ public function createChild($value)
+ {
+ $child = new self($value, $this);
+
+ return $child;
+ }
+
+ /**
+ * Attach a child node
+ *
+ * @param Rest_Reflection_Node $node
+ * @return void
+ */
+ public function attachChild(Rest_Reflection_Node $node)
+ {
+ $this->_children[] = $node;
+
+ if ($node->getParent() !== $this) {
+ $node->setParent($this);
+ }
+ }
+
+ /**
+ * Return an array of all child nodes
+ *
+ * @return array
+ */
+ public function getChildren()
+ {
+ return $this->_children;
+ }
+
+ /**
+ * Does this node have children?
+ *
+ * @return boolean
+ */
+ public function hasChildren()
+ {
+ return count($this->_children) > 0;
+ }
+
+ /**
+ * Return the parent node
+ *
+ * @return null|Rest_Reflection_Node
+ */
+ public function getParent()
+ {
+ return $this->_parent;
+ }
+
+ /**
+ * Return the node's current value
+ *
+ * @return mixed
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ /**
+ * Set the node value
+ *
+ * @param mixed $value
+ * @return void
+ */
+ public function setValue($value)
+ {
+ $this->_value = $value;
+ }
+
+ /**
+ * Retrieve the bottommost nodes of this node's tree
+ *
+ * Retrieves the bottommost nodes of the tree by recursively calling
+ * getEndPoints() on all children. If a child is null, it returns the parent
+ * as an end point.
+ *
+ * @return array
+ */
+ public function getEndPoints()
+ {
+ $endPoints = array();
+ if (!$this->hasChildren()) {
+ return $endPoints;
+ }
+
+ foreach ($this->_children as $child) {
+ $value = $child->getValue();
+
+ if (null === $value) {
+ $endPoints[] = $this;
+ } elseif ((null !== $value)
+ && $child->hasChildren())
+ {
+ $childEndPoints = $child->getEndPoints();
+ if (!empty($childEndPoints)) {
+ $endPoints = array_merge($endPoints, $childEndPoints);
+ }
+ } elseif ((null !== $value) && !$child->hasChildren()) {
+ $endPoints[] = $child;
+ }
+ }
+
+ return $endPoints;
+ }
+}
diff --git a/webservice/classes/rest/reflection/Parameter.php b/webservice/classes/rest/reflection/Parameter.php
new file mode 100644
index 0000000..3d8dc01
--- /dev/null
+++ b/webservice/classes/rest/reflection/Parameter.php
@@ -0,0 +1,138 @@
+_reflection = $r;
+ $this->setType($type);
+ $this->setDescription($description);
+ }
+
+ /**
+ * Proxy reflection calls
+ *
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ */
+ public function __call($method, $args)
+ {
+ if (method_exists($this->_reflection, $method)) {
+ return call_user_func_array(array($this->_reflection, $method), $args);
+ }
+
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid reflection method');
+ }
+
+ /**
+ * Retrieve parameter type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Set parameter type
+ *
+ * @param string|null $type
+ * @return void
+ */
+ public function setType($type)
+ {
+ if (!is_string($type) && (null !== $type)) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid parameter type');
+ }
+
+ $this->_type = $type;
+ }
+
+ /**
+ * Retrieve parameter description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->_description;
+ }
+
+ /**
+ * Set parameter description
+ *
+ * @param string|null $description
+ * @return void
+ */
+ public function setDescription($description)
+ {
+ if (!is_string($description) && (null !== $description)) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid parameter description');
+ }
+
+ $this->_description = $description;
+ }
+
+ /**
+ * Set parameter position
+ *
+ * @param int $index
+ * @return void
+ */
+ public function setPosition($index)
+ {
+ $this->_position = (int) $index;
+ }
+
+ /**
+ * Return parameter position
+ *
+ * @return int
+ */
+ public function getPosition()
+ {
+ return $this->_position;
+ }
+}
diff --git a/webservice/classes/rest/reflection/Prototype.php b/webservice/classes/rest/reflection/Prototype.php
new file mode 100644
index 0000000..1b654b5
--- /dev/null
+++ b/webservice/classes/rest/reflection/Prototype.php
@@ -0,0 +1,79 @@
+_return = $return;
+
+ if (!is_array($params) && (null !== $params)) {
+ require_once 'rest/Exception.php';
+ throw new Rest_Exception('Invalid parameters');
+ }
+
+ if (is_array($params)) {
+ foreach ($params as $param) {
+ if (!$param instanceof Rest_Reflection_Parameter) {
+ require_once 'rest/Exception.php';
+ throw new Rest_Exception('One or more params are invalid');
+ }
+ }
+ }
+
+ $this->_params = $params;
+ }
+
+ /**
+ * Retrieve return type
+ *
+ * @return string
+ */
+ public function getReturnType()
+ {
+ return $this->_return->getType();
+ }
+
+ /**
+ * Retrieve the return value object
+ *
+ * @access public
+ * @return Reflection_ReturnValue
+ */
+ public function getReturnValue()
+ {
+ return $this->_return;
+ }
+
+ /**
+ * Retrieve method parameters
+ *
+ * @return array Array of {@link Reflection_Parameter}s
+ */
+ public function getParameters()
+ {
+ return $this->_params;
+ }
+}
diff --git a/webservice/classes/rest/reflection/ReturnValue.php b/webservice/classes/rest/reflection/ReturnValue.php
new file mode 100644
index 0000000..f6a0411
--- /dev/null
+++ b/webservice/classes/rest/reflection/ReturnValue.php
@@ -0,0 +1,87 @@
+setType($type);
+ $this->setDescription($description);
+ }
+
+ /**
+ * Retrieve parameter type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Set parameter type
+ *
+ * @param string|null $type
+ * @return void
+ */
+ public function setType($type)
+ {
+ if (!is_string($type) && (null !== $type)) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid parameter type');
+ }
+
+ $this->_type = $type;
+ }
+
+ /**
+ * Retrieve parameter description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->_description;
+ }
+
+ /**
+ * Set parameter description
+ *
+ * @param string|null $description
+ * @return void
+ */
+ public function setDescription($description)
+ {
+ if (!is_string($description) && (null !== $description)) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid parameter description');
+ }
+
+ $this->_description = $description;
+ }
+}
diff --git a/webservice/classes/rest/reflection/function/Abstract.php b/webservice/classes/rest/reflection/function/Abstract.php
new file mode 100644
index 0000000..fb65965
--- /dev/null
+++ b/webservice/classes/rest/reflection/function/Abstract.php
@@ -0,0 +1,479 @@
+_reflection = $r;
+
+ // Determine namespace
+ if (null !== $namespace){
+ $this->setNamespace($namespace);
+ }
+
+ // Determine arguments
+ if (is_array($argv)) {
+ $this->_argv = $argv;
+ }
+
+ // If method call, need to store some info on the class
+ if ($r instanceof ReflectionMethod) {
+ $this->_class = $r->getDeclaringClass()->getName();
+ }
+
+ // Perform some introspection
+ $this->_reflect();
+ }
+
+ /**
+ * Create signature node tree
+ *
+ * Recursive method to build the signature node tree. Increments through
+ * each array in {@link $_sigParams}, adding every value of the next level
+ * to the current value (unless the current value is null).
+ *
+ * @param Rest_Reflection_Node $parent
+ * @param int $level
+ * @return void
+ */
+ protected function _addTree(Rest_Reflection_Node $parent, $level = 0)
+ {
+ if ($level >= $this->_sigParamsDepth) {
+ return;
+ }
+
+ foreach ($this->_sigParams[$level] as $value) {
+ $node = new Rest_Reflection_Node($value, $parent);
+ if ((null !== $value) && ($this->_sigParamsDepth > $level + 1)) {
+ $this->_addTree($node, $level + 1);
+ }
+ }
+ }
+
+ /**
+ * Build the signature tree
+ *
+ * Builds a signature tree starting at the return values and descending
+ * through each method argument. Returns an array of
+ * {@link Rest_Reflection_Node}s.
+ *
+ * @return array
+ */
+ protected function _buildTree()
+ {
+ $returnTree = array();
+ foreach ((array) $this->_return as $value) {
+ $node = new Rest_Reflection_Node($value);
+ $this->_addTree($node);
+ $returnTree[] = $node;
+ }
+
+ return $returnTree;
+ }
+
+ /**
+ * Build method signatures
+ *
+ * Builds method signatures using the array of return types and the array of
+ * parameters types
+ *
+ * @param array $return Array of return types
+ * @param string $returnDesc Return value description
+ * @param array $params Array of arguments (each an array of types)
+ * @param array $paramDesc Array of parameter descriptions
+ * @return array
+ */
+ protected function _buildSignatures($return, $returnDesc, $paramTypes, $paramDesc)
+ {
+ $this->_return = $return;
+ $this->_returnDesc = $returnDesc;
+ $this->_paramDesc = $paramDesc;
+ $this->_sigParams = $paramTypes;
+ $this->_sigParamsDepth = count($paramTypes);
+ $signatureTrees = $this->_buildTree();
+ $signatures = array();
+
+ $endPoints = array();
+ foreach ($signatureTrees as $root) {
+ $tmp = $root->getEndPoints();
+ if (empty($tmp)) {
+ $endPoints = array_merge($endPoints, array($root));
+ } else {
+ $endPoints = array_merge($endPoints, $tmp);
+ }
+ }
+
+ foreach ($endPoints as $node) {
+ if (!$node instanceof Rest_Reflection_Node) {
+ continue;
+ }
+
+ $signature = array();
+ do {
+ array_unshift($signature, $node->getValue());
+ $node = $node->getParent();
+ } while ($node instanceof Rest_Reflection_Node);
+
+ $signatures[] = $signature;
+ }
+
+ // Build prototypes
+ $params = $this->_reflection->getParameters();
+ foreach ($signatures as $signature) {
+ $return = new Rest_Reflection_ReturnValue(array_shift($signature), $this->_returnDesc);
+ $tmp = array();
+ foreach ($signature as $key => $type) {
+ $param = new Rest_Reflection_Parameter($params[$key], $type, $this->_paramDesc[$key]);
+ $param->setPosition($key);
+ $tmp[] = $param;
+ }
+
+ $this->_prototypes[] = new Rest_Reflection_Prototype($return, $tmp);
+ }
+ }
+
+ /**
+ * Use code reflection to create method signatures
+ *
+ * Determines the method help/description text from the function DocBlock
+ * comment. Determines method signatures using a combination of
+ * ReflectionFunction and parsing of DocBlock @param and @return values.
+ *
+ * @param ReflectionFunction $function
+ * @return array
+ */
+ protected function _reflect()
+ {
+ $function = $this->_reflection;
+ $helpText = '';
+ $signatures = array();
+ $returnDesc = '';
+ $paramCount = $function->getNumberOfParameters();
+ $paramCountRequired = $function->getNumberOfRequiredParameters();
+ $parameters = $function->getParameters();
+ $docBlock = $function->getDocComment();
+
+ if (!empty($docBlock)) {
+ // Get help text
+ if (preg_match(':/\*\*\s*\r?\n\s*\*\s(.*?)\r?\n\s*\*(\s@|/):s', $docBlock, $matches))
+ {
+ $helpText = $matches[1];
+ $helpText = preg_replace('/(^\s*\*\s)/m', '', $helpText);
+ $helpText = preg_replace('/\r?\n\s*\*\s*(\r?\n)*/s', "\n", $helpText);
+ $helpText = trim($helpText);
+ }
+
+ // Get return type(s) and description
+ $return = 'void';
+ if (preg_match('/@return\s+(\S+)/', $docBlock, $matches)) {
+ $return = explode('|', $matches[1]);
+ if (preg_match('/@return\s+\S+\s+(.*?)(@|\*\/)/s', $docBlock, $matches))
+ {
+ $value = $matches[1];
+ $value = preg_replace('/\s?\*\s/m', '', $value);
+ $value = preg_replace('/\s{2,}/', ' ', $value);
+ $returnDesc = trim($value);
+ }
+ }
+
+ // Get param types and description
+ if (preg_match_all('/@param\s+([^\s]+)/m', $docBlock, $matches)) {
+ $paramTypesTmp = $matches[1];
+ if (preg_match_all('/@param\s+\S+\s+(\$^\S+)\s+(.*?)(@|\*\/)/s', $docBlock, $matches))
+ {
+ $paramDesc = $matches[2];
+ foreach ($paramDesc as $key => $value) {
+ $value = preg_replace('/\s?\*\s/m', '', $value);
+ $value = preg_replace('/\s{2,}/', ' ', $value);
+ $paramDesc[$key] = trim($value);
+ }
+ }
+ }
+ } else {
+ $helpText = $function->getName();
+ $return = 'void';
+ }
+
+ // Set method description
+ $this->setDescription($helpText);
+
+ // Get all param types as arrays
+ if (!isset($paramTypesTmp) && (0 < $paramCount)) {
+ $paramTypesTmp = array_fill(0, $paramCount, 'mixed');
+ } elseif (!isset($paramTypesTmp)) {
+ $paramTypesTmp = array();
+ } elseif (count($paramTypesTmp) < $paramCount) {
+ $start = $paramCount - count($paramTypesTmp);
+ for ($i = $start; $i < $paramCount; ++$i) {
+ $paramTypesTmp[$i] = 'mixed';
+ }
+ }
+
+ // Get all param descriptions as arrays
+ if (!isset($paramDesc) && (0 < $paramCount)) {
+ $paramDesc = array_fill(0, $paramCount, '');
+ } elseif (!isset($paramDesc)) {
+ $paramDesc = array();
+ } elseif (count($paramDesc) < $paramCount) {
+ $start = $paramCount - count($paramDesc);
+ for ($i = $start; $i < $paramCount; ++$i) {
+ $paramDesc[$i] = '';
+ }
+ }
+
+ if (count($paramTypesTmp) != $paramCount) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception(
+ 'Variable number of arguments is not supported for services (except optional parameters). '
+ . 'Number of function arguments must currespond to actual number of arguments described in a docblock.');
+ }
+
+ $paramTypes = array();
+ foreach ($paramTypesTmp as $i => $param) {
+ $tmp = explode('|', $param);
+ if ($parameters[$i]->isOptional()) {
+ array_unshift($tmp, null);
+ }
+ $paramTypes[] = $tmp;
+ }
+
+ $this->_buildSignatures($return, $returnDesc, $paramTypes, $paramDesc);
+ }
+
+
+ /**
+ * Proxy reflection calls
+ *
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ */
+ public function __call($method, $args)
+ {
+ if (method_exists($this->_reflection, $method)) {
+ return call_user_func_array(array($this->_reflection, $method), $args);
+ }
+
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid reflection method ("' .$method. '")');
+ }
+
+ /**
+ * Retrieve configuration parameters
+ *
+ * Values are retrieved by key from {@link $_config}. Returns null if no
+ * value found.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function __get($key)
+ {
+ if (isset($this->_config[$key])) {
+ return $this->_config[$key];
+ }
+
+ return null;
+ }
+
+ /**
+ * Set configuration parameters
+ *
+ * Values are stored by $key in {@link $_config}.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function __set($key, $value)
+ {
+ $this->_config[$key] = $value;
+ }
+
+ /**
+ * Set method's namespace
+ *
+ * @param string $namespace
+ * @return void
+ */
+ public function setNamespace($namespace)
+ {
+ if (empty($namespace)) {
+ $this->_namespace = '';
+ return;
+ }
+
+ if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid namespace');
+ }
+
+ $this->_namespace = $namespace;
+ }
+
+ /**
+ * Return method's namespace
+ *
+ * @return string
+ */
+ public function getNamespace()
+ {
+ return $this->_namespace;
+ }
+
+ /**
+ * Set the description
+ *
+ * @param string $string
+ * @return void
+ */
+ public function setDescription($string)
+ {
+ if (!is_string($string)) {
+ require_once 'classes/rest/Exception.php';
+ throw new Rest_Exception('Invalid description');
+ }
+
+ $this->_description = $string;
+ }
+
+ /**
+ * Retrieve the description
+ *
+ * @return void
+ */
+ public function getDescription()
+ {
+ return $this->_description;
+ }
+
+ /**
+ * Retrieve all prototypes as array of
+ * {@link Rest_Reflection_Prototype Rest_Reflection_Prototypes}
+ *
+ * @return array
+ */
+ public function getPrototypes()
+ {
+ return $this->_prototypes;
+ }
+
+ /**
+ * Retrieve additional invocation arguments
+ *
+ * @return array
+ */
+ public function getInvokeArguments()
+ {
+ return $this->_argv;
+ }
+
+ /**
+ * Wakeup from serialization
+ *
+ * Reflection needs explicit instantiation to work correctly. Re-instantiate
+ * reflection object on wakeup.
+ *
+ * @return void
+ */
+ public function __wakeup()
+ {
+ if ($this->_reflection instanceof ReflectionMethod) {
+ $class = new ReflectionClass($this->_class);
+ $this->_reflection = new ReflectionMethod($class->newInstance(), $this->getName());
+ } else {
+ $this->_reflection = new ReflectionFunction($this->getName());
+ }
+ }
+}
diff --git a/webservice/classes/soap/IPPhpDoc.class.php b/webservice/classes/soap/IPPhpDoc.class.php
new file mode 100755
index 0000000..35e49b4
--- /dev/null
+++ b/webservice/classes/soap/IPPhpDoc.class.php
@@ -0,0 +1,110 @@
+getClasses();
+ }
+
+ /** Sets the current class
+ * @param string The class name
+ * @return void
+ */
+ public function setClass($class) {
+ $this->class = new IPReflectionClass($class);
+ }
+ /**
+ * Get all classes
+ *
+ * @return IPReflectionClass[]
+ */
+ function getClasses() {
+ $ar = get_declared_classes();
+ foreach($ar as $class){
+ $c = new reflectionClass($class);
+ if($c->isUserDefined()){//add only when class is user-defined
+ $this->classes[$class] = new IPReflectionClass($class);
+ }
+ }
+ ksort($this->classes);
+ return $this->classes;
+ }
+ /**
+ * Generates the documentation page with all classes, methods etc.
+ * @TODO FIXME: use the new template class
+ * @param string Template file (optional)
+ * @return string
+ */
+ public function getDocumentation($template="classes/soap/templates/docclass.xsl") {
+ if(!is_file($template))
+ throw new WSException("Could not find the template file: '$template'");
+ $xtpl = new IPXSLTemplate($template);
+ $documentation = Array();
+ $documentation['menu'] = Array();
+ //loop menu items
+ $documentation['menu'] = $this->getClasses();
+
+ if($this->class){
+ if($this->class->isUserDefined()) {
+ $this->class->properties = $this->class->getProperties(false, false);
+ $this->class->methods = $this->class->getMethods(false, false);
+ foreach((array)$this->class->methods as $method) {
+ $method->params = $method->getParameters();
+ }
+ } else {
+ $documentation['fault'] = "Native class";
+ }
+ $documentation['class'] = $this->class;
+ }
+ echo $xtpl->execute($documentation);
+ }
+
+
+ /**
+ *
+ * @param $comment String The doccomment
+ * @param $annotationName String the annotation name
+ * @param $annotationClass String the annotation class
+ * @return void
+ */
+ public static function getAnnotation($comment, $annotationName, $annotationClass = null){
+ if(!$annotationClass){
+ $annotationClass = $annotationName;
+ }
+ $start = 0;
+ if($start = stripos($comment, "@".$annotationName)){
+ $obi = new $annotationClass();
+ $start = strpos($comment, "(", $start);
+ $end = strpos($comment, ")", $start);
+ $propString = substr($comment, $start, ($end-$start) + 1);
+ $eval = "return Array$propString;";
+ $arr = @eval($eval);
+ if($arr === false) throw new Exception("Error parsing annotation: $propString");
+
+ foreach ((Array)$arr as $name => $value){
+ $obi->$name= $value;
+ }
+ return $obi;
+ }
+ throw new Exception("Cannot find annotation @$annotationName ($start, $end): {$this->comment} ");
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/IPReflectionClass.class.php b/webservice/classes/soap/IPReflectionClass.class.php
new file mode 100755
index 0000000..21e30b9
--- /dev/null
+++ b/webservice/classes/soap/IPReflectionClass.class.php
@@ -0,0 +1,114 @@
+classname = $classname;
+ parent::__construct($classname);
+
+ $this->parseComment();
+ }
+
+ /**
+ *Provides all methods exposed by this class as an array
+ *
+ * @param boolean If the method should also return protected functions
+ * @param boolean If the method should also return private functions
+ * @return IPReflectionMethod[]
+ */
+ public function getMethods($alsoProtected = true, $alsoPrivate = true){
+ $ar = parent::getMethods();
+ foreach($ar as $method){
+ $m = new IPReflectionMethod($this->classname, $method->name);
+ if((!$m->isPrivate() || $alsoPrivate) && (!$m->isProtected() || $alsoProtected) && ($m->getDeclaringClass()->name == $this->classname))
+ $this->methods[$method->name] = $m;
+ }
+ ksort($this->methods);
+ return $this->methods;
+ }
+
+ /**
+ * Exposes an array with public properties of the class
+ *
+ * @param boolean If the method should also return protected properties
+ * @param boolean If the method should also return private properties
+ * @return IPReflectionProperty[]
+ */
+ public function getProperties($alsoProtected=true,$alsoPrivate=true) {
+ $ar = parent::getProperties();
+ $this->properties = Array();
+ foreach($ar as $property){
+ if((!$property->isPrivate() || $alsoPrivate) && (!$property->isProtected() || $alsoProtected)){
+ try{
+ $p = new IPReflectionProperty($this->classname, $property->getName());
+ $this->properties[$property->name]=$p;
+ }catch(ReflectionException $exception){
+ echo "Fault on property: ".$property->name."
\n";
+ }
+ }
+ }
+ ksort($this->properties);
+ return $this->properties;
+ }
+
+ /**
+ * Exposes annotations of the class
+ * @param $annotationName String the annotation name
+ * @param $annotationClass String the annotation class
+ * @return void
+ */
+ public function getAnnotation($annotationName, $annotationClass = null){
+ return IPPhpDoc::getAnnotation($this->comment, $annotationName, $annotationClass);
+ }
+
+ /**
+ * Gets all the usefull information from the comments
+ * @return void
+ */
+ private function parseComment() {
+ $this->comment = $this->getDocComment();
+ new IPReflectionCommentParser($this->comment, $this);
+ }
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/IPReflectionCommentParser.class.php b/webservice/classes/soap/IPReflectionCommentParser.class.php
new file mode 100755
index 0000000..9d8340f
--- /dev/null
+++ b/webservice/classes/soap/IPReflectionCommentParser.class.php
@@ -0,0 +1,170 @@
+comment = $comment;
+ $this->obj = $obj;
+ $this->parse();
+ }
+ /**
+ * parses the comment, line for line
+ *
+ * Will take the type of comment (class, property or function) as an
+ * argument and split it up in lines.
+ * @param string Defines if its the comment for a class, public of function
+ * @return void
+ */
+ function parse() {
+ //reset object
+ $descriptionDone = false;
+ $this->fullDescriptionDone = false;
+
+ //split lines
+ $lines = split("\n", $this->comment);
+
+ //check lines for description or tags
+ foreach ($lines as $line) {
+ $pos = strpos($line,"* @");
+ if (trim($line) == "/**" || trim($line) == "*/") { //skip the start and end line
+ }elseif (!($pos === false)) { //comment
+ $this->parseTagLine(substr($line,$pos+3));
+ $descriptionDone=true;
+ }elseif(!$descriptionDone){
+ $this->parseDescription($line);
+ }
+ }
+ //if full description is empty, put small description in full description
+ if (trim(str_replace(Array("\n","\r"), Array("", ""), $this->obj->fullDescription)) == "")
+ $this->obj->fullDescription = $this->obj->smallDescription;
+ }
+
+ /**
+ * Parses the description to the small and full description properties
+ *
+ * @param string The description line
+ * @return void
+ */
+
+ function parseDescription($descriptionLine) {
+ if(strpos($descriptionLine,"*") <= 2) $descriptionLine = substr($descriptionLine, (strpos($descriptionLine,"*") + 1));
+
+ //geen lege comment regel indien al in grote omschrijving
+ if(trim(str_replace(Array("\n","\r"), Array("", ""), $descriptionLine)) == ""){
+ if($this->obj->fullDescription == "")
+ $descriptionLine = "";
+ $this->smallDescriptionDone = true;
+ }
+
+ if(!$this->smallDescriptionDone)//add to small description
+ $this->obj->smallDescription.=$descriptionLine;
+ else{//add to full description
+ $this->obj->fullDescription.=$descriptionLine;
+ }
+ }
+
+ /**
+ * Parses a tag line and extracts the tagname and values
+ *
+ * @param string The tagline
+ * @return void
+ */
+ function parseTagLine($tagLine) {
+ $tagArr = explode(" ", $tagLine);
+ $tag = $tagArr[0];
+
+ switch(strtolower($tag)){
+ case 'abstract':
+ $this->obj->abstract = true; break;
+ case 'access':
+ $this->obj->isPrivate = (strtolower(trim($tagArr[1]))=="private")?true:false;
+ break;
+ case 'author':
+ unset($tagArr[0]);
+ $this->obj->author = implode(" ",$tagArr);
+ break;
+ case 'copyright':
+ unset($tagArr[0]);
+ $this->obj->copyright = implode(" ",$tagArr);
+ break;
+ case 'deprecated':
+ case 'deprec':
+ $this->obj->deprecated = true;
+ break;
+ case 'extends': break;
+ case 'global':
+ $this->obj->globals[] = $tagArr[1];
+ break;
+ case 'param':
+ $o = new stdClass();
+ $o->type = trim($tagArr[1]);
+ $o->comment = implode(" ",$tagArr);
+ $this->obj->params[] = $o;
+ break;
+ case 'return':
+ $this->obj->return = trim($tagArr[1]); break;
+ case 'link':break;
+ case 'see':break;
+ case 'since':
+ $this->obj->since = trim($tagArr[1]); break;
+ case 'static':
+ $this->obj->static = true; break;
+ case 'throws':
+ unset($tagArr[0]);
+ $this->obj->throws = implode(" ",$tagArr);
+ break;
+ case 'todo':
+ unset($tagArr[0]);
+ $this->obj->todo[] = implode(" ",$tagArr);
+ break;
+ case 'var':
+ $this->obj->type = trim($tagArr[1]);
+ unset($tagArr[0],$tagArr[1]);
+ $comment=implode(" ",$tagArr);
+ //check if its an optional property
+ $this->obj->optional = strpos($comment,"[OPTIONAL]") !== FALSE;
+ $this->obj->autoincrement = strpos($comment,"[AUTOINCREMENT]") !== FALSE;
+ $this->obj->description = str_replace("[OPTIONAL]", "", $comment);
+ break;
+ case 'version':
+ $this->obj->version = $tagArr[1];
+ break;
+ default:
+ //echo "\nno valid tag: '".strtolower($tag)."' at tagline: '$tagLine'
";
+ //do nothing
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/IPReflectionMethod.class.php b/webservice/classes/soap/IPReflectionMethod.class.php
new file mode 100755
index 0000000..9f11b05
--- /dev/null
+++ b/webservice/classes/soap/IPReflectionMethod.class.php
@@ -0,0 +1,100 @@
+classname = $class;
+ parent::__construct($class,$method);
+ $this->parseComment();
+ }
+
+ /**
+ * Returns the full function name, including arguments
+ * @return string
+ */
+ public function getFullName(){
+ $args = $this->getParameters();
+ $argstr = "";
+
+ foreach((array)$args as $arg){
+ if($argstr!="")$argstr.=", ";
+ $argstr.= $arg->type ." $".$arg->name;
+ }
+ return $this->return." ".$this->name."(".$argstr.")";
+ }
+
+ /**
+ * Returns an array with parameter objects, containing type info etc.
+ *
+ * @return ReflectionParameter[] Associative array with parameter objects
+ */
+ public function getParameters(){
+ $this->parameters = Array();
+ $ar = parent::getParameters();
+ $i = 0;
+
+ foreach((array)$ar as $parameter){
+ $parameter->type = $this->params[$i++]->type;
+ $this->parameters[$parameter->name] = $parameter;
+ }
+
+ return $this->parameters;
+ }
+
+ /**
+ *
+ * @param $annotationName String the annotation name
+ * @param $annotationClass String the annotation class
+ * @return void
+ */
+ public function getAnnotation($annotationName, $annotationClass = null){
+ return IPPhpDoc::getAnnotation($this->comment, $annotationName, $annotationClass);
+ }
+
+ /**
+ * Parses the comment and adds found properties to this class
+ * @return void
+ */
+ private function parseComment(){
+ $this->comment = $this->getDocComment();
+ new IPReflectionCommentParser($this->comment, $this);
+ }
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/IPReflectionProperty.class.php b/webservice/classes/soap/IPReflectionProperty.class.php
new file mode 100755
index 0000000..4feaa29
--- /dev/null
+++ b/webservice/classes/soap/IPReflectionProperty.class.php
@@ -0,0 +1,75 @@
+classname = $class;
+ parent::__construct($class, $property);
+ $this->parseComment();
+ }
+
+ /**
+ *
+ * @param $annotationName String the annotation name
+ * @param $annotationClass String the annotation class
+ * @return void
+ */
+ public function getAnnotation($annotationName, $annotationClass = null){
+ return IPPhpDoc::getAnnotation($this->comment, $annotationName, $annotationClass);
+ }
+
+ private function parseComment(){
+ // No getDocComment available for properties in php 5.0.3 :(
+ $this->comment = $this->getDocComment();
+ new IPReflectionCommentParser($this->comment, $this);
+ }
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/IPXMLSchema.class.php b/webservice/classes/soap/IPXMLSchema.class.php
new file mode 100755
index 0000000..4b1653f
--- /dev/null
+++ b/webservice/classes/soap/IPXMLSchema.class.php
@@ -0,0 +1,179 @@
+parentElement = $parentElement;
+ }
+
+ /**
+ * Ads a complexType tag with xmlschema content to the types tag
+ * @param string The variable type (Array or class name)
+ * @param string The variable name
+ * @param domNode Used when adding an inline complexType
+ * @return domNode The complexType node
+ */
+
+ public function addComplexType($type, $name = false, $parent = false) {
+ if(!$parent){//outline element
+ //check if the complexType doesn't already exists
+ if(isset($this->types[$name])) return $this->types[$name];
+
+ //create the complexType tag beneath the xsd:schema tag
+ $complexTypeTag=$this->addElement("xsd:complexType", $this->parentElement);
+ if($name){//might be an anonymous element
+ $complexTypeTag->setAttribute("name",$name);
+ $this->types[$name]=$complexTypeTag;
+ }
+ }else{//inline element
+ $complexTypeTag = $this->addElement("xsd:complexType", $parent);
+ }
+
+ //check if its an array
+ if(strtolower(substr($type,0,6)) == 'array(' || substr($type,-2) == '[]'){
+ $this->addArray($type,$complexTypeTag);
+ }else{//it should be an object
+ $tag=$this->addElement("xsd:all", $complexTypeTag);
+ //check if it has the name 'object()' (kind of a stdClass)
+ if(strtolower(substr($type,0,6)) == 'object'){//stdClass
+ $content = substr($type, 7, (strlen($type)-1));
+ $properties = split(",", $content);//split the content into properties
+ foreach((array)$properties as $property){
+ if($pos = strpos($property, "=>")){//array with keys (order is important, so use 'sequence' tag)
+ $keyType = substr($property,6,($pos-6));
+ $valueType = substr($property,($pos+2), (strlen($property)-7));
+ $el->$this->addTypeElement($valueType, $keyType, $tag);
+ }else{
+ throw new WSDLException("Error creating WSDL: expected \"=>\". When using the object() as type, use it as object(paramname=>paramtype,paramname2=>paramtype2)");
+ }
+ }
+ }else{ //should be a known class
+
+ if(!class_exists($name)) throw new WSDLException("Error creating WSDL: no class found with the name '$name' / $type : $parent, so how should we know the structure for this datatype?");
+ $v = new IPReflectionClass($name);
+ //TODO: check if the class extends another class?
+ $properties = $v->getProperties(false, false);//not protected and private properties
+
+ foreach((array) $properties as $property){
+ if(!$property->isPrivate){
+ $el = $this->addTypeElement($property->type, $property->name, $tag, $property->optional);
+ }
+ }
+ }
+ }
+ return $complexTypeTag;
+ }
+
+ /**
+ * Adds an element tag beneath the parent and takes care
+ * of the type (XMLSchema type or complexType)
+ * @param string The datatype
+ * @param string Name of the element
+ * @param domNode The parent domNode
+ * @param boolean If the property is optional
+ * @return domNode
+ */
+ public function addTypeElement($type, $name, $parent, $optional = false) {
+ $el = $this->addElement("xsd:element", $parent);
+ $el->setAttribute("name", $name);
+
+ if($optional){//if it's an optional property, set minOccur to 0
+ $el->setAttribute("minOccurs", "0");
+ $el->setAttribute("maxOccurs", "1");
+ }
+
+ //check if XML Schema datatype
+ if($t = $this->checkSchemaType(strtolower($type)))
+ $el->setAttribute("type", "xsd:".$t);
+ else{//no XML Schema datatype
+ //if valueType==Array, then create anonymouse inline complexType (within element tag without type attribute)
+ if(substr($type,-2) == '[]'){
+ if($this->array_inline){
+ $this->addComplexType($type, false, $el);
+ }else{
+ $name = substr($type, 0, -2)."Array";
+ $el->setAttribute("type", "tns:".$name);
+ $this->addComplexType($type, $name, false);
+ }
+ }else{//else, new complextype, outline (element with 'ref' attrib)
+ $el->setAttribute("type", "tns:".$type);
+ $this->addComplexType($type, $type);
+ }
+ }
+ return $el;
+ }
+
+ /**
+ * Creates an xmlSchema element for the given array
+ */
+ public function addArray($type, $parent) {
+ $cc = $this->addElement("xsd:complexContent", $parent);
+ $rs = $this->addElement("xsd:restriction", $cc);
+ $rs->setAttribute("base", "SOAP-ENC:Array");
+
+ $type = (substr($type,-2) == '[]') ? substr($type, 0, (strlen($type)-2)) : substr($type, 6, (strlen($type)-7));
+ $el = $this->addElement("xsd:attribute", $rs);
+ $el->setAttribute("ref", "SOAP-ENC:arrayType");
+
+ //check if XML Schema datatype
+ if($t = $this->checkSchemaType(strtolower($type)))
+ $el->setAttribute("wsdl:arrayType", "xsd:".$t."[]");
+ else{//no XML Schema datatype
+ //if valueType==Array, then create anonymouse inline complexType (within element tag without type attribute)
+ if(substr($type,-2) == '[]'){
+ $this->addComplexType($type, false, $el);
+ }else{//else, new complextype, outline (element with 'ref' attrib)
+ $el->setAttribute("wsdl:arrayType", "tns:".$type."[]");
+ $this->addComplexType($type, $type);
+ }
+ }
+ return $el;
+ }
+
+ /**
+ * Checks if the given type is a valid XML Schema type or can be casted to a schema type
+ * @param string The datatype
+ * @return string
+ */
+ public static function checkSchemaType($type) {
+ //XML Schema types
+ $types = Array("string" => "string",
+ "int" => "int",
+ "integer" => "int",
+ "boolean" => "boolean",
+ "float" => "float");
+ if(isset($types[$type])) return $types[$type];
+ else return false;
+ }
+
+ /**
+ * Adds an child element to the parent
+ * @param string
+ * @param domNode
+ * @return domNode
+ */
+ private function addElement($name, $parent = false, $ns = false) {
+ if($ns)
+ $el = $parent->ownerDocument->createElementNS($ns, $name);
+ else
+ $el = $parent->ownerDocument->createElement($name);
+ if($parent)
+ $parent->appendChild($el);
+ return $el;
+ }
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/IPXSLTemplate.class.php b/webservice/classes/soap/IPXSLTemplate.class.php
new file mode 100755
index 0000000..9f21055
--- /dev/null
+++ b/webservice/classes/soap/IPXSLTemplate.class.php
@@ -0,0 +1,85 @@
+namespace = $namespace;
+ $this->tagName = $tagName;
+ $this->function = $function;
+ }
+
+ public function process($node) {
+ $x = $node;
+ eval($this->function);
+ }
+}
+
+
+class IPXSLTemplate {
+ const NAMESPACE = "http://schema.knowledgetree.com/xmltemplate/";
+ public $dom = null;
+ public $xsltproc = null;
+ public $customTags = Array();
+
+ public function __construct($file) {
+ $this->dom = new DOMDocument();
+ $this->dom->load($file);
+ $this->xsltproc = new XSLTProcessor();
+ $this->xsltproc->registerPHPFunctions();
+ }
+
+ public function execute($model) {
+ //process custom tags
+ foreach($this->customTags as $reg) {
+ $nodelist = $this->dom->getElementsByTagNameNS($reg->namespace, $reg->tagName);
+ for($i = $nodelist->length; $i > 0; $i--){
+ $reg->process($nodelist->item($i-1));
+ }
+ }
+
+ $this->xsltproc->importStyleSheet($this->dom);
+
+ $modelDom = new DomDocument();
+ $modelDom->appendChild($modelDom->createElement("model")); //root node
+ IPXSLTemplate::makeXML($model, $modelDom->documentElement);
+ //echo $modelDom->saveXML();
+ return $this->xsltproc->transformToXml($modelDom);
+ }
+
+ /** Add a new custom tag registration */
+ public function registerTag($namespace, $tagName, $function) {
+ $this->customTags[] = new tagRegistration($namespace, $tagName, $function);
+ }
+
+ /** Makes a XML node from an object/ array / text */
+ static function makeXML($model, $parent, $addToParent = false) {
+ if(is_array($model)){
+ foreach($model as $name => $value){
+ if(!is_numeric($name)) {
+ $node = $parent->ownerDocument->createElement($name);
+ $parent->appendChild($node);
+ IPXSLTemplate::makeXml($value, $node, true);
+ } else {
+ $node = $parent;
+ IPXSLTemplate::makeXml($value, $node);
+ }
+ }
+ } elseif (is_object($model)) {
+ if($addToParent)
+ $node = $parent;
+ else{
+ $node = $parent->ownerDocument->createElement(get_class($model));
+ $parent->appendChild($node);
+ }
+ foreach($model as $propertyName => $propertyValue){
+ $property = $parent->ownerDocument->createElement($propertyName);
+ $node->appendChild($property);
+ IPXSLTemplate::makeXml($propertyValue, $property);
+ }
+ } else {
+ $parent->appendChild($parent->ownerDocument->createTextNode($model));
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/WSDLException.class.php b/webservice/classes/soap/WSDLException.class.php
new file mode 100755
index 0000000..df20680
--- /dev/null
+++ b/webservice/classes/soap/WSDLException.class.php
@@ -0,0 +1,26 @@
+msg = $msg;
+ }
+ /**
+ * @return void
+ */
+ function Display() {
+ print "Error creating WSDL document:".$this->msg;
+ //var_dump(debug_backtrace());
+ }
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/WSDLStruct.class.php b/webservice/classes/soap/WSDLStruct.class.php
new file mode 100755
index 0000000..4b2c2b4
--- /dev/null
+++ b/webservice/classes/soap/WSDLStruct.class.php
@@ -0,0 +1,338 @@
+use = $use;
+ $this->binding_style=$type;
+ $this->tns = $tns;
+ $this->url = $url;
+ $this->doc = new domDocument();
+ $this->definitions = $this->addElement("wsdl:definitions",$this->doc);
+
+ $this->typesTag = $this->addElement("wsdl:types", $this->definitions);
+ $this->xsdSchema = $this->addElement("xsd:schema", $this->typesTag);
+ $this->xsdSchema->setAttribute("targetNamespace", $this->tns);
+ $this->xmlSchema = new IPXMLSchema($this->xsdSchema);
+
+ }
+
+ /**
+ * Adds the class to the services for this WSDL
+ *
+ * @param IPReflectionClass The service
+ * @return void
+ */
+ public function setService(IPReflectionClass $class){
+ $this->services[$class->classname] = $class;
+ $this->services[$class->classname]->getMethods(false, false);
+ }
+ /**
+ * @return string The WSDL document for this structure
+ */
+ public function generateDocument(){
+ $this->addToDebug("Generating document");
+
+ //add all definitions
+ $definitions=$this->definitions;
+ $definitions->setAttribute("xmlns", self::NS_WSDL);
+ $definitions->setAttribute("xmlns:soap", self::NS_SOAP);
+ $definitions->setAttribute("xmlns:SOAP-ENC", self::NS_ENC);
+ $definitions->setAttribute("xmlns:wsdl", self::NS_WSDL);
+ $definitions->setAttribute("xmlns:xsd", self::NS_XSD);
+ $definitions->setAttribute("xmlns:tns", $this->tns);
+ $definitions->setAttribute("targetNamespace", $this->tns);
+
+ //add all the services
+ foreach((array)$this->services as $serviceName => $service){
+ //add the portType
+ $portType = $this->addPortType($serviceName);
+
+ //add binding
+ $binding = $this->addBinding($serviceName);
+
+ //loop the operations
+ foreach((array)$service->methods as $operation){
+ $operationName = $operation->name;
+ $operationTag = $this->addOperation($operationName, $serviceName);
+
+ //input
+ //only when to operation needs arguments
+ $parameters = $operation->getParameters();
+ if(count($parameters)>0 || self::CREATE_EMPTY_INPUTS){
+ $messageName = $operationName."Request";
+ $input=$this->addElement("wsdl:input", $operationTag);
+ $input->setAttribute("message", "tns:".$messageName);
+ $para=Array();
+ foreach((array)$parameters as $parameterName => $parameter){
+ $para[$parameterName] = $parameter->type;
+ }
+ $this->addMessage($messageName, $para);
+ $this->addInput($this->bindingOperationTags[$serviceName][$operationName]);
+ }
+
+
+ //output
+ //only when the operation returns something
+ if(!$operation->return || trim($operation->return) == "") throw new WSDLException('No return type for '.$operationName);
+ if(strtolower(trim($operation->return))!='void'){
+ $messageName = $operationName."Response";
+ $output = $this->addElement("wsdl:output", $operationTag);
+ $output->setAttribute("message", "tns:".$messageName);
+ $this->addOutput($this->bindingOperationTags[$serviceName][$operationName]);
+ $this->addMessage($messageName,Array($operation->name."Return" => $operation->return));
+ }
+ }
+ // SH. now add the portType and binding
+ $this->definitions->AppendChild($portType);
+ $this->definitions->AppendChild($binding);
+
+ //add the service
+ $this->addService($serviceName);
+
+ }
+ return $this->doc->saveXML();
+ }
+
+ /**
+ * Adds a new operation to the given service
+ * @param string operation name
+ * @param string service name
+ * @return domElement
+ */
+ private function addOperation($operationName, $serviceName){
+ $this->addToDebug("Adding Operation: '$operationName : $serviceName'");
+ $operationTag = $this->addElement("wsdl:operation",$this->portTypeTags[$serviceName]);
+ $operationTag->setAttribute("name",$operationName);
+
+ //create operation tag for binding
+ $bindingOperationTag = $this->addElement("wsdl:operation",$this->bindingTags[$serviceName]);
+ $bindingOperationTag->setAttribute("name",$operationName);
+
+ //soap operation tag
+ $soapOperationTag = $this->addElement("soap:operation",$bindingOperationTag);
+ $soapOperationTag->setAttribute("soapAction",$this->url."&method=".$operationName);
+ $soapOperationTag->setAttribute("style",($this->binding_style == SOAP_RPC)? "rpc" : "document");
+
+ //save references
+ $this->operationTags[$serviceName][$operationName] = $operationTag;
+ $this->bindingOperationTags[$serviceName][$operationName] = $bindingOperationTag;
+
+ //and return
+ return $operationTag;
+ }
+
+ /**
+ * adds a new service tag to the WSDL file
+ * @param string the service name
+ * @return domElement
+ */
+ private function addService($serviceName){
+ $this->addToDebug("Adding service: '$serviceName'");
+ //create service
+ $serviceTag=$this->addElement("wsdl:service",$this->definitions);
+ $serviceTag->setAttribute("name",$serviceName);
+
+ //port tag
+ $portTag=$this->addElement("wsdl:port", $serviceTag);
+ $portTag->setAttribute("name", $serviceName."Port");
+ $portTag->setAttribute("binding", "tns:".$serviceName."Binding");
+
+ //address tag
+ $addressTag = $this->addElement("soap:address", $portTag);
+ $addressTag->setAttribute("location", $this->url);
+
+ //keep a reference
+ $this->serviceTags[$serviceName] = $serviceTag;
+ //and return
+ return $serviceTag;
+ }
+
+ /**
+ * Adds a new portType to the WSDL structure
+ * @param string the service name for which we create a portType
+ * @return domElement
+ */
+ private function addPortType($serviceName){
+ $this->addToDebug("Adding portType: '$serviceName'");
+ // SH don't add to main doc just yet
+ // $portTypeTag=$this->addElement("wsdl:portType", $this->definitions);
+ $portTypeTag = $this->addElement("wsdl:portType");
+ $portTypeTag->setAttribute("name", $serviceName."PortType");
+
+ //keep a reference
+ $this->portTypeTags[$serviceName]=$portTypeTag;
+ //and return
+ return $portTypeTag;
+ }
+
+ /**
+ * Adds a new binding to the WSDL structure
+ * @param string serviceName to bind
+ * @return domElement
+ */
+ private function addBinding($serviceName){
+ $this->addToDebug("Adding binding: '$serviceName'");
+ // SH. don't add to main doc just yet
+ // $bindingTag=$this->addElement("binding");
+ $bindingTag=$this->addElement("binding",$this->definitions);
+ $bindingTag->setAttribute("name", $serviceName."Binding");
+ $bindingTag->setAttribute("type", "tns:".$serviceName."PortType");
+
+ //soap binding tag
+ $soapBindingTag = $this->addElement("soap:binding", $bindingTag);
+ $soapBindingTag->setAttribute("style", ($this->binding_style == SOAP_RPC)? "rpc" : "document");
+ $soapBindingTag->setAttribute("transport", "http://schemas.xmlsoap.org/soap/http");
+
+ //keep a reference
+ $this->bindingTags[$serviceName] = $bindingTag;
+ //and return
+ return $bindingTag;
+ }
+
+ /**
+ * Adds a message tag to the WSDL document
+ * @param string Message name
+ * @param Array[string=>string] Array with variables & types
+ */
+ private function addMessage($name, $parts){
+ $this->addToDebug("Adding message: '$name'");
+ $msg = $this->addElement("message", $this->definitions);
+ $msg->setAttribute("name", $name);
+ foreach((array)$parts as $partName => $partType){
+ $this->addToDebug("Adding Message part: '$partName => $partType'");
+ $part=$this->addElement("part", $msg);
+ $part->setAttribute("name", $partName);
+
+ //check if it is a valid XML Schema datatype
+ if($t = IPXMLSchema::checkSchemaType(strtolower($partType)))
+ $part->setAttribute("type", "xsd:".$t);
+ else{
+ //If it is an array, change the type name
+ $partName = (substr($partType,-2) == "[]")?substr($partType,0,strpos($partType,"["))."Array":$partType;
+
+ $part->setAttribute("type", "tns:".$partName);
+ $this->xmlSchema->addComplexType($partType, $partName);
+ }
+ }
+ }
+
+ /**
+ * Adds an input element to the given parent (an operation tag)
+ * @param domNode The Parent domNode
+ * @param boolean Kind of tag. true=input tag, false=output tag
+ * @return domNode The input/output node
+ */
+ private function addInput($parent, $input=true){
+ $name = $input ? "wsdl:input" : "wsdl:output";
+ $tag=$this->addElement($name, $parent);
+ $soapOperation=$this->addElement("soap:body", $tag);
+ $soapOperation->setAttribute("use", ($this->use == SOAP_ENCODED)? "encoded" : "literal");
+ $soapOperation->setAttribute("namespace", $this->tns);
+ if($this->use == SOAP_ENCODED)
+ $soapOperation->setAttribute("encodingStyle", self::NS_ENC);
+ }
+
+ /**
+ * Adds an output element to the given parent (an operation tag)
+ * @param domNode The Parent domNode
+ * @return domNode The output node
+ */
+ private function addOutput($parent){
+ return $this->addInput($parent,false);
+ }
+
+ /************************* Supporting functions ****************************/
+
+ private function addToDebug($msg){
+ if($this->_debug) echo '-'.$msg."
\n";
+ }
+
+ /**
+ * Adds an child element to the parent
+ * @param string The name element
+ * @param domNode
+ * @return domNode
+ */
+ private function addElement($name, $parent=false, $ns=false){
+ if($ns)
+ $el=$this->doc->createElementNS($ns,$name);
+ else
+ $el=$this->doc->createElement($name);
+ if($parent)
+ $parent->appendChild($el);
+ return $el;
+ }
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/WSException.class.php b/webservice/classes/soap/WSException.class.php
new file mode 100755
index 0000000..93c4de4
--- /dev/null
+++ b/webservice/classes/soap/WSException.class.php
@@ -0,0 +1,24 @@
+msg = $msg;
+ }
+ /**
+ * @return void
+ */
+ public function Display() {
+ echo $this->msg;
+ }
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/WSHelper.class.php b/webservice/classes/soap/WSHelper.class.php
new file mode 100755
index 0000000..a7e82cb
--- /dev/null
+++ b/webservice/classes/soap/WSHelper.class.php
@@ -0,0 +1,183 @@
+uri = $uri;
+ $this->setWSDLCacheFolder($_SERVER['DOCUMENT_ROOT'].dirname($_SERVER['PHP_SELF'])."/wsdl/");
+ if($class) $this->setClass($class);
+ }
+
+ /**
+ * Adds the given class name to the list of classes
+ * to be included in the documentation/WSDL/Request handlers
+ * @param string
+ * @return void
+ */
+ public function setClass($name){
+ $this->name = $name;
+ $this->wsdlfile = $this->wsdlFolder.$this->name.".wsdl";
+ }
+
+ public function setWSDLCacheFolder($folder) {
+ $this->wsdlFolder = $folder;
+ //reset wsdlfile
+ $this->wsdlfile = $this->wsdlFolder.$this->name.".wsdl";
+ }
+ /**
+ * Sets the persistence level for the soap class
+ */
+ public function setPersistence($persistence) {
+ $this->persistence = $persistence;
+ }
+
+ /**
+ * Handles everything. Makes sure the webservice is handled,
+ * documentations is generated, or the wsdl is generated,
+ * according to the page request
+ * @return void
+ */
+ public function handle(){
+ if(substr($_SERVER['QUERY_STRING'], -4) == 'wsdl'){
+ $this->showWSDL();
+ }elseif(isset($GLOBALS['HTTP_RAW_POST_DATA']) && strlen($GLOBALS['HTTP_RAW_POST_DATA'])>0){
+ $this->handleRequest();
+ }else{
+ $this->createDocumentation();
+ }
+ }
+ /**
+ * Checks if the current WSDL is up-to-date, regenerates if necessary and outputs the WSDL
+ * @return void
+ */
+ public function showWSDL(){
+ //check if it's a legal webservice class
+ if(!in_array($this->name, $this->classNameArr))
+ throw new Exception("No valid webservice class.");
+
+ //@TODO: nog een mooie oplossing voor het cachen zoeken
+ header("Content-type: text/xml");
+ if($this->useWSDLCache && file_exists($this->wsdlfile)){
+ readfile($this->wsdlfile);
+ }else{
+ //make sure to refresh PHP WSDL cache system
+ ini_set("soap.wsdl_cache_enabled",0);
+ echo $this->createWSDL();
+ }
+ }
+
+ private function createWSDL(){
+ $this->class = new IPReflectionClass($this->name);
+ $wsdl = new WSDLStruct($this->uri, "http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."?class=".$this->name, $this->type, $this->use);
+ $wsdl->setService($this->class);
+
+ try {
+ $gendoc = $wsdl->generateDocument();
+ } catch (WSDLException $exception) {
+ $exception->Display();
+ exit();
+ }
+
+ $fh = fopen($this->wsdlfile, "w+");
+ fwrite($fh, $gendoc);
+ fclose($fh);
+
+ return $gendoc;
+ }
+
+ /**
+ * Lets the native PHP5 soap implementation handle the request
+ * after registrating the class
+ * @return void
+ */
+ private function handleRequest(){
+ //check if it's a legal webservice class
+ if(!in_array($this->name, $this->classNameArr))
+ throw new Exception("No valid webservice class.");
+
+ //check cache
+ //if(!file_exists($this->wsdlfile))
+ $this->createWSDL();
+
+ $options = Array('actor' => $this->actor, 'classmap' => $this->structureMap);
+
+ header("Content-type: text/xml");
+ $this->server = new SoapServer($this->wsdlfile, $options);
+ $this->server->setClass($this->name);
+ $this->server->setPersistence($this->persistence);
+
+ use_soap_error_handler(true);
+ $this->server->handle();
+ }
+
+ /**
+ * @param string code
+ * @param string string
+ * @param string actor
+ * @param mixed details
+ * @param string name
+ * @return void
+ */
+ public function fault($code, $string, $actor, $details, $name='') {
+ return $this->server->fault($code, $string, $actor, $details, $name);
+ }
+
+ /**
+ * Generates the documentations for the webservice usage.
+ * @TODO: "int", "boolean", "double", "float", "string", "void"
+ * @param string Template filename
+ * @return void
+ */
+ public function createDocumentation($template="classes/soap/templates/docclass.xsl") {
+ if(!is_file($template))
+ throw new WSException("Could not find the template file: '$template'");
+ $this->class = new IPReflectionClass($this->name);
+ $xtpl = new IPXSLTemplate($template);
+ $documentation = Array();
+ $documentation['menu'] = Array();
+ //loop menu items
+ sort($this->classNameArr);
+ foreach($this->classNameArr as $className) {
+ $documentation['menu'][] = new IPReflectionClass($className);
+ }
+
+ if($this->class){
+ $this->class->properties = $this->class->getProperties(false, false);
+ $this->class->methods = $this->class->getMethods(false, false);
+ foreach((array)$this->class->methods as $method) {
+ $method->params = $method->getParameters();
+ }
+
+ $documentation['class'] = $this->class;
+ }
+ echo $xtpl->execute($documentation);
+ }
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/common.php b/webservice/classes/soap/common.php
new file mode 100755
index 0000000..84324cc
--- /dev/null
+++ b/webservice/classes/soap/common.php
@@ -0,0 +1,87 @@
+.
+*
+* You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
+* California 94120-7775, or email info@knowledgetree.com.
+*
+* The interactive user interfaces in modified source and object code versions
+* of this program must display Appropriate Legal Notices, as required under
+* Section 5 of the GNU General Public License version 3.
+*
+* In accordance with Section 7(b) of the GNU General Public License version 3,
+* these Appropriate Legal Notices must retain the display of the "Powered by
+* KnowledgeTree" logo and retain the original copyright notice. If the display of the
+* logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
+* must display the words "Powered by KnowledgeTree" and retain the original
+* copyright notice.
+*
+* @copyright 2008-2009, KnowledgeTree Inc.
+* @license GNU General Public License version 3
+* @author KnowledgeTree Team
+* @package Webservice
+* @version Version 0.1
+*/
+
+
+error_reporting(E_ALL);
+ob_start("ob_gzhandler");
+
+require_once ("config.php");
+
+if(!extension_loaded("soap"))
+ die("Soap extension not loaded!");
+
+session_start();
+
+/** autoload function for PHP5
+* Loads all the classes in the model
+*
+*/
+function __autoload($classname) {
+ try{
+ if(file_exists("classes/soap/model/$classname.class.php"))
+ include("classes/soap/model/$classname.class.php");
+ elseif(file_exists("classes/soap/$classname.class.php"))
+ include("classes/soap/$classname.class.php");
+ elseif(file_exists("classes/soap/$classname.class.php"))
+ include("classes/soap/$classname.class.php");
+ } catch (Exception $e) {
+ echo $e->getMessage();
+ }
+
+}
+
+/** Write out debug file */
+function debug($txt,$file="debug.txt"){
+ $fp = fopen($file, "a");
+ fwrite($fp, str_replace("\n","\r\n","\r\n".$txt));
+ fclose($fp);
+}
+
+/** Write out object in the debug log */
+function debugObject($txt,$obj){
+ ob_start();
+ print_r($obj);
+ $data = ob_get_contents();
+ ob_end_clean();
+ debug($txt."\n".$data);
+}
+?>
diff --git a/webservice/classes/soap/config.php b/webservice/classes/soap/config.php
new file mode 100755
index 0000000..6344a5a
--- /dev/null
+++ b/webservice/classes/soap/config.php
@@ -0,0 +1,23 @@
+ "contact",
+ "address" => "address",
+
+);
+
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/model/RestService.class.php b/webservice/classes/soap/model/RestService.class.php
new file mode 100755
index 0000000..2f507bf
--- /dev/null
+++ b/webservice/classes/soap/model/RestService.class.php
@@ -0,0 +1,155 @@
+.
+*
+* You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
+* California 94120-7775, or email info@knowledgetree.com.
+*
+* The interactive user interfaces in modified source and object code versions
+* of this program must display Appropriate Legal Notices, as required under
+* Section 5 of the GNU General Public License version 3.
+*
+* In accordance with Section 7(b) of the GNU General Public License version 3,
+* these Appropriate Legal Notices must retain the display of the "Powered by
+* KnowledgeTree" logo and retain the original copyright notice. If the display of the
+* logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
+* must display the words "Powered by KnowledgeTree" and retain the original
+* copyright notice.
+*
+* @copyright 2008-2009, KnowledgeTree Inc.
+* @license GNU General Public License version 3
+* @author KnowledgeTree Team
+* @package Webservice
+* @version Version 0.1
+*/
+
+
+/**
+ * Class Service - will act as a switch between
+ * SOAP requests and REST requests
+ *@author KnowledgeTree Team
+ *@package Webservice
+ *@version Version 0.9
+ */
+class RestService
+{
+ /**
+ * Class construct
+ *
+ * @param object_type $object
+ * @return jason encoded string
+ */
+ public function __construct($object)
+ {
+ try {
+
+ $result = $this->runAsService($object);
+ echo jason_encode(array('status_code' => 0,'result' => $result));
+
+ } catch (Exception $e) {
+ echo json_encode(array('status_code' => 1,'result' => $e->getMessage()));
+ }
+ }
+
+ /**
+ * Constructor for invoking a reflection object
+ * Initiates the object as a service
+ * @param class $object
+ * @access private
+ * @return class instance
+ */
+
+ private function runAsService($object)
+ {
+
+ if (!isset($_GET['class'])) {
+
+ throw new Exception('Method name not specified.');
+ }
+
+ $reflObject = new ReflectionObject($object);
+
+ if (!$reflObject->hasMethod($_GET['class'])) {
+
+ throw new Exception('There is no method with this name.');
+
+ }
+
+ $reflMethod = $reflObject->getMethod($_GET['class']);
+
+ if ( !$reflMethod->isPublic() || $reflMethod->isStatic() || $reflMethod->isInternal() ) {
+
+ throw new Exception('Invalid method name specified.');
+
+ }
+
+ $reflParameters = $reflMethod->getParameters();
+
+ $args = array();
+
+
+ foreach ($reflParameters as $param) {
+
+ $paramName = $param->getName();
+
+ if (!isset($_GET[$paramName])) {
+
+ if ($param->isDefaultValueAvailable()) {
+
+ $paramValue = $param->getDefaultValue();
+
+ } else {
+
+ throw new Exception('Required parameter "'.$paramName.'" is not specified.');
+
+ }
+
+ } else {
+
+ $paramValue = $_GET[$paramName];
+
+ }
+
+
+ if ($param->getClass()) {
+
+ throw new Exception('The method contains unsupported parameter type: class object.');
+
+ }
+
+
+ if ($param->isArray() && !is_array($paramValue)) {
+
+ throw new Exception('Array expected for parameter "'.$paramName.'", but scalar found.');
+
+ }
+
+
+ $args[$param->getPosition()] = $paramValue;
+
+ }
+
+ return $reflMethod->invokeArgs($object, $args);
+
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/model/address.class.php b/webservice/classes/soap/model/address.class.php
new file mode 100755
index 0000000..116069d
--- /dev/null
+++ b/webservice/classes/soap/model/address.class.php
@@ -0,0 +1,24 @@
+
\ No newline at end of file
diff --git a/webservice/classes/soap/model/contact.class.php b/webservice/classes/soap/model/contact.class.php
new file mode 100755
index 0000000..74e0ae8
--- /dev/null
+++ b/webservice/classes/soap/model/contact.class.php
@@ -0,0 +1,34 @@
+
\ No newline at end of file
diff --git a/webservice/classes/soap/model/contactManager.class.php b/webservice/classes/soap/model/contactManager.class.php
new file mode 100755
index 0000000..a192add
--- /dev/null
+++ b/webservice/classes/soap/model/contactManager.class.php
@@ -0,0 +1,58 @@
+address = new Address();
+ $contact->address->city ="sesamcity";
+ $contact->address->street ="sesamstreet";
+ $contact->email = "me@you.com";
+ $contact->id = 1;
+ $contact->name ="me";
+
+ $ret[] = $contact;
+ return $ret;
+ }
+
+ /**
+ * Gets the contact with the given id.
+ * @param int The id
+ * @return contact
+ */
+ public function getContact($id) {
+ //get contact from db
+ //might wanna throw an exception when it does not exists
+ throw new Exception("Contact '$id' not found");
+ }
+ /**
+ * Generates an new, empty contact template
+ * @return contact
+ */
+ public function newContact() {
+ return new contact();
+ }
+
+ /**
+ * Saves a given contact
+ * @param contact
+ * @return void
+ */
+ public function saveContact(contact $contact) {
+ $contact->save();
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/webservice/classes/soap/templates/css/doc.css b/webservice/classes/soap/templates/css/doc.css
new file mode 100755
index 0000000..1c92f1f
--- /dev/null
+++ b/webservice/classes/soap/templates/css/doc.css
@@ -0,0 +1,88 @@
+body {
+ margin:0;
+ padding:0;
+ text-align: center;
+ background: #ffffff url("../images/doc/back.gif") repeat-y center;
+}
+body, table, th, td, p, div {
+ font-family: Arial, Helvetica;
+ font-size: 12pt;
+ line-height:1.4;
+}
+#main {
+ margin-right: auto;
+ margin-left: auto;
+ text-align: left;
+ width: 980px;
+}
+#mainpadded {
+ padding: 0px 40px 80px 40px;
+}
+#mainheader {
+ background: #ffffff url("../images/doc/backtop.jpg") no-repeat;
+ height: 180px;
+}
+#mainheaderpadded {
+ padding: 130px 40px 0px 40px;
+ text-align: right;
+}
+td {
+ vertical-align: top;
+}
+td#menu {
+ width: 300px;
+}
+td#content {
+}
+div.method {
+ padding-left: 10px;
+ margin-bottom: 20px;
+ border-left: 2px solid #C0C0C0;
+}
+div.methodwarning {
+ padding-left: 10px;
+ margin-bottom: 20px;
+ border-left: 4px solid #FF0000;
+}
+div.property {
+ padding-left: 10px;
+ margin-bottom: 20px;
+ border-left: 2px solid #C0C0C0;
+}
+div.propertywarning {
+ padding-left: 10px;
+ margin-bottom: 20px;
+ border-left: 4px solid #FF0000;
+}
+div.warning {
+ font-weight: bold;
+ color: #FF0000;
+ float: left;
+}
+a {
+ color: #FFA619;
+ text-decoration: none;
+ font-weight: bold;
+}
+a:hover {
+ text-decoration: underline;
+}
+p {
+ margin-top: 5px;
+ margin-bottom: 10px;
+}
+h1 {
+ margin-top: 0px;
+ margin-bottom: 10px;
+ padding: 0px;
+ font-family: Verdana, Helvetica;
+ font-size: 20pt;
+ color: #000000;
+}
+h2 {
+ margin-top: 0px;
+ margin-bottom: 10px;
+ font-family: Verdana, Helvetica;
+ font-size: 16pt;
+ color: #000000;
+}
\ No newline at end of file
diff --git a/webservice/classes/soap/templates/docclass.xsl b/webservice/classes/soap/templates/docclass.xsl
new file mode 100755
index 0000000..380bdc4
--- /dev/null
+++ b/webservice/classes/soap/templates/docclass.xsl
@@ -0,0 +1,116 @@
+
+
\n";
+
+$options = Array('actor' =>'http://www.knowledgetree.pr',
+ 'trace' => true);
+$client = new SoapClient($wsdl,$options);
+
+echo "