diff --git a/common/resource/dependency-structure.ddf b/common/resource/dependency-structure.ddf index f0e4e57951078c1f359d4f59f5d7272ee035ef8a..947c4fda309310decff0c9a4347fe89fbabe36ae 100644 --- a/common/resource/dependency-structure.ddf +++ b/common/resource/dependency-structure.ddf @@ -1,9 +1,3 @@ -# -# -# - -#show allResults - {package} = ch.systemsx.cisd.common [annotation] = ${package}.annotation.* @@ -34,8 +28,13 @@ check sets [test] [utilities] = ${package}.utilities.* check sets [utilities] +[user-failure-exception] = ${package}.exceptions.UserFailureException +check sets [user-failure-exception] + layer layer0 = [annotation] [exceptions] [logging] [test] layer layer1 = [utilities] layer layer2 = [config] [db] [parser] -check layeringOf layer0 layer1 layer2 \ No newline at end of file +check layeringOf layer0 layer1 layer2 + +check [parser] independentOf [user-failure-exception] \ No newline at end of file diff --git a/common/source/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactory.java b/common/source/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactory.java index 2fd5c5b13597a1ccc89e928c4347deb9a85d4cdf..7860db55ef1eccc3b65ded0972a6c3ee533940a0 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactory.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactory.java @@ -19,8 +19,6 @@ package ch.systemsx.cisd.common.parser; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -28,7 +26,6 @@ import java.util.Set; import ch.systemsx.cisd.common.converter.Converter; import ch.systemsx.cisd.common.converter.ConverterPool; import ch.systemsx.cisd.common.exceptions.CheckedExceptionTunnel; -import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.utilities.BeanUtils; import ch.systemsx.cisd.common.utilities.ClassUtils; @@ -57,7 +54,7 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac /** The class of object bean we are going to create here. */ private final Class<E> beanClass; - protected AbstractParserObjectFactory(Class<E> beanClass, IPropertyMapper propertyMapper) + protected AbstractParserObjectFactory(final Class<E> beanClass, final IPropertyMapper propertyMapper) { assert beanClass != null; assert propertyMapper != null; @@ -81,7 +78,7 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac * If given <var>converter</var>, then it will unregister it. * </p> */ - protected final <T> void registerConverter(Class<T> clazz, Converter<T> converter) + protected final <T> void registerConverter(final Class<T> clazz, final Converter<T> converter) { if (converter == null) { @@ -98,17 +95,11 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac } /** For given property name returns corresponding <code>IPropertyModel</code>. */ - private final IPropertyModel getPropertyModel(String name) + private final IPropertyModel getPropertyModel(final String name) { return propertyMapper.getProperty(name); } - /** Returns an unmodifiable list of <code>PropertyDescriptor</code>s. */ - private final Collection<PropertyDescriptor> getPropertyDescriptors() - { - return Collections.unmodifiableCollection(propertyDescriptors.values()); - } - /** * Checks given <code>IPropertyMapper</code>. * <p> @@ -116,46 +107,33 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac * {@link #propertyDescriptors}. * </p> */ - private final void checkPropertyMapper(Class<E> clazz, IPropertyMapper propMapper) throws UserFailureException + private final void checkPropertyMapper(final Class<E> clazz, final IPropertyMapper propMapper) + throws ParserException { - assert propertyDescriptors != null; + assert propertyDescriptors != null : "Property descriptors can not be null."; - Set<String> propertyNames = new HashSet<String>(propMapper.getAllPropertyNames()); - propertyNames.removeAll(propertyDescriptors.keySet()); + final Set<String> allPropertyNames = propMapper.getAllPropertyNames(); + final Set<String> propertyNames = new HashSet<String>(allPropertyNames); + final Set<String> descriptorNames = propertyDescriptors.keySet(); + propertyNames.removeAll(descriptorNames); if (propertyNames.size() > 0) { - throw UserFailureException.fromTemplate("The following header columns are not part of '%s': %s", clazz - .getSimpleName(), format(propertyNames)); - } - } - - private final String format(Set<String> set) - { - final StringBuilder builder = new StringBuilder(); - for (String s : set) - { - builder.append("'"); - builder.append(s); - builder.append("', "); + throw new UnmatchedPropertiesException(clazz, allPropertyNames, descriptorNames, propertyNames); } - // Remove trailing ", " - builder.setLength(builder.length() - 2); - return builder.toString(); } /** Whether given field name is mandatory. */ - private final boolean isMandatory(String fieldName) + private final boolean isMandatory(final String fieldName) { return mandatoryFields.contains(fieldName); } - private String getPropertyValue(final String[] lineTokens, final IPropertyModel propertyModel) + private final String getPropertyValue(final String[] lineTokens, final IPropertyModel propertyModel) { - int column = propertyModel.getColumn(); + final int column = propertyModel.getColumn(); if (column >= lineTokens.length) { - throw UserFailureException.fromTemplate("Not enough tokens are available (index: %d, available: %d)", - column, lineTokens.length); + throw new IndexOutOfBoundsException(column, lineTokens); } return lineTokens[column]; } @@ -164,13 +142,12 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac // IParserObjectFactory // - @SuppressWarnings("unchecked") - public E createObject(String[] lineTokens) + public E createObject(final String[] lineTokens) throws ParserException { try { - Object object = beanClass.newInstance(); - for (PropertyDescriptor descriptor : getPropertyDescriptors()) + final E object = beanClass.newInstance(); + for (final PropertyDescriptor descriptor : propertyDescriptors.values()) { final Method writeMethod = descriptor.getWriteMethod(); final IPropertyModel propertyModel = getPropertyModel(descriptor.getName()); @@ -185,11 +162,11 @@ public abstract class AbstractParserObjectFactory<E> implements IParserObjectFac final String fieldName = descriptor.getName(); if (isMandatory(fieldName)) { - throw UserFailureException.fromTemplate("Field/Property name '%s' is mandatory.", fieldName); + throw new MandatoryPropertyMissingException(beanClass, fieldName); } } } - return (E) object; + return object; } catch (IllegalAccessException ex) { throw new CheckedExceptionTunnel(ex); diff --git a/common/source/java/ch/systemsx/cisd/common/parser/AlwaysAcceptLineFilter.java b/common/source/java/ch/systemsx/cisd/common/parser/AlwaysAcceptLineFilter.java index ec6941724319f7080b453379d1a4b4c405a280d2..486f87e97e22cfacbb6db7fcdda40b0c5c2e4f0b 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/AlwaysAcceptLineFilter.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/AlwaysAcceptLineFilter.java @@ -2,16 +2,22 @@ package ch.systemsx.cisd.common.parser; /** * A default line filter that accepts any line. - * + * * @author Christian Ribeaud */ public final class AlwaysAcceptLineFilter implements ILineFilter { public static final ILineFilter INSTANCE = new AlwaysAcceptLineFilter(); - - private AlwaysAcceptLineFilter() {} - - public final boolean acceptLine(String line, int lineNumber) + + private AlwaysAcceptLineFilter() + { + } + + // + // ILineFilter + // + + public final boolean acceptLine(final String line, final int lineNumber) { return true; } diff --git a/common/source/java/ch/systemsx/cisd/common/parser/DefaultReaderParser.java b/common/source/java/ch/systemsx/cisd/common/parser/DefaultReaderParser.java index 80db898cce11dc0256f50fe61500ac626f7fcdca..b4019c4623e70b2eb531cc59a32ac9872fb1a858 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/DefaultReaderParser.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/DefaultReaderParser.java @@ -18,7 +18,6 @@ package ch.systemsx.cisd.common.parser; import java.io.Reader; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import org.apache.commons.io.IOUtils; @@ -44,12 +43,12 @@ public class DefaultReaderParser<E> implements IReaderParser<E> this(new DefaultLineTokenizer()); } - public DefaultReaderParser(ILineTokenizer lineTokenizer) + public DefaultReaderParser(final ILineTokenizer lineTokenizer) { this.lineTokenizer = lineTokenizer; } - protected E createObject(String[] tokens) + protected E createObject(final String[] tokens) throws ParserException { return factory.createObject(tokens); } @@ -60,7 +59,7 @@ public class DefaultReaderParser<E> implements IReaderParser<E> * Uses <code>ILineTokenizer</code> to do its job. * </p> */ - protected String[] parseLine(int lineNumber, String line) + protected String[] parseLine(final int lineNumber, final String line) { return lineTokenizer.tokenize(line); } @@ -69,32 +68,35 @@ public class DefaultReaderParser<E> implements IReaderParser<E> // Parser // - public final List<E> parse(Reader reader) + public final List<E> parse(final Reader reader) { return parse(reader, AlwaysAcceptLineFilter.INSTANCE); } - public final List<E> parse(Reader reader, ILineFilter lineFilter) + public final List<E> parse(final Reader reader, final ILineFilter lineFilter) throws ParsingException { final List<E> elements = new ArrayList<E>(); synchronized (lineTokenizer) { lineTokenizer.init(); - LineIterator lineIterator = IOUtils.lineIterator(reader); + final LineIterator lineIterator = IOUtils.lineIterator(reader); for (int lineNumber = 0; lineIterator.hasNext(); lineNumber++) { - String nextLine = lineIterator.nextLine(); + final String nextLine = lineIterator.nextLine(); if (lineFilter.acceptLine(nextLine, lineNumber)) { - String[] tokens = parseLine(lineNumber, nextLine); - E object; + final String[] tokens = parseLine(lineNumber, nextLine); + E object = null; try { object = createObject(tokens); - } catch (RuntimeException ex) + } catch (final ParserException parserException) { - throw new ParseException(String.format("Creating an object with following tokens '%s' failed.", - Arrays.asList(tokens)), ex, lineNumber); + throw new ParsingException(parserException, tokens, lineNumber); + } catch (final RuntimeException runtimeException) + { + // This should not happen but... + throw new ParsingException(runtimeException, tokens, lineNumber); } elements.add(object); } @@ -105,7 +107,7 @@ public class DefaultReaderParser<E> implements IReaderParser<E> } - public final void setObjectFactory(IParserObjectFactory<E> factory) + public final void setObjectFactory(final IParserObjectFactory<E> factory) { this.factory = factory; } diff --git a/common/source/java/ch/systemsx/cisd/common/parser/ExcludeEmptyAndCommentLineFilter.java b/common/source/java/ch/systemsx/cisd/common/parser/ExcludeEmptyAndCommentLineFilter.java index b5b4820236b581b38437d6f853b9ac21145172ee..fc0498aaa583bcfd8d0dcb01ffe4625ebfef0d68 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/ExcludeEmptyAndCommentLineFilter.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/ExcludeEmptyAndCommentLineFilter.java @@ -5,16 +5,22 @@ package ch.systemsx.cisd.common.parser; * <p> * A comment line starts with '#'. * </p> - * + * * @author Christian Ribeaud */ public final class ExcludeEmptyAndCommentLineFilter implements ILineFilter { public static final ILineFilter INSTANCE = new ExcludeEmptyAndCommentLineFilter(); - - private ExcludeEmptyAndCommentLineFilter() {} - - public final boolean acceptLine(String line, int lineNumber) + + private ExcludeEmptyAndCommentLineFilter() + { + } + + // + // ILineFilter + // + + public final boolean acceptLine(final String line, final int lineNumber) { final String trimmed = line.trim(); return trimmed.length() > 0 && trimmed.startsWith("#") == false; diff --git a/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactory.java b/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactory.java index 785dcaa0124c10a2e37ba568f87f5276edb115ef..27eb3b269830b303f8ee23111efb08f5744cce1f 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactory.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactory.java @@ -16,8 +16,6 @@ package ch.systemsx.cisd.common.parser; -import ch.systemsx.cisd.common.exceptions.UserFailureException; - /** * A <code>IParserObjectFactory</code> implementation knows how to deal with given line tokens and convert them into * an appropriate <code>Object</code>. @@ -39,21 +37,22 @@ public interface IParserObjectFactory<E> * * @author Christian Ribeaud */ - public final static IParserObjectFactory<String[]> STRING_ARRAY_OBJECT_FACTORY = new IParserObjectFactory<String[]>() - { + public final static IParserObjectFactory<String[]> STRING_ARRAY_OBJECT_FACTORY = + new IParserObjectFactory<String[]>() + { - // - // IParserObjectFactory - // + // + // IParserObjectFactory + // - public final String[] createObject(String[] lineTokens) - { - return lineTokens; - } - }; + public final String[] createObject(final String[] lineTokens) throws ParserException + { + return lineTokens; + } + }; /** * Parses given text line and returns an appropriate <i>Object</i>. */ - public E createObject(String[] lineTokens) throws UserFailureException; + public E createObject(final String[] lineTokens) throws ParserException; } \ No newline at end of file diff --git a/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactoryFactory.java b/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactoryFactory.java index 176010b1456f738342573480c27e37904ac863b4..1a37e2db98018fa2f5da70fb109db3502573f8c9 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactoryFactory.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactoryFactory.java @@ -26,5 +26,5 @@ public interface IParserObjectFactoryFactory<T> /** * Creates a new factory for the specified property mapper. */ - public IParserObjectFactory<T> createFactory(final IAliasPropertyMapper propertyMapper); + public IParserObjectFactory<T> createFactory(final IAliasPropertyMapper propertyMapper) throws ParserException; } diff --git a/common/source/java/ch/systemsx/cisd/common/parser/IPropertyMapper.java b/common/source/java/ch/systemsx/cisd/common/parser/IPropertyMapper.java index 1635e02198b0fbfe1592d4c91857a58de7443663..a07d1a7e65128462b1ba4c0d4aa0c5bd253f4242 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/IPropertyMapper.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/IPropertyMapper.java @@ -27,7 +27,7 @@ public interface IPropertyMapper { /** Returns an <code>IPropertyModel</code> for a given property name. */ - public IPropertyModel getProperty(String name); + public IPropertyModel getProperty(final String name); /** * Returns a set of all property names. diff --git a/common/source/java/ch/systemsx/cisd/common/parser/IReaderParser.java b/common/source/java/ch/systemsx/cisd/common/parser/IReaderParser.java index 1a84b795b68345bffa4abe3c6de923175ba11482..65325b2538fcd92c97da2724b18712fb1dab2e65 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/IReaderParser.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/IReaderParser.java @@ -38,7 +38,7 @@ public interface IReaderParser<E> * @param lineFilter you could define a filter for the lines found in given <code>reader</code>. * @return a <code>List</code> of elements. */ - public List<E> parse(Reader reader, ILineFilter lineFilter); + public List<E> parse(final Reader reader, final ILineFilter lineFilter) throws ParsingException; /** * Parses given <code>Reader</code>. Encapsulates given <code>Reader</code> in a {@link BufferedReader} for @@ -49,7 +49,7 @@ public interface IReaderParser<E> * * @return a <code>List</code> of elements. */ - public List<E> parse(Reader reader); + public List<E> parse(final Reader reader); /** * Sets the <code>IParserObjectFactory</code>. @@ -57,5 +57,5 @@ public interface IReaderParser<E> * Typically, the given <code>factory</code> transforms a line into an element. * </p> */ - public void setObjectFactory(IParserObjectFactory<E> factory); + public void setObjectFactory(final IParserObjectFactory<E> factory); } diff --git a/common/source/java/ch/systemsx/cisd/common/parser/IndexOutOfBoundsException.java b/common/source/java/ch/systemsx/cisd/common/parser/IndexOutOfBoundsException.java new file mode 100644 index 0000000000000000000000000000000000000000..5f615b245a461991be80044ed5afe7383b7b35b5 --- /dev/null +++ b/common/source/java/ch/systemsx/cisd/common/parser/IndexOutOfBoundsException.java @@ -0,0 +1,58 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * 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. + */ + +package ch.systemsx.cisd.common.parser; + +/** + * A <code>ParserException</code> extension which signalizes a lookup index outside of the currently available tokens. + * + * @author Christian Ribeaud + */ +public final class IndexOutOfBoundsException extends ParserException +{ + + static final String MESSAGE_FORMAT = "Not enough tokens are available (index: %d, available: %d)"; + + private static final long serialVersionUID = 1L; + + private final int column; + + private final String[] lineTokens; + + IndexOutOfBoundsException(final int column, final String[] lineTokens) + { + super(createMessage(column, lineTokens)); + this.column = column; + this.lineTokens = lineTokens; + } + + private final static String createMessage(final int index, final String[] lineTokens) + { + assert lineTokens != null : "Line tokens can not be null."; + return String.format(MESSAGE_FORMAT, index, lineTokens.length); + } + + public final int getColumn() + { + return column; + } + + public final String[] getLineTokens() + { + return lineTokens; + } + +} diff --git a/common/source/java/ch/systemsx/cisd/common/parser/MandatoryPropertyMissingException.java b/common/source/java/ch/systemsx/cisd/common/parser/MandatoryPropertyMissingException.java new file mode 100644 index 0000000000000000000000000000000000000000..6560e3639e2c3f3a46d5bc52e4cab074fe932880 --- /dev/null +++ b/common/source/java/ch/systemsx/cisd/common/parser/MandatoryPropertyMissingException.java @@ -0,0 +1,59 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * 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. + */ + +package ch.systemsx.cisd.common.parser; + +/** + * A <code>ParserException</code> extension which signalizes missing of a mandatory property. + * + * @author Christian Ribeaud + */ +public final class MandatoryPropertyMissingException extends ParserException +{ + + static final String MESSAGE_FORMAT = "Field/Property name '%s' is mandatory."; + + private static final long serialVersionUID = 1L; + + private final Class<?> beanClass; + + private final String fieldName; + + MandatoryPropertyMissingException(final Class<?> beanClass, final String fieldName) + { + super(createMessage(fieldName)); + assert beanClass != null : "Bean class can not be null."; + this.beanClass = beanClass; + this.fieldName = fieldName; + } + + private final static String createMessage(final String fieldName) + { + assert fieldName != null : "Field name can not be null."; + return String.format(MESSAGE_FORMAT, fieldName); + } + + public final Class<?> getBeanClass() + { + return beanClass; + } + + public final String getFieldName() + { + return fieldName; + } + +} diff --git a/common/source/java/ch/systemsx/cisd/common/parser/ParseException.java b/common/source/java/ch/systemsx/cisd/common/parser/ParserException.java similarity index 62% rename from common/source/java/ch/systemsx/cisd/common/parser/ParseException.java rename to common/source/java/ch/systemsx/cisd/common/parser/ParserException.java index f8aa5ea362ed7e7b5ecf5b52536cbc75638f3892..bfebad84f2d3082b0bdd61c6be81e80f07074182 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/ParseException.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/ParserException.java @@ -16,31 +16,25 @@ package ch.systemsx.cisd.common.parser; -import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.common.exceptions.HighLevelException; /** - * Signals that an error has been reached unexpectedly while parsing. + * A top level exception for the parser. * * @author Christian Ribeaud */ -public final class ParseException extends UserFailureException +public class ParserException extends HighLevelException { private static final long serialVersionUID = 1L; - private final int lineNumber; - - public ParseException(String message, Throwable cause, int lineNumber) + public ParserException(final String message, final Throwable cause) { super(message, cause); - this.lineNumber = lineNumber; } - /** - * Returns the line where the error was found. - */ - public final int getLineNumber() + public ParserException(final String message) { - return lineNumber; + super(message); } } diff --git a/common/source/java/ch/systemsx/cisd/common/parser/ParserUtilities.java b/common/source/java/ch/systemsx/cisd/common/parser/ParserUtilities.java index d35ab1fceaa82f5899b73d4d5625f6f74e596d8b..14983891d65565bc7174572255e8024c81917ec5 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/ParserUtilities.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/ParserUtilities.java @@ -72,7 +72,7 @@ public final class ParserUtilities */ public final static Line getFirstAcceptedLine(final File file, final ILineFilter lineFilter) { - assert file != null && file.exists(); + assert file != null && file.exists() : "Given file must not be null and must exist."; final ILineFilter filter = lineFilter == null ? AlwaysAcceptLineFilter.INSTANCE : lineFilter; LineIterator lineIterator = null; diff --git a/common/source/java/ch/systemsx/cisd/common/parser/ParsingException.java b/common/source/java/ch/systemsx/cisd/common/parser/ParsingException.java new file mode 100644 index 0000000000000000000000000000000000000000..9c95acbd0df5867e28820a1133b7b101fd9fb05f --- /dev/null +++ b/common/source/java/ch/systemsx/cisd/common/parser/ParsingException.java @@ -0,0 +1,64 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * 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. + */ + +package ch.systemsx.cisd.common.parser; + +import java.util.Arrays; + +import ch.systemsx.cisd.common.exceptions.HighLevelException; + +/** + * Signals that an error has been reached unexpectedly while parsing. + * + * @author Christian Ribeaud + */ +public final class ParsingException extends HighLevelException +{ + + static final String MESSAGE_FORMAT = "Creating an object with following tokens '%s' failed."; + + private static final long serialVersionUID = 1L; + + private final int lineNumber; + + private final String[] tokens; + + ParsingException(final RuntimeException cause, final String[] tokens, final int lineNumber) + { + super(createMessage(tokens), cause); + this.lineNumber = lineNumber; + this.tokens = tokens; + } + + private final static String createMessage(final String[] tokens) + { + assert tokens != null : "Tokens can not be null."; + return String.format(MESSAGE_FORMAT, Arrays.asList(tokens)); + } + + /** + * Returns the line where the error was found. + */ + public final int getLineNumber() + { + return lineNumber; + } + + public final String[] getTokens() + { + return tokens; + } +} diff --git a/common/source/java/ch/systemsx/cisd/common/parser/PropertiesParserObjectFactory.java b/common/source/java/ch/systemsx/cisd/common/parser/PropertiesParserObjectFactory.java deleted file mode 100644 index 8553894ef4163f6f036c9af57b55579f061fd91f..0000000000000000000000000000000000000000 --- a/common/source/java/ch/systemsx/cisd/common/parser/PropertiesParserObjectFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2007 ETH Zuerich, CISD - * - * 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. - */ - -package ch.systemsx.cisd.common.parser; - -import java.util.Set; - -import ch.systemsx.cisd.common.exceptions.UserFailureException; - -/** - * Creates new object by setting its properties. - * - * @author Tomasz Pylak on Oct 26, 2007 - */ -public class PropertiesParserObjectFactory<E> implements IParserObjectFactory<E> -{ - /** The <code>IPropertyMapper</code> implementation. */ - private final IPropertyMapper propertyMapper; - - private final IPropertyObjectFactory<E> objectFactory; - - public PropertiesParserObjectFactory(IPropertyMapper propertyMapper, IPropertyObjectFactory<E> objectFactory) - { - this.propertyMapper = propertyMapper; - this.objectFactory = objectFactory; - } - - public E createObject(String[] lineTokens) throws UserFailureException - { - IPropertiesSetter<E> setter = objectFactory.createObjectSetter(); - Set<String> propertyNames = propertyMapper.getAllPropertyNames(); - for (String name : propertyNames) - { - final IPropertyModel propertyModel = propertyMapper.getProperty(name); - String propertyValue = getPropertyValue(lineTokens, propertyModel); - setter.setProperty(name, propertyValue); - } - return setter.getConstructedObject(); - } - - private String getPropertyValue(final String[] lineTokens, final IPropertyModel propertyModel) - { - int column = propertyModel.getColumn(); - if (column >= lineTokens.length) - { - String name = propertyModel.getName(); - String mergedTokens = merge(lineTokens); - throw UserFailureException.fromTemplate("Value for column '%s' cannot be found in line '%s'", name, - mergedTokens); - } - return lineTokens[column]; - } - - private static String merge(String[] lineTokens) - { - StringBuffer sb = new StringBuffer(); - for (String col : lineTokens) - { - sb.append("<"); - sb.append(col); - sb.append("> "); - } - return sb.toString(); - } - -} 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 9e250e6a632ace4609cc0594540f834cd509186c..147d718c9acc50532988f6110486fa8b10837c19 100644 --- a/common/source/java/ch/systemsx/cisd/common/parser/TabFileLoader.java +++ b/common/source/java/ch/systemsx/cisd/common/parser/TabFileLoader.java @@ -51,23 +51,19 @@ public class TabFileLoader<T> /** * Loads from the specified tab file a list of objects of type <code>T</code>. * - * @throws UserFailureException if the file does not exists, the header line with correct column bean attribute - * names is missing, or a parsing error occurs. - * @throws EnvironmentFailureException if a IOException occured. + * @throws EnvironmentFailureException if a IOException occurred. */ - public final List<T> load(final File file) throws UserFailureException + public List<T> load(final File file) { - // Just check whether the file exists. Lets <code>FileUtils</code> do the rest. - if (file.exists() == false) - { - throw new UserFailureException("Given file '" + file.getAbsolutePath() + "' does not exist."); - } - DefaultReaderParser<T> parser = new DefaultReaderParser<T>(); + assert file != null : "Given file must not be null"; + assert file.isFile() : "Given file '" + file.getAbsolutePath() + "' is not a file."; + + final DefaultReaderParser<T> parser = new DefaultReaderParser<T>(); final ParserUtilities.Line headerLine = ParserUtilities.getFirstAcceptedLine(file, ExcludeEmptyAndCommentLineFilter.INSTANCE); if (headerLine == null) { - throw new UserFailureException("No header line found in file '" + file.getAbsolutePath() + "'."); + throw new IllegalArgumentException("No header line found in file '" + file.getAbsolutePath() + "'."); } final HeaderLineFilter lineFilter = new HeaderLineFilter(headerLine.number); final String[] tokens = StringUtils.split(headerLine.text, "\t"); @@ -82,15 +78,25 @@ public class TabFileLoader<T> } catch (IOException ex) { throw new EnvironmentFailureException(ex.getMessage()); - } catch (ParseException ex) + } catch (final ParsingException ex) { - throw UserFailureException.fromTemplate("A problem has occurred while parsing line %d of file '%s' [%s].", - ex.getLineNumber(), file, ex.getCause().getMessage()); + throwParsingException(ex, file); + throw new AssertionError("We should never reach this point."); } finally { IOUtils.closeQuietly(reader); } + } + /** + * Throws given <var>ex</var> or translates it into another kind of exception. + * <p> + * Default behavior just throws it. + * </p> + */ + protected void throwParsingException(final ParsingException parsingException, final File file) + { + throw parsingException; } /** @@ -109,8 +115,8 @@ public class TabFileLoader<T> { if (unique.add(token.toLowerCase()) == false) { - throw UserFailureException.fromTemplate("Duplicated column name '%s'.", token); + throw new IllegalArgumentException(String.format("Duplicated column name '%s'.", token)); } } } -} +} \ No newline at end of file diff --git a/common/source/java/ch/systemsx/cisd/common/parser/UnmatchedPropertiesException.java b/common/source/java/ch/systemsx/cisd/common/parser/UnmatchedPropertiesException.java new file mode 100644 index 0000000000000000000000000000000000000000..5b94959bebd81088e661879ed8f686030172337a --- /dev/null +++ b/common/source/java/ch/systemsx/cisd/common/parser/UnmatchedPropertiesException.java @@ -0,0 +1,100 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * 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. + */ + +package ch.systemsx.cisd.common.parser; + +import java.util.Collections; +import java.util.Set; + +/** + * A <code>ParserException</code> extension which signalizes unmatched properties. + * + * @author Christian Ribeaud + */ +public final class UnmatchedPropertiesException extends ParserException +{ + + static final String MESSAGE_FORMAT = "The following header columns are not part of '%s': %s"; + + private static final long serialVersionUID = 1L; + + /** The bean this is set during the parsing process. */ + private final Class<?> beanClass; + + /** The property names found in the parsed file. */ + private final Set<String> allPropertyNames; + + /** The property names found in the bean. */ + private final Set<String> descriptorNames; + + /** The difference of {@link #allPropertyNames} minus {@link #descriptorNames}. */ + private final Set<String> propertyNames; + + UnmatchedPropertiesException(final Class<?> beanClass, final Set<String> allPropertyNames, + final Set<String> descriptorNames, final Set<String> propertyNames) + { + super(createMessage(beanClass, propertyNames)); + assert allPropertyNames != null : "All property names can not be null."; + assert descriptorNames != null : "Descriptor names can not be null."; + this.beanClass = beanClass; + this.allPropertyNames = allPropertyNames; + this.descriptorNames = descriptorNames; + this.propertyNames = propertyNames; + } + + private final static String createMessage(final Class<?> beanClass, final Set<String> propertyNames) + { + assert beanClass != null : "Bean class can not be null."; + assert propertyNames != null : "Property names can not be null."; + assert propertyNames.size() > 0 : "There is no reason to throw this exception."; + return String.format(MESSAGE_FORMAT, beanClass.getSimpleName(), format(propertyNames)); + } + + private final static String format(final Set<String> set) + { + final StringBuilder builder = new StringBuilder(); + for (String s : set) + { + builder.append("'"); + builder.append(s); + builder.append("', "); + } + // Remove trailing ", " + builder.setLength(builder.length() - 2); + return builder.toString(); + } + + public final Class<?> getBeanClass() + { + return beanClass; + } + + public final Set<String> getAllPropertyNames() + { + return allPropertyNames; + } + + public final Set<String> getDescriptorNames() + { + return Collections.unmodifiableSet(descriptorNames); + } + + public final Set<String> getPropertyNames() + { + return propertyNames; + } + +} diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactoryTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactoryTest.java index 23616d625a2813d3fbf91f9ff7fabcd23d297e74..2a90ef6f777258db1c4783ce27eb1f7ae9a7b873 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactoryTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/parser/AbstractParserObjectFactoryTest.java @@ -23,7 +23,6 @@ import org.apache.commons.lang.ArrayUtils; import org.testng.annotations.Test; import ch.systemsx.cisd.common.annotation.Mandatory; -import ch.systemsx.cisd.common.exceptions.UserFailureException; /** * Test cases for corresponding {@link AbstractParserObjectFactory} class. @@ -67,9 +66,10 @@ public final class AbstractParserObjectFactoryTest { new BeanFactory(Bean.class, propertyMapper); fail("Following properties '[isnotin]' are not part of 'Bean'."); - } catch (UserFailureException ex) + } catch (UnmatchedPropertiesException ex) { - assertEquals("The following header columns are not part of 'Bean': 'isnotin'", ex.getMessage()); + assertEquals(String.format(UnmatchedPropertiesException.MESSAGE_FORMAT, "Bean", "'isnotin'"), ex + .getMessage()); } } @@ -85,9 +85,9 @@ public final class AbstractParserObjectFactoryTest { "1. experiment" }; beanFactory.createObject(lineTokens); fail("Field/Property name 'name' is mandatory."); - } catch (UserFailureException ex) + } catch (MandatoryPropertyMissingException ex) { - assertEquals("Field/Property name 'name' is mandatory.", ex.getMessage()); + assertEquals(String.format(MandatoryPropertyMissingException.MESSAGE_FORMAT, "name"), ex.getMessage()); } } @@ -108,12 +108,12 @@ public final class AbstractParserObjectFactoryTest BeanFactory beanFactory = new BeanFactory(Bean.class, propertyMapper); String[] defaultTokens = createDefaultLineTokens(); String[] lineTokens = (String[]) ArrayUtils.remove(defaultTokens, defaultTokens.length - 1); - String msg = String.format("Not enough tokens are available (index: 2, available: 2)", 5, lineTokens.length); + String msg = String.format(IndexOutOfBoundsException.MESSAGE_FORMAT, 2, lineTokens.length); try { beanFactory.createObject(lineTokens); fail(msg); - } catch (UserFailureException ex) + } catch (IndexOutOfBoundsException ex) { assertEquals(msg, ex.getMessage()); } diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/parser/DefaultReaderParserTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/parser/DefaultReaderParserTest.java index 55636f55f3682ff2c6345e9b9cd7b88738e03d45..afb4717ea3ff2e1d9c946b7bf3f07b463b11c216 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/parser/DefaultReaderParserTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/parser/DefaultReaderParserTest.java @@ -83,7 +83,7 @@ public final class DefaultReaderParserTest try { parser.parse(reader, new HeaderLineFilter(2)); - } catch (ParseException ex) + } catch (ParsingException ex) { assertEquals( "Creating an object with following tokens '[Christian, Ribeaud, Kapfrain 2/2, Efringen-Kirchen]' failed.",