SimianAssetServiceConnector.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  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. using System;
  28. using System.Collections.Generic;
  29. using System.Collections.Specialized;
  30. using System.IO;
  31. using System.Net;
  32. using System.Reflection;
  33. using log4net;
  34. using Mono.Addins;
  35. using Nini.Config;
  36. using OpenSim.Framework;
  37. using OpenSim.Region.Framework.Interfaces;
  38. using OpenSim.Region.Framework.Scenes;
  39. using OpenSim.Services.Interfaces;
  40. using OpenMetaverse;
  41. using OpenMetaverse.StructuredData;
  42. namespace OpenSim.Services.Connectors.SimianGrid
  43. {
  44. /// <summary>
  45. /// Connects to the SimianGrid asset service
  46. /// </summary>
  47. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianAssetServiceConnector")]
  48. public class SimianAssetServiceConnector : IAssetService, ISharedRegionModule
  49. {
  50. private static readonly ILog m_log =
  51. LogManager.GetLogger(
  52. MethodBase.GetCurrentMethod().DeclaringType);
  53. private static string ZeroID = UUID.Zero.ToString();
  54. private string m_serverUrl = String.Empty;
  55. private IImprovedAssetCache m_cache;
  56. private bool m_Enabled = false;
  57. #region ISharedRegionModule
  58. public Type ReplaceableInterface { get { return null; } }
  59. public void RegionLoaded(Scene scene)
  60. {
  61. if (m_cache == null)
  62. {
  63. IImprovedAssetCache cache = scene.RequestModuleInterface<IImprovedAssetCache>();
  64. if (cache is ISharedRegionModule)
  65. m_cache = cache;
  66. }
  67. }
  68. public void PostInitialise() { }
  69. public void Close() { }
  70. public SimianAssetServiceConnector() { }
  71. public string Name { get { return "SimianAssetServiceConnector"; } }
  72. public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IAssetService>(this); } }
  73. public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IAssetService>(this); } }
  74. #endregion ISharedRegionModule
  75. public SimianAssetServiceConnector(IConfigSource source)
  76. {
  77. CommonInit(source);
  78. }
  79. public SimianAssetServiceConnector(string url)
  80. {
  81. if (!url.EndsWith("/") && !url.EndsWith("="))
  82. url = url + '/';
  83. m_serverUrl = url;
  84. }
  85. public void Initialise(IConfigSource source)
  86. {
  87. IConfig moduleConfig = source.Configs["Modules"];
  88. if (moduleConfig != null)
  89. {
  90. string name = moduleConfig.GetString("AssetServices", "");
  91. if (name == Name)
  92. CommonInit(source);
  93. }
  94. }
  95. private void CommonInit(IConfigSource source)
  96. {
  97. IConfig gridConfig = source.Configs["AssetService"];
  98. if (gridConfig != null)
  99. {
  100. string serviceUrl = gridConfig.GetString("AssetServerURI");
  101. if (!String.IsNullOrEmpty(serviceUrl))
  102. {
  103. if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
  104. serviceUrl = serviceUrl + '/';
  105. m_serverUrl = serviceUrl;
  106. }
  107. }
  108. if (String.IsNullOrEmpty(m_serverUrl))
  109. m_log.Info("[SIMIAN ASSET CONNECTOR]: No AssetServerURI specified, disabling connector");
  110. else
  111. m_Enabled = true;
  112. }
  113. #region IAssetService
  114. public AssetBase Get(string id)
  115. {
  116. if (String.IsNullOrEmpty(m_serverUrl))
  117. {
  118. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  119. throw new InvalidOperationException();
  120. }
  121. // Cache fetch
  122. if (m_cache != null)
  123. {
  124. AssetBase asset = m_cache.Get(id);
  125. if (asset != null)
  126. return asset;
  127. }
  128. return SimianGetOperation(id);
  129. }
  130. public AssetBase GetCached(string id)
  131. {
  132. if (m_cache != null)
  133. return m_cache.Get(id);
  134. return null;
  135. }
  136. /// <summary>
  137. /// Get an asset's metadata
  138. /// </summary>
  139. /// <param name="id"></param>
  140. /// <returns></returns>
  141. public AssetMetadata GetMetadata(string id)
  142. {
  143. if (String.IsNullOrEmpty(m_serverUrl))
  144. {
  145. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  146. throw new InvalidOperationException();
  147. }
  148. // Cache fetch
  149. if (m_cache != null)
  150. {
  151. AssetBase asset = m_cache.Get(id);
  152. if (asset != null)
  153. return asset.Metadata;
  154. }
  155. // return GetRemoteMetadata(id);
  156. return SimianGetMetadataOperation(id);
  157. }
  158. public byte[] GetData(string id)
  159. {
  160. if (String.IsNullOrEmpty(m_serverUrl))
  161. {
  162. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  163. throw new InvalidOperationException();
  164. }
  165. AssetBase asset = Get(id);
  166. if (asset != null)
  167. return asset.Data;
  168. return null;
  169. }
  170. /// <summary>
  171. /// Get an asset asynchronously
  172. /// </summary>
  173. /// <param name="id">The asset id</param>
  174. /// <param name="sender">Represents the requester. Passed back via the handler</param>
  175. /// <param name="handler">The handler to call back once the asset has been retrieved</param>
  176. /// <returns>True if the id was parseable, false otherwise</returns>
  177. public bool Get(string id, Object sender, AssetRetrieved handler)
  178. {
  179. if (String.IsNullOrEmpty(m_serverUrl))
  180. {
  181. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  182. throw new InvalidOperationException();
  183. }
  184. // Cache fetch
  185. if (m_cache != null)
  186. {
  187. AssetBase asset = m_cache.Get(id);
  188. if (asset != null)
  189. {
  190. handler(id, sender, asset);
  191. return true;
  192. }
  193. }
  194. Util.FireAndForget(
  195. delegate(object o)
  196. {
  197. AssetBase asset = SimianGetOperation(id);
  198. handler(id, sender, asset);
  199. }, null, "SimianAssetServiceConnector.GetFromService"
  200. );
  201. return true;
  202. }
  203. public bool[] AssetsExist(string[] ids)
  204. {
  205. if (String.IsNullOrEmpty(m_serverUrl))
  206. {
  207. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  208. throw new InvalidOperationException();
  209. }
  210. bool[] exist = new bool[ids.Length];
  211. for (int i = 0; i < ids.Length; i++)
  212. {
  213. AssetMetadata metadata = GetMetadata(ids[i]);
  214. if (metadata != null)
  215. exist[i] = true;
  216. }
  217. return exist;
  218. }
  219. /// <summary>
  220. /// Creates a new asset
  221. /// </summary>
  222. /// Returns a random ID if none is passed into it
  223. /// <param name="asset"></param>
  224. /// <returns></returns>
  225. public string Store(AssetBase asset)
  226. {
  227. if (String.IsNullOrEmpty(m_serverUrl))
  228. {
  229. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  230. throw new InvalidOperationException();
  231. }
  232. bool storedInCache = false;
  233. // AssetID handling
  234. if (String.IsNullOrEmpty(asset.ID) || asset.ID == ZeroID)
  235. {
  236. asset.FullID = UUID.Random();
  237. asset.ID = asset.FullID.ToString();
  238. }
  239. // Cache handling
  240. if (m_cache != null)
  241. {
  242. m_cache.Cache(asset);
  243. storedInCache = true;
  244. }
  245. // Local asset handling
  246. if (asset.Local)
  247. {
  248. if (!storedInCache)
  249. {
  250. m_log.Error("Cannot store local " + asset.Metadata.ContentType + " asset without an asset cache");
  251. asset.ID = null;
  252. asset.FullID = UUID.Zero;
  253. }
  254. return asset.ID;
  255. }
  256. return SimianStoreOperation(asset);
  257. }
  258. /// <summary>
  259. /// Update an asset's content
  260. /// </summary>
  261. /// Attachments and bare scripts need this!!
  262. /// <param name="id"> </param>
  263. /// <param name="data"></param>
  264. /// <returns></returns>
  265. public bool UpdateContent(string id, byte[] data)
  266. {
  267. if (String.IsNullOrEmpty(m_serverUrl))
  268. {
  269. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  270. throw new InvalidOperationException();
  271. }
  272. AssetBase asset = Get(id);
  273. if (asset == null)
  274. {
  275. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to fetch asset {0} for updating", id);
  276. return false;
  277. }
  278. asset.Data = data;
  279. string result = Store(asset);
  280. return !String.IsNullOrEmpty(result);
  281. }
  282. /// <summary>
  283. /// Delete an asset
  284. /// </summary>
  285. /// <param name="id"></param>
  286. /// <returns></returns>
  287. public bool Delete(string id)
  288. {
  289. if (String.IsNullOrEmpty(m_serverUrl))
  290. {
  291. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  292. throw new InvalidOperationException();
  293. }
  294. if (m_cache != null)
  295. m_cache.Expire(id);
  296. return SimianDeleteOperation(id);
  297. }
  298. #endregion IAssetService
  299. #region SimianOperations
  300. /// <summary>
  301. /// Invokes the xRemoveAsset operation on the simian server to delete an asset
  302. /// </summary>
  303. /// <param name="id"></param>
  304. /// <returns></returns>
  305. private bool SimianDeleteOperation(string id)
  306. {
  307. try
  308. {
  309. NameValueCollection requestArgs = new NameValueCollection
  310. {
  311. { "RequestMethod", "xRemoveAsset" },
  312. { "AssetID", id }
  313. };
  314. OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
  315. if (! response["Success"].AsBoolean())
  316. {
  317. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to delete asset; {0}",response["Message"].AsString());
  318. return false;
  319. }
  320. return true;
  321. }
  322. catch (Exception ex)
  323. {
  324. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to delete asset {0}; {1}", id, ex.Message);
  325. }
  326. return false;
  327. }
  328. /// <summary>
  329. /// Invokes the xAddAsset operation on the simian server to create or update an asset
  330. /// </summary>
  331. /// <param name="id"></param>
  332. /// <returns></returns>
  333. private string SimianStoreOperation(AssetBase asset)
  334. {
  335. try
  336. {
  337. NameValueCollection requestArgs = new NameValueCollection
  338. {
  339. { "RequestMethod", "xAddAsset" },
  340. { "ContentType", asset.Metadata.ContentType },
  341. { "EncodedData", Convert.ToBase64String(asset.Data) },
  342. { "AssetID", asset.FullID.ToString() },
  343. { "CreatorID", asset.Metadata.CreatorID },
  344. { "Temporary", asset.Temporary ? "1" : "0" },
  345. { "Name", asset.Name }
  346. };
  347. OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
  348. if (! response["Success"].AsBoolean())
  349. {
  350. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR] failed to store asset; {0}",response["Message"].AsString());
  351. return null;
  352. }
  353. // asset.ID is always set before calling this function
  354. return asset.ID;
  355. }
  356. catch (Exception ex)
  357. {
  358. m_log.ErrorFormat("[SIMIAN ASSET CONNECTOR] failed to store asset; {0}",ex.Message);
  359. }
  360. return null;
  361. }
  362. /// <summary>
  363. /// Invokes the xGetAsset operation on the simian server to get data associated with an asset
  364. /// </summary>
  365. /// <param name="id"></param>
  366. /// <returns></returns>
  367. private AssetBase SimianGetOperation(string id)
  368. {
  369. try
  370. {
  371. NameValueCollection requestArgs = new NameValueCollection
  372. {
  373. { "RequestMethod", "xGetAsset" },
  374. { "ID", id }
  375. };
  376. OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
  377. if (! response["Success"].AsBoolean())
  378. {
  379. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR] Failed to get asset; {0}",response["Message"].AsString());
  380. return null;
  381. }
  382. AssetBase asset = new AssetBase();
  383. asset.ID = id;
  384. asset.Name = String.Empty;
  385. asset.Metadata.ContentType = response["ContentType"].AsString(); // this will also set the asset Type property
  386. asset.CreatorID = response["CreatorID"].AsString();
  387. asset.Data = System.Convert.FromBase64String(response["EncodedData"].AsString());
  388. asset.Local = false;
  389. asset.Temporary = response["Temporary"];
  390. return asset;
  391. }
  392. catch (Exception ex)
  393. {
  394. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to retrieve asset {0}; {1}", id, ex.Message);
  395. }
  396. return null;
  397. }
  398. /// <summary>
  399. /// Invokes the xGetAssetMetadata operation on the simian server to retrieve metadata for an asset
  400. /// This operation is generally used to determine if an asset exists in the database
  401. /// </summary>
  402. /// <param name="id"></param>
  403. /// <returns></returns>
  404. private AssetMetadata SimianGetMetadataOperation(string id)
  405. {
  406. try
  407. {
  408. NameValueCollection requestArgs = new NameValueCollection
  409. {
  410. { "RequestMethod", "xGetAssetMetadata" },
  411. { "ID", id }
  412. };
  413. OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
  414. if (! response["Success"].AsBoolean())
  415. {
  416. // this is not really an error, this call is used to test existence
  417. // m_log.DebugFormat("[SIMIAN ASSET CONNECTOR] Failed to get asset metadata; {0}",response["Message"].AsString());
  418. return null;
  419. }
  420. AssetMetadata metadata = new AssetMetadata();
  421. metadata.ID = id;
  422. metadata.ContentType = response["ContentType"].AsString();
  423. metadata.CreatorID = response["CreatorID"].AsString();
  424. metadata.Local = false;
  425. metadata.Temporary = response["Temporary"];
  426. string lastModifiedStr = response["Last-Modified"].AsString();
  427. if (! String.IsNullOrEmpty(lastModifiedStr))
  428. {
  429. DateTime lastModified;
  430. if (DateTime.TryParse(lastModifiedStr, out lastModified))
  431. metadata.CreationDate = lastModified;
  432. }
  433. return metadata;
  434. }
  435. catch (Exception ex)
  436. {
  437. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to get asset metadata; {0}", ex.Message);
  438. }
  439. return null;
  440. }
  441. #endregion
  442. // private AssetMetadata GetRemoteMetadata(string id)
  443. // {
  444. // Uri url;
  445. // AssetMetadata metadata = null;
  446. // // Determine if id is an absolute URL or a grid-relative UUID
  447. // if (!Uri.TryCreate(id, UriKind.Absolute, out url))
  448. // url = new Uri(m_serverUrl + id);
  449. // try
  450. // {
  451. // HttpWebRequest request = UntrustedHttpWebRequest.Create(url);
  452. // request.Method = "HEAD";
  453. // using (WebResponse response = request.GetResponse())
  454. // {
  455. // using (Stream responseStream = response.GetResponseStream())
  456. // {
  457. // // Create the metadata object
  458. // metadata = new AssetMetadata();
  459. // metadata.ContentType = response.ContentType;
  460. // metadata.ID = id;
  461. // UUID uuid;
  462. // if (UUID.TryParse(id, out uuid))
  463. // metadata.FullID = uuid;
  464. // string lastModifiedStr = response.Headers.Get("Last-Modified");
  465. // if (!String.IsNullOrEmpty(lastModifiedStr))
  466. // {
  467. // DateTime lastModified;
  468. // if (DateTime.TryParse(lastModifiedStr, out lastModified))
  469. // metadata.CreationDate = lastModified;
  470. // }
  471. // }
  472. // }
  473. // }
  474. // catch (Exception ex)
  475. // {
  476. // m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset HEAD from " + url + " failed: " + ex.Message);
  477. // }
  478. // return metadata;
  479. // }
  480. // private AssetBase GetRemote(string id)
  481. // {
  482. // AssetBase asset = null;
  483. // Uri url;
  484. // // Determine if id is an absolute URL or a grid-relative UUID
  485. // if (!Uri.TryCreate(id, UriKind.Absolute, out url))
  486. // url = new Uri(m_serverUrl + id);
  487. // try
  488. // {
  489. // HttpWebRequest request = UntrustedHttpWebRequest.Create(url);
  490. // using (WebResponse response = request.GetResponse())
  491. // {
  492. // using (Stream responseStream = response.GetResponseStream())
  493. // {
  494. // string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty;
  495. // // Create the asset object
  496. // asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID);
  497. // UUID assetID;
  498. // if (UUID.TryParse(id, out assetID))
  499. // asset.FullID = assetID;
  500. // // Grab the asset data from the response stream
  501. // using (MemoryStream stream = new MemoryStream())
  502. // {
  503. // responseStream.CopyStream(stream, Int32.MaxValue);
  504. // asset.Data = stream.ToArray();
  505. // }
  506. // }
  507. // }
  508. // // Cache store
  509. // if (m_cache != null && asset != null)
  510. // m_cache.Cache(asset);
  511. // return asset;
  512. // }
  513. // catch (Exception ex)
  514. // {
  515. // m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message);
  516. // return null;
  517. // }
  518. // }
  519. // private string StoreRemote(AssetBase asset)
  520. // {
  521. // // Distinguish public and private assets
  522. // bool isPublic = true;
  523. // switch ((AssetType)asset.Type)
  524. // {
  525. // case AssetType.CallingCard:
  526. // case AssetType.Gesture:
  527. // case AssetType.LSLBytecode:
  528. // case AssetType.LSLText:
  529. // isPublic = false;
  530. // break;
  531. // }
  532. // string errorMessage = null;
  533. // // Build the remote storage request
  534. // List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>()
  535. // {
  536. // new MultipartForm.Parameter("AssetID", asset.FullID.ToString()),
  537. // new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID),
  538. // new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"),
  539. // new MultipartForm.Parameter("Public", isPublic ? "1" : "0"),
  540. // new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data)
  541. // };
  542. // // Make the remote storage request
  543. // try
  544. // {
  545. // // Simian does not require the asset ID to be in the URL because it's in the post data.
  546. // // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs
  547. // HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString());
  548. // using (HttpWebResponse response = MultipartForm.Post(request, postParameters))
  549. // {
  550. // using (Stream responseStream = response.GetResponseStream())
  551. // {
  552. // string responseStr = null;
  553. // try
  554. // {
  555. // responseStr = responseStream.GetStreamString();
  556. // OSD responseOSD = OSDParser.Deserialize(responseStr);
  557. // if (responseOSD.Type == OSDType.Map)
  558. // {
  559. // OSDMap responseMap = (OSDMap)responseOSD;
  560. // if (responseMap["Success"].AsBoolean())
  561. // return asset.ID;
  562. // else
  563. // errorMessage = "Upload failed: " + responseMap["Message"].AsString();
  564. // }
  565. // else
  566. // {
  567. // errorMessage = "Response format was invalid:\n" + responseStr;
  568. // }
  569. // }
  570. // catch (Exception ex)
  571. // {
  572. // if (!String.IsNullOrEmpty(responseStr))
  573. // errorMessage = "Failed to parse the response:\n" + responseStr;
  574. // else
  575. // errorMessage = "Failed to retrieve the response: " + ex.Message;
  576. // }
  577. // }
  578. // }
  579. // }
  580. // catch (WebException ex)
  581. // {
  582. // errorMessage = ex.Message;
  583. // }
  584. // m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}",
  585. // asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage);
  586. // return null;
  587. // }
  588. }
  589. }