use of com.helger.commons.annotation.MustBeLocked in project ph-commons by phax.
the class AbstractWALDAO method modifyWriteData.
/**
* Modify the created document by e.g. adding some comment or digital
* signature or whatsoever.
*
* @param aDoc
* The created non-<code>null</code> document.
*/
@OverrideOnDemand
@MustBeLocked(ELockType.WRITE)
protected void modifyWriteData(@Nonnull final IMicroDocument aDoc) {
final IMicroComment aComment = new MicroComment("This file was generated automatically - do NOT modify!\n" + "Written at " + PDTToString.getAsString(ZonedDateTime.now(Clock.systemUTC()), Locale.US));
final IMicroElement eRoot = aDoc.getDocumentElement();
// Add a small comment
if (eRoot != null)
aDoc.insertBefore(aComment, eRoot);
else
aDoc.appendChild(aComment);
}
use of com.helger.commons.annotation.MustBeLocked in project ph-commons by phax.
the class AbstractWALDAO method _writeToFile.
/**
* The main method for writing the new data to a file. This method may only be
* called within a write lock!
*
* @return {@link ESuccess} and never <code>null</code>.
*/
@Nonnull
@SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
@MustBeLocked(ELockType.WRITE)
private ESuccess _writeToFile() {
// Build the filename to write to
final String sFilename = m_aFilenameProvider.get();
if (sFilename == null) {
// We're not operating on a file! Required for testing
if (!isSilentMode())
if (LOGGER.isInfoEnabled())
LOGGER.info("The DAO of class " + getClass().getName() + " cannot write to a file");
return ESuccess.FAILURE;
}
// Check for a filename change before writing
if (!sFilename.equals(m_sPreviousFilename)) {
onFilenameChange(m_sPreviousFilename, sFilename);
m_sPreviousFilename = sFilename;
}
if (!isSilentMode())
if (LOGGER.isInfoEnabled())
LOGGER.info("Trying to write WAL DAO file '" + sFilename + "'");
File aFileNew = null;
IMicroDocument aDoc = null;
final String sFilenameNew = _getFilenameNew(sFilename);
final String sFilenamePrev = _getFilenamePrev(sFilename);
try {
// Get the file handle
aFileNew = getSafeFile(sFilenameNew, EMode.WRITE);
m_aStatsCounterWriteTotal.increment();
final StopWatch aSW = StopWatch.createdStarted();
// Create XML document to write
aDoc = createWriteData();
if (aDoc == null)
throw new DAOException("Failed to create data to write to file");
// Generic modification
modifyWriteData(aDoc);
// Get the output stream
final OutputStream aOS = FileHelper.getOutputStream(aFileNew);
if (aOS == null) {
// Logger warning already emitted
throw new DAOException("Failed to open output stream for '" + aFileNew.getAbsolutePath() + "'");
}
// Write to file (closes the OS)
final IXMLWriterSettings aXWS = getXMLWriterSettings();
if (MicroWriter.writeToStream(aDoc, aOS, aXWS).isFailure())
throw new DAOException("Failed to write DAO XML data to file");
// Rename existing file to old
FileIOError aIOError;
boolean bRenamedToPrev = false;
if (m_aIO.existsFile(sFilename)) {
aIOError = m_aIO.renameFile(sFilename, sFilenamePrev);
bRenamedToPrev = true;
} else
aIOError = new FileIOError(EFileIOOperation.RENAME_FILE, EFileIOErrorCode.NO_ERROR);
if (aIOError.isSuccess()) {
// Rename new file to final
aIOError = m_aIO.renameFile(sFilenameNew, sFilename);
if (aIOError.isSuccess()) {
// Finally delete old file
aIOError = m_aIO.deleteFileIfExisting(sFilenamePrev);
} else {
// -> Revert original rename to stay as consistent as possible
if (bRenamedToPrev)
m_aIO.renameFile(sFilenamePrev, sFilename);
}
}
if (aIOError.isFailure())
throw new IllegalStateException("Error on rename(existing-old)/rename(new-existing)/delete(old): " + aIOError);
// Update stats etc.
m_aStatsCounterWriteTimer.addTime(aSW.stopAndGetMillis());
m_aStatsCounterWriteSuccess.increment();
m_nWriteCount++;
m_aLastWriteDT = PDTFactory.getCurrentLocalDateTime();
return ESuccess.SUCCESS;
} catch (final DAOException | RuntimeException ex) {
final String sErrorFilename = aFileNew != null ? aFileNew.getAbsolutePath() : sFilename;
if (LOGGER.isErrorEnabled())
LOGGER.error("The DAO of class " + getClass().getName() + " failed to write the DAO data to '" + sErrorFilename + "'", ex);
triggerExceptionHandlersWrite(ex, sErrorFilename, aDoc);
m_aStatsCounterWriteExceptions.increment();
return ESuccess.FAILURE;
}
}
use of com.helger.commons.annotation.MustBeLocked in project ph-commons by phax.
the class AbstractWALDAO method _writeWALFile.
@Nonnull
@MustBeLocked(ELockType.WRITE)
private ESuccess _writeWALFile(@Nonnull @Nonempty final List<DATATYPE> aModifiedElements, @Nonnull final EDAOActionType eActionType, @Nonnull @Nonempty final String sWALFilename) {
final FileSystemResource aWALRes = m_aIO.getResource(sWALFilename);
try (final DataOutputStream aDOS = new DataOutputStream(aWALRes.getOutputStream(EAppend.APPEND))) {
// Write action type ID
StreamHelper.writeSafeUTF(aDOS, eActionType.getID());
// Write number of elements
aDOS.writeInt(aModifiedElements.size());
// Write all data elements as XML Strings :)
for (final DATATYPE aModifiedElement : aModifiedElements) {
final String sElement = convertNativeToWALString(aModifiedElement);
StreamHelper.writeSafeUTF(aDOS, sElement);
}
return ESuccess.SUCCESS;
} catch (final Exception ex) {
if (LOGGER.isErrorEnabled())
LOGGER.error("Error writing WAL file " + aWALRes, ex);
triggerExceptionHandlersWrite(ex, sWALFilename, (IMicroDocument) null);
}
return ESuccess.FAILURE;
}
use of com.helger.commons.annotation.MustBeLocked in project ph-commons by phax.
the class AbstractWALDAO method markAsChanged.
@MustBeLocked(ELockType.WRITE)
protected final void markAsChanged(@Nonnull final List<DATATYPE> aModifiedElements, @Nonnull final EDAOActionType eActionType) {
ValueEnforcer.notNull(aModifiedElements, "ModifiedElements");
ValueEnforcer.notNull(eActionType, "ActionType");
// Just remember that something changed
internalSetPendingChanges(true);
if (internalIsAutoSaveEnabled()) {
// Auto save
// Write a WAL file
final String sWALFilename = _getWALFilename();
// Note: writing a WAL makes no sense, if the waiting time is zero
if (m_bCanWriteWAL && m_aWaitingTime.compareTo(Duration.ZERO) > 0 && sWALFilename != null && _writeWALFile(aModifiedElements, eActionType, sWALFilename).isSuccess()) {
// Remember change for later writing
// Note: pass the WAL filename in case the filename changes over time!
m_aWALListener.registerForLaterWriting(this, sWALFilename, m_aWaitingTime);
} else {
// write directly
_writeToFileAndResetPendingChanges("markAsChanged(" + eActionType.getID() + ")");
}
}
}
use of com.helger.commons.annotation.MustBeLocked in project ph-commons by phax.
the class FileIntIDFactory method readAndUpdateIDCounter.
/*
* Note: this method must only be called from within a locked section!
*/
@Override
@MustBeLocked(ELockType.WRITE)
protected final int readAndUpdateIDCounter(@Nonnegative final int nReserveCount) {
// Read the old content
final String sContent = SimpleFileIO.getFileAsString(m_aFile, CHARSET_TO_USE);
final int nRead = sContent != null ? StringParser.parseInt(sContent.trim(), 0) : 0;
// Write the new content to the new file
// This will fail, if the disk is full
SimpleFileIO.writeFile(m_aNewFile, Integer.toString(nRead + nReserveCount), CHARSET_TO_USE);
FileIOError aIOError;
boolean bRenamedToPrev = false;
if (m_aFile.exists()) {
// Rename the existing file to the prev file
aIOError = FileOperationManager.INSTANCE.renameFile(m_aFile, m_aPrevFile);
bRenamedToPrev = true;
} else
aIOError = new FileIOError(EFileIOOperation.RENAME_FILE, EFileIOErrorCode.NO_ERROR);
if (aIOError.isSuccess()) {
// Rename the new file to the destination file
aIOError = FileOperationManager.INSTANCE.renameFile(m_aNewFile, m_aFile);
if (aIOError.isSuccess()) {
// Finally delete the prev file (may not be existing for fresh
// instances)
aIOError = FileOperationManager.INSTANCE.deleteFileIfExisting(m_aPrevFile);
} else {
// -> Revert original rename to stay as consistent as possible
if (bRenamedToPrev)
FileOperationManager.INSTANCE.renameFile(m_aPrevFile, m_aFile);
}
}
if (aIOError.isFailure())
throw new IllegalStateException("Error on rename(existing-old)/rename(new-existing)/delete(old): " + aIOError);
return nRead;
}
Aggregations