package org.csc.phynixx.loggersystem.logger.channellogger;
/*
* #%L
* phynixx-common
* %%
* Copyright (C) 2014 csc
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;
import org.csc.phynixx.common.logger.IPhynixxLogger;
import org.csc.phynixx.common.logger.PhynixxLogManager;
import org.csc.phynixx.loggersystem.logger.IDataLogger;
import org.csc.phynixx.loggersystem.logger.IDataLoggerFactory;
/**
* create DataLogger using Files to store data. A logger is qualified by its
* name and a subsequent integer qualifier. It is possible to have more than one
* log file for a given logger. The log files differ in the qualifier.
*
* <pre>
* A log file is named according to the follwing pattern
* 'loggerSystemName'_'loggerName'_'qualifier'.log
*
* The different parts of the name make i possible to deduce the following information from the logfile name
* 1.) loggerSystem
* 2.) loggername
* 3.) qualifier pof the logfile for the logger
* </pre>
* A logical logger name has to unique for all logfile of the current
* loggerfactory. Diese Factory erzeugt FileChannelDataLogger . Es wird ein
* logischer Name mitgegeben und es wird im Verzeichnis eine datei mit diesem
* namen angelegt und auf dieser Datei eine TAEnabledRandomAccessFile
* instanziert.
* The logic Name is unique concerning the loggerssytem
*/
public class FileChannelDataLoggerFactory implements IDataLoggerFactory {
private static final String LOGGER_SYSTEM_FORMAT_PATTERN = "({0})_([a-z,A-Z,0-9]*[^_])_([0-9]*[^\\.])\\.[\\w]*";
private static final String LOGGER_FORMAT_PATTERN = "({0})_([0-9]*[^\\.])\\.[\\w]*";
private static final IPhynixxLogger LOGGER = PhynixxLogManager.getLogger(FileChannelDataLoggerFactory.class);
private File directory = null;
private String loggerSystemName = null;
/**
* @param loggerSystemName
* @param directoryName logfile are created in this directory
*/
public FileChannelDataLoggerFactory(String loggerSystemName, String directoryName) {
super();
this.loggerSystemName = loggerSystemName;
this.directory = new File(directoryName);
if (this.directory.exists() && !this.directory.isDirectory()) {
throw new IllegalArgumentException("Directory " + directory.getAbsolutePath() + " doesn't exist or is not a directory");
}
if (!this.directory.canExecute() && !this.directory.canWrite()) {
throw new IllegalArgumentException("Directory " + directory.getAbsolutePath() + " could not be written");
}
}
/**
* @param loggerSystemName
* @param directory logfile are created in this directory
*/
public FileChannelDataLoggerFactory(String loggerSystemName, File directory) {
super();
this.loggerSystemName = loggerSystemName;
this.directory = directory;
if (directory == null) {
throw new IllegalArgumentException("Log directory must be specified");
}
if (!directory.exists()) {
throw new IllegalArgumentException("Log directory must exists");
}
if (this.directory.exists() && !this.directory.isDirectory()) {
throw new IllegalArgumentException("Argument 'directory' has to be an existing directory");
}
}
/**
* @return Name of the loggerSystem
*/
@Override
public String getLoggerSystemName() {
return loggerSystemName;
}
/**
* @return directory containing the logfiles
*/
public File getLoggingDirectory() {
return directory;
}
private String createQualifiedLoggerName(String loggerName, int qualifier) {
return new StringBuilder(this.loggerSystemName).append("_").append(loggerName).append("_").append(qualifier).toString();
}
/**
* @param loggerName unique Identifier of the logger (concering to the logger system)
* @return dataLogger encapsulating the logfile
* @throws IOException
*/
@Override
public synchronized IDataLogger instanciateLogger(String loggerName) throws IOException {
return this.instanciateLogger(loggerName, AccessMode.APPEND);
}
/**
* @param loggerName unique Identifier of the logger (concering to the logger system)
* @return dataLogger encapsulating the logfile
* @throws IOException
*/
@Override
public synchronized IDataLogger instanciateLogger(String loggerName, AccessMode accessMode) throws IOException {
File logFile = this.provideFile(createQualifiedLoggerName(loggerName, 1), this.directory);
return new FileChannelDataLogger(logFile, accessMode);
}
/**
* destroys a logfiles
*/
@Override
public synchronized void cleanup() {
String pattern = MessageFormat.format(LOGGER_SYSTEM_FORMAT_PATTERN, this.loggerSystemName);
LogFilenameMatcher matcher = new LogFilenameMatcher(pattern);
LogFileTraverser.ICollectorCallback cb = new LogFileTraverser.ICollectorCallback() {
@Override
public void match(File file,
LogFilenameMatcher.LogFilenameParts parts) {
boolean success = file.delete();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Deleting " + file + " success=" + success);
}
}
};
new LogFileTraverser(matcher,
FileChannelDataLoggerFactory.this.getLoggingDirectory(), cb);
}
@Override
/**
* destroyes all logfile of the logger
*/
public synchronized void destroyLogger(String loggerName) {
String pattern = MessageFormat.format(LOGGER_FORMAT_PATTERN, loggerName);
LogFilenameMatcher matcher = new LogFilenameMatcher(pattern);
LogFileTraverser.ICollectorCallback cb = new LogFileTraverser.ICollectorCallback() {
@Override
public void match(File file,
LogFilenameMatcher.LogFilenameParts parts) {
boolean success = file.delete();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Deleting " + file + " success=" + success);
}
}
};
new LogFileTraverser(matcher,
FileChannelDataLoggerFactory.this.getLoggingDirectory(), cb);
}
@Override
/**
* @return logger having at least one logfile accociated
*/
public synchronized Set<String> findLoggerNames() throws IOException {
String pattern = MessageFormat.format(LOGGER_SYSTEM_FORMAT_PATTERN, this.loggerSystemName);
LogFilenameMatcher matcher = new LogFilenameMatcher(pattern);
final Set<String> loggerNames = new HashSet<String>();
LogFileTraverser.ICollectorCallback cb = new LogFileTraverser.ICollectorCallback() {
@Override
public void match(File file, LogFilenameMatcher.LogFilenameParts parts) {
loggerNames.add(parts.getLoggerName());
}
};
new LogFileTraverser(matcher, this.getLoggingDirectory(), cb);
return loggerNames;
}
private File provideFile(String fileName, File directory) throws IOException {
File file = new File(directory, fileName + ".log");
// Falls existent, so ist nichts zu tun.
if (file.exists()) {
return file;
}
if (!directory.exists()) {
final boolean mkdirs = directory.mkdirs();
if(!mkdirs) {
throw new IOException("Failed to create directory " + directory + " or one of its children");
}
}
if(!file.createNewFile()) {
throw new IOException("Failed to create file "+file);
}
return file;
}
}