Fix Clob,Blob read and writes 24/88024/1
authorstatta <statta@research.att.com>
Fri, 17 May 2019 18:55:18 +0000 (14:55 -0400)
committerstatta <statta@research.att.com>
Fri, 17 May 2019 18:58:50 +0000 (14:58 -0400)
Issue-ID: MUSIC-388

Change-Id: I3ddd84f097231a21423325b04c34a4a90e4ea0e0
Signed-off-by: statta <statta@research.att.com>
mdbc-server/src/main/java/org/apache/calcite/avatica/AvaticaSite.java [new file with mode: 0644]
mdbc-server/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java [new file with mode: 0644]
mdbc-server/src/main/java/org/onap/music/logging/EELFLoggerDelegate.java
mdbc-server/src/main/resources/logback.xml

diff --git a/mdbc-server/src/main/java/org/apache/calcite/avatica/AvaticaSite.java b/mdbc-server/src/main/java/org/apache/calcite/avatica/AvaticaSite.java
new file mode 100644 (file)
index 0000000..5fd4e69
--- /dev/null
@@ -0,0 +1,612 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to you under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.calcite.avatica;\r
+\r
+import org.apache.calcite.avatica.remote.TypedValue;\r
+import org.apache.calcite.avatica.util.Cursor;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.Reader;\r
+import java.math.BigDecimal;\r
+import java.math.BigInteger;\r
+import java.net.URL;\r
+import java.nio.charset.StandardCharsets;\r
+import java.sql.Array;\r
+import java.sql.Blob;\r
+import java.sql.Clob;\r
+import java.sql.Date;\r
+import java.sql.NClob;\r
+import java.sql.Ref;\r
+import java.sql.RowId;\r
+import java.sql.SQLException;\r
+import java.sql.SQLXML;\r
+import java.sql.Time;\r
+import java.sql.Timestamp;\r
+import java.sql.Types;\r
+import java.util.Calendar;\r
+\r
+/**\r
+ * A location that a value can be written to or read from.\r
+ */\r
+public class AvaticaSite {\r
+  final AvaticaParameter parameter;\r
+\r
+  /** Calendar is not thread-safe. But calendar is only used from within one\r
+   * thread, and we have to trust that clients are not modifying calendars\r
+   * that they pass to us in a method such as\r
+   * {@link java.sql.PreparedStatement#setTime(int, Time, Calendar)}, so we do\r
+   * not need to synchronize access. */\r
+  final Calendar calendar;\r
+  private final int index;\r
+  final TypedValue[] slots;\r
+\r
+  /** Value that means the parameter has been set to null.\r
+   * If value is null, parameter has not been set. */\r
+  public static final Object DUMMY_VALUE = Dummy.INSTANCE;\r
+\r
+  public AvaticaSite(AvaticaParameter parameter, Calendar calendar, int index,\r
+      TypedValue[] slots) {\r
+    assert calendar != null;\r
+    assert parameter != null;\r
+    assert slots != null;\r
+    this.parameter = parameter;\r
+    this.calendar = calendar;\r
+    this.index = index;\r
+    this.slots = slots;\r
+  }\r
+\r
+  private TypedValue wrap(ColumnMetaData.Rep rep, Object o,\r
+      Calendar calendar) {\r
+    return TypedValue.ofJdbc(rep, o, calendar);\r
+  }\r
+\r
+  private TypedValue wrap(ColumnMetaData.Rep rep, Object o) {\r
+    return TypedValue.ofJdbc(rep, o, calendar);\r
+  }\r
+\r
+  public boolean isSet(int index) {\r
+    return slots[index] != null;\r
+  }\r
+\r
+  public void setByte(byte o) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.BYTE, o);\r
+  }\r
+\r
+  public void setChar(char o) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.CHARACTER, o);\r
+  }\r
+\r
+  public void setShort(short o) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.SHORT, o);\r
+  }\r
+\r
+  public void setInt(int o) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.INTEGER, o);\r
+  }\r
+\r
+  public void setLong(long o) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.LONG, o);\r
+  }\r
+\r
+  public void setBoolean(boolean o) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.BOOLEAN, o);\r
+  }\r
+\r
+  public void setRowId(RowId x) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, x);\r
+  }\r
+\r
+  public void setNString(String o) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.STRING, o);\r
+  }\r
+\r
+  public void setNCharacterStream(Reader value, long length) {\r
+  }\r
+\r
+  public void setNClob(NClob value) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, value);\r
+  }\r
+\r
+  public void setClob(Reader reader, long length) {\r
+  }\r
+\r
+  public void setBlob(InputStream inputStream, long length) {\r
+  }\r
+\r
+  public void setNClob(Reader reader, long length) {\r
+  }\r
+\r
+  public void setSQLXML(SQLXML xmlObject) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, xmlObject);\r
+  }\r
+\r
+  public void setAsciiStream(InputStream x, long length) {\r
+  }\r
+\r
+  public void setBinaryStream(InputStream x, long length) {\r
+  }\r
+\r
+  public void setCharacterStream(Reader reader, long length) {\r
+  }\r
+\r
+  public void setAsciiStream(InputStream x) {\r
+  }\r
+\r
+  public void setBinaryStream(InputStream x) {\r
+  }\r
+\r
+  public void setCharacterStream(Reader reader) {\r
+  }\r
+\r
+  public void setNCharacterStream(Reader value) {\r
+  }\r
+\r
+  public void setClob(Reader reader) {\r
+  }\r
+  \r
+  public void setClob(InputStream inputStream) {\r
+  }\r
+\r
+  public void setBlob(InputStream inputStream) {\r
+  }\r
+\r
+  public void setNClob(Reader reader) {\r
+  }\r
+\r
+  public void setUnicodeStream(InputStream x, int length) {\r
+  }\r
+\r
+  public void setFloat(float x) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.FLOAT, x);\r
+  }\r
+\r
+  public void setDouble(double x) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.DOUBLE, x);\r
+  }\r
+\r
+  public void setBigDecimal(BigDecimal x) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.NUMBER, x);\r
+  }\r
+\r
+  public void setString(String x) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.STRING, x);\r
+  }\r
+\r
+  public void setBytes(byte[] x) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.BYTE_STRING, x);\r
+  }\r
+\r
+  public void setTimestamp(Timestamp x, Calendar calendar) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_TIMESTAMP, x, calendar);\r
+  }\r
+\r
+  public void setTime(Time x, Calendar calendar) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_TIME, x, calendar);\r
+  }\r
+\r
+  public void setDate(Date x, Calendar calendar) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_DATE, x, calendar);\r
+  }\r
+\r
+  public void setObject(Object x, int targetSqlType) {\r
+    if (x == null || Types.NULL == targetSqlType) {\r
+      setNull(targetSqlType);\r
+      return;\r
+    }\r
+    switch (targetSqlType) {\r
+    case Types.CLOB:\r
+       if (x instanceof Clob) {\r
+            setClob((Clob) x);\r
+            break;\r
+          } else if (x instanceof InputStream) {\r
+            setClob((InputStream) x);\r
+          }\r
+          throw unsupportedCast(x.getClass(), Blob.class);\r
+    case Types.DATALINK:\r
+    case Types.NCLOB:\r
+    case Types.OTHER:\r
+    case Types.REF:\r
+    case Types.SQLXML:\r
+    case Types.STRUCT:\r
+      throw notImplemented();\r
+    case Types.ARRAY:\r
+      setArray(toArray(x));\r
+      break;\r
+    case Types.BIGINT:\r
+      setLong(toLong(x));\r
+      break;\r
+    case Types.BINARY:\r
+    case Types.LONGVARBINARY:\r
+    case Types.VARBINARY:\r
+      setBytes(toBytes(x));\r
+      break;\r
+    case Types.BIT:\r
+    case Types.BOOLEAN:\r
+      setBoolean(toBoolean(x));\r
+      break;\r
+    case Types.BLOB:\r
+      if (x instanceof Blob) {\r
+        setBlob((Blob) x);\r
+        break;\r
+      } else if (x instanceof InputStream) {\r
+        setBlob((InputStream) x);\r
+      }\r
+      throw unsupportedCast(x.getClass(), Blob.class);\r
+    case Types.DATE:\r
+      setDate(toDate(x), calendar);\r
+      break;\r
+    case Types.DECIMAL:\r
+    case Types.NUMERIC:\r
+      setBigDecimal(toBigDecimal(x));\r
+      break;\r
+    case Types.DISTINCT:\r
+      throw notImplemented();\r
+    case Types.DOUBLE:\r
+    case Types.FLOAT: // yes really; SQL FLOAT is up to 8 bytes\r
+      setDouble(toDouble(x));\r
+      break;\r
+    case Types.INTEGER:\r
+      setInt(toInt(x));\r
+      break;\r
+    case Types.JAVA_OBJECT:\r
+      setObject(x);\r
+      break;\r
+    case Types.LONGNVARCHAR:\r
+    case Types.LONGVARCHAR:\r
+    case Types.NVARCHAR:\r
+    case Types.VARCHAR:\r
+    case Types.CHAR:\r
+    case Types.NCHAR:\r
+      setString(toString(x));\r
+      break;\r
+    case Types.REAL:\r
+      setFloat(toFloat(x));\r
+      break;\r
+    case Types.ROWID:\r
+      if (x instanceof RowId) {\r
+        setRowId((RowId) x);\r
+        break;\r
+      }\r
+      throw unsupportedCast(x.getClass(), RowId.class);\r
+    case Types.SMALLINT:\r
+      setShort(toShort(x));\r
+      break;\r
+    case Types.TIME:\r
+      setTime(toTime(x), calendar);\r
+      break;\r
+    case Types.TIMESTAMP:\r
+      setTimestamp(toTimestamp(x), calendar);\r
+      break;\r
+    case Types.TINYINT:\r
+      setByte(toByte(x));\r
+      break;\r
+    default:\r
+      throw notImplemented();\r
+    }\r
+  }\r
+\r
+  /** Similar logic to {@link #setObject}. */\r
+  public static Object get(Cursor.Accessor accessor, int targetSqlType,\r
+      Calendar localCalendar) throws SQLException {\r
+    switch (targetSqlType) {\r
+    case Types.CLOB:\r
+        return accessor.getClob();\r
+    case Types.DATALINK:\r
+    case Types.NCLOB:\r
+    case Types.REF:\r
+    case Types.SQLXML:\r
+    case Types.STRUCT:\r
+      throw notImplemented();\r
+    case Types.ARRAY:\r
+      return accessor.getArray();\r
+    case Types.BIGINT:\r
+      final long aLong = accessor.getLong();\r
+      if (aLong == 0 && accessor.wasNull()) {\r
+        return null;\r
+      }\r
+      return aLong;\r
+    case Types.BINARY:\r
+    case Types.LONGVARBINARY:\r
+    case Types.VARBINARY:\r
+      return accessor.getBytes();\r
+    case Types.BIT:\r
+    case Types.BOOLEAN:\r
+      final boolean aBoolean = accessor.getBoolean();\r
+      if (!aBoolean && accessor.wasNull()) {\r
+        return null;\r
+      }\r
+      return aBoolean;\r
+    case Types.BLOB:\r
+      return accessor.getBlob();\r
+    case Types.DATE:\r
+      return accessor.getDate(localCalendar);\r
+    case Types.DECIMAL:\r
+    case Types.NUMERIC:\r
+      return accessor.getBigDecimal();\r
+    case Types.DISTINCT:\r
+      throw notImplemented();\r
+    case Types.DOUBLE:\r
+    case Types.FLOAT: // yes really; SQL FLOAT is up to 8 bytes\r
+      final double aDouble = accessor.getDouble();\r
+      if (aDouble == 0 && accessor.wasNull()) {\r
+        return null;\r
+      }\r
+      return aDouble;\r
+    case Types.INTEGER:\r
+      final int anInt = accessor.getInt();\r
+      if (anInt == 0 && accessor.wasNull()) {\r
+        return null;\r
+      }\r
+      return anInt;\r
+    case Types.JAVA_OBJECT:\r
+    case Types.OTHER:\r
+      return accessor.getObject();\r
+    case Types.LONGNVARCHAR:\r
+    case Types.LONGVARCHAR:\r
+    case Types.NVARCHAR:\r
+    case Types.VARCHAR:\r
+    case Types.CHAR:\r
+    case Types.NCHAR:\r
+      return accessor.getString();\r
+    case Types.REAL:\r
+      final float aFloat = accessor.getFloat();\r
+      if (aFloat == 0 && accessor.wasNull()) {\r
+        return null;\r
+      }\r
+      return aFloat;\r
+    case Types.ROWID:\r
+      throw notImplemented();\r
+    case Types.SMALLINT:\r
+      final short aShort = accessor.getShort();\r
+      if (aShort == 0 && accessor.wasNull()) {\r
+        return null;\r
+      }\r
+      return aShort;\r
+    case Types.TIME:\r
+      return accessor.getTime(localCalendar);\r
+    case Types.TIMESTAMP:\r
+      return accessor.getTimestamp(localCalendar);\r
+    case Types.TINYINT:\r
+      final byte aByte = accessor.getByte();\r
+      if (aByte == 0 && accessor.wasNull()) {\r
+        return null;\r
+      }\r
+      return aByte;\r
+    default:\r
+      throw notImplemented();\r
+    }\r
+  }\r
+\r
+  public void setObject(Object x) {\r
+    slots[index] = TypedValue.ofJdbc(x, calendar);\r
+  }\r
+\r
+  public void setNull(int sqlType) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, null);\r
+  }\r
+\r
+  public void setRef(Ref x) {\r
+  }\r
+\r
+  public void setBlob(Blob x) {\r
+     InputStream iStream;\r
+    try {\r
+        iStream = x.getBinaryStream();\r
+        int length =0;\r
+        while(iStream.read() != -1)\r
+            length ++;\r
+         setBytes(x.getBytes(1, length));\r
+         \r
+    } catch (SQLException | IOException e) {\r
+        throw new RuntimeException(e);\r
+    }\r
+    \r
+  }\r
+\r
+  public void setClob(Clob x) {\r
+  }\r
+\r
+  public void setArray(Array x) {\r
+    slots[index] = wrap(ColumnMetaData.Rep.ARRAY, x);\r
+  }\r
+\r
+  public void setNull(int sqlType, String typeName) {\r
+  }\r
+\r
+  public void setURL(URL x) {\r
+  }\r
+\r
+  public void setObject(Object x, int targetSqlType,\r
+      int scaleOrLength) {\r
+  }\r
+\r
+  private static RuntimeException unsupportedCast(Class<?> from, Class<?> to) {\r
+    return new UnsupportedOperationException("Cannot convert from "\r
+        + from.getCanonicalName() + " to " + to.getCanonicalName());\r
+  }\r
+\r
+  private static RuntimeException notImplemented() {\r
+    return new RuntimeException("not implemented");\r
+  }\r
+\r
+  private static Array toArray(Object x) {\r
+    if (x instanceof Array) {\r
+      return (Array) x;\r
+    }\r
+    throw unsupportedCast(x.getClass(), Array.class);\r
+  }\r
+\r
+  public static BigDecimal toBigDecimal(Object x) {\r
+    if (x instanceof BigDecimal) {\r
+      return (BigDecimal) x;\r
+    } else if (x instanceof BigInteger) {\r
+      return new BigDecimal((BigInteger) x);\r
+    } else if (x instanceof Number) {\r
+      if (x instanceof Double || x instanceof Float) {\r
+        return new BigDecimal(((Number) x).doubleValue());\r
+      } else {\r
+        return new BigDecimal(((Number) x).longValue());\r
+      }\r
+    } else if (x instanceof Boolean) {\r
+      return (Boolean) x ? BigDecimal.ONE : BigDecimal.ZERO;\r
+    } else if (x instanceof String) {\r
+      return new BigDecimal((String) x);\r
+    }\r
+    throw unsupportedCast(x.getClass(), BigDecimal.class);\r
+  }\r
+\r
+  private static boolean toBoolean(Object x) {\r
+    if (x instanceof Boolean) {\r
+      return (Boolean) x;\r
+    } else if (x instanceof Number) {\r
+      return ((Number) x).intValue() != 0;\r
+    } else if (x instanceof String) {\r
+      String s = (String) x;\r
+      if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("yes")) {\r
+        return true;\r
+      } else if (s.equalsIgnoreCase("false") || s.equalsIgnoreCase("no")) {\r
+        return false;\r
+      }\r
+    }\r
+    throw unsupportedCast(x.getClass(), Boolean.TYPE);\r
+  }\r
+\r
+  private static byte toByte(Object x) {\r
+    if (x instanceof Number) {\r
+      return ((Number) x).byteValue();\r
+    } else if (x instanceof Boolean) {\r
+      return (Boolean) x ? (byte) 1 : (byte) 0;\r
+    } else if (x instanceof String) {\r
+      return Byte.parseByte((String) x);\r
+    } else {\r
+      throw unsupportedCast(x.getClass(), Byte.TYPE);\r
+    }\r
+  }\r
+\r
+  private static byte[] toBytes(Object x) {\r
+    if (x instanceof byte[]) {\r
+      return (byte[]) x;\r
+    }\r
+    if (x instanceof String) {\r
+      return ((String) x).getBytes(StandardCharsets.UTF_8);\r
+    }\r
+    throw unsupportedCast(x.getClass(), byte[].class);\r
+  }\r
+\r
+  private static Date toDate(Object x) {\r
+    if (x instanceof String) {\r
+      return Date.valueOf((String) x);\r
+    }\r
+    return new Date(toLong(x));\r
+  }\r
+\r
+  private static Time toTime(Object x) {\r
+    if (x instanceof String) {\r
+      return Time.valueOf((String) x);\r
+    }\r
+    return new Time(toLong(x));\r
+  }\r
+\r
+  private static Timestamp toTimestamp(Object x) {\r
+    if (x instanceof String) {\r
+      return Timestamp.valueOf((String) x);\r
+    }\r
+    return new Timestamp(toLong(x));\r
+  }\r
+\r
+  private static double toDouble(Object x) {\r
+    if (x instanceof Number) {\r
+      return ((Number) x).doubleValue();\r
+    } else if (x instanceof Boolean) {\r
+      return (Boolean) x ? 1D : 0D;\r
+    } else if (x instanceof String) {\r
+      return Double.parseDouble((String) x);\r
+    } else {\r
+      throw unsupportedCast(x.getClass(), Double.TYPE);\r
+    }\r
+  }\r
+\r
+  private static float toFloat(Object x) {\r
+    if (x instanceof Number) {\r
+      return ((Number) x).floatValue();\r
+    } else if (x instanceof Boolean) {\r
+      return (Boolean) x ? 1F : 0F;\r
+    } else if (x instanceof String) {\r
+      return Float.parseFloat((String) x);\r
+    } else {\r
+      throw unsupportedCast(x.getClass(), Float.TYPE);\r
+    }\r
+  }\r
+\r
+  private static int toInt(Object x) {\r
+    if (x instanceof Number) {\r
+      return ((Number) x).intValue();\r
+    } else if (x instanceof Boolean) {\r
+      return (Boolean) x ? 1 : 0;\r
+    } else if (x instanceof String) {\r
+      return Integer.parseInt((String) x);\r
+    } else {\r
+      throw unsupportedCast(x.getClass(), Integer.TYPE);\r
+    }\r
+  }\r
+\r
+  private static long toLong(Object x) {\r
+    if (x instanceof Number) {\r
+      return ((Number) x).longValue();\r
+    } else if (x instanceof Boolean) {\r
+      return (Boolean) x ? 1L : 0L;\r
+    } else if (x instanceof String) {\r
+      return Long.parseLong((String) x);\r
+    } else {\r
+      throw unsupportedCast(x.getClass(), Long.TYPE);\r
+    }\r
+  }\r
+\r
+  private static short toShort(Object x) {\r
+    if (x instanceof Number) {\r
+      return ((Number) x).shortValue();\r
+    } else if (x instanceof Boolean) {\r
+      return (Boolean) x ? (short) 1 : (short) 0;\r
+    } else if (x instanceof String) {\r
+      return Short.parseShort((String) x);\r
+    } else {\r
+      throw unsupportedCast(x.getClass(), Short.TYPE);\r
+    }\r
+  }\r
+\r
+  private static String toString(Object x) {\r
+    if (x instanceof String) {\r
+      return (String) x;\r
+    } else if (x instanceof Character\r
+        || x instanceof Boolean) {\r
+      return x.toString();\r
+    }\r
+    throw unsupportedCast(x.getClass(), String.class);\r
+  }\r
+\r
+  /** Singleton value to denote parameters that have been set to null (as\r
+   * opposed to not set).\r
+   *\r
+   * <p>Not a valid value for a parameter.\r
+   *\r
+   * <p>As an enum, it is serializable by Jackson. */\r
+  private enum Dummy {\r
+    INSTANCE\r
+  }\r
+}\r
+\r
+// End AvaticaSite.java\r
diff --git a/mdbc-server/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java b/mdbc-server/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
new file mode 100644 (file)
index 0000000..cacbb8b
--- /dev/null
@@ -0,0 +1,1504 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to you under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.calcite.avatica.util;\r
+\r
+import java.io.InputStream;\r
+import java.io.Reader;\r
+import java.lang.reflect.Field;\r
+import java.math.BigDecimal;\r
+import java.math.RoundingMode;\r
+import java.net.URL;\r
+import java.nio.charset.StandardCharsets;\r
+import java.sql.Array;\r
+import java.sql.Blob;\r
+import java.sql.Clob;\r
+import java.sql.Date;\r
+import java.sql.NClob;\r
+import java.sql.Ref;\r
+import java.sql.SQLDataException;\r
+import java.sql.SQLException;\r
+import java.sql.SQLXML;\r
+import java.sql.Struct;\r
+import java.sql.Time;\r
+import java.sql.Timestamp;\r
+import java.sql.Types;\r
+import java.util.ArrayList;\r
+import java.util.Calendar;\r
+import java.util.List;\r
+import java.util.Map;\r
+import javax.sql.rowset.serial.SerialBlob;\r
+import org.apache.calcite.avatica.AvaticaSite;\r
+import org.apache.calcite.avatica.AvaticaUtils;\r
+import org.apache.calcite.avatica.ColumnMetaData;\r
+\r
+/**\r
+ * Base class for implementing a cursor.\r
+ *\r
+ * <p>Derived class needs to provide {@link Getter} and can override\r
+ * {@link org.apache.calcite.avatica.util.Cursor.Accessor} implementations if it\r
+ * wishes.</p>\r
+ */\r
+public abstract class AbstractCursor implements Cursor {\r
+  /**\r
+   * Slot into which each accessor should write whether the\r
+   * value returned was null.\r
+   */\r
+  protected final boolean[] wasNull = {false};\r
+\r
+  protected AbstractCursor() {\r
+  }\r
+\r
+  public boolean wasNull() {\r
+    return wasNull[0];\r
+  }\r
+\r
+  public List<Accessor> createAccessors(List<ColumnMetaData> types,\r
+      Calendar localCalendar, ArrayImpl.Factory factory) {\r
+    List<Accessor> accessors = new ArrayList<>();\r
+    for (ColumnMetaData type : types) {\r
+      accessors.add(\r
+          createAccessor(type, accessors.size(), localCalendar, factory));\r
+    }\r
+    return accessors;\r
+  }\r
+\r
+  protected Accessor createAccessor(ColumnMetaData columnMetaData, int ordinal,\r
+      Calendar localCalendar, ArrayImpl.Factory factory) {\r
+    // Create an accessor appropriate to the underlying type; the accessor\r
+    // can convert to any type in the same family.\r
+    Getter getter = createGetter(ordinal);\r
+    return createAccessor(columnMetaData, getter, localCalendar, factory);\r
+  }\r
+\r
+  protected Accessor createAccessor(ColumnMetaData columnMetaData,\r
+      Getter getter, Calendar localCalendar, ArrayImpl.Factory factory) {\r
+    switch (columnMetaData.type.rep) {\r
+    case NUMBER:\r
+      switch (columnMetaData.type.id) {\r
+      case Types.TINYINT:\r
+      case Types.SMALLINT:\r
+      case Types.INTEGER:\r
+      case Types.BIGINT:\r
+      case Types.REAL:\r
+      case Types.FLOAT:\r
+      case Types.DOUBLE:\r
+      case Types.NUMERIC:\r
+      case Types.DECIMAL:\r
+        return new NumberAccessor(getter, columnMetaData.scale);\r
+      }\r
+    }\r
+    switch (columnMetaData.type.id) {\r
+    case Types.TINYINT:\r
+      return new ByteAccessor(getter);\r
+    case Types.SMALLINT:\r
+      return new ShortAccessor(getter);\r
+    case Types.INTEGER:\r
+      return new IntAccessor(getter);\r
+    case Types.BIGINT:\r
+      return new LongAccessor(getter);\r
+    case Types.BOOLEAN:\r
+      return new BooleanAccessor(getter);\r
+    case Types.REAL:\r
+      return new FloatAccessor(getter);\r
+    case Types.FLOAT:\r
+    case Types.DOUBLE:\r
+      return new DoubleAccessor(getter);\r
+    case Types.DECIMAL:\r
+      return new BigDecimalAccessor(getter);\r
+    case Types.CHAR:\r
+      switch (columnMetaData.type.rep) {\r
+      case PRIMITIVE_CHAR:\r
+      case CHARACTER:\r
+        return new StringFromCharAccessor(getter, columnMetaData.displaySize);\r
+      default:\r
+        return new FixedStringAccessor(getter, columnMetaData.displaySize);\r
+      }\r
+    case Types.VARCHAR:\r
+      return new StringAccessor(getter);\r
+    case Types.BINARY:\r
+    case Types.VARBINARY:\r
+      switch (columnMetaData.type.rep) {\r
+      case STRING:\r
+        return new BinaryFromStringAccessor(getter);\r
+      default:\r
+        return new BinaryAccessor(getter);\r
+      }\r
+    case Types.DATE:\r
+      switch (columnMetaData.type.rep) {\r
+      case PRIMITIVE_INT:\r
+      case INTEGER:\r
+      case NUMBER:\r
+        return new DateFromNumberAccessor(getter, localCalendar);\r
+      case JAVA_SQL_DATE:\r
+        return new DateAccessor(getter);\r
+      default:\r
+        throw new AssertionError("bad " + columnMetaData.type.rep);\r
+      }\r
+    case Types.TIME:\r
+      switch (columnMetaData.type.rep) {\r
+      case PRIMITIVE_INT:\r
+      case INTEGER:\r
+      case NUMBER:\r
+        return new TimeFromNumberAccessor(getter, localCalendar);\r
+      case JAVA_SQL_TIME:\r
+        return new TimeAccessor(getter);\r
+      default:\r
+        throw new AssertionError("bad " + columnMetaData.type.rep);\r
+      }\r
+    case Types.TIMESTAMP:\r
+      switch (columnMetaData.type.rep) {\r
+      case PRIMITIVE_LONG:\r
+      case LONG:\r
+      case NUMBER:\r
+        return new TimestampFromNumberAccessor(getter, localCalendar);\r
+      case JAVA_SQL_TIMESTAMP:\r
+        return new TimestampAccessor(getter);\r
+      case JAVA_UTIL_DATE:\r
+        return new TimestampFromUtilDateAccessor(getter, localCalendar);\r
+      default:\r
+        throw new AssertionError("bad " + columnMetaData.type.rep);\r
+      }\r
+    case 2013: // TIME_WITH_TIMEZONE\r
+      switch (columnMetaData.type.rep) {\r
+      case STRING:\r
+        return new StringAccessor(getter);\r
+      default:\r
+        throw new AssertionError("bad " + columnMetaData.type.rep);\r
+      }\r
+    case 2014: // TIMESTAMP_WITH_TIMEZONE\r
+      switch (columnMetaData.type.rep) {\r
+      case STRING:\r
+        return new StringAccessor(getter);\r
+      default:\r
+        throw new AssertionError("bad " + columnMetaData.type.rep);\r
+      }\r
+    case Types.ARRAY:\r
+      final ColumnMetaData.ArrayType arrayType =\r
+          (ColumnMetaData.ArrayType) columnMetaData.type;\r
+      final SlotGetter componentGetter = new SlotGetter();\r
+      final Accessor componentAccessor =\r
+          createAccessor(ColumnMetaData.dummy(arrayType.getComponent(), true),\r
+              componentGetter, localCalendar, factory);\r
+      return new ArrayAccessor(getter, arrayType.getComponent(), componentAccessor,\r
+          componentGetter, factory);\r
+    case Types.STRUCT:\r
+      switch (columnMetaData.type.rep) {\r
+      case OBJECT:\r
+        final ColumnMetaData.StructType structType =\r
+            (ColumnMetaData.StructType) columnMetaData.type;\r
+        List<Accessor> accessors = new ArrayList<>();\r
+        for (ColumnMetaData column : structType.columns) {\r
+          final Getter fieldGetter =\r
+              structType.columns.size() == 1\r
+                  ? getter\r
+                  : new StructGetter(getter, column);\r
+          accessors.add(\r
+              createAccessor(column, fieldGetter, localCalendar, factory));\r
+        }\r
+        return new StructAccessor(getter, accessors);\r
+      default:\r
+        throw new AssertionError("bad " + columnMetaData.type.rep);\r
+      }\r
+    case Types.JAVA_OBJECT:\r
+    case Types.OTHER: // e.g. map\r
+      if (columnMetaData.type.getName().startsWith("INTERVAL_")) {\r
+        int end = columnMetaData.type.getName().indexOf("(");\r
+        if (end < 0) {\r
+          end = columnMetaData.type.getName().length();\r
+        }\r
+        TimeUnitRange range =\r
+            TimeUnitRange.valueOf(\r
+                columnMetaData.type.getName().substring("INTERVAL_".length(), end));\r
+        if (range.monthly()) {\r
+          return new IntervalYearMonthAccessor(getter, range);\r
+        } else {\r
+          return new IntervalDayTimeAccessor(getter, range,\r
+              columnMetaData.scale);\r
+        }\r
+      }\r
+      return new ObjectAccessor(getter);\r
+    default:\r
+      throw new RuntimeException("unknown type " + columnMetaData.type.id);\r
+    }\r
+  }\r
+\r
+  protected abstract Getter createGetter(int ordinal);\r
+\r
+  public abstract boolean next();\r
+\r
+  /** Accesses a timestamp value as a string.\r
+   * The timestamp is in SQL format (e.g. "2013-09-22 22:30:32"),\r
+   * not Java format ("2013-09-22 22:30:32.123"). */\r
+  private static String timestampAsString(long v, Calendar calendar) {\r
+    if (calendar != null) {\r
+      v -= calendar.getTimeZone().getOffset(v);\r
+    }\r
+    return DateTimeUtils.unixTimestampToString(v);\r
+  }\r
+\r
+  /** Accesses a date value as a string, e.g. "2013-09-22". */\r
+  private static String dateAsString(int v, Calendar calendar) {\r
+    AvaticaUtils.discard(calendar); // time zone shift doesn't make sense\r
+    return DateTimeUtils.unixDateToString(v);\r
+  }\r
+\r
+  /** Accesses a time value as a string, e.g. "22:30:32". */\r
+  private static String timeAsString(int v, Calendar calendar) {\r
+    if (calendar != null) {\r
+      v -= calendar.getTimeZone().getOffset(v);\r
+    }\r
+    return DateTimeUtils.unixTimeToString(v);\r
+  }\r
+\r
+  private static Date longToDate(long v, Calendar calendar) {\r
+    if (calendar != null) {\r
+      v -= calendar.getTimeZone().getOffset(v);\r
+    }\r
+    return new Date(v);\r
+  }\r
+\r
+  static Time intToTime(int v, Calendar calendar) {\r
+    if (calendar != null) {\r
+      v -= calendar.getTimeZone().getOffset(v);\r
+    }\r
+    return new Time(v);\r
+  }\r
+\r
+  static Timestamp longToTimestamp(long v, Calendar calendar) {\r
+    if (calendar != null) {\r
+      v -= calendar.getTimeZone().getOffset(v);\r
+    }\r
+    return new Timestamp(v);\r
+  }\r
+\r
+  /** Implementation of {@link Cursor.Accessor}. */\r
+  static class AccessorImpl implements Accessor {\r
+    protected final Getter getter;\r
+\r
+    AccessorImpl(Getter getter) {\r
+      assert getter != null;\r
+      this.getter = getter;\r
+    }\r
+\r
+    public boolean wasNull() throws SQLException {\r
+      return getter.wasNull();\r
+    }\r
+\r
+    public String getString() throws SQLException {\r
+      final Object o = getObject();\r
+      return o == null ? null : o.toString();\r
+    }\r
+\r
+    public boolean getBoolean() throws SQLException {\r
+      return getLong() != 0L;\r
+    }\r
+\r
+    public byte getByte() throws SQLException {\r
+      return (byte) getLong();\r
+    }\r
+\r
+    public short getShort() throws SQLException {\r
+      return (short) getLong();\r
+    }\r
+\r
+    public int getInt() throws SQLException {\r
+      return (int) getLong();\r
+    }\r
+\r
+    public long getLong() throws SQLException {\r
+      throw cannotConvert("long");\r
+    }\r
+\r
+    public float getFloat() throws SQLException {\r
+      return (float) getDouble();\r
+    }\r
+\r
+    public double getDouble() throws SQLException {\r
+      throw cannotConvert("double");\r
+    }\r
+\r
+    public BigDecimal getBigDecimal() throws SQLException {\r
+      throw cannotConvert("BigDecimal");\r
+    }\r
+\r
+    public BigDecimal getBigDecimal(int scale) throws SQLException {\r
+      throw cannotConvert("BigDecimal with scale");\r
+    }\r
+\r
+    public byte[] getBytes() throws SQLException {\r
+      throw cannotConvert("byte[]");\r
+    }\r
+\r
+    public InputStream getAsciiStream() throws SQLException {\r
+      throw cannotConvert("InputStream (ascii)");\r
+    }\r
+\r
+    public InputStream getUnicodeStream() throws SQLException {\r
+      throw cannotConvert("InputStream (unicode)");\r
+    }\r
+\r
+    public InputStream getBinaryStream() throws SQLException {\r
+      throw cannotConvert("InputStream (binary)");\r
+    }\r
+\r
+    public Object getObject() throws SQLException {\r
+      return getter.getObject();\r
+    }\r
+\r
+    public Reader getCharacterStream() throws SQLException {\r
+      throw cannotConvert("Reader");\r
+    }\r
+\r
+    private SQLException cannotConvert(String targetType) throws SQLException {\r
+      return new SQLDataException("cannot convert to " + targetType + " ("\r
+          + this + ")");\r
+    }\r
+\r
+    public Object getObject(Map<String, Class<?>> map) throws SQLException {\r
+      throw cannotConvert("Object (with map)");\r
+    }\r
+\r
+    public Ref getRef() throws SQLException {\r
+      throw cannotConvert("Ref");\r
+    }\r
+\r
+    public Blob getBlob() throws SQLException {\r
+        throw cannotConvert("Blob");\r
+    }\r
+\r
+    public Clob getClob() throws SQLException {\r
+      throw cannotConvert("Clob");\r
+    }\r
+\r
+    public Array getArray() throws SQLException {\r
+      throw cannotConvert("Array");\r
+    }\r
+\r
+    public Struct getStruct() throws SQLException {\r
+      throw cannotConvert("Struct");\r
+    }\r
+\r
+    public Date getDate(Calendar calendar) throws SQLException {\r
+      throw cannotConvert("Date");\r
+    }\r
+\r
+    public Time getTime(Calendar calendar) throws SQLException {\r
+      throw cannotConvert("Time");\r
+    }\r
+\r
+    public Timestamp getTimestamp(Calendar calendar) throws SQLException {\r
+      throw cannotConvert("Timestamp");\r
+    }\r
+\r
+    public URL getURL() throws SQLException {\r
+      throw cannotConvert("URL");\r
+    }\r
+\r
+    public NClob getNClob() throws SQLException {\r
+      throw cannotConvert("NClob");\r
+    }\r
+\r
+    public SQLXML getSQLXML() throws SQLException {\r
+      throw cannotConvert("SQLXML");\r
+    }\r
+\r
+    public String getNString() throws SQLException {\r
+      throw cannotConvert("NString");\r
+    }\r
+\r
+    public Reader getNCharacterStream() throws SQLException {\r
+      throw cannotConvert("NCharacterStream");\r
+    }\r
+\r
+    public <T> T getObject(Class<T> type) throws SQLException {\r
+      throw cannotConvert("Object (with type)");\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor of exact numeric values. The subclass must implement the\r
+   * {@link #getLong()} method.\r
+   */\r
+  private abstract static class ExactNumericAccessor extends AccessorImpl {\r
+    private ExactNumericAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    public BigDecimal getBigDecimal(int scale) throws SQLException {\r
+      final long v = getLong();\r
+      if (v == 0 && getter.wasNull()) {\r
+        return null;\r
+      }\r
+      return BigDecimal.valueOf(v).setScale(scale, RoundingMode.DOWN);\r
+    }\r
+\r
+    public BigDecimal getBigDecimal() throws SQLException {\r
+      final long val = getLong();\r
+      if (val == 0 && getter.wasNull()) {\r
+        return null;\r
+      }\r
+      return BigDecimal.valueOf(val);\r
+    }\r
+\r
+    public double getDouble() throws SQLException {\r
+      return getLong();\r
+    }\r
+\r
+    public float getFloat() throws SQLException {\r
+      return getLong();\r
+    }\r
+\r
+    public abstract long getLong() throws SQLException;\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link Boolean};\r
+   * corresponds to {@link java.sql.Types#BOOLEAN}.\r
+   */\r
+  private static class BooleanAccessor extends ExactNumericAccessor {\r
+    private BooleanAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    public boolean getBoolean() throws SQLException {\r
+      Boolean o = (Boolean) getObject();\r
+      return o != null && o;\r
+    }\r
+\r
+    public long getLong() throws SQLException {\r
+      return getBoolean() ? 1 : 0;\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link Byte};\r
+   * corresponds to {@link java.sql.Types#TINYINT}.\r
+   */\r
+  private static class ByteAccessor extends ExactNumericAccessor {\r
+    private ByteAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    public byte getByte() throws SQLException {\r
+      Object obj = getObject();\r
+      if (null == obj) {\r
+        return 0;\r
+      } else if (obj instanceof Integer) {\r
+        return ((Integer) obj).byteValue();\r
+      }\r
+      return (Byte) obj;\r
+    }\r
+\r
+    public long getLong() throws SQLException {\r
+      return getByte();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link Short};\r
+   * corresponds to {@link java.sql.Types#SMALLINT}.\r
+   */\r
+  private static class ShortAccessor extends ExactNumericAccessor {\r
+    private ShortAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    public short getShort() throws SQLException {\r
+      Object obj = getObject();\r
+      if (null == obj) {\r
+        return 0;\r
+      } else if (obj instanceof Integer) {\r
+        return ((Integer) obj).shortValue();\r
+      }\r
+      return (Short) obj;\r
+    }\r
+\r
+    public long getLong() throws SQLException {\r
+      return getShort();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is an {@link Integer};\r
+   * corresponds to {@link java.sql.Types#INTEGER}.\r
+   */\r
+  private static class IntAccessor extends ExactNumericAccessor {\r
+    private IntAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    public int getInt() throws SQLException {\r
+      Integer o = (Integer) super.getObject();\r
+      return o == null ? 0 : o;\r
+    }\r
+\r
+    public long getLong() throws SQLException {\r
+      return getInt();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link Long};\r
+   * corresponds to {@link java.sql.Types#BIGINT}.\r
+   */\r
+  private static class LongAccessor extends ExactNumericAccessor {\r
+    private LongAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    public long getLong() throws SQLException {\r
+      Long o = (Long) super.getObject();\r
+      return o == null ? 0 : o;\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor of values that are {@link Double} or null.\r
+   */\r
+  private abstract static class ApproximateNumericAccessor\r
+      extends AccessorImpl {\r
+    private ApproximateNumericAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    public BigDecimal getBigDecimal(int scale) throws SQLException {\r
+      final double v = getDouble();\r
+      if (v == 0d && getter.wasNull()) {\r
+        return null;\r
+      }\r
+      return BigDecimal.valueOf(v).setScale(scale, RoundingMode.DOWN);\r
+    }\r
+\r
+    public BigDecimal getBigDecimal() throws SQLException {\r
+      final double v = getDouble();\r
+      if (v == 0 && getter.wasNull()) {\r
+        return null;\r
+      }\r
+      return BigDecimal.valueOf(v);\r
+    }\r
+\r
+    public abstract double getDouble() throws SQLException;\r
+\r
+    public long getLong() throws SQLException {\r
+      return (long) getDouble();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link Float};\r
+   * corresponds to {@link java.sql.Types#FLOAT}.\r
+   */\r
+  private static class FloatAccessor extends ApproximateNumericAccessor {\r
+    private FloatAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    public float getFloat() throws SQLException {\r
+      Float o = (Float) getObject();\r
+      return o == null ? 0f : o;\r
+    }\r
+\r
+    public double getDouble() throws SQLException {\r
+      return getFloat();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link Double};\r
+   * corresponds to {@link java.sql.Types#DOUBLE}.\r
+   */\r
+  private static class DoubleAccessor extends ApproximateNumericAccessor {\r
+    private DoubleAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    public double getDouble() throws SQLException {\r
+      Object obj = getObject();\r
+      if (null == obj) {\r
+        return 0d;\r
+      } else if (obj instanceof BigDecimal) {\r
+        return ((BigDecimal) obj).doubleValue();\r
+      }\r
+      return (Double) obj;\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor of exact numeric values. The subclass must implement the\r
+   * {@link #getLong()} method.\r
+   */\r
+  private abstract static class BigNumberAccessor extends AccessorImpl {\r
+    private BigNumberAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    protected abstract Number getNumber() throws SQLException;\r
+\r
+    public double getDouble() throws SQLException {\r
+      Number number = getNumber();\r
+      return number == null ? 0d : number.doubleValue();\r
+    }\r
+\r
+    public float getFloat() throws SQLException {\r
+      Number number = getNumber();\r
+      return number == null ? 0f : number.floatValue();\r
+    }\r
+\r
+    public long getLong() throws SQLException {\r
+      Number number = getNumber();\r
+      return number == null ? 0L : number.longValue();\r
+    }\r
+\r
+    public int getInt() throws SQLException {\r
+      Number number = getNumber();\r
+      return number == null ? 0 : number.intValue();\r
+    }\r
+\r
+    public short getShort() throws SQLException {\r
+      Number number = getNumber();\r
+      return number == null ? 0 : number.shortValue();\r
+    }\r
+\r
+    public byte getByte() throws SQLException {\r
+      Number number = getNumber();\r
+      return number == null ? 0 : number.byteValue();\r
+    }\r
+\r
+    public boolean getBoolean() throws SQLException {\r
+      Number number = getNumber();\r
+      return number != null && number.doubleValue() != 0;\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link BigDecimal};\r
+   * corresponds to {@link java.sql.Types#DECIMAL}.\r
+   */\r
+  private static class BigDecimalAccessor extends BigNumberAccessor {\r
+    private BigDecimalAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    protected Number getNumber() throws SQLException {\r
+      return (Number) getObject();\r
+    }\r
+\r
+    public BigDecimal getBigDecimal(int scale) throws SQLException {\r
+      return (BigDecimal) getObject();\r
+    }\r
+\r
+    public BigDecimal getBigDecimal() throws SQLException {\r
+      return (BigDecimal) getObject();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link Number};\r
+   * corresponds to {@link java.sql.Types#NUMERIC}.\r
+   *\r
+   * <p>This is useful when numbers have been translated over JSON. JSON\r
+   * converts a 0L (0 long) value to the string "0" and back to 0 (0 int).\r
+   * So you cannot be sure that the source and target type are the same.\r
+   */\r
+  static class NumberAccessor extends BigNumberAccessor {\r
+    private final int scale;\r
+\r
+    NumberAccessor(Getter getter, int scale) {\r
+      super(getter);\r
+      this.scale = scale;\r
+    }\r
+\r
+    protected Number getNumber() throws SQLException {\r
+      return (Number) super.getObject();\r
+    }\r
+\r
+    public BigDecimal getBigDecimal(int scale) throws SQLException {\r
+      Number n = getNumber();\r
+      if (n == null) {\r
+        return null;\r
+      }\r
+      BigDecimal decimal = AvaticaSite.toBigDecimal(n);\r
+      if (0 != scale) {\r
+        return decimal.setScale(scale, RoundingMode.UNNECESSARY);\r
+      }\r
+      return decimal;\r
+    }\r
+\r
+    public BigDecimal getBigDecimal() throws SQLException {\r
+      return getBigDecimal(scale);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link String};\r
+   * corresponds to {@link java.sql.Types#CHAR}\r
+   * and {@link java.sql.Types#VARCHAR}.\r
+   */\r
+  private static class StringAccessor extends AccessorImpl {\r
+    private StringAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    public String getString() throws SQLException {\r
+      final Object obj = getObject();\r
+      if (obj instanceof String) {\r
+        return (String) obj;\r
+      }\r
+      return null == obj ? null : obj.toString();\r
+    }\r
+\r
+    @Override public byte[] getBytes() throws SQLException {\r
+      return super.getBytes();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link String};\r
+   * corresponds to {@link java.sql.Types#CHAR}.\r
+   */\r
+  private static class FixedStringAccessor extends StringAccessor {\r
+    protected final Spacer spacer;\r
+\r
+    private FixedStringAccessor(Getter getter, int length) {\r
+      super(getter);\r
+      this.spacer = new Spacer(length);\r
+    }\r
+\r
+    public String getString() throws SQLException {\r
+      String s = super.getString();\r
+      if (s == null) {\r
+        return null;\r
+      }\r
+      return spacer.padRight(s);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link String};\r
+   * corresponds to {@link java.sql.Types#CHAR}.\r
+   */\r
+  private static class StringFromCharAccessor extends FixedStringAccessor {\r
+    private StringFromCharAccessor(Getter getter, int length) {\r
+      super(getter, length);\r
+    }\r
+\r
+    public String getString() throws SQLException {\r
+      Character s = (Character) super.getObject();\r
+      if (s == null) {\r
+        return null;\r
+      }\r
+      return spacer.padRight(s.toString());\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is an array of\r
+   * {@link org.apache.calcite.avatica.util.ByteString} values;\r
+   * corresponds to {@link java.sql.Types#BINARY}\r
+   * and {@link java.sql.Types#VARBINARY}.\r
+   */\r
+  private static class BinaryAccessor extends AccessorImpl {\r
+    private BinaryAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    //FIXME: Protobuf gets byte[]\r
+    @Override public byte[] getBytes() throws SQLException {\r
+      Object obj = getObject();\r
+      if (null == obj) {\r
+        return null;\r
+      }\r
+      if (obj instanceof ByteString) {\r
+        return ((ByteString) obj).getBytes();\r
+      } else if (obj instanceof String) {\r
+        // Need to unwind the base64 for JSON\r
+        return ByteString.parseBase64((String) obj);\r
+      } else if (obj instanceof byte[]) {\r
+        // Protobuf would have a byte array\r
+        return (byte[]) obj;\r
+      } else {\r
+        throw new RuntimeException("Cannot handle " + obj.getClass() + " as bytes");\r
+      }\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      Object o = getObject();\r
+      if (null == o) {\r
+        return null;\r
+      }\r
+      if (o instanceof byte[]) {\r
+        return new String((byte[]) o, StandardCharsets.UTF_8);\r
+      } else if (o instanceof ByteString) {\r
+        return ((ByteString) o).toString();\r
+      }\r
+      throw new IllegalStateException("Unhandled value type: " + o.getClass());\r
+    }\r
+    \r
+    \r
+    @Override public Blob getBlob() throws SQLException {\r
+        \r
+        Object o = getObject();\r
+        if (null == o) {\r
+          return null;\r
+        }\r
+        if (o instanceof byte[]) {\r
+            byte[] byteArr = (byte[] )o;\r
+            //System.out.println(new String(byteArr, StandardCharsets.UTF_8));\r
+            return new SerialBlob(byteArr);\r
+        } \r
+        \r
+        throw new IllegalStateException("Unhandled value type: " + o.getClass());\r
+        \r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@link String},\r
+   * encoding {@link java.sql.Types#BINARY}\r
+   * and {@link java.sql.Types#VARBINARY} values in Base64 format.\r
+   */\r
+  private static class BinaryFromStringAccessor extends StringAccessor {\r
+    private BinaryFromStringAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    @Override public Object getObject() throws SQLException {\r
+      return super.getObject();\r
+    }\r
+\r
+    @Override public byte[] getBytes() throws SQLException {\r
+      // JSON sends this as a base64-enc string, protobuf can do binary.\r
+      Object obj = getObject();\r
+\r
+      if (obj instanceof byte[]) {\r
+        // If we already have bytes, just send them back.\r
+        return (byte[]) obj;\r
+      }\r
+\r
+      return getBase64Decoded();\r
+    }\r
+\r
+    private byte[] getBase64Decoded() throws SQLException {\r
+      final String string = super.getString();\r
+      if (null == string) {\r
+        return null;\r
+      }\r
+      // Need to base64 decode the string.\r
+      return ByteString.parseBase64(string);\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      final byte[] bytes = getBase64Decoded();\r
+      if (null == bytes) {\r
+        return null;\r
+      }\r
+      // Need to base64 decode the string.\r
+      return new String(bytes, StandardCharsets.UTF_8);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a DATE,\r
+   * in its default representation {@code int};\r
+   * corresponds to {@link java.sql.Types#DATE}.\r
+   */\r
+  private static class DateFromNumberAccessor extends NumberAccessor {\r
+    private final Calendar localCalendar;\r
+\r
+    private DateFromNumberAccessor(Getter getter, Calendar localCalendar) {\r
+      super(getter, 0);\r
+      this.localCalendar = localCalendar;\r
+    }\r
+\r
+    @Override public Object getObject() throws SQLException {\r
+      return getDate(localCalendar);\r
+    }\r
+\r
+    @Override public Date getDate(Calendar calendar) throws SQLException {\r
+      final Number v = getNumber();\r
+      if (v == null) {\r
+        return null;\r
+      }\r
+      return longToDate(v.longValue() * DateTimeUtils.MILLIS_PER_DAY, calendar);\r
+    }\r
+\r
+    @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {\r
+      final Number v = getNumber();\r
+      if (v == null) {\r
+        return null;\r
+      }\r
+      return longToTimestamp(v.longValue() * DateTimeUtils.MILLIS_PER_DAY,\r
+          calendar);\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      final Number v = getNumber();\r
+      if (v == null) {\r
+        return null;\r
+      }\r
+      return dateAsString(v.intValue(), null);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a Time,\r
+   * in its default representation {@code int};\r
+   * corresponds to {@link java.sql.Types#TIME}.\r
+   */\r
+  private static class TimeFromNumberAccessor extends NumberAccessor {\r
+    private final Calendar localCalendar;\r
+\r
+    private TimeFromNumberAccessor(Getter getter, Calendar localCalendar) {\r
+      super(getter, 0);\r
+      this.localCalendar = localCalendar;\r
+    }\r
+\r
+    @Override public Object getObject() throws SQLException {\r
+      return getTime(localCalendar);\r
+    }\r
+\r
+    @Override public Time getTime(Calendar calendar) throws SQLException {\r
+      final Number v = getNumber();\r
+      if (v == null) {\r
+        return null;\r
+      }\r
+      return intToTime(v.intValue(), calendar);\r
+    }\r
+\r
+    @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {\r
+      final Number v = getNumber();\r
+      if (v == null) {\r
+        return null;\r
+      }\r
+      return longToTimestamp(v.longValue(), calendar);\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      final Number v = getNumber();\r
+      if (v == null) {\r
+        return null;\r
+      }\r
+      return timeAsString(v.intValue(), null);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a TIMESTAMP,\r
+   * in its default representation {@code long};\r
+   * corresponds to {@link java.sql.Types#TIMESTAMP}.\r
+   */\r
+  private static class TimestampFromNumberAccessor extends NumberAccessor {\r
+    private final Calendar localCalendar;\r
+\r
+    private TimestampFromNumberAccessor(Getter getter, Calendar localCalendar) {\r
+      super(getter, 0);\r
+      this.localCalendar = localCalendar;\r
+    }\r
+\r
+    @Override public Object getObject() throws SQLException {\r
+      return getTimestamp(localCalendar);\r
+    }\r
+\r
+    @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {\r
+      final Number v = getNumber();\r
+      if (v == null) {\r
+        return null;\r
+      }\r
+      return longToTimestamp(v.longValue(), calendar);\r
+    }\r
+\r
+    @Override public Date getDate(Calendar calendar) throws SQLException {\r
+      final Timestamp timestamp  = getTimestamp(calendar);\r
+      if (timestamp == null) {\r
+        return null;\r
+      }\r
+      return new Date(timestamp.getTime());\r
+    }\r
+\r
+    @Override public Time getTime(Calendar calendar) throws SQLException {\r
+      final Timestamp timestamp  = getTimestamp(calendar);\r
+      if (timestamp == null) {\r
+        return null;\r
+      }\r
+      return new Time(\r
+          DateTimeUtils.floorMod(timestamp.getTime(),\r
+              DateTimeUtils.MILLIS_PER_DAY));\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      final Number v = getNumber();\r
+      if (v == null) {\r
+        return null;\r
+      }\r
+      return timestampAsString(v.longValue(), null);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a DATE,\r
+   * represented as a java.sql.Date;\r
+   * corresponds to {@link java.sql.Types#DATE}.\r
+   */\r
+  private static class DateAccessor extends ObjectAccessor {\r
+    private DateAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    @Override public Date getDate(Calendar calendar) throws SQLException {\r
+      java.sql.Date date = (Date) getObject();\r
+      if (date == null) {\r
+        return null;\r
+      }\r
+      if (calendar != null) {\r
+        long v = date.getTime();\r
+        v -= calendar.getTimeZone().getOffset(v);\r
+        date = new Date(v);\r
+      }\r
+      return date;\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      final int v = getInt();\r
+      if (v == 0 && wasNull()) {\r
+        return null;\r
+      }\r
+      return dateAsString(v, null);\r
+    }\r
+\r
+    @Override public long getLong() throws SQLException {\r
+      Date date = getDate(null);\r
+      return date == null\r
+          ? 0L\r
+          : (date.getTime() / DateTimeUtils.MILLIS_PER_DAY);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a TIME,\r
+   * represented as a java.sql.Time;\r
+   * corresponds to {@link java.sql.Types#TIME}.\r
+   */\r
+  private static class TimeAccessor extends ObjectAccessor {\r
+    private TimeAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    @Override public Time getTime(Calendar calendar) throws SQLException {\r
+      Time date  = (Time) getObject();\r
+      if (date == null) {\r
+        return null;\r
+      }\r
+      if (calendar != null) {\r
+        long v = date.getTime();\r
+        v -= calendar.getTimeZone().getOffset(v);\r
+        date = new Time(v);\r
+      }\r
+      return date;\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      final int v = getInt();\r
+      if (v == 0 && wasNull()) {\r
+        return null;\r
+      }\r
+      return timeAsString(v, null);\r
+    }\r
+\r
+    @Override public long getLong() throws SQLException {\r
+      Time time = getTime(null);\r
+      return time == null ? 0L\r
+          : (time.getTime() % DateTimeUtils.MILLIS_PER_DAY);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a TIMESTAMP,\r
+   * represented as a java.sql.Timestamp;\r
+   * corresponds to {@link java.sql.Types#TIMESTAMP}.\r
+   */\r
+  private static class TimestampAccessor extends ObjectAccessor {\r
+    private TimestampAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+\r
+    @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {\r
+      Timestamp timestamp  = (Timestamp) getObject();\r
+      if (timestamp == null) {\r
+        return null;\r
+      }\r
+      if (calendar != null) {\r
+        long v = timestamp.getTime();\r
+        v -= calendar.getTimeZone().getOffset(v);\r
+        timestamp = new Timestamp(v);\r
+      }\r
+      return timestamp;\r
+    }\r
+\r
+    @Override public Date getDate(Calendar calendar) throws SQLException {\r
+      final Timestamp timestamp  = getTimestamp(calendar);\r
+      if (timestamp == null) {\r
+        return null;\r
+      }\r
+      return new Date(timestamp.getTime());\r
+    }\r
+\r
+    @Override public Time getTime(Calendar calendar) throws SQLException {\r
+      final Timestamp timestamp  = getTimestamp(calendar);\r
+      if (timestamp == null) {\r
+        return null;\r
+      }\r
+      return new Time(\r
+          DateTimeUtils.floorMod(timestamp.getTime(),\r
+              DateTimeUtils.MILLIS_PER_DAY));\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      final long v = getLong();\r
+      if (v == 0 && wasNull()) {\r
+        return null;\r
+      }\r
+      return timestampAsString(v, null);\r
+    }\r
+\r
+    @Override public long getLong() throws SQLException {\r
+      Timestamp timestamp = getTimestamp(null);\r
+      return timestamp == null ? 0 : timestamp.getTime();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a TIMESTAMP,\r
+   * represented as a java.util.Date;\r
+   * corresponds to {@link java.sql.Types#TIMESTAMP}.\r
+   */\r
+  private static class TimestampFromUtilDateAccessor extends ObjectAccessor {\r
+    private final Calendar localCalendar;\r
+\r
+    private TimestampFromUtilDateAccessor(Getter getter,\r
+        Calendar localCalendar) {\r
+      super(getter);\r
+      this.localCalendar = localCalendar;\r
+    }\r
+\r
+    @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {\r
+      java.util.Date date  = (java.util.Date) getObject();\r
+      if (date == null) {\r
+        return null;\r
+      }\r
+      long v = date.getTime();\r
+      if (calendar != null) {\r
+        v -= calendar.getTimeZone().getOffset(v);\r
+      }\r
+      return new Timestamp(v);\r
+    }\r
+\r
+    @Override public Date getDate(Calendar calendar) throws SQLException {\r
+      final Timestamp timestamp  = getTimestamp(calendar);\r
+      if (timestamp == null) {\r
+        return null;\r
+      }\r
+      return new Date(timestamp.getTime());\r
+    }\r
+\r
+    @Override public Time getTime(Calendar calendar) throws SQLException {\r
+      final Timestamp timestamp  = getTimestamp(calendar);\r
+      if (timestamp == null) {\r
+        return null;\r
+      }\r
+      return new Time(\r
+          DateTimeUtils.floorMod(timestamp.getTime(),\r
+              DateTimeUtils.MILLIS_PER_DAY));\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      java.util.Date date  = (java.util.Date) getObject();\r
+      if (date == null) {\r
+        return null;\r
+      }\r
+      return timestampAsString(date.getTime(), null);\r
+    }\r
+\r
+    @Override public long getLong() throws SQLException {\r
+      Timestamp timestamp = getTimestamp(localCalendar);\r
+      return timestamp == null ? 0 : timestamp.getTime();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@code int};\r
+   * corresponds to {@link java.sql.Types#OTHER}.\r
+   */\r
+  private static class IntervalYearMonthAccessor extends IntAccessor {\r
+    private final TimeUnitRange range;\r
+\r
+    private IntervalYearMonthAccessor(Getter getter, TimeUnitRange range) {\r
+      super(getter);\r
+      this.range = range;\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      final int v = getInt();\r
+      if (v == 0 && wasNull()) {\r
+        return null;\r
+      }\r
+      return DateTimeUtils.intervalYearMonthToString(v, range);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a {@code long};\r
+   * corresponds to {@link java.sql.Types#OTHER}.\r
+   */\r
+  private static class IntervalDayTimeAccessor extends LongAccessor {\r
+    private final TimeUnitRange range;\r
+    private final int scale;\r
+\r
+    private IntervalDayTimeAccessor(Getter getter, TimeUnitRange range,\r
+        int scale) {\r
+      super(getter);\r
+      this.range = range;\r
+      this.scale = scale;\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      final long v = getLong();\r
+      if (v == 0 && wasNull()) {\r
+        return null;\r
+      }\r
+      return DateTimeUtils.intervalDayTimeToString(v, range, scale);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is an ARRAY;\r
+   * corresponds to {@link java.sql.Types#ARRAY}.\r
+   */\r
+  public static class ArrayAccessor extends AccessorImpl {\r
+    final ColumnMetaData.AvaticaType componentType;\r
+    final Accessor componentAccessor;\r
+    final SlotGetter componentSlotGetter;\r
+    final ArrayImpl.Factory factory;\r
+\r
+    public ArrayAccessor(Getter getter,\r
+        ColumnMetaData.AvaticaType componentType, Accessor componentAccessor,\r
+        SlotGetter componentSlotGetter, ArrayImpl.Factory factory) {\r
+      super(getter);\r
+      this.componentType = componentType;\r
+      this.componentAccessor = componentAccessor;\r
+      this.componentSlotGetter = componentSlotGetter;\r
+      this.factory = factory;\r
+    }\r
+\r
+    @Override public Object getObject() throws SQLException {\r
+      final Object object = super.getObject();\r
+      if (object == null || object instanceof ArrayImpl) {\r
+        return object;\r
+      } else if (object instanceof List) {\r
+        List<?> list = (List<?>) object;\r
+        // Run the array values through the component accessor\r
+        List<Object> convertedValues = new ArrayList<>(list.size());\r
+        for (Object val : list) {\r
+          if (null == val) {\r
+            convertedValues.add(null);\r
+          } else {\r
+            // Set the current value in the SlotGetter so we can use the Accessor to coerce it.\r
+            componentSlotGetter.slot = val;\r
+            convertedValues.add(convertValue());\r
+          }\r
+        }\r
+        return convertedValues;\r
+      }\r
+      // The object can be java array in case of user-provided class for row storage.\r
+      return AvaticaUtils.primitiveList(object);\r
+    }\r
+\r
+    private Object convertValue() throws SQLException {\r
+      switch (componentType.id) {\r
+      case Types.BOOLEAN:\r
+      case Types.BIT:\r
+        return componentAccessor.getBoolean();\r
+      case Types.TINYINT:\r
+        return componentAccessor.getByte();\r
+      case Types.SMALLINT:\r
+        return componentAccessor.getShort();\r
+      case Types.INTEGER:\r
+        return componentAccessor.getInt();\r
+      case Types.BIGINT:\r
+        return componentAccessor.getLong();\r
+      case Types.FLOAT:\r
+        return componentAccessor.getFloat();\r
+      case Types.DOUBLE:\r
+        return componentAccessor.getDouble();\r
+      case Types.ARRAY:\r
+        return componentAccessor.getArray();\r
+      case Types.CHAR:\r
+      case Types.VARCHAR:\r
+      case Types.LONGVARCHAR:\r
+      case Types.NCHAR:\r
+      case Types.LONGNVARCHAR:\r
+        return componentAccessor.getString();\r
+      case Types.BINARY:\r
+      case Types.VARBINARY:\r
+      case Types.LONGVARBINARY:\r
+        return componentAccessor.getBytes();\r
+      case Types.DECIMAL:\r
+        return componentAccessor.getBigDecimal();\r
+      case Types.DATE:\r
+      case Types.TIME:\r
+      case Types.TIMESTAMP:\r
+      case Types.STRUCT:\r
+      case Types.JAVA_OBJECT:\r
+        return componentAccessor.getObject();\r
+      default:\r
+        throw new IllegalStateException("Unhandled ARRAY component type: " + componentType.rep\r
+            + ", id: " + componentType.id);\r
+      }\r
+    }\r
+\r
+    @SuppressWarnings("unchecked") @Override public Array getArray() throws SQLException {\r
+      final Object o = getObject();\r
+      if (o == null) {\r
+        return null;\r
+      }\r
+      if (o instanceof ArrayImpl) {\r
+        return (ArrayImpl) o;\r
+      }\r
+      // If it's not an Array already, assume it is a List.\r
+      return new ArrayImpl((List<Object>) o, this);\r
+    }\r
+\r
+    @Override public String getString() throws SQLException {\r
+      final Array array = getArray();\r
+      return array == null ? null : array.toString();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is a STRUCT;\r
+   * corresponds to {@link java.sql.Types#STRUCT}.\r
+   */\r
+  private static class StructAccessor extends AccessorImpl {\r
+    private final List<Accessor> fieldAccessors;\r
+\r
+    private StructAccessor(Getter getter, List<Accessor> fieldAccessors) {\r
+      super(getter);\r
+      this.fieldAccessors = fieldAccessors;\r
+    }\r
+\r
+    @Override public Object getObject() throws SQLException {\r
+      return getStruct();\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    @Override public <T> T getObject(Class<T> clz) throws SQLException {\r
+      // getStruct() is not exposed on Accessor, only AccessorImpl. getObject(Class) is exposed,\r
+      // so we can make it do the right thing (call getStruct()).\r
+      if (clz.equals(Struct.class)) {\r
+        return (T) getStruct();\r
+      }\r
+      return super.getObject(clz);\r
+    }\r
+\r
+    @Override public Struct getStruct() throws SQLException {\r
+      final Object o = super.getObject();\r
+      if (o == null) {\r
+        return null;\r
+      } else if (o instanceof StructImpl) {\r
+        return (StructImpl) o;\r
+      } else if (o instanceof List) {\r
+        return new StructImpl((List) o);\r
+      } else {\r
+        final List<Object> list = new ArrayList<>();\r
+        for (Accessor fieldAccessor : fieldAccessors) {\r
+          list.add(fieldAccessor.getObject());\r
+        }\r
+        return new StructImpl(list);\r
+      }\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Accessor that assumes that the underlying value is an OBJECT;\r
+   * corresponds to {@link java.sql.Types#JAVA_OBJECT}.\r
+   */\r
+  private static class ObjectAccessor extends AccessorImpl {\r
+    private ObjectAccessor(Getter getter) {\r
+      super(getter);\r
+    }\r
+  }\r
+\r
+  /** Gets a value from a particular field of the current record of this\r
+   * cursor. */\r
+  protected interface Getter {\r
+    Object getObject() throws SQLException;\r
+\r
+    boolean wasNull() throws SQLException;\r
+  }\r
+\r
+  /** Abstract implementation of {@link Getter}. */\r
+  protected abstract class AbstractGetter implements Getter {\r
+    public boolean wasNull() throws SQLException {\r
+      return wasNull[0];\r
+    }\r
+  }\r
+\r
+  /** Implementation of {@link Getter} that returns the current contents of\r
+   * a mutable slot. */\r
+  public class SlotGetter implements Getter {\r
+    public Object slot;\r
+\r
+    public Object getObject() throws SQLException {\r
+      return slot;\r
+    }\r
+\r
+    public boolean wasNull() throws SQLException {\r
+      return slot == null;\r
+    }\r
+  }\r
+\r
+  /** Implementation of {@link Getter} that returns the value of a given field\r
+   * of the current contents of another getter. */\r
+  public class StructGetter implements Getter {\r
+    public final Getter getter;\r
+    private final ColumnMetaData columnMetaData;\r
+\r
+    public StructGetter(Getter getter, ColumnMetaData columnMetaData) {\r
+      this.getter = getter;\r
+      this.columnMetaData = columnMetaData;\r
+    }\r
+\r
+    public Object getObject() throws SQLException {\r
+      try {\r
+        final Object o = getter.getObject();\r
+        if (o instanceof Object[]) {\r
+          Object[] objects = (Object[]) o;\r
+          return objects[columnMetaData.ordinal];\r
+        }\r
+        final Field field = o.getClass().getField(columnMetaData.label);\r
+        return field.get(getter.getObject());\r
+      } catch (IllegalAccessException | NoSuchFieldException e) {\r
+        throw new SQLException(e);\r
+      }\r
+    }\r
+\r
+    public boolean wasNull() throws SQLException {\r
+      return getObject() == null;\r
+    }\r
+  }\r
+}\r
+\r
+// End AbstractCursor.java\r
index d8b5256..2bd26ff 100755 (executable)
@@ -7,9 +7,9 @@
  * 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
- * 
+ *
+ *             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.
  */
 package org.onap.music.logging;
 
+import static com.att.eelf.configuration.Configuration.MDC_ALERT_SEVERITY;
+import static com.att.eelf.configuration.Configuration.MDC_INSTANCE_UUID;
+import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
 import static com.att.eelf.configuration.Configuration.MDC_SERVER_FQDN;
 import static com.att.eelf.configuration.Configuration.MDC_SERVER_IP_ADDRESS;
 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_INSTANCE_ID;
 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
-
+import java.io.IOException;
+import java.io.InputStream;
 import java.net.InetAddress;
 import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-
 import javax.servlet.http.HttpServletRequest;
-
 import org.slf4j.MDC;
-
 import com.att.eelf.configuration.EELFLogger;
 import com.att.eelf.configuration.EELFManager;
 import com.att.eelf.configuration.SLF4jWrapper;
 
 public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
 
+
        public static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
        public static final EELFLogger applicationLogger = EELFManager.getInstance().getApplicationLogger();
        public static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
        public static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
        public static final EELFLogger debugLogger = EELFManager.getInstance().getDebugLogger();
+       // DateTime Format according to the ECOMP Application Logging Guidelines.
+               private static final SimpleDateFormat ecompLogDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
+               
 
        private String className;
-       private static ConcurrentMap<String, EELFLoggerDelegate> classMap = new ConcurrentHashMap<>();
+       private static ConcurrentMap<String, EELFLoggerDelegate> classMap = new ConcurrentHashMap<String, EELFLoggerDelegate>();
 
        public EELFLoggerDelegate(final String className) {
                super(className);
@@ -92,7 +100,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         */
        public void trace(EELFLogger logger, String msg) {
                if (logger.isTraceEnabled()) {
+                       MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                        logger.trace(msg);
+                       MDC.remove(LoggerProperties.MDC_CLASS_NAME);
                }
        }
 
@@ -105,7 +115,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         */
        public void trace(EELFLogger logger, String msg, Object... arguments) {
                if (logger.isTraceEnabled()) {
+                       MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                        logger.trace(msg, arguments);
+                       MDC.remove(LoggerProperties.MDC_CLASS_NAME);
                }
        }
 
@@ -118,7 +130,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         */
        public void trace(EELFLogger logger, String msg, Throwable th) {
                if (logger.isTraceEnabled()) {
+                       MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                        logger.trace(msg, th);
+                       MDC.remove(LoggerProperties.MDC_CLASS_NAME);
                }
        }
 
@@ -130,7 +144,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         */
        public void debug(EELFLogger logger, String msg) {
                if (logger.isDebugEnabled()) {
+                       MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                        logger.debug(msg);
+                       MDC.remove(LoggerProperties.MDC_CLASS_NAME);
                }
        }
 
@@ -143,7 +159,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         */
        public void debug(EELFLogger logger, String msg, Object... arguments) {
                if (logger.isDebugEnabled()) {
+                       MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                        logger.debug(msg, arguments);
+                       MDC.remove(LoggerProperties.MDC_CLASS_NAME);
                }
        }
 
@@ -156,7 +174,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         */
        public void debug(EELFLogger logger, String msg, Throwable th) {
                if (logger.isDebugEnabled()) {
+                       MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                        logger.debug(msg, th);
+                       MDC.remove(LoggerProperties.MDC_CLASS_NAME);
                }
        }
 
@@ -167,7 +187,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param msg
         */
        public void info(EELFLogger logger, String msg) {
-               logger.info(className + " - "+msg);
+               MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
+               logger.info(msg);
+               MDC.remove(LoggerProperties.MDC_CLASS_NAME);
        }
 
        /**
@@ -178,7 +200,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param arguments
         */
        public void info(EELFLogger logger, String msg, Object... arguments) {
+               MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                logger.info(msg, arguments);
+               MDC.remove(LoggerProperties.MDC_CLASS_NAME);
        }
 
        /**
@@ -189,7 +213,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param th
         */
        public void info(EELFLogger logger, String msg, Throwable th) {
+               MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                logger.info(msg, th);
+               MDC.remove(LoggerProperties.MDC_CLASS_NAME);
        }
 
        /**
@@ -199,7 +225,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param msg
         */
        public void warn(EELFLogger logger, String msg) {
+               MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                logger.warn(msg);
+               MDC.remove(LoggerProperties.MDC_CLASS_NAME);
        }
 
        /**
@@ -210,7 +238,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param arguments
         */
        public void warn(EELFLogger logger, String msg, Object... arguments) {
+               MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                logger.warn(msg, arguments);
+               MDC.remove(LoggerProperties.MDC_CLASS_NAME);
        }
 
        /**
@@ -221,7 +251,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param th
         */
        public void warn(EELFLogger logger, String msg, Throwable th) {
+               MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
                logger.warn(msg, th);
+               MDC.remove(LoggerProperties.MDC_CLASS_NAME);
        }
 
        /**
@@ -231,7 +263,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param msg
         */
        public void error(EELFLogger logger, String msg) {
-               logger.error(className+ " - " + msg);
+               MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
+               logger.error(msg);
+               MDC.remove(LoggerProperties.MDC_CLASS_NAME);
        }
 
        /**
@@ -242,7 +276,9 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param arguments
         */
        public void error(EELFLogger logger, String msg, Object... arguments) {
-               logger.error(msg, arguments);
+               MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
+               logger.warn(msg, arguments);
+               MDC.remove(LoggerProperties.MDC_CLASS_NAME);
        }
 
        /**
@@ -253,19 +289,11 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param th
         */
        public void error(EELFLogger logger, String msg, Throwable th) {
-               logger.error(msg, th);
+               MDC.put(LoggerProperties.MDC_CLASS_NAME, className);
+               logger.warn(msg, th);
+               MDC.remove(LoggerProperties.MDC_CLASS_NAME);
        }
 
-       /**
-        * Logs a message with the associated alarm severity at error level.
-        * 
-        * @param logger
-        * @param msg
-        * @param severtiy
-        */
-       public void error(EELFLogger logger, String msg, Object /*AlarmSeverityEnum*/ severtiy) {
-               logger.error(msg);
-       }
 
        /**
         * Initializes the logger context.
@@ -277,11 +305,30 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
                info(applicationLogger, msg);
                error(errorLogger, msg);
                debug(debugLogger, msg);
-        info(auditLogger, msg);
+               // Audit and metrics logger must be told start AND stop times
+               final String currentDateTime = getCurrentDateTimeUTC();
+               // Set the MDC with audit properties
+               MDC.put(LoggerProperties.AUDITLOG_BEGIN_TIMESTAMP, currentDateTime);
+               MDC.put(LoggerProperties.AUDITLOG_END_TIMESTAMP, currentDateTime);
+               info(auditLogger, msg);
+               MDC.remove(LoggerProperties.AUDITLOG_BEGIN_TIMESTAMP);
+               MDC.remove(LoggerProperties.AUDITLOG_END_TIMESTAMP);
+               // Set the MDC with metrics properties
+               MDC.put(LoggerProperties.METRICSLOG_BEGIN_TIMESTAMP, currentDateTime);
+               MDC.put(LoggerProperties.METRICSLOG_END_TIMESTAMP, currentDateTime);
                info(metricsLogger, msg);
+               MDC.remove(LoggerProperties.METRICSLOG_BEGIN_TIMESTAMP);
+               MDC.remove(LoggerProperties.METRICSLOG_END_TIMESTAMP);
+       }
+       
+       
+       public static String getCurrentDateTimeUTC() {
+               String currentDateTime = ecompLogDateFormat.format(new Date());
+               return currentDateTime;
        }
 
 
+       
        /**
         * Builds a message using a template string and the arguments.
         * 
@@ -289,7 +336,6 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param args
         * @return
         */
-       @SuppressWarnings("unused")
        private String formatMessage(String message, Object... args) {
                StringBuilder sbFormattedMessage = new StringBuilder();
                if (args != null && args.length > 0 && message != null && message != "") {
@@ -307,9 +353,11 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         */
        private void setGlobalLoggingContext() {
                MDC.put(MDC_SERVICE_INSTANCE_ID, "");
+               MDC.put(MDC_ALERT_SEVERITY, AlarmSeverityEnum.INFORMATIONAL.toString());
                try {
                        MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getHostName());
                        MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress());
+                       MDC.put(MDC_INSTANCE_UUID, LoggerProperties.getProperty(LoggerProperties.INSTANCE_UUID));
                } catch (Exception e) {
                        errorLogger.error("setGlobalLoggingContext failed", e);
                }
@@ -335,23 +383,185 @@ public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
         * @param req
         * @param appName
         */
-       public void setRequestBasedDefaultsIntoGlobalLoggingContext(HttpServletRequest req, String appName) {
+       public void setRequestBasedDefaultsIntoGlobalLoggingContext(HttpServletRequest req, String appName,String reqId,String loginId) {// Load the default fields
                // Load the default fields
-               setGlobalLoggingContext();
+                               setGlobalLoggingContext();
+
+                               // Load the request based fields
+                               if (req != null) {
+                                       // Load the Request into MDC context.
+                                       
+                                       MDC.put(MDC_KEY_REQUEST_ID, reqId);
+
+                                       // Load user agent into MDC context, if available.
+                                       String accessingClient = req.getHeader(LoggerProperties.USERAGENT_NAME);
+                                       if (accessingClient != null && !"".equals(accessingClient) && (accessingClient.contains("Mozilla")
+                                                       || accessingClient.contains("Chrome") || accessingClient.contains("Safari"))) {
+                                               accessingClient = appName + "_FE";
+                                       }
+                                       MDC.put(LoggerProperties.PARTNER_NAME, accessingClient);
+
+                                       // Protocol, Rest URL & Rest Path
+                                       MDC.put(LoggerProperties.FULL_URL, LoggerProperties.UNKNOWN);
+                                       MDC.put(LoggerProperties.PROTOCOL, LoggerProperties.HTTP);
+                                       String restURL = getFullURL(req);
+                                       if (restURL != null && restURL != "") {
+                                               MDC.put(LoggerProperties.FULL_URL, restURL);
+                                               if (restURL.toLowerCase().contains("https")) {
+                                                       MDC.put(LoggerProperties.PROTOCOL, LoggerProperties.HTTPS);
+                                               }
+                                       }
+
+                                       // Rest Path
+                                       MDC.put(MDC_SERVICE_NAME, req.getServletPath());
+
+                                       // Client IPAddress i.e. IPAddress of the remote host who is making
+                                       // this request.
+                                       String clientIPAddress = req.getHeader("X-FORWARDED-FOR");
+                                       if (clientIPAddress == null) {
+                                               clientIPAddress = req.getRemoteAddr();
+                                       }
+                                       MDC.put(LoggerProperties.CLIENT_IP_ADDRESS, clientIPAddress);
+
+                                       // Load loginId into MDC context.
+                                       MDC.put(LoggerProperties.MDC_LOGIN_ID, "Unknown");
+
+                               
+
+                                       if (loginId != null && loginId != "") {
+                                               MDC.put(LoggerProperties.MDC_LOGIN_ID, loginId);
+                                       }
+                               }
+       }
+       
+
+       
+       
+       public static String getFullURL(HttpServletRequest request) {
+               if (request != null) {
+                       StringBuffer requestURL = request.getRequestURL();
+                       String queryString = request.getQueryString();
+
+                       if (queryString == null) {
+                               return requestURL.toString();
+                       } else {
+                               return requestURL.append('?').append(queryString).toString();
+                       }
+               }
+               return "";
+       }
+       
+       
 
-               // Load the request based fields
-               if (req != null) {
+}
 
+enum AlarmSeverityEnum {
+    CRITICAL("1"),
+    MAJOR("2"), 
+    MINOR("3"), 
+    INFORMATIONAL("4"), 
+    NONE("0");
 
-                       // Rest Path
-                       MDC.put(MDC_SERVICE_NAME, req.getServletPath());
+    private final String severity;
 
-                       // Client IPAddress i.e. IPAddress of the remote host who is making
-                       // this request.
-                       String clientIPAddress = req.getHeader("X-FORWARDED-FOR");
-                       if (clientIPAddress == null) {
-                               clientIPAddress = req.getRemoteAddr();
-                       }
-               }
-       }
+    AlarmSeverityEnum(String severity) {
+        this.severity = severity;
+    }
+
+    public String severity() {
+        return severity;
+    }
+}
+
+class LoggerProperties {
+
+    
+public static final String MDC_APPNAME = "AppName";
+public static final String MDC_REST_PATH = "RestPath";
+public static final String MDC_REST_METHOD = "RestMethod";
+public static final String INSTANCE_UUID = "instance_uuid";
+public static final String MDC_CLASS_NAME = "class";
+public static final String MDC_LOGIN_ID = "LoginId";
+public static final String MDC_TIMER = "Timer";
+public static final String PARTNER_NAME = "PartnerName";
+public static final String FULL_URL = "Full-URL";
+public static final String AUDITLOG_BEGIN_TIMESTAMP = "AuditLogBeginTimestamp";
+public static final String AUDITLOG_END_TIMESTAMP = "AuditLogEndTimestamp";
+public static final String METRICSLOG_BEGIN_TIMESTAMP = "MetricsLogBeginTimestamp";
+public static final String METRICSLOG_END_TIMESTAMP = "MetricsLogEndTimestamp";
+public static final String CLIENT_IP_ADDRESS = "ClientIPAddress";
+public static final String STATUS_CODE = "StatusCode";
+public static final String RESPONSE_CODE = "ResponseCode";
+
+public static final String HTTP = "HTTP";
+public static final String HTTPS = "HTTPS";
+public static final String UNKNOWN = "Unknown";
+public static final String PROTOCOL = "PROTOCOL";
+public static final String USERAGENT_NAME = "user-agent";
+public static final String USER_ATTRIBUTE_NAME = "user_attribute_name";
+
+
+private LoggerProperties(){}
+
+private static Properties properties;
+
+private static String propertyFileName = "logger.properties";
+
+private static final Object lockObject = new Object();
+
+//private static final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(LoggerProperties.class);
+
+/**
+ * Gets the property value for the specified key. If a value is found, leading
+ * and trailing space is trimmed.
+ *
+ * @param property
+ *            Property key
+ * @return Value for the named property; null if the property file was not
+ *         loaded or the key was not found.
+ */
+public static String getProperty(String property) {
+    if (properties == null) {
+        synchronized (lockObject) {
+            try {
+                if (!initialize()) {
+//                  logger.error(EELFLoggerDelegate.errorLogger, "Failed to read property file " + propertyFileName);
+                    return null;
+                }
+            } catch (IOException e) {
+//              logger.error(EELFLoggerDelegate.errorLogger, "Failed to read property file " + propertyFileName ,e);
+                return null;
+            }
+        }
+    }
+    String value = properties.getProperty(property);
+    if (value != null)
+        value = value.trim();
+    return value;
+}
+
+/**
+ * Reads properties from a portal.properties file on the classpath.
+ * 
+ * Clients do NOT need to call this method. Clients MAY call this method to test
+ * whether the properties file can be loaded successfully.
+ * 
+ * @return True if properties were successfully loaded, else false.
+ * @throws IOException
+ *             On failure
+ */
+private static boolean initialize() throws IOException {
+    if (properties != null)
+        return true;
+    InputStream in = LoggerProperties.class.getClassLoader().getResourceAsStream(propertyFileName);
+    if (in == null)
+        return false;
+    properties = new Properties();
+    try {
+        properties.load(in);
+    } finally {
+        in.close();
+    }
+    return true;
 }
+}
\ No newline at end of file
index af973b8..b9e9dcf 100755 (executable)
   -->
   <!--<jmxConfigurator /> -->
 
+  <!--change this when deploying on server -->
+  <property name="log.home" value="." />
   <!--  specify the component name -->
-  <property name="catalina.home" value="/var/log/metric/" />
   <property name="componentName" value="mdbc"></property>
   
   <!--  specify the base path of the log directory -->
-  <property name="logDirPrefix" value="${catalina.base}/logs"></property>
+  <property name="logDirPrefix" value="${log.home}/logs"></property>
   
   <!-- The directories where logs are written -->
   <property name="logDirectory" value="${logDirPrefix}/${componentName}" />
-  <!-- Can easily relocate debug logs by modifying this path. -->
-  <property name="debugLogDirectory" value="${logDirPrefix}/${componentName}" />
-  
+
+   
   <!--  log file names -->
   <property name="generalLogName" value="application" />
   <property name="errorLogName" value="error" />
   
   <!-- 1610 Logging Fields Format Revisions --> 
   <property name="auditLoggerPattern"
-       value="%X{AuditLogBeginTimestamp}|%X{AuditLogEndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{Timer}|%X{ServerFQDN}|%X{ClientIPAddress}|%X{ClassName}|%X{Unused}|%X{ProcessKey}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}| %msg%n" />
+       value="%X{AuditLogBeginTimestamp}|%X{AuditLogEndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{Timer}|%X{ServerFQDN}|%X{ClientIPAddress}|%X{class}|%X{Unused}|%X{ProcessKey}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}| %msg%n" />
 
   <property name="metricsLoggerPattern"
-       value="%X{MetricsLogBeginTimestamp}|%X{MetricsLogEndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{Timer}|%X{ServerFQDN}|%X{ClientIPAddress}|%X{ClassName}|%X{Unused}|%X{ProcessKey}|%X{TargetVisualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}| %msg%n" />
+       value="%X{MetricsLogBeginTimestamp}|%X{MetricsLogEndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{Timer}|%X{ServerFQDN}|%X{ClientIPAddress}|%X{class}|%X{Unused}|%X{ProcessKey}|%X{TargetVisualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}| %msg%n" />
 
   <property name="errorLoggerPattern"
-       value="%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}|%X{RequestId}|%thread|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{ClassName}|%X{AlertSeverity}|%X{ErrorCode}|%X{ErrorDescription}| %msg%n" />
+       value="%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}|%X{RequestId}|%thread|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{class}|%X{AlertSeverity}|%X{ErrorCode}|%X{ErrorDescription}| %msg%n" />
 
   <property name="defaultLoggerPattern"
-       value="%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}|%X{RequestId}|%thread|%X{ClassName}| %msg%n" />
+       value="%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}|%X{RequestId}|%thread|%X{class}| %msg%n" />
 
   <!-- use %class so library logging calls yield their class name -->
   <property name="applicationLoggerPattern"
-       value="%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}|%X{RequestId}|%thread|%class{36}| %msg%n" />
+       value="%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}|%X{RequestId}|%thread|%X{class}| %msg%n" />
 
   <!-- Example evaluator filter applied against console appender -->
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
   
    <appender name="EELFDebug"
     class="ch.qos.logback.core.rolling.RollingFileAppender">
-    <file>${debugLogDirectory}/${debugLogName}.log</file>
+    <file>${logDirectory}/${debugLogName}.log</file>
     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> 
       <!-- daily rollover --> 
       <fileNamePattern>${logDirectory}/${debugLogName}.%d{yyyy-MM-dd}.log.zip</fileNamePattern> 
   
  
 
-  <logger name="com.att.eelf" level="info" additivity="false">
+  <logger name="com.att.eelf" level="debug" additivity="false">
     <appender-ref ref="asyncEELF" />
   </logger>
-
-  <logger name="com.att.eelf" level="info" additivity="false">
+   
+  <logger name="com.att.eelf.audit" level="debug" additivity="false">
     <appender-ref ref="asyncEELFAudit" />
   </logger>
   
-  <logger name="com.att.eelf" level="debug" additivity="false">
-    <appender-ref ref="asyncEELFDebug" />
+  <logger name="com.att.eelf.metrics" level="debug" additivity="false">
+        <appender-ref ref="asyncEELFMetrics" />
   </logger>
-       
-  <logger name="com.att.eelf.error" level="info" additivity="false">
-    <appender-ref ref="asyncEELFError" />
+    
+  <logger name="com.att.eelf.error" level="debug" additivity="false">
+       <appender-ref ref="asyncEELFError" />
   </logger>
-
-  <logger name="com.att.eelf.metrics" level="info" additivity="false">
-    <appender-ref ref="asyncEELFMetrics" />
-  </logger>      
+  
+   <logger name="com.att.eelf.debug" level="debug" additivity="false">
+        <appender-ref ref="asyncEELFDebug" />
+  </logger>
+  
     
   <root level="DEBUG">
     <appender-ref ref="asyncEELF" />
   </root>
 
-</configuration>
+</configuration>
\ No newline at end of file