aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstatta <statta@research.att.com>2019-05-17 14:55:18 -0400
committerstatta <statta@research.att.com>2019-05-17 14:58:50 -0400
commited4b4af2de4b02efd3f097323e9a999f905e60e6 (patch)
tree919a170162967b07443e7cf97b487dc25038cc2c
parent96933528fdd51e606e48d79941ce43249ffb48b6 (diff)
Fix Clob,Blob read and writes
Issue-ID: MUSIC-388 Change-Id: I3ddd84f097231a21423325b04c34a4a90e4ea0e0 Signed-off-by: statta <statta@research.att.com>
-rw-r--r--mdbc-server/src/main/java/org/apache/calcite/avatica/AvaticaSite.java612
-rw-r--r--mdbc-server/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java1504
-rwxr-xr-xmdbc-server/src/main/java/org/onap/music/logging/EELFLoggerDelegate.java286
-rwxr-xr-xmdbc-server/src/main/resources/logback.xml49
4 files changed, 2389 insertions, 62 deletions
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
index 0000000..5fd4e69
--- /dev/null
+++ b/mdbc-server/src/main/java/org/apache/calcite/avatica/AvaticaSite.java
@@ -0,0 +1,612 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.avatica;
+
+import org.apache.calcite.avatica.remote.TypedValue;
+import org.apache.calcite.avatica.util.Cursor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLXML;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.Calendar;
+
+/**
+ * A location that a value can be written to or read from.
+ */
+public class AvaticaSite {
+ final AvaticaParameter parameter;
+
+ /** Calendar is not thread-safe. But calendar is only used from within one
+ * thread, and we have to trust that clients are not modifying calendars
+ * that they pass to us in a method such as
+ * {@link java.sql.PreparedStatement#setTime(int, Time, Calendar)}, so we do
+ * not need to synchronize access. */
+ final Calendar calendar;
+ private final int index;
+ final TypedValue[] slots;
+
+ /** Value that means the parameter has been set to null.
+ * If value is null, parameter has not been set. */
+ public static final Object DUMMY_VALUE = Dummy.INSTANCE;
+
+ public AvaticaSite(AvaticaParameter parameter, Calendar calendar, int index,
+ TypedValue[] slots) {
+ assert calendar != null;
+ assert parameter != null;
+ assert slots != null;
+ this.parameter = parameter;
+ this.calendar = calendar;
+ this.index = index;
+ this.slots = slots;
+ }
+
+ private TypedValue wrap(ColumnMetaData.Rep rep, Object o,
+ Calendar calendar) {
+ return TypedValue.ofJdbc(rep, o, calendar);
+ }
+
+ private TypedValue wrap(ColumnMetaData.Rep rep, Object o) {
+ return TypedValue.ofJdbc(rep, o, calendar);
+ }
+
+ public boolean isSet(int index) {
+ return slots[index] != null;
+ }
+
+ public void setByte(byte o) {
+ slots[index] = wrap(ColumnMetaData.Rep.BYTE, o);
+ }
+
+ public void setChar(char o) {
+ slots[index] = wrap(ColumnMetaData.Rep.CHARACTER, o);
+ }
+
+ public void setShort(short o) {
+ slots[index] = wrap(ColumnMetaData.Rep.SHORT, o);
+ }
+
+ public void setInt(int o) {
+ slots[index] = wrap(ColumnMetaData.Rep.INTEGER, o);
+ }
+
+ public void setLong(long o) {
+ slots[index] = wrap(ColumnMetaData.Rep.LONG, o);
+ }
+
+ public void setBoolean(boolean o) {
+ slots[index] = wrap(ColumnMetaData.Rep.BOOLEAN, o);
+ }
+
+ public void setRowId(RowId x) {
+ slots[index] = wrap(ColumnMetaData.Rep.OBJECT, x);
+ }
+
+ public void setNString(String o) {
+ slots[index] = wrap(ColumnMetaData.Rep.STRING, o);
+ }
+
+ public void setNCharacterStream(Reader value, long length) {
+ }
+
+ public void setNClob(NClob value) {
+ slots[index] = wrap(ColumnMetaData.Rep.OBJECT, value);
+ }
+
+ public void setClob(Reader reader, long length) {
+ }
+
+ public void setBlob(InputStream inputStream, long length) {
+ }
+
+ public void setNClob(Reader reader, long length) {
+ }
+
+ public void setSQLXML(SQLXML xmlObject) {
+ slots[index] = wrap(ColumnMetaData.Rep.OBJECT, xmlObject);
+ }
+
+ public void setAsciiStream(InputStream x, long length) {
+ }
+
+ public void setBinaryStream(InputStream x, long length) {
+ }
+
+ public void setCharacterStream(Reader reader, long length) {
+ }
+
+ public void setAsciiStream(InputStream x) {
+ }
+
+ public void setBinaryStream(InputStream x) {
+ }
+
+ public void setCharacterStream(Reader reader) {
+ }
+
+ public void setNCharacterStream(Reader value) {
+ }
+
+ public void setClob(Reader reader) {
+ }
+
+ public void setClob(InputStream inputStream) {
+ }
+
+ public void setBlob(InputStream inputStream) {
+ }
+
+ public void setNClob(Reader reader) {
+ }
+
+ public void setUnicodeStream(InputStream x, int length) {
+ }
+
+ public void setFloat(float x) {
+ slots[index] = wrap(ColumnMetaData.Rep.FLOAT, x);
+ }
+
+ public void setDouble(double x) {
+ slots[index] = wrap(ColumnMetaData.Rep.DOUBLE, x);
+ }
+
+ public void setBigDecimal(BigDecimal x) {
+ slots[index] = wrap(ColumnMetaData.Rep.NUMBER, x);
+ }
+
+ public void setString(String x) {
+ slots[index] = wrap(ColumnMetaData.Rep.STRING, x);
+ }
+
+ public void setBytes(byte[] x) {
+ slots[index] = wrap(ColumnMetaData.Rep.BYTE_STRING, x);
+ }
+
+ public void setTimestamp(Timestamp x, Calendar calendar) {
+ slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_TIMESTAMP, x, calendar);
+ }
+
+ public void setTime(Time x, Calendar calendar) {
+ slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_TIME, x, calendar);
+ }
+
+ public void setDate(Date x, Calendar calendar) {
+ slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_DATE, x, calendar);
+ }
+
+ public void setObject(Object x, int targetSqlType) {
+ if (x == null || Types.NULL == targetSqlType) {
+ setNull(targetSqlType);
+ return;
+ }
+ switch (targetSqlType) {
+ case Types.CLOB:
+ if (x instanceof Clob) {
+ setClob((Clob) x);
+ break;
+ } else if (x instanceof InputStream) {
+ setClob((InputStream) x);
+ }
+ throw unsupportedCast(x.getClass(), Blob.class);
+ case Types.DATALINK:
+ case Types.NCLOB:
+ case Types.OTHER:
+ case Types.REF:
+ case Types.SQLXML:
+ case Types.STRUCT:
+ throw notImplemented();
+ case Types.ARRAY:
+ setArray(toArray(x));
+ break;
+ case Types.BIGINT:
+ setLong(toLong(x));
+ break;
+ case Types.BINARY:
+ case Types.LONGVARBINARY:
+ case Types.VARBINARY:
+ setBytes(toBytes(x));
+ break;
+ case Types.BIT:
+ case Types.BOOLEAN:
+ setBoolean(toBoolean(x));
+ break;
+ case Types.BLOB:
+ if (x instanceof Blob) {
+ setBlob((Blob) x);
+ break;
+ } else if (x instanceof InputStream) {
+ setBlob((InputStream) x);
+ }
+ throw unsupportedCast(x.getClass(), Blob.class);
+ case Types.DATE:
+ setDate(toDate(x), calendar);
+ break;
+ case Types.DECIMAL:
+ case Types.NUMERIC:
+ setBigDecimal(toBigDecimal(x));
+ break;
+ case Types.DISTINCT:
+ throw notImplemented();
+ case Types.DOUBLE:
+ case Types.FLOAT: // yes really; SQL FLOAT is up to 8 bytes
+ setDouble(toDouble(x));
+ break;
+ case Types.INTEGER:
+ setInt(toInt(x));
+ break;
+ case Types.JAVA_OBJECT:
+ setObject(x);
+ break;
+ case Types.LONGNVARCHAR:
+ case Types.LONGVARCHAR:
+ case Types.NVARCHAR:
+ case Types.VARCHAR:
+ case Types.CHAR:
+ case Types.NCHAR:
+ setString(toString(x));
+ break;
+ case Types.REAL:
+ setFloat(toFloat(x));
+ break;
+ case Types.ROWID:
+ if (x instanceof RowId) {
+ setRowId((RowId) x);
+ break;
+ }
+ throw unsupportedCast(x.getClass(), RowId.class);
+ case Types.SMALLINT:
+ setShort(toShort(x));
+ break;
+ case Types.TIME:
+ setTime(toTime(x), calendar);
+ break;
+ case Types.TIMESTAMP:
+ setTimestamp(toTimestamp(x), calendar);
+ break;
+ case Types.TINYINT:
+ setByte(toByte(x));
+ break;
+ default:
+ throw notImplemented();
+ }
+ }
+
+ /** Similar logic to {@link #setObject}. */
+ public static Object get(Cursor.Accessor accessor, int targetSqlType,
+ Calendar localCalendar) throws SQLException {
+ switch (targetSqlType) {
+ case Types.CLOB:
+ return accessor.getClob();
+ case Types.DATALINK:
+ case Types.NCLOB:
+ case Types.REF:
+ case Types.SQLXML:
+ case Types.STRUCT:
+ throw notImplemented();
+ case Types.ARRAY:
+ return accessor.getArray();
+ case Types.BIGINT:
+ final long aLong = accessor.getLong();
+ if (aLong == 0 && accessor.wasNull()) {
+ return null;
+ }
+ return aLong;
+ case Types.BINARY:
+ case Types.LONGVARBINARY:
+ case Types.VARBINARY:
+ return accessor.getBytes();
+ case Types.BIT:
+ case Types.BOOLEAN:
+ final boolean aBoolean = accessor.getBoolean();
+ if (!aBoolean && accessor.wasNull()) {
+ return null;
+ }
+ return aBoolean;
+ case Types.BLOB:
+ return accessor.getBlob();
+ case Types.DATE:
+ return accessor.getDate(localCalendar);
+ case Types.DECIMAL:
+ case Types.NUMERIC:
+ return accessor.getBigDecimal();
+ case Types.DISTINCT:
+ throw notImplemented();
+ case Types.DOUBLE:
+ case Types.FLOAT: // yes really; SQL FLOAT is up to 8 bytes
+ final double aDouble = accessor.getDouble();
+ if (aDouble == 0 && accessor.wasNull()) {
+ return null;
+ }
+ return aDouble;
+ case Types.INTEGER:
+ final int anInt = accessor.getInt();
+ if (anInt == 0 && accessor.wasNull()) {
+ return null;
+ }
+ return anInt;
+ case Types.JAVA_OBJECT:
+ case Types.OTHER:
+ return accessor.getObject();
+ case Types.LONGNVARCHAR:
+ case Types.LONGVARCHAR:
+ case Types.NVARCHAR:
+ case Types.VARCHAR:
+ case Types.CHAR:
+ case Types.NCHAR:
+ return accessor.getString();
+ case Types.REAL:
+ final float aFloat = accessor.getFloat();
+ if (aFloat == 0 && accessor.wasNull()) {
+ return null;
+ }
+ return aFloat;
+ case Types.ROWID:
+ throw notImplemented();
+ case Types.SMALLINT:
+ final short aShort = accessor.getShort();
+ if (aShort == 0 && accessor.wasNull()) {
+ return null;
+ }
+ return aShort;
+ case Types.TIME:
+ return accessor.getTime(localCalendar);
+ case Types.TIMESTAMP:
+ return accessor.getTimestamp(localCalendar);
+ case Types.TINYINT:
+ final byte aByte = accessor.getByte();
+ if (aByte == 0 && accessor.wasNull()) {
+ return null;
+ }
+ return aByte;
+ default:
+ throw notImplemented();
+ }
+ }
+
+ public void setObject(Object x) {
+ slots[index] = TypedValue.ofJdbc(x, calendar);
+ }
+
+ public void setNull(int sqlType) {
+ slots[index] = wrap(ColumnMetaData.Rep.OBJECT, null);
+ }
+
+ public void setRef(Ref x) {
+ }
+
+ public void setBlob(Blob x) {
+ InputStream iStream;
+ try {
+ iStream = x.getBinaryStream();
+ int length =0;
+ while(iStream.read() != -1)
+ length ++;
+ setBytes(x.getBytes(1, length));
+
+ } catch (SQLException | IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void setClob(Clob x) {
+ }
+
+ public void setArray(Array x) {
+ slots[index] = wrap(ColumnMetaData.Rep.ARRAY, x);
+ }
+
+ public void setNull(int sqlType, String typeName) {
+ }
+
+ public void setURL(URL x) {
+ }
+
+ public void setObject(Object x, int targetSqlType,
+ int scaleOrLength) {
+ }
+
+ private static RuntimeException unsupportedCast(Class<?> from, Class<?> to) {
+ return new UnsupportedOperationException("Cannot convert from "
+ + from.getCanonicalName() + " to " + to.getCanonicalName());
+ }
+
+ private static RuntimeException notImplemented() {
+ return new RuntimeException("not implemented");
+ }
+
+ private static Array toArray(Object x) {
+ if (x instanceof Array) {
+ return (Array) x;
+ }
+ throw unsupportedCast(x.getClass(), Array.class);
+ }
+
+ public static BigDecimal toBigDecimal(Object x) {
+ if (x instanceof BigDecimal) {
+ return (BigDecimal) x;
+ } else if (x instanceof BigInteger) {
+ return new BigDecimal((BigInteger) x);
+ } else if (x instanceof Number) {
+ if (x instanceof Double || x instanceof Float) {
+ return new BigDecimal(((Number) x).doubleValue());
+ } else {
+ return new BigDecimal(((Number) x).longValue());
+ }
+ } else if (x instanceof Boolean) {
+ return (Boolean) x ? BigDecimal.ONE : BigDecimal.ZERO;
+ } else if (x instanceof String) {
+ return new BigDecimal((String) x);
+ }
+ throw unsupportedCast(x.getClass(), BigDecimal.class);
+ }
+
+ private static boolean toBoolean(Object x) {
+ if (x instanceof Boolean) {
+ return (Boolean) x;
+ } else if (x instanceof Number) {
+ return ((Number) x).intValue() != 0;
+ } else if (x instanceof String) {
+ String s = (String) x;
+ if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("yes")) {
+ return true;
+ } else if (s.equalsIgnoreCase("false") || s.equalsIgnoreCase("no")) {
+ return false;
+ }
+ }
+ throw unsupportedCast(x.getClass(), Boolean.TYPE);
+ }
+
+ private static byte toByte(Object x) {
+ if (x instanceof Number) {
+ return ((Number) x).byteValue();
+ } else if (x instanceof Boolean) {
+ return (Boolean) x ? (byte) 1 : (byte) 0;
+ } else if (x instanceof String) {
+ return Byte.parseByte((String) x);
+ } else {
+ throw unsupportedCast(x.getClass(), Byte.TYPE);
+ }
+ }
+
+ private static byte[] toBytes(Object x) {
+ if (x instanceof byte[]) {
+ return (byte[]) x;
+ }
+ if (x instanceof String) {
+ return ((String) x).getBytes(StandardCharsets.UTF_8);
+ }
+ throw unsupportedCast(x.getClass(), byte[].class);
+ }
+
+ private static Date toDate(Object x) {
+ if (x instanceof String) {
+ return Date.valueOf((String) x);
+ }
+ return new Date(toLong(x));
+ }
+
+ private static Time toTime(Object x) {
+ if (x instanceof String) {
+ return Time.valueOf((String) x);
+ }
+ return new Time(toLong(x));
+ }
+
+ private static Timestamp toTimestamp(Object x) {
+ if (x instanceof String) {
+ return Timestamp.valueOf((String) x);
+ }
+ return new Timestamp(toLong(x));
+ }
+
+ private static double toDouble(Object x) {
+ if (x instanceof Number) {
+ return ((Number) x).doubleValue();
+ } else if (x instanceof Boolean) {
+ return (Boolean) x ? 1D : 0D;
+ } else if (x instanceof String) {
+ return Double.parseDouble((String) x);
+ } else {
+ throw unsupportedCast(x.getClass(), Double.TYPE);
+ }
+ }
+
+ private static float toFloat(Object x) {
+ if (x instanceof Number) {
+ return ((Number) x).floatValue();
+ } else if (x instanceof Boolean) {
+ return (Boolean) x ? 1F : 0F;
+ } else if (x instanceof String) {
+ return Float.parseFloat((String) x);
+ } else {
+ throw unsupportedCast(x.getClass(), Float.TYPE);
+ }
+ }
+
+ private static int toInt(Object x) {
+ if (x instanceof Number) {
+ return ((Number) x).intValue();
+ } else if (x instanceof Boolean) {
+ return (Boolean) x ? 1 : 0;
+ } else if (x instanceof String) {
+ return Integer.parseInt((String) x);
+ } else {
+ throw unsupportedCast(x.getClass(), Integer.TYPE);
+ }
+ }
+
+ private static long toLong(Object x) {
+ if (x instanceof Number) {
+ return ((Number) x).longValue();
+ } else if (x instanceof Boolean) {
+ return (Boolean) x ? 1L : 0L;
+ } else if (x instanceof String) {
+ return Long.parseLong((String) x);
+ } else {
+ throw unsupportedCast(x.getClass(), Long.TYPE);
+ }
+ }
+
+ private static short toShort(Object x) {
+ if (x instanceof Number) {
+ return ((Number) x).shortValue();
+ } else if (x instanceof Boolean) {
+ return (Boolean) x ? (short) 1 : (short) 0;
+ } else if (x instanceof String) {
+ return Short.parseShort((String) x);
+ } else {
+ throw unsupportedCast(x.getClass(), Short.TYPE);
+ }
+ }
+
+ private static String toString(Object x) {
+ if (x instanceof String) {
+ return (String) x;
+ } else if (x instanceof Character
+ || x instanceof Boolean) {
+ return x.toString();
+ }
+ throw unsupportedCast(x.getClass(), String.class);
+ }
+
+ /** Singleton value to denote parameters that have been set to null (as
+ * opposed to not set).
+ *
+ * <p>Not a valid value for a parameter.
+ *
+ * <p>As an enum, it is serializable by Jackson. */
+ private enum Dummy {
+ INSTANCE
+ }
+}
+
+// End AvaticaSite.java
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
index 0000000..cacbb8b
--- /dev/null
+++ b/mdbc-server/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
@@ -0,0 +1,1504 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.avatica.util;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.SQLDataException;
+import java.sql.SQLException;
+import java.sql.SQLXML;
+import java.sql.Struct;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Map;
+import javax.sql.rowset.serial.SerialBlob;
+import org.apache.calcite.avatica.AvaticaSite;
+import org.apache.calcite.avatica.AvaticaUtils;
+import org.apache.calcite.avatica.ColumnMetaData;
+
+/**
+ * Base class for implementing a cursor.
+ *
+ * <p>Derived class needs to provide {@link Getter} and can override
+ * {@link org.apache.calcite.avatica.util.Cursor.Accessor} implementations if it
+ * wishes.</p>
+ */
+public abstract class AbstractCursor implements Cursor {
+ /**
+ * Slot into which each accessor should write whether the
+ * value returned was null.
+ */
+ protected final boolean[] wasNull = {false};
+
+ protected AbstractCursor() {
+ }
+
+ public boolean wasNull() {
+ return wasNull[0];
+ }
+
+ public List<Accessor> createAccessors(List<ColumnMetaData> types,
+ Calendar localCalendar, ArrayImpl.Factory factory) {
+ List<Accessor> accessors = new ArrayList<>();
+ for (ColumnMetaData type : types) {
+ accessors.add(
+ createAccessor(type, accessors.size(), localCalendar, factory));
+ }
+ return accessors;
+ }
+
+ protected Accessor createAccessor(ColumnMetaData columnMetaData, int ordinal,
+ Calendar localCalendar, ArrayImpl.Factory factory) {
+ // Create an accessor appropriate to the underlying type; the accessor
+ // can convert to any type in the same family.
+ Getter getter = createGetter(ordinal);
+ return createAccessor(columnMetaData, getter, localCalendar, factory);
+ }
+
+ protected Accessor createAccessor(ColumnMetaData columnMetaData,
+ Getter getter, Calendar localCalendar, ArrayImpl.Factory factory) {
+ switch (columnMetaData.type.rep) {
+ case NUMBER:
+ switch (columnMetaData.type.id) {
+ case Types.TINYINT:
+ case Types.SMALLINT:
+ case Types.INTEGER:
+ case Types.BIGINT:
+ case Types.REAL:
+ case Types.FLOAT:
+ case Types.DOUBLE:
+ case Types.NUMERIC:
+ case Types.DECIMAL:
+ return new NumberAccessor(getter, columnMetaData.scale);
+ }
+ }
+ switch (columnMetaData.type.id) {
+ case Types.TINYINT:
+ return new ByteAccessor(getter);
+ case Types.SMALLINT:
+ return new ShortAccessor(getter);
+ case Types.INTEGER:
+ return new IntAccessor(getter);
+ case Types.BIGINT:
+ return new LongAccessor(getter);
+ case Types.BOOLEAN:
+ return new BooleanAccessor(getter);
+ case Types.REAL:
+ return new FloatAccessor(getter);
+ case Types.FLOAT:
+ case Types.DOUBLE:
+ return new DoubleAccessor(getter);
+ case Types.DECIMAL:
+ return new BigDecimalAccessor(getter);
+ case Types.CHAR:
+ switch (columnMetaData.type.rep) {
+ case PRIMITIVE_CHAR:
+ case CHARACTER:
+ return new StringFromCharAccessor(getter, columnMetaData.displaySize);
+ default:
+ return new FixedStringAccessor(getter, columnMetaData.displaySize);
+ }
+ case Types.VARCHAR:
+ return new StringAccessor(getter);
+ case Types.BINARY:
+ case Types.VARBINARY:
+ switch (columnMetaData.type.rep) {
+ case STRING:
+ return new BinaryFromStringAccessor(getter);
+ default:
+ return new BinaryAccessor(getter);
+ }
+ case Types.DATE:
+ switch (columnMetaData.type.rep) {
+ case PRIMITIVE_INT:
+ case INTEGER:
+ case NUMBER:
+ return new DateFromNumberAccessor(getter, localCalendar);
+ case JAVA_SQL_DATE:
+ return new DateAccessor(getter);
+ default:
+ throw new AssertionError("bad " + columnMetaData.type.rep);
+ }
+ case Types.TIME:
+ switch (columnMetaData.type.rep) {
+ case PRIMITIVE_INT:
+ case INTEGER:
+ case NUMBER:
+ return new TimeFromNumberAccessor(getter, localCalendar);
+ case JAVA_SQL_TIME:
+ return new TimeAccessor(getter);
+ default:
+ throw new AssertionError("bad " + columnMetaData.type.rep);
+ }
+ case Types.TIMESTAMP:
+ switch (columnMetaData.type.rep) {
+ case PRIMITIVE_LONG:
+ case LONG:
+ case NUMBER:
+ return new TimestampFromNumberAccessor(getter, localCalendar);
+ case JAVA_SQL_TIMESTAMP:
+ return new TimestampAccessor(getter);
+ case JAVA_UTIL_DATE:
+ return new TimestampFromUtilDateAccessor(getter, localCalendar);
+ default:
+ throw new AssertionError("bad " + columnMetaData.type.rep);
+ }
+ case 2013: // TIME_WITH_TIMEZONE
+ switch (columnMetaData.type.rep) {
+ case STRING:
+ return new StringAccessor(getter);
+ default:
+ throw new AssertionError("bad " + columnMetaData.type.rep);
+ }
+ case 2014: // TIMESTAMP_WITH_TIMEZONE
+ switch (columnMetaData.type.rep) {
+ case STRING:
+ return new StringAccessor(getter);
+ default:
+ throw new AssertionError("bad " + columnMetaData.type.rep);
+ }
+ case Types.ARRAY:
+ final ColumnMetaData.ArrayType arrayType =
+ (ColumnMetaData.ArrayType) columnMetaData.type;
+ final SlotGetter componentGetter = new SlotGetter();
+ final Accessor componentAccessor =
+ createAccessor(ColumnMetaData.dummy(arrayType.getComponent(), true),
+ componentGetter, localCalendar, factory);
+ return new ArrayAccessor(getter, arrayType.getComponent(), componentAccessor,
+ componentGetter, factory);
+ case Types.STRUCT:
+ switch (columnMetaData.type.rep) {
+ case OBJECT:
+ final ColumnMetaData.StructType structType =
+ (ColumnMetaData.StructType) columnMetaData.type;
+ List<Accessor> accessors = new ArrayList<>();
+ for (ColumnMetaData column : structType.columns) {
+ final Getter fieldGetter =
+ structType.columns.size() == 1
+ ? getter
+ : new StructGetter(getter, column);
+ accessors.add(
+ createAccessor(column, fieldGetter, localCalendar, factory));
+ }
+ return new StructAccessor(getter, accessors);
+ default:
+ throw new AssertionError("bad " + columnMetaData.type.rep);
+ }
+ case Types.JAVA_OBJECT:
+ case Types.OTHER: // e.g. map
+ if (columnMetaData.type.getName().startsWith("INTERVAL_")) {
+ int end = columnMetaData.type.getName().indexOf("(");
+ if (end < 0) {
+ end = columnMetaData.type.getName().length();
+ }
+ TimeUnitRange range =
+ TimeUnitRange.valueOf(
+ columnMetaData.type.getName().substring("INTERVAL_".length(), end));
+ if (range.monthly()) {
+ return new IntervalYearMonthAccessor(getter, range);
+ } else {
+ return new IntervalDayTimeAccessor(getter, range,
+ columnMetaData.scale);
+ }
+ }
+ return new ObjectAccessor(getter);
+ default:
+ throw new RuntimeException("unknown type " + columnMetaData.type.id);
+ }
+ }
+
+ protected abstract Getter createGetter(int ordinal);
+
+ public abstract boolean next();
+
+ /** Accesses a timestamp value as a string.
+ * The timestamp is in SQL format (e.g. "2013-09-22 22:30:32"),
+ * not Java format ("2013-09-22 22:30:32.123"). */
+ private static String timestampAsString(long v, Calendar calendar) {
+ if (calendar != null) {
+ v -= calendar.getTimeZone().getOffset(v);
+ }
+ return DateTimeUtils.unixTimestampToString(v);
+ }
+
+ /** Accesses a date value as a string, e.g. "2013-09-22". */
+ private static String dateAsString(int v, Calendar calendar) {
+ AvaticaUtils.discard(calendar); // time zone shift doesn't make sense
+ return DateTimeUtils.unixDateToString(v);
+ }
+
+ /** Accesses a time value as a string, e.g. "22:30:32". */
+ private static String timeAsString(int v, Calendar calendar) {
+ if (calendar != null) {
+ v -= calendar.getTimeZone().getOffset(v);
+ }
+ return DateTimeUtils.unixTimeToString(v);
+ }
+
+ private static Date longToDate(long v, Calendar calendar) {
+ if (calendar != null) {
+ v -= calendar.getTimeZone().getOffset(v);
+ }
+ return new Date(v);
+ }
+
+ static Time intToTime(int v, Calendar calendar) {
+ if (calendar != null) {
+ v -= calendar.getTimeZone().getOffset(v);
+ }
+ return new Time(v);
+ }
+
+ static Timestamp longToTimestamp(long v, Calendar calendar) {
+ if (calendar != null) {
+ v -= calendar.getTimeZone().getOffset(v);
+ }
+ return new Timestamp(v);
+ }
+
+ /** Implementation of {@link Cursor.Accessor}. */
+ static class AccessorImpl implements Accessor {
+ protected final Getter getter;
+
+ AccessorImpl(Getter getter) {
+ assert getter != null;
+ this.getter = getter;
+ }
+
+ public boolean wasNull() throws SQLException {
+ return getter.wasNull();
+ }
+
+ public String getString() throws SQLException {
+ final Object o = getObject();
+ return o == null ? null : o.toString();
+ }
+
+ public boolean getBoolean() throws SQLException {
+ return getLong() != 0L;
+ }
+
+ public byte getByte() throws SQLException {
+ return (byte) getLong();
+ }
+
+ public short getShort() throws SQLException {
+ return (short) getLong();
+ }
+
+ public int getInt() throws SQLException {
+ return (int) getLong();
+ }
+
+ public long getLong() throws SQLException {
+ throw cannotConvert("long");
+ }
+
+ public float getFloat() throws SQLException {
+ return (float) getDouble();
+ }
+
+ public double getDouble() throws SQLException {
+ throw cannotConvert("double");
+ }
+
+ public BigDecimal getBigDecimal() throws SQLException {
+ throw cannotConvert("BigDecimal");
+ }
+
+ public BigDecimal getBigDecimal(int scale) throws SQLException {
+ throw cannotConvert("BigDecimal with scale");
+ }
+
+ public byte[] getBytes() throws SQLException {
+ throw cannotConvert("byte[]");
+ }
+
+ public InputStream getAsciiStream() throws SQLException {
+ throw cannotConvert("InputStream (ascii)");
+ }
+
+ public InputStream getUnicodeStream() throws SQLException {
+ throw cannotConvert("InputStream (unicode)");
+ }
+
+ public InputStream getBinaryStream() throws SQLException {
+ throw cannotConvert("InputStream (binary)");
+ }
+
+ public Object getObject() throws SQLException {
+ return getter.getObject();
+ }
+
+ public Reader getCharacterStream() throws SQLException {
+ throw cannotConvert("Reader");
+ }
+
+ private SQLException cannotConvert(String targetType) throws SQLException {
+ return new SQLDataException("cannot convert to " + targetType + " ("
+ + this + ")");
+ }
+
+ public Object getObject(Map<String, Class<?>> map) throws SQLException {
+ throw cannotConvert("Object (with map)");
+ }
+
+ public Ref getRef() throws SQLException {
+ throw cannotConvert("Ref");
+ }
+
+ public Blob getBlob() throws SQLException {
+ throw cannotConvert("Blob");
+ }
+
+ public Clob getClob() throws SQLException {
+ throw cannotConvert("Clob");
+ }
+
+ public Array getArray() throws SQLException {
+ throw cannotConvert("Array");
+ }
+
+ public Struct getStruct() throws SQLException {
+ throw cannotConvert("Struct");
+ }
+
+ public Date getDate(Calendar calendar) throws SQLException {
+ throw cannotConvert("Date");
+ }
+
+ public Time getTime(Calendar calendar) throws SQLException {
+ throw cannotConvert("Time");
+ }
+
+ public Timestamp getTimestamp(Calendar calendar) throws SQLException {
+ throw cannotConvert("Timestamp");
+ }
+
+ public URL getURL() throws SQLException {
+ throw cannotConvert("URL");
+ }
+
+ public NClob getNClob() throws SQLException {
+ throw cannotConvert("NClob");
+ }
+
+ public SQLXML getSQLXML() throws SQLException {
+ throw cannotConvert("SQLXML");
+ }
+
+ public String getNString() throws SQLException {
+ throw cannotConvert("NString");
+ }
+
+ public Reader getNCharacterStream() throws SQLException {
+ throw cannotConvert("NCharacterStream");
+ }
+
+ public <T> T getObject(Class<T> type) throws SQLException {
+ throw cannotConvert("Object (with type)");
+ }
+ }
+
+ /**
+ * Accessor of exact numeric values. The subclass must implement the
+ * {@link #getLong()} method.
+ */
+ private abstract static class ExactNumericAccessor extends AccessorImpl {
+ private ExactNumericAccessor(Getter getter) {
+ super(getter);
+ }
+
+ public BigDecimal getBigDecimal(int scale) throws SQLException {
+ final long v = getLong();
+ if (v == 0 && getter.wasNull()) {
+ return null;
+ }
+ return BigDecimal.valueOf(v).setScale(scale, RoundingMode.DOWN);
+ }
+
+ public BigDecimal getBigDecimal() throws SQLException {
+ final long val = getLong();
+ if (val == 0 && getter.wasNull()) {
+ return null;
+ }
+ return BigDecimal.valueOf(val);
+ }
+
+ public double getDouble() throws SQLException {
+ return getLong();
+ }
+
+ public float getFloat() throws SQLException {
+ return getLong();
+ }
+
+ public abstract long getLong() throws SQLException;
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link Boolean};
+ * corresponds to {@link java.sql.Types#BOOLEAN}.
+ */
+ private static class BooleanAccessor extends ExactNumericAccessor {
+ private BooleanAccessor(Getter getter) {
+ super(getter);
+ }
+
+ public boolean getBoolean() throws SQLException {
+ Boolean o = (Boolean) getObject();
+ return o != null && o;
+ }
+
+ public long getLong() throws SQLException {
+ return getBoolean() ? 1 : 0;
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link Byte};
+ * corresponds to {@link java.sql.Types#TINYINT}.
+ */
+ private static class ByteAccessor extends ExactNumericAccessor {
+ private ByteAccessor(Getter getter) {
+ super(getter);
+ }
+
+ public byte getByte() throws SQLException {
+ Object obj = getObject();
+ if (null == obj) {
+ return 0;
+ } else if (obj instanceof Integer) {
+ return ((Integer) obj).byteValue();
+ }
+ return (Byte) obj;
+ }
+
+ public long getLong() throws SQLException {
+ return getByte();
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link Short};
+ * corresponds to {@link java.sql.Types#SMALLINT}.
+ */
+ private static class ShortAccessor extends ExactNumericAccessor {
+ private ShortAccessor(Getter getter) {
+ super(getter);
+ }
+
+ public short getShort() throws SQLException {
+ Object obj = getObject();
+ if (null == obj) {
+ return 0;
+ } else if (obj instanceof Integer) {
+ return ((Integer) obj).shortValue();
+ }
+ return (Short) obj;
+ }
+
+ public long getLong() throws SQLException {
+ return getShort();
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is an {@link Integer};
+ * corresponds to {@link java.sql.Types#INTEGER}.
+ */
+ private static class IntAccessor extends ExactNumericAccessor {
+ private IntAccessor(Getter getter) {
+ super(getter);
+ }
+
+ public int getInt() throws SQLException {
+ Integer o = (Integer) super.getObject();
+ return o == null ? 0 : o;
+ }
+
+ public long getLong() throws SQLException {
+ return getInt();
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link Long};
+ * corresponds to {@link java.sql.Types#BIGINT}.
+ */
+ private static class LongAccessor extends ExactNumericAccessor {
+ private LongAccessor(Getter getter) {
+ super(getter);
+ }
+
+ public long getLong() throws SQLException {
+ Long o = (Long) super.getObject();
+ return o == null ? 0 : o;
+ }
+ }
+
+ /**
+ * Accessor of values that are {@link Double} or null.
+ */
+ private abstract static class ApproximateNumericAccessor
+ extends AccessorImpl {
+ private ApproximateNumericAccessor(Getter getter) {
+ super(getter);
+ }
+
+ public BigDecimal getBigDecimal(int scale) throws SQLException {
+ final double v = getDouble();
+ if (v == 0d && getter.wasNull()) {
+ return null;
+ }
+ return BigDecimal.valueOf(v).setScale(scale, RoundingMode.DOWN);
+ }
+
+ public BigDecimal getBigDecimal() throws SQLException {
+ final double v = getDouble();
+ if (v == 0 && getter.wasNull()) {
+ return null;
+ }
+ return BigDecimal.valueOf(v);
+ }
+
+ public abstract double getDouble() throws SQLException;
+
+ public long getLong() throws SQLException {
+ return (long) getDouble();
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link Float};
+ * corresponds to {@link java.sql.Types#FLOAT}.
+ */
+ private static class FloatAccessor extends ApproximateNumericAccessor {
+ private FloatAccessor(Getter getter) {
+ super(getter);
+ }
+
+ public float getFloat() throws SQLException {
+ Float o = (Float) getObject();
+ return o == null ? 0f : o;
+ }
+
+ public double getDouble() throws SQLException {
+ return getFloat();
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link Double};
+ * corresponds to {@link java.sql.Types#DOUBLE}.
+ */
+ private static class DoubleAccessor extends ApproximateNumericAccessor {
+ private DoubleAccessor(Getter getter) {
+ super(getter);
+ }
+
+ public double getDouble() throws SQLException {
+ Object obj = getObject();
+ if (null == obj) {
+ return 0d;
+ } else if (obj instanceof BigDecimal) {
+ return ((BigDecimal) obj).doubleValue();
+ }
+ return (Double) obj;
+ }
+ }
+
+ /**
+ * Accessor of exact numeric values. The subclass must implement the
+ * {@link #getLong()} method.
+ */
+ private abstract static class BigNumberAccessor extends AccessorImpl {
+ private BigNumberAccessor(Getter getter) {
+ super(getter);
+ }
+
+ protected abstract Number getNumber() throws SQLException;
+
+ public double getDouble() throws SQLException {
+ Number number = getNumber();
+ return number == null ? 0d : number.doubleValue();
+ }
+
+ public float getFloat() throws SQLException {
+ Number number = getNumber();
+ return number == null ? 0f : number.floatValue();
+ }
+
+ public long getLong() throws SQLException {
+ Number number = getNumber();
+ return number == null ? 0L : number.longValue();
+ }
+
+ public int getInt() throws SQLException {
+ Number number = getNumber();
+ return number == null ? 0 : number.intValue();
+ }
+
+ public short getShort() throws SQLException {
+ Number number = getNumber();
+ return number == null ? 0 : number.shortValue();
+ }
+
+ public byte getByte() throws SQLException {
+ Number number = getNumber();
+ return number == null ? 0 : number.byteValue();
+ }
+
+ public boolean getBoolean() throws SQLException {
+ Number number = getNumber();
+ return number != null && number.doubleValue() != 0;
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link BigDecimal};
+ * corresponds to {@link java.sql.Types#DECIMAL}.
+ */
+ private static class BigDecimalAccessor extends BigNumberAccessor {
+ private BigDecimalAccessor(Getter getter) {
+ super(getter);
+ }
+
+ protected Number getNumber() throws SQLException {
+ return (Number) getObject();
+ }
+
+ public BigDecimal getBigDecimal(int scale) throws SQLException {
+ return (BigDecimal) getObject();
+ }
+
+ public BigDecimal getBigDecimal() throws SQLException {
+ return (BigDecimal) getObject();
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link Number};
+ * corresponds to {@link java.sql.Types#NUMERIC}.
+ *
+ * <p>This is useful when numbers have been translated over JSON. JSON
+ * converts a 0L (0 long) value to the string "0" and back to 0 (0 int).
+ * So you cannot be sure that the source and target type are the same.
+ */
+ static class NumberAccessor extends BigNumberAccessor {
+ private final int scale;
+
+ NumberAccessor(Getter getter, int scale) {
+ super(getter);
+ this.scale = scale;
+ }
+
+ protected Number getNumber() throws SQLException {
+ return (Number) super.getObject();
+ }
+
+ public BigDecimal getBigDecimal(int scale) throws SQLException {
+ Number n = getNumber();
+ if (n == null) {
+ return null;
+ }
+ BigDecimal decimal = AvaticaSite.toBigDecimal(n);
+ if (0 != scale) {
+ return decimal.setScale(scale, RoundingMode.UNNECESSARY);
+ }
+ return decimal;
+ }
+
+ public BigDecimal getBigDecimal() throws SQLException {
+ return getBigDecimal(scale);
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link String};
+ * corresponds to {@link java.sql.Types#CHAR}
+ * and {@link java.sql.Types#VARCHAR}.
+ */
+ private static class StringAccessor extends AccessorImpl {
+ private StringAccessor(Getter getter) {
+ super(getter);
+ }
+
+ public String getString() throws SQLException {
+ final Object obj = getObject();
+ if (obj instanceof String) {
+ return (String) obj;
+ }
+ return null == obj ? null : obj.toString();
+ }
+
+ @Override public byte[] getBytes() throws SQLException {
+ return super.getBytes();
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link String};
+ * corresponds to {@link java.sql.Types#CHAR}.
+ */
+ private static class FixedStringAccessor extends StringAccessor {
+ protected final Spacer spacer;
+
+ private FixedStringAccessor(Getter getter, int length) {
+ super(getter);
+ this.spacer = new Spacer(length);
+ }
+
+ public String getString() throws SQLException {
+ String s = super.getString();
+ if (s == null) {
+ return null;
+ }
+ return spacer.padRight(s);
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link String};
+ * corresponds to {@link java.sql.Types#CHAR}.
+ */
+ private static class StringFromCharAccessor extends FixedStringAccessor {
+ private StringFromCharAccessor(Getter getter, int length) {
+ super(getter, length);
+ }
+
+ public String getString() throws SQLException {
+ Character s = (Character) super.getObject();
+ if (s == null) {
+ return null;
+ }
+ return spacer.padRight(s.toString());
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is an array of
+ * {@link org.apache.calcite.avatica.util.ByteString} values;
+ * corresponds to {@link java.sql.Types#BINARY}
+ * and {@link java.sql.Types#VARBINARY}.
+ */
+ private static class BinaryAccessor extends AccessorImpl {
+ private BinaryAccessor(Getter getter) {
+ super(getter);
+ }
+
+ //FIXME: Protobuf gets byte[]
+ @Override public byte[] getBytes() throws SQLException {
+ Object obj = getObject();
+ if (null == obj) {
+ return null;
+ }
+ if (obj instanceof ByteString) {
+ return ((ByteString) obj).getBytes();
+ } else if (obj instanceof String) {
+ // Need to unwind the base64 for JSON
+ return ByteString.parseBase64((String) obj);
+ } else if (obj instanceof byte[]) {
+ // Protobuf would have a byte array
+ return (byte[]) obj;
+ } else {
+ throw new RuntimeException("Cannot handle " + obj.getClass() + " as bytes");
+ }
+ }
+
+ @Override public String getString() throws SQLException {
+ Object o = getObject();
+ if (null == o) {
+ return null;
+ }
+ if (o instanceof byte[]) {
+ return new String((byte[]) o, StandardCharsets.UTF_8);
+ } else if (o instanceof ByteString) {
+ return ((ByteString) o).toString();
+ }
+ throw new IllegalStateException("Unhandled value type: " + o.getClass());
+ }
+
+
+ @Override public Blob getBlob() throws SQLException {
+
+ Object o = getObject();
+ if (null == o) {
+ return null;
+ }
+ if (o instanceof byte[]) {
+ byte[] byteArr = (byte[] )o;
+ //System.out.println(new String(byteArr, StandardCharsets.UTF_8));
+ return new SerialBlob(byteArr);
+ }
+
+ throw new IllegalStateException("Unhandled value type: " + o.getClass());
+
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@link String},
+ * encoding {@link java.sql.Types#BINARY}
+ * and {@link java.sql.Types#VARBINARY} values in Base64 format.
+ */
+ private static class BinaryFromStringAccessor extends StringAccessor {
+ private BinaryFromStringAccessor(Getter getter) {
+ super(getter);
+ }
+
+ @Override public Object getObject() throws SQLException {
+ return super.getObject();
+ }
+
+ @Override public byte[] getBytes() throws SQLException {
+ // JSON sends this as a base64-enc string, protobuf can do binary.
+ Object obj = getObject();
+
+ if (obj instanceof byte[]) {
+ // If we already have bytes, just send them back.
+ return (byte[]) obj;
+ }
+
+ return getBase64Decoded();
+ }
+
+ private byte[] getBase64Decoded() throws SQLException {
+ final String string = super.getString();
+ if (null == string) {
+ return null;
+ }
+ // Need to base64 decode the string.
+ return ByteString.parseBase64(string);
+ }
+
+ @Override public String getString() throws SQLException {
+ final byte[] bytes = getBase64Decoded();
+ if (null == bytes) {
+ return null;
+ }
+ // Need to base64 decode the string.
+ return new String(bytes, StandardCharsets.UTF_8);
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a DATE,
+ * in its default representation {@code int};
+ * corresponds to {@link java.sql.Types#DATE}.
+ */
+ private static class DateFromNumberAccessor extends NumberAccessor {
+ private final Calendar localCalendar;
+
+ private DateFromNumberAccessor(Getter getter, Calendar localCalendar) {
+ super(getter, 0);
+ this.localCalendar = localCalendar;
+ }
+
+ @Override public Object getObject() throws SQLException {
+ return getDate(localCalendar);
+ }
+
+ @Override public Date getDate(Calendar calendar) throws SQLException {
+ final Number v = getNumber();
+ if (v == null) {
+ return null;
+ }
+ return longToDate(v.longValue() * DateTimeUtils.MILLIS_PER_DAY, calendar);
+ }
+
+ @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {
+ final Number v = getNumber();
+ if (v == null) {
+ return null;
+ }
+ return longToTimestamp(v.longValue() * DateTimeUtils.MILLIS_PER_DAY,
+ calendar);
+ }
+
+ @Override public String getString() throws SQLException {
+ final Number v = getNumber();
+ if (v == null) {
+ return null;
+ }
+ return dateAsString(v.intValue(), null);
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a Time,
+ * in its default representation {@code int};
+ * corresponds to {@link java.sql.Types#TIME}.
+ */
+ private static class TimeFromNumberAccessor extends NumberAccessor {
+ private final Calendar localCalendar;
+
+ private TimeFromNumberAccessor(Getter getter, Calendar localCalendar) {
+ super(getter, 0);
+ this.localCalendar = localCalendar;
+ }
+
+ @Override public Object getObject() throws SQLException {
+ return getTime(localCalendar);
+ }
+
+ @Override public Time getTime(Calendar calendar) throws SQLException {
+ final Number v = getNumber();
+ if (v == null) {
+ return null;
+ }
+ return intToTime(v.intValue(), calendar);
+ }
+
+ @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {
+ final Number v = getNumber();
+ if (v == null) {
+ return null;
+ }
+ return longToTimestamp(v.longValue(), calendar);
+ }
+
+ @Override public String getString() throws SQLException {
+ final Number v = getNumber();
+ if (v == null) {
+ return null;
+ }
+ return timeAsString(v.intValue(), null);
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a TIMESTAMP,
+ * in its default representation {@code long};
+ * corresponds to {@link java.sql.Types#TIMESTAMP}.
+ */
+ private static class TimestampFromNumberAccessor extends NumberAccessor {
+ private final Calendar localCalendar;
+
+ private TimestampFromNumberAccessor(Getter getter, Calendar localCalendar) {
+ super(getter, 0);
+ this.localCalendar = localCalendar;
+ }
+
+ @Override public Object getObject() throws SQLException {
+ return getTimestamp(localCalendar);
+ }
+
+ @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {
+ final Number v = getNumber();
+ if (v == null) {
+ return null;
+ }
+ return longToTimestamp(v.longValue(), calendar);
+ }
+
+ @Override public Date getDate(Calendar calendar) throws SQLException {
+ final Timestamp timestamp = getTimestamp(calendar);
+ if (timestamp == null) {
+ return null;
+ }
+ return new Date(timestamp.getTime());
+ }
+
+ @Override public Time getTime(Calendar calendar) throws SQLException {
+ final Timestamp timestamp = getTimestamp(calendar);
+ if (timestamp == null) {
+ return null;
+ }
+ return new Time(
+ DateTimeUtils.floorMod(timestamp.getTime(),
+ DateTimeUtils.MILLIS_PER_DAY));
+ }
+
+ @Override public String getString() throws SQLException {
+ final Number v = getNumber();
+ if (v == null) {
+ return null;
+ }
+ return timestampAsString(v.longValue(), null);
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a DATE,
+ * represented as a java.sql.Date;
+ * corresponds to {@link java.sql.Types#DATE}.
+ */
+ private static class DateAccessor extends ObjectAccessor {
+ private DateAccessor(Getter getter) {
+ super(getter);
+ }
+
+ @Override public Date getDate(Calendar calendar) throws SQLException {
+ java.sql.Date date = (Date) getObject();
+ if (date == null) {
+ return null;
+ }
+ if (calendar != null) {
+ long v = date.getTime();
+ v -= calendar.getTimeZone().getOffset(v);
+ date = new Date(v);
+ }
+ return date;
+ }
+
+ @Override public String getString() throws SQLException {
+ final int v = getInt();
+ if (v == 0 && wasNull()) {
+ return null;
+ }
+ return dateAsString(v, null);
+ }
+
+ @Override public long getLong() throws SQLException {
+ Date date = getDate(null);
+ return date == null
+ ? 0L
+ : (date.getTime() / DateTimeUtils.MILLIS_PER_DAY);
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a TIME,
+ * represented as a java.sql.Time;
+ * corresponds to {@link java.sql.Types#TIME}.
+ */
+ private static class TimeAccessor extends ObjectAccessor {
+ private TimeAccessor(Getter getter) {
+ super(getter);
+ }
+
+ @Override public Time getTime(Calendar calendar) throws SQLException {
+ Time date = (Time) getObject();
+ if (date == null) {
+ return null;
+ }
+ if (calendar != null) {
+ long v = date.getTime();
+ v -= calendar.getTimeZone().getOffset(v);
+ date = new Time(v);
+ }
+ return date;
+ }
+
+ @Override public String getString() throws SQLException {
+ final int v = getInt();
+ if (v == 0 && wasNull()) {
+ return null;
+ }
+ return timeAsString(v, null);
+ }
+
+ @Override public long getLong() throws SQLException {
+ Time time = getTime(null);
+ return time == null ? 0L
+ : (time.getTime() % DateTimeUtils.MILLIS_PER_DAY);
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a TIMESTAMP,
+ * represented as a java.sql.Timestamp;
+ * corresponds to {@link java.sql.Types#TIMESTAMP}.
+ */
+ private static class TimestampAccessor extends ObjectAccessor {
+ private TimestampAccessor(Getter getter) {
+ super(getter);
+ }
+
+ @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {
+ Timestamp timestamp = (Timestamp) getObject();
+ if (timestamp == null) {
+ return null;
+ }
+ if (calendar != null) {
+ long v = timestamp.getTime();
+ v -= calendar.getTimeZone().getOffset(v);
+ timestamp = new Timestamp(v);
+ }
+ return timestamp;
+ }
+
+ @Override public Date getDate(Calendar calendar) throws SQLException {
+ final Timestamp timestamp = getTimestamp(calendar);
+ if (timestamp == null) {
+ return null;
+ }
+ return new Date(timestamp.getTime());
+ }
+
+ @Override public Time getTime(Calendar calendar) throws SQLException {
+ final Timestamp timestamp = getTimestamp(calendar);
+ if (timestamp == null) {
+ return null;
+ }
+ return new Time(
+ DateTimeUtils.floorMod(timestamp.getTime(),
+ DateTimeUtils.MILLIS_PER_DAY));
+ }
+
+ @Override public String getString() throws SQLException {
+ final long v = getLong();
+ if (v == 0 && wasNull()) {
+ return null;
+ }
+ return timestampAsString(v, null);
+ }
+
+ @Override public long getLong() throws SQLException {
+ Timestamp timestamp = getTimestamp(null);
+ return timestamp == null ? 0 : timestamp.getTime();
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a TIMESTAMP,
+ * represented as a java.util.Date;
+ * corresponds to {@link java.sql.Types#TIMESTAMP}.
+ */
+ private static class TimestampFromUtilDateAccessor extends ObjectAccessor {
+ private final Calendar localCalendar;
+
+ private TimestampFromUtilDateAccessor(Getter getter,
+ Calendar localCalendar) {
+ super(getter);
+ this.localCalendar = localCalendar;
+ }
+
+ @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {
+ java.util.Date date = (java.util.Date) getObject();
+ if (date == null) {
+ return null;
+ }
+ long v = date.getTime();
+ if (calendar != null) {
+ v -= calendar.getTimeZone().getOffset(v);
+ }
+ return new Timestamp(v);
+ }
+
+ @Override public Date getDate(Calendar calendar) throws SQLException {
+ final Timestamp timestamp = getTimestamp(calendar);
+ if (timestamp == null) {
+ return null;
+ }
+ return new Date(timestamp.getTime());
+ }
+
+ @Override public Time getTime(Calendar calendar) throws SQLException {
+ final Timestamp timestamp = getTimestamp(calendar);
+ if (timestamp == null) {
+ return null;
+ }
+ return new Time(
+ DateTimeUtils.floorMod(timestamp.getTime(),
+ DateTimeUtils.MILLIS_PER_DAY));
+ }
+
+ @Override public String getString() throws SQLException {
+ java.util.Date date = (java.util.Date) getObject();
+ if (date == null) {
+ return null;
+ }
+ return timestampAsString(date.getTime(), null);
+ }
+
+ @Override public long getLong() throws SQLException {
+ Timestamp timestamp = getTimestamp(localCalendar);
+ return timestamp == null ? 0 : timestamp.getTime();
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@code int};
+ * corresponds to {@link java.sql.Types#OTHER}.
+ */
+ private static class IntervalYearMonthAccessor extends IntAccessor {
+ private final TimeUnitRange range;
+
+ private IntervalYearMonthAccessor(Getter getter, TimeUnitRange range) {
+ super(getter);
+ this.range = range;
+ }
+
+ @Override public String getString() throws SQLException {
+ final int v = getInt();
+ if (v == 0 && wasNull()) {
+ return null;
+ }
+ return DateTimeUtils.intervalYearMonthToString(v, range);
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a {@code long};
+ * corresponds to {@link java.sql.Types#OTHER}.
+ */
+ private static class IntervalDayTimeAccessor extends LongAccessor {
+ private final TimeUnitRange range;
+ private final int scale;
+
+ private IntervalDayTimeAccessor(Getter getter, TimeUnitRange range,
+ int scale) {
+ super(getter);
+ this.range = range;
+ this.scale = scale;
+ }
+
+ @Override public String getString() throws SQLException {
+ final long v = getLong();
+ if (v == 0 && wasNull()) {
+ return null;
+ }
+ return DateTimeUtils.intervalDayTimeToString(v, range, scale);
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is an ARRAY;
+ * corresponds to {@link java.sql.Types#ARRAY}.
+ */
+ public static class ArrayAccessor extends AccessorImpl {
+ final ColumnMetaData.AvaticaType componentType;
+ final Accessor componentAccessor;
+ final SlotGetter componentSlotGetter;
+ final ArrayImpl.Factory factory;
+
+ public ArrayAccessor(Getter getter,
+ ColumnMetaData.AvaticaType componentType, Accessor componentAccessor,
+ SlotGetter componentSlotGetter, ArrayImpl.Factory factory) {
+ super(getter);
+ this.componentType = componentType;
+ this.componentAccessor = componentAccessor;
+ this.componentSlotGetter = componentSlotGetter;
+ this.factory = factory;
+ }
+
+ @Override public Object getObject() throws SQLException {
+ final Object object = super.getObject();
+ if (object == null || object instanceof ArrayImpl) {
+ return object;
+ } else if (object instanceof List) {
+ List<?> list = (List<?>) object;
+ // Run the array values through the component accessor
+ List<Object> convertedValues = new ArrayList<>(list.size());
+ for (Object val : list) {
+ if (null == val) {
+ convertedValues.add(null);
+ } else {
+ // Set the current value in the SlotGetter so we can use the Accessor to coerce it.
+ componentSlotGetter.slot = val;
+ convertedValues.add(convertValue());
+ }
+ }
+ return convertedValues;
+ }
+ // The object can be java array in case of user-provided class for row storage.
+ return AvaticaUtils.primitiveList(object);
+ }
+
+ private Object convertValue() throws SQLException {
+ switch (componentType.id) {
+ case Types.BOOLEAN:
+ case Types.BIT:
+ return componentAccessor.getBoolean();
+ case Types.TINYINT:
+ return componentAccessor.getByte();
+ case Types.SMALLINT:
+ return componentAccessor.getShort();
+ case Types.INTEGER:
+ return componentAccessor.getInt();
+ case Types.BIGINT:
+ return componentAccessor.getLong();
+ case Types.FLOAT:
+ return componentAccessor.getFloat();
+ case Types.DOUBLE:
+ return componentAccessor.getDouble();
+ case Types.ARRAY:
+ return componentAccessor.getArray();
+ case Types.CHAR:
+ case Types.VARCHAR:
+ case Types.LONGVARCHAR:
+ case Types.NCHAR:
+ case Types.LONGNVARCHAR:
+ return componentAccessor.getString();
+ case Types.BINARY:
+ case Types.VARBINARY:
+ case Types.LONGVARBINARY:
+ return componentAccessor.getBytes();
+ case Types.DECIMAL:
+ return componentAccessor.getBigDecimal();
+ case Types.DATE:
+ case Types.TIME:
+ case Types.TIMESTAMP:
+ case Types.STRUCT:
+ case Types.JAVA_OBJECT:
+ return componentAccessor.getObject();
+ default:
+ throw new IllegalStateException("Unhandled ARRAY component type: " + componentType.rep
+ + ", id: " + componentType.id);
+ }
+ }
+
+ @SuppressWarnings("unchecked") @Override public Array getArray() throws SQLException {
+ final Object o = getObject();
+ if (o == null) {
+ return null;
+ }
+ if (o instanceof ArrayImpl) {
+ return (ArrayImpl) o;
+ }
+ // If it's not an Array already, assume it is a List.
+ return new ArrayImpl((List<Object>) o, this);
+ }
+
+ @Override public String getString() throws SQLException {
+ final Array array = getArray();
+ return array == null ? null : array.toString();
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is a STRUCT;
+ * corresponds to {@link java.sql.Types#STRUCT}.
+ */
+ private static class StructAccessor extends AccessorImpl {
+ private final List<Accessor> fieldAccessors;
+
+ private StructAccessor(Getter getter, List<Accessor> fieldAccessors) {
+ super(getter);
+ this.fieldAccessors = fieldAccessors;
+ }
+
+ @Override public Object getObject() throws SQLException {
+ return getStruct();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public <T> T getObject(Class<T> clz) throws SQLException {
+ // getStruct() is not exposed on Accessor, only AccessorImpl. getObject(Class) is exposed,
+ // so we can make it do the right thing (call getStruct()).
+ if (clz.equals(Struct.class)) {
+ return (T) getStruct();
+ }
+ return super.getObject(clz);
+ }
+
+ @Override public Struct getStruct() throws SQLException {
+ final Object o = super.getObject();
+ if (o == null) {
+ return null;
+ } else if (o instanceof StructImpl) {
+ return (StructImpl) o;
+ } else if (o instanceof List) {
+ return new StructImpl((List) o);
+ } else {
+ final List<Object> list = new ArrayList<>();
+ for (Accessor fieldAccessor : fieldAccessors) {
+ list.add(fieldAccessor.getObject());
+ }
+ return new StructImpl(list);
+ }
+ }
+ }
+
+ /**
+ * Accessor that assumes that the underlying value is an OBJECT;
+ * corresponds to {@link java.sql.Types#JAVA_OBJECT}.
+ */
+ private static class ObjectAccessor extends AccessorImpl {
+ private ObjectAccessor(Getter getter) {
+ super(getter);
+ }
+ }
+
+ /** Gets a value from a particular field of the current record of this
+ * cursor. */
+ protected interface Getter {
+ Object getObject() throws SQLException;
+
+ boolean wasNull() throws SQLException;
+ }
+
+ /** Abstract implementation of {@link Getter}. */
+ protected abstract class AbstractGetter implements Getter {
+ public boolean wasNull() throws SQLException {
+ return wasNull[0];
+ }
+ }
+
+ /** Implementation of {@link Getter} that returns the current contents of
+ * a mutable slot. */
+ public class SlotGetter implements Getter {
+ public Object slot;
+
+ public Object getObject() throws SQLException {
+ return slot;
+ }
+
+ public boolean wasNull() throws SQLException {
+ return slot == null;
+ }
+ }
+
+ /** Implementation of {@link Getter} that returns the value of a given field
+ * of the current contents of another getter. */
+ public class StructGetter implements Getter {
+ public final Getter getter;
+ private final ColumnMetaData columnMetaData;
+
+ public StructGetter(Getter getter, ColumnMetaData columnMetaData) {
+ this.getter = getter;
+ this.columnMetaData = columnMetaData;
+ }
+
+ public Object getObject() throws SQLException {
+ try {
+ final Object o = getter.getObject();
+ if (o instanceof Object[]) {
+ Object[] objects = (Object[]) o;
+ return objects[columnMetaData.ordinal];
+ }
+ final Field field = o.getClass().getField(columnMetaData.label);
+ return field.get(getter.getObject());
+ } catch (IllegalAccessException | NoSuchFieldException e) {
+ throw new SQLException(e);
+ }
+ }
+
+ public boolean wasNull() throws SQLException {
+ return getObject() == null;
+ }
+ }
+}
+
+// End AbstractCursor.java
diff --git a/mdbc-server/src/main/java/org/onap/music/logging/EELFLoggerDelegate.java b/mdbc-server/src/main/java/org/onap/music/logging/EELFLoggerDelegate.java
index d8b5256..2bd26ff 100755
--- a/mdbc-server/src/main/java/org/onap/music/logging/EELFLoggerDelegate.java
+++ b/mdbc-server/src/main/java/org/onap/music/logging/EELFLoggerDelegate.java
@@ -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.
@@ -19,34 +19,42 @@
*/
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
diff --git a/mdbc-server/src/main/resources/logback.xml b/mdbc-server/src/main/resources/logback.xml
index af973b8..b9e9dcf 100755
--- a/mdbc-server/src/main/resources/logback.xml
+++ b/mdbc-server/src/main/resources/logback.xml
@@ -45,18 +45,18 @@
-->
<!--<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" />
@@ -73,20 +73,20 @@
<!-- 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">
@@ -321,7 +321,7 @@
<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>
@@ -344,28 +344,29 @@
- <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