]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/externalAPI/cmis_repository_wrapper.php
Release 6.5.0
[Github/sugarcrm.git] / include / externalAPI / cmis_repository_wrapper.php
1 <?php
2 # Licensed to the Apache Software Foundation (ASF) under one
3 # or more contributor license agreements.  See the NOTICE file
4 # distributed with this work for additional information
5 # regarding copyright ownership.  The ASF licenses this file
6 # to you under the Apache License, Version 2.0 (the
7 # "License"); you may not use this file except in compliance
8 # with the License.  You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing,
13 # software distributed under the License is distributed on an
14 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 # KIND, either express or implied.  See the License for the
16 # specific language governing permissions and limitations
17 # under the License.
18
19 define("HTTP_OK", 200);
20 define("HTTP_CREATED", 201);
21 define("HTTP_ACCEPTED", 202);
22 define("HTTP_NONAUTHORITATIVE_INFORMATION", 203);
23 define("HTTP_NO_CONTENT", 204);
24 define("HTTP_RESET_CONTENT", 205);
25 define("HTTP_PARTIAL_CONTENT", 206);
26 define("HTTP_MULTIPLE_CHOICES", 300);
27 define("HTTP_BAD_REQUEST", 400); // invalidArgument, filterNotValid
28 define("HTTP_UNAUTHORIZED", 401);
29 define("HTTP_FORBIDDEN", 403); // permissionDenied, streamNotSupported
30 define("HTTP_NOT_FOUND", 404); // objectNotFound
31 define("HTTP_METHOD_NOT_ALLOWED", 405); // notSupported
32 define("HTTP_NOT_ACCEPTABLE", 406);
33 define("HTTP_PROXY_AUTHENTICATION_REQUIRED", 407);
34 define("xHTTP_REQUEST_TIMEOUT", 408); //Had to change this b/c HTTP_REQUEST_TIMEOUT conflicts with definition in Drupal 7
35 define("HTTP_CONFLICT", 409); // constraint, contentAlreadyExists, versioning, updateConflict, nameConstraintViolation
36 define("HTTP_UNSUPPORTED_MEDIA_TYPE", 415);
37 define("HTTP_UNPROCESSABLE_ENTITY", 422);
38 define("HTTP_INTERNAL_SERVER_ERROR", 500); // runtime, storage
39
40 class CmisInvalidArgumentException extends Exception {}
41 class CmisObjectNotFoundException extends Exception {}
42 class CmisPermissionDeniedException extends Exception {}
43 class CmisNotSupportedException extends Exception {}
44 class CmisConstraintException extends Exception {}
45 class CmisRuntimeException extends Exception {}
46
47 class CMISRepositoryWrapper
48 {
49     // Handles --
50     //   Workspace -- but only endpoints with a single repo
51     //   Entry -- but only for objects
52     //   Feeds -- but only for non-hierarchical feeds
53     // Does not handle --
54     //   -- Hierarchical Feeds
55     //   -- Types
56     //   -- Others?
57     // Only Handles Basic Auth
58     // Very Little Error Checking
59     // Does not work against pre CMIS 1.0 Repos
60
61     var $url;
62     var $username;
63     var $password;
64     var $authenticated;
65     var $workspace;
66     var $last_request;
67     var $do_not_urlencode;
68     protected $_addlCurlOptions = array();
69
70     static $namespaces = array (
71         "cmis" => "http://docs.oasis-open.org/ns/cmis/core/200908/",
72         "cmisra" => "http://docs.oasis-open.org/ns/cmis/restatom/200908/",
73         "atom" => "http://www.w3.org/2005/Atom",
74         "app" => "http://www.w3.org/2007/app",
75
76     );
77
78     function __construct($url, $username = null, $password = null, $options = null, array $addlCurlOptions = array())
79     {
80         if (is_array($options) && $options["config:do_not_urlencode"]) {
81             $this->do_not_urlencode=true;
82         }
83         $this->_addlCurlOptions = $addlCurlOptions; // additional cURL options
84
85         $this->connect($url, $username, $password, $options);
86     }
87
88     static function getOpUrl($url, $options = null)
89     {
90         if (is_array($options) && (count($options) > 0))
91         {
92             $needs_question = strstr($url, "?") === false;
93             return $url . ($needs_question ? "?" : "&") . http_build_query($options);
94         } else
95         {
96             return $url;
97         }
98     }
99
100     function convertStatusCode($code, $message)
101     {
102         switch ($code) {
103             case HTTP_BAD_REQUEST:
104                 return new CmisInvalidArgumentException($message, $code);
105             case HTTP_NOT_FOUND:
106                 return new CmisObjectNotFoundException($message, $code);
107             case HTTP_FORBIDDEN:
108                 return new CmisPermissionDeniedException($message, $code);
109             case HTTP_METHOD_NOT_ALLOWED:
110                 return new CmisNotSupportedException($message, $code);
111             case HTTP_CONFLICT:
112                 return new CmisConstraintException($message, $code);
113             default:
114                 return new CmisRuntimeException($message, $code);
115             }
116     }
117
118     function connect($url, $username, $password, $options)
119     {
120         // TODO: Make this work with cookies
121         $this->url = $url;
122         $this->username = $username;
123         $this->password = $password;
124         $this->auth_options = $options;
125         $this->authenticated = false;
126         $retval = $this->doGet($this->url);
127         if ($retval->code == HTTP_OK || $retval->code == HTTP_CREATED)
128         {
129             $this->authenticated = true;
130             $this->workspace = CMISRepositoryWrapper :: extractWorkspace($retval->body);
131         }
132     }
133
134     function doGet($url)
135     {
136         $retval = $this->doRequest($url);
137         if ($retval->code != HTTP_OK)
138         {
139             throw $this->convertStatusCode($retval->code, $retval->body);
140         }
141         return $retval;
142     }
143
144     function doDelete($url)
145     {
146         $retval = $this->doRequest($url, "DELETE");
147         if ($retval->code != HTTP_NO_CONTENT)
148         {
149             throw $this->convertStatusCode($retval->code, $retval->body);
150         }
151         return $retval;
152     }
153
154     function doPost($url, $content, $contentType, $charset = null)
155     {
156         $retval = $this->doRequest($url, "POST", $content, $contentType);
157         if ($retval->code != HTTP_CREATED)
158         {
159             throw $this->convertStatusCode($retval->code, $retval->body);
160         }
161         return $retval;
162     }
163
164     function doPut($url, $content, $contentType, $charset = null)
165     {
166         $retval = $this->doRequest($url, "PUT", $content, $contentType);
167         if (($retval->code < HTTP_OK) || ($retval->code >= HTTP_MULTIPLE_CHOICES))
168         {
169             throw $this->convertStatusCode($retval->code, $retval->body);
170         }
171         return $retval;
172     }
173
174     function doRequest($url, $method = "GET", $content = null, $contentType = null, $charset = null)
175     {
176         // Process the HTTP request
177         // 'til now only the GET request has been tested
178         // Does not URL encode any inputs yet
179         if (is_array($this->auth_options))
180         {
181             $url = CMISRepositoryWrapper :: getOpUrl($url, $this->auth_options);
182         }
183         $session = curl_init($url);
184         curl_setopt($session, CURLOPT_HEADER, false);
185         curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
186         if ($this->username)
187         {
188             curl_setopt($session, CURLOPT_USERPWD, $this->username . ":" . $this->password);
189         }
190         curl_setopt($session, CURLOPT_CUSTOMREQUEST, $method);
191         if ($contentType)
192         {
193             curl_setopt($session, CURLOPT_HTTPHEADER, array (
194                 "Content-Type: " . $contentType
195             ));
196         }
197         if ($content)
198         {
199             curl_setopt($session, CURLOPT_POSTFIELDS, $content);
200         }
201         if ($method == "POST")
202         {
203             curl_setopt($session, CURLOPT_POST, true);
204         }
205
206         // apply addl. cURL options
207         // WARNING: this may override previously set options
208         if (count($this->_addlCurlOptions)) {
209             foreach ($this->_addlCurlOptions as $key => $value) {
210                 curl_setopt($session, $key, $value);
211             }
212         }
213
214
215         //TODO: Make this storage optional
216         $retval = new stdClass();
217         $retval->url = $url;
218         $retval->method = $method;
219         $retval->content_sent = $content;
220         $retval->content_type_sent = $contentType;
221         $retval->body = curl_exec($session);
222         $retval->code = curl_getinfo($session, CURLINFO_HTTP_CODE);
223         $retval->content_type = curl_getinfo($session, CURLINFO_CONTENT_TYPE);
224         $retval->content_length = curl_getinfo($session, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
225         curl_close($session);
226         $this->last_request = $retval;
227         return $retval;
228     }
229
230     function getLastRequest()
231     {
232         return $this->last_request;
233     }
234
235     function getLastRequestBody()
236     {
237         return $this->last_request->body;
238     }
239
240     function getLastRequestCode()
241     {
242         return $this->last_request->code;
243     }
244
245     function getLastRequestContentType()
246     {
247         return $this->last_request->content_type;
248     }
249
250     function getLastRequestContentLength()
251     {
252         return $this->last_request->content_length;
253     }
254
255     function getLastRequestURL()
256     {
257         return $this->last_request->url;
258     }
259
260     function getLastRequestMethod()
261     {
262         return $this->last_request->method;
263     }
264
265     function getLastRequestContentTypeSent()
266     {
267         return $this->last_request->content_type_sent;
268     }
269
270     function getLastRequestContentSent()
271     {
272         return $this->last_request->content_sent;
273     }
274
275     // Static Utility Functions
276     static function processTemplate($template, $values = array ())
277     {
278         // Fill in the blanks --
279         $retval = $template;
280         if (is_array($values))
281         {
282             foreach ($values as $name => $value)
283             {
284                 $retval = str_replace("{" . $name . "}", $value, $retval);
285             }
286         }
287         // Fill in any unpoupated variables with ""
288         return preg_replace("/{[a-zA-Z0-9_]+}/", "", $retval);
289
290     }
291
292     static function doXQuery($xmldata, $xquery)
293     {
294         $doc = new DOMDocument();
295         $doc->loadXML($xmldata);
296         return CMISRepositoryWrapper :: doXQueryFromNode($doc, $xquery);
297     }
298
299     static function doXQueryFromNode($xmlnode, $xquery)
300     {
301         // Perform an XQUERY on a NODE
302         // Register the 4 CMIS namespaces
303         //THis may be a hopeless HACK!
304         //TODO: Review
305         if (!($xmlnode instanceof DOMDocument)) {
306             $xdoc=new DOMDocument();
307             $xnode = $xdoc->importNode($xmlnode,true);
308             $xdoc->appendChild($xnode);
309             $xpath = new DomXPath($xdoc);
310         } else {
311                 $xpath = new DomXPath($xmlnode);
312         }
313         foreach (CMISRepositoryWrapper :: $namespaces as $nspre => $nsuri)
314         {
315             $xpath->registerNamespace($nspre, $nsuri);
316         }
317         return $xpath->query($xquery);
318
319     }
320     static function getLinksArray($xmlnode)
321     {
322         // Gets the links of an object or a workspace
323         // Distinguishes between the two "down" links
324         //  -- the children link is put into the associative array with the "down" index
325         //  -- the descendants link is put into the associative array with the "down-tree" index
326         //  These links are distinguished by the mime type attribute, but these are probably the only two links that share the same rel ..
327         //    so this was done as a one off
328         $links = array ();
329         $link_nodes = $xmlnode->getElementsByTagName("link");
330         foreach ($link_nodes as $ln)
331         {
332             if ($ln->attributes->getNamedItem("rel")->nodeValue == "down" && $ln->attributes->getNamedItem("type")->nodeValue == "application/cmistree+xml")
333             {
334                 //Descendents and children share same "rel" but different document type.
335                 $links["down-tree"] = $ln->attributes->getNamedItem("href")->nodeValue;
336             } else
337             {
338                 $links[$ln->attributes->getNamedItem("rel")->nodeValue] = $ln->attributes->getNamedItem("href")->nodeValue;
339             }
340         }
341         return $links;
342     }
343         static function extractAllowableActions($xmldata)
344     {
345         $doc = new DOMDocument();
346         $doc->loadXML($xmldata);
347         return CMISRepositoryWrapper :: extractAllowableActionsFromNode($doc);
348     }
349     static function extractAllowableActionsFromNode($xmlnode)
350     {
351         $result = array();
352         $allowableActions = $xmlnode->getElementsByTagName("allowableActions");
353         if ($allowableActions->length > 0) {
354             foreach($allowableActions->item(0)->childNodes as $action)
355             {
356                 if (isset($action->localName)) {
357                     $result[$action->localName] = (preg_match("/^true$/i", $action->nodeValue) > 0);
358                 }
359             }
360         }
361         return $result;
362     }
363     static function extractObject($xmldata)
364     {
365         $doc = new DOMDocument();
366         $doc->loadXML($xmldata);
367         return CMISRepositoryWrapper :: extractObjectFromNode($doc);
368
369     }
370     static function extractObjectFromNode($xmlnode)
371     {
372         // Extracts the contents of an Object and organizes them into:
373         //  -- Links
374         //  -- Properties
375         //  -- the Object ID
376         // RRM -- NEED TO ADD ALLOWABLEACTIONS
377         $retval = new stdClass();
378         $retval->links = CMISRepositoryWrapper :: getLinksArray($xmlnode);
379         $retval->properties = array ();
380         $prop_nodes = $xmlnode->getElementsByTagName("object")->item(0)->getElementsByTagName("properties")->item(0)->childNodes;
381         foreach ($prop_nodes as $pn)
382         {
383             if ($pn->attributes)
384             {
385                 $propDefId = $pn->attributes->getNamedItem("propertyDefinitionId");
386                 // TODO: Maybe use ->length=0 to even detect null values
387                 if (!is_null($propDefId) && $pn->getElementsByTagName("value") && $pn->getElementsByTagName("value")->item(0))
388                 {
389                         if ($pn->getElementsByTagName("value")->length > 1) {
390                                 $retval->properties[$propDefId->nodeValue] = array();
391                                 for ($idx=0;$idx < $pn->getElementsByTagName("value")->length;$idx++) {
392                                         $retval->properties[$propDefId->nodeValue][$idx] = $pn->getElementsByTagName("value")->item($idx)->nodeValue;
393                                 }
394                         } else {
395                                 $retval->properties[$propDefId->nodeValue] = $pn->getElementsByTagName("value")->item(0)->nodeValue;
396                         }
397                 }
398             }
399         }
400         $retval->uuid = $xmlnode->getElementsByTagName("id")->item(0)->nodeValue;
401         $retval->id = $retval->properties["cmis:objectId"];
402         //TODO: RRM FIX THIS
403         $children_node = $xmlnode->getElementsByTagName("children");
404         if (is_object($children_node)) {
405                     $children_feed_c = $children_node->item(0);
406         }
407         if (is_object($children_feed_c)) {
408                         $children_feed_l = $children_feed_c->getElementsByTagName("feed");
409         }
410         if (isset($children_feed_l) && is_object($children_feed_l) && is_object($children_feed_l->item(0))) {
411                 $children_feed = $children_feed_l->item(0);
412                         $children_doc = new DOMDocument();
413                         $xnode = $children_doc->importNode($children_feed,true); // Avoid Wrong Document Error
414                         $children_doc->appendChild($xnode);
415                 $retval->children = CMISRepositoryWrapper :: extractObjectFeedFromNode($children_doc);
416         }
417                 $retval->allowableActions = CMISRepositoryWrapper :: extractAllowableActionsFromNode($xmlnode);
418         return $retval;
419     }
420
421     function handleSpaces($path)
422     {
423         return $this->do_not_urlencode ? $path : rawurlencode($path);
424     }
425
426     static function extractTypeDef($xmldata)
427     {
428         $doc = new DOMDocument();
429         $doc->loadXML($xmldata);
430         return CMISRepositoryWrapper :: extractTypeDefFromNode($doc);
431
432     }
433     static function extractTypeDefFromNode($xmlnode)
434     {
435         // Extracts the contents of an Object and organizes them into:
436         //  -- Links
437         //  -- Properties
438         //  -- the Object ID
439         // RRM -- NEED TO ADD ALLOWABLEACTIONS
440         $retval = new stdClass();
441         $retval->links = CMISRepositoryWrapper :: getLinksArray($xmlnode);
442         $retval->properties = array ();
443         $retval->attributes = array ();
444         $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmisra:type/*");
445         foreach ($result as $node)
446         {
447             if ((substr($node->nodeName, 0, 13) == "cmis:property") && (substr($node->nodeName, -10) == "Definition"))
448             {
449                 $id = $node->getElementsByTagName("id")->item(0)->nodeValue;
450                 $cardinality = $node->getElementsByTagName("cardinality")->item(0)->nodeValue;
451                 $propertyType = $node->getElementsByTagName("propertyType")->item(0)->nodeValue;
452                 // Stop Gap for now
453                 $retval->properties[$id] = array (
454                     "cmis:propertyType" => $propertyType,
455                     "cmis:cardinality" => $cardinality,
456
457                 );
458             } else
459             {
460                 $retval->attributes[$node->nodeName] = $node->nodeValue;
461             }
462             $retval->id = $retval->attributes["cmis:id"];
463         }
464         //TODO: RRM FIX THIS
465         $children_node = $xmlnode->getElementsByTagName("children");
466         if (is_object($children_node)) {
467                     $children_feed_c = $children_node->item(0);
468         }
469         if (is_object($children_feed_c)) {
470                         $children_feed_l = $children_feed_c->getElementsByTagName("feed");
471         }
472         if (is_object($children_feed_l) && is_object($children_feed_l->item(0))) {
473                 $children_feed = $children_feed_l->item(0);
474                         $children_doc = new DOMDocument();
475                         $xnode = $children_doc->importNode($children_feed,true); // Avoid Wrong Document Error
476                         $children_doc->appendChild($xnode);
477                 $retval->children = CMISRepositoryWrapper :: extractTypeFeedFromNode($children_doc);
478         }
479
480         /*
481          *
482
483
484
485                         $prop_nodes = $xmlnode->getElementsByTagName("object")->item(0)->getElementsByTagName("properties")->item(0)->childNodes;
486                         foreach ($prop_nodes as $pn) {
487                                 if ($pn->attributes) {
488                                         $retval->properties[$pn->attributes->getNamedItem("propertyDefinitionId")->nodeValue] = $pn->getElementsByTagName("value")->item(0)->nodeValue;
489                                 }
490                         }
491                 $retval->uuid=$xmlnode->getElementsByTagName("id")->item(0)->nodeValue;
492                 $retval->id=$retval->properties["cmis:objectId"];
493          */
494         return $retval;
495     }
496
497     static function extractObjectFeed($xmldata)
498     {
499         //Assumes only one workspace for now
500         $doc = new DOMDocument();
501         $doc->loadXML($xmldata);
502         return CMISRepositoryWrapper :: extractObjectFeedFromNode($doc);
503     }
504     static function extractObjectFeedFromNode($xmlnode)
505     {
506         // Process a feed and extract the objects
507         //   Does not handle hierarchy
508         //   Provides two arrays
509         //   -- one sequential array (a list)
510         //   -- one hash table indexed by objectID
511         //   and a property "numItems" that holds the total number of items available.
512         $retval = new stdClass();
513         // extract total number of items
514         $numItemsNode = CMISRepositoryWrapper::doXQueryFromNode($xmlnode, "/atom:feed/cmisra:numItems");
515         $retval->numItems = $numItemsNode->length ? (int) $numItemsNode->item(0)->nodeValue : -1; // set to negative value if info is not available
516
517         $retval->objectList = array ();
518         $retval->objectsById = array ();
519         $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "/atom:feed/atom:entry");
520         foreach ($result as $node)
521         {
522             $obj = CMISRepositoryWrapper :: extractObjectFromNode($node);
523             $retval->objectsById[$obj->id] = $obj;
524             $retval->objectList[] = & $retval->objectsById[$obj->id];
525         }
526         return $retval;
527     }
528
529     static function extractTypeFeed($xmldata)
530     {
531         //Assumes only one workspace for now
532         $doc = new DOMDocument();
533         $doc->loadXML($xmldata);
534         return CMISRepositoryWrapper :: extractTypeFeedFromNode($doc);
535     }
536     static function extractTypeFeedFromNode($xmlnode)
537     {
538         // Process a feed and extract the objects
539         //   Does not handle hierarchy
540         //   Provides two arrays
541         //   -- one sequential array (a list)
542         //   -- one hash table indexed by objectID
543         $retval = new stdClass();
544         $retval->objectList = array ();
545         $retval->objectsById = array ();
546         $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "/atom:feed/atom:entry");
547         foreach ($result as $node)
548         {
549             $obj = CMISRepositoryWrapper :: extractTypeDefFromNode($node);
550             $retval->objectsById[$obj->id] = $obj;
551             $retval->objectList[] = & $retval->objectsById[$obj->id];
552         }
553         return $retval;
554     }
555
556     static function extractWorkspace($xmldata)
557     {
558         //Assumes only one workspace for now
559         $doc = new DOMDocument();
560         $doc->loadXML($xmldata);
561         return CMISRepositoryWrapper :: extractWorkspaceFromNode($doc);
562     }
563     static function extractWorkspaceFromNode($xmlnode)
564     {
565         // Assumes only one workspace for now
566         // Load up the workspace object with arrays of
567         //  links
568         //  URI Templates
569         //  Collections
570         //  Capabilities
571         //  General Repository Information
572         $retval = new stdClass();
573         $retval->links = CMISRepositoryWrapper :: getLinksArray($xmlnode);
574         $retval->uritemplates = array ();
575         $retval->collections = array ();
576         $retval->capabilities = array ();
577         $retval->repositoryInfo = array ();
578         $retval->permissions = array();
579         $retval->permissionsMapping = array();
580         $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmisra:uritemplate");
581         foreach ($result as $node)
582         {
583             $retval->uritemplates[$node->getElementsByTagName("type")->item(0)->nodeValue] = $node->getElementsByTagName("template")->item(0)->nodeValue;
584         }
585         $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//app:collection");
586         foreach ($result as $node)
587         {
588             $retval->collections[$node->getElementsByTagName("collectionType")->item(0)->nodeValue] = $node->attributes->getNamedItem("href")->nodeValue;
589         }
590         $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmis:capabilities/*");
591         foreach ($result as $node)
592         {
593             $retval->capabilities[$node->nodeName] = $node->nodeValue;
594         }
595         $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmisra:repositoryInfo/*[name()!='cmis:capabilities' and name()!='cmis:aclCapability']");
596         foreach ($result as $node)
597         {
598             $retval->repositoryInfo[$node->nodeName] = $node->nodeValue;
599         }
600         $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmis:aclCapability/cmis:permissions");
601         foreach ($result as $node)
602         {
603             $retval->permissions[$node->getElementsByTagName("permission")->item(0)->nodeValue] = $node->getElementsByTagName("description")->item(0)->nodeValue;
604         }
605         $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmis:aclCapability/cmis:mapping");
606         foreach ($result as $node)
607         {
608             $key = $node->getElementsByTagName("key")->item(0)->nodeValue;
609             $values = array();
610             foreach ($node->getElementsByTagName("permission") as $value)
611             {
612                 array_push($values, $value->nodeValue);
613             }
614             $retval->permissionsMapping[$key] = $values;
615         }
616         $result = CMISRepositoryWrapper :: doXQueryFromNode($xmlnode, "//cmis:aclCapability/*[name()!='cmis:permissions' and name()!='cmis:mapping']");
617         foreach ($result as $node)
618         {
619             $retval->repositoryInfo[$node->nodeName] = $node->nodeValue;
620         }
621
622         return $retval;
623     }
624 }
625
626 // Option Contants for Array Indexing
627 // -- Generally optional flags that control how much information is returned
628 // -- Change log token is an anomoly -- but included in URL as parameter
629 define("OPT_MAX_ITEMS", "maxItems");
630 define("OPT_SKIP_COUNT", "skipCount");
631 define("OPT_FILTER", "filter");
632 define("OPT_INCLUDE_PROPERTY_DEFINITIONS", "includePropertyDefinitions");
633 define("OPT_INCLUDE_RELATIONSHIPS", "includeRelationships");
634 define("OPT_INCLUDE_POLICY_IDS", "includePolicyIds");
635 define("OPT_RENDITION_FILTER", "renditionFilter");
636 define("OPT_INCLUDE_ACL", "includeACL");
637 define("OPT_INCLUDE_ALLOWABLE_ACTIONS", "includeAllowableActions");
638 define("OPT_DEPTH", "depth");
639 define("OPT_CHANGE_LOG_TOKEN", "changeLogToken");
640
641 define("LINK_ALLOWABLE_ACTIONS", "http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions");
642
643 define("MIME_ATOM_XML", 'application/atom+xml');
644 define("MIME_ATOM_XML_ENTRY", 'application/atom+xml;type=entry');
645 define("MIME_ATOM_XML_FEED", 'application/atom+xml;type=feed');
646 define("MIME_CMIS_TREE", 'application/cmistree+xml');
647 define("MIME_CMIS_QUERY", 'application/cmisquery+xml');
648
649 // Many Links have a pattern to them based upon objectId -- but can that be depended upon?
650
651 class CMISService extends CMISRepositoryWrapper
652 {
653     var $_link_cache;
654     var $_title_cache;
655     var $_objTypeId_cache;
656     var $_type_cache;
657     function __construct($url, $username, $password, $options = null, array $addlCurlOptions = array())
658     {
659         parent :: __construct($url, $username, $password, $options, $addlCurlOptions);
660         $this->_link_cache = array ();
661         $this->_title_cache = array ();
662         $this->_objTypeId_cache = array ();
663         $this->_type_cache = array ();
664     }
665
666     // Utility Methods -- Added Titles
667     // Should refactor to allow for single object
668     function cacheObjectInfo($obj)
669     {
670         $this->_link_cache[$obj->id] = $obj->links;
671         $this->_title_cache[$obj->id] = $obj->properties["cmis:name"]; // Broad Assumption Here?
672         $this->_objTypeId_cache[$obj->id] = $obj->properties["cmis:objectTypeId"];
673     }
674
675     function cacheFeedInfo($objs)
676     {
677         foreach ($objs->objectList as $obj)
678         {
679             $this->cacheObjectInfo($obj);
680         }
681     }
682
683     function cacheTypeFeedInfo($typs)
684     {
685         foreach ($typs->objectList as $typ)
686         {
687             $this->cacheTypeInfo($typ);
688         }
689     }
690
691     function cacheTypeInfo($tDef)
692     {
693         // TODO: Fix Type Caching with missing properties
694         $this->_type_cache[$tDef->id] = $tDef;
695     }
696
697     function getPropertyType($typeId, $propertyId)
698     {
699         if ($this->_type_cache[$typeId]->properties)
700         {
701             return $this->_type_cache[$typeId]->properties[$propertyId]["cmis:propertyType"];
702         }
703         $obj = $this->getTypeDefinition($typeId);
704         return $obj->properties[$propertyId]["cmis:propertyType"];
705     }
706
707     function getObjectType($objectId)
708     {
709         if ($this->_objTypeId_cache[$objectId])
710         {
711             return $this->_objTypeId_cache[$objectId];
712         }
713         $obj = $this->getObject($objectId);
714         return $obj->properties["cmis:objectTypeId"];
715     }
716
717     function getTitle($objectId)
718     {
719         if ($this->_title_cache[$objectId])
720         {
721             return $this->_title_cache[$objectId];
722         }
723         $obj = $this->getObject($objectId);
724         return $obj->properties["cmis:name"];
725     }
726
727     function getTypeLink($typeId, $linkName)
728     {
729         if ($this->_type_cache[$typeId]->links)
730         {
731             return $this->_type_cache[$typeId]->links[$linkName];
732         }
733         $typ = $this->getTypeDefinition($typeId);
734         return $typ->links[$linkName];
735     }
736
737     function getLink($objectId, $linkName)
738     {
739         if ($this->_link_cache[$objectId][$linkName])
740         {
741             return $this->_link_cache[$objectId][$linkName];
742         }
743         $obj = $this->getObject($objectId);
744         return $obj->links[$linkName];
745     }
746
747     // Repository Services
748     function getRepositories()
749     {
750         throw Exception("Not Implemented");
751     }
752
753     function getRepositoryInfo()
754     {
755         return $this->workspace;
756     }
757
758     function getTypeDescendants($typeId=null, $depth, $options = array ())
759     {
760         // TODO: Refactor Type Entries Caching
761         $varmap = $options;
762         if ($typeId) {
763                 $hash_values = $options;
764                 $hash_values['depth'] = $depth;
765                 $myURL = $this->getTypeLink($typeId, "down-tree");
766                 $myURL = CMISRepositoryWrapper :: getOpUrl ($myURL, $hash_values);
767         } else {
768                 $myURL = $this->processTemplate($this->workspace->collections['http://docs.oasis-open.org/ns/cmis/link/200908/typedescendants'], $varmap);
769         }
770         $ret = $this->doGet($myURL);
771         $typs = $this->extractTypeFeed($ret->body);
772         $this->cacheTypeFeedInfo($typs);
773         return $typs;
774     }
775
776     function getTypeChildren($typeId=null, $options = array ())
777     {
778         // TODO: Refactor Type Entries Caching
779         $varmap = $options;
780         if ($typeId) {
781                 $myURL = $this->getTypeLink($typeId, "down");
782                 //TODO: Need GenURLQueryString Utility
783         } else {
784             //TODO: Need right URL
785                 $myURL = $this->processTemplate($this->workspace->collections['types'], $varmap);
786         }
787         $ret = $this->doGet($myURL);
788         $typs = $this->extractTypeFeed($ret->body);
789         $this->cacheTypeFeedInfo($typs);
790         return $typs;
791     }
792
793     function getTypeDefinition($typeId, $options = array ())
794     { // Nice to have
795         $varmap = $options;
796         $varmap["id"] = $typeId;
797         $myURL = $this->processTemplate($this->workspace->uritemplates['typebyid'], $varmap);
798         $ret = $this->doGet($myURL);
799         $obj = $this->extractTypeDef($ret->body);
800         $this->cacheTypeInfo($obj);
801         return $obj;
802     }
803
804     function getObjectTypeDefinition($objectId)
805     { // Nice to have
806         $myURL = $this->getLink($objectId, "describedby");
807         $ret = $this->doGet($myURL);
808         $obj = $this->extractTypeDef($ret->body);
809         $this->cacheTypeInfo($obj);
810         return $obj;
811     }
812     //Navigation Services
813     function getFolderTree($folderId, $depth, $options = array ())
814     {
815         $hash_values = $options;
816         $hash_values['depth'] = $depth;
817         $myURL = $this->getLink($folderId, "http://docs.oasis-open.org/ns/cmis/link/200908/foldertree");
818         $myURL = CMISRepositoryWrapper :: getOpUrl ($myURL, $hash_values);
819         $ret = $this->doGet($myURL);
820         $objs = $this->extractObjectFeed($ret->body);
821         $this->cacheFeedInfo($objs);
822         return $objs;
823     }
824
825     function getDescendants($folderId, $depth, $options = array ())
826     { // Nice to have
827         $hash_values = $options;
828         $hash_values['depth'] = $depth;
829         $myURL = $this->getLink($folderId, "down-tree");
830         $myURL = CMISRepositoryWrapper :: getOpUrl ($myURL, $hash_values);
831         $ret = $this->doGet($myURL);
832         $objs = $this->extractObjectFeed($ret->body);
833         $this->cacheFeedInfo($objs);
834         return $objs;
835     }
836
837     function getChildren($folderId, $options = array ())
838     {
839         $myURL = $this->getLink($folderId, "down");
840         //TODO: Need GenURLQueryString Utility
841         $ret = $this->doGet($myURL);
842         $objs = $this->extractObjectFeed($ret->body);
843         $this->cacheFeedInfo($objs);
844         return $objs;
845     }
846
847     function getFolderParent($folderId, $options = array ())
848     { //yes
849         $myURL = $this->getLink($folderId, "up");
850         //TODO: Need GenURLQueryString Utility
851         $ret = $this->doGet($myURL);
852         $obj = $this->extractObjectEntry($ret->body);
853         $this->cacheObjectInfo($obj);
854         return $obj;
855     }
856
857     function getObjectParents($objectId, $options = array ())
858     { // yes
859         $myURL = $this->getLink($objectId, "up");
860         //TODO: Need GenURLQueryString Utility
861         $ret = $this->doGet($myURL);
862         $objs = $this->extractObjectFeed($ret->body);
863         $this->cacheFeedInfo($objs);
864         return $objs;
865     }
866
867     function getCheckedOutDocs($options = array ())
868     {
869         $obj_url = $this->workspace->collections['checkedout'];
870         $ret = $this->doGet($obj_url);
871         $objs = $this->extractObjectFeed($ret->body);
872         $this->cacheFeedInfo($objs);
873         return $objs;
874     }
875
876     //Discovery Services
877
878     static function getQueryTemplate()
879     {
880         ob_start();
881         echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' . "\n";
882 ?>
883 <cmis:query xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
884 xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/"
885 xmlns:atom="http://www.w3.org/2005/Atom"
886 xmlns:app="http://www.w3.org/2007/app"
887 xmlns:cmisra="http://docs.oasisopen.org/ns/cmis/restatom/200908/">
888 <cmis:statement>{q}</cmis:statement>
889 <cmis:searchAllVersions>{searchAllVersions}</cmis:searchAllVersions>
890 <cmis:includeAllowableActions>{includeAllowableActions}</cmis:includeAllowableActions>
891 <cmis:includeRelationships>{includeRelationships}</cmis:includeRelationships>
892 <cmis:renditionFilter>{renditionFilter}</cmis:renditionFilter>
893 <cmis:maxItems>{maxItems}</cmis:maxItems>
894 <cmis:skipCount>{skipCount}</cmis:skipCount>
895 </cmis:query>
896 <?php
897
898         return ob_get_clean();
899     }
900     function query($statement, $options = array ())
901     {
902         static $query_template;
903         if (!isset ($query_template))
904         {
905             $query_template = CMISService :: getQueryTemplate();
906         }
907         $hash_values = $options;
908         $hash_values['q'] = $statement;
909         $post_value = CMISRepositoryWrapper :: processTemplate($query_template, $hash_values);
910         $ret = $this->doPost($this->workspace->collections['query'], $post_value, MIME_CMIS_QUERY);
911         $objs = $this->extractObjectFeed($ret->body);
912         $this->cacheFeedInfo($objs);
913         return $objs;
914     }
915
916     function getContentChanges()
917     {
918         throw Exception("Not Implemented");
919     }
920
921     //Object Services
922     static function getEntryTemplate()
923     {
924         ob_start();
925         echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' . "\n";
926 ?>
927 <atom:entry xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
928 xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/"
929 xmlns:atom="http://www.w3.org/2005/Atom"
930 xmlns:app="http://www.w3.org/2007/app"
931 xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/">
932 <atom:title>{title}</atom:title>
933 {SUMMARY}
934 {CONTENT}
935 <cmisra:object><cmis:properties>{PROPERTIES}</cmis:properties></cmisra:object>
936 </atom:entry>
937 <?php
938
939         return ob_get_clean();
940     }
941
942     static function getPropertyTemplate()
943     {
944         ob_start();
945 ?>
946                 <cmis:property{propertyType} propertyDefinitionId="{propertyId}">
947                         <cmis:value>{properties}</cmis:value>
948                 </cmis:property{propertyType}>
949 <?php
950
951         return ob_get_clean();
952     }
953
954     function processPropertyTemplates($objectType, $propMap)
955     {
956         static $propTemplate;
957         static $propertyTypeMap;
958         if (!isset ($propTemplate))
959         {
960             $propTemplate = CMISService :: getPropertyTemplate();
961         }
962         if (!isset ($propertyTypeMap))
963         { // Not sure if I need to do this like this
964             $propertyTypeMap = array (
965                 "integer" => "Integer",
966                 "boolean" => "Boolean",
967                 "datetime" => "DateTime",
968                 "decimal" => "Decimal",
969                 "html" => "Html",
970                 "id" => "Id",
971                 "string" => "String",
972                 "url" => "Url",
973                 "xml" => "Xml",
974
975             );
976         }
977         $propertyContent = "";
978         $hash_values = array ();
979         foreach ($propMap as $propId => $propValue)
980         {
981             $hash_values['propertyType'] = $propertyTypeMap[$this->getPropertyType($objectType, $propId)];
982             $hash_values['propertyId'] = $propId;
983             if (is_array($propValue))
984             {
985                 $first_one = true;
986                 $hash_values['properties'] = "";
987                 foreach ($propValue as $val)
988                 {
989                     //This is a bit of a hack
990                     if ($first_one)
991                     {
992                         $first_one = false;
993                     } else
994                     {
995                         $hash_values['properties'] .= "</cmis:value>\n<cmis:value>";
996                     }
997                     $hash_values['properties'] .= $val;
998                 }
999             } else
1000             {
1001                 $hash_values['properties'] = $propValue;
1002             }
1003             //echo "HASH:\n";
1004             //print_r(array("template" =>$propTemplate, "Hash" => $hash_values));
1005             $propertyContent .= CMISRepositoryWrapper :: processTemplate($propTemplate, $hash_values);
1006         }
1007         return $propertyContent;
1008     }
1009
1010     static function getContentEntry($content, $content_type = "application/octet-stream")
1011     {
1012         static $contentTemplate;
1013         if (!isset ($contentTemplate))
1014         {
1015             $contentTemplate = CMISService :: getContentTemplate();
1016         }
1017         if ($content)
1018         {
1019             return CMISRepositoryWrapper :: processTemplate($contentTemplate, array (
1020                 "content" => base64_encode($content
1021             ), "content_type" => $content_type));
1022         } else
1023         {
1024             return "";
1025         }
1026     }
1027
1028     static function getSummaryTemplate()
1029     {
1030         ob_start();
1031 ?>
1032                 <atom:summary>{summary}</atom:summary>
1033 <?php
1034
1035         return ob_get_clean();
1036     }
1037
1038     static function getContentTemplate()
1039     {
1040         ob_start();
1041 ?>
1042                 <cmisra:content>
1043                         <cmisra:mediatype>
1044                                 {content_type}
1045                         </cmisra:mediatype>
1046                         <cmisra:base64>
1047                                 {content}
1048                         </cmisra:base64>
1049                 </cmisra:content>
1050 <?php
1051
1052         return ob_get_clean();
1053     }
1054     static function createAtomEntry($name, $properties)
1055     {
1056
1057     }
1058     function getObject($objectId, $options = array ())
1059     {
1060         $varmap = $options;
1061         $varmap["id"] = $objectId;
1062         $obj_url = $this->processTemplate($this->workspace->uritemplates['objectbyid'], $varmap);
1063         $ret = $this->doGet($obj_url);
1064         $obj = $this->extractObject($ret->body);
1065         $this->cacheObjectInfo($obj);
1066         return $obj;
1067     }
1068
1069     function getObjectByPath($path, $options = array ())
1070     {
1071         $varmap = $options;
1072         $varmap["path"] = $this->handleSpaces($path);
1073         $obj_url = $this->processTemplate($this->workspace->uritemplates['objectbypath'], $varmap);
1074         $ret = $this->doGet($obj_url);
1075         $obj = $this->extractObject($ret->body);
1076         $this->cacheObjectInfo($obj);
1077         return $obj;
1078     }
1079
1080     function getProperties($objectId, $options = array ())
1081     {
1082         // May need to set the options array default --
1083         return $this->getObject($objectId, $options);
1084     }
1085
1086     function getAllowableActions($objectId, $options = array ())
1087     {
1088         $myURL = $this->getLink($objectId, LINK_ALLOWABLE_ACTIONS);
1089         $ret = $this->doGet($myURL);
1090         $result = $this->extractAllowableActions($ret->body);
1091         return $result;
1092     }
1093
1094     function getRenditions($objectId, $options = array (
1095         OPT_RENDITION_FILTER => "*"
1096     ))
1097     {
1098         return getObject($objectId, $options);
1099     }
1100
1101     function getContentStream($objectId, $options = array ())
1102     { // Yes
1103         $myURL = $this->getLink($objectId, "edit-media");
1104         $ret = $this->doGet($myURL);
1105         // doRequest stores the last request information in this object
1106         return $ret->body;
1107     }
1108
1109     function postObject($folderId, $objectName, $objectType, $properties = array (), $content = null, $content_type = "application/octet-stream", $options = array ())
1110     { // Yes
1111         $myURL = $this->getLink($folderId, "down");
1112         // TODO: Need Proper Query String Handling
1113         // Assumes that the 'down' link does not have a querystring in it
1114         $myURL = CMISRepositoryWrapper :: getOpUrl($myURL, $options);
1115         static $entry_template;
1116         if (!isset ($entry_template))
1117         {
1118             $entry_template = CMISService :: getEntryTemplate();
1119         }
1120         if (is_array($properties))
1121         {
1122             $hash_values = $properties;
1123         } else
1124         {
1125             $hash_values = array ();
1126         }
1127         if (!isset ($hash_values["cmis:objectTypeId"]))
1128         {
1129             $hash_values["cmis:objectTypeId"] = $objectType;
1130         }
1131         $properties_xml = $this->processPropertyTemplates($hash_values["cmis:objectTypeId"], $hash_values);
1132         if (is_array($options))
1133         {
1134             $hash_values = $options;
1135         } else
1136         {
1137             $hash_values = array ();
1138         }
1139         $hash_values["PROPERTIES"] = $properties_xml;
1140         $hash_values["SUMMARY"] = CMISService :: getSummaryTemplate();
1141         if ($content)
1142         {
1143             $hash_values["CONTENT"] = CMISService :: getContentEntry($content, $content_type);
1144         }
1145         if (!isset ($hash_values['title']))
1146         {
1147             $hash_values['title'] = $objectName;
1148         }
1149         if (!isset ($hash_values['summary']))
1150         {
1151             $hash_values['summary'] = $objectName;
1152         }
1153         $post_value = CMISRepositoryWrapper :: processTemplate($entry_template, $hash_values);
1154         $ret = $this->doPost($myURL, $post_value, MIME_ATOM_XML_ENTRY);
1155         // print "DO_POST\n";
1156         // print_r($ret);
1157         $obj = $this->extractObject($ret->body);
1158         $this->cacheObjectInfo($obj);
1159         return $obj;
1160     }
1161
1162     function createDocument($folderId, $fileName, $properties = array (), $content = null, $content_type = "application/octet-stream", $options = array ())
1163     { // Yes
1164         return $this->postObject($folderId, $fileName, "cmis:document", $properties, $content, $content_type, $options);
1165     }
1166
1167     function createDocumentFromSource()
1168     { //Yes?
1169         throw new CmisNotSupportedException("createDocumentFromSource is not supported by the AtomPub binding!");
1170     }
1171
1172     function createFolder($folderId, $folderName, $properties = array (), $options = array ())
1173     { // Yes
1174         return $this->postObject($folderId, $folderName, "cmis:folder", $properties, null, null, $options);
1175     }
1176
1177     function createRelationship()
1178     { // Not in first Release
1179         throw Exception("Not Implemented");
1180     }
1181
1182     function createPolicy()
1183     { // Not in first Release
1184         throw Exception("Not Implemented");
1185     }
1186
1187     function updateProperties($objectId, $properties = array (), $options = array ())
1188     { // Yes
1189         $varmap = $options;
1190         $varmap["id"] = $objectId;
1191         $objectName = $this->getTitle($objectId);
1192         $objectType = $this->getObjectType($objectId);
1193         $obj_url = $this->getLink($objectId, "edit");
1194         $obj_url = CMISRepositoryWrapper :: getOpUrl($obj_url, $options);
1195         static $entry_template;
1196         if (!isset ($entry_template))
1197         {
1198             $entry_template = CMISService :: getEntryTemplate();
1199         }
1200         if (is_array($properties))
1201         {
1202             $hash_values = $properties;
1203         } else
1204         {
1205             $hash_values = array ();
1206         }
1207         $properties_xml = $this->processPropertyTemplates($objectType, $hash_values);
1208         if (is_array($options))
1209         {
1210             $hash_values = $options;
1211         } else
1212         {
1213             $hash_values = array ();
1214         }
1215         $hash_values["PROPERTIES"] = $properties_xml;
1216         $hash_values["SUMMARY"] = CMISService :: getSummaryTemplate();
1217         if (!isset ($hash_values['title']))
1218         {
1219             $hash_values['title'] = $objectName;
1220         }
1221         if (!isset ($hash_values['summary']))
1222         {
1223             $hash_values['summary'] = $objectName;
1224         }
1225         $put_value = CMISRepositoryWrapper :: processTemplate($entry_template, $hash_values);
1226                 // print $put_value; // RRM DEBUG
1227         $ret = $this->doPut($obj_url, $put_value, MIME_ATOM_XML_ENTRY);
1228         $obj = $this->extractObject($ret->body);
1229         $this->cacheObjectInfo($obj);
1230         return $obj;
1231     }
1232
1233     function moveObject($objectId, $targetFolderId, $sourceFolderId, $options = array ())
1234     { //yes
1235         $options['sourceFolderId'] = $sourceFolderId;
1236         return $this->postObject($targetFolderId, $this->getTitle($objectId), $this->getObjectType($objectId), array (
1237             "cmis:objectId" => $objectId
1238         ), null, null, $options);
1239     }
1240
1241     function deleteObject($objectId, $options = array ())
1242     { //Yes
1243         $varmap = $options;
1244         $varmap["id"] = $objectId;
1245         $obj_url = $this->getLink($objectId, "edit");
1246         $ret = $this->doDelete($obj_url);
1247         return;
1248     }
1249
1250     function deleteTree()
1251     { // Nice to have
1252         throw Exception("Not Implemented");
1253     }
1254
1255     function setContentStream($objectId, $content, $content_type, $options = array ())
1256     { //Yes
1257         $myURL = $this->getLink($objectId, "edit-media");
1258         $ret = $this->doPut($myURL, $content, $content_type);
1259     }
1260
1261     function deleteContentStream($objectId, $options = array ())
1262     { //yes
1263         $myURL = $this->getLink($objectId, "edit-media");
1264         $ret = $this->doDelete($myURL);
1265         return;
1266     }
1267
1268     //Versioning Services
1269     function getPropertiesOfLatestVersion($objectId, $major =false, $options = array ())
1270     {
1271         return $this->getObjectOfLatestVersion($objectId, $major, $options);
1272     }
1273
1274     function getObjectOfLatestVersion($objectId, $major = false, $options = array ())
1275     {
1276         return $this->getObject($objectId, $options); // Won't be able to handle major/minor distinction
1277         // Need to add this -- "current-version"
1278         /*
1279          * Headers: CMIS-filter, CMIS-returnVersion (enumReturnVersion)
1280          * HTTP Arguments: filter, returnVersion
1281          * Enum returnVersion: This, Latest, Major
1282          */
1283     }
1284
1285     function getAllVersions()
1286     {
1287         throw Exception("Not Implemented");
1288     }
1289
1290     function checkOut()
1291     {
1292         throw Exception("Not Implemented");
1293     }
1294
1295     function checkIn()
1296     {
1297         throw Exception("Not Implemented");
1298     }
1299
1300     function cancelCheckOut()
1301     {
1302         throw Exception("Not Implemented");
1303     }
1304
1305     function deleteAllVersions()
1306     {
1307         throw Exception("Not Implemented");
1308     }
1309
1310     //Relationship Services
1311     function getObjectRelationships()
1312     {
1313         // get stripped down version of object (for the links) and then get the relationships?
1314         // Low priority -- can get all information when getting object
1315         throw Exception("Not Implemented");
1316     }
1317
1318     //Multi-Filing Services
1319     function addObjectToFolder()
1320     { // Probably
1321         throw Exception("Not Implemented");
1322     }
1323
1324     function removeObjectFromFolder()
1325     { //Probably
1326         throw Exception("Not Implemented");
1327     }
1328
1329     //Policy Services
1330     function getAppliedPolicies()
1331     {
1332         throw Exception("Not Implemented");
1333     }
1334
1335     function applyPolicy()
1336     {
1337         throw Exception("Not Implemented");
1338     }
1339
1340     function removePolicy()
1341     {
1342         throw Exception("Not Implemented");
1343     }
1344
1345     //ACL Services
1346     function getACL()
1347     {
1348         throw Exception("Not Implemented");
1349     }
1350
1351     function applyACL()
1352     {
1353         throw Exception("Not Implemented");
1354     }
1355 }