| /* |
| |
| Derby - Class org.apache.derby.impl.load.ControlInfo |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You 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 org.apache.derby.impl.load; |
| |
| import java.io.PrintStream; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.util.Date; |
| import java.util.Properties; |
| |
| //read the control file properties. If the passed parameter for control file |
| //name is null, assigns default values to the properties. Also, if the control |
| //file has message property in it, it sends the errors to that file by |
| //redirecting system err to that message file |
| class ControlInfo |
| { |
| |
| static final String ESCAPE = "Escape"; |
| static final String DEFAULT_ESCAPE = "\\"; |
| static final String QUOTE = "Quote"; |
| static final String DEFAULT_QUOTE = "'"; |
| static final String COMMIT_COUNT = "CommitCount"; |
| static final String DEFAULT_COMMIT_COUNT = "0"; |
| static final String START_ROW = "StartRow"; |
| static final String DEFAULT_START_ROW = "1"; |
| static final String STOP_ROW = "StopRow"; |
| static final String DEFAULT_STOP_ROW = "0"; |
| |
| static final String FIELD_SEPARATOR = "FieldSeparator"; |
| static final String DEFAULT_FIELD_SEPARATOR = ","; |
| static final String RECORD_SEPARATOR = "RecordSeparator"; |
| static final String DEFAULT_RECORD_SEPARATOR = System.getProperty("line.separator"); |
| static final String COLUMN_DEFINITION = "ColumnDefinition"; |
| static final String DEFAULT_COLUMN_DEFINITION = "FALSE"; |
| static final String NULL_STRING = "Null"; |
| static final String DEFAULT_NULL_STRING = "NULL"; |
| static final String FORMAT = "Format"; |
| static final String DEFAULT_FORMAT = "ASCII_DELIMITED"; |
| static final String DB2_DELIMITED_FORMAT = "DB2_DELIMITED"; //beetle 5007 |
| static final String FIELD_START_DELIMITER = "FieldStartDelimiter"; |
| static final String DEFAULT_FIELD_START_DELIMITER = "\""; |
| static final String FIELD_END_DELIMITER = "FieldEndDelimiter"; |
| static final String DEFAULT_FIELD_END_DELIMITER = "\""; |
| static final String COLUMN_WIDTHS = "ColumnWidths"; |
| static final String MESSAGE_FILE = "MessageFile"; |
| static final String DEFAULT_VERSION = "1"; |
| static final String VERSION = "Version"; |
| static final String NEWLINE = "\n"; |
| static final String COMMA = ","; |
| static final String SPACE = " "; |
| static final String TAB = "\t"; |
| static final String CR = "\r"; |
| static final String LF = "\n"; |
| static final String CRLF = "\r\n"; |
| static final String LFCR = "\n\r"; |
| static final String FF = "\f"; |
| static final String EMPTY_LINE = "\n\n"; |
| static final String SEMICOLON = ";"; |
| static final String DATA_CODESET = "DataCodeset"; |
| static final String HAS_DELIMETER_AT_END = "HasDelimeterAtEnd"; |
| |
| static final String INTERNAL_NONE = "None"; |
| static final String INTERNAL_TRUE = "True"; |
| static final String INTERNAL_FALSE = "False"; |
| static final String INTERNAL_TAB = "Tab"; |
| static final String INTERNAL_SPACE = "Space"; |
| static final String INTERNAL_CR = "CR"; |
| static final String INTERNAL_LF = "LF"; |
| static final String INTERNAL_CRLF = "CR-LF"; |
| static final String INTERNAL_LFCR = "LF-CR"; |
| static final String INTERNAL_COMMA = "Comma"; |
| static final String INTERNAL_SEMICOLON = "Semicolon"; |
| static final String INTERNAL_NEWLINE = "New Line"; |
| static final String INTERNAL_FF = "FF"; |
| static final String INTERNAL_EMPTY_LINE = "Empty line"; |
| |
| private Properties currentProperties; |
| |
| public ControlInfo() throws Exception { |
| getCurrentProperties(); |
| //the field and record separators can't be subset of each other |
| if (getFieldSeparator().indexOf(getRecordSeparator()) != -1) { |
| throw LoadError.fieldAndRecordSeparatorsSubset(); |
| } |
| } |
| |
| //read the value of a given property |
| String getPropertyValue(String aKey) throws Exception { |
| return getCurrentProperties().getProperty(aKey); |
| } |
| |
| //following are the default values for few of the properties |
| private void loadDefaultValues() { |
| currentProperties = new Properties(); |
| currentProperties.put(FIELD_SEPARATOR, DEFAULT_FIELD_SEPARATOR); |
| currentProperties.put(RECORD_SEPARATOR, DEFAULT_RECORD_SEPARATOR); |
| currentProperties.put(COLUMN_DEFINITION, DEFAULT_COLUMN_DEFINITION); |
| currentProperties.put(NULL_STRING, DEFAULT_NULL_STRING); |
| currentProperties.put(FORMAT, DEFAULT_FORMAT); |
| currentProperties.put(FIELD_START_DELIMITER, DEFAULT_FIELD_START_DELIMITER); |
| currentProperties.put(FIELD_END_DELIMITER, DEFAULT_FIELD_END_DELIMITER); |
| currentProperties.put(VERSION, DEFAULT_VERSION); |
| currentProperties.put(HAS_DELIMETER_AT_END, INTERNAL_FALSE); |
| } |
| |
| //get control file version. |
| String getCurrentVersion() throws Exception { |
| return(DEFAULT_VERSION); |
| } |
| |
| //2 possible formats: fixed and delimited. default is ASCII_DELIMITED |
| String getFormat() throws Exception { |
| return(getCurrentProperties().getProperty(FORMAT)); |
| } |
| |
| //read the column widths property which is comma delimited. |
| //In case of fixed format, if column widths are missing, it will |
| //throw an exception |
| int[] getColumnWidths() { |
| return null; |
| } |
| |
| //default is DEFAULT_FIELD_SEPARATOR |
| String getFieldSeparator() throws Exception { |
| String fieldSeparator = getCurrentProperties().getProperty(FIELD_SEPARATOR); |
| fieldSeparator = mapFromUserFriendlyFieldDelimiters(fieldSeparator); |
| return fieldSeparator; |
| } |
| |
| String getFieldStartDelimiter() throws Exception { |
| return(getCurrentProperties().getProperty(FIELD_START_DELIMITER)); |
| } |
| |
| String getFieldEndDelimiter() throws Exception { |
| return(getCurrentProperties().getProperty(FIELD_END_DELIMITER)); |
| } |
| |
| String getRecordSeparator() throws Exception { |
| String recordSeparator = getCurrentProperties().getProperty(RECORD_SEPARATOR); |
| recordSeparator = mapFromUserFriendlyRecordDelimiters(recordSeparator); |
| return recordSeparator; |
| } |
| |
| //to be used to cover cases where column delimeters are placed at the end of |
| //each column resulting in an extra delimeter at the end of a row. |
| boolean getHasDelimiterAtEnd() throws Exception { |
| String hasDelimeterAtEnd = getCurrentProperties().getProperty(HAS_DELIMETER_AT_END); |
| return hasDelimeterAtEnd.equals(INTERNAL_TRUE); |
| } |
| String getHasDelimeterAtEndString() throws Exception { |
| String hasDelimeterAtEnd = getCurrentProperties().getProperty(HAS_DELIMETER_AT_END); |
| return hasDelimeterAtEnd; |
| } |
| //if at the time of export, the column has null into it, we will spit |
| //nullString in the output file. |
| //If at the time of import, we see nullString for a column, we will |
| //send null as part of resultSet interface |
| String getNullString() throws Exception { |
| return(getCurrentProperties().getProperty(NULL_STRING)); |
| } |
| |
| //for fixed format, get column definitions |
| String getColumnDefinition() throws Exception { |
| return(getCurrentProperties().getProperty(COLUMN_DEFINITION)); |
| } |
| |
| private String mapFromUserFriendlyFieldDelimiters(String aDelimiter) { |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_TAB.toUpperCase(java.util.Locale.ENGLISH))) |
| return TAB; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_SPACE.toUpperCase(java.util.Locale.ENGLISH))) |
| return SPACE; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_CR.toUpperCase(java.util.Locale.ENGLISH))) |
| return CR; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_LF.toUpperCase(java.util.Locale.ENGLISH))) |
| return LF; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_CRLF.toUpperCase(java.util.Locale.ENGLISH))) |
| return CRLF; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_LFCR.toUpperCase(java.util.Locale.ENGLISH))) |
| return LFCR; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_COMMA.toUpperCase(java.util.Locale.ENGLISH))) |
| return COMMA; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_SEMICOLON.toUpperCase(java.util.Locale.ENGLISH))) |
| return SEMICOLON; |
| |
| aDelimiter = commonToFieldAndRecordDelimiters(aDelimiter, "\\n", '\n'); |
| aDelimiter = commonToFieldAndRecordDelimiters(aDelimiter, "\\t", '\t'); |
| aDelimiter = commonToFieldAndRecordDelimiters(aDelimiter, "\\r", '\r'); |
| aDelimiter = commonToFieldAndRecordDelimiters(aDelimiter, "\\f", '\f'); |
| return aDelimiter; |
| } |
| |
| //vjbms: when user types \n in vjbms, it comes as 2 characters \ and n |
| //and not just one character '\n' That's the reason for the following |
| //check. I look for "\n" and replace it with '\n'. Same thing for \t |
| // \r and \f |
| private String commonToFieldAndRecordDelimiters(String aDelimiter, |
| String specialChars, char replacementChar) { |
| String beforeSpecialChars; |
| String afterSpecialChars; |
| int specialCharsPosition; |
| while (aDelimiter.indexOf(specialChars) != -1) { |
| specialCharsPosition = aDelimiter.indexOf(specialChars); |
| beforeSpecialChars = aDelimiter.substring(0,specialCharsPosition); |
| afterSpecialChars = aDelimiter.substring(specialCharsPosition+2); |
| aDelimiter = beforeSpecialChars + replacementChar + afterSpecialChars; |
| } |
| return aDelimiter; |
| } |
| |
| private String mapFromUserFriendlyRecordDelimiters(String aDelimiter) { |
| if (aDelimiter.equals("\n")) |
| aDelimiter = INTERNAL_NEWLINE; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_NEWLINE.toUpperCase(java.util.Locale.ENGLISH))) |
| return NEWLINE; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_CR.toUpperCase(java.util.Locale.ENGLISH))) |
| return CR; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_LF.toUpperCase(java.util.Locale.ENGLISH))) |
| return LF; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_CRLF.toUpperCase(java.util.Locale.ENGLISH))) |
| return CRLF; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_LFCR.toUpperCase(java.util.Locale.ENGLISH))) |
| return LFCR; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_FF.toUpperCase(java.util.Locale.ENGLISH))) |
| return FF; |
| if (aDelimiter.toUpperCase(java.util.Locale.ENGLISH).equals(INTERNAL_EMPTY_LINE.toUpperCase(java.util.Locale.ENGLISH))) |
| return EMPTY_LINE; |
| |
| aDelimiter = commonToFieldAndRecordDelimiters(aDelimiter, "\\n", '\n'); |
| aDelimiter = commonToFieldAndRecordDelimiters(aDelimiter, "\\t", '\t'); |
| aDelimiter = commonToFieldAndRecordDelimiters(aDelimiter, "\\r", '\r'); |
| aDelimiter = commonToFieldAndRecordDelimiters(aDelimiter, "\\f", '\f'); |
| return aDelimiter; |
| } |
| |
| /** |
| * |
| * @return Code set, can return null for use the default code set. |
| * @throws Exception |
| */ |
| String getDataCodeset() throws Exception { |
| return(getCurrentProperties().getProperty(DATA_CODESET)); |
| } |
| |
| |
| /**read the control file properties into a local variable which is used later on |
| *In case there is no control file, read the default values for these properties |
| * @exception Exception if there is an error |
| */ |
| Properties getCurrentProperties() throws Exception{ |
| if (currentProperties == null) { |
| loadDefaultValues(); |
| } |
| return currentProperties; |
| } |
| |
| |
| |
| |
| // Following set routines can be used to change the default properties |
| |
| public void setColumnWidths(String columnWidths) throws Exception { |
| if(columnWidths!=null) |
| currentProperties.setProperty(COLUMN_WIDTHS, columnWidths); |
| } |
| |
| |
| public void setFieldSeparator(String fieldSeperator) throws Exception { |
| if(fieldSeperator!=null) |
| currentProperties.setProperty(FIELD_SEPARATOR, fieldSeperator); |
| } |
| |
| public void setFieldStartDelimiter(String fsdl) throws Exception { |
| if(fsdl!=null) |
| currentProperties.setProperty(FIELD_START_DELIMITER, fsdl); |
| } |
| |
| public void setFieldEndDelimiter(String fedl) throws Exception { |
| if(fedl!=null) |
| currentProperties.setProperty(FIELD_END_DELIMITER, fedl); |
| } |
| |
| public void setRecordSeparator(String recordSeperator) throws Exception { |
| if(recordSeperator!=null) |
| currentProperties.setProperty(RECORD_SEPARATOR, recordSeperator); |
| } |
| |
| public void setHasDelimiterAtEnd(String hasDelimeterAtEnd) throws Exception { |
| if(hasDelimeterAtEnd!=null) |
| currentProperties.setProperty(HAS_DELIMETER_AT_END, hasDelimeterAtEnd); |
| } |
| |
| public void setNullString(String nullString) throws Exception { |
| if(nullString!=null) |
| currentProperties.setProperty(NULL_STRING, nullString); |
| } |
| |
| //for fixed format, set column definitions |
| public void setcolumnDefinition(String columnDefinition) throws Exception { |
| if(columnDefinition!=null) |
| currentProperties.setProperty(COLUMN_DEFINITION, columnDefinition); |
| } |
| |
| |
| public void setDataCodeset(String codeset) throws Exception { |
| if(codeset!=null) |
| currentProperties.setProperty(DATA_CODESET, codeset); |
| } |
| |
| |
| public void setCharacterDelimiter(String charDelimiter) throws Exception{ |
| if(charDelimiter !=null) |
| { |
| setFieldStartDelimiter(charDelimiter) ; |
| setFieldEndDelimiter(charDelimiter); |
| } |
| } |
| |
| |
| |
| public void setControlProperties(String characterDelimiter , |
| String columnDelimiter, |
| String codeset) throws Exception |
| { |
| setCharacterDelimiter(characterDelimiter); |
| setFieldSeparator(columnDelimiter); |
| setDataCodeset(codeset); |
| //check whether the delimiters are valid ones |
| validateDelimiters(); |
| } |
| |
| |
| private void validateDelimiters() throws Exception |
| { |
| |
| |
| char colDel = (getFieldSeparator()).charAt(0); |
| char charDel = (getFieldStartDelimiter()).charAt(0); |
| |
| //The period was specified as a character string delimiter. |
| if(charDel == '.') |
| { |
| throw LoadError.periodAsCharDelimiterNotAllowed(); |
| } |
| |
| |
| // check for the invalid delimiters. A delimiter is not valid it |
| // is used more than once, i.e same character is used |
| // character data delimiter and also as a column delimiter. |
| // An hex decimal character (0-9, a-f ,A-F ) is not a |
| // valid delimiter, because binary data can be imported/exported |
| // as hex string. |
| |
| if(colDel == charDel || |
| colDel == '.' || |
| Character.isSpaceChar(colDel) || |
| Character.isSpaceChar(charDel) || |
| Character.digit(colDel, 16) != -1 || |
| Character.digit(charDel, 16) != -1 ) |
| { |
| throw LoadError.delimitersAreNotMutuallyExclusive(); |
| } |
| |
| } |
| } |
| |