From c90c5cc7b92544cbad3ae300d992a32f8dd48c29 Mon Sep 17 00:00:00 2001 From: Istvan Toth Date: Wed, 18 Jun 2025 10:20:50 +0200 Subject: [PATCH 1/3] ZOOKEEPER-4942: Add option to preserve JVM TLS certification revocation properties --- .../zookeeper/common/ClientX509Util.java | 12 ++++--- .../org/apache/zookeeper/common/X509Util.java | 34 +++++++++++------- .../org/apache/zookeeper/common/ZKConfig.java | 18 ++++++++++ .../auth/X509AuthenticationProvider.java | 4 +-- .../apache/zookeeper/common/X509UtilTest.java | 36 +++++++++++++++++++ 5 files changed, 85 insertions(+), 19 deletions(-) diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java index 9aa03ae491a..0f88461056f 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java @@ -79,7 +79,9 @@ public SslContext createNettySslContextForClient(ZKConfig config) sslContextBuilder.trustManager(tm); } - sslContextBuilder.enableOcsp(config.getBoolean(getSslOcspEnabledProperty())); + if (config.getTriState(getSslOcspEnabledProperty()) != null) { + sslContextBuilder.enableOcsp(config.getBoolean(getSslOcspEnabledProperty())); + } String[] enabledProtocols = getEnabledProtocols(config); if (enabledProtocols != null) { sslContextBuilder.protocols(enabledProtocols); @@ -123,7 +125,9 @@ public SslContext createNettySslContextForServer(ZKConfig config, KeyManager key sslContextBuilder.trustManager(trustManager); } - sslContextBuilder.enableOcsp(config.getBoolean(getSslOcspEnabledProperty())); + if (config.getTriState(getSslOcspEnabledProperty()) != null) { + sslContextBuilder.enableOcsp(config.getBoolean(getSslOcspEnabledProperty())); + } String[] enabledProtocols = getEnabledProtocols(config); if (enabledProtocols != null) { sslContextBuilder.protocols(enabledProtocols); @@ -189,8 +193,8 @@ private TrustManager getTrustManager(ZKConfig config) throws X509Exception.Trust getSslTruststorePasswdPathProperty()); String trustStoreType = config.getProperty(getSslTruststoreTypeProperty()); - boolean sslCrlEnabled = config.getBoolean(getSslCrlEnabledProperty()); - boolean sslOcspEnabled = config.getBoolean(getSslOcspEnabledProperty()); + Boolean sslCrlEnabled = config.getTriState(getSslCrlEnabledProperty()); + Boolean sslOcspEnabled = config.getTriState(getSslOcspEnabledProperty()); boolean sslServerHostnameVerificationEnabled = isServerHostnameVerificationEnabled(config); boolean sslClientHostnameVerificationEnabled = isClientHostnameVerificationEnabled(config); diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java b/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java index 153a826ba4f..166332557dc 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java @@ -392,8 +392,8 @@ public SSLContextAndOptions createSSLContextAndOptionsFromConfig(ZKConfig config String trustStorePasswordProp = getPasswordFromConfigPropertyOrFile(config, sslTruststorePasswdProperty, sslTruststorePasswdPathProperty); String trustStoreTypeProp = config.getProperty(sslTruststoreTypeProperty); - boolean sslCrlEnabled = config.getBoolean(this.sslCrlEnabledProperty); - boolean sslOcspEnabled = config.getBoolean(this.sslOcspEnabledProperty); + Boolean sslCrlEnabled = config.getTriState(this.sslCrlEnabledProperty); + Boolean sslOcspEnabled = config.getTriState(this.sslOcspEnabledProperty); boolean sslServerHostnameVerificationEnabled = isServerHostnameVerificationEnabled(config); boolean sslClientHostnameVerificationEnabled = isClientHostnameVerificationEnabled(config); boolean fipsMode = getFipsMode(config); @@ -537,8 +537,8 @@ public static X509TrustManager createTrustManager( String trustStoreLocation, String trustStorePassword, String trustStoreTypeProp, - boolean crlEnabled, - boolean ocspEnabled, + Boolean crlEnabled, + Boolean ocspEnabled, final boolean serverHostnameVerificationEnabled, final boolean clientHostnameVerificationEnabled, final boolean fipsMode) throws TrustManagerException { @@ -548,17 +548,25 @@ public static X509TrustManager createTrustManager( try { KeyStore ts = loadTrustStore(trustStoreLocation, trustStorePassword, trustStoreTypeProp); PKIXBuilderParameters pbParams = new PKIXBuilderParameters(ts, new X509CertSelector()); - if (crlEnabled || ocspEnabled) { - pbParams.setRevocationEnabled(true); - System.setProperty("com.sun.net.ssl.checkRevocation", "true"); - System.setProperty("com.sun.security.enableCRLDP", "true"); - if (ocspEnabled) { - Security.setProperty("ocsp.enable", "true"); + // Leave CRL/OCSP JVM global properties alone both are set to "system" (represented as null) + if (crlEnabled != null || ocspEnabled != null) { + if (crlEnabled == null) { + crlEnabled = false; } - } else { - pbParams.setRevocationEnabled(false); + if (ocspEnabled == null) { + ocspEnabled = false; + } + if (crlEnabled || ocspEnabled) { + pbParams.setRevocationEnabled(true); + System.setProperty("com.sun.net.ssl.checkRevocation", "true"); + System.setProperty("com.sun.security.enableCRLDP", "true"); + if (ocspEnabled) { + Security.setProperty("ocsp.enable", "true"); + } + } else { + pbParams.setRevocationEnabled(false); + } } - // Revocation checking is only supported with the PKIX algorithm TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); tmf.init(new CertPathTrustManagerParameters(pbParams)); diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java index 846a5632e06..dd069d56b42 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java @@ -233,6 +233,24 @@ private void parseProperties(Properties cfg) { } } + /** + * Returns {@code Boolean.True} if and only if the property named by the argument + * exists and is case insensitive equal to the string {@code "true"}. + * Returns {@code nuln} if and only if the property named by the argument + * exists and is case insensitive equal to the string {@code "system"}. + * Returns {@code Boolean.False} otherwise. + */ + public Boolean getTriState(String key) { + String propertyValue = getProperty(key); + if (propertyValue != null && propertyValue.equalsIgnoreCase("system")) { + return null; + } else if (propertyValue == null) { + return false; + } else { + return Boolean.parseBoolean(propertyValue.trim()); + } + } + /** * Returns {@code true} if and only if the property named by the argument * exists and is equal to the string {@code "true"}. diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java index 4ea925320f6..cfa17676fc8 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java @@ -85,8 +85,8 @@ public X509AuthenticationProvider() throws X509Exception { x509Util.getSslKeystorePasswdPathProperty()); String keyStoreTypeProp = config.getProperty(x509Util.getSslKeystoreTypeProperty()); - boolean crlEnabled = Boolean.parseBoolean(config.getProperty(x509Util.getSslCrlEnabledProperty())); - boolean ocspEnabled = Boolean.parseBoolean(config.getProperty(x509Util.getSslOcspEnabledProperty())); + Boolean crlEnabled = config.getTriState(x509Util.getSslOcspEnabledProperty()); + Boolean ocspEnabled = config.getTriState(x509Util.getSslOcspEnabledProperty()); boolean hostnameVerificationEnabled = Boolean.parseBoolean(config.getProperty(x509Util.getSslHostnameVerificationEnabledProperty())); X509KeyManager km = null; diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java index e4f19d77fd1..e11c98b7bbc 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java @@ -266,6 +266,42 @@ public void testOCSPEnabled( assertTrue(Boolean.valueOf(Security.getProperty("ocsp.enable"))); } + @ParameterizedTest + @MethodSource("data") + @Timeout(value = 5) + public void testOCSPCRLTransparentFalse( + X509KeyType caKeyType, X509KeyType certKeyType, String keyPassword, Integer paramIndex) + throws Exception { + System.setProperty("com.sun.net.ssl.checkRevocation", Boolean.FALSE.toString()); + System.setProperty("com.sun.security.enableCRLDP", Boolean.FALSE.toString()); + Security.setProperty("ocsp.enable", Boolean.FALSE.toString()); + init(caKeyType, certKeyType, keyPassword, paramIndex); + System.setProperty(x509Util.getSslOcspEnabledProperty(), "system"); + System.setProperty(x509Util.getSslCrlEnabledProperty(), "system"); + x509Util.getDefaultSSLContext(); + assertFalse(Boolean.valueOf(System.getProperty("com.sun.net.ssl.checkRevocation"))); + assertFalse(Boolean.valueOf(System.getProperty("com.sun.security.enableCRLDP"))); + assertFalse(Boolean.valueOf(Security.getProperty("ocsp.enable"))); + } + + @ParameterizedTest + @MethodSource("data") + @Timeout(value = 5) + public void testOCSPCRLTransparentTrue( + X509KeyType caKeyType, X509KeyType certKeyType, String keyPassword, Integer paramIndex) + throws Exception { + System.setProperty("com.sun.net.ssl.checkRevocation", Boolean.TRUE.toString()); + System.setProperty("com.sun.security.enableCRLDP", Boolean.TRUE.toString()); + Security.setProperty("ocsp.enable", Boolean.TRUE.toString()); + init(caKeyType, certKeyType, keyPassword, paramIndex); + System.setProperty(x509Util.getSslOcspEnabledProperty(), "system"); + System.setProperty(x509Util.getSslCrlEnabledProperty(), "system"); + x509Util.getDefaultSSLContext(); + assertTrue(Boolean.valueOf(System.getProperty("com.sun.net.ssl.checkRevocation"))); + assertTrue(Boolean.valueOf(System.getProperty("com.sun.security.enableCRLDP"))); + assertTrue(Boolean.valueOf(Security.getProperty("ocsp.enable"))); + } + @ParameterizedTest @MethodSource("data") @Timeout(value = 5) From a8aec1d86e94595f604384bb77318c90c2392b4c Mon Sep 17 00:00:00 2001 From: Istvan Toth Date: Wed, 18 Jun 2025 13:25:29 +0200 Subject: [PATCH 2/3] refactor to use Enum --- .../zookeeper/common/ClientX509Util.java | 8 ++-- .../org/apache/zookeeper/common/X509Util.java | 20 +++------ .../org/apache/zookeeper/common/ZKConfig.java | 10 +---- .../auth/X509AuthenticationProvider.java | 5 ++- .../apache/zookeeper/common/X509UtilTest.java | 44 +++++++++---------- 5 files changed, 38 insertions(+), 49 deletions(-) diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java index 0f88461056f..1c2b0e49ea5 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java @@ -79,7 +79,7 @@ public SslContext createNettySslContextForClient(ZKConfig config) sslContextBuilder.trustManager(tm); } - if (config.getTriState(getSslOcspEnabledProperty()) != null) { + if (!config.getTriState(getSslOcspEnabledProperty()).isSystem()) { sslContextBuilder.enableOcsp(config.getBoolean(getSslOcspEnabledProperty())); } String[] enabledProtocols = getEnabledProtocols(config); @@ -125,7 +125,7 @@ public SslContext createNettySslContextForServer(ZKConfig config, KeyManager key sslContextBuilder.trustManager(trustManager); } - if (config.getTriState(getSslOcspEnabledProperty()) != null) { + if (!config.getTriState(getSslOcspEnabledProperty()).isSystem()) { sslContextBuilder.enableOcsp(config.getBoolean(getSslOcspEnabledProperty())); } String[] enabledProtocols = getEnabledProtocols(config); @@ -193,8 +193,8 @@ private TrustManager getTrustManager(ZKConfig config) throws X509Exception.Trust getSslTruststorePasswdPathProperty()); String trustStoreType = config.getProperty(getSslTruststoreTypeProperty()); - Boolean sslCrlEnabled = config.getTriState(getSslCrlEnabledProperty()); - Boolean sslOcspEnabled = config.getTriState(getSslOcspEnabledProperty()); + TriState sslCrlEnabled = config.getTriState(getSslCrlEnabledProperty()); + TriState sslOcspEnabled = config.getTriState(getSslOcspEnabledProperty()); boolean sslServerHostnameVerificationEnabled = isServerHostnameVerificationEnabled(config); boolean sslClientHostnameVerificationEnabled = isClientHostnameVerificationEnabled(config); diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java b/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java index 166332557dc..60000a19cfc 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java @@ -392,8 +392,8 @@ public SSLContextAndOptions createSSLContextAndOptionsFromConfig(ZKConfig config String trustStorePasswordProp = getPasswordFromConfigPropertyOrFile(config, sslTruststorePasswdProperty, sslTruststorePasswdPathProperty); String trustStoreTypeProp = config.getProperty(sslTruststoreTypeProperty); - Boolean sslCrlEnabled = config.getTriState(this.sslCrlEnabledProperty); - Boolean sslOcspEnabled = config.getTriState(this.sslOcspEnabledProperty); + TriState sslCrlEnabled = config.getTriState(this.sslCrlEnabledProperty); + TriState sslOcspEnabled = config.getTriState(this.sslOcspEnabledProperty); boolean sslServerHostnameVerificationEnabled = isServerHostnameVerificationEnabled(config); boolean sslClientHostnameVerificationEnabled = isClientHostnameVerificationEnabled(config); boolean fipsMode = getFipsMode(config); @@ -537,8 +537,8 @@ public static X509TrustManager createTrustManager( String trustStoreLocation, String trustStorePassword, String trustStoreTypeProp, - Boolean crlEnabled, - Boolean ocspEnabled, + TriState crlEnabled, + TriState ocspEnabled, final boolean serverHostnameVerificationEnabled, final boolean clientHostnameVerificationEnabled, final boolean fipsMode) throws TrustManagerException { @@ -549,18 +549,12 @@ public static X509TrustManager createTrustManager( KeyStore ts = loadTrustStore(trustStoreLocation, trustStorePassword, trustStoreTypeProp); PKIXBuilderParameters pbParams = new PKIXBuilderParameters(ts, new X509CertSelector()); // Leave CRL/OCSP JVM global properties alone both are set to "system" (represented as null) - if (crlEnabled != null || ocspEnabled != null) { - if (crlEnabled == null) { - crlEnabled = false; - } - if (ocspEnabled == null) { - ocspEnabled = false; - } - if (crlEnabled || ocspEnabled) { + if (!crlEnabled.isSystem() || !ocspEnabled.isSystem()) { + if (crlEnabled.isTrue() || ocspEnabled.isTrue()) { pbParams.setRevocationEnabled(true); System.setProperty("com.sun.net.ssl.checkRevocation", "true"); System.setProperty("com.sun.security.enableCRLDP", "true"); - if (ocspEnabled) { + if (ocspEnabled.isTrue()) { Security.setProperty("ocsp.enable", "true"); } } else { diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java index dd069d56b42..06e7d05b7f7 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java @@ -240,15 +240,9 @@ private void parseProperties(Properties cfg) { * exists and is case insensitive equal to the string {@code "system"}. * Returns {@code Boolean.False} otherwise. */ - public Boolean getTriState(String key) { + public TriState getTriState(String key) { String propertyValue = getProperty(key); - if (propertyValue != null && propertyValue.equalsIgnoreCase("system")) { - return null; - } else if (propertyValue == null) { - return false; - } else { - return Boolean.parseBoolean(propertyValue.trim()); - } + return TriState.parse(propertyValue); } /** diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java index cfa17676fc8..af952abaa4f 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java @@ -32,6 +32,7 @@ import javax.servlet.http.HttpServletRequest; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.common.ClientX509Util; +import org.apache.zookeeper.common.TriState; import org.apache.zookeeper.common.X509Exception; import org.apache.zookeeper.common.X509Exception.KeyManagerException; import org.apache.zookeeper.common.X509Exception.TrustManagerException; @@ -85,8 +86,8 @@ public X509AuthenticationProvider() throws X509Exception { x509Util.getSslKeystorePasswdPathProperty()); String keyStoreTypeProp = config.getProperty(x509Util.getSslKeystoreTypeProperty()); - Boolean crlEnabled = config.getTriState(x509Util.getSslOcspEnabledProperty()); - Boolean ocspEnabled = config.getTriState(x509Util.getSslOcspEnabledProperty()); + TriState crlEnabled = config.getTriState(x509Util.getSslOcspEnabledProperty()); + TriState ocspEnabled = config.getTriState(x509Util.getSslOcspEnabledProperty()); boolean hostnameVerificationEnabled = Boolean.parseBoolean(config.getProperty(x509Util.getSslHostnameVerificationEnabledProperty())); X509KeyManager km = null; diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java index e11c98b7bbc..2ae89600f2b 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java @@ -409,8 +409,8 @@ public void testLoadPEMTrustStore( X509TrustManager tm = X509Util.createTrustManager( x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath(), x509TestContext.getTrustStorePassword(), KeyStoreFileType.PEM.getPropertyValue(), - false, - false, + TriState.False, + TriState.False, true, true, false); @@ -430,8 +430,8 @@ public void testLoadPEMTrustStoreNullPassword( x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath(), null, KeyStoreFileType.PEM.getPropertyValue(), - false, - false, + TriState.False, + TriState.False, true, true, false); @@ -449,8 +449,8 @@ public void testLoadPEMTrustStoreAutodetectStoreFileType( x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath(), x509TestContext.getTrustStorePassword(), null, // null StoreFileType means 'autodetect from file extension' - false, - false, + TriState.False, + TriState.False, true, true, false); @@ -524,8 +524,8 @@ public void testLoadJKSTrustStore( x509TestContext.getTrustStoreFile(KeyStoreFileType.JKS).getAbsolutePath(), x509TestContext.getTrustStorePassword(), KeyStoreFileType.JKS.getPropertyValue(), - true, - true, + TriState.True, + TriState.True, true, true, false); @@ -545,8 +545,8 @@ public void testLoadJKSTrustStoreNullPassword( x509TestContext.getTrustStoreFile(KeyStoreFileType.JKS).getAbsolutePath(), null, KeyStoreFileType.JKS.getPropertyValue(), - false, - false, + TriState.False, + TriState.False, true, true, false); @@ -563,8 +563,8 @@ public void testLoadJKSTrustStoreAutodetectStoreFileType( x509TestContext.getTrustStoreFile(KeyStoreFileType.JKS).getAbsolutePath(), x509TestContext.getTrustStorePassword(), null, // null StoreFileType means 'autodetect from file extension' - true, - true, + TriState.True, + TriState.True, true, true, false); @@ -582,8 +582,8 @@ public void testLoadJKSTrustStoreWithWrongPassword( x509TestContext.getTrustStoreFile(KeyStoreFileType.JKS).getAbsolutePath(), "wrong password", KeyStoreFileType.JKS.getPropertyValue(), - true, - true, + TriState.True, + TriState.True, true, true, false); @@ -657,8 +657,8 @@ public void testLoadPKCS12TrustStore( X509TrustManager tm = X509Util.createTrustManager( x509TestContext.getTrustStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath(), x509TestContext.getTrustStorePassword(), KeyStoreFileType.PKCS12.getPropertyValue(), - true, - true, + TriState.True, + TriState.True, true, true, false); @@ -678,8 +678,8 @@ public void testLoadPKCS12TrustStoreNullPassword( x509TestContext.getTrustStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath(), null, KeyStoreFileType.PKCS12.getPropertyValue(), - false, - false, + TriState.False, + TriState.False, true, true, false); @@ -696,8 +696,8 @@ public void testLoadPKCS12TrustStoreAutodetectStoreFileType( x509TestContext.getTrustStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath(), x509TestContext.getTrustStorePassword(), null, // null StoreFileType means 'autodetect from file extension' - true, - true, + TriState.True, + TriState.True, true, true, false); @@ -715,8 +715,8 @@ public void testLoadPKCS12TrustStoreWithWrongPassword( x509TestContext.getTrustStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath(), "wrong password", KeyStoreFileType.PKCS12.getPropertyValue(), - true, - true, + TriState.True, + TriState.True, true, true, false); From ccf3caee6befa8d29dcf0d41b754d5e046a81312 Mon Sep 17 00:00:00 2001 From: Istvan Toth Date: Wed, 18 Jun 2025 13:33:30 +0200 Subject: [PATCH 3/3] add missing file --- .../org/apache/zookeeper/common/TriState.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 zookeeper-server/src/main/java/org/apache/zookeeper/common/TriState.java diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/common/TriState.java b/zookeeper-server/src/main/java/org/apache/zookeeper/common/TriState.java new file mode 100644 index 00000000000..52d6359f358 --- /dev/null +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/TriState.java @@ -0,0 +1,40 @@ +package org.apache.zookeeper.common; + +/** + * Represent True / False / System (unset/default) values. + * + */ +public enum TriState { + True, + False, + System; + + /** + * @param value the string representation + * @return TriState.true if value equals "true" ignoring case, TriState.System + * if value equals "system", Tristate.False otherwise + */ + public static TriState parse(String value) { + if (value == null) { + return TriState.False; + } else if (value.equalsIgnoreCase("true")) { + return TriState.True; + } else if (value.equalsIgnoreCase("system")) { + return TriState.System; + } else { + return TriState.False; + } + } + + public boolean isTrue() { + return this == TriState.True; + } + + public boolean isFalse() { + return this == TriState.False; + } + + public boolean isSystem() { + return this == TriState.System; + } +}