This class handles the communication between Jackalope and Jackrabbit over
Davex. Once the login method has been called, the workspace is set and can
not be changed anymore.
We make one exception to the rule that nothing may be cached in the
transport: Repository descriptors are considered immutable and cached
(because they are also used in startup to check the backend version is
compatible).
/** * {@inheritDoc} */ public function deleteWorkspace($name) { $this->transport->deleteWorkspace($name); }
/** * Handles errors caused by singleRequest and multiRequest * * For transport level errors, tries to figure out what went wrong to * throw the most appropriate exception. * * @param curl $curl * @param string $response the response body * @param int $httpCode the http response code * * @throws NoSuchWorkspaceException if it was not possible to reach the server (resolve host or connect) * @throws ItemNotFoundException if the object was not found * @throws RepositoryException on any other error. * @throws PathNotFoundException if the path was not found (server returned 404 without xml response) */ protected function handleError(curl $curl, $response, $httpCode) { // first: check if the backend is too old for us if (!self::$versionChecked) { // avoid endless loops. self::$versionChecked = true; try { // getting the descriptors triggers a version check $this->client->getRepositoryDescriptors(); } catch (\Exception $e) { if ($e instanceof \PHPCR\UnsupportedRepositoryOperationException) { throw $e; } //otherwise ignore exception here as to not confuse what happened } } switch ($curl->errno()) { case CURLE_COULDNT_RESOLVE_HOST: case CURLE_COULDNT_CONNECT: $info = $curl->getinfo(); throw new NoSuchWorkspaceException($curl->error() . ' "' . $info['url'] . '"'); case CURLE_RECV_ERROR: throw new RepositoryException(sprintf('CURLE_RECV_ERROR (errno 56) encountered. This has been known to happen intermittently with ' . 'some versions of libcurl (see https://github.com/jackalope/jackalope-jackrabbit/issues/89). ' . 'You can use the "jackalope.jackrabbit_force_http_version_10" option to force HTTP 1.0 as a workaround')); } // use XML error response if it's there if (substr($response, 0, 2) === '<?') { $dom = new DOMDocument(); $dom->loadXML($response); $err = $dom->getElementsByTagNameNS(Client::NS_DCR, 'exception'); if ($err->length > 0) { $err = $err->item(0); $errClass = $err->getElementsByTagNameNS(Client::NS_DCR, 'class')->item(0)->textContent; $errMsg = $err->getElementsByTagNameNS(Client::NS_DCR, 'message')->item(0)->textContent; $exceptionMsg = 'HTTP ' . $httpCode . ': ' . $errMsg; switch ($errClass) { case 'javax.jcr.NoSuchWorkspaceException': throw new NoSuchWorkspaceException($exceptionMsg); case 'javax.jcr.nodetype.NoSuchNodeTypeException': throw new NoSuchNodeTypeException($exceptionMsg); case 'javax.jcr.ItemNotFoundException': throw new ItemNotFoundException($exceptionMsg); case 'javax.jcr.nodetype.ConstraintViolationException': throw new ConstraintViolationException($exceptionMsg); case 'javax.jcr.ReferentialIntegrityException': throw new ReferentialIntegrityException($exceptionMsg); //TODO: Two more errors needed for Transactions. How does the corresponding Jackrabbit response look like? // javax.transaction.RollbackException => \PHPCR\Transaction\RollbackException // java.lang.SecurityException => \PHPCR\AccessDeniedException //TODO: map more errors here? //TODO: Two more errors needed for Transactions. How does the corresponding Jackrabbit response look like? // javax.transaction.RollbackException => \PHPCR\Transaction\RollbackException // java.lang.SecurityException => \PHPCR\AccessDeniedException //TODO: map more errors here? default: // try to generically "guess" the right exception class name $class = substr($errClass, strlen('javax.jcr.')); $class = explode('.', $class); array_walk($class, function (&$ns) { $ns = ucfirst(str_replace('nodetype', 'NodeType', $ns)); }); $class = '\\PHPCR\\' . implode('\\', $class); if (class_exists($class)) { throw new $class($exceptionMsg); } throw new RepositoryException($exceptionMsg . " ({$errClass})"); } } } if (401 == $httpCode) { throw new LoginException("HTTP 401 Unauthorized\n" . $this->getShortErrorString()); } if (404 == $httpCode) { throw new PathNotFoundException("HTTP 404 Path Not Found: {$this->method} \n" . $this->getShortErrorString()); } if (405 == $httpCode) { throw new HTTPErrorException("HTTP 405 Method Not Allowed: {$this->method} \n" . $this->getShortErrorString(), 405); } if (412 == $httpCode) { throw new LockException("Unable to lock the non-lockable node '" . reset($this->uri) . "\n" . $this->getShortErrorString()); } if ($httpCode >= 500) { $msg = "HTTP {$httpCode} Error from backend on: {$this->method} \n" . $this->getLongErrorString($curl, $response); try { $workspaceUri = array($this->client->getWorkSpaceUri()); if (!$this->errorHandlingMode && ($workspaceUri !== $this->uri || self::GET !== $this->method)) { $this->errorHandlingMode = true; $this->setUri($workspaceUri); $this->setMethod(self::GET); $this->executeDom(); } } catch (PathNotFoundException $e) { $msg = "Error likely caused by incorrect server URL configuration '" . reset($this->uri) . "' resulted in:\n{$msg}"; } $this->errorHandlingMode = false; throw new RepositoryException($msg); } $curlError = $curl->error(); $msg = "Unexpected error: \nCURL Error: {$curlError} \nResponse (HTTP {$httpCode}): {$this->method} \n" . $this->getLongErrorString($curl, $response); throw new RepositoryException($msg); }
/** * {@inheritDoc} */ public function getNodePathForIdentifier($uuid, $workspace = null) { if (null !== $workspace && $workspace != $this->workspace) { $client = new Client($this->factory, $this->server); $client->login($this->credentials, $workspace); return $client->getNodePathForIdentifier($uuid); } $request = $this->getRequest(Request::REPORT, $this->workspaceUri); $request->setBody($this->buildLocateRequest($uuid)); $dom = $request->executeDom(); /* answer looks like <D:multistatus xmlns:D="DAV:"> <D:response> <D:href>http://localhost:8080/server/tests/jcr%3aroot/tests_level1_access_base/idExample/</D:href> </D:response> </D:multistatus> */ $set = $dom->getElementsByTagNameNS(self::NS_DAV, 'href'); if ($set->length != 1) { throw new RepositoryException('Unexpected answer from server: ' . $dom->saveXML()); } $fullPath = $set->item(0)->textContent; if (strncmp($this->workspaceUriRoot, $fullPath, strlen($this->workspaceUri))) { throw new RepositoryException("Server answered a path that is not in the current workspace: uuid={$uuid}, path={$fullPath}, workspace=" . $this->workspaceUriRoot); } return $this->stripServerRootFromUri(substr(urldecode($fullPath), 0, -1)); }