diff --git a/common/source/java/ch/systemsx/cisd/common/parser/TabFileLoader.java b/common/source/java/ch/systemsx/cisd/common/parser/TabFileLoader.java index 889496388a1ba60b3a46d043fa10d26d87dcbf71..ba4b9765f89ba7a99ae78e30ab029ce49e4eaa7a 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/TabFileLoader.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/TabFileLoader.java @@ -44,7 +44,6 @@ import ch.systemsx.cisd.common.parser.filter.ILineFilter; * <pre> * column1 column2 column2 * </pre> - * * <li>Comment section: * * <pre> @@ -53,7 +52,6 @@ import ch.systemsx.cisd.common.parser.filter.ILineFilter; * # ... * column1 column2 column2 * </pre> - * * <li>Column headers at the end of the comment section: * * <pre> @@ -71,7 +69,7 @@ import ch.systemsx.cisd.common.parser.filter.ILineFilter; public class TabFileLoader<T> { - private static final String PREFIX = "#"; + public static final String COMMENT_PREFIX = "#"; private final IParserObjectFactoryFactory<T> factory; @@ -129,10 +127,10 @@ public class TabFileLoader<T> while (lineIterator.hasNext()) { previousLineHasColumnHeaders = - (previousLine != null) && PREFIX.equals(previousLine.getText()); + (previousLine != null) && COMMENT_PREFIX.equals(previousLine.getText()); previousLine = line; line = lineIterator.next(); - if (line.getText().startsWith(PREFIX) == false) + if (line.getText().startsWith(COMMENT_PREFIX) == false) { break; } @@ -180,7 +178,8 @@ public class TabFileLoader<T> * Note that the search is case-insensitive. * </p> * - * @throws IllegalArgumentException if there is at least one duplicate in the given <var>tokens</var>. + * @throws IllegalArgumentException if there is at least one duplicate in the given + * <var>tokens</var>. */ private final static void notUnique(final String[] tokens) { diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/BatchDataSetHandler.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/BatchDataSetHandler.java index eac9ffef91860c50fad4954649d3f79b5bb9a859..597ab729006d190fb9e435595b35b0e7e4ef6e0e 100644 --- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/BatchDataSetHandler.java +++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/BatchDataSetHandler.java @@ -58,25 +58,26 @@ public class BatchDataSetHandler implements IDataSetHandler { return processedDatasetFiles; } + LogUtils log = new LogUtils(datasetsParentDir); TableMap<String, DataSetMappingInformation> datasetsMapping = DatasetMappingUtil.tryGetDatasetsMapping(datasetsParentDir); if (datasetsMapping == null) { - touchErrorMarkerFile(datasetsParentDir); + touchErrorMarkerFile(datasetsParentDir, log); return processedDatasetFiles; } Set<String> processedFiles = new HashSet<String>(); List<File> files = listAll(datasetsParentDir); for (File file : files) { - if (canDatasetBeProcessed(file, datasetsMapping)) + if (canDatasetBeProcessed(file, datasetsMapping, log)) { processedDatasetFiles.addAll(delegator.handleDataSet(file)); processedFiles.add(file.getName().toLowerCase()); } } - cleanMappingFile(datasetsParentDir, processedFiles); - finish(datasetsParentDir, datasetsMapping.values().size() - processedFiles.size()); + clean(datasetsParentDir, processedFiles, log, datasetsMapping.values().size()); + log.sendNotificationsIfNecessary(); return processedDatasetFiles; } @@ -108,30 +109,33 @@ public class BatchDataSetHandler implements IDataSetHandler return new File(datasetsParentDir, ERROR_MARKER_FILE).isFile(); } - private void cleanMappingFile(File datasetsParentDir, Set<String> processedFiles) + private void cleanMappingFile(File datasetsParentDir, Set<String> processedFiles, LogUtils log) { try { DatasetMappingUtil.cleanMappingFile(datasetsParentDir, processedFiles); } catch (IOException ex) { - LogUtils.error(datasetsParentDir, "Cannot clean dataset mappings file: " - + ex.getMessage()); + log.userError("Cannot clean dataset mappings file: " + ex.getMessage()); } } - private void finish(File datasetsParentDir, int unprocessedDatasetsCounter) + private void clean(File datasetsParentDir, Set<String> processedFiles, LogUtils log, + int datasetMappingsNumber) { + cleanMappingFile(datasetsParentDir, processedFiles, log); + + int unprocessedDatasetsCounter = datasetMappingsNumber - processedFiles.size(); if (unprocessedDatasetsCounter == 0 && hasNoPotentialDatasetFiles(datasetsParentDir)) { - clean(datasetsParentDir); + cleanDatasetsDir(datasetsParentDir); } else { - touchErrorMarkerFile(datasetsParentDir); + touchErrorMarkerFile(datasetsParentDir, log); } } - private static void touchErrorMarkerFile(File parentDir) + private static void touchErrorMarkerFile(File parentDir, LogUtils log) { File errorMarkerFile = new File(parentDir, ERROR_MARKER_FILE); if (errorMarkerFile.isFile()) @@ -151,13 +155,13 @@ public class BatchDataSetHandler implements IDataSetHandler .getPath()); } else { - LogUtils.warn(parentDir, + log.userWarning( "Correct the errors and delete the '%s' file to start processing again.", ERROR_MARKER_FILE); } } - private void clean(File datasetsParentDir) + private void cleanDatasetsDir(File datasetsParentDir) { LogUtils.deleteUserLog(datasetsParentDir); DatasetMappingUtil.deleteMappingFile(datasetsParentDir); @@ -167,7 +171,7 @@ public class BatchDataSetHandler implements IDataSetHandler // Checks that the sample from the mapping exists and is assigned to the experiment - we do not // want to move datasets to unidentified directory in this case. private boolean canDatasetBeProcessed(File file, - TableMap<String, DataSetMappingInformation> datasetsMapping) + TableMap<String, DataSetMappingInformation> datasetsMapping, LogUtils log) { if (DatasetMappingUtil.isMappingFile(file)) { @@ -179,7 +183,7 @@ public class BatchDataSetHandler implements IDataSetHandler { return false; } - return datasetMappingResolver.isMappingCorrect(mapping, file.getParentFile()); + return datasetMappingResolver.isMappingCorrect(mapping, log); } private void deleteEmptyDir(File dir) diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/BatchDataSetInfoExtractor.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/BatchDataSetInfoExtractor.java index 3462b82a9768c899598b341c35e05fc249cf24e1..8a1a974929dc3599e2625dbd9d03d1a7765d9948 100644 --- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/BatchDataSetInfoExtractor.java +++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/BatchDataSetInfoExtractor.java @@ -33,12 +33,9 @@ public class BatchDataSetInfoExtractor implements IDataSetInfoExtractor { private final Properties properties; - private final String groupCode; - public BatchDataSetInfoExtractor(final Properties globalProperties) { this.properties = ExtendedProperties.getSubset(globalProperties, EXTRACTOR_KEY + '.', true); - this.groupCode = DatasetMappingResolver.getGroupCode(properties); } public DataSetInformation getDataSetInformation(File incomingDataSetPath, @@ -55,7 +52,7 @@ public class BatchDataSetInfoExtractor implements IDataSetInfoExtractor String sampleCode = getSampleCode(plainInfo, openbisService, incomingDataSetPath.getParentFile()); info.setSampleCode(sampleCode); - info.setGroupCode(groupCode); + info.setGroupCode(plainInfo.getGroupCode()); MLConversionType conversion = getConversion(plainInfo.getConversion()); info.setConversion(conversion); return info; @@ -83,7 +80,7 @@ public class BatchDataSetInfoExtractor implements IDataSetInfoExtractor { String sampleCode = new DatasetMappingResolver(properties, openbisService).tryFigureSampleCode(mapping, - logDir); + new LogUtils(logDir)); if (sampleCode == null) { // should not happen, the dataset handler should skip datasets with incorrect mapping diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DataSetMappingInformation.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DataSetMappingInformation.java index 8274cb3e21f07886b4f335fca8e18e237347732f..9af7d942ed061b96b9ed56874de03d1658c34a96 100644 --- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DataSetMappingInformation.java +++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DataSetMappingInformation.java @@ -39,6 +39,8 @@ public class DataSetMappingInformation private String projectCode; + private String groupCode; + private String conversion; private List<NewProperty> properties; @@ -87,6 +89,17 @@ public class DataSetMappingInformation this.projectCode = StringUtils.trimToNull(projectCode); } + public String getGroupCode() + { + return groupCode; + } + + @BeanProperty(label = "group") + public void setGroupCode(String groupCode) + { + this.groupCode = groupCode; + } + public String getConversion() { return conversion; diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DataSetMappingInformationParser.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DataSetMappingInformationParser.java index 4e4d2b04abeed46ea94aa63880369eed6b51c696..f87a74cb737aae6b8a7f993c69b3044cc3a553de 100644 --- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DataSetMappingInformationParser.java +++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DataSetMappingInformationParser.java @@ -71,7 +71,7 @@ class DataSetMappingInformationParser { causeMsg = "\nThe exception was caused by: " + cause.getMessage(); } - LogUtils.error(mappingFile.getParentFile(), + LogUtils.basicError(mappingFile.getParentFile(), "The datasets cannot be processed because the mapping file '%s' has incorrect format." + " The following exception occured:\n%s%s", mappingFile.getPath(), e .getMessage(), causeMsg); diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DatasetMappingResolver.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DatasetMappingResolver.java index 869d79cab62f7fbb12140f42aea32fb54d40364c..be8d4350427a7edf0fcd98227472f7de74724e48 100644 --- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DatasetMappingResolver.java +++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DatasetMappingResolver.java @@ -16,14 +16,12 @@ package ch.systemsx.cisd.yeastx.etl; -import java.io.File; import java.util.List; import java.util.Properties; import org.apache.commons.io.FilenameUtils; import ch.systemsx.cisd.common.collections.CollectionUtils; -import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE; @@ -48,23 +46,8 @@ class DatasetMappingResolver */ private final static String PROPERTY_TYPE_CODE_PROPERTY_NAME = "unique-property-type-code"; - private static final String GROUP_CODE_PROPERTY_NAME = "group-code"; - private static final String PROPERTIES_PREFIX = "USER."; - public static String getGroupCode(Properties properties) - { - String groupCode = properties.getProperty(GROUP_CODE_PROPERTY_NAME); - if (groupCode == null) - { - throw ConfigurationFailureException - .fromTemplate( - "No group code defined in server configuration. Use '%s' property to specify it.", - GROUP_CODE_PROPERTY_NAME); - } - return groupCode; - } - public static String tryGetUniquePropertyTypeCode(Properties properties) { return tryGetPropertyTypeCode(properties); @@ -72,15 +55,12 @@ class DatasetMappingResolver private final IEncapsulatedOpenBISService openbisService; - private final String groupCode; - private final String propertyCodeOrNull; public DatasetMappingResolver(Properties properties, IEncapsulatedOpenBISService openbisService) { this.openbisService = openbisService; this.propertyCodeOrNull = tryGetPropertyTypeCode(properties); - this.groupCode = properties.getProperty(GROUP_CODE_PROPERTY_NAME); } private static String tryGetPropertyTypeCode(Properties properties) @@ -95,7 +75,7 @@ class DatasetMappingResolver } } - public String tryFigureSampleCode(DataSetMappingInformation mapping, File logDir) + public String tryFigureSampleCode(DataSetMappingInformation mapping, LogUtils log) { String sampleCodeOrLabel = mapping.getSampleCodeOrLabel(); if (propertyCodeOrNull == null) @@ -107,21 +87,21 @@ class DatasetMappingResolver // The main purpose of this checks is to ensure that sample with the given code exists. // If it is not a case, we will try to check if the specified sample label is unique (in // all experiments). - if (tryFigureExperiment(sampleCodeOrLabel) != null) + if (tryFigureExperiment(sampleCodeOrLabel, mapping, log) != null) { return sampleCodeOrLabel; } } ListSamplesByPropertyCriteria criteria = - new ListSamplesByPropertyCriteria(propertyCodeOrNull, sampleCodeOrLabel, groupCode, - tryGetExperimentIdentifier(mapping)); + new ListSamplesByPropertyCriteria(propertyCodeOrNull, sampleCodeOrLabel, mapping + .getGroupCode(), tryGetExperimentIdentifier(mapping)); List<String> samples; try { samples = openbisService.listSamplesByCriteria(criteria); } catch (UserFailureException e) { - logMappingError(mapping, logDir, e.getMessage()); + logMappingError(mapping, log, e.getMessage()); return null; } if (samples.size() == 1) @@ -129,7 +109,7 @@ class DatasetMappingResolver return samples.get(0); } else if (samples.size() == 0) { - logMappingError(mapping, logDir, "there is no sample which matches the criteria <" + logMappingError(mapping, log, "there is no sample which matches the criteria <" + criteria + ">"); return null; } else @@ -139,7 +119,7 @@ class DatasetMappingResolver "there should be exacty one sample which matches the criteria '%s', but %d of them were found." + " Consider using the unique sample code.", criteria, samples .size()); - logMappingError(mapping, logDir, errMsg); + logMappingError(mapping, log, errMsg); return null; } } @@ -158,29 +138,29 @@ class DatasetMappingResolver } } - public boolean isMappingCorrect(DataSetMappingInformation mapping, File logDir) + public boolean isMappingCorrect(DataSetMappingInformation mapping, LogUtils log) { - if (isExperimentColumnCorrect(mapping, logDir) == false) + if (isExperimentColumnCorrect(mapping, log) == false) { return false; } - String sampleCode = tryFigureSampleCode(mapping, logDir); + String sampleCode = tryFigureSampleCode(mapping, log); if (sampleCode == null) { return false; } - return isConversionColumnValid(mapping, logDir) - && existsAndBelongsToExperiment(mapping, logDir, sampleCode); + return isConversionColumnValid(mapping, log) + && existsAndBelongsToExperiment(mapping, log, sampleCode); } private static boolean isConversionColumnValid(final DataSetMappingInformation mapping, - File logDir) + LogUtils log) { String conversionText = mapping.getConversion(); MLConversionType conversion = MLConversionType.tryCreate(conversionText); if (conversion == null) { - LogUtils.error(logDir, String.format( + log.userError(String.format( "Error for file '%s'. Unexpected value '%s' in 'conversion' column. " + "Leave the column empty or use one of the allowed values: %s.", mapping.getFileName(), conversionText, CollectionUtils.abbreviate( @@ -191,18 +171,14 @@ class DatasetMappingResolver boolean conversionRequired = isConversionRequired(mapping); if (conversion == MLConversionType.NONE && conversionRequired) { - LogUtils - .error( - logDir, - "Error for file '%s'. Conversion column cannot be empty for this type of file.", - mapping.getFileName()); + log.userError("Error for file '%s'. Conversion column cannot be empty " + + "for this type of file.", mapping.getFileName()); return false; } if (conversion != MLConversionType.NONE && conversionRequired == false) { - LogUtils.error(logDir, - "Error for file '%s'. Conversion column must be empty for this type of file.", - mapping.getFileName()); + log.userError("Error for file '%s'. Conversion column must be empty " + + "for this type of file.", mapping.getFileName()); return false; } return true; @@ -215,36 +191,46 @@ class DatasetMappingResolver return conversionRequired; } - private boolean existsAndBelongsToExperiment(DataSetMappingInformation mapping, File logDir, + private boolean existsAndBelongsToExperiment(DataSetMappingInformation mapping, LogUtils log, String sampleCode) { - ExperimentPE experiment = tryFigureExperiment(sampleCode); + ExperimentPE experiment = tryFigureExperiment(sampleCode, mapping, log); if (experiment == null) { - logMappingError(mapping, logDir, String.format( - "sample with the code '%s' does not exist" - + " or is not connected to any experiment", sampleCode)); + logMappingError(mapping, log, String.format("sample with the code '%s' does not exist" + + " or is not connected to any experiment", sampleCode)); return false; } return true; } - private ExperimentPE tryFigureExperiment(String sampleCode) + private ExperimentPE tryFigureExperiment(String sampleCode, DataSetMappingInformation mapping, + LogUtils log) { - SampleIdentifier sampleIdentifier = createSampleIdentifier(sampleCode); - return openbisService.getBaseExperiment(sampleIdentifier); + SampleIdentifier sampleIdentifier = createSampleIdentifier(sampleCode, mapping); + try + { + return openbisService.getBaseExperiment(sampleIdentifier); + } catch (UserFailureException e) + { + log.userError("Error when checking if sample '%s' belongs to an experiment: %s", + sampleIdentifier, e.getMessage()); + return null; + } } - private SampleIdentifier createSampleIdentifier(String sampleCode) + private SampleIdentifier createSampleIdentifier(String sampleCode, + DataSetMappingInformation mapping) { - return new SampleIdentifier(new GroupIdentifier((String) null, groupCode), sampleCode); + return new SampleIdentifier(new GroupIdentifier((String) null, mapping.getGroupCode()), + sampleCode); } - private boolean isExperimentColumnCorrect(DataSetMappingInformation mapping, File logDir) + private boolean isExperimentColumnCorrect(DataSetMappingInformation mapping, LogUtils log) { if ((mapping.getExperimentCode() == null) != (mapping.getProjectCode() == null)) { - logMappingError(mapping, logDir, + logMappingError(mapping, log, "experiment and project columns should be both empty or should be both filled."); return false; } @@ -252,7 +238,7 @@ class DatasetMappingResolver { logMappingError( mapping, - logDir, + log, "openBis is not configured to use the sample label to identify the sample." + " You can still identify the sample by the code (clear the experiment column in this case)." + " You can also contact your administrator to change the server configuration and set the property type code which should be used."); @@ -261,10 +247,10 @@ class DatasetMappingResolver return true; } - private void logMappingError(DataSetMappingInformation mapping, File logDir, String errorMessage) + private void logMappingError(DataSetMappingInformation mapping, LogUtils log, + String errorMessage) { - LogUtils.error(logDir, "Mapping for file " + mapping.getFileName() + " is incorrect: " - + errorMessage); + log.userError("Mapping for file " + mapping.getFileName() + " is incorrect: " + errorMessage); } public static void adaptPropertyCodes(List<DataSetMappingInformation> list) diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DatasetMappingUtil.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DatasetMappingUtil.java index e5135eaf1a968d8c74d3dc6adc259a4bd60538fd..895b1eeda37e56de7b8e04c84bd934c43f135d7b 100644 --- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DatasetMappingUtil.java +++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/DatasetMappingUtil.java @@ -27,6 +27,7 @@ import java.util.Set; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; import ch.systemsx.cisd.common.collections.CollectionUtils; import ch.systemsx.cisd.common.collections.IKeyExtractor; @@ -34,6 +35,7 @@ import ch.systemsx.cisd.common.collections.TableMap; import ch.systemsx.cisd.common.collections.TableMap.UniqueKeyViolationException; import ch.systemsx.cisd.common.collections.TableMap.UniqueKeyViolationStrategy; import ch.systemsx.cisd.common.filesystem.FileUtilities; +import ch.systemsx.cisd.common.parser.TabFileLoader; /** * @author Tomasz Pylak @@ -62,7 +64,8 @@ class DatasetMappingUtil UniqueKeyViolationStrategy.ERROR); } catch (UniqueKeyViolationException e) { - LogUtils.error(logDir, + // TODO 2009-06-16, Tomasz Pylak: use email to send notifications + LogUtils.basicError(logDir, "The file '%s' appears more than once. No datasets will be processed.", e .getInvalidKey()); return null; @@ -87,18 +90,82 @@ class DatasetMappingUtil return datasetsMapping.tryGet(datasetFileName.toLowerCase()); } + // returns the content of the first line comment or null if there is no comment or it is empty + private static String tryGetFirstLineCommentContent(File mappingFile) + { + List<String> lines; + try + { + lines = readLines(mappingFile); + } catch (IOException e) + { + errorInFile(mappingFile, e.getMessage()); + return null; + } + if (lines.size() == 0) + { + return null; + } + String firstLine = lines.get(0); + if (StringUtils.isBlank(firstLine)) + { + return null; + } + firstLine = firstLine.trim(); + if (firstLine.startsWith(TabFileLoader.COMMENT_PREFIX) == false) + { + return null; + } + firstLine = firstLine.substring(1).trim(); + return firstLine; + } + + private static void errorInFile(File file, String message) + { + LogUtils.basicError(file.getParentFile(), "Error while reading the file '%s': %s", file + .getPath(), message); + } + + // returns email address from the first line of the mapping file or null if there is no emai or + // it is invalid + private static String tryGetEmail(File mappingFile) + { + String email = tryGetFirstLineCommentContent(mappingFile); + if (email == null) + { + errorInFile(mappingFile, String.format( + "There should be a '%s' character followed by an email address " + + "in the first line of the file. " + + "The email is needed to send messages about errors.", + TabFileLoader.COMMENT_PREFIX)); + return null; + } + if (email.contains("@") == false || email.contains(".") == false) + { + errorInFile(mappingFile, String.format( + "The text '%s' does not seem to be an email address.", email)); + return null; + } + return email; + } + public static TableMap<String/* file name in lowercase */, DataSetMappingInformation> tryGetDatasetsMapping( File parentDir) { File mappingFile = tryGetMappingFile(parentDir); if (mappingFile == null) { - LogUtils.warn(parentDir, "Cannot process the directory '%s' " + LogUtils.basicWarn(parentDir, "Cannot process the directory '%s' " + "because a file with extension '%s' which contains dataset descriptions " + "does not exist or there is more than one.", parentDir.getPath(), CollectionUtils.abbreviate(MAPPING_FILE_EXTENSIONS, -1)); return null; } + String notificationEmail = tryGetEmail(mappingFile); + if (notificationEmail == null) + { + return null; + } List<DataSetMappingInformation> list = DataSetMappingInformationParser.tryParse(mappingFile); if (list == null) diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/LogUtils.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/LogUtils.java index 936f638062ded6d8066e334ed91d64227d790f13..c7664344e461f08433366ebf9079b4583e69fa8e 100644 --- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/LogUtils.java +++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/LogUtils.java @@ -40,34 +40,75 @@ class LogUtils private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, LogUtils.class); - public static void error(File loggingDir, String messageFormat, Object... arguments) + private final File loggingDir; + + private final StringBuffer messageToSend; + + public LogUtils(File loggingDir) { - notifyUser(loggingDir, "ERROR", messageFormat, arguments); - adminError(messageFormat, arguments); + this.loggingDir = loggingDir; + this.messageToSend = new StringBuffer(); } - public static void warn(File loggingDir, String messageFormat, Object... arguments) + public void userError(String messageFormat, Object... arguments) { - notifyUser(loggingDir, "WARNING", messageFormat, arguments); - adminWarn(messageFormat, arguments); + String message = basicError(loggingDir, messageFormat, arguments); + messageToSend.append(message); } - private static void notifyUser(File loggingDir, String messageKind, String messageFormat, - Object... arguments) + public void userWarning(String messageFormat, Object... arguments) + { + String message = basicWarn(loggingDir, messageFormat, arguments); + messageToSend.append(message); + } + + public void sendNotificationsIfNecessary() + { + // TODO 2009-06-16, Tomasz Pylak: add email notification + if (messageToSend.length() > 0) + { + System.out.println("Email content: "); + System.out.println(messageToSend); + } + } + + /** Adds an entry about an error to the user log file. Does not send an email. */ + public static String basicError(File loggingDir, String messageFormat, Object... arguments) + { + String message = createUserMessage("ERROR", messageFormat, arguments); + notifyUserByLogFile(loggingDir, message); + return message; + } + + /** Adds an entry about a warning to the user log file. Does not send an email. */ + public static String basicWarn(File loggingDir, String messageFormat, Object... arguments) + { + String message = createUserMessage("WARNING", messageFormat, arguments); + notifyUserByLogFile(loggingDir, message); + return message; + } + + private static void notifyUserByLogFile(File loggingDir, String message) { - String now = new Date().toString(); - String message = now + " " + messageKind + ": " + format(messageFormat, arguments); OutputStream output; try { output = new FileOutputStream(getUserLogFile(loggingDir), true); - IOUtils.writeLines(Arrays.asList(message), "\n", output); + IOUtils.writeLines(Arrays.asList(message), "", output); } catch (IOException ex) { adminError("Cannot notify a user: " + ex.getMessage()); } } + private static String createUserMessage(String messageKind, String messageFormat, + Object... arguments) + { + String now = new Date().toString(); + String message = now + " " + messageKind + ": " + format(messageFormat, arguments) + "\n"; + return message; + } + private static File getUserLogFile(File loggingDir) { return new File(loggingDir, ConstantsYeastX.USER_LOG_FILE); @@ -83,7 +124,7 @@ class LogUtils operationLog.warn(format(messageFormat, arguments)); } - public static void info(String messageFormat, Object... arguments) + public static void adminInfo(String messageFormat, Object... arguments) { operationLog.info(format(messageFormat, arguments)); }