CrudUpdate.php
Go to the documentation of this file.
00001 <?php 00002 00005 00026 class CrudUpdate extends WebService 00027 { 00029 private $db; 00030 00032 private $conneg; 00033 00035 private $dtdURL; 00036 00038 public static $supportedSerializations = 00039 array ("application/json", "application/rdf+xml", "application/rdf+n3", "application/*", "text/xml", "text/*", 00040 "*/*"); 00041 00043 private $registered_ip = ""; 00044 00046 private $dataset; 00047 00049 private $document = array(); 00050 00052 private $mime = ""; 00053 00055 private $requester_ip = ""; 00056 00058 private $errorMessenger = 00059 '{ 00060 "ws": "/ws/crud/update/", 00061 "_200": { 00062 "id": "WS-CRUD-UPDATE-200", 00063 "level": "Warning", 00064 "name": "No RDF document to index", 00065 "description": "No RDF document defined for this query" 00066 }, 00067 "_201": { 00068 "id": "WS-CRUD-UPDATE-201", 00069 "level": "Warning", 00070 "name": "Unknown MIME type for this RDF document", 00071 "description": "Unknown MIME type defined for the target RDF document for this query" 00072 }, 00073 "_202": { 00074 "id": "WS-CRUD-UPDATE-202", 00075 "level": "Warning", 00076 "name": "No dataset specified", 00077 "description": "No dataset URI has been defined for this query" 00078 }, 00079 "_300": { 00080 "id": "WS-CRUD-UPDATE-300", 00081 "level": "Warning", 00082 "name": "Syntax error in the RDF document", 00083 "description": "A syntax error has been detected in the RDF document" 00084 }, 00085 "_301": { 00086 "id": "WS-CRUD-UPDATE-301", 00087 "level": "Fatal", 00088 "name": "Can\'t update the record(s) in the triple store", 00089 "description": "An error occured when we tried to update the record(s) in the triple store" 00090 }, 00091 "_302": { 00092 "id": "WS-CRUD-UPDATE-302", 00093 "level": "Fatal", 00094 "name": "Can\'t list the record(s) that have to be updated", 00095 "description": "An error occured when we tried to list all the record(s) that have to be updated" 00096 }, 00097 "_303": { 00098 "id": "WS-CRUD-UPDATE-303", 00099 "level": "Fatal", 00100 "name": "Can\'t delete the temporary update graph", 00101 "description": "An error occured when we tried to delete the temporary update graph" 00102 }, 00103 "_304": { 00104 "id": "WS-CRUD-UPDATE-304", 00105 "level": "Fatal", 00106 "name": "Can\'t update the Solr index", 00107 "description": "An error occured when we tried to update the Solr index" 00108 }, 00109 "_305": { 00110 "id": "WS-CRUD-UPDATE-305", 00111 "level": "Fatal", 00112 "name": "Can\'t commit changes to the Solr index", 00113 "description": "An error occured when we tried to commit changes to the Solr index" 00114 }, 00115 "_307": { 00116 "id": "WS-CRUD-CREATE-307", 00117 "level": "Warning", 00118 "name": "Can\'t parse RDF document", 00119 "description": "Can\'t parse the specified RDF document" 00120 }, 00121 "_308": { 00122 "id": "WS-CRUD-CREATE-308", 00123 "level": "Fatal", 00124 "name": "Can\'t create a tracking record for one of the input records", 00125 "description": "We can\'t create the records because we can\'t ensure that we have a track of their changes." 00126 } 00127 }'; 00128 00129 00141 function __construct($document, $mime, $dataset, $registered_ip, $requester_ip) 00142 { 00143 parent::__construct(); 00144 00145 $this->db = new DB_Virtuoso($this->db_username, $this->db_password, $this->db_dsn, $this->db_host); 00146 00147 $this->requester_ip = $requester_ip; 00148 $this->dataset = $dataset; 00149 $this->mime = $mime; 00150 00151 if (extension_loaded("mbstring") && mb_detect_encoding($document, "UTF-8", TRUE) != "UTF-8") 00152 { 00153 $this->document = utf8_encode($document); 00154 } 00155 else //we have to assume the input is UTF-8 00156 { 00157 $this->document = $document; 00158 } 00159 00160 if($registered_ip == "") 00161 { 00162 $this->registered_ip = $requester_ip; 00163 } 00164 else 00165 { 00166 $this->registered_ip = $registered_ip; 00167 } 00168 00169 if(strtolower(substr($this->registered_ip, 0, 4)) == "self") 00170 { 00171 $pos = strpos($this->registered_ip, "::"); 00172 00173 if($pos !== FALSE) 00174 { 00175 $account = substr($this->registered_ip, $pos + 2, strlen($this->registered_ip) - ($pos + 2)); 00176 00177 $this->registered_ip = $requester_ip . "::" . $account; 00178 } 00179 else 00180 { 00181 $this->registered_ip = $requester_ip; 00182 } 00183 } 00184 00185 $this->uri = $this->wsf_base_url . "/wsf/ws/crud/update/"; 00186 $this->title = "Crud Update Web Service"; 00187 $this->crud_usage = new CrudUsage(TRUE, FALSE, FALSE, FALSE); 00188 $this->endpoint = $this->wsf_base_url . "/ws/crud/update/"; 00189 00190 $this->dtdURL = "auth/CrudUpdate.dtd"; 00191 00192 $this->errorMessenger = json_decode($this->errorMessenger); 00193 } 00194 00195 function __destruct() 00196 { 00197 parent::__destruct(); 00198 00199 if(isset($this->db)) 00200 { 00201 @$this->db->close(); 00202 } 00203 } 00204 00215 protected function validateQuery() 00216 { 00217 // Validation of the "requester_ip" to make sure the system that is sending the query as the rights. 00218 $ws_av = new AuthValidator($this->requester_ip, $this->dataset, $this->uri); 00219 00220 $ws_av->pipeline_conneg($this->conneg->getAccept(), $this->conneg->getAcceptCharset(), 00221 $this->conneg->getAcceptEncoding(), $this->conneg->getAcceptLanguage()); 00222 00223 $ws_av->process(); 00224 00225 if($ws_av->pipeline_getResponseHeaderStatus() != 200) 00226 { 00227 $this->conneg->setStatus($ws_av->pipeline_getResponseHeaderStatus()); 00228 $this->conneg->setStatusMsg($ws_av->pipeline_getResponseHeaderStatusMsg()); 00229 $this->conneg->setStatusMsgExt($ws_av->pipeline_getResponseHeaderStatusMsgExt()); 00230 $this->conneg->setError($ws_av->pipeline_getError()->id, $ws_av->pipeline_getError()->webservice, 00231 $ws_av->pipeline_getError()->name, $ws_av->pipeline_getError()->description, 00232 $ws_av->pipeline_getError()->debugInfo, $ws_av->pipeline_getError()->level); 00233 00234 return; 00235 } 00236 00237 unset($ws_av); 00238 00239 // If the system send a query on the behalf of another user, we validate that other user as well 00240 if($this->registered_ip != $this->requester_ip) 00241 { 00242 // Validation of the "registered_ip" to make sure the user of this system has the rights 00243 $ws_av = new AuthValidator($this->registered_ip, $this->dataset, $this->uri); 00244 00245 $ws_av->pipeline_conneg($this->conneg->getAccept(), $this->conneg->getAcceptCharset(), 00246 $this->conneg->getAcceptEncoding(), $this->conneg->getAcceptLanguage()); 00247 00248 $ws_av->process(); 00249 00250 if($ws_av->pipeline_getResponseHeaderStatus() != 200) 00251 { 00252 $this->conneg->setStatus($ws_av->pipeline_getResponseHeaderStatus()); 00253 $this->conneg->setStatusMsg($ws_av->pipeline_getResponseHeaderStatusMsg()); 00254 $this->conneg->setStatusMsgExt($ws_av->pipeline_getResponseHeaderStatusMsgExt()); 00255 $this->conneg->setError($ws_av->pipeline_getError()->id, $ws_av->pipeline_getError()->webservice, 00256 $ws_av->pipeline_getError()->name, $ws_av->pipeline_getError()->description, 00257 $ws_av->pipeline_getError()->debugInfo, $ws_av->pipeline_getError()->level); 00258 return; 00259 } 00260 } 00261 } 00262 00273 public function pipeline_getError() { return ($this->conneg->error); } 00274 00275 00286 public function pipeline_getResultset() { return ""; } 00287 00300 public function injectDoctype($xmlDoc) 00301 { 00302 $posHeader = strpos($xmlDoc, '"?>') + 3; 00303 $xmlDoc = substr($xmlDoc, 0, $posHeader) 00304 . "\n<!DOCTYPE resultset PUBLIC \"-//Structured Dynamics LLC//Crud Update DTD 0.1//EN\" \"" . $this->dtdBaseURL 00305 . $this->dtdURL . "\">" . substr($xmlDoc, $posHeader, strlen($xmlDoc) - $posHeader); 00306 00307 return ($xmlDoc); 00308 } 00309 00328 public function ws_conneg($accept, $accept_charset, $accept_encoding, $accept_language) 00329 { 00330 $this->conneg = 00331 new Conneg($accept, $accept_charset, $accept_encoding, $accept_language, CrudUpdate::$supportedSerializations); 00332 00333 // Check for errors 00334 00335 if($this->document == "") 00336 { 00337 $this->conneg->setStatus(400); 00338 $this->conneg->setStatusMsg("Bad Request"); 00339 $this->conneg->setStatusMsgExt($this->errorMessenger->_200->name); 00340 $this->conneg->setError($this->errorMessenger->_200->id, $this->errorMessenger->ws, 00341 $this->errorMessenger->_200->name, $this->errorMessenger->_200->description, "", 00342 $this->errorMessenger->_200->level); 00343 00344 return; 00345 } 00346 00347 if($this->mime != "application/rdf+xml" && $this->mime != "application/rdf+n3") 00348 { 00349 $this->conneg->setStatus(400); 00350 $this->conneg->setStatusMsg("Bad Request"); 00351 $this->conneg->setStatusMsgExt($this->errorMessenger->_201->name); 00352 $this->conneg->setError($this->errorMessenger->_201->id, $this->errorMessenger->ws, 00353 $this->errorMessenger->_201->name, $this->errorMessenger->_201->description, "", 00354 $this->errorMessenger->_201->level); 00355 00356 return; 00357 } 00358 00359 if($this->dataset == "") 00360 { 00361 $this->conneg->setStatus(400); 00362 $this->conneg->setStatusMsg("Bad Request"); 00363 $this->conneg->setStatusMsgExt($this->errorMessenger->_202->name); 00364 $this->conneg->setError($this->errorMessenger->_202->id, $this->errorMessenger->ws, 00365 $this->errorMessenger->_202->name, $this->errorMessenger->_202->description, "", 00366 $this->errorMessenger->_202->level); 00367 return; 00368 } 00369 00370 // Check if the dataset is created 00371 00372 $ws_dr = new DatasetRead($this->dataset, "false", "self", 00373 $this->wsf_local_ip); // Here the one that makes the request is the WSF (internal request). 00374 // $ws_dr = new DatasetRead($this->dataset, "false", $this->registered_ip, $this->requester_ip); 00375 00376 $ws_dr->pipeline_conneg($this->conneg->getAccept(), $this->conneg->getAcceptCharset(), 00377 $this->conneg->getAcceptEncoding(), $this->conneg->getAcceptLanguage()); 00378 00379 $ws_dr->process(); 00380 00381 if($ws_dr->pipeline_getResponseHeaderStatus() != 200) 00382 { 00383 $this->conneg->setStatus($ws_dr->pipeline_getResponseHeaderStatus()); 00384 $this->conneg->setStatusMsg($ws_dr->pipeline_getResponseHeaderStatusMsg()); 00385 $this->conneg->setStatusMsgExt($ws_dr->pipeline_getResponseHeaderStatusMsgExt()); 00386 $this->conneg->setError($ws_dr->pipeline_getError()->id, $ws_dr->pipeline_getError()->webservice, 00387 $ws_dr->pipeline_getError()->name, $ws_dr->pipeline_getError()->description, 00388 $ws_dr->pipeline_getError()->debugInfo, $ws_dr->pipeline_getError()->level); 00389 return; 00390 } 00391 } 00392 00411 public function pipeline_conneg($accept, $accept_charset, $accept_encoding, $accept_language) 00412 { $this->ws_conneg($accept, $accept_charset, $accept_encoding, $accept_language); } 00413 00424 public function pipeline_getResponseHeaderStatus() { return $this->conneg->getStatus(); } 00425 00436 public function pipeline_getResponseHeaderStatusMsg() { return $this->conneg->getStatusMsg(); } 00437 00450 public function pipeline_getResponseHeaderStatusMsgExt() { return $this->conneg->getStatusMsgExt(); } 00451 00462 public function pipeline_serialize() { return ""; } 00463 00472 public function pipeline_serialize_reification() { return ""; } 00473 00484 public function ws_serialize() { return ""; } 00485 00498 public function ws_respond($content) 00499 { 00500 // First send the header of the request 00501 $this->conneg->respond(); 00502 00503 // second, send the content of the request 00504 00505 // Make sure there is no error. 00506 if($this->conneg->getStatus() == 200) 00507 { 00508 echo $content; 00509 } 00510 00511 $this->__destruct(); 00512 } 00513 00514 00523 public function process() 00524 { 00525 // Make sure there was no conneg error prior to this process call 00526 if($this->conneg->getStatus() == 200) 00527 { 00528 $this->validateQuery(); 00529 00530 // If the query is still valid 00531 if($this->conneg->getStatus() == 200) 00532 { 00533 // Step #0: Parse the file using ARC2 to populate the Solr index. 00534 // Get triples from ARC for some offline processing. 00535 $parser = ARC2::getRDFParser(); 00536 $parser->parse($this->dataset, $this->document); 00537 00538 $rdfxmlSerializer = ARC2::getRDFXMLSerializer(); 00539 00540 $resourceIndex = $parser->getSimpleIndex(0); 00541 00542 if(count($parser->getErrors()) > 0) 00543 { 00544 $errorsOutput = ""; 00545 $errors = $parser->getErrors(); 00546 00547 foreach($errors as $key => $error) 00548 { 00549 $errorsOutput .= "[Error #$key] $error\n"; 00550 } 00551 00552 $this->conneg->setStatus(400); 00553 $this->conneg->setStatusMsg("Bad Request"); 00554 $this->conneg->setError($this->errorMessenger->_307->id, $this->errorMessenger->ws, 00555 $this->errorMessenger->_307->name, $this->errorMessenger->_307->description, $errorsOutput, 00556 $this->errorMessenger->_307->level); 00557 00558 return; 00559 } 00560 00561 // Get all the reification statements 00562 $break = FALSE; 00563 $statementsUri = array(); 00564 00565 foreach($resourceIndex as $resource => $description) 00566 { 00567 foreach($description as $predicate => $values) 00568 { 00569 if($predicate == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type") 00570 { 00571 foreach($values as $value) 00572 { 00573 if($value["type"] == "uri" && $value["value"] == "http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement") 00574 { 00575 array_push($statementsUri, $resource); 00576 break; 00577 } 00578 } 00579 } 00580 00581 if($break) 00582 { 00583 break; 00584 } 00585 } 00586 00587 if($break) 00588 { 00589 break; 00590 } 00591 } 00592 00593 // Get all references of all instance records resources (except for the statement resources) 00594 $irsUri = array(); 00595 00596 foreach($resourceIndex as $resource => $description) 00597 { 00598 if($resource != $datasetUri && array_search($resource, $statementsUri) === FALSE) 00599 { 00600 array_push($irsUri, $resource); 00601 } 00602 } 00603 00604 // Track the record description changes 00605 if($this->track_update === TRUE) 00606 { 00607 foreach($irsUri as $uri) 00608 { 00609 // First check if the record is already existing for this record, within this dataset. 00610 include_once("../read/CrudRead.php"); 00611 00612 $ws_cr = new CrudRead($uri, $this->dataset, FALSE, TRUE, $this->registered_ip, $this->requester_ip); 00613 00614 $ws_cr->ws_conneg("application/rdf+xml", "utf-8", "identity", "en"); 00615 00616 $ws_cr->process(); 00617 00618 $oldRecordDescription = $ws_cr->ws_serialize(); 00619 00620 $ws_cr_error = $ws_cr->pipeline_getError(); 00621 00622 if($ws_cr->pipeline_getResponseHeaderStatus() == 400 && $ws_cr_error->id == "WS-CRUD-READ-300") 00623 { 00624 // The record is not existing within this dataset, so we simply move-on 00625 continue; 00626 } 00627 elseif($ws_cr->pipeline_getResponseHeaderStatus() != 200) 00628 { 00629 // An error occured. Since we can't get the past state of a record, we have to send an error 00630 // for the CrudUpdate call since we can't create a tracking record for this record. 00631 $this->conneg->setStatus(400); 00632 $this->conneg->setStatusMsg("Bad Request"); 00633 $this->conneg->setError($this->errorMessenger->_308->id, $this->errorMessenger->ws, 00634 $this->errorMessenger->_308->name, $this->errorMessenger->_308->description, 00635 "We can't create a track record for the following record: $uri", 00636 $this->errorMessenger->_308->level); 00637 00638 break; 00639 } 00640 00641 $endpoint = ""; 00642 if($this->tracking_endpoint != "") 00643 { 00644 // We send the query to a remove tracking endpoint 00645 $endpoint = $this->tracking_endpoint."create/"; 00646 } 00647 else 00648 { 00649 // We send the query to a local tracking endpoint 00650 $endpoint = $this->wsf_base_url."/ws/tracker/create/"; 00651 } 00652 00653 include_once("../../framework/WebServiceQuerier.php"); 00654 00655 $wsq = new WebServiceQuerier($endpoint, "post", 00656 "text/xml", "from_dataset=" . urlencode($this->dataset) . 00657 "&record=" . urlencode($uri) . 00658 "&action=update" . 00659 "&previous_state=" . urlencode($oldRecordDescription) . 00660 "&previous_state_mime=" . urlencode("application/rdf+xml") . 00661 "&performer=" . urlencode($this->registered_ip) . 00662 "®istered_ip=self"); 00663 00664 if($wsq->getStatus() != 200) 00665 { 00666 $this->conneg->setStatus($wsq->getStatus()); 00667 $this->conneg->setStatusMsg($wsq->getStatusMessage()); 00668 /* 00669 $this->conneg->setError($this->errorMessenger->_302->id, $this->errorMessenger->ws, 00670 $this->errorMessenger->_302->name, $this->errorMessenger->_302->description, odbc_errormsg(), 00671 $this->errorMessenger->_302->level); 00672 */ 00673 } 00674 00675 unset($wsq); 00676 } 00677 } 00678 00679 00680 // Step #1: indexing the incomming rdf document in its own temporary graph 00681 $tempGraphUri = "temp-graph-" . md5($this->document); 00682 00683 $irs = array(); 00684 00685 foreach($irsUri as $uri) 00686 { 00687 $irs[$uri] = $resourceIndex[$uri]; 00688 } 00689 00690 @$this->db->query("DB.DBA.RDF_LOAD_RDFXML_MT('" 00691 . str_replace("'", "\'", $rdfxmlSerializer->getSerializedIndex($irs)) 00692 . "', '$tempGraphUri', '$tempGraphUri', 0)"); 00693 00694 if(odbc_error()) 00695 { 00696 $this->conneg->setStatus(400); 00697 $this->conneg->setStatusMsg("Bad Request"); 00698 $this->conneg->setStatusMsgExt($this->errorMessenger->_300->name); 00699 $this->conneg->setError($this->errorMessenger->_300->id, $this->errorMessenger->ws, 00700 $this->errorMessenger->_300->name, $this->errorMessenger->_300->description, odbc_errormsg(), 00701 $this->errorMessenger->_300->level); 00702 return; 00703 } 00704 00705 // Step #2: use that temp graph to modify (delete/insert using SPARUL) the target graph of the update query 00706 $query = "delete from <" . $this->dataset . "> 00707 { 00708 ?s ?p_original ?o_original. 00709 } 00710 where 00711 { 00712 graph <" . $tempGraphUri . "> 00713 { 00714 ?s ?p ?o. 00715 } 00716 00717 graph <" . $this->dataset . "> 00718 { 00719 ?s ?p_original ?o_original. 00720 } 00721 } 00722 00723 insert into <" . $this->dataset . "> 00724 { 00725 ?s ?p ?o. 00726 } 00727 where 00728 { 00729 graph <" . $tempGraphUri . "> 00730 { 00731 ?s ?p ?o. 00732 } 00733 }"; 00734 00735 @$this->db->query($this->db->build_sparql_query(str_replace(array ("\n", "\r", "\t"), " ", $query), array(), 00736 FALSE)); 00737 00738 if(odbc_error()) 00739 { 00740 $this->conneg->setStatus(500); 00741 $this->conneg->setStatusMsg("Internal Error"); 00742 $this->conneg->setStatusMsgExt($this->errorMessenger->_301->name); 00743 $this->conneg->setError($this->errorMessenger->_301->id, $this->errorMessenger->ws, 00744 $this->errorMessenger->_301->name, $this->errorMessenger->_301->description, odbc_errormsg(), 00745 $this->errorMessenger->_301->level); 00746 00747 return; 00748 } 00749 00750 if(count($statementsUri) > 0) 00751 { 00752 $tempGraphReificationUri = "temp-graph-reification-" . md5($this->document); 00753 00754 $statements = array(); 00755 00756 foreach($statementsUri as $uri) 00757 { 00758 $statements[$uri] = $resourceIndex[$uri]; 00759 } 00760 00761 @$this->db->query("DB.DBA.RDF_LOAD_RDFXML_MT('" 00762 . str_replace("'", "\'", $rdfxmlSerializer->getSerializedIndex($statements)) 00763 . "', '$tempGraphReificationUri', '$tempGraphReificationUri', 0)"); 00764 00765 if(odbc_error()) 00766 { 00767 $this->conneg->setStatus(400); 00768 $this->conneg->setStatusMsg("Bad Request"); 00769 $this->conneg->setStatusMsgExt($this->errorMessenger->_300->name); 00770 $this->conneg->setError($this->errorMessenger->_300->id, $this->errorMessenger->ws, 00771 $this->errorMessenger->_300->name, $this->errorMessenger->_300->description, odbc_errormsg(), 00772 $this->errorMessenger->_300->level); 00773 return; 00774 } 00775 00776 00777 // Step #2.5: use the temp graph to modify the reification graph 00778 $query = "delete from <" . $this->dataset . "reification/> 00779 { 00780 ?s_original ?p_original ?o_original. 00781 } 00782 where 00783 { 00784 graph <" . $tempGraphReificationUri . "> 00785 { 00786 ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#subject> ?rei_subject . 00787 ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate> ?rei_predicate . 00788 ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#object> ?rei_object . 00789 00790 ?s ?p ?o. 00791 } 00792 00793 graph <" . $this->dataset . "reification/> 00794 { 00795 ?s_original <http://www.w3.org/1999/02/22-rdf-syntax-ns#subject> ?rei_subject . 00796 ?s_original <http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate> ?rei_predicate . 00797 ?s_original <http://www.w3.org/1999/02/22-rdf-syntax-ns#object> ?rei_object . 00798 00799 ?s_original ?p_original ?o_original. 00800 } 00801 } 00802 00803 insert into <" . $this->dataset . "reification/> 00804 { 00805 ?s_original ?p2 ?o2. 00806 } 00807 where 00808 { 00809 graph <" . $tempGraphReificationUri . "> 00810 { 00811 ?s_original ?p2 ?o2. 00812 } 00813 }"; 00814 00815 @$this->db->query($this->db->build_sparql_query(str_replace(array ("\n", "\r", "\t"), " ", $query), array(), 00816 FALSE)); 00817 00818 if(odbc_error()) 00819 { 00820 $this->conneg->setStatus(500); 00821 $this->conneg->setStatusMsg("Internal Error"); 00822 $this->conneg->setStatusMsgExt($this->errorMessenger->_301->name); 00823 $this->conneg->setError($this->errorMessenger->_301->id, $this->errorMessenger->ws, 00824 $this->errorMessenger->_301->name, $this->errorMessenger->_301->description, odbc_errormsg(), 00825 $this->errorMessenger->_301->level); 00826 00827 return; 00828 } 00829 00830 // Step #2.6: Remove the temp graph 00831 $query = "clear graph <" . $tempGraphReificationUri . ">"; 00832 00833 @$this->db->query($this->db->build_sparql_query(str_replace(array ("\n", "\r", "\t"), "", $query), array(), 00834 FALSE)); 00835 00836 if(odbc_error()) 00837 { 00838 $this->conneg->setStatus(500); 00839 $this->conneg->setStatusMsg("Internal Error"); 00840 $this->conneg->setStatusMsgExt($this->errorMessenger->_303->name); 00841 $this->conneg->setError($this->errorMessenger->_303->id, $this->errorMessenger->ws, 00842 $this->errorMessenger->_303->name, $this->errorMessenger->_303->description, 00843 odbc_errormsg() . " -- Query: [" . str_replace(array ("\n", "\r", "\t"), " ", $query) . "]", 00844 $this->errorMessenger->_303->level); 00845 return; 00846 } 00847 } 00848 00849 // Step #3: Remove the temp graph 00850 $query = "clear graph <" . $tempGraphUri . ">"; 00851 00852 @$this->db->query($this->db->build_sparql_query(str_replace(array ("\n", "\r", "\t"), "", $query), array(), 00853 FALSE)); 00854 00855 if(odbc_error()) 00856 { 00857 $this->conneg->setStatus(500); 00858 $this->conneg->setStatusMsg("Internal Error"); 00859 $this->conneg->setStatusMsgExt($this->errorMessenger->_303->name); 00860 $this->conneg->setError($this->errorMessenger->_303->id, $this->errorMessenger->ws, 00861 $this->errorMessenger->_303->name, $this->errorMessenger->_303->description, 00862 odbc_errormsg() . " -- Query: [" . str_replace(array ("\n", "\r", "\t"), " ", $query) . "]", 00863 $this->errorMessenger->_303->level); 00864 return; 00865 } 00866 00867 00868 // Step #4: Update Solr index 00869 00870 00878 /* 00879 $resultset = $this->db->query("select * from SD.WSF.ws_ontologies where struct_type = 'class'"); 00880 00881 odbc_binmode($resultset, ODBC_BINMODE_PASSTHRU); 00882 odbc_longreadlen($resultset, 16384); 00883 00884 odbc_fetch_row($resultset); 00885 $classHierarchy = unserialize(odbc_result($resultset, "struct")); 00886 00887 if (odbc_error()) 00888 { 00889 $this->conneg->setStatus(500); 00890 $this->conneg->setStatusMsg("Internal Error"); 00891 $this->conneg->setStatusMsgExt("Error #crud-create-103"); 00892 return; 00893 } 00894 */ 00895 00896 $filename = rtrim($this->ontological_structure_folder, "/") . "/classHierarchySerialized.srz"; 00897 $file = fopen($filename, "r"); 00898 $classHierarchy = fread($file, filesize($filename)); 00899 $classHierarchy = unserialize($classHierarchy); 00900 fclose($file); 00901 00902 $labelProperties = 00903 array (Namespaces::$iron . "prefLabel", Namespaces::$iron . "altLabel", Namespaces::$skos_2008 . "prefLabel", 00904 Namespaces::$skos_2008 . "altLabel", Namespaces::$skos_2004 . "prefLabel", 00905 Namespaces::$skos_2004 . "altLabel", Namespaces::$rdfs . "label", Namespaces::$dcterms . "title", 00906 Namespaces::$foaf . "name", Namespaces::$foaf . "givenName", Namespaces::$foaf . "family_name"); 00907 00908 $descriptionProperties = array (Namespaces::$iron . "description", Namespaces::$dcterms . "description", 00909 Namespaces::$skos_2008 . "definition", Namespaces::$skos_2004 . "definition"); 00910 00911 00912 // Index in Solr 00913 00914 $solr = new Solr($this->wsf_solr_core, $this->solr_host, $this->solr_port); 00915 00916 // Used to detect if we will be creating a new field. If we are, then we will 00917 // update the fields index once the new document will be indexed. 00918 $indexedFields = $solr->getFieldsIndex(); 00919 $newFields = FALSE; 00920 00921 foreach($irsUri as $subject) 00922 { 00923 // Skip Bnodes indexation in Solr 00924 // One of the prerequise is that each records indexed in Solr (and then available in Search and Browse) 00925 // should have a URI. Bnodes are simply skiped. 00926 00927 if(stripos($subject, "_:arc") !== FALSE) 00928 { 00929 continue; 00930 } 00931 00932 $add = "<add><doc><field name=\"uid\">" . md5($this->dataset . $subject) . "</field>"; 00933 $add .= "<field name=\"uri\">$subject</field>"; 00934 $add .= "<field name=\"dataset\">" . $this->dataset . "</field>"; 00935 00936 // Get types for this subject. 00937 $types = array(); 00938 00939 foreach($resourceIndex[$subject]["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"] as $value) 00940 { 00941 array_push($types, $value["value"]); 00942 00943 $add .= "<field name=\"type\">" . $value["value"] . "</field>"; 00944 } 00945 00946 // get the preferred and alternative labels for this resource 00947 $prefLabelFound = FALSE; 00948 00949 foreach($labelProperties as $property) 00950 { 00951 if(isset($resourceIndex[$subject][$property]) && !$prefLabelFound) 00952 { 00953 $prefLabelFound = TRUE; 00954 $add .= "<field name=\"prefLabel\">" . $this->xmlEncode($resourceIndex[$subject][$property][0]["value"]) 00955 . "</field>"; 00956 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$iron . "prefLabel") . "</field>"; 00957 } 00958 elseif(isset($resourceIndex[$subject][$property])) 00959 { 00960 foreach($resourceIndex[$subject][$property] as $value) 00961 { 00962 $add .= "<field name=\"altLabel\">" . $this->xmlEncode($value["value"]) . "</field>"; 00963 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$iron . "altLabel") . "</field>"; 00964 } 00965 } 00966 } 00967 00968 // get the description of the resource 00969 foreach($descriptionProperties as $property) 00970 { 00971 if(isset($resourceIndex[$subject][$property])) 00972 { 00973 $add .= "<field name=\"description\">" . $this->xmlEncode($resourceIndex[$subject][$property][0]["value"]) 00974 . "</field>"; 00975 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$iron . "description") . "</field>"; 00976 break; 00977 } 00978 } 00979 00980 // Add the prefURL if available 00981 if(isset($resourceIndex[$subject][$iron . "prefURL"])) 00982 { 00983 $add .= "<field name=\"prefURL\">" 00984 . $this->xmlEncode($resourceIndex[$subject][$iron . "prefURL"][0]["value"]) . "</field>"; 00985 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$iron . "prefURL") . "</field>"; 00986 } 00987 00988 // If enabled, and supported by the structWSF setting, let's add any lat/long positionning to the index. 00989 if($this->geoEnabled) 00990 { 00991 // Check if there exists a lat-long coordinate for that resource. 00992 if(isset($resourceIndex[$subject][Namespaces::$geo."lat"]) && 00993 isset($resourceIndex[$subject][Namespaces::$geo."long"])) 00994 { 00995 $lat = $resourceIndex[$subject][Namespaces::$geo."lat"][0]["value"]; 00996 $long = $resourceIndex[$subject][Namespaces::$geo."long"][0]["value"]; 00997 00998 // Add Lat/Long 00999 $add .= "<field name=\"lat\">". 01000 $this->xmlEncode($lat). 01001 "</field>"; 01002 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$geo."lat") . "</field>"; 01003 01004 $add .= "<field name=\"long\">". 01005 $this->xmlEncode($long). 01006 "</field>"; 01007 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$geo."long") . "</field>"; 01008 01009 // Add Lat/Long in radius 01010 01011 $add .= "<field name=\"lat_rad\">". 01012 $this->xmlEncode($lat * (pi() / 180)). 01013 "</field>"; 01014 01015 $add .= "<field name=\"long_rad\">". 01016 $this->xmlEncode($long * (pi() / 180)). 01017 "</field>"; 01018 01019 // Add hashcode 01020 01021 include_once("../../framework/geohash.php"); 01022 01023 $geohash = new Geohash(); 01024 01025 $add .= "<field name=\"geohash\">". 01026 $this->xmlEncode($geohash->encode($lat, $long)). 01027 "</field>"; 01028 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$sco."geohash") . "</field>"; 01029 01030 01031 // Add cartesian tiers 01032 01033 // Note: Cartesian tiers are not currently supported. The Lucene Java API 01034 // for this should be ported to PHP to enable this feature. 01035 } 01036 01037 $coordinates; 01038 01039 // Check if there is a polygonCoordinates property 01040 if(isset($resourceIndex[$subject][Namespaces::$sco."polygonCoordinates"])) 01041 { 01042 $polygonCoordinates = $resourceIndex[$subject][Namespaces::$sco."polygonCoordinates"][0]["value"]; 01043 $coordinates = explode(" ", $polygonCoordinates); 01044 01045 $add .= "<field name=\"polygonCoordinates\">". 01046 $this->xmlEncode($resourceIndex[$subject][Namespaces::$sco."polygonCoordinates"][0]["value"]). 01047 "</field>"; 01048 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$sco."polygonCoordinates") . "</field>"; 01049 } 01050 01051 // Check if there is a polylineCoordinates property 01052 if(isset($resourceIndex[$subject][Namespaces::$sco."polylineCoordinates"])) 01053 { 01054 $polylineCoordinates = $resourceIndex[$subject][Namespaces::$sco."polylineCoordinates"][0]["value"]; 01055 array_push($coordinates, explode(" ", $polygonCoordinates)); 01056 01057 $add .= "<field name=\"polylineCoordinates\">". 01058 $this->xmlEncode($resourceIndex[$subject][Namespaces::$sco."polylineCoordinates"][0]["value"]). 01059 "</field>"; 01060 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$sco."polylineCoordinates") . "</field>"; 01061 } 01062 01063 01064 if(count($coordinates) > 0) 01065 { 01066 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$geo."lat") . "</field>"; 01067 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$geo."long") . "</field>"; 01068 01069 foreach($coordinates as $key => $coordinate) 01070 { 01071 $points = explode(",", $coordinate); 01072 01073 if($points[0] != "" && $points[1] != "") 01074 { 01075 // Add Lat/Long 01076 $add .= "<field name=\"lat\">". 01077 $this->xmlEncode($points[1]). 01078 "</field>"; 01079 01080 $add .= "<field name=\"long\">". 01081 $this->xmlEncode($points[0]). 01082 "</field>"; 01083 01084 // Add altitude 01085 if(isset($points[2]) && $points[2] != "") 01086 { 01087 $add .= "<field name=\"alt\">". 01088 $this->xmlEncode($points[2]). 01089 "</field>"; 01090 if($key == 0) 01091 { 01092 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$geo."alt") . "</field>"; 01093 } 01094 } 01095 01096 // Add Lat/Long in radius 01097 01098 $add .= "<field name=\"lat_rad\">". 01099 $this->xmlEncode($points[1] * (pi() / 180)). 01100 "</field>"; 01101 01102 $add .= "<field name=\"long_rad\">". 01103 $this->xmlEncode($points[0] * (pi() / 180)). 01104 "</field>"; 01105 01106 // Add hashcode 01107 01108 include_once("../../framework/geohash.php"); 01109 01110 $geohash = new Geohash(); 01111 01112 $add .= "<field name=\"geohash\">". 01113 $this->xmlEncode($geohash->encode($points[1], $points[0])). 01114 "</field>"; 01115 01116 if($key == 0) 01117 { 01118 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$sco."geohash") . "</field>"; 01119 } 01120 01121 01122 // Add cartesian tiers 01123 01124 // Note: Cartesian tiers are not currently supported. The Lucene Java API 01125 // for this should be ported to PHP to enable this feature. 01126 } 01127 } 01128 } 01129 01130 // Check if there is any geonames:locatedIn assertion for that resource. 01131 if(isset($resourceIndex[$subject][Namespaces::$geonames."locatedIn"])) 01132 { 01133 $add .= "<field name=\"located_in\">". 01134 $this->xmlEncode($resourceIndex[$subject][Namespaces::$geonames."locatedIn"][0]["value"]). 01135 "</field>"; 01136 } 01137 01138 // Check if there is any wgs84_pos:alt assertion for that resource. 01139 if(isset($resourceIndex[$subject][Namespaces::$geo."alt"])) 01140 { 01141 $add .= "<field name=\"alt\">". 01142 $this->xmlEncode($resourceIndex[$subject][Namespaces::$geo."alt"][0]["value"]). 01143 "</field>"; 01144 $add .= "<field name=\"attribute\">" . $this->xmlEncode(Namespaces::$geo."alt") . "</field>"; 01145 } 01146 } 01147 01148 // Get properties with the type of the object 01149 foreach($resourceIndex[$subject] as $predicate => $values) 01150 { 01151 if(array_search($predicate, $labelProperties) === FALSE && 01152 array_search($predicate, $descriptionProperties) === FALSE && 01153 $predicate != Namespaces::$iron."prefURL" && 01154 $predicate != Namespaces::$geo."long" && 01155 $predicate != Namespaces::$geo."lat" && 01156 $predicate != Namespaces::$geo."alt" && 01157 $predicate != Namespaces::$sco."polygonCoordinates" && 01158 $predicate != Namespaces::$sco."polylineCoordinates") // skip label & description & prefURL properties 01159 { 01160 foreach($values as $value) 01161 { 01162 if($value["type"] == "literal") 01163 { 01164 // Detect if the field currently exists in the fields index 01165 if(!$newFields && array_search(urlencode($predicate) . "_attr", $indexedFields) !== FALSE) 01166 { 01167 $newFields = TRUE; 01168 } 01169 01170 $add .= "<field name=\"" . urlencode($predicate) . "_attr\">" . $this->xmlEncode($value["value"]) 01171 . "</field>"; 01172 $add .= "<field name=\"attribute\">" . $this->xmlEncode($predicate) . "</field>"; 01173 01174 // Check if there is a reification statement for that triple. If there is one, we index it in the index as: 01175 // <property> <text> 01176 // Note: Eventually we could want to update the Solr index to include a new "reifiedText" field. 01177 foreach($statementsUri as $statementUri) 01178 { 01179 if($resourceIndex[$statementUri]["http://www.w3.org/1999/02/22-rdf-syntax-ns#subject"][0]["value"] 01180 == $subject 01181 && $resourceIndex[$statementUri]["http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate"][0][ 01182 "value"] == $predicate && 01183 $resourceIndex[$statementUri]["http://www.w3.org/1999/02/22-rdf-syntax-ns#object"][0]["value"] 01184 == $value["value"]) 01185 { 01186 foreach($resourceIndex[$statementUri] as $reiPredicate => $reiValues) 01187 { 01188 if($reiPredicate != "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" 01189 && $reiPredicate != "http://www.w3.org/1999/02/22-rdf-syntax-ns#subject" 01190 && $reiPredicate != "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate" 01191 && $reiPredicate != "http://www.w3.org/1999/02/22-rdf-syntax-ns#object") 01192 { 01193 foreach($reiValues as $reiValue) 01194 { 01195 if($reiValue["type"] == "literal") 01196 { 01197 // Attribute used to reify information to a statement. 01198 $add .= "<field name=\"" . urlencode($reiPredicate) . "_reify_attr\">" 01199 . $this->xmlEncode($predicate) . 01200 "</field>"; 01201 01202 $add .= "<field name=\"" . urlencode($reiPredicate) . "_reify_obj\">" 01203 . $this->xmlEncode($value["value"]) . 01204 "</field>"; 01205 01206 $add .= "<field name=\"" . urlencode($reiPredicate) . "_reify_value\">" 01207 . $this->xmlEncode($reiValue["value"]) . 01208 "</field>"; 01209 01210 $add .= "<field name=\"attribute\">" . $this->xmlEncode($reiPredicate) . "</field>"; 01211 } 01212 } 01213 } 01214 } 01215 } 01216 } 01217 } 01218 elseif($value["type"] == "uri") 01219 { 01220 // Detect if the field currently exists in the fields index 01221 if(!$newFields && array_search(urlencode($predicate) . "_attr", $indexedFields) !== FALSE) 01222 { 01223 $newFields = TRUE; 01224 } 01225 01226 $query = $this->db->build_sparql_query("select ?p ?o from <" . $this->dataset . "> where {<" 01227 . $value["value"] . "> ?p ?o.}", array ('p', 'o'), FALSE); 01228 01229 $resultset3 = $this->db->query($query); 01230 01231 $subjectTriples = array(); 01232 01233 while(odbc_fetch_row($resultset3)) 01234 { 01235 $p = odbc_result($resultset3, 1); 01236 $o = odbc_result($resultset3, 2); 01237 01238 if(!isset($subjectTriples[$p])) 01239 { 01240 $subjectTriples[$p] = array(); 01241 } 01242 01243 array_push($subjectTriples[$p], $o); 01244 } 01245 01246 unset($resultset3); 01247 01248 $labels = ""; 01249 01250 foreach($labelProperties as $property) 01251 { 01252 if(isset($subjectTriples[$property])) 01253 { 01254 $labels .= $subjectTriples[$property][0] . " "; 01255 } 01256 } 01257 01258 // Detect if the field currently exists in the fields index 01259 if(!$newFields && array_search(urlencode($predicate) . "_attr_obj", $indexedFields) !== FALSE) 01260 { 01261 $newFields = TRUE; 01262 } 01263 01264 if($labels != "") 01265 { 01266 $add .= "<field name=\"" . urlencode($predicate) . "_attr_obj\">" . $this->xmlEncode($labels) 01267 . "</field>"; 01268 $add .= "<field name=\"" . urlencode($predicate) . "_attr_obj_uri\">" 01269 . $this->xmlEncode($value["value"]) . "</field>"; 01270 $add .= "<field name=\"attribute\">" . $this->xmlEncode($predicate) . "</field>"; 01271 } 01272 01273 // Check if there is a reification statement for that triple. If there is one, we index it in the index as: 01274 // <property> <text> 01275 // Note: Eventually we could want to update the Solr index to include a new "reifiedText" field. 01276 $statementAdded = FALSE; 01277 01278 foreach($statementsUri as $statementUri) 01279 { 01280 if($resourceIndex[$statementUri]["http://www.w3.org/1999/02/22-rdf-syntax-ns#subject"][0]["value"] 01281 == $subject 01282 && $resourceIndex[$statementUri]["http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate"][0][ 01283 "value"] == $predicate && 01284 $resourceIndex[$statementUri]["http://www.w3.org/1999/02/22-rdf-syntax-ns#object"][0]["value"] 01285 == $value["value"]) 01286 { 01287 foreach($resourceIndex[$statementUri] as $reiPredicate => $reiValues) 01288 { 01289 if($reiPredicate != "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" 01290 && $reiPredicate != "http://www.w3.org/1999/02/22-rdf-syntax-ns#subject" 01291 && $reiPredicate != "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate" 01292 && $reiPredicate != "http://www.w3.org/1999/02/22-rdf-syntax-ns#object") 01293 { 01294 foreach($reiValues as $reiValue) 01295 { 01296 if($reiValue["type"] == "literal") 01297 { 01298 // Attribute used to reify information to a statement. 01299 $add .= "<field name=\"" . urlencode($reiPredicate) . "_reify_attr_obj\">" 01300 . $this->xmlEncode($predicate) . 01301 "</field>"; 01302 01303 $add .= "<field name=\"" . urlencode($reiPredicate) . "_reify_obj\">" 01304 . $this->xmlEncode($value["value"]) . 01305 "</field>"; 01306 01307 $add .= "<field name=\"" . urlencode($reiPredicate) . "_reify_value\">" 01308 . $this->xmlEncode($reiValue["value"]) . 01309 "</field>"; 01310 01311 $add .= "<field name=\"attribute\">" . $this->xmlEncode($reiPredicate) . "</field>"; 01312 $statementAdded = TRUE; 01313 break; 01314 } 01315 } 01316 } 01317 01318 if($statementAdded) 01319 { 01320 break; 01321 } 01322 } 01323 } 01324 } 01325 } 01326 } 01327 } 01328 } 01329 01330 // Get all types by inference 01331 foreach($types as $type) 01332 { 01333 $superClasses = $classHierarchy->getSuperClasses($type); 01334 01335 foreach($superClasses as $sc) 01336 { 01337 $add .= "<field name=\"inferred_type\">" . $this->xmlEncode($sc->name) . "</field>"; 01338 } 01339 } 01340 01341 $add .= "</doc></add>"; 01342 01343 if(!$solr->update($add)) 01344 { 01345 $this->conneg->setStatus(500); 01346 $this->conneg->setStatusMsg("Internal Error"); 01347 $this->conneg->setError($this->errorMessenger->_304->id, $this->errorMessenger->ws, 01348 $this->errorMessenger->_304->name, $this->errorMessenger->_304->description, "", 01349 $this->errorMessenger->_304->level); 01350 return; 01351 } 01352 } 01353 01354 if($this->solr_auto_commit === FALSE) 01355 { 01356 if(!$solr->commit()) 01357 { 01358 $this->conneg->setStatus(500); 01359 $this->conneg->setStatusMsg("Internal Error"); 01360 $this->conneg->setStatusMsgExt($this->errorMessenger->_305->name); 01361 $this->conneg->setError($this->errorMessenger->_305->id, $this->errorMessenger->ws, 01362 $this->errorMessenger->_305->name, $this->errorMessenger->_305->description, "", 01363 $this->errorMessenger->_305->level); 01364 return; 01365 } 01366 } 01367 01368 // Update the fields index if a new field as been detected. 01369 if($newFields) 01370 { 01371 $solr->updateFieldsIndex(); 01372 } 01373 01374 /* 01375 if(!$solr->optimize()) 01376 { 01377 $this->conneg->setStatus(500); 01378 $this->conneg->setStatusMsg("Internal Error"); 01379 $this->conneg->setStatusMsgExt("Error #crud-create-105"); 01380 return; 01381 } 01382 */ 01383 } 01384 } 01385 } 01386 } 01387 01389 01390 ?>
