Skip to content
Snippets Groups Projects
Commit 0750ff5a authored by izabel's avatar izabel
Browse files

LMS-192 + LMS-147

SVN: 4545
parent 5f2945b0
No related branches found
No related tags found
No related merge requests found
Showing
with 128 additions and 63 deletions
......@@ -24,7 +24,7 @@ import java.lang.annotation.Target;
/**
* Log annotation for methods invoked by {@link LogInvocationHandler}.
*
*
* @author Franz-Josef Elmer
*/
@Retention(RetentionPolicy.RUNTIME)
......@@ -32,6 +32,7 @@ import java.lang.annotation.Target;
@Inherited
public @interface LogAnnotation
{
public LogCategory logCategory() default LogCategory.ACCESS;
public LogCategory logCategory() default LogCategory.OPERATION;
public LogLevel logLevel() default LogLevel.UNDEFINED;
}
......@@ -25,9 +25,9 @@ public enum LogCategory
{
/** Log category for data (read) access events. */
ACCESS,
ACCESS(true),
/** Log category for authentication and authorization events. */
AUTH,
AUTH(true),
/** Log category for log events related to the machine's state (low-level). */
MACHINE,
/**
......@@ -41,6 +41,23 @@ public enum LogCategory
/** Log category for (normal) operational events. */
OPERATION,
/** Log category for data manipulation events (write access). */
TRACKING
TRACKING(true);
final boolean adminLog;
private LogCategory(boolean adminLog)
{
this.adminLog = adminLog;
}
private LogCategory()
{
this(false);
}
public boolean isAdminLog()
{
return adminLog;
}
}
......@@ -40,6 +40,20 @@ public final class LogFactory
return category.name() + "." + clazz.getCanonicalName();
}
/**
* @return The logger name for the given {@link LogCategory}. Needs to be used for admin logs (i.e.
* {@link LogCategory#isAdminLog()} needs to return <code>true</code>). It will contain the name of the
* <var>category</var>.
*/
public static String getLoggerName(LogCategory category)
{
if (category.isAdminLog() == false)
{
throw new IllegalArgumentException("Only admin logs are allowed here, but we got " + category + ".");
}
return category.name() ;
}
/**
* @return The logger for the given {@link LogCategory} and {@link Class}. The name of the logger will contain the
* name of the <var>category</var>, followed by the canonical name of <var>clazz</var>.
......@@ -48,4 +62,15 @@ public final class LogFactory
{
return Logger.getLogger(getLoggerName(category, clazz));
}
/**
* @return The logger for the given {@link LogCategory}. Needs to be an admin log (i.e.
* {@link LogCategory#isAdminLog()} needs to return <code>true</code>). The name of the logger will
* contain the name of the <var>category</var>.
*/
public static Logger getLogger(LogCategory category)
{
return Logger.getLogger(getLoggerName(category));
}
}
......@@ -26,19 +26,22 @@ import org.apache.log4j.Logger;
/**
* Invocation handler used to log invocations.
*
*
* @author Franz-Josef Elmer
*/
public final class LogInvocationHandler implements InvocationHandler
{
private final Object object;
private final String name;
private final Level defaultLogLevel;
private final Class<?> classUsedToNameLogger;
/**
* Creates a new instance.
*
*
* @param object Object whose invocations should be logged.
* @param name Meaningful name of <code>object</code>. Will be used in the log message.
* @param logLevel The log level to use for normal (successful) events.
......@@ -102,13 +105,13 @@ public final class LogInvocationHandler implements InvocationHandler
}
}
}
private Level getLogLevel(Method method)
{
final LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
if (annotation == null)
{
return Level.DEBUG;
return Level.DEBUG;
} else if (annotation.logLevel().equals(LogLevel.UNDEFINED))
{
return defaultLogLevel;
......@@ -117,11 +120,11 @@ public final class LogInvocationHandler implements InvocationHandler
return Log4jSimpleLogger.toLog4jPriority(annotation.logLevel());
}
}
private Logger createLogger(Method method)
private Logger createLogger(Method method)
{
final LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
final LogCategory logCategory = (annotation == null) ? LogCategory.ACCESS : annotation.logCategory();
final LogCategory logCategory = (annotation == null) ? LogCategory.OPERATION : annotation.logCategory();
return LogFactory.getLogger(logCategory, classUsedToNameLogger);
}
}
\ No newline at end of file
package ch.systemsx.cisd.common.logging;
/**
/**
* A simple form of log levels.
*
* @author Bernd RInn
* @author Bernd Rinn
*/
public enum LogLevel
{
UNDEFINED, OFF, TRACE, DEBUG, INFO, WARN, ERROR
UNDEFINED, OFF, TRACE, DEBUG, INFO, WARN, ERROR;
}
\ No newline at end of file
......@@ -73,7 +73,8 @@ public class DefaultParser<E> implements IParser<E>
// Parser
//
public final List<E> parse(final Iterator<Line> lineIterator, final ILineFilter lineFilter) throws ParsingException
public final List<E> parse(final Iterator<Line> lineIterator, final ILineFilter lineFilter, final long headerLength)
throws ParsingException
{
final List<E> elements = new ArrayList<E>();
synchronized (lineTokenizer)
......@@ -90,6 +91,12 @@ public class DefaultParser<E> implements IParser<E>
E object = null;
try
{
if (tokens.length > headerLength)
{
throw new RuntimeException(String.format(
"Line <%s> has more columns (%s) than the header (%s)", number, String
.valueOf(tokens.length), String.valueOf(headerLength)));
}
object = createObject(tokens);
} catch (final ParserException parserException)
{
......
......@@ -32,9 +32,11 @@ public interface IParser<E>
* Parses the lines delivered by the specified iterator and creating elements of type <code>E</code>.
*
* @param lineFilter A filter lines have to pass in order to be parsed.
* @param headerLength number of columns in the header
* @return a <code>List</code> of elements.
*/
public List<E> parse(final Iterator<Line> lineIterator, final ILineFilter lineFilter) throws ParsingException;
public List<E> parse(final Iterator<Line> lineIterator, final ILineFilter lineFilter, final long headerLength)
throws ParsingException;
/**
* Sets the <code>IParserObjectFactory</code>.
......
......@@ -35,28 +35,34 @@ import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
import ch.systemsx.cisd.common.exceptions.UserFailureException;
/**
* Convenient class to load a tab file and deliver a list of beans of type <code>T</code>. The following
* formats for the column headers are recognized.
* <ol><li>Column headers in first line:
* <pre>
* Convenient class to load a tab file and deliver a list of beans of type <code>T</code>. The following formats for
* the column headers are recognized.
* <ol>
* <li>Column headers in first line:
*
* <pre>
* column1 column2 column2
* </pre>
* <li>Comment section:
* <pre>
* </pre>
*
* <li>Comment section:
*
* <pre>
* # 1. line of comment
* # 2. line of comment
* # ...
* column1 column2 column2
* </pre>
* <li>Column headers at the end of the comment section:
* <pre>
* </pre>
*
* <li>Column headers at the end of the comment section:
*
* <pre>
* # 1. line of comment
* # 2. line of comment
* # ...
* #
* #column1 column2 column2
* </pre>
*
* </pre>
*
* </ol>
*
* @author Franz-Josef Elmer
......@@ -103,8 +109,7 @@ public class TabFileLoader<T>
IOUtils.closeQuietly(reader);
}
}
List<T> load(Reader reader)
{
List<T> result = new ArrayList<T>();
......@@ -128,18 +133,19 @@ public class TabFileLoader<T>
}
@SuppressWarnings("null")
final String headerLine = previousLineHasColumnHeaders ? previousLine.getText().substring(1) : line.getText();
final DefaultParser<T> parser = new DefaultParser<T>();
final String[] tokens = StringUtils.split(headerLine, "\t");
final long headerLength = tokens.length;
notUnique(tokens);
final IAliasPropertyMapper propertyMapper = new HeaderFilePropertyMapper(tokens);
parser.setObjectFactory(factory.createFactory(propertyMapper));
ILineFilter filter = AlwaysAcceptLineFilter.INSTANCE;
if (previousLineHasColumnHeaders)
{
result.addAll(parser.parse(Arrays.asList(line).iterator(), filter));
result.addAll(parser.parse(Arrays.asList(line).iterator(), filter, headerLength));
}
result.addAll(parser.parse(lineIterator, filter));
result.addAll(parser.parse(lineIterator, filter, headerLength));
return result;
}
......@@ -149,6 +155,7 @@ public class TabFileLoader<T>
Iterator<Line> iterator = new Iterator<Line>()
{
private int lineNumber;
public void remove()
{
lineIterator.remove();
......
......@@ -16,7 +16,9 @@
package ch.systemsx.cisd.common.db;
import static org.testng.AssertJUnit.*;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertTrue;
import java.io.File;
import java.util.Arrays;
......@@ -34,8 +36,9 @@ import ch.systemsx.cisd.common.logging.LogMonitoringAppender;
import ch.systemsx.cisd.common.utilities.FileUtilities;
/**
* Test cases for the @{link DBREstrictionParser}.
* Test cases for the
*
* @{link DBREstrictionParser}.
* @author Bernd Rinn
*/
public class DBRestrictionParserTest
......@@ -65,9 +68,8 @@ public class DBRestrictionParserTest
{
String invalidDomainStatement = "create domain bla for varchar(0)";
final List<String> domainScript =
Arrays.asList("create table sometable", "create domain user_id as varchar(15)",
invalidDomainStatement, "create domain code as varchar(8)",
"create domain description_80 as varchar(81)");
Arrays.asList("create table sometable", "create domain user_id as varchar(15)", invalidDomainStatement,
"create domain code as varchar(8)", "create domain description_80 as varchar(81)");
final LogMonitoringAppender appender =
LogMonitoringAppender.addAppender(LogCategory.OPERATION, "line \"" + invalidDomainStatement
+ "\" starts like a domain definition, but key word 'AS' is missing.");
......@@ -89,9 +91,8 @@ public class DBRestrictionParserTest
@Test
public void testDefaultKeywordInDomain()
{
final List<String> domainScript =
Arrays.asList("create domain vc22 as varchar(22) default 'nothing special'");
final List<String> domainScript = Arrays.asList("create domain vc22 as varchar(22) default 'nothing special'");
final LogMonitoringAppender appender = LogMonitoringAppender.addAppender(LogCategory.OPERATION, "ill-formed");
try
{
......@@ -104,13 +105,12 @@ public class DBRestrictionParserTest
LogMonitoringAppender.removeAppender(appender);
}
}
@Test
public void testDoublePrecisionInDomain()
{
final List<String> domainScript =
Arrays.asList("create domain dp as double precision");
final List<String> domainScript = Arrays.asList("create domain dp as double precision");
final LogMonitoringAppender appender = LogMonitoringAppender.addAppender(LogCategory.OPERATION, "ill-formed");
try
{
......@@ -122,13 +122,12 @@ public class DBRestrictionParserTest
LogMonitoringAppender.removeAppender(appender);
}
}
@Test
public void testDoublePrecisionAndDefaultInDomain()
{
final List<String> domainScript =
Arrays.asList("create domain dp as double precision default 3.14159");
final List<String> domainScript = Arrays.asList("create domain dp as double precision default 3.14159");
final LogMonitoringAppender appender = LogMonitoringAppender.addAppender(LogCategory.OPERATION, "ill-formed");
try
{
......@@ -140,7 +139,7 @@ public class DBRestrictionParserTest
LogMonitoringAppender.removeAppender(appender);
}
}
@Test
public void testColumnLengths()
{
......
......@@ -31,17 +31,19 @@ import org.testng.annotations.Test;
*/
public final class DefaultParserTest
{
private final static List<String> text
= Arrays.asList("", "# This is a comment", "firstName\tlastName\taddress\tcity",
"Charles\tDarwin\tHumboldt Ave. 1865\t4242 Somewhere",
"Albert\tEinstein\tNewton Road 1905\t4711 Princton");
private final static List<String> text =
Arrays.asList("", "# This is a comment", "firstName\tlastName\taddress\tcity",
"Charles\tDarwin\tHumboldt Ave. 1865\t4242 Somewhere",
"Albert\tEinstein\tNewton Road 1905\t4711 Princton");
private final static long HEADER_LENGTH = 4;
@Test
public final void testParseWithoutFactoryAndHeader()
{
final IParser<String[]> parser = new DefaultParser<String[]>();
parser.setObjectFactory(IParserObjectFactory.STRING_ARRAY_OBJECT_FACTORY);
final List<String[]> result = parser.parse(createLineIterator(), new HeaderLineFilter());
final List<String[]> result = parser.parse(createLineIterator(), new HeaderLineFilter(), HEADER_LENGTH);
assertEquals(3, result.size());
assertEquals(result.get(0)[0], "firstName");
assertEquals(result.get(1)[1], "Darwin");
......@@ -54,7 +56,7 @@ public final class DefaultParserTest
{
final IParser<String[]> parser = new DefaultParser<String[]>();
parser.setObjectFactory(IParserObjectFactory.STRING_ARRAY_OBJECT_FACTORY);
final List<String[]> result = parser.parse(createLineIterator(), new HeaderLineFilter(3));
final List<String[]> result = parser.parse(createLineIterator(), new HeaderLineFilter(3), HEADER_LENGTH);
assertEquals(2, result.size());
assertEquals(result.get(0)[0], "Charles");
assertEquals(result.get(1)[1], "Einstein");
......@@ -77,31 +79,33 @@ public final class DefaultParserTest
parser.setObjectFactory(IParserObjectFactory.STRING_ARRAY_OBJECT_FACTORY);
try
{
parser.parse(createLineIterator(), new HeaderLineFilter(2));
parser.parse(createLineIterator(), new HeaderLineFilter(2), HEADER_LENGTH);
} catch (ParsingException ex)
{
assertEquals(
"Creating an object with following tokens '[firstName, lastName, address, city]' failed.",
ex.getMessage());
assertEquals("Creating an object with following tokens '[firstName, lastName, address, city]' failed.", ex
.getMessage());
assertEquals(3, ex.getLineNumber());
}
}
private Iterator<Line> createLineIterator()
{
return new Iterator<Line>()
{
private Iterator<String> iterator = text.iterator();
private int lineNumber;
public void remove()
{
throw new UnsupportedOperationException();
}
public Line next()
{
return new Line(++lineNumber, iterator.next());
}
public boolean hasNext()
{
return iterator.hasNext();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment