using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using libsecondlife;
using OpenSim.Framework.Communications;
using OpenSim.Framework.Console;
using OpenSim.Framework.Data;
using InventoryFolder=OpenSim.Framework.Communications.Caches.InventoryFolder;
using InventoryCategory = OpenSim.Framework.Data.InventoryCategory;
namespace OpenSim.Framework.Communications
{
public abstract class InventoryServiceBase : MarshalByRefObject, IInventoryServices
{
protected IInventoryData _databasePlugin;
public InventoryServiceBase()
{
}
///
/// Adds a new inventory data server plugin
///
/// The filename to the user server plugin DLL
public void AddPlugin(string FileName)
{
if (!String.IsNullOrEmpty(FileName))
{
MainLog.Instance.Verbose("Inventory", "Inventorystorage: Attempting to load " + FileName);
Assembly pluginAssembly = Assembly.LoadFrom(FileName);
foreach (Type pluginType in pluginAssembly.GetTypes())
{
if (!pluginType.IsAbstract)
{
Type typeInterface = pluginType.GetInterface("IInventoryData", true);
if (typeInterface != null)
{
IInventoryData plug =
(IInventoryData)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
plug.Initialise();
this._databasePlugin = plug;
//TODO! find a better place to create inventory skeletons
loadInventoryFromXmlFile(InventoryCategory.Library, "Inventory_Library.xml");
loadInventoryFromXmlFile(InventoryCategory.Default, "Inventory_Default.xml");
MainLog.Instance.Verbose("Inventorystorage: Added IInventoryData Interface");
break;
}
}
}
}
}
///
/// Returns the root folder plus any folders in root (so down one level in the Inventory folders tree)
///
///
///
public List RequestFirstLevelFolders(LLUUID folderID)
{
InventoryFolderBase root = _databasePlugin.getInventoryFolder(folderID);
List folders = new List();
if (root != null)
{
folders.Add(root);
List subFolders = _databasePlugin.getInventoryFolders(root.folderID);
foreach (InventoryFolderBase f in subFolders)
folders.Add(f);
}
return folders;
}
///
///
///
public InventoryFolderBase RequestUsersRoot(LLUUID userID)
{
return _databasePlugin.getInventoryFolder(userID); // the id of the root folder, is the user id
}
///
///
///
///
///
public List RequestSubFolders(LLUUID parentFolderID)
{
return _databasePlugin.getInventoryFolders(parentFolderID);
}
public List RequestFolderItems(LLUUID folderID)
{
return _databasePlugin.getInventoryInFolder(folderID);
}
public void AddFolder(InventoryFolderBase folder)
{
_databasePlugin.addInventoryFolder(folder);
}
public void AddItem(InventoryItemBase item)
{
_databasePlugin.addInventoryItem(item);
}
public void deleteItem(InventoryItemBase item)
{
_databasePlugin.deleteInventoryItem(item);
}
///
///
///
///
public void AddNewInventorySet(UsersInventory inventory)
{
foreach (InventoryFolderBase folder in inventory.Folders.Values)
{
this.AddFolder(folder);
}
}
public void CreateNewUserInventory(LLUUID defaultFolders, LLUUID user)
{
try
{
// Get Default folder set from the database
//TODO! We need to get the whole hierachy and not just one level down
List folders = this.RequestFirstLevelFolders(LLUUID.Parse("00000112-000f-0000-0000-000100bba000"));
// create an index list, where each of the elements has the index of its parent in the hierachy
// this algorithm is pretty shoddy O(n^2), but it is only executed once per user.
int[] parentIdx = new int[folders.Count];
for (int i = 0; i < folders.Count; i++)
parentIdx[i] = -1;
for (int i = 0; i < folders.Count; i++)
for (int j = 0; j < folders.Count; j++)
if (folders[i].folderID == folders[j].parentID)
parentIdx[j] = i;
//assign a new owerid and a new to the folders
foreach (InventoryFolderBase ifb in folders)
{
if (ifb.parentID == LLUUID.Zero)
ifb.folderID = user;
else
ifb.folderID = LLUUID.Random();
ifb.agentID = user;
ifb.category = InventoryCategory.User;
}
// correct the parent id
for (int i = 0; i < folders.Count; i++)
{
if (folders[i].parentID != LLUUID.Zero)
folders[i].parentID = folders[parentIdx[i]].folderID; // root folder id is the same as the user id
}
// the list is structurally sound, using new folder id's, so save it
foreach (InventoryFolderBase ifb in folders)
_databasePlugin.addInventoryFolder(ifb);
}
catch (Exception e)
{
MainLog.Instance.Error(e.ToString());
}
}
public class UsersInventory
{
public Dictionary Folders = new Dictionary();
public Dictionary Items = new Dictionary();
public UsersInventory()
{
}
public virtual void CreateNewInventorySet(LLUUID user)
{
InventoryFolderBase folder = new InventoryFolderBase();
folder.parentID = LLUUID.Zero;
folder.agentID = user;
folder.folderID = user; // id of root folder is the same as the agent id
folder.name = "My Inventory";
folder.type = 8;
folder.version = 1;
folder.category = InventoryCategory.User;
Folders.Add(folder.folderID, folder);
LLUUID rootFolder = folder.folderID;
folder = new InventoryFolderBase();
folder.parentID = rootFolder;
folder.agentID = user;
folder.folderID = LLUUID.Random();
folder.name = "Textures";
folder.type = 0;
folder.version = 1;
folder.category = InventoryCategory.User;
Folders.Add(folder.folderID, folder);
folder = new InventoryFolderBase();
folder.parentID = rootFolder;
folder.agentID = user;
folder.folderID = LLUUID.Random();
folder.name = "Objects";
folder.type = 6;
folder.version = 1;
folder.category = InventoryCategory.User;
Folders.Add(folder.folderID, folder);
folder = new InventoryFolderBase();
folder.parentID = rootFolder;
folder.agentID = user;
folder.folderID = LLUUID.Random();
folder.name = "Clothes";
folder.type = 5;
folder.version = 1;
folder.category = InventoryCategory.User;
Folders.Add(folder.folderID, folder);
}
}
public void GetRootFoldersForUser(LLUUID user, out LLUUID libraryFolder, out LLUUID personalFolder)
{
List folders = _databasePlugin.getUserRootFolders(user);
libraryFolder = LLUUID.Zero;
personalFolder = LLUUID.Zero;
for (int i = 0; i < folders.Count; i++)
{
if (folders[i].category == InventoryCategory.Library)
libraryFolder = folders[i].folderID;
else if (folders[i].category == InventoryCategory.User)
personalFolder = folders[i].folderID;
}
}
/*
* Dot net has some issues, serializing a dictionary, so we cannot reuse the InventoryFolder
* class defined in Communications.Framework.Communications.Caches. So we serialize/deserialize
* into this simpler class, and then use that.
*/
[XmlRoot(ElementName = "inventory", IsNullable = true)]
public class SerializedInventory
{
[XmlRoot(ElementName = "folder", IsNullable = true)]
public class SerializedFolder : InventoryFolderBase
{
[XmlArray(ElementName = "folders", IsNullable = true)]
[XmlArrayItem(ElementName = "folder", IsNullable = true, Type = typeof(SerializedFolder))]
public ArrayList SubFolders;
[XmlArray(ElementName = "items", IsNullable = true)]
[XmlArrayItem(ElementName = "item", IsNullable = true, Type = typeof(InventoryItemBase))]
public ArrayList Items;
}
[XmlElement(ElementName = "folder", IsNullable = true)]
public SerializedFolder root;
}
public void uploadInventory(SerializedInventory.SerializedFolder folder)
{
foreach (InventoryItemBase iib in folder.Items)
{
// assign default values, if they haven't assigned
iib.avatarID = folder.agentID;
if (iib.assetID == LLUUID.Zero)
iib.assetID = LLUUID.Random();
if (iib.creatorsID == LLUUID.Zero)
iib.creatorsID = folder.agentID;
if (iib.inventoryID == LLUUID.Zero)
iib.inventoryID = LLUUID.Random();
if (iib.inventoryName == null || iib.inventoryName.Length == 0)
iib.inventoryName = "new item";
iib.parentFolderID = folder.folderID;
_databasePlugin.addInventoryItem(iib);
}
foreach (SerializedInventory.SerializedFolder sf in folder.SubFolders)
{
// assign default values, if they haven't assigned
sf.agentID = folder.agentID;
sf.category = folder.category;
if (sf.folderID == LLUUID.Zero)
sf.folderID = LLUUID.Random();
if (sf.name == null || sf.name.Length == 0)
sf.name = "new folder";
sf.parentID = folder.folderID;
_databasePlugin.addInventoryFolder(sf);
uploadInventory(sf);
}
}
public void loadInventoryFromXmlFile(InventoryCategory inventoryCategory, string fileName)
{
_databasePlugin.deleteInventoryCategory(inventoryCategory);
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
XmlReader reader = new XmlTextReader(fs);
XmlSerializer x = new XmlSerializer(typeof(SerializedInventory));
SerializedInventory inventory = (SerializedInventory)x.Deserialize(reader);
// the library and default inventories has no owner, so we use a random guid.
if (inventory.root.category == InventoryCategory.Library || inventory.root.category == InventoryCategory.Default)
{
if (inventory.root.folderID != LLUUID.Zero)
inventory.root.agentID = inventory.root.folderID;
else
inventory.root.agentID = LLUUID.Random();
}
else if (inventory.root.category == InventoryCategory.User)
{
if (inventory.root.agentID == LLUUID.Zero)
inventory.root.agentID = LLUUID.Random();
}
inventory.root.folderID = inventory.root.agentID; // the root folder always has the same id as the owning agent
inventory.root.parentID = LLUUID.Zero;
inventory.root.version = 0;
inventory.root.category = inventoryCategory;
_databasePlugin.addInventoryFolder(inventory.root);
uploadInventory(inventory.root);
}
protected void saveInventoryToXmlFile(SerializedInventory inventory, string fileName)
{
FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
XmlTextWriter writer = new XmlTextWriter(fs, Encoding.UTF8);
writer.Formatting = Formatting.Indented;
XmlSerializer x = new XmlSerializer(typeof(SerializedInventory));
x.Serialize(writer, inventory);
}
public abstract void RequestInventoryForUser(LLUUID userID, InventoryFolderInfo folderCallBack, InventoryItemInfo itemCallBack);
public abstract void AddNewInventoryFolder(LLUUID userID, InventoryFolderBase folder);
public abstract void AddNewInventoryItem(LLUUID userID, InventoryItemBase item);
public abstract void DeleteInventoryItem(LLUUID userID, InventoryItemBase item);
}
}