public function handleMessage(Import $import, Message $message, Channel $channel)
 {
     if (!$import->getTmpFileName()) {
         $this->log->error("Import w/o tmp file name: {$message->content}.");
         $channel->ack($message);
         return;
     }
     if (!file_exists($import->getTmpFileName())) {
         $this->log->error("Tmp file name '{$import->getTmpFileName()}' does not exist.");
         $channel->ack($message);
         return;
     }
     $this->log->info("Got " . $message->content);
     // TODO: error handling
     $handle = fopen($import->getTmpFileName(), "r+");
     while (fread($handle, 3) === "") {
         fseek($handle, -3, SEEK_CUR);
         fwrite($handle, "   ");
         $this->log->info("Removed BOM in file '{$import->getTmpFileName()}'.");
     }
     fseek($handle, 0, SEEK_SET);
     $data = fread($handle, 1024);
     if (($sp = strpos($data, "<?xml")) !== false) {
         if (($ep = strpos($data, "?>")) !== false) {
             $newData = substr($data, $sp, $ep - $sp + 2) . str_repeat(" ", $sp) . substr($data, $ep + 2);
             fseek($handle, 0, SEEK_SET);
             fwrite($handle, $newData);
         }
     }
     fclose($handle);
     $eshopId = $import->getEshop()->getId();
     $reader = new \XMLReader();
     $reader->open($import->getTmpFileName());
     while ($reader->read()) {
         if (strtoupper($reader->name) !== "SHOPITEM") {
             continue;
         }
         $item = @$reader->expand();
         if ($item === false) {
             $this->log->error("XMLReader error: " . json_encode(libxml_get_last_error()));
             break;
         }
         $reader->next();
         $product = new Product();
         $product->setEshopId($eshopId);
         foreach ($item->childNodes as $child) {
             /** @var \DOMNode $child */
             if ($child->nodeType !== XML_ELEMENT_NODE) {
                 continue;
             }
             $textContent = trim($child->textContent);
             if (empty($textContent)) {
                 $textContent = null;
             }
             switch ($name = strtoupper($child->nodeName)) {
                 case "ITEM_GROUP_ID":
                     $product->setItemGroupId($textContent);
                     break;
                 case "ITEM_ID":
                     $product->setItemId($textContent);
                     break;
                 case "PRODUCTNAME":
                     $product->setName($textContent);
                     break;
                 case "PRODUCT":
                     $product->setLongName($textContent);
                     break;
                 case "DESCRIPTION":
                     $product->setDescription($textContent);
                     break;
                 case "URL":
                     // TODO: normalize URL
                     $product->setUrl($textContent);
                     break;
                 case "PRICE_VAT":
                     $product->setPrice(floatval(preg_replace("/[^0-9.]+/", "", str_replace(",", ".", $textContent))));
                     break;
                 case "DELIVERY_DATE":
                     $product->setDeliveryDate(intval(preg_replace("/[^0-9]+/", "", $textContent)));
                     break;
                 case "IMGURL":
                 case "IMGURL_ALTERNATIVE":
                     // TODO: normalize URL
                     $image = new Image();
                     $image->setUrl($textContent);
                     $product->addImage($image);
                     break;
                 case "EAN":
                     $product->setEan($textContent);
                     break;
                 case "ISBN":
                     $product->setIsbn($textContent);
                     break;
                 case "PRODUCTNO":
                     $product->setProductno($textContent);
                     break;
                 case "MANUFACTURER":
                     $product->setManufacturer($textContent);
                     break;
                 case "BRAND":
                     $product->setBrand($textContent);
                     break;
                 case "CATEGORYTEXT":
                     if (!empty($textContent)) {
                         $product->addCategoryText($textContent);
                     }
                     break;
                 case "ITEM_TYPE":
                     try {
                         $product->setItemType(ProductItemTypeEnum::fromXML($textContent));
                     } catch (\InvalidArgumentException $e) {
                         $this->log->warning("Got exception while assigning ITEM_TYPE: " . $e->getMessage());
                     }
                     break;
                 case "EXTRA_MESSAGE":
                     try {
                         $product->addExtraMessage(ProductExtraMessageEnum::fromXML($textContent));
                     } catch (\InvalidArgumentException $e) {
                         $this->log->warning("Got exception while assigning EXTRA_MESSAGE: " . $e->getMessage());
                     }
                     break;
             }
         }
         if ($product->getUrl() === null) {
             $this->log->warning("Skipping product without URL: " . ProductMeta::toJson($product));
             continue;
         }
         if ($product->getName() === null) {
             if ($product->getLongName() === null) {
                 $this->log->warning("Skipping product without PRODUCT/PRODUCTNAME: " . ProductMeta::toJson($product));
                 continue;
             } else {
                 $product->setName($product->getLongName());
             }
         }
         if ($product->getItemId() === null) {
             $product->setItemId($product->getUrl());
         }
         if ($product->getItemGroupId() === null) {
             $product->setItemGroupId($product->getItemId());
         }
         for (;;) {
             $existing = $this->productRepository->findOneFromEshop($product);
             if (!$existing) {
                 $this->fillCategoryIds($product);
                 $ret = $this->productRepository->insert($product);
                 if (isset($ret["ok"]) && $ret["ok"]) {
                     $this->changeProducer->publish(Change::create()->setProduct($product), RoutingKeys::CHANGE_PRODUCT_CREATE);
                     break;
                 }
             } else {
                 $this->mergeProducts($product, $existing);
                 $this->fillCategoryIds($product);
                 $ret = $this->productRepository->update(["_id" => $existing->getId(), "v" => $existing->getV()], ProductMeta::toArray($product));
                 if (isset($ret["ok"]) && $ret["ok"] && isset($ret["updatedExisting"]) && $ret["updatedExisting"]) {
                     $this->changeProducer->publish(Change::create()->setProduct($product), RoutingKeys::CHANGE_PRODUCT_UPDATE);
                     break;
                 }
             }
         }
     }
     // TODO: delete products not present in feed
     $reader->close();
     libxml_clear_errors();
     unlink($import->getTmpFileName());
     $channel->ack($message);
 }