blob: c2cac872e7d5287c109cad75cc971cb36e981941 [file] [log] [blame]
/*
* 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.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Common;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Threading;
namespace Apache.IoTDB.Data
{
/// <summary>
/// Provides a simple way to create and manage the contents of connection strings used by
/// <see cref="IoTDBConnection" />.
/// </summary>
public class IoTDBConnectionStringBuilder : DbConnectionStringBuilder
{
private const string DataSourceKeyword = "DataSource";
private const string UserNameKeyword = "Username";
private const string PasswordKeyword = "Password";
private const string PortKeyword = "Port";
private const string FetchSizeKeyword = "FetchSize";
private const string CompressionKeyword = "Compression";
private const string PoolSizeKeyword = "PoolSize";
private const string ZoneIdKeyword = "ZoneId";
private const string TimeOutKeyword = "TimeOut";
private enum Keywords
{
DataSource,
Username,
Password,
Port,
FetchSize,
Compression,
PoolSize,
ZoneId,
TimeOut
}
private static readonly IReadOnlyList<string> _validKeywords;
private static readonly IReadOnlyDictionary<string, Keywords> _keywords;
private string _dataSource = "127.0.0.1";
private string _userName = "root";
private string _password = "root";
private bool _enableRpcCompression = false;
private int _fetchSize = 1800;
private string _zoneId = "UTC+08:00";
private int _port = 6667;
private int _poolSize = 8;
private int _timeOut = 10000;
static IoTDBConnectionStringBuilder()
{
var validKeywords = new string[9];
validKeywords[(int)Keywords.DataSource] = DataSourceKeyword;
validKeywords[(int)Keywords.Username] = UserNameKeyword;
validKeywords[(int)Keywords.Password] = PasswordKeyword;
validKeywords[(int)Keywords.Port] = PortKeyword;
validKeywords[(int)Keywords.FetchSize] = FetchSizeKeyword;
validKeywords[(int)Keywords.Compression] = CompressionKeyword;
validKeywords[(int)Keywords.PoolSize] = PoolSizeKeyword;
validKeywords[(int)Keywords.ZoneId] = ZoneIdKeyword;
validKeywords[(int)Keywords.TimeOut] = TimeOutKeyword;
_validKeywords = validKeywords;
_keywords = new Dictionary<string, Keywords>(9, StringComparer.OrdinalIgnoreCase)
{
[DataSourceKeyword] = Keywords.DataSource,
[UserNameKeyword] = Keywords.Username,
[PasswordKeyword] = Keywords.Password,
[PortKeyword] = Keywords.Port,
[FetchSizeKeyword] = Keywords.FetchSize,
[CompressionKeyword] = Keywords.Compression,
[PoolSizeKeyword] = Keywords.PoolSize,
[ZoneIdKeyword] = Keywords.ZoneId,
[TimeOutKeyword] = Keywords.TimeOut
};
}
/// <summary>
/// Initializes a new instance of the <see cref="IoTDBConnectionStringBuilder" /> class.
/// </summary>
public IoTDBConnectionStringBuilder()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IoTDBConnectionStringBuilder" /> class.
/// </summary>
/// <param name="connectionString">
/// The initial connection string the builder will represent. Can be null.
/// </param>
public IoTDBConnectionStringBuilder(string connectionString)
=> ConnectionString = connectionString;
/// <summary>
/// Gets or sets the database file.
/// </summary>
/// <value>The database file.</value>
public virtual string DataSource
{
get => _dataSource;
set => base[DataSourceKeyword] = _dataSource = value;
}
public virtual string Username
{
get => _userName;
set => base[UserNameKeyword] = _userName = value;
}
public virtual string Password
{
get => _password;
set => base[PasswordKeyword] = _password = value;
}
public virtual int Port
{
get => _port;
set => base[PortKeyword] = _port = value;
}
public virtual int FetchSize
{
get => _fetchSize;
set => base[FetchSizeKeyword] = _fetchSize = value;
}
public virtual bool Compression
{
get => _enableRpcCompression;
set => base[CompressionKeyword] = _enableRpcCompression = value;
}
public virtual int PoolSize
{
get => _poolSize;
set => base[PoolSizeKeyword] = _poolSize = value;
}
public virtual string ZoneId
{
get => _zoneId;
set => base[ZoneIdKeyword] = _zoneId = value;
}
public virtual int TimeOut
{
get => _timeOut;
set => base[PoolSizeKeyword] = _timeOut = value;
}
/// <summary>
/// Gets a collection containing the keys used by the connection string.
/// </summary>
/// <value>A collection containing the keys used by the connection string.</value>
public override ICollection Keys
=> new ReadOnlyCollection<string>((string[])_validKeywords);
/// <summary>
/// Gets a collection containing the values used by the connection string.
/// </summary>
/// <value>A collection containing the values used by the connection string.</value>
public override ICollection Values
{
get
{
var values = new object[_validKeywords.Count];
for (var i = 0; i < _validKeywords.Count; i++)
{
values[i] = GetAt((Keywords)i);
}
return new ReadOnlyCollection<object>(values);
}
}
/// <summary>
/// Gets or sets the value associated with the specified key.
/// </summary>
/// <param name="keyword">The key.</param>
/// <returns>The value.</returns>
public override object this[string keyword]
{
get => GetAt(GetIndex(keyword));
set
{
if (value == null)
{
Remove(keyword);
return;
}
switch (GetIndex(keyword))
{
case Keywords.DataSource:
DataSource = Convert.ToString(value, CultureInfo.InvariantCulture);
return;
case Keywords.Username:
Username = Convert.ToString(value, CultureInfo.InvariantCulture);
return;
case Keywords.Password:
Password = Convert.ToString(value, CultureInfo.InvariantCulture);
return;
case Keywords.Port:
Port = Convert.ToInt32(value, CultureInfo.InvariantCulture);
return;
case Keywords.FetchSize:
FetchSize = Convert.ToInt32(value, CultureInfo.InvariantCulture);
return;
case Keywords.Compression:
Compression = Convert.ToBoolean(value, CultureInfo.InvariantCulture);
return;
case Keywords.PoolSize:
PoolSize = Convert.ToInt32(value, CultureInfo.InvariantCulture);
return;
case Keywords.ZoneId:
ZoneId = Convert.ToString(value, CultureInfo.InvariantCulture);
return;
case Keywords.TimeOut:
TimeOut = Convert.ToInt32(value, CultureInfo.InvariantCulture);
return;
default:
Debug.WriteLine(false, "Unexpected keyword: " + keyword);
return;
}
}
}
private static TEnum ConvertToEnum<TEnum>(object value)
where TEnum : struct
{
if (value is string stringValue)
{
return (TEnum)Enum.Parse(typeof(TEnum), stringValue, ignoreCase: true);
}
if (value is TEnum enumValue)
{
enumValue = (TEnum)value;
}
else if (value.GetType().GetTypeInfo().IsEnum)
{
throw new ArgumentException($"ConvertFailed{value.GetType()},{typeof(TEnum)}");
}
else
{
enumValue = (TEnum)Enum.ToObject(typeof(TEnum), value);
}
if (!Enum.IsDefined(typeof(TEnum), enumValue))
{
throw new ArgumentOutOfRangeException(
nameof(value),
value,
$"Invalid Enum Value{typeof(TEnum)},{enumValue}");
}
return enumValue;
}
/// <summary>
/// Clears the contents of the builder.
/// </summary>
public override void Clear()
{
base.Clear();
for (var i = 0; i < _validKeywords.Count; i++)
{
Reset((Keywords)i);
}
}
/// <summary>
/// Determines whether the specified key is used by the connection string.
/// </summary>
/// <param name="keyword">The key to look for.</param>
/// <returns>true if it is use; otherwise, false.</returns>
public override bool ContainsKey(string keyword)
=> _keywords.ContainsKey(keyword);
/// <summary>
/// Removes the specified key and its value from the connection string.
/// </summary>
/// <param name="keyword">The key to remove.</param>
/// <returns>true if the key was used; otherwise, false.</returns>
public override bool Remove(string keyword)
{
if (!_keywords.TryGetValue(keyword, out var index)
|| !base.Remove(_validKeywords[(int)index]))
{
return false;
}
Reset(index);
return true;
}
/// <summary>
/// Determines whether the specified key should be serialized into the connection string.
/// </summary>
/// <param name="keyword">The key to check.</param>
/// <returns>true if it should be serialized; otherwise, false.</returns>
public override bool ShouldSerialize(string keyword)
=> _keywords.TryGetValue(keyword, out var index) && base.ShouldSerialize(_validKeywords[(int)index]);
/// <summary>
/// Gets the value of the specified key if it is used.
/// </summary>
/// <param name="keyword">The key.</param>
/// <param name="value">The value.</param>
/// <returns>true if the key was used; otherwise, false.</returns>
public override bool TryGetValue(string keyword, out object value)
{
if (!_keywords.TryGetValue(keyword, out var index))
{
value = null;
return false;
}
value = GetAt(index);
return true;
}
private object GetAt(Keywords index)
{
switch (index)
{
case Keywords.DataSource:
return DataSource;
case Keywords.Password:
return Password;
case Keywords.Username:
return Username;
case Keywords.Port:
return Port;
case Keywords.FetchSize:
return FetchSize;
case Keywords.Compression:
return Compression;
case Keywords.PoolSize:
return PoolSize;
case Keywords.ZoneId:
return ZoneId;
case Keywords.TimeOut:
return TimeOut;
default:
Debug.Assert(false, "Unexpected keyword: " + index);
return null;
}
}
private static Keywords GetIndex(string keyword)
=> !_keywords.TryGetValue(keyword, out var index)
? throw new ArgumentException($"Keyword Not Supported{keyword}")
: index;
private void Reset(Keywords index)
{
switch (index)
{
case Keywords.DataSource:
_dataSource = "127.0.0.1";
return;
case Keywords.Password:
_password = "root";
return;
case Keywords.Username:
_userName = "root";
return;
case Keywords.Port:
_port = 6667;
return;
case Keywords.FetchSize:
_fetchSize = 1800;
return;
case Keywords.Compression:
_enableRpcCompression = false;
return;
case Keywords.PoolSize:
_poolSize = 8;
return;
case Keywords.ZoneId:
_zoneId = "UTC+08:00";
return;
case Keywords.TimeOut:
_timeOut = 10000;//10sec.
return;
default:
Debug.Assert(false, "Unexpected keyword: " + index);
return;
}
}
}
}