Updated 'core'.
[hub.git] / application / hub / main / database / frontend / node / class_NodeDistributedHashTableDatabaseWrapper.php
1 <?php
2 /**
3  * A database wrapper for distributed hash tables
4  *
5  * @author              Roland Haeder <webmaster@shipsimu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2015 Hub Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.shipsimu.org
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 class NodeDistributedHashTableDatabaseWrapper extends BaseDatabaseWrapper implements NodeDhtWrapper, Registerable {
25         /**
26          * "Cached" results for dabase for looking for unpublished entries
27          */
28         private $unpublishedEntriesInstance = NULL;
29
30         // Constants for database table names
31         const DB_TABLE_NODE_DHT = 'node_dht';
32
33         // Constants for database column names
34         const DB_COLUMN_NODE_ID            = 'node_id';
35         const DB_COLUMN_SESSION_ID         = 'session_id';
36         const DB_COLUMN_EXTERNAL_ADDRESS   = 'external_address';
37         const DB_COLUMN_PRIVATE_KEY_HASH   = 'private_key_hash';
38         const DB_COLUMN_NODE_MODE          = 'node_mode';
39         const DB_COLUMN_ACCEPTED_OBJECTS   = 'accepted_object_types';
40         const DB_COLUMN_NODE_LIST          = 'node_list';
41         const DB_COLUMN_PUBLICATION_STATUS = 'publication_status';
42         const DB_COLUMN_ANSWER_STATUS      = 'answer_status';
43         const DB_COLUMN_ACCEPT_BOOTSTRAP   = 'accept_bootstrap';
44
45         // Publication status'
46         const PUBLICATION_STATUS_PENDING = 'PENDING';
47
48         // Exception codes
49         const EXCEPTION_NODE_ALREADY_REGISTERED = 0x800;
50         const EXCEPTION_NODE_NOT_REGISTERED     = 0x801;
51
52         /**
53          * Protected constructor
54          *
55          * @return      void
56          */
57         protected function __construct () {
58                 // Call parent constructor
59                 parent::__construct(__CLASS__);
60         }
61
62         /**
63          * Creates an instance of this database wrapper by a provided user class
64          *
65          * @return      $wrapperInstance        An instance of the created wrapper class
66          */
67         public static final function createNodeDistributedHashTableDatabaseWrapper () {
68                 // Get a new instance
69                 $wrapperInstance = new NodeDistributedHashTableDatabaseWrapper();
70
71                 // Set (primary!) table name
72                 $wrapperInstance->setTableName(self::DB_TABLE_NODE_DHT);
73
74                 // Return the instance
75                 return $wrapperInstance;
76         }
77
78         /**
79          * Static getter for an array of all DHT database entries
80          *
81          * @return      $elements       All elements for the DHT dabase
82          */
83         public static final function getAllElements () {
84                 // Create array and ...
85                 $elements = array(
86                         self::DB_COLUMN_NODE_ID,
87                         self::DB_COLUMN_SESSION_ID,
88                         self::DB_COLUMN_EXTERNAL_ADDRESS,
89                         self::DB_COLUMN_PRIVATE_KEY_HASH,
90                         self::DB_COLUMN_NODE_MODE,
91                         self::DB_COLUMN_ACCEPTED_OBJECTS,
92                         self::DB_COLUMN_NODE_LIST
93                 );
94
95                 // ... return it
96                 return $elements;
97         }
98
99         /**
100          * Prepares a search instance for given node data
101          *
102          * @param       $nodeData                       An array with valid node data
103          * @return      $searchInstance         An instance of a SearchCriteria class
104          */
105         private function prepareSearchInstance (array $nodeData) {
106                 // Debug message
107                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
108
109                 // Assert on array elements
110                 assert(isset($nodeData[self::DB_COLUMN_NODE_ID]));
111
112                 // Get instance
113                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
114
115                 // Search for node id and limit it to one entry
116                 $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeData[self::DB_COLUMN_NODE_ID]);
117                 $searchInstance->setLimit(1);
118
119                 // Debug message
120                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
121
122                 // Return it
123                 return $searchInstance;
124         }
125
126         /**
127          * Getter for result instance for unpublished entries
128          *
129          * @return      $unpublishedEntriesInstance             Result instance
130          */
131         public final function getUnpublishedEntriesInstance () {
132                 return $this->unpublishedEntriesInstance;
133         }
134
135         /**
136          * Prepares a "local" instance of a StoreableCriteria class with all node
137          * data for insert/update queries. This data set contains data from *this*
138          * (local) node.
139          *
140          * @return      $dataSetInstance        An instance of a StoreableCriteria class
141          */
142         private function prepareLocalDataSetInstance () {
143                 // Debug message
144                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
145
146                 // Get node/request instances
147                 $nodeInstance = NodeObjectFactory::createNodeInstance();
148                 $requestInstance = ApplicationHelper::getSelfInstance()->getRequestInstance();
149
150                 // Get a dataset instance
151                 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
152
153                 // Set the primary key
154                 $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID);
155
156                 // Get Universal Node Locator and "explode" it
157                 $unlInstance = $nodeInstance->determineUniversalNodeLocator();
158
159                 // Get UNL data from it
160                 $unlData = $unlInstance->getUnlData();
161
162                 // Make sure both is valid
163                 // @TODO Bad check on UNL, better use a proper validator
164                 assert(isset($unlData[NodeInformationDatabaseWrapper::DB_COLUMN_EXTERNAL_UNL]));
165                 assert($unlData[NodeInformationDatabaseWrapper::DB_COLUMN_EXTERNAL_UNL] !== 'invalid');
166
167                 // Get an array of all accepted object types
168                 $objectList = $nodeInstance->getListFromAcceptedObjectTypes();
169
170                 // Make sure this is an array
171                 assert(is_array($objectList));
172
173                 // Add public node data
174                 $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_MODE       , $requestInstance->getRequestElement('mode'));
175                 $dataSetInstance->addCriteria(self::DB_COLUMN_EXTERNAL_ADDRESS, $unlData[NodeInformationDatabaseWrapper::DB_COLUMN_EXTERNAL_UNL]);
176                 $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_ID         , $nodeInstance->getNodeId());
177                 $dataSetInstance->addCriteria(self::DB_COLUMN_SESSION_ID      , $nodeInstance->getSessionId());
178                 $dataSetInstance->addCriteria(self::DB_COLUMN_PRIVATE_KEY_HASH, $nodeInstance->getPrivateKeyHash());
179                 $dataSetInstance->addCriteria(self::DB_COLUMN_ACCEPTED_OBJECTS, implode(BaseHubNode::OBJECT_LIST_SEPARATOR, $objectList));
180                 $dataSetInstance->addCriteria(self::DB_COLUMN_ACCEPT_BOOTSTRAP, $this->translateBooleanToYesNo($nodeInstance->isAcceptingDhtBootstrap()));
181
182                 // Debug message
183                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
184
185                 // Return it
186                 return $dataSetInstance;
187         }
188
189         /**
190          * Checks whether the local (*this*) node is registered in the DHT by
191          * checking if the external address is found.
192          *
193          * @return      $isRegistered   Whether *this* node is registered in the DHT
194          */
195         public function isLocalNodeRegistered () {
196                 // Debug message
197                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
198
199                 // Get a search criteria instance
200                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
201
202                 // Get node instance
203                 $nodeInstance = NodeObjectFactory::createNodeInstance();
204
205                 // Get Universal Node Locator and "explode" it
206                 $unlData = $nodeInstance->getUniversalNodeLocatorArray();
207
208                 // Make sure the external address is set and not invalid
209                 // @TODO Bad check on UNL, better use a proper validator
210                 assert(isset($unlData[NodeInformationDatabaseWrapper::DB_COLUMN_EXTERNAL_UNL]));
211                 assert($unlData[NodeInformationDatabaseWrapper::DB_COLUMN_EXTERNAL_UNL] != 'invalid');
212
213                 // Add Universal Node Locator/node id as criteria
214                 $searchInstance->addCriteria(self::DB_COLUMN_EXTERNAL_ADDRESS, $unlData[NodeInformationDatabaseWrapper::DB_COLUMN_EXTERNAL_UNL]);
215                 $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID         , $nodeInstance->getNodeId());
216                 $searchInstance->addCriteria(self::DB_COLUMN_SESSION_ID      , $nodeInstance->getSessionId());
217                 $searchInstance->setLimit(1);
218
219                 // Query database and get a result instance back
220                 $resultInstance = $this->doSelectByCriteria($searchInstance);
221
222                 // Cache result of if there is an entry, valid() will tell us if an entry is there
223                 $isRegistered = $resultInstance->valid();
224
225                 // Debug message
226                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: isRegistered=' . intval($isRegistered) . ' - EXIT!');
227
228                 // Return result
229                 return $isRegistered;
230         }
231
232         /**
233          * Registeres the local (*this*) node with its data in the DHT.
234          *
235          * @return      void
236          */
237         public function registerLocalNode () {
238                 // Debug message
239                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
240
241                 // Assert to make sure this method is called with no record in DB (the actual backend of the DHT)
242                 assert(!$this->isLocalNodeRegistered());
243
244                 // Get prepared data set instance
245                 $dataSetInstance = $this->prepareLocalDataSetInstance();
246
247                 // "Insert" this dataset instance completely into the database
248                 $this->queryInsertDataSet($dataSetInstance);
249
250                 // Debug message
251                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
252         }
253
254         /**
255          * Updates local (*this*) node's data in DHT, this is but not limited to the
256          * session id, ip number (and/or hostname) and port number.
257          *
258          * @return      void
259          */
260         public function updateLocalNode () {
261                 // Debug message
262                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
263
264                 // Assert to make sure this method is called with one record in DB (the actual backend of the DHT)
265                 assert($this->isLocalNodeRegistered());
266
267                 // Get node instance
268                 $nodeInstance = NodeObjectFactory::createNodeInstance();
269
270                 // Get search criteria
271                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
272
273                 // Search for node id and limit it to one entry
274                 $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeInstance->getNodeId());
275                 $searchInstance->setLimit(1);
276
277                 // Get a prepared dataset instance
278                 $dataSetInstance = $this->prepareLocalDataSetInstance();
279
280                 // Set search instance
281                 $dataSetInstance->setSearchInstance($searchInstance);
282
283                 // Update DHT database record
284                 $this->queryUpdateDataSet($dataSetInstance);
285
286                 // Debug message
287                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
288         }
289
290         /**
291          * Finds a node locally by given session id
292          *
293          * @param       $sessionId      Session id to lookup
294          * @return      $nodeData       Node data array
295          */
296         public function findNodeLocalBySessionId ($sessionId) {
297                 // Debug message
298                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: sessionId=' . $sessionId . ' - CALLED!');
299
300                 // Get search criteria
301                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
302
303                 // Search for session id and limit it to one entry
304                 $searchInstance->addCriteria(self::DB_COLUMN_SESSION_ID, $sessionId);
305                 $searchInstance->setLimit(1);
306
307                 // Query database and get a result instance back
308                 $resultInstance = $this->doSelectByCriteria($searchInstance);
309
310                 // Debug message
311                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: resultInstance->valid()=' . intval($resultInstance->valid()) . ' - EXIT!');
312
313                 // Return result instance
314                 return $resultInstance;
315         }
316
317         /**
318          * Registeres a node by given message data.
319          *
320          * @param       $messageData            An array of all message data
321          * @param       $handlerInstance        An instance of a HandleableDataSet class
322          * @return      void
323          */
324         public function registerNodeByMessageData (array $messageData, HandleableDataSet $handlerInstance) {
325                 // Debug message
326                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: handlerInstance=' . $handlerInstance->__toString() . ' - CALLED!');
327
328                 // Get a data set instance
329                 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
330
331                 // Set primary key (session id)
332                 $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID);
333
334                 // Add all array elements
335                 $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData);
336
337                 // Remove 'node_list'
338                 $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST);
339
340                 // Run the "INSERT" query
341                 $this->queryInsertDataSet($dataSetInstance);
342
343                 // Debug message
344                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . '] - EXIT!');
345         }
346
347         /**
348          * Updates an existing entry in node list
349          *
350          * @param       $messageData            An array of all message data
351          * @param       $handlerInstance        An instance of a HandleableDataSet class
352          * @param       $searchInstance         An instance of LocalSearchCriteria class
353          * @return      void
354          */
355         public function updateNodeByMessageData (array $messageData, HandleableDataSet $handlerInstance, LocalSearchCriteria $searchInstance) {
356                 // Debug message
357                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
358
359                 // Get a data set instance
360                 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
361
362                 // Add search instance
363                 $dataSetInstance->setSearchInstance($searchInstance);
364
365                 // Set primary key (session id)
366                 $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID);
367
368                 // Add all array elements
369                 $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData);
370
371                 // Remove 'node_list'
372                 $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST);
373
374                 // Run the "UPDATE" query
375                 $this->queryUpdateDataSet($dataSetInstance);
376
377                 // Debug message
378                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
379         }
380
381         /**
382          * Determines whether the given node data is already inserted in the DHT
383          *
384          * @param       $nodeData               An array with valid node data
385          * @return      $isRegistered   Whether the given node data is already inserted
386          */
387         public function isNodeRegistered (array $nodeData) {
388                 // Debug message
389                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
390
391                 // Assert on array elements
392                 assert(isset($nodeData[self::DB_COLUMN_NODE_ID]));
393
394                 // Debug message
395                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: node-id=' . $nodeData[self::DB_COLUMN_NODE_ID]);
396
397                 // Get search criteria
398                 $searchInstance = $this->prepareSearchInstance($nodeData);
399
400                 // Query database and get a result instance back
401                 $resultInstance = $this->doSelectByCriteria(
402                         // Search instance
403                         $searchInstance,
404                         // Only look for these array elements ("keys")
405                         array(
406                                 self::DB_COLUMN_NODE_ID          => TRUE,
407                                 self::DB_COLUMN_EXTERNAL_ADDRESS => TRUE
408                         )
409                 );
410
411                 // Check if there is an entry
412                 $isRegistered = $resultInstance->valid();
413
414                 // Debug message
415                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: isRegistered=' . intval($isRegistered) . ' - EXIT!');
416
417                 // Return registration status
418                 return $isRegistered;
419         }
420
421         /**
422          * Registers a node with given data in the DHT. If the node is already
423          * registered this method shall throw an exception.
424          *
425          * @param       $nodeData       An array with valid node data
426          * @return      void
427          * @throws      NodeAlreadyRegisteredException  If the node is already registered
428          */
429         public function registerNode (array $nodeData) {
430                 // Debug message
431                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
432
433                 // Assert on array elements
434                 assert(isset($nodeData[self::DB_COLUMN_NODE_ID]));
435
436                 // Is the node registered?
437                 if ($this->isNodeRegistered($nodeData)) {
438                         // Throw an exception
439                         throw new NodeAlreadyRegisteredException(array($this, $nodeData), self::EXCEPTION_NODE_ALREADY_REGISTERED);
440                 } // END - if
441
442                 // @TODO Unimplemented part
443                 $this->partialStub('nodeData=' . print_r($nodeData, TRUE));
444
445                 // Debug message
446                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
447         }
448
449         /**
450          * Updates a node's entry in the DHT with given data. This will enrich or
451          * just update already exsiting data. If the node is not found this method
452          * shall throw an exception.
453          *
454          * @param       $nodeData       An array with valid node data
455          * @return      void
456          * @throws      NodeDataMissingException        If the node's data is missing
457          */
458         public function updateNode (array $nodeData) {
459                 // Debug message
460                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
461
462                 // Assert on array elements
463                 assert(isset($nodeData[self::DB_COLUMN_NODE_ID]));
464
465                 // Debug message
466                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: Updating DHT entry for node-id=' . $nodeData[self::DB_COLUMN_NODE_ID] . ' ...');
467
468                 // Is the node registered?
469                 if (!$this->isNodeRegistered($nodeData)) {
470                         // No, then throw an exception
471                         throw new NodeDataMissingException(array($this, $nodeData), self::EXCEPTION_NODE_NOT_REGISTERED);
472                 } // END - if
473
474                 // Get a search instance
475                 $searchInstance = $this->prepareSearchInstance($nodeData);
476
477                 // Get a data set instance
478                 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
479
480                 // Add search instance
481                 $dataSetInstance->setSearchInstance($searchInstance);
482
483                 // Set primary key (session id)
484                 $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID);
485
486                 // Get node instance
487                 $nodeInstance = NodeObjectFactory::createNodeInstance();
488
489                 // Debug message
490                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: nodeData=' . print_r($nodeData, TRUE));
491
492                 // Add all array elements
493                 $nodeInstance->addArrayToDataSet($dataSetInstance, $nodeData);
494
495                 // Remove 'node_list'
496                 $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST);
497
498                 // Run the "UPDATE" query
499                 $this->queryUpdateDataSet($dataSetInstance);
500
501                 // Debug message
502                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
503         }
504
505         /**
506          * Checks whether there are unpublished entries
507          *
508          * @return      $hasUnpublished         Whether there are unpublished entries
509          * @todo        Add minimum/maximum age limitations
510          */
511         public function hasUnpublishedEntries () {
512                 // Get search instance
513                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
514
515                 // Add exclusion key which is the publish status
516                 $searchInstance->addExcludeCriteria(NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_PUBLICATION_STATUS, NodeDistributedHashTableDatabaseWrapper::PUBLICATION_STATUS_PENDING);
517
518                 // Remember search instance
519                 $this->setSearchInstance($searchInstance);
520
521                 // Run the query
522                 $this->unpublishedEntriesInstance = $this->doSelectByCriteria($searchInstance);
523
524                 // Check pending entries
525                 $hasUnpublished = $this->unpublishedEntriesInstance->valid();
526
527                 // Debug message
528                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
529
530                 // Return it
531                 return $hasUnpublished;
532         }
533
534         /**
535          * Initializes publication of DHT entries. This does only prepare
536          * publication. The next step is to pickup such prepared entries and publish
537          * them by uploading to other (recently appeared) DHT members.
538          *
539          * @return      void
540          * @todo        Add timestamp to dataset instance
541          */
542         public function initEntryPublication () {
543                 // Debug message
544                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
545
546                 /*
547                  * Make sure that hasUnpublishedEntries() has been called first by
548                  * asserting on the "cached" object instance. This "caching" saves some
549                  * needless queries as this method shall be called immediately after
550                  * hasUnpublishedEntries() returns TRUE.
551                  */
552                 assert($this->unpublishedEntriesInstance instanceof SearchableResult);
553
554                 // Result is still okay?
555                 assert($this->unpublishedEntriesInstance->valid());
556
557                 // Remove 'publication_status'
558                 $this->getSearchInstance()->unsetCriteria(self::DB_COLUMN_PUBLICATION_STATUS);
559
560                 // Make sure all entries are marked as pending, first get a dataset instance.
561                 $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT));
562
563                 // Add search instance
564                 $dataSetInstance->setSearchInstance($this->getSearchInstance());
565
566                 // Set primary key (node id)
567                 $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID);
568
569                 // Add criteria (that should be set)
570                 $dataSetInstance->addCriteria(self::DB_COLUMN_PUBLICATION_STATUS, self::PUBLICATION_STATUS_PENDING);
571
572                 // Run the "UPDATE" query
573                 $this->queryUpdateDataSet($dataSetInstance);
574
575                 // Debug message
576                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
577         }
578
579         /**
580          * Removes non-public data from given array.
581          *
582          * @param       $data   An array with possible non-public data that needs to be removed.
583          * @return      $data   A cleaned up array with only public data.
584          */
585         public function removeNonPublicDataFromArray(array $data) {
586                 // Currently call only inner method
587                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: Calling parent::removeNonPublicDataFromArray(data) ...');
588                 $data = parent::removeNonPublicDataFromArray($data);
589                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: data[]=' . gettype($data));
590
591                 // Return cleaned data
592                 return $data;
593         }
594
595         /**
596          * Find recipients for given package data and exclude the sender
597          *
598          * @param       $packageData    An array of valid package data
599          * @return      $recipients             An indexed array with DHT recipients
600          */
601         public function getResultFromExcludedSender (array $packageData) {
602                 // Debug message
603                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
604
605                 // Assert on required array field
606                 assert(isset($packageData[NetworkPackage::PACKAGE_DATA_SENDER]));
607
608                 // Get max recipients
609                 $maxRecipients = $this->getConfigInstance()->getConfigEntry('max_dht_recipients');
610
611                 // First creata a search instance
612                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
613
614                 // Then exclude 'sender' field as the sender is the current (*this*) node
615                 $searchInstance->addExcludeCriteria(NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_SESSION_ID, $packageData[NetworkPackage::PACKAGE_DATA_SENDER]);
616
617                 // Set limit to maximum DHT recipients
618                 $searchInstance->setLimit($maxRecipients);
619
620                 // Get a result instance back from DHT database wrapper.
621                 $resultInstance = $this->doSelectByCriteria($searchInstance);
622
623                 // Debug message
624                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
625
626                 // Return result instance
627                 return $resultInstance;
628         }
629
630         /**
631          * Find recopients by given key/value pair. First look for the key and if it
632          * matches, compare the value.
633          *
634          * @param       $key                    Key to look for
635          * @param       $value                  Value to compare if key matches
636          * @return      $recipients             An indexed array with DHT recipients
637          */
638         public function getResultFromKeyValue ($key, $value) {
639                 // Debug message
640                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!');
641
642                 // Get max recipients
643                 $maxRecipients = $this->getConfigInstance()->getConfigEntry('max_dht_recipients');
644
645                 // First creata a search instance
646                 $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
647
648                 // Find the key/value pair
649                 $searchInstance->addCriteria($key, $value);
650
651                 // Get a result instance back from DHT database wrapper.
652                 $resultInstance = $this->doSelectByCriteria($searchInstance);
653
654                 // Debug message
655                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: EXIT!');
656
657                 // Return result instance
658                 return $resultInstance;
659         }
660
661         /**
662          * Enable DHT bootstrap request acceptance for local node
663          *
664          * @return      void
665          */
666         public function enableAcceptDhtBootstrap () {
667                 // Debug message
668                 /* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . __METHOD__ . ':' . __LINE__ . ']: Enabling DHT bootstrap requests ...');
669
670                 // Is the node already registered?
671                 if ($this->isLocalNodeRegistered()) {
672                         // Just update our record
673                         $this->updateLocalNode();
674                 } else {
675                         // Register it
676                         $this->registerLocalNode();
677                 }
678         }
679 }
680
681 // [EOF]
682 ?>