/*
* 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.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using OpenMetaverse;
using log4net;
using NHibernate;
using NHibernate.Criterion;
using OpenSim.Framework;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
using Environment=NHibernate.Cfg.Environment;
namespace OpenSim.Data.NHibernate
{
///
/// A RegionData Interface to the NHibernate database
///
public class NHibernateRegionData : IRegionDataStore
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public NHibernateManager manager;
public void Initialise(string connect)
{
m_log.InfoFormat("[NHIBERNATE] Initializing NHibernateRegionData");
manager = new NHibernateManager(connect, "RegionStore");
}
/***********************************************************************
*
* Public Interface Functions
*
**********************************************************************/
public void Dispose() {}
public void StoreRegionSettings(RegionSettings rs)
{
RegionSettings oldRegionSettings = (RegionSettings)manager.Load(typeof(RegionSettings), rs.RegionUUID);
if (oldRegionSettings != null)
{
manager.Update(rs);
}
else
{
manager.Save(rs);
}
}
public RegionSettings LoadRegionSettings(UUID regionUUID)
{
RegionSettings regionSettings = (RegionSettings) manager.Load(typeof(RegionSettings), regionUUID);
if (regionSettings == null)
{
regionSettings = new RegionSettings();
regionSettings.RegionUUID = regionUUID;
manager.Save(regionSettings);
}
regionSettings.OnSave += StoreRegionSettings;
return regionSettings;
}
// This looks inefficient, but it turns out that it isn't
// based on trial runs with nhibernate 1.2
private void SaveOrUpdate(SceneObjectPart p)
{
try
{
SceneObjectPart old = (SceneObjectPart)manager.Load(typeof(SceneObjectPart), p.UUID);
if (old != null)
{
m_log.InfoFormat("[NHIBERNATE] updating object {0}", p.UUID);
manager.Update(p);
}
else
{
m_log.InfoFormat("[NHIBERNATE] saving object {0}", p.UUID);
manager.Save(p);
}
}
catch (Exception e)
{
m_log.Error("[NHIBERNATE] issue saving part", e);
}
}
private void SaveOrUpdate(Terrain t)
{
try
{
Terrain old = (Terrain)manager.Load(typeof(Terrain), t.RegionID);
if (old != null)
{
m_log.InfoFormat("[NHIBERNATE] updating terrain {0}", t.RegionID);
manager.Update(t);
}
else
{
m_log.InfoFormat("[NHIBERNATE] saving terrain {0}", t.RegionID);
manager.Save(t);
}
}
catch (Exception e)
{
m_log.Error("[NHIBERNATE] issue saving terrain", e);
}
}
///
/// Adds an object into region storage
///
/// the object
/// the region UUID
public void StoreObject(SceneObjectGroup obj, UUID regionUUID)
{
uint flags = obj.RootPart.GetEffectiveObjectFlags();
// Eligibility check
if ((flags & (uint)PrimFlags.Temporary) != 0)
return;
if ((flags & (uint)PrimFlags.TemporaryOnRez) != 0)
return;
try
{
foreach (SceneObjectPart part in obj.Children.Values)
{
m_log.InfoFormat("Storing part {0}", part.UUID);
SaveOrUpdate(part);
}
}
catch (Exception e)
{
m_log.Error("Can't save: ", e);
}
}
private SceneObjectGroup LoadObject(UUID uuid, UUID region)
{
SceneObjectGroup group = new SceneObjectGroup();
ICriteria criteria = manager.GetSession().CreateCriteria(typeof(SceneObjectPart));
criteria.Add(Expression.Eq("RegionID", region));
criteria.Add(Expression.Eq("ParentUUID", uuid));
criteria.AddOrder( Order.Asc("ParentID") );
foreach (SceneObjectPart p in criteria.List())
{
// root part
if (p.UUID == uuid)
{
group.SetRootPart(p);
}
else
{
group.AddPart(p);
}
}
return group;
}
///
/// Removes an object from region storage
///
/// the object
/// the region UUID
public void RemoveObject(UUID obj, UUID regionUUID)
{
SceneObjectGroup g = LoadObject(obj, regionUUID);
foreach (SceneObjectPart p in g.Children.Values)
{
manager.Delete(p);
}
m_log.InfoFormat("[REGION DB]: Removing obj: {0} from region: {1}", obj.Guid, regionUUID);
}
///
/// Load persisted objects from region storage.
///
/// The region UUID
/// List of loaded groups
public List LoadObjects(UUID regionUUID)
{
Dictionary SOG = new Dictionary();
List ret = new List();
ICriteria criteria = manager.GetSession().CreateCriteria(typeof(SceneObjectPart));
criteria.Add(Expression.Eq("RegionID", regionUUID));
criteria.AddOrder(Order.Asc("ParentID"));
criteria.AddOrder(Order.Asc("LinkNum"));
foreach (SceneObjectPart p in criteria.List())
{
// root part
if (p.UUID == p.ParentUUID)
{
SceneObjectGroup group = new SceneObjectGroup();
group.SetRootPart(p);
SOG.Add(p.ParentUUID, group);
}
else
{
SOG[p.ParentUUID].AddPart(p);
}
// get the inventory
ICriteria InvCriteria = manager.GetSession().CreateCriteria(typeof(TaskInventoryItem));
InvCriteria.Add(Expression.Eq("ParentPartID", p.UUID));
IList inventory = new List();
foreach (TaskInventoryItem i in InvCriteria.List())
{
inventory.Add(i);
}
if (inventory.Count > 0)
p.Inventory.RestoreInventoryItems(inventory);
}
foreach (SceneObjectGroup g in SOG.Values)
{
ret.Add(g);
}
return ret;
}
///
/// Store a terrain revision in region storage
///
/// terrain heightfield
/// region UUID
public void StoreTerrain(double[,] ter, UUID regionID)
{
lock (this) {
Terrain t = new Terrain(regionID, ter);
SaveOrUpdate(t);
}
}
///
/// Load the latest terrain revision from region storage
///
/// the region UUID
/// Heightfield data
public double[,] LoadTerrain(UUID regionID)
{
Terrain t = (Terrain)manager.Load(typeof(Terrain), regionID);
if (t != null)
{
return t.Doubles;
}
m_log.Info("No terrain yet");
return null;
}
///
///
///
///
public void RemoveLandObject(UUID globalID)
{
}
///
///
///
///
public void StoreLandObject(ILandObject parcel)
{
}
///
///
///
///
///
public List LoadLandObjects(UUID regionUUID)
{
List landDataForRegion = new List();
return landDataForRegion;
}
///
/// See
///
public void Shutdown()
{
//session.Flush();
}
///
/// Load a region banlist
///
/// the region UUID
/// The banlist
public List LoadRegionBanList(UUID regionUUID)
{
List regionbanlist = new List();
return regionbanlist;
}
///
/// Add en entry into region banlist
///
///
public void AddToRegionBanlist(EstateBan item)
{
}
///
/// remove an entry from the region banlist
///
///
public void RemoveFromRegionBanlist(EstateBan item)
{
}
///
///
///
///
///
// private static Array serializeTerrain(double[,] val)
// {
// MemoryStream str = new MemoryStream(65536*sizeof (double));
// BinaryWriter bw = new BinaryWriter(str);
//
// // TODO: COMPATIBILITY - Add byte-order conversions
// for (int x = 0; x < 256; x++)
// for (int y = 0; y < 256; y++)
// bw.Write(val[x, y]);
//
// return str.ToArray();
// }
///
/// see IRegionDatastore
///
///
///
public void StorePrimInventory(UUID primID, ICollection items)
{
ICriteria criteria = manager.GetSession().CreateCriteria(typeof(TaskInventoryItem));
criteria.Add(Expression.Eq("ParentPartID", primID));
try
{
foreach (TaskInventoryItem i in criteria.List())
{
manager.Delete(i);
}
foreach (TaskInventoryItem i in items)
{
manager.Save(i);
}
}
catch (Exception e)
{
m_log.Error("[NHIBERNATE] StoreInvetory", e);
}
}
}
}