//******************************************************************************************************
// MySqlOutputAdapter.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), 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.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 10/27/2009 - Stephen C. Wills
// Generated original version of source code.
// 12/13/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Reflection;
using System.Text;
using GSF;
using GSF.TimeSeries;
using GSF.TimeSeries.Adapters;
namespace MySqlAdapters
{
///
/// Represents an output adapter that archives measurements to a MySQL database table.
///
[Description("MySQL: Archives measurements to a MySQL database.")]
public class MySqlOutputAdapter : OutputAdapterBase
{
#region [ Members ]
// Fields
private string m_mySqlConnectionString;
private DbConnection m_connection;
private long m_measurementCount;
private bool m_disposed;
#endregion
#region [ Constructors ]
///
/// Initializes a new instance of the class.
///
public MySqlOutputAdapter()
{
m_mySqlConnectionString = null;
m_measurementCount = 0;
}
#endregion
#region [ Properties ]
///
/// Returns a connection string containing only the key-value pairs
/// that are used to connect to MySQL.
///
public string MySqlConnectionString
{
get
{
return m_mySqlConnectionString;
}
}
///
/// Returns a flag that determines if measurements sent to this
/// are destined for archival.
///
public override bool OutputIsForArchive
{
get
{
return true;
}
}
///
/// Gets a flag that determines if this
/// uses an asynchronous connection.
///
protected override bool UseAsyncConnect
{
get
{
return false;
}
}
#endregion
#region [ Methods ]
///
/// Initializes this .
///
public override void Initialize()
{
base.Initialize();
// Create the MySQL connection string using only the portions of the
// original connection string that are used by MySQL.
StringBuilder builder = new StringBuilder();
string[] pairs = ConnectionString.Split(';');
foreach (string pair in pairs)
{
string key = pair.ToLower().Split('=')[0].Trim();
if (s_validKeys.Contains(key))
{
builder.Append(pair);
builder.Append(';');
}
}
m_mySqlConnectionString = builder.ToString();
// Create a new MySQL connection object
m_connection = CreateConnection();
m_connection.ConnectionString = m_mySqlConnectionString;
m_connection.StateChange += m_connection_StateChange;
}
///
/// Attempts to connect to this .
///
protected override void AttemptConnection()
{
m_connection.Open();
}
///
/// Attempts to disconnect from this .
///
protected override void AttemptDisconnection()
{
m_connection.Close();
m_measurementCount = 0;
}
///
/// Gets a short one-line status of this .
///
/// Maximum length of the status message.
/// Text of the status message.
public override string GetShortStatus(int maxLength)
{
return string.Format("Archived {0} measurements to MySQL database.", m_measurementCount).CenterText(maxLength);
}
///
/// Archives locally.
///
/// Measurements to be archived.
protected override void ProcessMeasurements(IMeasurement[] measurements)
{
if ((object)measurements != null)
{
foreach (IMeasurement measurement in measurements)
{
// Create the command string to insert the measurement as a record in the table.
StringBuilder commandString = new StringBuilder("INSERT INTO Measurement VALUES ('");
IDbCommand command = m_connection.CreateCommand();
commandString.Append(measurement.ID);
commandString.Append("','");
commandString.Append((long)measurement.Timestamp);
commandString.Append("',");
commandString.Append(measurement.AdjustedValue);
commandString.Append(')');
command.CommandText = commandString.ToString();
command.ExecuteNonQuery();
}
m_measurementCount += measurements.Length;
}
}
///
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected override void Dispose(bool disposing)
{
if (!m_disposed)
{
try
{
if (disposing)
{
if (m_connection != null)
{
m_connection.StateChange -= m_connection_StateChange;
m_connection.Dispose();
}
m_connection = null;
}
}
finally
{
m_disposed = true; // Prevent duplicate dispose.
base.Dispose(disposing); // Call base class Dispose().
}
}
}
private DbConnection CreateConnection()
{
string[] mySQLConnectorNetVersions = { "6.3.6.0", "6.3.4.0", "6.2.4.0", "6.1.5.0", "6.0.7.0", "5.2.7.0", "5.1.7.0", "5.0.9.0" };
string assemblyNameFormat = "MySql.Data, Version={0}, Culture=neutral, PublicKeyToken=c5687fc88969c44d";
string assemblyName;
// Attempt to load latest version of the MySQL connector net to creator the proper data provider string
foreach (string connectorNetVersion in mySQLConnectorNetVersions)
{
try
{
Assembly mySqlAssembly;
Type connectionType;
// Create an assembly name based on this version of the MySQL Connector/NET
assemblyName = string.Format(assemblyNameFormat, connectorNetVersion);
// See if this version of the MySQL Connector/NET can be loaded
mySqlAssembly = Assembly.Load(new AssemblyName(assemblyName));
// If assembly load succeeded, create a valid data provider string
connectionType = mySqlAssembly.GetType("MySql.Data.MySqlClient.MySqlConnection");
return (DbConnection)Activator.CreateInstance(connectionType);
}
catch
{
// Nothing to do but try next version
}
}
return null;
}
private void m_connection_StateChange(object sender, StateChangeEventArgs e)
{
if (e.CurrentState == ConnectionState.Closed && Enabled)
{
// Connection lost,
// attempt to reconnect
Start();
}
}
#endregion
#region [ Static ]
// Static Fields
// Collection of keys that can be used in a MySQL connection string.
private static readonly string[] s_validKeys =
{
"server", "port", "protocol",
"database", "uid", "user", "pwd", "password",
"encryption", "encrypt", "charset",
"default command timeout", "connection timeout",
"ignore prepare", "shared memory name"
};
#endregion
}
}