/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSim Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Data.Common; using System.Reflection; using log4net; using NHibernate; using NHibernate.Cfg; using NHibernate.Tool.hbm2ddl; using OpenMetaverse; using Environment=NHibernate.Cfg.Environment; namespace OpenSim.Data.NHibernate { public class NHibernateManager { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private string dialect; private Configuration configuration; private ISessionFactory sessionFactory; #region Initialization /// <summary> /// Initiate NHibernate Manager /// </summary> /// <param name="connect">NHibernate dialect, driver and connection string separated by ';'</param> /// <param name="store">Name of the store</param> public NHibernateManager(string connect, string store) { ParseConnectionString(connect); //To create sql file uncomment code below and write the name of the file //SchemaExport exp = new SchemaExport(cfg); //exp.SetOutputFile("nameofthefile.sql"); //exp.Create(false, true); Assembly assembly = GetType().Assembly; sessionFactory = configuration.BuildSessionFactory(); RunMigration(dialect, assembly, store); } /// <summary> /// Initiate NHibernate Manager with spesific assembly /// </summary> /// <param name="connect">NHibernate dialect, driver and connection string separated by ';'</param> /// <param name="store">Name of the store</param> /// <param name="assembly">Outside assembly to be included </param> public NHibernateManager(string connect, string store, Assembly assembly) { ParseConnectionString(connect); configuration.AddAssembly(assembly); sessionFactory = configuration.BuildSessionFactory(); RunMigration(dialect, assembly, store); } /// <summary> /// Parses the connection string and creates the NHibernate configuration /// </summary> /// <param name="connect">NHibernate dialect, driver and connection string separated by ';'</param> private void ParseConnectionString(string connect) { // Split out the dialect, driver, and connect string char[] split = { ';' }; string[] parts = connect.Split(split, 3); if (parts.Length != 3) { // TODO: make this a real exception type throw new Exception("Malformed Inventory connection string '" + connect + "'"); } dialect = parts[0]; // NHibernate setup configuration = new Configuration(); configuration.SetProperty(Environment.ConnectionProvider, "NHibernate.Connection.DriverConnectionProvider"); configuration.SetProperty(Environment.Dialect, "NHibernate.Dialect." + dialect); configuration.SetProperty(Environment.ConnectionDriver, "NHibernate.Driver." + parts[1]); configuration.SetProperty(Environment.ConnectionString, parts[2]); configuration.AddAssembly("OpenSim.Data.NHibernate"); } /// <summary> /// Runs migration for the the store in assembly /// </summary> /// <param name="dialect">Dialect in use</param> /// <param name="assembly">Assembly where migration files exist</param> /// <param name="store">Name of the store in use</param> private void RunMigration(string dialect, Assembly assembly, string store) { // Migration subtype is the folder name under which migrations are stored. For mysql this folder is // MySQLDialect instead of MySQL5Dialect which is the dialect currently in use. To avoid renaming // this folder each time the mysql version changes creating simple mapping: String migrationSubType = dialect; if (dialect.StartsWith("MySQL")) { migrationSubType = "MySQLDialect"; } Migration migration = new Migration((DbConnection)sessionFactory.ConnectionProvider.GetConnection(), assembly, migrationSubType, store); migration.Update(); } #endregion /// <summary> /// Gets object of given type from database with given id. /// Uses stateless session for efficiency. /// </summary> /// <param name="type">Type of the object.</param> /// <param name="id">Id of the object.</param> /// <returns>The object or null if object was not found.</returns> public object Get(Type type, Object id) { using (IStatelessSession session = sessionFactory.OpenStatelessSession()) { object obj = null; try { obj = session.Get(type.FullName, id); } catch (Exception e) { m_log.ErrorFormat("[NHIBERNATE] {0} of id {1} loading threw exception: " + e.ToString(), type.Name, id); } return obj; } } /// <summary> /// Gets object of given type from database with given id. /// Use this method for objects containing collections. For flat objects stateless mode is more efficient. /// </summary> /// <param name="type">Type of the object.</param> /// <param name="id">Id of the object.</param> /// <returns>The object or null if object was not found.</returns> public object GetWithStatefullSession(Type type, Object id) { using (ISession session = sessionFactory.OpenSession()) { object obj = null; try { obj = session.Get(type.FullName, id); } catch (Exception e) { m_log.ErrorFormat("[NHIBERNATE] {0} of id {1} loading threw exception: " + e.ToString(), type.Name, id); } return obj; } } /// <summary> /// Inserts given object to database. /// Uses stateless session for efficiency. /// </summary> /// <param name="obj">Object to be insterted.</param> /// <returns>Identifier of the object. Useful for situations when NHibernate generates the identifier.</returns> public object Insert(object obj) { try { using (IStatelessSession session = sessionFactory.OpenStatelessSession()) { using (ITransaction transaction=session.BeginTransaction()) { Object identifier=session.Insert(obj); transaction.Commit(); return identifier; } } } catch (Exception e) { m_log.Error("[NHIBERNATE] issue inserting object ", e); return null; } } /// <summary> /// Inserts given object to database. /// Use this method for objects containing collections. For flat objects stateless mode is more efficient. /// </summary> /// <param name="obj">Object to be insterted.</param> /// <returns>Identifier of the object. Useful for situations when NHibernate generates the identifier.</returns> public object InsertWithStatefullSession(object obj) { try { using (ISession session = sessionFactory.OpenSession()) { using (ITransaction transaction = session.BeginTransaction()) { Object identifier = session.Save(obj); transaction.Commit(); return identifier; } } } catch (Exception e) { m_log.Error("[NHIBERNATE] issue inserting object ", e); return null; } } /// <summary> /// Updates given object to database. /// Uses stateless session for efficiency. /// </summary> /// <param name="obj">Object to be updated.</param> /// <returns>True if operation was succesful.</returns> public bool Update(object obj) { try { using (IStatelessSession session = sessionFactory.OpenStatelessSession()) { using (ITransaction transaction = session.BeginTransaction()) { session.Update(obj); transaction.Commit(); return true; } } } catch (Exception e) { m_log.Error("[NHIBERNATE] issue updating object ", e); return false; } } /// <summary> /// Updates given object to database. /// Use this method for objects containing collections. For flat objects stateless mode is more efficient. /// </summary> /// <param name="obj">Object to be updated.</param> /// <returns>True if operation was succesful.</returns> public bool UpdateWithStatefullSession(object obj) { try { using (ISession session = sessionFactory.OpenSession()) { using (ITransaction transaction = session.BeginTransaction()) { session.Update(obj); transaction.Commit(); return true; } } } catch (Exception e) { m_log.Error("[NHIBERNATE] issue updating object ", e); return false; } } /// <summary> /// Deletes given object from database. /// </summary> /// <param name="obj">Object to be deleted.</param> /// <returns>True if operation was succesful.</returns> public bool Delete(object obj) { try { using (IStatelessSession session = sessionFactory.OpenStatelessSession()) { using (ITransaction transaction = session.BeginTransaction()) { session.Delete(obj); transaction.Commit(); return true; } } } catch (Exception e) { m_log.Error("[NHIBERNATE] issue deleting object ", e); return false; } } /// <summary> /// Returns statefull session which can be used to execute custom nhibernate or sql queries. /// </summary> /// <returns>Statefull session</returns> public ISession GetSession() { return sessionFactory.OpenSession(); } /// <summary> /// Drops the database schema. This exist for unit tests. It should not be invoked from other than test teardown. /// </summary> public void DropSchema() { SchemaExport export = new SchemaExport(this.configuration); export.Drop(true, true); using (ISession session = sessionFactory.OpenSession()) { ISQLQuery sqlQuery = session.CreateSQLQuery("drop table migrations"); sqlQuery.ExecuteUpdate(); } } } }