aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Grid/AssetInventoryServer/Plugins
diff options
context:
space:
mode:
authorMike Mazur2009-02-16 02:25:44 +0000
committerMike Mazur2009-02-16 02:25:44 +0000
commit16fa7f516a484e9f21fac34262214b3d9d761823 (patch)
tree925c10831c04d053b707857ffa785482316d4dcb /OpenSim/Grid/AssetInventoryServer/Plugins
parentAdded OpenSim asset frontend plugin. (diff)
downloadopensim-SC_OLD-16fa7f516a484e9f21fac34262214b3d9d761823.zip
opensim-SC_OLD-16fa7f516a484e9f21fac34262214b3d9d761823.tar.gz
opensim-SC_OLD-16fa7f516a484e9f21fac34262214b3d9d761823.tar.bz2
opensim-SC_OLD-16fa7f516a484e9f21fac34262214b3d9d761823.tar.xz
Converted to Linux newlines.
Diffstat (limited to 'OpenSim/Grid/AssetInventoryServer/Plugins')
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimAssetFrontendPlugin.cs480
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimAssetStoragePlugin.cs740
2 files changed, 610 insertions, 610 deletions
diff --git a/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimAssetFrontendPlugin.cs b/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimAssetFrontendPlugin.cs
index e76c8ee..1abd3f5 100644
--- a/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimAssetFrontendPlugin.cs
+++ b/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimAssetFrontendPlugin.cs
@@ -1,240 +1,240 @@
1/* 1/*
2 * Copyright (c) 2008 Intel Corporation 2 * Copyright (c) 2008 Intel Corporation
3 * All rights reserved. 3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 7 *
8 * -- Redistributions of source code must retain the above copyright 8 * -- Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * -- Redistributions in binary form must reproduce the above copyright 10 * -- Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the 11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 12 * documentation and/or other materials provided with the distribution.
13 * -- Neither the name of the Intel Corporation nor the names of its 13 * -- Neither the name of the Intel Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from 14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission. 15 * this software without specific prior written permission.
16 * 16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS 20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */ 28 */
29 29
30using System; 30using System;
31using System.Collections.Generic; 31using System.Collections.Generic;
32using System.Net; 32using System.Net;
33using System.IO; 33using System.IO;
34using System.Xml; 34using System.Xml;
35using ExtensionLoader; 35using ExtensionLoader;
36using OpenMetaverse; 36using OpenMetaverse;
37using HttpServer; 37using HttpServer;
38using OpenSim.Framework; 38using OpenSim.Framework;
39 39
40namespace OpenSim.Grid.AssetInventoryServer.Plugins 40namespace OpenSim.Grid.AssetInventoryServer.Plugins
41{ 41{
42 public class OpenSimAssetFrontendPlugin : IAssetInventoryServerPlugin 42 public class OpenSimAssetFrontendPlugin : IAssetInventoryServerPlugin
43 { 43 {
44 AssetInventoryServer server; 44 AssetInventoryServer server;
45 45
46 public OpenSimAssetFrontendPlugin() 46 public OpenSimAssetFrontendPlugin()
47 { 47 {
48 } 48 }
49 49
50 #region IPlugin implementation 50 #region IPlugin implementation
51 51
52 public void Initialise(AssetInventoryServer server) 52 public void Initialise(AssetInventoryServer server)
53 { 53 {
54 this.server = server; 54 this.server = server;
55 55
56 // Asset request 56 // Asset request
57 server.HttpServer.AddHandler("get", null, @"^/assets/", AssetRequestHandler); 57 server.HttpServer.AddHandler("get", null, @"^/assets/", AssetRequestHandler);
58 58
59 // Asset creation 59 // Asset creation
60 server.HttpServer.AddHandler("post", null, @"^/assets/", AssetPostHandler); 60 server.HttpServer.AddHandler("post", null, @"^/assets/", AssetPostHandler);
61 } 61 }
62 62
63 /// <summary> 63 /// <summary>
64 /// <para>Initialises asset interface</para> 64 /// <para>Initialises asset interface</para>
65 /// </summary> 65 /// </summary>
66 public void Initialise() 66 public void Initialise()
67 { 67 {
68 Logger.Log.InfoFormat("[ASSET]: {0} cannot be default-initialized!", Name); 68 Logger.Log.InfoFormat("[ASSET]: {0} cannot be default-initialized!", Name);
69 throw new PluginNotInitialisedException(Name); 69 throw new PluginNotInitialisedException(Name);
70 } 70 }
71 71
72 public void Dispose() 72 public void Dispose()
73 { 73 {
74 } 74 }
75 75
76 public string Version 76 public string Version
77 { 77 {
78 // TODO: this should be something meaningful and not hardcoded? 78 // TODO: this should be something meaningful and not hardcoded?
79 get { return "0.1"; } 79 get { return "0.1"; }
80 } 80 }
81 81
82 public string Name 82 public string Name
83 { 83 {
84 get { return "AssetInventoryServer OpenSim asset frontend"; } 84 get { return "AssetInventoryServer OpenSim asset frontend"; }
85 } 85 }
86 86
87 #endregion IPlugin implementation 87 #endregion IPlugin implementation
88 88
89 bool AssetRequestHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response) 89 bool AssetRequestHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
90 { 90 {
91 UUID assetID; 91 UUID assetID;
92 // Split the URL up to get the asset ID out 92 // Split the URL up to get the asset ID out
93 string[] rawUrl = request.Uri.PathAndQuery.Split('/'); 93 string[] rawUrl = request.Uri.PathAndQuery.Split('/');
94 94
95 if (rawUrl.Length >= 3 && rawUrl[2].Length >= 36 && UUID.TryParse(rawUrl[2].Substring(0, 36), out assetID)) 95 if (rawUrl.Length >= 3 && rawUrl[2].Length >= 36 && UUID.TryParse(rawUrl[2].Substring(0, 36), out assetID))
96 { 96 {
97 Metadata metadata; 97 Metadata metadata;
98 byte[] assetData; 98 byte[] assetData;
99 BackendResponse dataResponse; 99 BackendResponse dataResponse;
100 100
101 if ((dataResponse = server.StorageProvider.TryFetchDataMetadata(assetID, out metadata, out assetData)) == BackendResponse.Success) 101 if ((dataResponse = server.StorageProvider.TryFetchDataMetadata(assetID, out metadata, out assetData)) == BackendResponse.Success)
102 { 102 {
103 MemoryStream stream = new MemoryStream(); 103 MemoryStream stream = new MemoryStream();
104 104
105 XmlWriterSettings settings = new XmlWriterSettings(); 105 XmlWriterSettings settings = new XmlWriterSettings();
106 settings.Indent = true; 106 settings.Indent = true;
107 XmlWriter writer = XmlWriter.Create(stream, settings); 107 XmlWriter writer = XmlWriter.Create(stream, settings);
108 108
109 writer.WriteStartDocument(); 109 writer.WriteStartDocument();
110 writer.WriteStartElement("AssetBase"); 110 writer.WriteStartElement("AssetBase");
111 writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance"); 111 writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
112 writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema"); 112 writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
113 writer.WriteStartElement("FullID"); 113 writer.WriteStartElement("FullID");
114 writer.WriteStartElement("Guid"); 114 writer.WriteStartElement("Guid");
115 writer.WriteString(assetID.ToString()); 115 writer.WriteString(assetID.ToString());
116 writer.WriteEndElement(); 116 writer.WriteEndElement();
117 writer.WriteEndElement(); 117 writer.WriteEndElement();
118 writer.WriteStartElement("ID"); 118 writer.WriteStartElement("ID");
119 writer.WriteString(assetID.ToString()); 119 writer.WriteString(assetID.ToString());
120 writer.WriteEndElement(); 120 writer.WriteEndElement();
121 writer.WriteStartElement("Data"); 121 writer.WriteStartElement("Data");
122 writer.WriteBase64(assetData, 0, assetData.Length); 122 writer.WriteBase64(assetData, 0, assetData.Length);
123 writer.WriteEndElement(); 123 writer.WriteEndElement();
124 writer.WriteStartElement("Type"); 124 writer.WriteStartElement("Type");
125 writer.WriteValue(Utils.ContentTypeToSLAssetType(metadata.ContentType)); 125 writer.WriteValue(Utils.ContentTypeToSLAssetType(metadata.ContentType));
126 writer.WriteEndElement(); 126 writer.WriteEndElement();
127 writer.WriteStartElement("Name"); 127 writer.WriteStartElement("Name");
128 writer.WriteString(metadata.Name); 128 writer.WriteString(metadata.Name);
129 writer.WriteEndElement(); 129 writer.WriteEndElement();
130 writer.WriteStartElement("Description"); 130 writer.WriteStartElement("Description");
131 writer.WriteString(metadata.Description); 131 writer.WriteString(metadata.Description);
132 writer.WriteEndElement(); 132 writer.WriteEndElement();
133 writer.WriteStartElement("Local"); 133 writer.WriteStartElement("Local");
134 writer.WriteValue(false); 134 writer.WriteValue(false);
135 writer.WriteEndElement(); 135 writer.WriteEndElement();
136 writer.WriteStartElement("Temporary"); 136 writer.WriteStartElement("Temporary");
137 writer.WriteValue(metadata.Temporary); 137 writer.WriteValue(metadata.Temporary);
138 writer.WriteEndElement(); 138 writer.WriteEndElement();
139 writer.WriteEndElement(); 139 writer.WriteEndElement();
140 writer.WriteEndDocument(); 140 writer.WriteEndDocument();
141 141
142 writer.Flush(); 142 writer.Flush();
143 byte[] buffer = stream.GetBuffer(); 143 byte[] buffer = stream.GetBuffer();
144 144
145 response.Status = HttpStatusCode.OK; 145 response.Status = HttpStatusCode.OK;
146 response.ContentType = "application/xml"; 146 response.ContentType = "application/xml";
147 response.ContentLength = stream.Length; 147 response.ContentLength = stream.Length;
148 response.Body.Write(buffer, 0, (int)stream.Length); 148 response.Body.Write(buffer, 0, (int)stream.Length);
149 response.Body.Flush(); 149 response.Body.Flush();
150 } 150 }
151 else 151 else
152 { 152 {
153 Logger.Log.WarnFormat("Failed to fetch asset data or metadata for {0}: {1}", assetID, dataResponse); 153 Logger.Log.WarnFormat("Failed to fetch asset data or metadata for {0}: {1}", assetID, dataResponse);
154 response.Status = HttpStatusCode.NotFound; 154 response.Status = HttpStatusCode.NotFound;
155 } 155 }
156 } 156 }
157 else 157 else
158 { 158 {
159 Logger.Log.Warn("Unrecognized OpenSim asset request: " + request.Uri.PathAndQuery); 159 Logger.Log.Warn("Unrecognized OpenSim asset request: " + request.Uri.PathAndQuery);
160 } 160 }
161 161
162 return true; 162 return true;
163 } 163 }
164 164
165 bool AssetPostHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response) 165 bool AssetPostHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
166 { 166 {
167 byte[] assetData = null; 167 byte[] assetData = null;
168 Metadata metadata = new Metadata(); 168 Metadata metadata = new Metadata();
169 169
170 Logger.Log.Debug("Handling OpenSim asset upload"); 170 Logger.Log.Debug("Handling OpenSim asset upload");
171 171
172 try 172 try
173 { 173 {
174 using (XmlReader reader = XmlReader.Create(request.Body)) 174 using (XmlReader reader = XmlReader.Create(request.Body))
175 { 175 {
176 reader.MoveToContent(); 176 reader.MoveToContent();
177 reader.ReadStartElement("AssetBase"); 177 reader.ReadStartElement("AssetBase");
178 178
179 reader.ReadStartElement("FullID"); 179 reader.ReadStartElement("FullID");
180 UUID.TryParse(reader.ReadElementContentAsString("Guid", String.Empty), out metadata.ID); 180 UUID.TryParse(reader.ReadElementContentAsString("Guid", String.Empty), out metadata.ID);
181 reader.ReadEndElement(); 181 reader.ReadEndElement();
182 reader.ReadStartElement("ID"); 182 reader.ReadStartElement("ID");
183 reader.Skip(); 183 reader.Skip();
184 reader.ReadEndElement(); 184 reader.ReadEndElement();
185 185
186 // HACK: Broken on Mono. https://bugzilla.novell.com/show_bug.cgi?id=464229 186 // HACK: Broken on Mono. https://bugzilla.novell.com/show_bug.cgi?id=464229
187 //int readBytes = 0; 187 //int readBytes = 0;
188 //byte[] buffer = new byte[1024]; 188 //byte[] buffer = new byte[1024];
189 //MemoryStream stream = new MemoryStream(); 189 //MemoryStream stream = new MemoryStream();
190 //BinaryWriter writer = new BinaryWriter(stream); 190 //BinaryWriter writer = new BinaryWriter(stream);
191 //while ((readBytes = reader.ReadElementContentAsBase64(buffer, 0, buffer.Length)) > 0) 191 //while ((readBytes = reader.ReadElementContentAsBase64(buffer, 0, buffer.Length)) > 0)
192 // writer.Write(buffer, 0, readBytes); 192 // writer.Write(buffer, 0, readBytes);
193 //writer.Flush(); 193 //writer.Flush();
194 //assetData = stream.GetBuffer(); 194 //assetData = stream.GetBuffer();
195 //Array.Resize<byte>(ref assetData, (int)stream.Length); 195 //Array.Resize<byte>(ref assetData, (int)stream.Length);
196 196
197 assetData = Convert.FromBase64String(reader.ReadElementContentAsString()); 197 assetData = Convert.FromBase64String(reader.ReadElementContentAsString());
198 198
199 int type; 199 int type;
200 Int32.TryParse(reader.ReadElementContentAsString("Type", String.Empty), out type); 200 Int32.TryParse(reader.ReadElementContentAsString("Type", String.Empty), out type);
201 metadata.ContentType = Utils.SLAssetTypeToContentType(type); 201 metadata.ContentType = Utils.SLAssetTypeToContentType(type);
202 metadata.Name = reader.ReadElementContentAsString("Name", String.Empty); 202 metadata.Name = reader.ReadElementContentAsString("Name", String.Empty);
203 metadata.Description = reader.ReadElementContentAsString("Description", String.Empty); 203 metadata.Description = reader.ReadElementContentAsString("Description", String.Empty);
204 Boolean.TryParse(reader.ReadElementContentAsString("Local", String.Empty), out metadata.Temporary); 204 Boolean.TryParse(reader.ReadElementContentAsString("Local", String.Empty), out metadata.Temporary);
205 Boolean.TryParse(reader.ReadElementContentAsString("Temporary", String.Empty), out metadata.Temporary); 205 Boolean.TryParse(reader.ReadElementContentAsString("Temporary", String.Empty), out metadata.Temporary);
206 206
207 reader.ReadEndElement(); 207 reader.ReadEndElement();
208 } 208 }
209 209
210 if (assetData != null && assetData.Length > 0) 210 if (assetData != null && assetData.Length > 0)
211 { 211 {
212 metadata.SHA1 = OpenMetaverse.Utils.SHA1(assetData); 212 metadata.SHA1 = OpenMetaverse.Utils.SHA1(assetData);
213 metadata.CreationDate = DateTime.Now; 213 metadata.CreationDate = DateTime.Now;
214 214
215 BackendResponse storageResponse = server.StorageProvider.TryCreateAsset(metadata, assetData); 215 BackendResponse storageResponse = server.StorageProvider.TryCreateAsset(metadata, assetData);
216 216
217 if (storageResponse == BackendResponse.Success) 217 if (storageResponse == BackendResponse.Success)
218 response.Status = HttpStatusCode.Created; 218 response.Status = HttpStatusCode.Created;
219 else if (storageResponse == BackendResponse.NotFound) 219 else if (storageResponse == BackendResponse.NotFound)
220 response.Status = HttpStatusCode.NotFound; 220 response.Status = HttpStatusCode.NotFound;
221 else 221 else
222 response.Status = HttpStatusCode.InternalServerError; 222 response.Status = HttpStatusCode.InternalServerError;
223 } 223 }
224 else 224 else
225 { 225 {
226 Logger.Log.Warn("AssetPostHandler called with no asset data"); 226 Logger.Log.Warn("AssetPostHandler called with no asset data");
227 response.Status = HttpStatusCode.BadRequest; 227 response.Status = HttpStatusCode.BadRequest;
228 } 228 }
229 } 229 }
230 catch (Exception ex) 230 catch (Exception ex)
231 { 231 {
232 Logger.Log.Warn("Failed to parse POST data (expecting AssetBase): " + ex.Message); 232 Logger.Log.Warn("Failed to parse POST data (expecting AssetBase): " + ex.Message);
233 response.Status = HttpStatusCode.BadRequest; 233 response.Status = HttpStatusCode.BadRequest;
234 } 234 }
235 235
236 Logger.Log.Debug("Finished handling OpenSim asset upload, Status: " + response.Status.ToString()); 236 Logger.Log.Debug("Finished handling OpenSim asset upload, Status: " + response.Status.ToString());
237 return true; 237 return true;
238 } 238 }
239 } 239 }
240} 240}
diff --git a/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimAssetStoragePlugin.cs b/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimAssetStoragePlugin.cs
index 148b401..a5e4c95 100644
--- a/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimAssetStoragePlugin.cs
+++ b/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimAssetStoragePlugin.cs
@@ -1,370 +1,370 @@
1/* 1/*
2 * Copyright (c) 2008 Intel Corporation 2 * Copyright (c) 2008 Intel Corporation
3 * All rights reserved. 3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 7 *
8 * -- Redistributions of source code must retain the above copyright 8 * -- Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * -- Redistributions in binary form must reproduce the above copyright 10 * -- Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the 11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 12 * documentation and/or other materials provided with the distribution.
13 * -- Neither the name of the Intel Corporation nor the names of its 13 * -- Neither the name of the Intel Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from 14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission. 15 * this software without specific prior written permission.
16 * 16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS 20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */ 28 */
29 29
30using System; 30using System;
31using System.Collections.Generic; 31using System.Collections.Generic;
32using System.Net; 32using System.Net;
33using System.Data; 33using System.Data;
34using MySql.Data.MySqlClient; 34using MySql.Data.MySqlClient;
35using ExtensionLoader; 35using ExtensionLoader;
36using ExtensionLoader.Config; 36using ExtensionLoader.Config;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenMetaverse.StructuredData; 38using OpenMetaverse.StructuredData;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Grid.AssetInventoryServer.Extensions; 40using OpenSim.Grid.AssetInventoryServer.Extensions;
41 41
42namespace OpenSim.Grid.AssetInventoryServer.Plugins 42namespace OpenSim.Grid.AssetInventoryServer.Plugins
43{ 43{
44 public class OpenSimAssetStoragePlugin : IAssetStorageProvider 44 public class OpenSimAssetStoragePlugin : IAssetStorageProvider
45 { 45 {
46 const string EXTENSION_NAME = "OpenSimAssetStorage"; // Used in metrics reporting 46 const string EXTENSION_NAME = "OpenSimAssetStorage"; // Used in metrics reporting
47 47
48 private AssetInventoryServer server; 48 private AssetInventoryServer server;
49 private IAssetProviderPlugin m_assetProvider; 49 private IAssetProviderPlugin m_assetProvider;
50 50
51 public OpenSimAssetStoragePlugin() 51 public OpenSimAssetStoragePlugin()
52 { 52 {
53 } 53 }
54 54
55 #region IAssetStorageProvider implementation 55 #region IAssetStorageProvider implementation
56 56
57 public BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata) 57 public BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata)
58 { 58 {
59 metadata = null; 59 metadata = null;
60 BackendResponse ret; 60 BackendResponse ret;
61 61
62 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 62 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
63 { 63 {
64 IDataReader reader; 64 IDataReader reader;
65 65
66 try 66 try
67 { 67 {
68 dbConnection.Open(); 68 dbConnection.Open();
69 69
70 IDbCommand command = dbConnection.CreateCommand(); 70 IDbCommand command = dbConnection.CreateCommand();
71 command.CommandText = String.Format("SELECT name,description,assetType,temporary FROM assets WHERE id='{0}'", assetID.ToString()); 71 command.CommandText = String.Format("SELECT name,description,assetType,temporary FROM assets WHERE id='{0}'", assetID.ToString());
72 reader = command.ExecuteReader(); 72 reader = command.ExecuteReader();
73 73
74 if (reader.Read()) 74 if (reader.Read())
75 { 75 {
76 metadata = new Metadata(); 76 metadata = new Metadata();
77 metadata.CreationDate = OpenMetaverse.Utils.Epoch; 77 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
78 metadata.SHA1 = null; 78 metadata.SHA1 = null;
79 metadata.ID = assetID; 79 metadata.ID = assetID;
80 metadata.Name = reader.GetString(0); 80 metadata.Name = reader.GetString(0);
81 metadata.Description = reader.GetString(1); 81 metadata.Description = reader.GetString(1);
82 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2)); 82 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
83 metadata.Temporary = reader.GetBoolean(3); 83 metadata.Temporary = reader.GetBoolean(3);
84 84
85 ret = BackendResponse.Success; 85 ret = BackendResponse.Success;
86 } 86 }
87 else 87 else
88 { 88 {
89 ret = BackendResponse.NotFound; 89 ret = BackendResponse.NotFound;
90 } 90 }
91 } 91 }
92 catch (MySqlException ex) 92 catch (MySqlException ex)
93 { 93 {
94 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); 94 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
95 ret = BackendResponse.Failure; 95 ret = BackendResponse.Failure;
96 } 96 }
97 } 97 }
98 98
99 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now); 99 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now);
100 return ret; 100 return ret;
101 } 101 }
102 102
103 public BackendResponse TryFetchData(UUID assetID, out byte[] assetData) 103 public BackendResponse TryFetchData(UUID assetID, out byte[] assetData)
104 { 104 {
105 assetData = null; 105 assetData = null;
106 BackendResponse ret; 106 BackendResponse ret;
107 107
108 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 108 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
109 { 109 {
110 IDataReader reader; 110 IDataReader reader;
111 111
112 try 112 try
113 { 113 {
114 dbConnection.Open(); 114 dbConnection.Open();
115 115
116 IDbCommand command = dbConnection.CreateCommand(); 116 IDbCommand command = dbConnection.CreateCommand();
117 command.CommandText = String.Format("SELECT data FROM assets WHERE id='{0}'", assetID.ToString()); 117 command.CommandText = String.Format("SELECT data FROM assets WHERE id='{0}'", assetID.ToString());
118 reader = command.ExecuteReader(); 118 reader = command.ExecuteReader();
119 119
120 if (reader.Read()) 120 if (reader.Read())
121 { 121 {
122 assetData = (byte[])reader.GetValue(0); 122 assetData = (byte[])reader.GetValue(0);
123 ret = BackendResponse.Success; 123 ret = BackendResponse.Success;
124 } 124 }
125 else 125 else
126 { 126 {
127 ret = BackendResponse.NotFound; 127 ret = BackendResponse.NotFound;
128 } 128 }
129 } 129 }
130 catch (MySqlException ex) 130 catch (MySqlException ex)
131 { 131 {
132 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); 132 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
133 ret = BackendResponse.Failure; 133 ret = BackendResponse.Failure;
134 } 134 }
135 } 135 }
136 136
137 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now); 137 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now);
138 return ret; 138 return ret;
139 } 139 }
140 140
141 public BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData) 141 public BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData)
142 { 142 {
143 metadata = null; 143 metadata = null;
144 assetData = null; 144 assetData = null;
145 //BackendResponse ret; 145 //BackendResponse ret;
146 146
147 AssetBase asset_base = m_assetProvider.FetchAsset(assetID); 147 AssetBase asset_base = m_assetProvider.FetchAsset(assetID);
148 148
149 if (asset_base != null) 149 if (asset_base != null)
150 { 150 {
151 metadata = new Metadata(); 151 metadata = new Metadata();
152 metadata.CreationDate = OpenMetaverse.Utils.Epoch; 152 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
153 metadata.SHA1 = null; 153 metadata.SHA1 = null;
154 metadata.Name = asset_base.Name; 154 metadata.Name = asset_base.Name;
155 metadata.Description = asset_base.Description; 155 metadata.Description = asset_base.Description;
156 metadata.ContentType = Utils.SLAssetTypeToContentType(asset_base.Type); 156 metadata.ContentType = Utils.SLAssetTypeToContentType(asset_base.Type);
157 metadata.Temporary = asset_base.Temporary; 157 metadata.Temporary = asset_base.Temporary;
158 158
159 assetData = asset_base.Data; 159 assetData = asset_base.Data;
160 } 160 }
161 else return BackendResponse.NotFound; 161 else return BackendResponse.NotFound;
162 162
163 return BackendResponse.Success; 163 return BackendResponse.Success;
164 164
165 //using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 165 //using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
166 //{ 166 //{
167 // IDataReader reader; 167 // IDataReader reader;
168 168
169 // try 169 // try
170 // { 170 // {
171 // dbConnection.Open(); 171 // dbConnection.Open();
172 172
173 // IDbCommand command = dbConnection.CreateCommand(); 173 // IDbCommand command = dbConnection.CreateCommand();
174 // command.CommandText = String.Format("SELECT name,description,assetType,temporary,data FROM assets WHERE id='{0}'", assetID.ToString()); 174 // command.CommandText = String.Format("SELECT name,description,assetType,temporary,data FROM assets WHERE id='{0}'", assetID.ToString());
175 // reader = command.ExecuteReader(); 175 // reader = command.ExecuteReader();
176 176
177 // if (reader.Read()) 177 // if (reader.Read())
178 // { 178 // {
179 // metadata = new Metadata(); 179 // metadata = new Metadata();
180 // metadata.CreationDate = OpenMetaverse.Utils.Epoch; 180 // metadata.CreationDate = OpenMetaverse.Utils.Epoch;
181 // metadata.SHA1 = null; 181 // metadata.SHA1 = null;
182 // metadata.ID = assetID; 182 // metadata.ID = assetID;
183 // metadata.Name = reader.GetString(0); 183 // metadata.Name = reader.GetString(0);
184 // metadata.Description = reader.GetString(1); 184 // metadata.Description = reader.GetString(1);
185 // metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2)); 185 // metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
186 // metadata.Temporary = reader.GetBoolean(3); 186 // metadata.Temporary = reader.GetBoolean(3);
187 187
188 // assetData = (byte[])reader.GetValue(4); 188 // assetData = (byte[])reader.GetValue(4);
189 189
190 // ret = BackendResponse.Success; 190 // ret = BackendResponse.Success;
191 // } 191 // }
192 // else 192 // else
193 // { 193 // {
194 // ret = BackendResponse.NotFound; 194 // ret = BackendResponse.NotFound;
195 // } 195 // }
196 // } 196 // }
197 // catch (MySqlException ex) 197 // catch (MySqlException ex)
198 // { 198 // {
199 // Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); 199 // Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
200 // ret = BackendResponse.Failure; 200 // ret = BackendResponse.Failure;
201 // } 201 // }
202 //} 202 //}
203 203
204 //server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now); 204 //server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now);
205 //server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now); 205 //server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now);
206 //return ret; 206 //return ret;
207 } 207 }
208 208
209 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID) 209 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID)
210 { 210 {
211 assetID = metadata.ID = UUID.Random(); 211 assetID = metadata.ID = UUID.Random();
212 return TryCreateAsset(metadata, assetData); 212 return TryCreateAsset(metadata, assetData);
213 } 213 }
214 214
215 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData) 215 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData)
216 { 216 {
217 BackendResponse ret; 217 BackendResponse ret;
218 218
219 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 219 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
220 { 220 {
221 try 221 try
222 { 222 {
223 dbConnection.Open(); 223 dbConnection.Open();
224 224
225 MySqlCommand command = new MySqlCommand( 225 MySqlCommand command = new MySqlCommand(
226 "REPLACE INTO assets (name,description,assetType,local,temporary,data,id) VALUES " + 226 "REPLACE INTO assets (name,description,assetType,local,temporary,data,id) VALUES " +
227 "(?name,?description,?assetType,?local,?temporary,?data,?id)", dbConnection); 227 "(?name,?description,?assetType,?local,?temporary,?data,?id)", dbConnection);
228 228
229 command.Parameters.AddWithValue("?name", metadata.Name); 229 command.Parameters.AddWithValue("?name", metadata.Name);
230 command.Parameters.AddWithValue("?description", metadata.Description); 230 command.Parameters.AddWithValue("?description", metadata.Description);
231 command.Parameters.AddWithValue("?assetType", Utils.ContentTypeToSLAssetType(metadata.ContentType)); 231 command.Parameters.AddWithValue("?assetType", Utils.ContentTypeToSLAssetType(metadata.ContentType));
232 command.Parameters.AddWithValue("?local", 0); 232 command.Parameters.AddWithValue("?local", 0);
233 command.Parameters.AddWithValue("?temporary", metadata.Temporary); 233 command.Parameters.AddWithValue("?temporary", metadata.Temporary);
234 command.Parameters.AddWithValue("?data", assetData); 234 command.Parameters.AddWithValue("?data", assetData);
235 command.Parameters.AddWithValue("?id", metadata.ID.ToString()); 235 command.Parameters.AddWithValue("?id", metadata.ID.ToString());
236 236
237 int rowsAffected = command.ExecuteNonQuery(); 237 int rowsAffected = command.ExecuteNonQuery();
238 if (rowsAffected == 1) 238 if (rowsAffected == 1)
239 { 239 {
240 ret = BackendResponse.Success; 240 ret = BackendResponse.Success;
241 } 241 }
242 else if (rowsAffected == 2) 242 else if (rowsAffected == 2)
243 { 243 {
244 Logger.Log.Info("Replaced asset " + metadata.ID.ToString()); 244 Logger.Log.Info("Replaced asset " + metadata.ID.ToString());
245 ret = BackendResponse.Success; 245 ret = BackendResponse.Success;
246 } 246 }
247 else 247 else
248 { 248 {
249 Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected); 249 Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected);
250 ret = BackendResponse.Failure; 250 ret = BackendResponse.Failure;
251 } 251 }
252 } 252 }
253 catch (MySqlException ex) 253 catch (MySqlException ex)
254 { 254 {
255 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); 255 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
256 ret = BackendResponse.Failure; 256 ret = BackendResponse.Failure;
257 } 257 }
258 } 258 }
259 259
260 server.MetricsProvider.LogAssetCreate(EXTENSION_NAME, ret, metadata.ID, assetData.Length, DateTime.Now); 260 server.MetricsProvider.LogAssetCreate(EXTENSION_NAME, ret, metadata.ID, assetData.Length, DateTime.Now);
261 return ret; 261 return ret;
262 } 262 }
263 263
264 public int ForEach(Action<Metadata> action, int start, int count) 264 public int ForEach(Action<Metadata> action, int start, int count)
265 { 265 {
266 int rowCount = 0; 266 int rowCount = 0;
267 267
268 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) 268 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
269 { 269 {
270 MySqlDataReader reader; 270 MySqlDataReader reader;
271 271
272 try 272 try
273 { 273 {
274 dbConnection.Open(); 274 dbConnection.Open();
275 275
276 MySqlCommand command = dbConnection.CreateCommand(); 276 MySqlCommand command = dbConnection.CreateCommand();
277 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data,id FROM assets LIMIT {0}, {1}", 277 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data,id FROM assets LIMIT {0}, {1}",
278 start, count); 278 start, count);
279 reader = command.ExecuteReader(); 279 reader = command.ExecuteReader();
280 } 280 }
281 catch (MySqlException ex) 281 catch (MySqlException ex)
282 { 282 {
283 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); 283 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
284 return 0; 284 return 0;
285 } 285 }
286 286
287 while (reader.Read()) 287 while (reader.Read())
288 { 288 {
289 Metadata metadata = new Metadata(); 289 Metadata metadata = new Metadata();
290 metadata.CreationDate = OpenMetaverse.Utils.Epoch; 290 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
291 metadata.Description = reader.GetString(1); 291 metadata.Description = reader.GetString(1);
292 metadata.ID = UUID.Parse(reader.GetString(5)); 292 metadata.ID = UUID.Parse(reader.GetString(5));
293 metadata.Name = reader.GetString(0); 293 metadata.Name = reader.GetString(0);
294 metadata.SHA1 = OpenMetaverse.Utils.SHA1((byte[])reader.GetValue(4)); 294 metadata.SHA1 = OpenMetaverse.Utils.SHA1((byte[])reader.GetValue(4));
295 metadata.Temporary = reader.GetBoolean(3); 295 metadata.Temporary = reader.GetBoolean(3);
296 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2)); 296 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
297 297
298 action(metadata); 298 action(metadata);
299 ++rowCount; 299 ++rowCount;
300 } 300 }
301 301
302 reader.Close(); 302 reader.Close();
303 } 303 }
304 304
305 return rowCount; 305 return rowCount;
306 } 306 }
307 307
308 #endregion IAssetStorageProvider implementation 308 #endregion IAssetStorageProvider implementation
309 309
310 #region IPlugin implementation 310 #region IPlugin implementation
311 311
312 public void Initialise(AssetInventoryServer server) 312 public void Initialise(AssetInventoryServer server)
313 { 313 {
314 this.server = server; 314 this.server = server;
315 315
316 try 316 try
317 { 317 {
318 m_assetProvider = LoadDatabasePlugin("OpenSim.Data.MySQL.dll", server.ConfigFile.Configs["MySQL"].GetString("database_connect", null)); 318 m_assetProvider = LoadDatabasePlugin("OpenSim.Data.MySQL.dll", server.ConfigFile.Configs["MySQL"].GetString("database_connect", null));
319 if (m_assetProvider == null) 319 if (m_assetProvider == null)
320 { 320 {
321 Logger.Log.Error("[ASSET]: Failed to load a database plugin, server halting."); 321 Logger.Log.Error("[ASSET]: Failed to load a database plugin, server halting.");
322 Environment.Exit(-1); 322 Environment.Exit(-1);
323 } 323 }
324 else 324 else
325 Logger.Log.InfoFormat("[ASSET]: Loaded storage backend: {0}", Version); 325 Logger.Log.InfoFormat("[ASSET]: Loaded storage backend: {0}", Version);
326 } 326 }
327 catch (Exception e) 327 catch (Exception e)
328 { 328 {
329 Logger.Log.WarnFormat("[ASSET]: Failure loading data plugin: {0}", e.ToString()); 329 Logger.Log.WarnFormat("[ASSET]: Failure loading data plugin: {0}", e.ToString());
330 } 330 }
331 } 331 }
332 332
333 /// <summary> 333 /// <summary>
334 /// <para>Initialises asset interface</para> 334 /// <para>Initialises asset interface</para>
335 /// </summary> 335 /// </summary>
336 public void Initialise() 336 public void Initialise()
337 { 337 {
338 Logger.Log.InfoFormat("[ASSET]: {0} cannot be default-initialized!", Name); 338 Logger.Log.InfoFormat("[ASSET]: {0} cannot be default-initialized!", Name);
339 throw new PluginNotInitialisedException(Name); 339 throw new PluginNotInitialisedException(Name);
340 } 340 }
341 341
342 public void Dispose() 342 public void Dispose()
343 { 343 {
344 } 344 }
345 345
346 public string Version 346 public string Version
347 { 347 {
348 get { return m_assetProvider.Version; } 348 get { return m_assetProvider.Version; }
349 } 349 }
350 350
351 public string Name 351 public string Name
352 { 352 {
353 get { return "AssetInventoryServer OpenSim asset storage provider"; } 353 get { return "AssetInventoryServer OpenSim asset storage provider"; }
354 } 354 }
355 355
356 #endregion IPlugin implementation 356 #endregion IPlugin implementation
357 357
358 private IAssetProviderPlugin LoadDatabasePlugin(string provider, string connect) 358 private IAssetProviderPlugin LoadDatabasePlugin(string provider, string connect)
359 { 359 {
360 PluginLoader<IAssetProviderPlugin> loader = new PluginLoader<IAssetProviderPlugin>(new AssetDataInitialiser(connect)); 360 PluginLoader<IAssetProviderPlugin> loader = new PluginLoader<IAssetProviderPlugin>(new AssetDataInitialiser(connect));
361 361
362 // Loader will try to load all providers (MySQL, MSSQL, etc) 362 // Loader will try to load all providers (MySQL, MSSQL, etc)
363 // unless it is constrainted to the correct "Provider" entry in the addin.xml 363 // unless it is constrainted to the correct "Provider" entry in the addin.xml
364 loader.Add("/OpenSim/AssetData", new PluginProviderFilter (provider)); 364 loader.Add("/OpenSim/AssetData", new PluginProviderFilter (provider));
365 loader.Load(); 365 loader.Load();
366 366
367 return loader.Plugin; 367 return loader.Plugin;
368 } 368 }
369 } 369 }
370} 370}