diff options
author | James Ahlborn <jtahlborn@yahoo.com> | 2014-03-20 04:17:37 +0000 |
---|---|---|
committer | James Ahlborn <jtahlborn@yahoo.com> | 2014-03-20 04:17:37 +0000 |
commit | f73e6c33c75c8a0ba444ff200fdc234b59e59027 (patch) | |
tree | 9fb6c4cc452ec52b4945cf584800f7b068f26daf /src/main | |
parent | a8a31e67bc8ec31c6377c5f38299314721a5c0fb (diff) | |
download | jackcess-f73e6c33c75c8a0ba444ff200fdc234b59e59027.tar.gz jackcess-f73e6c33c75c8a0ba444ff200fdc234b59e59027.zip |
add initial ColumnValidator support
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@849 f203690c-595d-4dc9-a70b-905162fa7fd2
Diffstat (limited to 'src/main')
9 files changed, 286 insertions, 46 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/Database.java b/src/main/java/com/healthmarketscience/jackcess/Database.java index ab4b7ca..4e9d136 100644 --- a/src/main/java/com/healthmarketscience/jackcess/Database.java +++ b/src/main/java/com/healthmarketscience/jackcess/Database.java @@ -33,6 +33,7 @@ import java.util.TimeZone; import com.healthmarketscience.jackcess.query.Query; import com.healthmarketscience.jackcess.impl.DatabaseImpl; +import com.healthmarketscience.jackcess.util.ColumnValidatorFactory; import com.healthmarketscience.jackcess.util.ErrorHandler; import com.healthmarketscience.jackcess.util.LinkResolver; @@ -366,7 +367,7 @@ public interface Database extends Iterable<Table>, Closeable, Flushable public void setColumnOrder(Table.ColumnOrder newColumnOrder); /** - * Gets currently foreign-key enforcement policy. + * Gets current foreign-key enforcement policy. * @usage _intermediate_method_ */ public boolean isEnforceForeignKeys(); @@ -379,6 +380,19 @@ public interface Database extends Iterable<Table>, Closeable, Flushable public void setEnforceForeignKeys(Boolean newEnforceForeignKeys); /** + * Gets currently configured ColumnValidatorFactory (always non-{@code null}). + * @usage _intermediate_method_ + */ + public ColumnValidatorFactory getColumnValidatorFactory(); + + /** + * Sets a new ColumnValidatorFactory. If {@code null}, resets to the + * default value. + * @usage _intermediate_method_ + */ + public void setColumnValidatorFactory(ColumnValidatorFactory newFactory); + + /** * Returns the FileFormat of this database (which may involve inspecting the * database itself). * @throws IllegalStateException if the file format cannot be determined diff --git a/src/main/java/com/healthmarketscience/jackcess/Table.java b/src/main/java/com/healthmarketscience/jackcess/Table.java index 0765e1f..16b559f 100644 --- a/src/main/java/com/healthmarketscience/jackcess/Table.java +++ b/src/main/java/com/healthmarketscience/jackcess/Table.java @@ -71,6 +71,12 @@ public interface Table extends Iterable<Row> public boolean isHidden(); /** + * Whether or not this table is a system (internal) table. + * @usage _general_method_ + */ + public boolean isSystem(); + + /** * @usage _general_method_ */ public int getColumnCount(); diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java index ae68a17..b2a1ffc 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java @@ -65,6 +65,8 @@ import com.healthmarketscience.jackcess.impl.scsu.Compress; import com.healthmarketscience.jackcess.impl.scsu.EndOfInputException; import com.healthmarketscience.jackcess.impl.scsu.Expand; import com.healthmarketscience.jackcess.impl.scsu.IllegalInputException; +import com.healthmarketscience.jackcess.util.ColumnValidator; +import com.healthmarketscience.jackcess.util.SimpleColumnValidator; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -221,6 +223,8 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> { private PropertyMap _props; /** Holds additional info for writing long values */ private LongValueBufferHolder _lvalBufferH; + /** Validator for writing new values */ + private ColumnValidator _validator = SimpleColumnValidator.INSTANCE; /** * @usage _advanced_method_ @@ -509,6 +513,18 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> { public ComplexColumnInfo<? extends ComplexValue> getComplexInfo() { return _complexInfo; } + + public ColumnValidator getColumnValidator() { + return _validator; + } + + public void setColumnValidator(ColumnValidator newValidator) { + if(newValidator == null) { + newValidator = getDatabase().getColumnValidatorFactory() + .createValidator(this); + } + _validator = newValidator; + } private void setUnknownDataType(byte type) { // slight hack, stash the original type in the _scale @@ -1198,6 +1214,14 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> { } /** + * Passes the given obj through the currently configured validator for this + * column and returns the result. + */ + public Object validate(Object obj) throws IOException { + return _validator.validate(this, obj); + } + + /** * Serialize an Object into a raw byte value for this column in little * endian order * @param obj Object to serialize diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java index 810868c..8ddc4a0 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java @@ -72,8 +72,10 @@ import com.healthmarketscience.jackcess.Table; import com.healthmarketscience.jackcess.impl.query.QueryImpl; import com.healthmarketscience.jackcess.query.Query; import com.healthmarketscience.jackcess.util.CaseInsensitiveColumnMatcher; +import com.healthmarketscience.jackcess.util.ColumnValidatorFactory; import com.healthmarketscience.jackcess.util.ErrorHandler; import com.healthmarketscience.jackcess.util.LinkResolver; +import com.healthmarketscience.jackcess.util.SimpleColumnValidatorFactory; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -303,6 +305,8 @@ public class DatabaseImpl implements Database private Table.ColumnOrder _columnOrder; /** whether or not enforcement of foreign-keys is enabled */ private boolean _enforceForeignKeys; + /** factory for ColumnValidators */ + private ColumnValidatorFactory _validatorFactory = SimpleColumnValidatorFactory.INSTANCE; /** cache of in-use tables */ private final TableCache _tableCache = new TableCache(); /** handler for reading/writing properteies */ @@ -638,6 +642,17 @@ public class DatabaseImpl implements Database _enforceForeignKeys = newEnforceForeignKeys; } + public ColumnValidatorFactory getColumnValidatorFactory() { + return _validatorFactory; + } + + public void setColumnValidatorFactory(ColumnValidatorFactory newFactory) { + if(newFactory == null) { + newFactory = SimpleColumnValidatorFactory.INSTANCE; + } + _validatorFactory = newFactory; + } + /** * @usage _advanced_method_ */ diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java index 15dfaec..f52bb1d 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java @@ -303,6 +303,11 @@ public class TableImpl implements Table } _fkEnforcer = new FKEnforcer(this); + + // after fully constructed, allow column validator to be configured + for(ColumnImpl col : _columns) { + col.setColumnValidator(null); + } } public String getName() { @@ -313,6 +318,10 @@ public class TableImpl implements Table return((_flags & DatabaseImpl.HIDDEN_OBJECT_FLAG) != 0); } + public boolean isSystem() { + return(_tableType != TYPE_USER); + } + /** * @usage _advanced_method_ */ @@ -1528,8 +1537,35 @@ public class TableImpl implements Table dupeRows.set(i, row); } - // fill in autonumbers - handleAutoNumbersForAdd(row); + // handle various value massaging activities + Object complexAutoNumber = null; + for(ColumnImpl column : _columns) { + + Object rowValue = null; + if(column.isAutoNumber()) { + + // fill in autonumbers, ignore given row value, use next + // autonumber + ColumnImpl.AutoNumberGenerator autoNumGen = + column.getAutoNumberGenerator(); + if(autoNumGen.getType() != DataType.COMPLEX_TYPE) { + rowValue = autoNumGen.getNext(null); + } else { + // complex type auto numbers are shared across all complex + // columns in the row + complexAutoNumber = autoNumGen.getNext(complexAutoNumber); + rowValue = complexAutoNumber; + } + + } else { + + // pass input value through column validator + rowValue = column.validate(column.getRowValue(row)); + } + + column.setRowValue(row, rowValue); + } + ++autoNumAssignCount; // write the row of data to a temporary buffer @@ -1732,20 +1768,38 @@ public class TableImpl implements Table Map<ColumnImpl,byte[]> keepRawVarValues = (!_varColumns.isEmpty() ? new HashMap<ColumnImpl,byte[]>() : null); + // handle various value massaging activities for(ColumnImpl column : _columns) { - if(_autoNumColumns.contains(column)) { + + Object rowValue = null; + if(column.isAutoNumber()) { + // fill in any auto-numbers (we don't allow autonumber values to be // modified) - column.setRowValue(row, getRowColumn(getFormat(), rowBuffer, column, - rowState, null)); - } else if(column.getRowValue(row) == Column.KEEP_VALUE) { - // fill in any "keep value" fields - column.setRowValue(row, getRowColumn(getFormat(), rowBuffer, column, - rowState, keepRawVarValues)); - } else if(_indexColumns.contains(column)) { - // read row value to help update indexes - getRowColumn(getFormat(), rowBuffer, column, rowState, null); + rowValue = getRowColumn(getFormat(), rowBuffer, column, rowState, null); + + } else { + + rowValue = column.getRowValue(row); + if(rowValue == Column.KEEP_VALUE) { + + // fill in any "keep value" fields (restore old value) + rowValue = getRowColumn(getFormat(), rowBuffer, column, rowState, + keepRawVarValues); + + } else { + + if(_indexColumns.contains(column)) { + // read (old) row value to help update indexes + getRowColumn(getFormat(), rowBuffer, column, rowState, null); + } + + // pass input value through column validator + rowValue = column.validate(rowValue); + } } + + column.setRowValue(row, rowValue); } // generate new row bytes @@ -1969,10 +2023,7 @@ public class TableImpl implements Table return dataPage; } - /** - * @usage _advanced_method_ - */ - public ByteBuffer createRow(Object[] rowArray, ByteBuffer buffer) + protected ByteBuffer createRow(Object[] rowArray, ByteBuffer buffer) throws IOException { return createRow(rowArray, buffer, 0, @@ -2133,33 +2184,6 @@ public class TableImpl implements Table } /** - * Fill in all autonumber column values. - */ - private void handleAutoNumbersForAdd(Object[] row) - throws IOException - { - if(_autoNumColumns.isEmpty()) { - return; - } - - Object complexAutoNumber = null; - for(ColumnImpl col : _autoNumColumns) { - // ignore given row value, use next autonumber - ColumnImpl.AutoNumberGenerator autoNumGen = col.getAutoNumberGenerator(); - Object rowValue = null; - if(autoNumGen.getType() != DataType.COMPLEX_TYPE) { - rowValue = autoNumGen.getNext(null); - } else { - // complex type auto numbers are shared across all complex columns - // in the row - complexAutoNumber = autoNumGen.getNext(complexAutoNumber); - rowValue = complexAutoNumber; - } - col.setRowValue(row, rowValue); - } - } - - /** * Restores all autonumber column values from a failed add row. */ private void restoreAutoNumbersFromAdd(Object[] row) @@ -2224,8 +2248,7 @@ public class TableImpl implements Table @Override public String toString() { return CustomToStringStyle.builder(this) - .append("type", (_tableType + - ((_tableType == TYPE_USER) ? " (USER)" : " (SYSTEM)"))) + .append("type", (_tableType + (!isSystem() ? " (USER)" : " (SYSTEM)"))) .append("name", _name) .append("rowCount", _rowCount) .append("columnCount", _columns.size()) diff --git a/src/main/java/com/healthmarketscience/jackcess/util/ColumnValidator.java b/src/main/java/com/healthmarketscience/jackcess/util/ColumnValidator.java new file mode 100644 index 0000000..50c8916 --- /dev/null +++ b/src/main/java/com/healthmarketscience/jackcess/util/ColumnValidator.java @@ -0,0 +1,41 @@ +/* +Copyright (c) 2014 James Ahlborn + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +USA + +*/ + +package com.healthmarketscience.jackcess.util; + +import java.io.IOException; + +import com.healthmarketscience.jackcess.Column; + +/** + * Interface which allows for data manipulation/validation as values are being + * inserted into a database. + * + * @author James Ahlborn + */ +public interface ColumnValidator +{ + /** + * Validates and/or manipulates the given potential new value for the given + * column. This method may return an entirely different value or throw an + * exception if the input value is not valid. + */ + public Object validate(Column col, Object val) throws IOException; +} diff --git a/src/main/java/com/healthmarketscience/jackcess/util/ColumnValidatorFactory.java b/src/main/java/com/healthmarketscience/jackcess/util/ColumnValidatorFactory.java new file mode 100644 index 0000000..3a8a323 --- /dev/null +++ b/src/main/java/com/healthmarketscience/jackcess/util/ColumnValidatorFactory.java @@ -0,0 +1,38 @@ +/* +Copyright (c) 2014 James Ahlborn + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +USA + +*/ + +package com.healthmarketscience.jackcess.util; + +import com.healthmarketscience.jackcess.Column; + +/** + * Factory which generates appropriate ColumnValidators when Column instances + * are created. + * + * @author James Ahlborn + */ +public interface ColumnValidatorFactory +{ + /** + * Returns a ColumnValidator instance for the given column, must be + * non-{@code null}. + */ + public ColumnValidator createValidator(Column col); +} diff --git a/src/main/java/com/healthmarketscience/jackcess/util/SimpleColumnValidator.java b/src/main/java/com/healthmarketscience/jackcess/util/SimpleColumnValidator.java new file mode 100644 index 0000000..7dd8817 --- /dev/null +++ b/src/main/java/com/healthmarketscience/jackcess/util/SimpleColumnValidator.java @@ -0,0 +1,40 @@ +/* +Copyright (c) 2014 James Ahlborn + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +USA + +*/ + +package com.healthmarketscience.jackcess.util; + +import java.io.IOException; + +import com.healthmarketscience.jackcess.Column; + +/** + * Simple concrete implementation of ColumnValidator which simply returns the + * given value. + * + * @author James Ahlborn + */ +public class SimpleColumnValidator implements ColumnValidator +{ + public static final SimpleColumnValidator INSTANCE = new SimpleColumnValidator(); + + public Object validate(Column col, Object val) throws IOException { + return val; + } +} diff --git a/src/main/java/com/healthmarketscience/jackcess/util/SimpleColumnValidatorFactory.java b/src/main/java/com/healthmarketscience/jackcess/util/SimpleColumnValidatorFactory.java new file mode 100644 index 0000000..367f8c7 --- /dev/null +++ b/src/main/java/com/healthmarketscience/jackcess/util/SimpleColumnValidatorFactory.java @@ -0,0 +1,39 @@ +/* +Copyright (c) 2014 James Ahlborn + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +USA + +*/ + +package com.healthmarketscience.jackcess.util; + +import com.healthmarketscience.jackcess.Column; + +/** + * Simple concrete implementation of ColumnValidatorFactory which returns + * {@link SimpleColumnValidator.INSTANCE} for all columns. + * + * @author James Ahlborn + */ +public class SimpleColumnValidatorFactory implements ColumnValidatorFactory +{ + public static final SimpleColumnValidatorFactory INSTANCE = + new SimpleColumnValidatorFactory(); + + public ColumnValidator createValidator(Column col) { + return SimpleColumnValidator.INSTANCE; + } +} |