*
* @author Roland Haeder <webmaster@ship-simu.org>
* @version 0.0.0
- * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2011 Hub Developer Team
+ * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 Hub Developer Team
* @license GNU GPL 3.0 or any newer version
* @link http://www.ship-simu.org
*
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class PackageAssembler extends BaseHubSystem implements Assembler, Registerable {
+ /**
+ * Pending data
+ */
+ private $pendingData = '';
+
/**
* Protected constructor
*
/**
* Creates an instance of this class
*
+ * @param $packageInstance An instance of a Receivable class
* @return $assemblerInstance An instance of an Assembler class
*/
- public static final function createPackageAssembler () {
+ public static final function createPackageAssembler (Receivable $packageInstance) {
// Get new instance
$assemblerInstance = new PackageAssembler();
+ // Set package instance here
+ $assemblerInstance->setPackageInstance($packageInstance);
+
+ // Create an instance of a raw data input stream
+ $streamInstance = ObjectFactory::createObjectByConfiguredName('node_raw_data_input_stream_class');
+
+ // And set it
+ $assemblerInstance->setInputStreamInstance($streamInstance);
+
// Return the prepared instance
return $assemblerInstance;
}
+ /**
+ * Checks whether the input buffer (stacker to be more preceise) is empty.
+ *
+ * @return $isInputBufferEmpty Whether the input buffer is empty
+ */
+ private function ifInputBufferIsEmpty () {
+ // Check it
+ $isInputBufferEmpty = $this->getPackageInstance()->getStackerInstance()->isStackEmpty(NetworkPackage::STACKER_NAME_DECODED_HANDLED);
+
+ // Debug message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-ASSEMBLER: isInputBufferEmpty=' . intval($isInputBufferEmpty));
+
+ // Return it
+ return $isInputBufferEmpty;
+ }
+
+ /**
+ * Checks whether given package content is completed (start/end markers are found)
+ *
+ * @param $packageContent An array with two elements: 'raw_data' and 'error_code'
+ * @return $isCompleted Whether the given package content is completed
+ */
+ private function isPackageContentCompleted (array $packageContent) {
+ // Check both
+ $isCompleted = $this->ifStartEndMarkersSet($packageContent[BaseRawDataHandler::PACKAGE_RAW_DATA]);
+
+ // Return status
+ return $isCompleted;
+ }
+
/**
* Assembles the content from $packageContent. This method does only
* initialize the whole process by creating a call-back which will then
* chunks and (maybe) re-request some chunks from the sender, this would
* take to much time and therefore slow down this node again.
*
- * @param $packageContent An array with two elements: 'decoded_data' and 'error_code'
+ * @param $packageContent An array with two elements: 'raw_data' and 'error_code'
* @return void
* @throws UnsupportedPackageCodeHandlerException If the package code handler is not implemented
*/
public function chunkPackageContent (array $packageContent) {
// Validate the package content array again
assert(
- (isset($packageContent[BaseRawDataHandler::PACKAGE_DECODED_DATA])) &&
+ (isset($packageContent[BaseRawDataHandler::PACKAGE_RAW_DATA])) &&
(isset($packageContent[BaseRawDataHandler::PACKAGE_ERROR_CODE]))
);
call_user_func(array($this, $methodName), $packageContent);
}
+ /**************************************************************************
+ * Call-back methods for above method *
+ **************************************************************************/
+
/**
* Call-back handler to handle unhandled packages. This method "explodes"
* the string with the chunk separator from PackageFragmenter class, does
* some low checks on it and feeds it into another queue for verification
* and re-request for bad chunks.
*
- * @param $packageContent An array with two elements: 'decoded_data' and 'error_code'
+ * @param $packageContent An array with two elements: 'raw_data' and 'error_code'
* @return void
* @throws FinalChunkVerificationException If the final chunk does not start with 'EOP:'
*/
private function handlePackageByUnhandledPackage (array $packageContent) {
- /*
- * "explode" the string from 'decoded_data' with chunk separator to
- * get an array of chunks. These chunks must then be verified by
- * their checksums. Also the final chunk must be handled.
- */
- $chunks = explode(PackageFragmenter::CHUNK_SEPARATOR, $packageContent[BaseRawDataHandler::PACKAGE_DECODED_DATA]);
-
- // Validate final chunk
- if (!$this->isValidFinalChunk($chunks)) {
- // Last chunk is not valid
- throw new FinalChunkVerificationException(array($this, $chunks), BaseListener::EXCEPTION_FINAL_CHUNK_VERIFICATION);
- } // END - if
+ // Debug message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-ASSEMBLER: packageData[' . BaseRawDataHandler::PACKAGE_RAW_DATA . ']=' . $packageContent[BaseRawDataHandler::PACKAGE_RAW_DATA]);
+
+ // Check for some conditions
+ if ((!$this->ifInputBufferIsEmpty()) || (!$this->isPackageContentCompleted($packageContent))) {
+ // Last chunk is not valid, so wait for more
+ $this->pendingData .= $packageContent[BaseRawDataHandler::PACKAGE_RAW_DATA];
+
+ // Debug message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-ASSEMBLER: Partial data received. Waiting for more ... ( ' . strlen($packageContent[BaseRawDataHandler::PACKAGE_RAW_DATA]) . ' bytes)');
+ } else {
+ // Debug message
+ //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__)->debugOutput('packageContent=' . print_r($packageContent,true) . ',chunks='.print_r($chunks,true));
+
+ /*
+ * "explode" the string from 'raw_data' with chunk separator to
+ * get an array of chunks. These chunks must then be verified by
+ * their checksums. Also the final chunk must be handled.
+ */
+ $chunks = explode(PackageFragmenter::CHUNK_SEPARATOR, $packageContent[BaseRawDataHandler::PACKAGE_RAW_DATA]);
+
+ // Now get a chunk handler instance
+ $handlerInstance = ChunkHandlerFactory::createChunkHandlerInstance();
+
+ // Add all chunks because the last final chunk is found
+ $handlerInstance->addAllChunksWithFinal($chunks);
+ }
+ }
+
+ /**
+ * Checks whether the assembler's pending data is empty which means it has
+ * no pending data left for handling ... ;-)
+ *
+ * @return $ifPendingDataIsEmpty Whether pending data is empty
+ */
+ public function isPendingDataEmpty () {
+ // A simbple check
+ $ifPendingDataIsEmpty = empty($this->pendingData);
+
+ // Return it
+ return $ifPendingDataIsEmpty;
+ }
+
+ /**
+ * Handles the assembler's pending data
+ *
+ * @return void
+ */
+ public function handlePendingData () {
+ // Assert on condition
+ assert(!$this->isPendingDataEmpty());
+
+ // Init fake array
+ $packageContent = array(
+ BaseRawDataHandler::PACKAGE_RAW_DATA => $this->getInputStreamInstance()->streamData($this->pendingData),
+ BaseRawDataHandler::PACKAGE_ERROR_CODE => BaseRawDataHandler::SOCKET_ERROR_UNHANDLED
+ );
+
+ // Clear pending data
+ $this->pendingData = '';
- // Now get a chunk handler instance
- $handlerInstance = ChunkHandlerFactory::createChunkHandlerInstance();
+ // Debug message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-ASSEMBLER: Last block of partial data received. A total of ' . strlen($packageContent[BaseRawDataHandler::PACKAGE_RAW_DATA]) . ' bytes has been received.');
- // Add all chunks because the last final chunk is found
- $handlerInstance->addAllChunksWithFinal($chunks);
+ // Call the real handler method
+ $this->handlePackageByUnhandledPackage($packageContent);
}
}