[CALCITE-1667] In Avatica, forbid calls to JDK APIs that use the default locale, time zone or character set
Use the "forbidden-apis" maven plugin to detect calls to such APIs. Eliminate calls to such APIs. Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/8df27ce9 Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/8df27ce9 Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/8df27ce9 Branch: refs/heads/master Commit: 8df27ce9dfc24c3116e6343432d581d112d83557 Parents: 75152c5 Author: Julian Hyde <[email protected]> Authored: Fri Mar 3 01:27:20 2017 -0800 Committer: Julian Hyde <[email protected]> Committed: Fri Mar 3 11:08:49 2017 -0800 ---------------------------------------------------------------------- .../avatica/AvaticaPreparedStatement.java | 3 +- .../calcite/avatica/AvaticaResultSet.java | 3 +- .../org/apache/calcite/avatica/AvaticaSite.java | 3 +- .../apache/calcite/avatica/AvaticaUtils.java | 1 + .../avatica/BuiltInConnectionProperty.java | 3 +- .../calcite/avatica/ConnectionConfigImpl.java | 3 +- .../org/apache/calcite/avatica/SqlState.java | 7 +- .../remote/AvaticaRemoteConnectionProperty.java | 3 +- .../apache/calcite/avatica/remote/Driver.java | 4 +- .../avatica/remote/RemoteProtobufService.java | 4 +- .../calcite/avatica/util/AbstractCursor.java | 2 +- .../org/apache/calcite/avatica/util/Base64.java | 24 ++-- .../calcite/avatica/util/DateTimeUtils.java | 32 +++-- .../org/apache/calcite/avatica/util/Unsafe.java | 55 +++++++++ .../AvaticaResultSetConversionsTest.java | 5 +- .../calcite/avatica/MetaResultSetTest.java | 7 +- .../avatica/remote/KerberosConnectionTest.java | 4 +- .../calcite/avatica/remote/TypedValueTest.java | 12 +- .../calcite/avatica/test/AvaticaUtilsTest.java | 5 +- avatica/pom.xml | 39 ++++++ .../apache/calcite/avatica/jdbc/JdbcMeta.java | 3 +- .../calcite/avatica/jdbc/JdbcResultSet.java | 2 +- .../calcite/avatica/server/HttpServer.java | 8 +- .../calcite/avatica/RemoteDriverTest.java | 123 +++++++++++-------- .../apache/calcite/avatica/SpnegoTestUtil.java | 10 +- .../apache/calcite/avatica/SslDriverTest.java | 5 +- .../calcite/avatica/remote/RemoteMetaTest.java | 35 ++++-- .../server/AbstractAvaticaHandlerTest.java | 3 +- .../server/HttpServerSpnegoWithJaasTest.java | 4 +- .../server/HttpServerSpnegoWithoutJaasTest.java | 4 +- .../main/config/forbidden-apis/signatures.txt | 39 ++++++ .../calcite/avatica/hsqldb/HsqldbServer.java | 9 +- .../apache/calcite/avatica/tck/TestRunner.java | 12 +- .../org/apache/calcite/avatica/tck/Unsafe.java | 55 +++++++++ 34 files changed, 406 insertions(+), 125 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java index 31cdfd2..e611c9a 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.List; +import java.util.Locale; /** * Implementation of {@link java.sql.PreparedStatement} @@ -115,7 +116,7 @@ public abstract class AvaticaPreparedStatement */ protected synchronized Calendar getCalendar() { if (calendar == null) { - calendar = Calendar.getInstance(connection.getTimeZone()); + calendar = Calendar.getInstance(connection.getTimeZone(), Locale.ROOT); } return calendar; } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaResultSet.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaResultSet.java b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaResultSet.java index a102eba..51bf8fa 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaResultSet.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaResultSet.java @@ -40,6 +40,7 @@ import java.sql.Time; import java.sql.Timestamp; import java.util.Calendar; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.TimeZone; @@ -87,7 +88,7 @@ public class AvaticaResultSet implements ResultSet, ArrayImpl.Factory { this.fetchSize = statement.getFetchSize(); this.fetchDirection = statement.getFetchDirection(); this.resultSetMetaData = resultSetMetaData; - this.localCalendar = Calendar.getInstance(timeZone); + this.localCalendar = Calendar.getInstance(timeZone, Locale.ROOT); } private int findColumn0(String columnLabel) throws SQLException { http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaSite.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaSite.java b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaSite.java index b33b0b2..0e23866 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaSite.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaSite.java @@ -24,6 +24,7 @@ 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; @@ -477,7 +478,7 @@ public class AvaticaSite { return (byte[]) x; } if (x instanceof String) { - return ((String) x).getBytes(); + return ((String) x).getBytes(StandardCharsets.UTF_8); } throw unsupportedCast(x.getClass(), byte[].class); } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java index 53aff83..56a23c8 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java @@ -37,6 +37,7 @@ import java.util.Set; /** Avatica utilities. */ public class AvaticaUtils { + private static final Map<Class, Class> BOX; private static final MethodHandle SET_LARGE_MAX_ROWS = http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/BuiltInConnectionProperty.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/BuiltInConnectionProperty.java b/avatica/core/src/main/java/org/apache/calcite/avatica/BuiltInConnectionProperty.java index aa7d710..d68bae8 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/BuiltInConnectionProperty.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/BuiltInConnectionProperty.java @@ -20,6 +20,7 @@ import org.apache.calcite.avatica.remote.AvaticaHttpClientFactoryImpl; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; @@ -90,7 +91,7 @@ public enum BuiltInConnectionProperty implements ConnectionProperty { static { NAME_TO_PROPS = new HashMap<>(); for (BuiltInConnectionProperty p : BuiltInConnectionProperty.values()) { - NAME_TO_PROPS.put(p.camelName.toUpperCase(), p); + NAME_TO_PROPS.put(p.camelName.toUpperCase(Locale.ROOT), p); NAME_TO_PROPS.put(p.name(), p); } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/ConnectionConfigImpl.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/ConnectionConfigImpl.java b/avatica/core/src/main/java/org/apache/calcite/avatica/ConnectionConfigImpl.java index e9d7272..a003b82 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/ConnectionConfigImpl.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/ConnectionConfigImpl.java @@ -22,6 +22,7 @@ import org.apache.calcite.avatica.remote.Service; import java.io.File; import java.math.BigDecimal; import java.util.LinkedHashMap; +import java.util.Locale; import java.util.Map; import java.util.Properties; @@ -121,7 +122,7 @@ public class ConnectionConfigImpl implements ConnectionConfig { new LinkedHashMap<ConnectionProperty, String>(); for (String name : properties.stringPropertyNames()) { final ConnectionProperty connectionProperty = - nameToProps.get(name.toUpperCase()); + nameToProps.get(name.toUpperCase(Locale.ROOT)); if (connectionProperty == null) { // For now, don't throw. It messes up sub-projects. //throw new RuntimeException("Unknown property '" + name + "'"); http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/SqlState.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/SqlState.java b/avatica/core/src/main/java/org/apache/calcite/avatica/SqlState.java index 1459757..9f967aa 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/SqlState.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/SqlState.java @@ -16,7 +16,10 @@ */ package org.apache.calcite.avatica; +import java.io.BufferedWriter; +import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -1810,7 +1813,9 @@ public enum SqlState { /** Validates the data, and generates the HTML table. */ private static void main(String[] args) { - PrintWriter pw = new PrintWriter(System.out); + PrintWriter pw = new PrintWriter( + new BufferedWriter( + new OutputStreamWriter(System.out, StandardCharsets.UTF_8))); pw.println(" * <table>"); SqlState parent = null; for (SqlState s : values()) { http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionProperty.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionProperty.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionProperty.java index e0d9bb1..e965989 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionProperty.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionProperty.java @@ -19,6 +19,7 @@ package org.apache.calcite.avatica.remote; import org.apache.calcite.avatica.ConnectionProperty; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Properties; @@ -42,7 +43,7 @@ public enum AvaticaRemoteConnectionProperty implements ConnectionProperty { NAME_TO_PROPS = new HashMap<>(); for (AvaticaRemoteConnectionProperty p : AvaticaRemoteConnectionProperty.values()) { - NAME_TO_PROPS.put(p.camelName.toUpperCase(), p); + NAME_TO_PROPS.put(p.camelName.toUpperCase(Locale.ROOT), p); NAME_TO_PROPS.put(p.name(), p); } } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Driver.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Driver.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Driver.java index 86f0814..3f6d4df 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Driver.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Driver.java @@ -35,6 +35,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Properties; /** @@ -184,7 +185,8 @@ public class Driver extends UnregisteredDriver { Serialization serializationType = Serialization.JSON; if (null != serializationStr) { try { - serializationType = Serialization.valueOf(serializationStr.toUpperCase()); + serializationType = + Serialization.valueOf(serializationStr.toUpperCase(Locale.ROOT)); } catch (Exception e) { // Log a warning instead of failing harshly? Intentionally no loggers available? throw new RuntimeException(e); http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/remote/RemoteProtobufService.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/RemoteProtobufService.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/RemoteProtobufService.java index 2e92662..0f4cbfb 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/RemoteProtobufService.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/RemoteProtobufService.java @@ -20,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.nio.charset.StandardCharsets; /** @@ -51,7 +52,8 @@ public class RemoteProtobufService extends ProtobufService { try { resp = translation.parseResponse(response); } catch (IOException e) { - LOG.debug("Failed to deserialize reponse to {}. '{}'", request, new String(response)); + LOG.debug("Failed to deserialize reponse to {}. '{}'", request, + new String(response, StandardCharsets.UTF_8)); // Not a protobuf that we could parse. throw new RuntimeException(e); } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java b/avatica/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java index 3bf69d6..77739ab 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java @@ -792,7 +792,7 @@ public abstract class AbstractCursor implements Cursor { if (obj instanceof ByteString) { return ((ByteString) obj).getBytes(); } else if (obj instanceof String) { - return ((String) obj).getBytes(); + return ((String) obj).getBytes(StandardCharsets.UTF_8); } else if (obj instanceof byte[]) { return (byte[]) obj; } else { http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/util/Base64.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/util/Base64.java b/avatica/core/src/main/java/org/apache/calcite/avatica/util/Base64.java index c2393b1..c42b1f5 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/util/Base64.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/util/Base64.java @@ -18,6 +18,9 @@ package org.apache.calcite.avatica.util; //CHECKSTYLE: OFF +import java.nio.charset.StandardCharsets; +import java.util.Locale; + /** * <p>Encodes and decodes to and from Base64 notation.</p> * <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p> @@ -713,7 +716,7 @@ public class Base64 } // end try catch (java.io.UnsupportedEncodingException uue){ // Fall back to some Java default - return new String( baos.toByteArray() ); + return new String( baos.toByteArray(), StandardCharsets.UTF_8 ); } // end catch } // end encode @@ -853,7 +856,7 @@ public class Base64 return new String( encoded, PREFERRED_ENCODING ); } // end try catch (java.io.UnsupportedEncodingException uue) { - return new String( encoded ); + return new String( encoded, StandardCharsets.UTF_8 ); } // end catch } // end encodeBytes @@ -917,7 +920,9 @@ public class Base64 if( off + len > source.length ){ throw new IllegalArgumentException( - String.format( "Cannot have offset of %d and length of %d with array of length %d", off,len,source.length)); + String.format( Locale.ROOT, + "Cannot have offset of %d and length of %d with array of length %d", + off,len,source.length ) ); } // end if: off < 0 @@ -1057,11 +1062,11 @@ public class Base64 throw new NullPointerException( "Destination array was null." ); } // end if if( srcOffset < 0 || srcOffset + 3 >= source.length ){ - throw new IllegalArgumentException( String.format( + throw new IllegalArgumentException( String.format( Locale.ROOT, "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset ) ); } // end if if( destOffset < 0 || destOffset +2 >= destination.length ){ - throw new IllegalArgumentException( String.format( + throw new IllegalArgumentException( String.format( Locale.ROOT, "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset ) ); } // end if @@ -1171,7 +1176,7 @@ public class Base64 throw new NullPointerException( "Cannot decode null source array." ); } // end if if( off < 0 || off + len > source.length ){ - throw new IllegalArgumentException( String.format( + throw new IllegalArgumentException( String.format( Locale.ROOT, "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len ) ); } // end if @@ -1216,8 +1221,9 @@ public class Base64 } // end if: white space, equals sign or better else { // There's a bad input character in the Base64 stream. - throw new java.io.IOException( String.format( - "Bad Base64 input character decimal %d in array position %d", ((int)source[i])&0xFF, i ) ); + throw new java.io.IOException( String.format( Locale.ROOT, + "Bad Base64 input character decimal %d in array position %d", + ((int)source[i])&0xFF, i ) ); } // end else: } // each input character @@ -1266,7 +1272,7 @@ public class Base64 bytes = s.getBytes( PREFERRED_ENCODING ); } // end try catch( java.io.UnsupportedEncodingException uee ) { - bytes = s.getBytes(); + bytes = s.getBytes( StandardCharsets.UTF_8 ); } // end catch //</change> http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java b/avatica/core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java index 85b6d6c..406dcfd 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/util/DateTimeUtils.java @@ -20,6 +20,7 @@ import java.text.NumberFormat; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Calendar; +import java.util.Locale; import java.util.TimeZone; /** @@ -48,9 +49,15 @@ public class DateTimeUtils { public static final String TIMESTAMP_FORMAT_STRING = DATE_FORMAT_STRING + " " + TIME_FORMAT_STRING; - /** The GMT time zone. */ + /** The GMT time zone. + * + * @deprecated Use {@link #UTC_ZONE} */ + @Deprecated // to be removed before 2.0 public static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT"); + /** The UTC time zone. */ + public static final TimeZone UTC_ZONE = TimeZone.getTimeZone("UTC"); + /** The Java default time zone. */ public static final TimeZone DEFAULT_ZONE = TimeZone.getDefault(); @@ -85,15 +92,10 @@ public class DateTimeUtils { public static final Calendar ZERO_CALENDAR; static { - ZERO_CALENDAR = Calendar.getInstance(DateTimeUtils.GMT_ZONE); + ZERO_CALENDAR = Calendar.getInstance(DateTimeUtils.GMT_ZONE, Locale.ROOT); ZERO_CALENDAR.setTimeInMillis(0); } - /** - * Calendar set to local time. - */ - private static final Calendar LOCAL_CALENDAR = Calendar.getInstance(); - //~ Methods ---------------------------------------------------------------- /** @@ -117,11 +119,11 @@ public class DateTimeUtils { TimeZone tz, ParsePosition pp) { assert pattern != null; - SimpleDateFormat df = new SimpleDateFormat(pattern); + SimpleDateFormat df = new SimpleDateFormat(pattern, Locale.ROOT); if (tz == null) { tz = DEFAULT_ZONE; } - Calendar ret = Calendar.getInstance(tz); + Calendar ret = Calendar.getInstance(tz, Locale.ROOT); df.setCalendar(ret); df.setLenient(false); @@ -204,7 +206,7 @@ public class DateTimeUtils { if (!secFraction.matches("\\d+")) { return null; } - NumberFormat nf = NumberFormat.getIntegerInstance(); + NumberFormat nf = NumberFormat.getIntegerInstance(Locale.ROOT); Number num = nf.parse(s, pp); if ((num == null) || (pp.getIndex() != s.length())) { // Invalid decimal portion @@ -248,7 +250,7 @@ public class DateTimeUtils { * @throws IllegalArgumentException if the given pattern is invalid */ public static void checkDateFormat(String pattern) { - new SimpleDateFormat(pattern); + new SimpleDateFormat(pattern, Locale.ROOT); } /** @@ -258,7 +260,7 @@ public class DateTimeUtils { * @param format {@link SimpleDateFormat} pattern */ public static SimpleDateFormat newDateFormat(String format) { - SimpleDateFormat sdf = new SimpleDateFormat(format); + SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.ROOT); sdf.setLenient(false); return sdf; } @@ -999,6 +1001,12 @@ public class DateTimeUtils { return x - floorDiv(x, y) * y; } + /** Creates an instance of {@link Calendar} in the root locale and UTC time + * zone. */ + public static Calendar calendar() { + return Calendar.getInstance(UTC_ZONE, Locale.ROOT); + } + //~ Inner Classes ---------------------------------------------------------- /** http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/main/java/org/apache/calcite/avatica/util/Unsafe.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/util/Unsafe.java b/avatica/core/src/main/java/org/apache/calcite/avatica/util/Unsafe.java new file mode 100644 index 0000000..1d0238c --- /dev/null +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/util/Unsafe.java @@ -0,0 +1,55 @@ +/* + * 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.util.Calendar; +import java.util.Locale; + +/** + * Contains methods that call JDK methods that the + * <a href="https://github.com/policeman-tools/forbidden-apis">forbidden + * APIs checker</a> does not approve of. + * + * <p>This class is excluded from the check, so methods called via this class + * will not fail the build. + */ +public class Unsafe { + private Unsafe() {} + + /** Calls {@link System#exit}. */ + public static void systemExit(int status) { + System.exit(status); + } + + /** Calls {@link Object#notifyAll()}. */ + public static void notifyAll(Object o) { + o.notifyAll(); + } + + /** Calls {@link Object#wait()}. */ + public static void wait(Object o) throws InterruptedException { + o.wait(); + } + + /** Returns a {@link java.util.Calendar} with the local time zone and root + * locale. */ + public static Calendar localCalendar() { + return Calendar.getInstance(Locale.ROOT); + } +} + +// End Unsafe.java http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/test/java/org/apache/calcite/avatica/AvaticaResultSetConversionsTest.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/test/java/org/apache/calcite/avatica/AvaticaResultSetConversionsTest.java b/avatica/core/src/test/java/org/apache/calcite/avatica/AvaticaResultSetConversionsTest.java index 95d160b..bf3047f 100644 --- a/avatica/core/src/test/java/org/apache/calcite/avatica/AvaticaResultSetConversionsTest.java +++ b/avatica/core/src/test/java/org/apache/calcite/avatica/AvaticaResultSetConversionsTest.java @@ -18,6 +18,7 @@ package org.apache.calcite.avatica; import org.apache.calcite.avatica.ColumnMetaData.AvaticaType; import org.apache.calcite.avatica.remote.TypedValue; +import org.apache.calcite.avatica.util.DateTimeUtils; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -43,7 +44,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.TimeZone; import static org.hamcrest.CoreMatchers.isA; import static org.junit.Assert.assertEquals; @@ -913,8 +913,7 @@ public class AvaticaResultSetConversionsTest { } } - private static final Calendar DEFAULT_CALENDAR = Calendar - .getInstance(TimeZone.getTimeZone("GMT")); + private static final Calendar DEFAULT_CALENDAR = DateTimeUtils.calendar(); private static Connection connection = null; private static ResultSet resultSet = null; http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/test/java/org/apache/calcite/avatica/MetaResultSetTest.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/test/java/org/apache/calcite/avatica/MetaResultSetTest.java b/avatica/core/src/test/java/org/apache/calcite/avatica/MetaResultSetTest.java index 6ec1dc7..3d5eb80 100644 --- a/avatica/core/src/test/java/org/apache/calcite/avatica/MetaResultSetTest.java +++ b/avatica/core/src/test/java/org/apache/calcite/avatica/MetaResultSetTest.java @@ -30,6 +30,7 @@ import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Types; import java.util.List; +import java.util.Locale; import static org.junit.Assert.assertEquals; @@ -624,21 +625,21 @@ public class MetaResultSetTest { private static void assertColumn(ResultSetMetaData rsMeta, int column, String name, int type, int nullable) throws SQLException { assertEquals( - String.format( + String.format(Locale.ROOT, "Expected column %d to be named '%s', was '%s'.", column, name, rsMeta.getColumnName(column)), name, rsMeta.getColumnName(column)); assertEquals( - String.format( + String.format(Locale.ROOT, "Expected column %d type to be '%d', was '%d'.", column, type, rsMeta.getColumnType(column)), type, rsMeta.getColumnType(column)); assertEquals( - String.format( + String.format(Locale.ROOT, "Expected column %d nullability to be '%d', was '%d'.", column, nullable, rsMeta.isNullable(column)), nullable, http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/test/java/org/apache/calcite/avatica/remote/KerberosConnectionTest.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/test/java/org/apache/calcite/avatica/remote/KerberosConnectionTest.java b/avatica/core/src/test/java/org/apache/calcite/avatica/remote/KerberosConnectionTest.java index a57b95b..ad98569 100644 --- a/avatica/core/src/test/java/org/apache/calcite/avatica/remote/KerberosConnectionTest.java +++ b/avatica/core/src/test/java/org/apache/calcite/avatica/remote/KerberosConnectionTest.java @@ -22,6 +22,7 @@ import org.junit.Test; import org.mockito.Mockito; import java.io.File; +import java.util.Locale; import java.util.Map.Entry; import javax.security.auth.Subject; @@ -135,7 +136,8 @@ public class KerberosConnectionTest { end = start + 1000 * 60 * 60 * 24; // Ten minutes prior to expiration now = end - 1000 * 60 * 10; - assertTrue(String.format("start=%d, end=%d, now=%d", start, end, now), + assertTrue( + String.format(Locale.ROOT, "start=%d, end=%d, now=%d", start, end, now), renewal.shouldRenew(start, end, now)); } } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/test/java/org/apache/calcite/avatica/remote/TypedValueTest.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/test/java/org/apache/calcite/avatica/remote/TypedValueTest.java b/avatica/core/src/test/java/org/apache/calcite/avatica/remote/TypedValueTest.java index 9343ed2..7606a87 100644 --- a/avatica/core/src/test/java/org/apache/calcite/avatica/remote/TypedValueTest.java +++ b/avatica/core/src/test/java/org/apache/calcite/avatica/remote/TypedValueTest.java @@ -20,12 +20,12 @@ import org.apache.calcite.avatica.ColumnMetaData.Rep; import org.apache.calcite.avatica.proto.Common; import org.apache.calcite.avatica.util.Base64; import org.apache.calcite.avatica.util.ByteString; +import org.apache.calcite.avatica.util.DateTimeUtils; import org.junit.Test; import java.math.BigDecimal; import java.util.Calendar; -import java.util.GregorianCalendar; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; @@ -123,7 +123,8 @@ public class TypedValueTest { assertEquals(new ByteString(bytes).toBase64String(), (String) deserializedObj); // But we should get a non-b64 byte array as the JDBC representation - deserializedObj = TypedValue.protoToJdbc(proto, GregorianCalendar.getInstance()); + deserializedObj = + TypedValue.protoToJdbc(proto, DateTimeUtils.calendar()); assertThat(deserializedObj, is(instanceOf(byte[].class))); assertArrayEquals(bytes, (byte[]) deserializedObj); } @@ -151,7 +152,7 @@ public class TypedValueTest { @Test public void testLegacyDecimalParsing() { final BigDecimal decimal = new BigDecimal("123451234512345"); - final Calendar calendar = GregorianCalendar.getInstance(); + final Calendar calendar = DateTimeUtils.calendar(); // CALCITE-1103 Decimals were (incorrectly) getting serialized as normal "numbers" which // caused them to use the numberValue field. TypedValue should still be able to handle @@ -169,7 +170,7 @@ public class TypedValueTest { final byte[] b64Bytes = Base64.encodeBytes(bytes).getBytes(UTF_8); TypedValue tv = TypedValue.ofLocal(Rep.BYTE_STRING, new ByteString(bytes)); // JSON encodes it as base64 - assertEquals(new String(b64Bytes), tv.value); + assertEquals(new String(b64Bytes, UTF_8), tv.value); // Get the protobuf variant Common.TypedValue protoTv = tv.toProto(); @@ -182,7 +183,8 @@ public class TypedValueTest { assertArrayEquals(bytes, protoByteString.toByteArray()); // We should have the b64 string as a backwards compatibility feature - assertEquals(new String(b64Bytes), protoTv.getStringValue()); + assertEquals(new String(b64Bytes, UTF_8), + protoTv.getStringValue()); } @Test public void testLegacyBase64StringEncodingForBytes() { http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/core/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java b/avatica/core/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java index 366b507..b1a422c 100644 --- a/avatica/core/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java +++ b/avatica/core/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java @@ -28,6 +28,7 @@ import java.math.BigInteger; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashSet; +import java.util.Locale; import java.util.Properties; import java.util.Set; @@ -292,11 +293,11 @@ public class AvaticaUtilsTest { } public String name() { - return name.toUpperCase(); + return name.toUpperCase(Locale.ROOT); } public String camelName() { - return name.toLowerCase(); + return name.toLowerCase(Locale.ROOT); } public Object defaultValue() { http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/pom.xml ---------------------------------------------------------------------- diff --git a/avatica/pom.xml b/avatica/pom.xml index d8952aa..5860bd9 100644 --- a/avatica/pom.xml +++ b/avatica/pom.xml @@ -58,6 +58,7 @@ limitations under the License. <build-helper-maven-plugin.version>1.9</build-helper-maven-plugin.version> <checksum-maven-plugin.version>1.2</checksum-maven-plugin.version> <dropwizard-metrics3.version>3.1.2</dropwizard-metrics3.version> + <forbiddenapis.version>2.3</forbiddenapis.version> <freemarker.version>2.3.19</freemarker.version> <git-commit-id-plugin.version>2.1.9</git-commit-id-plugin.version> <!-- We support guava versions as old as 14.0.1 (the version used by Hive) @@ -300,6 +301,39 @@ limitations under the License. </extensions> <plugins> <plugin> + <groupId>de.thetaphi</groupId> + <artifactId>forbiddenapis</artifactId> + <configuration> + <!-- if the used Java version is too new, don't fail, just do nothing: --> + <failOnUnsupportedJava>false</failOnUnsupportedJava> + <bundledSignatures> + <!-- + This will automatically choose the right + signatures based on 'maven.compiler.target': + --> + <bundledSignature>jdk-unsafe</bundledSignature> + <bundledSignature>jdk-deprecated</bundledSignature> + <!-- disallow undocumented classes like sun.misc.Unsafe: --> + <bundledSignature>jdk-non-portable</bundledSignature> + </bundledSignatures> + <signaturesFiles> + <signaturesFile>${top.dir}/src/main/config/forbidden-apis/signatures.txt</signaturesFile> + </signaturesFiles> + <excludes> + <exclude>**/org/apache/calcite/avatica/tck/Unsafe.class</exclude> + <exclude>**/org/apache/calcite/avatica/util/Unsafe.class</exclude> + </excludes> + </configuration> + <executions> + <execution> + <goals> + <goal>check</goal> + <goal>testCheck</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> <groupId>org.apache.rat</groupId> <artifactId>apache-rat-plugin</artifactId> <configuration> @@ -486,6 +520,11 @@ limitations under the License. </dependencies> </plugin> <plugin> + <groupId>de.thetaphi</groupId> + <artifactId>forbiddenapis</artifactId> + <version>${forbiddenapis.version}</version> + </plugin> + <plugin> <groupId>net.hydromatic</groupId> <artifactId>hydromatic-resource-maven-plugin</artifactId> <version>${hydromatic-resource.version}</version> http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java b/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java index e90d78a..4756e8d 100644 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java +++ b/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java @@ -35,6 +35,7 @@ import org.apache.calcite.avatica.proto.Common; import org.apache.calcite.avatica.proto.Requests; import org.apache.calcite.avatica.remote.ProtobufMeta; import org.apache.calcite.avatica.remote.TypedValue; +import org.apache.calcite.avatica.util.Unsafe; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; @@ -85,7 +86,7 @@ public class JdbcMeta implements ProtobufMeta { // End of constants, start of member variables - final Calendar calendar = Calendar.getInstance(); + final Calendar calendar = Unsafe.localCalendar(); /** Generates ids for statements. The ids are unique across all connections * created by this JdbcMeta. */ http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java b/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java index 5383289..17b33f8 100644 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java +++ b/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java @@ -77,7 +77,7 @@ class JdbcResultSet extends Meta.MetaResultSet { public static JdbcResultSet create(String connectionId, int statementId, ResultSet resultSet, int maxRowCount, Meta.Signature signature) { try { - final Calendar calendar = Calendar.getInstance(DateTimeUtils.GMT_ZONE); + final Calendar calendar = DateTimeUtils.calendar(); final int fetchRowCount; if (maxRowCount == JdbcMeta.UNLIMITED_COUNT) { fetchRowCount = -1; http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java b/avatica/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java index 911d359..4c871f0 100644 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java +++ b/avatica/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java @@ -49,6 +49,7 @@ import java.security.Principal; import java.security.PrivilegedAction; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -246,7 +247,8 @@ public class HttpServer { final int port = connector.getLocalPort(); - return new RpcMetadataResponse(String.format("%s:%d", host, port)); + return new RpcMetadataResponse( + String.format(Locale.ROOT, "%s:%d", host, port)); } /** @@ -804,7 +806,9 @@ public class HttpServer { options.put("doNotPrompt", "true"); options.put("useKeyTab", "true"); options.put("isInitiator", "false"); - options.put("debug", System.getProperty("sun.security.krb5.debug", "false").toLowerCase()); + options.put("debug", + System.getProperty("sun.security.krb5.debug", "false") + .toLowerCase(Locale.ROOT)); return new AppConfigurationEntry[] {new AppConfigurationEntry(getKrb5LoginModuleName(), AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options)}; http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java b/avatica/server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java index 10bf85f..0823a12 100644 --- a/avatica/server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java +++ b/avatica/server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java @@ -26,6 +26,7 @@ import org.apache.calcite.avatica.remote.ProtobufTranslation; import org.apache.calcite.avatica.remote.ProtobufTranslationImpl; import org.apache.calcite.avatica.remote.Service; import org.apache.calcite.avatica.remote.TypedValue; +import org.apache.calcite.avatica.util.DateTimeUtils; import com.google.common.cache.Cache; @@ -59,6 +60,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.TimeZone; @@ -363,10 +365,11 @@ public class RemoteDriverTest { @Test public void testInsertDrop() throws Exception { final String t = AvaticaUtils.unique("TEST_TABLE2"); final String create = - String.format("create table if not exists %s (" + String.format(Locale.ROOT, "create table if not exists %s (" + "id int not null, " + "msg varchar(3) not null)", t); - final String insert = String.format("insert into %s values(1, 'foo')", t); + final String insert = String.format(Locale.ROOT, + "insert into %s values(1, 'foo')", t); Connection connection = ljs(); Statement statement = connection.createStatement(); statement.execute(create); @@ -558,14 +561,17 @@ public class RemoteDriverTest { @Test public void testCreateInsertUpdateDrop() throws Exception { ConnectionSpec.getDatabaseLock().lock(); final String t = AvaticaUtils.unique("TEST_TABLE"); - final String drop = String.format("drop table %s if exists", t); - final String create = String.format("create table %s(" - + "id int not null, " - + "msg varchar(3) not null)", - t); - final String insert = String.format("insert into %s values(1, 'foo')", t); + final String drop = + String.format(Locale.ROOT, "drop table %s if exists", t); + final String create = + String.format(Locale.ROOT, "create table %s(" + + "id int not null, " + + "msg varchar(3) not null)", + t); + final String insert = String.format(Locale.ROOT, + "insert into %s values(1, 'foo')", t); final String update = - String.format("update %s set msg='bar' where id=1", t); + String.format(Locale.ROOT, "update %s set msg='bar' where id=1", t); try (Connection connection = getLocalConnection(); Statement statement = connection.createStatement(); PreparedStatement pstmt = connection.prepareStatement("values 1")) { @@ -681,9 +687,11 @@ public class RemoteDriverTest { private void assertResultSetsEqual(Statement s1, Statement s2) throws SQLException { final TimeZone moscowTz = TimeZone.getTimeZone("Europe/Moscow"); - final Calendar moscowCalendar = Calendar.getInstance(moscowTz); + final Calendar moscowCalendar = + Calendar.getInstance(moscowTz, Locale.ROOT); final TimeZone alaskaTz = TimeZone.getTimeZone("America/Anchorage"); - final Calendar alaskaCalendar = Calendar.getInstance(alaskaTz); + final Calendar alaskaCalendar = + Calendar.getInstance(alaskaTz, Locale.ROOT); try (ResultSet rs1 = s1.getResultSet(); ResultSet rs2 = s2.getResultSet()) { assertEquals(rs1.getMetaData().getColumnCount(), @@ -1058,12 +1066,14 @@ public class RemoteDriverTest { try (Statement stmt = conn.createStatement()) { final String tableName = AvaticaUtils.unique("BATCH_EXECUTE"); LOG.info("Creating table {}", tableName); - final String createCommand = String.format("create table if not exists %s (" - + "id int not null, " - + "msg varchar(10) not null)", tableName); + final String createCommand = String.format(Locale.ROOT, + "create table if not exists %s (" + + "id int not null, " + + "msg varchar(10) not null)", tableName); assertFalse("Failed to create table", stmt.execute(createCommand)); - final String updatePrefix = String.format("INSERT INTO %s values(", tableName); + final String updatePrefix = + String.format(Locale.ROOT, "INSERT INTO %s values(", tableName); for (int i = 0; i < numRows; i++) { stmt.addBatch(updatePrefix + i + ", '" + Integer.toString(i) + "')"); } @@ -1104,13 +1114,15 @@ public class RemoteDriverTest { final String tableName = AvaticaUtils.unique("PREPARED_BATCH_EXECUTE"); LOG.info("Creating table {}", tableName); try (Statement stmt = conn.createStatement()) { - final String createCommand = String.format("create table if not exists %s (" - + "id int not null, " - + "msg varchar(10) not null)", tableName); + final String createCommand = + String.format(Locale.ROOT, "create table if not exists %s (" + + "id int not null, " + + "msg varchar(10) not null)", tableName); assertFalse("Failed to create table", stmt.execute(createCommand)); } - final String insertSql = String.format("INSERT INTO %s values(?, ?)", tableName); + final String insertSql = + String.format(Locale.ROOT, "INSERT INTO %s values(?, ?)", tableName); try (PreparedStatement pstmt = conn.prepareStatement(insertSql)) { // Add batches with the prepared statement for (int i = 0; i < numRows; i++) { @@ -1157,13 +1169,15 @@ public class RemoteDriverTest { final String tableName = AvaticaUtils.unique("PREPARED_INSERT_EXECUTE"); LOG.info("Creating table {}", tableName); try (Statement stmt = conn.createStatement()) { - final String createCommand = String.format("create table if not exists %s (" - + "id int not null, " - + "msg varchar(10) not null)", tableName); + final String createCommand = + String.format(Locale.ROOT, "create table if not exists %s (" + + "id int not null, " + + "msg varchar(10) not null)", tableName); assertFalse("Failed to create table", stmt.execute(createCommand)); } - final String insertSql = String.format("INSERT INTO %s values(?, ?)", tableName); + final String insertSql = + String.format(Locale.ROOT, "INSERT INTO %s values(?, ?)", tableName); try (PreparedStatement pstmt = conn.prepareStatement(insertSql)) { // Add batches with the prepared statement for (int i = 0; i < numRows; i++) { @@ -1204,13 +1218,15 @@ public class RemoteDriverTest { final String tableName = AvaticaUtils.unique("PREPARED_INSERT_EXECUTE_NULLS"); LOG.info("Creating table {}", tableName); try (Statement stmt = conn.createStatement()) { - final String createCommand = String.format("create table if not exists %s (" - + "id int not null, " - + "msg varchar(10))", tableName); + final String createCommand = + String.format(Locale.ROOT, "create table if not exists %s (" + + "id int not null, " + + "msg varchar(10))", tableName); assertFalse("Failed to create table", stmt.execute(createCommand)); } - final String insertSql = String.format("INSERT INTO %s values(?, ?)", tableName); + final String insertSql = + String.format(Locale.ROOT, "INSERT INTO %s values(?, ?)", tableName); try (PreparedStatement pstmt = conn.prepareStatement(insertSql)) { // Add batches with the prepared statement for (int i = 0; i < numRows; i++) { @@ -1260,13 +1276,15 @@ public class RemoteDriverTest { final String tableName = AvaticaUtils.unique("BATCH_INSERT_EXECUTE_NULLS"); LOG.info("Creating table {}", tableName); try (Statement stmt = conn.createStatement()) { - final String createCommand = String.format("create table if not exists %s (" - + "id int not null, " - + "msg varchar(10))", tableName); + final String createCommand = + String.format(Locale.ROOT, "create table if not exists %s (" + + "id int not null, " + + "msg varchar(10))", tableName); assertFalse("Failed to create table", stmt.execute(createCommand)); } - final String insertSql = String.format("INSERT INTO %s values(?, ?)", tableName); + final String insertSql = + String.format(Locale.ROOT, "INSERT INTO %s values(?, ?)", tableName); try (PreparedStatement pstmt = conn.prepareStatement(insertSql)) { // Add batches with the prepared statement for (int i = 0; i < numRows; i++) { @@ -1367,22 +1385,25 @@ public class RemoteDriverTest { } private void executeBatchInsertWithDates(Connection conn) throws Exception { - final Calendar calendar = Calendar.getInstance(); + final Calendar calendar = DateTimeUtils.calendar(); long now = calendar.getTime().getTime(); final int numRows = 10; final String tableName = AvaticaUtils.unique("BATCH_INSERT_EXECUTE_DATES"); LOG.info("Creating table {}", tableName); try (Statement stmt = conn.createStatement()) { - final String dropCommand = String.format("drop table if exists %s", tableName); + final String dropCommand = + String.format(Locale.ROOT, "drop table if exists %s", tableName); assertFalse("Failed to drop table", stmt.execute(dropCommand)); - final String createCommand = String.format("create table %s (" - + "id char(15) not null, " - + "created_date date not null, " - + "val_string varchar)", tableName); + final String createCommand = + String.format(Locale.ROOT, "create table %s (" + + "id char(15) not null, " + + "created_date date not null, " + + "val_string varchar)", tableName); assertFalse("Failed to create table", stmt.execute(createCommand)); } - final String insertSql = String.format("INSERT INTO %s values(?, ?, ?)", tableName); + final String insertSql = + String.format(Locale.ROOT, "INSERT INTO %s values(?, ?, ?)", tableName); try (PreparedStatement pstmt = conn.prepareStatement(insertSql)) { // Add batches with the prepared statement for (int i = 0; i < numRows; i++) { @@ -1472,7 +1493,7 @@ public class RemoteDriverTest { assertNotNull(metadata); String actualColumnName = metadata.getColumnName(1); // HSQLDB is going to upper-case the column name - assertEquals(columnName.toUpperCase(), actualColumnName); + assertEquals(columnName.toUpperCase(Locale.ROOT), actualColumnName); } finally { ConnectionSpec.getDatabaseLock().unlock(); } @@ -1521,13 +1542,15 @@ public class RemoteDriverTest { final String tableName = AvaticaUtils.unique("BATCH_CLEARS"); LOG.info("Creating table {}", tableName); try (Statement stmt = conn.createStatement()) { - final String createCommand = String.format("create table if not exists %s (" - + "id int not null, " - + "msg varchar(10) not null)", tableName); + final String createCommand = + String.format(Locale.ROOT, "create table if not exists %s (" + + "id int not null, " + + "msg varchar(10) not null)", tableName); assertFalse("Failed to create table", stmt.execute(createCommand)); } - final String insertSql = String.format("INSERT INTO %s values(?, ?)", tableName); + final String insertSql = + String.format(Locale.ROOT, "INSERT INTO %s values(?, ?)", tableName); try (PreparedStatement pstmt = conn.prepareStatement(insertSql)) { // Add batches with the prepared statement for (int i = 0; i < numRows; i++) { @@ -1579,12 +1602,14 @@ public class RemoteDriverTest { try (Statement stmt = conn.createStatement()) { final String tableName = AvaticaUtils.unique("BATCH_EXECUTE"); LOG.info("Creating table {}", tableName); - final String createCommand = String.format("create table if not exists %s (" - + "id int not null, " - + "msg varchar(10) not null)", tableName); + final String createCommand = + String.format(Locale.ROOT, "create table if not exists %s (" + + "id int not null, " + + "msg varchar(10) not null)", tableName); assertFalse("Failed to create table", stmt.execute(createCommand)); - final String updatePrefix = String.format("INSERT INTO %s values(", tableName); + final String updatePrefix = + String.format(Locale.ROOT, "INSERT INTO %s values(", tableName); for (int i = 0; i < numRows; i++) { stmt.addBatch(updatePrefix + i + ", '" + Integer.toString(i) + "')"); if (numRows / 2 - 1 == i) { @@ -1688,7 +1713,7 @@ public class RemoteDriverTest { String sql = "CREATE TABLE " + tableName + " (keycolumn VARCHAR(5), column1 date)"; assertFalse(stmt.execute(sql)); TimeZone tzUtc = TimeZone.getTimeZone("UTC"); - Calendar cUtc = Calendar.getInstance(tzUtc); + Calendar cUtc = Calendar.getInstance(tzUtc, Locale.ROOT); cUtc.set(Calendar.YEAR, 1970); cUtc.set(Calendar.MONTH, Calendar.JANUARY); cUtc.set(Calendar.DAY_OF_MONTH, 1); @@ -1726,7 +1751,7 @@ public class RemoteDriverTest { String sql = "CREATE TABLE " + tableName + " (keycolumn VARCHAR(5), column1 date)"; assertFalse(stmt.execute(sql)); TimeZone tzUtc = TimeZone.getTimeZone("GMT+8"); - Calendar cUtc = Calendar.getInstance(tzUtc); + Calendar cUtc = Calendar.getInstance(tzUtc, Locale.ROOT); cUtc.set(Calendar.YEAR, 1970); cUtc.set(Calendar.MONTH, Calendar.JANUARY); cUtc.set(Calendar.DAY_OF_MONTH, 1); http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/server/src/test/java/org/apache/calcite/avatica/SpnegoTestUtil.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/test/java/org/apache/calcite/avatica/SpnegoTestUtil.java b/avatica/server/src/test/java/org/apache/calcite/avatica/SpnegoTestUtil.java index 21248f6..ab4491d 100644 --- a/avatica/server/src/test/java/org/apache/calcite/avatica/SpnegoTestUtil.java +++ b/avatica/server/src/test/java/org/apache/calcite/avatica/SpnegoTestUtil.java @@ -32,9 +32,11 @@ import org.eclipse.jetty.server.handler.DefaultHandler; import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; import java.net.ServerSocket; +import java.nio.charset.StandardCharsets; import java.security.AccessController; import java.security.Principal; import java.security.PrivilegedAction; @@ -99,7 +101,11 @@ public class SpnegoTestUtil { */ public static void writeSpnegoConf(File configFile, File serverKeytab) throws Exception { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(configFile))) { + try (BufferedWriter writer = + new BufferedWriter( + new OutputStreamWriter( + new FileOutputStream(configFile), + StandardCharsets.UTF_8))) { // Server login writer.write("com.sun.security.jgss.accept {\n"); writer.write(" com.sun.security.auth.module.Krb5LoginModule required\n"); http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/server/src/test/java/org/apache/calcite/avatica/SslDriverTest.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/test/java/org/apache/calcite/avatica/SslDriverTest.java b/avatica/server/src/test/java/org/apache/calcite/avatica/SslDriverTest.java index 9dcdfa2..e3b89f5 100644 --- a/avatica/server/src/test/java/org/apache/calcite/avatica/SslDriverTest.java +++ b/avatica/server/src/test/java/org/apache/calcite/avatica/SslDriverTest.java @@ -20,6 +20,7 @@ import org.apache.calcite.avatica.jdbc.JdbcMeta; import org.apache.calcite.avatica.remote.Driver; import org.apache.calcite.avatica.remote.LocalService; import org.apache.calcite.avatica.server.HttpServer; +import org.apache.calcite.avatica.util.DateTimeUtils; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.style.IETFUtils; @@ -195,8 +196,8 @@ public class SslDriverTest { PublicKey signerPublicKey, PrivateKey signerPrivateKey) throws IOException, CertIOException, OperatorCreationException, CertificateException, NoSuchAlgorithmException { - Calendar startDate = Calendar.getInstance(); - Calendar endDate = Calendar.getInstance(); + Calendar startDate = DateTimeUtils.calendar(); + Calendar endDate = DateTimeUtils.calendar(); endDate.add(Calendar.YEAR, 100); BigInteger serialNumber = BigInteger.valueOf(startDate.getTimeInMillis()); http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica/server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java index 24bcdc6..ebd3c76 100644 --- a/avatica/server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java +++ b/avatica/server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java @@ -66,6 +66,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Random; @@ -319,14 +320,15 @@ public class RemoteMetaTest { AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url); Statement statement = conn.createStatement(); final String create = - String.format("create table if not exists %s (" + String.format(Locale.ROOT, "create table if not exists %s (" + " id int not null, msg varchar(255) not null)", t); int status = statement.executeUpdate(create); assertEquals(status, 0); statement = conn.createStatement(); - final String update = String.format("insert into %s values ('%d', '%s')", - t, RANDOM.nextInt(Integer.MAX_VALUE), UUID.randomUUID()); + final String update = + String.format(Locale.ROOT, "insert into %s values ('%d', '%s')", + t, RANDOM.nextInt(Integer.MAX_VALUE), UUID.randomUUID()); status = statement.executeUpdate(update); assertEquals(status, 1); } finally { @@ -584,26 +586,35 @@ public class RemoteMetaTest { assertFalse(stmt.execute("DROP TABLE IF EXISTS " + productTable)); assertFalse( stmt.execute( - String.format("CREATE TABLE %s(id integer, stock integer)", productTable))); + String.format(Locale.ROOT, + "CREATE TABLE %s(id integer, stock integer)", + productTable))); assertFalse(stmt.execute("DROP TABLE IF EXISTS " + salesTable)); assertFalse( stmt.execute( - String.format("CREATE TABLE %s(id integer, units_sold integer)", salesTable))); + String.format(Locale.ROOT, + "CREATE TABLE %s(id integer, units_sold integer)", + salesTable))); final int productId = 1; // No products and no sales assertFalse( stmt.execute( - String.format("INSERT INTO %s VALUES(%d, 0)", productTable, productId))); + String.format(Locale.ROOT, "INSERT INTO %s VALUES(%d, 0)", + productTable, productId))); assertFalse( stmt.execute( - String.format("INSERT INTO %s VALUES(%d, 0)", salesTable, productId))); + String.format(Locale.ROOT, "INSERT INTO %s VALUES(%d, 0)", + salesTable, productId))); conn.setAutoCommit(false); PreparedStatement productStmt = conn.prepareStatement( - String.format("UPDATE %s SET stock = stock + ? WHERE id = ?", productTable)); + String.format(Locale.ROOT, + "UPDATE %s SET stock = stock + ? WHERE id = ?", productTable)); PreparedStatement salesStmt = conn.prepareStatement( - String.format("UPDATE %s SET units_sold = units_sold + ? WHERE id = ?", salesTable)); + String.format(Locale.ROOT, + "UPDATE %s SET units_sold = units_sold + ? WHERE id = ?", + salesTable)); // No stock assertEquals(0, getInventory(conn, productTable, productId)); @@ -651,7 +662,8 @@ public class RemoteMetaTest { private int getInventory(Connection conn, String productTable, int productId) throws Exception { try (Statement stmt = conn.createStatement()) { ResultSet results = stmt.executeQuery( - String.format("SELECT stock FROM %s WHERE id = %d", productTable, productId)); + String.format(Locale.ROOT, "SELECT stock FROM %s WHERE id = %d", + productTable, productId)); assertTrue(results.next()); return results.getInt(1); } @@ -660,7 +672,8 @@ public class RemoteMetaTest { private int getSales(Connection conn, String salesTable, int productId) throws Exception { try (Statement stmt = conn.createStatement()) { ResultSet results = stmt.executeQuery( - String.format("SELECT units_sold FROM %s WHERE id = %d", salesTable, productId)); + String.format(Locale.ROOT, "SELECT units_sold FROM %s WHERE id = %d", + salesTable, productId)); assertTrue(results.next()); return results.getInt(1); } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/server/src/test/java/org/apache/calcite/avatica/server/AbstractAvaticaHandlerTest.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/test/java/org/apache/calcite/avatica/server/AbstractAvaticaHandlerTest.java b/avatica/server/src/test/java/org/apache/calcite/avatica/server/AbstractAvaticaHandlerTest.java index c5f9441..66eb361 100644 --- a/avatica/server/src/test/java/org/apache/calcite/avatica/server/AbstractAvaticaHandlerTest.java +++ b/avatica/server/src/test/java/org/apache/calcite/avatica/server/AbstractAvaticaHandlerTest.java @@ -24,6 +24,7 @@ import org.junit.Before; import org.junit.Test; import java.net.HttpURLConnection; +import java.nio.charset.StandardCharsets; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; @@ -72,7 +73,7 @@ public class AbstractAvaticaHandlerTest { } @Override public boolean matches(Object item) { - String msg = new String((byte[]) item); + String msg = new String((byte[]) item, StandardCharsets.UTF_8); return msg.contains("User is not authenticated"); } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithJaasTest.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithJaasTest.java b/avatica/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithJaasTest.java index e9c5299..8f6fede 100644 --- a/avatica/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithJaasTest.java +++ b/avatica/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithJaasTest.java @@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.net.HttpURLConnection; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.security.Principal; import java.security.PrivilegedExceptionAction; import java.util.Set; @@ -220,7 +221,8 @@ public class HttpServerSpnegoWithJaasTest { // We should get a response which is "OK" with our client's name assertNotNull(response); - assertEquals("OK " + SpnegoTestUtil.CLIENT_PRINCIPAL, new String(response)); + assertEquals("OK " + SpnegoTestUtil.CLIENT_PRINCIPAL, + new String(response, StandardCharsets.UTF_8)); } } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithoutJaasTest.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithoutJaasTest.java b/avatica/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithoutJaasTest.java index 1f234d2..d30b760 100644 --- a/avatica/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithoutJaasTest.java +++ b/avatica/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithoutJaasTest.java @@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.net.HttpURLConnection; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.security.Principal; import java.security.PrivilegedExceptionAction; import java.util.Set; @@ -211,7 +212,8 @@ public class HttpServerSpnegoWithoutJaasTest { // We should get a response which is "OK" with our client's name assertNotNull(response); - assertEquals("OK " + SpnegoTestUtil.CLIENT_PRINCIPAL, new String(response)); + assertEquals("OK " + SpnegoTestUtil.CLIENT_PRINCIPAL, + new String(response, StandardCharsets.UTF_8)); } } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/src/main/config/forbidden-apis/signatures.txt ---------------------------------------------------------------------- diff --git a/avatica/src/main/config/forbidden-apis/signatures.txt b/avatica/src/main/config/forbidden-apis/signatures.txt new file mode 100644 index 0000000..588837d --- /dev/null +++ b/avatica/src/main/config/forbidden-apis/signatures.txt @@ -0,0 +1,39 @@ +# 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. +# +# Signatures of APIs to avoid. +# Cribbed from Elasticsearch + +java.lang.Character#codePointBefore(char[],int) @ Implicit start offset is error-prone when the char[] is a buffer and the first chars are random chars +java.lang.Character#codePointAt(char[],int) @ Implicit end offset is error-prone when the char[] is a buffer and the last chars are random chars + +@defaultMessage Only use wait / notify when really needed try to use concurrency primitives, latches or callbacks instead. +java.lang.Object#wait() +java.lang.Object#wait(long) +java.lang.Object#wait(long,int) +java.lang.Object#notify() +java.lang.Object#notifyAll() + +@defaultMessage Please do not try to stop the world +java.lang.System#gc() + +@defaultMessage Please do not try to kill the world +java.lang.System#exit(int) +java.lang.Runtime#exit(int) + +@defaultMessage Don't interrupt threads; use FutureUtils#cancel(Future<T>) instead +java.util.concurrent.Future#cancel(boolean) + +# End signatures.txt http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/standalone-server/src/main/java/org/apache/calcite/avatica/hsqldb/HsqldbServer.java ---------------------------------------------------------------------- diff --git a/avatica/standalone-server/src/main/java/org/apache/calcite/avatica/hsqldb/HsqldbServer.java b/avatica/standalone-server/src/main/java/org/apache/calcite/avatica/hsqldb/HsqldbServer.java index 3e873a5..9e30dad 100644 --- a/avatica/standalone-server/src/main/java/org/apache/calcite/avatica/hsqldb/HsqldbServer.java +++ b/avatica/standalone-server/src/main/java/org/apache/calcite/avatica/hsqldb/HsqldbServer.java @@ -20,6 +20,7 @@ import org.apache.calcite.avatica.jdbc.JdbcMeta; import org.apache.calcite.avatica.remote.Driver.Serialization; import org.apache.calcite.avatica.remote.LocalService; import org.apache.calcite.avatica.server.HttpServer; +import org.apache.calcite.avatica.util.Unsafe; import com.beust.jcommander.IStringConverter; import com.beust.jcommander.JCommander; @@ -30,6 +31,8 @@ import net.hydromatic.scott.data.hsqldb.ScottHsqldb; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Locale; + /** * An Avatica server for HSQLDB. */ @@ -49,7 +52,7 @@ public class HsqldbServer { public void start() { if (null != server) { LOG.error("The server was already started"); - System.exit(ExitCodes.ALREADY_STARTED.ordinal()); + Unsafe.systemExit(ExitCodes.ALREADY_STARTED.ordinal()); return; } @@ -71,7 +74,7 @@ public class HsqldbServer { serialization); } catch (Exception e) { LOG.error("Failed to start Avatica server", e); - System.exit(ExitCodes.START_FAILED.ordinal()); + Unsafe.systemExit(ExitCodes.START_FAILED.ordinal()); } } @@ -117,7 +120,7 @@ public class HsqldbServer { */ public static class SerializationConverter implements IStringConverter<Serialization> { @Override public Serialization convert(String value) { - return Serialization.valueOf(value.toUpperCase()); + return Serialization.valueOf(value.toUpperCase(Locale.ROOT)); } } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/tck/src/main/java/org/apache/calcite/avatica/tck/TestRunner.java ---------------------------------------------------------------------- diff --git a/avatica/tck/src/main/java/org/apache/calcite/avatica/tck/TestRunner.java b/avatica/tck/src/main/java/org/apache/calcite/avatica/tck/TestRunner.java index 9ada4a4..6807354 100644 --- a/avatica/tck/src/main/java/org/apache/calcite/avatica/tck/TestRunner.java +++ b/avatica/tck/src/main/java/org/apache/calcite/avatica/tck/TestRunner.java @@ -77,7 +77,7 @@ public class TestRunner implements Runnable { if (null == driver) { LOG.error("Failed to find driver for {}", jdbcUrl); - System.exit(TestRunnerExitCodes.NO_SUCH_DRIVER.ordinal()); + Unsafe.systemExit(TestRunnerExitCodes.NO_SUCH_DRIVER.ordinal()); return; } @@ -98,10 +98,10 @@ public class TestRunner implements Runnable { if (globalResults.numFailed > 0) { // Tests failed, don't exit normally - System.exit(TestRunnerExitCodes.FAILED_TESTS.ordinal()); + Unsafe.systemExit(TestRunnerExitCodes.FAILED_TESTS.ordinal()); } else { // Exited normally - System.exit(TestRunnerExitCodes.NORMAL.ordinal()); + Unsafe.systemExit(TestRunnerExitCodes.NORMAL.ordinal()); } } @@ -132,7 +132,7 @@ public class TestRunner implements Runnable { return testClasses; } catch (Exception e) { LOG.error("Failed to instantiate test classes", e); - System.exit(TestRunnerExitCodes.TEST_CASE_INSTANTIATION.ordinal()); + Unsafe.systemExit(TestRunnerExitCodes.TEST_CASE_INSTANTIATION.ordinal()); // Unreachable.. return null; } @@ -146,10 +146,10 @@ public class TestRunner implements Runnable { driver = DriverManager.getDriver(driverUrl); } catch (SQLException e) { LOG.error("Could not instantiate JDBC Driver with URL: '{}'", jdbcUrl, e); - System.exit(TestRunnerExitCodes.BAD_JDBC_URL.ordinal()); + Unsafe.systemExit(TestRunnerExitCodes.BAD_JDBC_URL.ordinal()); } catch (ClassNotFoundException e) { LOG.error("Could not load Avatica Driver class", e); - System.exit(TestRunnerExitCodes.MISSING_DRIVER_CLASS.ordinal()); + Unsafe.systemExit(TestRunnerExitCodes.MISSING_DRIVER_CLASS.ordinal()); } } http://git-wip-us.apache.org/repos/asf/calcite/blob/8df27ce9/avatica/tck/src/main/java/org/apache/calcite/avatica/tck/Unsafe.java ---------------------------------------------------------------------- diff --git a/avatica/tck/src/main/java/org/apache/calcite/avatica/tck/Unsafe.java b/avatica/tck/src/main/java/org/apache/calcite/avatica/tck/Unsafe.java new file mode 100644 index 0000000..e88b6b7 --- /dev/null +++ b/avatica/tck/src/main/java/org/apache/calcite/avatica/tck/Unsafe.java @@ -0,0 +1,55 @@ +/* + * 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.tck; + +import java.util.Calendar; +import java.util.Locale; + +/** + * Contains methods that call JDK methods that the + * <a href="https://github.com/policeman-tools/forbidden-apis">forbidden + * APIs checker</a> does not approve of. + * + * <p>This class is excluded from the check, so methods called via this class + * will not fail the build. + */ +class Unsafe { + private Unsafe() {} + + /** Calls {@link System#exit}. */ + static void systemExit(int status) { + System.exit(status); + } + + /** Calls {@link Object#notifyAll()}. */ + public static void notifyAll(Object o) { + o.notifyAll(); + } + + /** Calls {@link Object#wait()}. */ + public static void wait(Object o) throws InterruptedException { + o.wait(); + } + + /** Returns a {@link Calendar} with the local time zone and root + * locale. */ + public static Calendar localCalendar() { + return Calendar.getInstance(Locale.ROOT); + } +} + +// End Unsafe.java
