class TapeLibraryContentAddressableStorage implements ContentAddressableStorage {

    @Override
    public String createReadOrderRequest(String containerName, List<String> objectsIds)
        throws ContentAddressableStorageServerException, ContentAddressableStorageNotFoundException {
        TapeReadRequestReferentialEntity tapeReadRequestReferentialEntity;
        List<FileInTape> filesInTape = new ArrayList<>();
        String readRequestId = GUIDFactory.newGUID().getId();

        Map<String, TarLocation> tarLocationMap = new HashMap<>();
        Set<String> archiveSet = new HashSet<>();
        try {
            for (String objectName : objectsIds) {

                Optional<TapeObjectReferentialEntity> object =
                    objectReferentialRepository.find(containerName, objectName);
                if (!object.isPresent()) {
                    throw new ContentAddressableStorageNotFoundException(
                        ErrorMessage.OBJECT_NOT_FOUND + containerName + "/" + objectName);
                }

                // Get TARs containing the object segments
                TapeLibraryObjectStorageLocation location = object.get().getLocation();
                if (!(location instanceof TapeLibraryTarObjectStorageLocation)) {
                    // TODO: 15/07/19 object is in the local FS and not yet in TAR (throw exception or read it from local FS ?)
                    throw new UnsupportedOperationException("Object stored in tar. Not implemented yet");
                }

                List<TarEntryDescription> tarEntryDescriptions =
                    ((TapeLibraryTarObjectStorageLocation) location).getTarEntries();

                if (tarEntryDescriptions == null || tarEntryDescriptions.isEmpty()) {
                    throw new IllegalStateException(
                        "empty TAR description for object : " + containerName + "/" + objectName);
                }

                for (TarEntryDescription o : tarEntryDescriptions) {
                    // If Tar in cache then already in DISK. Access TAR in cache increase expire time
                    archiveSet.add(o.getTarFileId());

                    String tarFileIdWithoutExtension = StringUtils.substringBeforeLast(o.getTarFileId(), ".");
                    Path path = archiveOutputRetentionPolicy.get(o.getTarFileId());
                    if (null != path) {
                        tarLocationMap.putIfAbsent(tarFileIdWithoutExtension, TarLocation.DISK);
                    } else {
                        tarLocationMap.putIfAbsent(tarFileIdWithoutExtension, TarLocation.TAPE);
                    }
                }


                filesInTape.add(new FileInTape(objectName, object.get().getStorageId(), tarEntryDescriptions));
            }

            tapeReadRequestReferentialEntity =
                new TapeReadRequestReferentialEntity(readRequestId, containerName, tarLocationMap, filesInTape);
            readRequestReferentialRepository.insert(tapeReadRequestReferentialEntity);

            for (String tarId : archiveSet) {
                Optional<TapeArchiveReferentialEntity> tapeLibraryTarReferentialEntity =
                    archiveReferentialRepository.find(tarId);
                if (!tapeLibraryTarReferentialEntity.isPresent()) {
                    throw new IllegalStateException("TAR information not found for tarId : " + tarId);
                }

                TapeLibraryArchiveStorageLocation tarLocation = tapeLibraryTarReferentialEntity.get().getLocation();
                if (!(tarLocation instanceof TapeLibraryOnTapeArchiveStorageLocation)) {
                    throw new UnsupportedOperationException("Tar file is not yet on tape.");
                }

                String tarIdWithoutExtension = StringUtils.substringBeforeLast(tarId, ".");
                if (tarLocationMap.get(tarIdWithoutExtension).equals(TarLocation.DISK)) {
                    // Do not add read order task as TAR already exists in local FS
                    continue;
                }

                // Create read orders
                String tapeCode = ((TapeLibraryOnTapeArchiveStorageLocation) tarLocation).getTapeCode();
                Integer filePosition = ((TapeLibraryOnTapeArchiveStorageLocation) tarLocation).getFilePosition();
                String bucketId = getBucketByTapeCode(tapeCode);
                ReadOrder readOrder = new ReadOrder(readRequestId, tapeCode, filePosition, tarId, bucketId);

                // add read orders to worker queue
                readWriteQueue.addIfAbsent(
                    Arrays.asList(
                        new QueryCriteria(ReadOrder.FILE_NAME, tarId, QueryCriteriaOperator.EQ),
                        new QueryCriteria(ReadOrder.MESSAGE_TYPE, QueueMessageType.ReadOrder.name(),
                            QueryCriteriaOperator.EQ)),
                    readOrder);
            }

        } catch (ObjectReferentialException | QueueException | ArchiveReferentialException | TapeCatalogException
            | ReadRequestReferentialException e) {
            throw new ContentAddressableStorageServerException(
                "Error on reading from tape");
        }

        return tapeReadRequestReferentialEntity.getRequestId();
    }

    public  TapeLibraryContentAddressableStorage(
        BasicFileStorage basicFileStorage,
        ObjectReferentialRepository objectReferentialRepository,
        ArchiveReferentialRepository archiveReferentialRepository,
        ReadRequestReferentialRepository readRequestReferentialRepository,
        FileBucketTarCreatorManager fileBucketTarCreatorManager,
        QueueRepository readWriteQueue, TapeCatalogService tapeCatalogService,
        String outputTarStorageFolder,
        ArchiveOutputRetentionPolicy archiveOutputRetentionPolicy);

}