/** * Writes collection of {@link DefaultData} objects to the storage. * * @param storageData Storage to write. * @param dataToWrite Data to write. * @param dataProcessors Processors that will be used for data writing. Can be null. In this case, * the direct write is done. * @param synchronously If write will be done synchronously or not. * @throws BusinessException If storage is used as a recording storage. * @throws SerializationException If serialization fails during auto-finalization. * @throws IOException If {@link IOException} occurs during auto-finalization. */ public void writeToStorage( StorageData storageData, Collection<? extends DefaultData> dataToWrite, Collection<AbstractDataProcessor> dataProcessors, boolean synchronously) throws BusinessException, IOException, SerializationException { StorageData local = getLocalStorageDataObject(storageData); StorageWriter writer = openedStoragesMap.get(local); if (writer != null) { if (synchronously) { writer.processSynchronously(dataToWrite, dataProcessors); } else { writer.process(dataToWrite, dataProcessors); } } else if (Objects.equals(local, recorderStorageData)) { throw new BusinessException( "Write data to storage " + local + ".", StorageErrorCodeEnum.WRITE_FAILED); } else if (local.getState() == StorageState.CLOSED) { throw new BusinessException( "Write data to storage " + local + ".", StorageErrorCodeEnum.STORAGE_ALREADY_CLOSED); } else { log.error("Writer for the not closed storage " + local + " is not available."); throw new RuntimeException( "Writer for the not closed storage " + local + " is not available."); } }
/** * Returns the storage data based on the ID. This method can be helpful when the updated version * of {@link StorageData} needs to be retrieved. * * @param id ID of storage. * @return {@link StorageData} */ public StorageData getStorageData(String id) { for (StorageData storageData : existingStoragesSet) { if (storageData.getId().equals(id)) { return storageData; } } return null; }
/** * Returns if the storage is opened, and thus if the write to the storage can be executed. * * @param storageData Storage to check. * @return True if storage is opened, otherwise false. */ public boolean isStorageOpen(StorageData storageData) { for (StorageData existing : openedStoragesMap.keySet()) { if (existing.getId().equals(storageData.getId())) { return true; } } return false; }
/** {@inheritDoc} */ @MethodLog public Collection<AbstractStorageLabel<?>> getAllLabelsInStorages() { Set<AbstractStorageLabel<?>> labels = new HashSet<AbstractStorageLabel<?>>(); for (StorageData storageData : getExistingStorages()) { labels.addAll(storageData.getLabelList()); } return labels; }
/** * Returns if the storage is closed. * * @param storageData Storage to check. * @return True if storage is closed, in any other situation false. */ public boolean isStorageClosed(StorageData storageData) { for (StorageData existing : existingStoragesSet) { if (existing.getId().equals(storageData.getId())) { return existing.isStorageClosed(); } } return false; }
/** * Returns list of readable storages. * * @return Returns list of readable storages. */ public List<StorageData> getReadableStorages() { List<StorageData> list = new ArrayList<StorageData>(); for (StorageData storageData : existingStoragesSet) { if (storageData.isStorageClosed()) { list.add(storageData); } } return list; }
/** * Returns the local cached object that represent the {@link StorageData}. * * @param storageData Template. * @return Local object. * @throws BusinessException If local object can not be found. */ private StorageData getLocalStorageDataObject(StorageData storageData) throws BusinessException { for (StorageData existing : existingStoragesSet) { if (existing.getId().equals(storageData.getId())) { return existing; } } throw new BusinessException( "Find storage " + storageData + ".", StorageErrorCodeEnum.STORAGE_DOES_NOT_EXIST); }
/** * Add a label to the storage and saves new state of the storage to the disk. * * @param storageData {@link StorageData}. * @param storageLabel Label to add. * @param doOverwrite Overwrite if label type already exists and is only one per storage allowed. * @throws IOException If {@link IOException} happens. * @throws SerializationException If {@link SerializationException} happens. * @throws BusinessException If provided storage data does not exist. */ public void addLabelToStorage( StorageData storageData, AbstractStorageLabel<?> storageLabel, boolean doOverwrite) throws IOException, SerializationException, BusinessException { StorageData local = getLocalStorageDataObject(storageData); if (null != local) { local.addLabel(storageLabel, doOverwrite); writeStorageDataToDisk(local); } }
/** * Removes label from storage and saves new state of the storage data to the disk. * * @param storageData {@link StorageData}. * @param storageLabel Label to remove. * @return True if the label was removed, false otherwise. * @throws IOException If {@link IOException} happens. * @throws SerializationException If {@link SerializationException} happens. * @throws BusinessException If provided storage data does not exist. */ public boolean removeLabelFromStorage( StorageData storageData, AbstractStorageLabel<?> storageLabel) throws IOException, SerializationException, BusinessException { StorageData local = getLocalStorageDataObject(storageData); if (null != local) { boolean removed = local.removeLabel(storageLabel); writeStorageDataToDisk(local); return removed; } return false; }
/** * Creates new storage. * * @param storageData Storage. * @throws IOException if {@link IOException} occurs. * @throws SerializationException If serialization fails. * @throws BusinessException If name for storage is not provided. */ public void createStorage(StorageData storageData) throws IOException, SerializationException, BusinessException { if (null == storageData.getName()) { throw new BusinessException( "Create new storage.", StorageErrorCodeEnum.STORAGE_NAME_IS_NOT_PROVIDED); } storageData.setId(getRandomUUIDString()); storageData.setCmrVersion(cmrVersion); writeStorageDataToDisk(storageData); existingStoragesSet.add(storageData); }
/** * Updates size of the given storage and saves information to this. * * @param storageData Storage data. * @throws IOException If {@link IOException} happened during operation. * @throws SerializationException If serialization failed. */ private void updateExistingStorageSize(StorageData storageData) throws IOException, SerializationException { if (null != storageData) { synchronized (storageData) { long newSize = getDiskSizeForStorage(storageData); if (newSize != storageData.getDiskSize()) { storageData.setDiskSize(newSize); writeStorageDataToDisk(storageData); } } } }
/** * Updates the storage data for already existing storage. * * @param storageData Storage data containing update values. * @throws BusinessException If storage does not exists. * @throws SerializationException If serialization fails. * @throws IOException If IO operation fails. */ public void updateStorageData(StorageData storageData) throws BusinessException, IOException, SerializationException { StorageData local = getLocalStorageDataObject(storageData); if (null == local) { throw new BusinessException( "Update of the storage data" + storageData + ".", StorageErrorCodeEnum.STORAGE_DOES_NOT_EXIST); } else { synchronized (local) { local.setName(storageData.getName()); local.setDescription(storageData.getDescription()); writeStorageDataToDisk(local); } } }
/** * Deletes a storage information and files from disk. * * @param storageData {@link StorageData} to delete. * @throws BusinessException If storage is not closed. * @throws IOException If {@link IOException} occurs. */ public void deleteStorage(StorageData storageData) throws BusinessException, IOException { StorageData local = getLocalStorageDataObject(storageData); synchronized (local) { if ((storageRecorder.isRecordingOn() || storageRecorder.isRecordingScheduled()) && Objects.equals(local, recorderStorageData)) { throw new BusinessException( "Delete the storage " + local + ".", StorageErrorCodeEnum.STORAGE_ALREADY_CLOSED); } if (local.isStorageOpened()) { StorageWriter writer = openedStoragesMap.get(local); if (writer != null) { writer.cancel(); } openedStoragesMap.remove(local); } deleteCompleteStorageDataFromDisk(local); existingStoragesSet.remove(local); } }
/** * Opens existing storage if it is not already opened. * * @param storageData Storage to open. * @return {@link StorageWriter} created for this storage. Of <code>null</code> if no new writer * is created. * @throws IOException If {@link IOException} occurs. * @throws SerializationException If exception occurs during update of storage data. * @throws BusinessException If provided storage data does not exist or if the storage is closed. */ public StorageWriter openStorage(StorageData storageData) throws IOException, SerializationException, BusinessException { StorageData local = getLocalStorageDataObject(storageData); synchronized (local) { if (isStorageClosed(local)) { throw new BusinessException( "Open the storage " + local + ".", StorageErrorCodeEnum.STORAGE_ALREADY_CLOSED); } if (!isStorageOpen(local)) { local.markOpened(); StorageWriter writer = storageWriterProvider.getCmrStorageWriter(); openedStoragesMap.put(local, writer); writer.prepareForWrite(local); writeStorageDataToDisk(local); return writer; } } return null; }
/** {@inheritDoc} */ @MethodLog public StorageData removeLabelFromStorage( StorageData storageData, AbstractStorageLabel<?> storageLabel) throws StorageException { try { storageManager.removeLabelFromStorage(storageData, storageLabel); return storageManager.getStorageData(storageData.getId()); } catch (IOException | SerializationException e) { throw new StorageException( "Exception occurred trying to save storage data changes to disk.", e); } }
/** {@inheritDoc} */ @MethodLog public StorageData addLabelToStorage( StorageData storageData, AbstractStorageLabel<?> storageLabel, boolean doOverwrite) throws StorageException { try { storageManager.addLabelToStorage(storageData, storageLabel, doOverwrite); storageLabelDataDao.saveLabel(storageLabel); return storageManager.getStorageData(storageData.getId()); } catch (IOException | SerializationException e) { throw new StorageException( "Exception occurred trying to save storage data changes to disk.", e); } }
/** * Closes the storage if it is open. * * @param storageData Storage. * @throws BusinessException When storage that should be closed is used for recording or it is * already closed. * @throws SerializationException If serialization fails. * @throws IOException If {@link IOException} occurs. */ public void closeStorage(StorageData storageData) throws BusinessException, IOException, SerializationException { StorageData local = getLocalStorageDataObject(storageData); synchronized (local) { if ((storageRecorder.isRecordingOn() || storageRecorder.isRecordingScheduled()) && Objects.equals(local, recorderStorageData)) { throw new BusinessException( "Close the storage " + local + ".", StorageErrorCodeEnum.STORAGE_CAN_NOT_BE_CLOSED); } else if (isStorageClosed(local)) { throw new BusinessException( "Close the storage " + local + ".", StorageErrorCodeEnum.STORAGE_ALREADY_CLOSED); } StorageWriter writer = openedStoragesMap.get(local); if (writer != null) { writer.closeStorageWriter(); } openedStoragesMap.remove(local); local.setDiskSize(getDiskSizeForStorage(local)); local.markClosed(); writeStorageDataToDisk(local); } }
/** * Stops recording. * * @throws SerializationException If serialization fails during write {@link StorageData} to disk. * @throws IOException If IOException occurs during write {@link StorageData} to disk. * @throws BusinessException If {@link BusinessException} is throw during auto-finalize process. */ public void stopRecording() throws IOException, SerializationException, BusinessException { synchronized (this) { if (storageRecorder.isRecordingOn() || storageRecorder.isRecordingScheduled()) { boolean autoFinalize = storageRecorder.getRecordingProperties().isAutoFinalize(); StorageWriter storageWriter = storageRecorder.getStorageWriter(); storageRecorder.stopRecording(); recorderStorageData.markOpened(); openedStoragesMap.put(recorderStorageData, storageWriter); if (autoFinalize) { this.closeStorage(recorderStorageData); } writeStorageDataToDisk(recorderStorageData); recorderStorageData = null; // NOPMD } } }
/** * Starts recording on the provided storage if recording is not active. If storage is not created * it will be. If it is not open, it will be. * * @param storageData Storage. * @param recordingProperties Recording properties. Must not be null. * @throws IOException If {@link IOException} occurs while creating and opening the storage. * @throws SerializationException If serialization fails when creating the storage. * @throws BusinessException If recording can not be started for some reason. */ public void startOrScheduleRecording( StorageData storageData, RecordingProperties recordingProperties) throws IOException, SerializationException, BusinessException { if (!isStorageExisting(storageData)) { this.createStorage(storageData); } StorageData local = getLocalStorageDataObject(storageData); if (!isStorageOpen(local)) { this.openStorage(local); } synchronized (this) { if (!storageRecorder.isRecordingOn() && !storageRecorder.isRecordingScheduled()) { StorageWriter storageWriter = openedStoragesMap.remove(local); storageRecorder.startOrScheduleRecording(storageWriter, recordingProperties); recorderStorageData = local; recorderStorageData.markRecording(); writeStorageDataToDisk(recorderStorageData); } } }
/** {@inheritDoc} */ @MethodLog public StorageData startOrScheduleRecording( StorageData storageData, RecordingProperties recordingProperties) throws StorageException { if ((storageManager.getRecordingState() == RecordingState.ON || storageManager.getRecordingState() == RecordingState.SCHEDULED) && !storageData.equals(storageManager.getRecordingStorage())) { throw new StorageException( "Recording is already active/scheduled with different storage. Only one storage at time can be chosen as recording destination."); } else if (storageManager.getRecordingState() == RecordingState.ON || storageManager.getRecordingState() == RecordingState.SCHEDULED) { throw new StorageException("Recording is already active/scheduled with selected storage."); } else { try { storageManager.startOrScheduleRecording(storageData, recordingProperties); return storageManager.getRecordingStorage(); } catch (IOException | SerializationException e) { throw new StorageException( "Exception occurred trying to start recording on storage " + storageData + ".", e); } } }
/** * Creates a storage form the uploaded local storage directory. * * @param localStorageData Local storage information. * @throws IOException If {@link IOException} occurs. * @throws BusinessException If there is not enough space for the unpacking the storage. * @throws SerializationException If serialization fails. */ public void createStorageFromUploadedDir(final IStorageData localStorageData) throws IOException, BusinessException, SerializationException { long storageBytesLeft = getBytesHardDriveOccupancyLeft(); if (localStorageData.getDiskSize() > storageBytesLeft) { throw new BusinessException( "Create the uploaded storage " + localStorageData + ".", StorageErrorCodeEnum.LOW_DISK_SPACE); } Path uploadPath = Paths.get(this.getStorageUploadsFolder()); if (Files.notExists(uploadPath)) { throw new IOException( "Can not perform storage unpacking. The main upload path " + uploadPath.toString() + " does not exist."); } else { final MutableObject storageUploadPath = new MutableObject(); final MutableObject uploadedStorageData = new MutableObject(); final ISerializer serializer = getSerializationManagerProvider().createSerializer(); Files.walkFileTree( uploadPath, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { // skip all other files, search for the local data if (!file.toString() .endsWith( localStorageData.getId() + StorageFileType.LOCAL_STORAGE_FILE.getExtension())) { return FileVisitResult.CONTINUE; } // when found confirm it is the one we wanted to upload InputStream inputStream = null; Input input = null; try { inputStream = Files.newInputStream(file, StandardOpenOption.READ); input = new Input(inputStream); Object deserialized = serializer.deserialize(input); if (Objects.equals(deserialized, localStorageData)) { uploadedStorageData.setValue(new StorageData(localStorageData)); storageUploadPath.setValue(file.toAbsolutePath().getParent()); return FileVisitResult.TERMINATE; } } catch (SerializationException e) { log.warn("Error de-serializing local storage file.", e); } finally { if (null != input) { input.close(); } } return FileVisitResult.CONTINUE; } }); // do the rest out of the file walk Path parentDir = (Path) storageUploadPath.getValue(); StorageData storageData = (StorageData) uploadedStorageData.getValue(); if (null != storageData && null != parentDir) { Path storageDir = getStoragePath(storageData); if (existingStoragesSet.add(storageData)) { if (Files.notExists(storageDir)) { printStorageCmrVersionWarn(storageData); Files.walkFileTree(parentDir, new CopyMoveFileVisitor(parentDir, storageDir, true)); Path localInformation = getStoragePath(storageData) .resolve( storageData.getId() + StorageFileType.LOCAL_STORAGE_FILE.getExtension()); Files.deleteIfExists(localInformation); writeStorageDataToDisk(storageData); } else { throw new IOException("Directory to place uploaded storage already exists."); } } else { log.info( "Uploaded storage on path " + parentDir.toString() + " contains the storage that is already available on the CMR. Dir will be deleted."); Files.walkFileTree(parentDir, new DeleteFileVisitor()); } } } }