content: /*
   * Copyright (c) 2024, Alibaba Cloud;
   * 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 com.aliyun.dataworks.migrationx.transformer.core.sqoop;
  
  /**
   * Encapsulates a set of delimiters used to encode a record.
   */
  public class DelimiterSet implements Cloneable {
      public static final DelimiterSet DEFAULT_DELIMITERS;
      public static final DelimiterSet HIVE_DELIMITERS;
      public static final DelimiterSet MYSQL_DELIMITERS;
  
      public static final char NULL_CHAR = '\000';
  
      static {
          DEFAULT_DELIMITERS = new DelimiterSet(',', '\n', NULL_CHAR, NULL_CHAR,
              false);
          MYSQL_DELIMITERS = new DelimiterSet(',', '\n', '\'', '\\', false);
          HIVE_DELIMITERS = new DelimiterSet('\001', '\n',
              NULL_CHAR, NULL_CHAR, false);
      }
  
      private char fieldDelim; // fields terminated by this.
      private char recordDelim; // records terminated by this.
  
      // If these next two fields are '\000', then they are ignored.
      private char enclosedBy;
      private char escapedBy;
  
      // If true, then the enclosed-by character is applied to every
      // field, not just ones containing embedded delimiters.
  
      private boolean encloseRequired;
  
      public static final String OUTPUT_FIELD_DELIM_KEY =
          "sqoop.output.field.delim";
      public static final String OUTPUT_RECORD_DELIM_KEY =
          "sqoop.output.record.delim";
      public static final String OUTPUT_ENCLOSED_BY_KEY =
          "sqoop.output.enclosed.by";
      public static final String OUTPUT_ESCAPED_BY_KEY =
          "sqoop.output.escaped.by";
      public static final String OUTPUT_ENCLOSE_REQUIRED_KEY =
          "sqoop.output.enclose.required";
  
      /**
       * Create the input variations for export instead of overloading them.
       */
      public static final String INPUT_FIELD_DELIM_KEY =
          "sqoop.input.field.delim";
      public static final String INPUT_RECORD_DELIM_KEY =
          "sqoop.input.record.delim";
      public static final String INPUT_ENCLOSED_BY_KEY =
          "sqoop.input.enclosed.by";
      public static final String INPUT_ESCAPED_BY_KEY =
          "sqoop.input.escaped.by";
      public static final String INPUT_ENCLOSE_REQUIRED_KEY =
          "sqoop.input.enclose.required";
  
      /**
       * Create a delimiter set with the default delimiters (comma for fields, newline for records).
       */
      public DelimiterSet() {
          this(',', '\n', NULL_CHAR, NULL_CHAR, false);
      }
  
      /**
       * Create a delimiter set with the specified delimiters.
       *
       * @param field             the fields-terminated-by delimiter
       * @param record            the lines-terminated-by delimiter
       * @param enclose           the enclosed-by character
       * @param escape            the escaped-by character
       * @param isEncloseRequired If true, enclosed-by is applied to all fields. If false, only applied to fields that
       *                          embed delimiters.
       */
      public DelimiterSet(char field, char record, char enclose, char escape,
                          boolean isEncloseRequired) {
          this.fieldDelim = field;
          this.recordDelim = record;
          this.enclosedBy = enclose;
          this.escapedBy = escape;
          this.encloseRequired = isEncloseRequired;
      }
  
      /**
       * Identical to clone() but does not throw spurious exceptions.
       *
       * @return a new copy of this same set of delimiters.
       */
      public DelimiterSet copy() {
          try {
              return (DelimiterSet)clone();
          } catch (CloneNotSupportedException cnse) {
              // Should never happen for DelimiterSet.
              return null;
          }
      }
  
      /**
       * Sets the fields-terminated-by character.
       */
      public void setFieldsTerminatedBy(char f) {
          this.fieldDelim = f;
      }
  
      /**
       * @return the fields-terminated-by character.
       */
      public char getFieldsTerminatedBy() {
          return this.fieldDelim;
      }
  
      /**
       * Sets the end-of-record lines-terminated-by character.
       */
      public void setLinesTerminatedBy(char r) {
          this.recordDelim = r;
      }
  
      /**
       * @return the end-of-record (lines-terminated-by) character.
       */
      public char getLinesTerminatedBy() {
          return this.recordDelim;
      }
  
      /**
       * Sets the enclosed-by character.
       *
       * @param e the enclosed-by character, or '\000' for no enclosing character.
       */
      public void setEnclosedBy(char e) {
          this.enclosedBy = e;
      }
  
      /**
       * @return the enclosed-by character, or '\000' for none.
       */
      public char getEnclosedBy() {
          return this.enclosedBy;
      }
  
      /**
       * Sets the escaped-by character.
       *
       * @param e the escaped-by character, or '\000' for no escape character.
       */
      public void setEscapedBy(char e) {
          this.escapedBy = e;
      }
  
      /**
       * @return the escaped-by character, or '\000' for none.
       */
      public char getEscapedBy() {
          return this.escapedBy;
      }
  
      /**
       * Set whether the enclosed-by character must be applied to all fields, or only fields with embedded delimiters.
       */
      public void setEncloseRequired(boolean required) {
          this.encloseRequired = required;
      }
  
      /**
       * @return true if the enclosed-by character must be applied to all fields, or false if it's only used for fields
       * with embedded delimiters.
       */
      public boolean isEncloseRequired() {
          return this.encloseRequired;
      }
  
      @Override
      /**
       * @return a string representation of the delimiters.
       */
      public String toString() {
          return "fields=" + this.fieldDelim
              + " records=" + this.recordDelim
              + " escape=" + this.escapedBy
              + " enclose=" + this.enclosedBy
              + " required=" + this.encloseRequired;
      }
  
      /**
       * Format this set of delimiters as a call to the constructor for this object, that would generate identical
       * delimiters.
       *
       * @return a String that can be embedded in generated code that provides this set of delimiters.
       */
      public String formatConstructor() {
          return "new DelimiterSet((char) " + (int)this.fieldDelim + ", "
              + "(char) " + (int)this.recordDelim + ", "
              + "(char) " + (int)this.enclosedBy + ", "
              + "(char) " + (int)this.escapedBy + ", "
              + this.encloseRequired + ")";
      }
  
      @Override
      /**
       * @return a hash code for this set of delimiters.
       */
      public int hashCode() {
          return (int)this.fieldDelim
              + (((int)this.recordDelim) << 4)
              + (((int)this.escapedBy) << 8)
              + (((int)this.enclosedBy) << 12)
              + (((int)this.recordDelim) << 16)
              + (this.encloseRequired ? 0xFEFE : 0x7070);
      }
  
      @Override
      /**
       * @return true if this delimiter set is the same as another set of
       * delimiters.
       */
      public boolean equals(Object other) {
          if (null == other) {
              return false;
          } else if (!other.getClass().equals(getClass())) {
              return false;
          }
  
          DelimiterSet set = (DelimiterSet)other;
          return this.fieldDelim == set.fieldDelim
              && this.recordDelim == set.recordDelim
              && this.escapedBy == set.escapedBy
              && this.enclosedBy == set.enclosedBy
              && this.encloseRequired == set.encloseRequired;
      }
  
      @Override
      /**
       * @return a new copy of this same set of delimiters.
       */
      public Object clone() throws CloneNotSupportedException {
          return super.clone();
      }
  }