NHibernateInventoryData.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.IO;
  30. using System.Reflection;
  31. using System.Text.RegularExpressions;
  32. using libsecondlife;
  33. using log4net;
  34. using NHibernate;
  35. using NHibernate.Cfg;
  36. using NHibernate.Expression;
  37. using NHibernate.Mapping.Attributes;
  38. using NHibernate.Tool.hbm2ddl;
  39. using OpenSim.Framework;
  40. using Environment=NHibernate.Cfg.Environment;
  41. namespace OpenSim.Data.NHibernate
  42. {
  43. public class NHibernateInventoryData: IInventoryData
  44. {
  45. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  46. private Configuration cfg;
  47. private ISessionFactory factory;
  48. /// <summary>
  49. /// Initialises the interface
  50. /// </summary>
  51. public void Initialise(string connect)
  52. {
  53. // Split out the dialect, driver, and connect string
  54. char[] split = {';'};
  55. string[] parts = connect.Split(split, 3);
  56. if (parts.Length != 3) {
  57. // TODO: make this a real exception type
  58. throw new Exception("Malformed Inventory connection string '" + connect + "'");
  59. }
  60. // Establish NHibernate Connection
  61. cfg = new Configuration();
  62. cfg.SetProperty(Environment.ConnectionProvider,
  63. "NHibernate.Connection.DriverConnectionProvider");
  64. cfg.SetProperty(Environment.Dialect,
  65. "NHibernate.Dialect." + parts[0]);
  66. cfg.SetProperty(Environment.ConnectionDriver,
  67. "NHibernate.Driver." + parts[1]);
  68. cfg.SetProperty(Environment.ConnectionString, parts[2]);
  69. cfg.AddAssembly("OpenSim.Data.NHibernate");
  70. HbmSerializer.Default.Validate = true;
  71. using ( MemoryStream stream =
  72. HbmSerializer.Default.Serialize(Assembly.GetExecutingAssembly()))
  73. cfg.AddInputStream(stream);
  74. // If uncommented this will auto create tables, but it
  75. // does drops of the old tables, so we need a smarter way
  76. // to acturally manage this.
  77. // new SchemaExport(cfg).Create(true, true);
  78. factory = cfg.BuildSessionFactory();
  79. InitDB();
  80. }
  81. private void InitDB()
  82. {
  83. string regex = @"no such table: Inventory";
  84. Regex RE = new Regex(regex, RegexOptions.Multiline);
  85. try {
  86. using(ISession session = factory.OpenSession()) {
  87. session.Load(typeof(InventoryItemBase), LLUUID.Zero);
  88. }
  89. } catch (ObjectNotFoundException e) {
  90. // yes, we know it's not there, but that's ok
  91. } catch (ADOException e) {
  92. Match m = RE.Match(e.ToString());
  93. if(m.Success) {
  94. // We don't have this table, so create it.
  95. new SchemaExport(cfg).Create(true, true);
  96. }
  97. }
  98. }
  99. /*****************************************************************
  100. *
  101. * Basic CRUD operations on Data
  102. *
  103. ****************************************************************/
  104. // READ
  105. /// <summary>
  106. /// Returns an inventory item by its UUID
  107. /// </summary>
  108. /// <param name="item">The UUID of the item to be returned</param>
  109. /// <returns>A class containing item information</returns>
  110. public InventoryItemBase getInventoryItem(LLUUID item)
  111. {
  112. using(ISession session = factory.OpenSession()) {
  113. try {
  114. return session.Load(typeof(InventoryItemBase), item) as InventoryItemBase;
  115. } catch {
  116. m_log.ErrorFormat("Couldn't find inventory item: {0}", item);
  117. return null;
  118. }
  119. }
  120. }
  121. /// <summary>
  122. /// Creates a new inventory item based on item
  123. /// </summary>
  124. /// <param name="item">The item to be created</param>
  125. public void addInventoryItem(InventoryItemBase item)
  126. {
  127. if (!ExistsItem(item.ID)) {
  128. using(ISession session = factory.OpenSession()) {
  129. using(ITransaction transaction = session.BeginTransaction()) {
  130. session.Save(item);
  131. transaction.Commit();
  132. }
  133. }
  134. } else {
  135. m_log.ErrorFormat("Attempted to add Inventory Item {0} that already exists, updating instead", item.ID);
  136. updateInventoryItem(item);
  137. }
  138. }
  139. /// <summary>
  140. /// Updates an inventory item with item (updates based on ID)
  141. /// </summary>
  142. /// <param name="item">The updated item</param>
  143. public void updateInventoryItem(InventoryItemBase item)
  144. {
  145. if (ExistsItem(item.ID)) {
  146. using(ISession session = factory.OpenSession()) {
  147. using(ITransaction transaction = session.BeginTransaction()) {
  148. session.Update(item);
  149. transaction.Commit();
  150. }
  151. }
  152. } else {
  153. m_log.ErrorFormat("Attempted to add Inventory Item {0} that already exists", item.ID);
  154. }
  155. }
  156. /// <summary>
  157. ///
  158. /// </summary>
  159. /// <param name="item"></param>
  160. public void deleteInventoryItem(LLUUID itemID)
  161. {
  162. using(ISession session = factory.OpenSession()) {
  163. using(ITransaction transaction = session.BeginTransaction()) {
  164. session.Delete(itemID);
  165. transaction.Commit();
  166. }
  167. }
  168. }
  169. /// <summary>
  170. /// Returns an inventory folder by its UUID
  171. /// </summary>
  172. /// <param name="folder">The UUID of the folder to be returned</param>
  173. /// <returns>A class containing folder information</returns>
  174. public InventoryFolderBase getInventoryFolder(LLUUID folder)
  175. {
  176. using(ISession session = factory.OpenSession()) {
  177. try {
  178. return session.Load(typeof(InventoryFolderBase), folder) as InventoryFolderBase;
  179. } catch {
  180. m_log.ErrorFormat("Couldn't find inventory item: {0}", folder);
  181. return null;
  182. }
  183. }
  184. }
  185. /// <summary>
  186. /// Creates a new inventory folder based on folder
  187. /// </summary>
  188. /// <param name="folder">The folder to be created</param>
  189. public void addInventoryFolder(InventoryFolderBase folder)
  190. {
  191. if (!ExistsFolder(folder.ID)) {
  192. using(ISession session = factory.OpenSession()) {
  193. using(ITransaction transaction = session.BeginTransaction()) {
  194. session.Save(folder);
  195. transaction.Commit();
  196. }
  197. }
  198. } else {
  199. m_log.ErrorFormat("Attempted to add Inventory Folder {0} that already exists, updating instead", folder.ID);
  200. updateInventoryFolder(folder);
  201. }
  202. }
  203. /// <summary>
  204. /// Updates an inventory folder with folder (updates based on ID)
  205. /// </summary>
  206. /// <param name="folder">The updated folder</param>
  207. public void updateInventoryFolder(InventoryFolderBase folder)
  208. {
  209. if (ExistsFolder(folder.ID)) {
  210. using(ISession session = factory.OpenSession()) {
  211. using(ITransaction transaction = session.BeginTransaction()) {
  212. session.Update(folder);
  213. transaction.Commit();
  214. }
  215. }
  216. } else {
  217. m_log.ErrorFormat("Attempted to add Inventory Folder {0} that already exists", folder.ID);
  218. }
  219. }
  220. /// <summary>
  221. ///
  222. /// </summary>
  223. /// <param name="folder"></param>
  224. public void deleteInventoryFolder(LLUUID folderID)
  225. {
  226. using(ISession session = factory.OpenSession()) {
  227. using(ITransaction transaction = session.BeginTransaction()) {
  228. session.Delete(folderID.ToString());
  229. transaction.Commit();
  230. }
  231. }
  232. }
  233. // useful private methods
  234. private bool ExistsItem(LLUUID uuid)
  235. {
  236. return (getInventoryItem(uuid) != null) ? true : false;
  237. }
  238. private bool ExistsFolder(LLUUID uuid)
  239. {
  240. return (getInventoryFolder(uuid) != null) ? true : false;
  241. }
  242. public void Shutdown()
  243. {
  244. // TODO: DataSet commit
  245. }
  246. /// <summary>
  247. /// Closes the interface
  248. /// </summary>
  249. public void Close()
  250. {
  251. }
  252. /// <summary>
  253. /// The plugin being loaded
  254. /// </summary>
  255. /// <returns>A string containing the plugin name</returns>
  256. public string getName()
  257. {
  258. return "NHibernate Inventory Data Interface";
  259. }
  260. /// <summary>
  261. /// The plugins version
  262. /// </summary>
  263. /// <returns>A string containing the plugin version</returns>
  264. public string getVersion()
  265. {
  266. Module module = GetType().Module;
  267. string dllName = module.Assembly.ManifestModule.Name;
  268. Version dllVersion = module.Assembly.GetName().Version;
  269. return
  270. string.Format("{0}.{1}.{2}.{3}", dllVersion.Major, dllVersion.Minor, dllVersion.Build,
  271. dllVersion.Revision);
  272. }
  273. // Move seems to be just update
  274. public void moveInventoryFolder(InventoryFolderBase folder)
  275. {
  276. updateInventoryFolder(folder);
  277. }
  278. public void moveInventoryItem(InventoryItemBase item)
  279. {
  280. updateInventoryItem(item);
  281. }
  282. /// <summary>
  283. /// Returns a list of inventory items contained within the specified folder
  284. /// </summary>
  285. /// <param name="folderID">The UUID of the target folder</param>
  286. /// <returns>A List of InventoryItemBase items</returns>
  287. public List<InventoryItemBase> getInventoryInFolder(LLUUID folderID)
  288. {
  289. using(ISession session = factory.OpenSession()) {
  290. // try {
  291. ICriteria criteria = session.CreateCriteria(typeof(InventoryItemBase));
  292. criteria.Add(Expression.Eq("Folder", folderID) );
  293. List<InventoryItemBase> list = new List<InventoryItemBase>();
  294. foreach (InventoryItemBase item in criteria.List())
  295. {
  296. list.Add(item);
  297. }
  298. return list;
  299. // } catch {
  300. // return new List<InventoryItemBase>();
  301. // }
  302. }
  303. }
  304. public List<InventoryFolderBase> getUserRootFolders(LLUUID user)
  305. {
  306. return new List<InventoryFolderBase>();
  307. }
  308. // see InventoryItemBase.getUserRootFolder
  309. public InventoryFolderBase getUserRootFolder(LLUUID user)
  310. {
  311. using(ISession session = factory.OpenSession()) {
  312. // try {
  313. ICriteria criteria = session.CreateCriteria(typeof(InventoryFolderBase));
  314. criteria.Add(Expression.Eq("ParentID", LLUUID.Zero) );
  315. criteria.Add(Expression.Eq("Owner", user) );
  316. foreach (InventoryFolderBase folder in criteria.List())
  317. {
  318. return folder;
  319. }
  320. m_log.ErrorFormat("No Inventory Root Folder Found for: {0}", user);
  321. return new InventoryFolderBase();
  322. // } catch {
  323. // return new InventoryFolderBase();
  324. // }
  325. }
  326. }
  327. /// <summary>
  328. /// Append a list of all the child folders of a parent folder
  329. /// </summary>
  330. /// <param name="folders">list where folders will be appended</param>
  331. /// <param name="parentID">ID of parent</param>
  332. private void getInventoryFolders(ref List<InventoryFolderBase> folders, LLUUID parentID)
  333. {
  334. using(ISession session = factory.OpenSession()) {
  335. // try {
  336. ICriteria criteria = session.CreateCriteria(typeof(InventoryFolderBase));
  337. criteria.Add(Expression.Eq("ParentID", parentID) );
  338. foreach (InventoryFolderBase item in criteria.List())
  339. {
  340. folders.Add(item);
  341. }
  342. // } catch {
  343. // m_log.ErrorFormat("Can't run getInventoryFolders for Folder ID: {0}", parentID);
  344. // }
  345. }
  346. }
  347. /// <summary>
  348. /// Returns a list of inventory folders contained in the folder 'parentID'
  349. /// </summary>
  350. /// <param name="parentID">The folder to get subfolders for</param>
  351. /// <returns>A list of inventory folders</returns>
  352. public List<InventoryFolderBase> getInventoryFolders(LLUUID parentID)
  353. {
  354. List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
  355. getInventoryFolders(ref folders, parentID);
  356. return folders;
  357. }
  358. // See IInventoryData
  359. public List<InventoryFolderBase> getFolderHierarchy(LLUUID parentID)
  360. {
  361. List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
  362. getInventoryFolders(ref folders, parentID);
  363. for (int i = 0; i < folders.Count; i++)
  364. getInventoryFolders(ref folders, folders[i].ID);
  365. return folders;
  366. }
  367. }
  368. }