OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
HGAssetMapper.cs
Go to the documentation of this file.
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 OpenSimulator 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 
28 using System;
29 using System.Collections.Generic;
30 using System.IO;
31 using System.Reflection;
32 using System.Threading;
33 using System.Xml;
34 
35 using log4net;
36 using OpenMetaverse;
37 using OpenSim.Framework;
38 using OpenSim.Framework.Serialization.External;
39 
40 using OpenSim.Region.Framework.Scenes;
41 using OpenSim.Region.Framework.Scenes.Serialization;
42 using OpenSim.Region.Framework.Interfaces;
43 using OpenSim.Services.Interfaces;
44 
45 //using HyperGrid.Framework;
46 //using OpenSim.Region.Communications.Hypergrid;
47 
48 namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
49 {
50  public class HGAssetMapper
51  {
52  #region Fields
53  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54 
55  // This maps between inventory server urls and inventory server clients
56 // private Dictionary<string, InventoryClient> m_inventoryServers = new Dictionary<string, InventoryClient>();
57 
58  private Scene m_scene;
59  private string m_HomeURI;
60 
61  #endregion
62 
63  #region Constructor
64 
65  public HGAssetMapper(Scene scene, string homeURL)
66  {
67  m_scene = scene;
68  m_HomeURI = homeURL;
69  }
70 
71  #endregion
72 
73  #region Internal functions
74 
75  private AssetMetadata FetchMetadata(string url, UUID assetID)
76  {
77  if (string.IsNullOrEmpty(url))
78  return null;
79 
80  if (!url.EndsWith("/") && !url.EndsWith("="))
81  url = url + "/";
82 
83  AssetMetadata meta = m_scene.AssetService.GetMetadata(url + assetID.ToString());
84 
85  if (meta != null)
86  m_log.DebugFormat("[HG ASSET MAPPER]: Fetched metadata for asset {0} of type {1} from {2} ", assetID, meta.Type, url);
87  else
88  m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetched metadata for asset {0} from {1} ", assetID, url);
89 
90  return meta;
91  }
92 
93  private AssetBase FetchAsset(string url, UUID assetID)
94  {
95  // Test if it's already here
96  AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
97  if (asset == null)
98  {
99  if (string.IsNullOrEmpty(url))
100  return null;
101 
102  if (!url.EndsWith("/") && !url.EndsWith("="))
103  url = url + "/";
104 
105  asset = m_scene.AssetService.Get(url + assetID.ToString());
106 
107  //if (asset != null)
108  // m_log.DebugFormat("[HG ASSET MAPPER]: Fetched asset {0} of type {1} from {2} ", assetID, asset.Metadata.Type, url);
109  //else
110  // m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetch asset {0} from {1} ", assetID, url);
111 
112  }
113 
114  return asset;
115  }
116 
117  public bool PostAsset(string url, AssetBase asset)
118  {
119  if (string.IsNullOrEmpty(url))
120  return false;
121 
122  if (!url.EndsWith("/") && !url.EndsWith("="))
123  url = url + "/";
124 
125  if (asset == null)
126  {
127  m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache.");
128  return false;
129  }
130 
131  // See long comment in AssetCache.AddAsset
132  if (asset.Temporary || asset.Local)
133  return true;
134 
135  // We need to copy the asset into a new asset, because
136  // we need to set its ID to be URL+UUID, so that the
137  // HGAssetService dispatches it to the remote grid.
138  // It's not pretty, but the best that can be done while
139  // not having a global naming infrastructure
140  AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID);
141  Copy(asset, asset1);
142  asset1.ID = url + asset.ID;
143 
144  AdjustIdentifiers(asset1.Metadata);
145  if (asset1.Metadata.Type == (sbyte)AssetType.Object)
146  asset1.Data = AdjustIdentifiers(asset.Data);
147  else
148  asset1.Data = asset.Data;
149 
150  string id = m_scene.AssetService.Store(asset1);
151  if (String.IsNullOrEmpty(id))
152  {
153  m_log.DebugFormat("[HG ASSET MAPPER]: Asset server {0} did not accept {1}", url, asset.ID);
154  return false;
155  }
156  else {
157  m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
158  return true;
159  }
160  }
161 
162  private void Copy(AssetBase from, AssetBase to)
163  {
164  //to.Data = from.Data; // don't copy this, it's copied elsewhere
165  to.Description = from.Description;
166  to.FullID = from.FullID;
167  to.ID = from.ID;
168  to.Local = from.Local;
169  to.Name = from.Name;
170  to.Temporary = from.Temporary;
171  to.Type = from.Type;
172 
173  }
174 
175  private void AdjustIdentifiers(AssetMetadata meta)
176  {
177  if (!string.IsNullOrEmpty(meta.CreatorID))
178  {
179  UUID uuid = UUID.Zero;
180  UUID.TryParse(meta.CreatorID, out uuid);
181  UserAccount creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid);
182  if (creator != null)
183  meta.CreatorID = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName;
184  }
185  }
186 
187  protected byte[] AdjustIdentifiers(byte[] data)
188  {
189  string xml = Utils.BytesToString(data);
190  return Utils.StringToBytes(RewriteSOP(xml));
191  }
192 
193  protected string RewriteSOP(string xmlData)
194  {
195 // Console.WriteLine("Input XML [{0}]", xmlData);
196  return ExternalRepresentationUtils.RewriteSOP(xmlData, m_scene.Name, m_HomeURI, m_scene.UserAccountService, m_scene.RegionInfo.ScopeID);
197 
198  }
199 
200  // TODO: unused
201  // private void Dump(Dictionary<UUID, bool> lst)
202  // {
203  // m_log.Debug("XXX -------- UUID DUMP ------- XXX");
204  // foreach (KeyValuePair<UUID, bool> kvp in lst)
205  // m_log.Debug(" >> " + kvp.Key + " (texture? " + kvp.Value + ")");
206  // m_log.Debug("XXX -------- UUID DUMP ------- XXX");
207  // }
208 
209  #endregion
210 
211 
212  #region Public interface
213 
214  public void Get(UUID assetID, UUID ownerID, string userAssetURL)
215  {
216  // Get the item from the remote asset server onto the local AssetService
217 
218  AssetMetadata meta = FetchMetadata(userAssetURL, assetID);
219  if (meta == null)
220  return;
221 
222  // The act of gathering UUIDs downloads some assets from the remote server
223  // but not all...
224  HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
225  uuidGatherer.AddForInspection(assetID);
226  uuidGatherer.GatherAll();
227 
228  m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", uuidGatherer.GatheredUuids.Count);
229  bool success = true;
230  foreach (UUID uuid in uuidGatherer.GatheredUuids.Keys)
231  if (FetchAsset(userAssetURL, uuid) == null)
232  success = false;
233 
234  // maybe all pieces got here...
235  if (!success)
236  m_log.DebugFormat("[HG ASSET MAPPER]: Problems getting item {0} from asset server {1}", assetID, userAssetURL);
237  else
238  m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL);
239  }
240 
241  public void Post(UUID assetID, UUID ownerID, string userAssetURL)
242  {
243  m_log.DebugFormat("[HG ASSET MAPPER]: Starting to send asset {0} with children to asset server {1}", assetID, userAssetURL);
244 
245  // Find all the embedded assets
246 
247  AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
248  if (asset == null)
249  {
250  m_log.DebugFormat("[HG ASSET MAPPER]: Something wrong with asset {0}, it could not be found", assetID);
251  return;
252  }
253 
254  HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty);
255  uuidGatherer.AddForInspection(asset.FullID);
256  uuidGatherer.GatherAll();
257 
258  // Check which assets already exist in the destination server
259 
260  string url = userAssetURL;
261  if (!url.EndsWith("/") && !url.EndsWith("="))
262  url = url + "/";
263 
264  string[] remoteAssetIDs = new string[uuidGatherer.GatheredUuids.Count];
265  int i = 0;
266  foreach (UUID id in uuidGatherer.GatheredUuids.Keys)
267  remoteAssetIDs[i++] = url + id.ToString();
268 
269  bool[] exist = m_scene.AssetService.AssetsExist(remoteAssetIDs);
270 
271  var existSet = new HashSet<string>();
272  i = 0;
273  foreach (UUID id in uuidGatherer.GatheredUuids.Keys)
274  {
275  if (exist[i])
276  existSet.Add(id.ToString());
277  ++i;
278  }
279 
280  // Send only those assets which don't already exist in the destination server
281 
282  bool success = true;
283 
284  foreach (UUID uuid in uuidGatherer.GatheredUuids.Keys)
285  {
286  if (!existSet.Contains(uuid.ToString()))
287  {
288  asset = m_scene.AssetService.Get(uuid.ToString());
289  if (asset == null)
290  {
291  m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid);
292  }
293  else
294  {
295  try
296  {
297  success &= PostAsset(userAssetURL, asset);
298  }
299  catch (Exception e)
300  {
301  m_log.Error(
302  string.Format(
303  "[HG ASSET MAPPER]: Failed to post asset {0} (type {1}, length {2}) referenced from {3} to {4} with exception ",
304  asset.ID, asset.Type, asset.Data.Length, assetID, userAssetURL),
305  e);
306 
307  // For debugging purposes for now we will continue to throw the exception up the stack as was already happening. However, after
308  // debugging we may want to simply report the failure if we can tell this is due to a failure
309  // with a particular asset and not a destination network failure where all asset posts will fail (and
310  // generate large amounts of log spam).
311  throw e;
312  }
313  }
314  }
315  else
316  {
317  m_log.DebugFormat(
318  "[HG ASSET MAPPER]: Didn't post asset {0} referenced from {1} because it already exists in asset server {2}",
319  uuid, assetID, userAssetURL);
320  }
321  }
322 
323  if (!success)
324  m_log.DebugFormat("[HG ASSET MAPPER]: Problems sending asset {0} with children to asset server {1}", assetID, userAssetURL);
325  else
326  m_log.DebugFormat("[HG ASSET MAPPER]: Successfully sent asset {0} with children to asset server {1}", assetID, userAssetURL);
327  }
328 
329  #endregion
330 
331  }
332 }
void Post(UUID assetID, UUID ownerID, string userAssetURL)
sbyte Type
(sbyte) AssetType enum
Definition: AssetBase.cs:198
bool Local
Is this a region only asset, or does this exist on the asset server also
Definition: AssetBase.cs:213
Asset class. All Assets are reference by this class or a class derived from this class ...
Definition: AssetBase.cs:49
void Get(UUID assetID, UUID ownerID, string userAssetURL)
Interactive OpenSim region server
Definition: OpenSim.cs:55
UUID FullID
Asset UUID
Definition: AssetBase.cs:168
bool Temporary
Is this asset going to be saved to the asset database?
Definition: AssetBase.cs:222