aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
diff options
context:
space:
mode:
authorDr Scofield2008-07-25 09:56:35 +0000
committerDr Scofield2008-07-25 09:56:35 +0000
commit7025a8040e06250d73c295aa641969d7189474d8 (patch)
tree87515da33453c530bd18b57c81809d25f59afeac /OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
parentAdd casts from integer to float. Fix issue 1822. (diff)
downloadopensim-SC_OLD-7025a8040e06250d73c295aa641969d7189474d8.zip
opensim-SC_OLD-7025a8040e06250d73c295aa641969d7189474d8.tar.gz
opensim-SC_OLD-7025a8040e06250d73c295aa641969d7189474d8.tar.bz2
opensim-SC_OLD-7025a8040e06250d73c295aa641969d7189474d8.tar.xz
From: awebb
Further improvements to the REST handlers.
Diffstat (limited to 'OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs')
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs295
1 files changed, 199 insertions, 96 deletions
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
index 65603c5..5de2cb4 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
31using System.IO; 31using System.IO;
32using System.Threading; 32using System.Threading;
33using System.Xml; 33using System.Xml;
34using OpenJPEGNet;
34using OpenSim.Framework; 35using OpenSim.Framework;
35using OpenSim.Framework.Servers; 36using OpenSim.Framework.Servers;
36using OpenSim.Framework.Communications; 37using OpenSim.Framework.Communications;
@@ -44,35 +45,33 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
44 public class RestInventoryServices : IRest 45 public class RestInventoryServices : IRest
45 { 46 {
46 47
47 private string key = "inventory";
48 private bool enabled = false; 48 private bool enabled = false;
49 private string qPrefix = "inventory"; 49 private string qPrefix = "inventory";
50 50
51 // A simple constructor is used to handle any once-only 51 /// <summary>
52 // initialization of working classes. 52 /// A simple constructor is used to handle any once-only
53 /// initialization of working classes.
54 /// </summary>
53 55
54 public RestInventoryServices(RestHandler p_rest) 56 public RestInventoryServices()
55 { 57 {
56 58
57 Rest.Log.InfoFormat("{0} Inventory services initializing", MsgId); 59 Rest.Log.InfoFormat("{0} Inventory services initializing", MsgId);
58 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); 60 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
59 61
60 // Update to reflect the full prefix if not absolute 62 // If a relative path was specified for the handler's domain,
63 // add the standard prefix to make it absolute, e.g. /admin
61 64
62 if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) 65 if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
63 { 66 {
64 qPrefix = Rest.Prefix + Rest.UrlPathSeparator + qPrefix; 67 qPrefix = Rest.Prefix + Rest.UrlPathSeparator + qPrefix;
65 } 68 }
66 69
67 // Authentication domain 70 // Register interface using the absolute URI.
68
69 Rest.Domains.Add(key, Rest.Config.GetString("inventory-domain",qPrefix));
70
71 // Register interface
72 71
73 Rest.Plugin.AddPathHandler(DoInventory,qPrefix,Allocate); 72 Rest.Plugin.AddPathHandler(DoInventory,qPrefix,Allocate);
74 73
75 // Activate 74 // Activate if everything went OK
76 75
77 enabled = true; 76 enabled = true;
78 77
@@ -80,16 +79,20 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
80 79
81 } 80 }
82 81
83 // Post-construction, pre-enabled initialization opportunity 82 /// <summary>
84 // Not currently exploited. 83 /// Post-construction, pre-enabled initialization opportunity
84 /// Not currently exploited.
85 /// </summary>
85 86
86 public void Initialize() 87 public void Initialize()
87 { 88 {
88 } 89 }
89 90
90 // Called by the plug-in to halt REST processing. Local processing is 91 /// <summary>
91 // disabled, and control blocks until all current processing has 92 /// Called by the plug-in to halt REST processing. Local processing is
92 // completed. No new processing will be started 93 /// disabled, and control blocks until all current processing has
94 /// completed. No new processing will be started
95 /// </summary>
93 96
94 public void Close() 97 public void Close()
95 { 98 {
@@ -97,7 +100,10 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
97 Rest.Log.InfoFormat("{0} Inventory services closing down", MsgId); 100 Rest.Log.InfoFormat("{0} Inventory services closing down", MsgId);
98 } 101 }
99 102
100 // Convenient properties 103 /// <summary>
104 /// This property is declared locally because it is used a lot and
105 /// brevity is nice.
106 /// </summary>
101 107
102 internal string MsgId 108 internal string MsgId
103 { 109 {
@@ -106,15 +112,22 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
106 112
107 #region Interface 113 #region Interface
108 114
115 /// <summary>
116 /// The plugin (RestHandler) calls this method to allocate the request
117 /// state carrier for a new request. It is destroyed when the request
118 /// completes. All request-instance specific state is kept here. This
119 /// is registered when this service provider is registered.
120 /// </summary>
121
109 private RequestData Allocate(OSHttpRequest request, OSHttpResponse response) 122 private RequestData Allocate(OSHttpRequest request, OSHttpResponse response)
110 { 123 {
111 return (RequestData) new InventoryRequestData(request, response, qPrefix); 124 return (RequestData) new InventoryRequestData(request, response, qPrefix);
112 } 125 }
113 126
114 /// <summary> 127 /// <summary>
115 /// This method is registered with the handler when this class is 128 /// This method is registered with the handler when this service provider
116 /// initialized. It is called whenever the URI includes this handler's 129 /// is initialized. It is called whenever the plug-in identifies this service
117 /// prefix string. 130 /// provider as the best match.
118 /// It handles all aspects of inventory REST processing. 131 /// It handles all aspects of inventory REST processing.
119 /// </summary> 132 /// </summary>
120 133
@@ -125,7 +138,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
125 138
126 Rest.Log.DebugFormat("{0} DoInventory ENTRY", MsgId); 139 Rest.Log.DebugFormat("{0} DoInventory ENTRY", MsgId);
127 140
128 // We're disabled 141 // If we're disabled, do nothing.
142
129 if (!enabled) 143 if (!enabled)
130 { 144 {
131 return; 145 return;
@@ -169,23 +183,32 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
169 183
170 Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName); 184 Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName);
171 185
172 // We can only get here if we're authorized 186 /// <remarks>
173 // 187 /// We can only get here if we are authorized
174 // The requestor may have specified an LLUUID or 188 ///
175 // a conjoined FirstNameLastName string. We'll 189 /// The requestor may have specified an LLUUID or
176 // try both. If we fail with the first, UUID, 190 /// a conjoined FirstName LastName string. We'll
177 // attempt, then we need two nodes to construct 191 /// try both. If we fail with the first, UUID,
178 // a valid avatar name. 192 /// attempt, we try the other. As an example, the
193 /// URI for a valid inventory request might be:
194 ///
195 /// http://<host>:<port>/admin/inventory/Arthur Dent
196 ///
197 /// Indicating that this is an inventory request for
198 /// an avatar named Arthur Dent. This is ALl that is
199 /// required to designate a GET for an entire
200 /// inventory.
201 /// </remarks>
179 202
180 // Do we have at least a user agent name? 203 // Do we have at least a user agent name?
181 204
182 if (rdata.parameters.Length < 1) 205 if (rdata.parameters.Length < 1)
183 { 206 {
184 Rest.Log.WarnFormat("{0} Inventory: No user agent identifier specified", MsgId); 207 Rest.Log.WarnFormat("{0} Inventory: No user agent identifier specified", MsgId);
185 rdata.Fail(Rest.HttpStatusCodeBadRequest, Rest.HttpStatusDescBadRequest); 208 rdata.Fail(Rest.HttpStatusCodeBadRequest, Rest.HttpStatusDescBadRequest+": No user identity specified");
186 } 209 }
187 210
188 // The next parameter MUST be the agent identification, either an LLUUID 211 // The first parameter MUST be the agent identification, either an LLUUID
189 // or a space-separated First-name Last-Name specification. 212 // or a space-separated First-name Last-Name specification.
190 213
191 try 214 try
@@ -205,10 +228,13 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
205 else 228 else
206 { 229 {
207 Rest.Log.DebugFormat("{0} A Valid UUID or both first and last names must be specified", MsgId); 230 Rest.Log.DebugFormat("{0} A Valid UUID or both first and last names must be specified", MsgId);
208 rdata.Fail(Rest.HttpStatusCodeBadRequest, Rest.HttpStatusDescBadRequest); 231 rdata.Fail(Rest.HttpStatusCodeBadRequest, Rest.HttpStatusDescBadRequest+": invalid user identity");
209 } 232 }
210 } 233 }
211 234
235 // If the user rpofile is null then either the server is broken, or the
236 // user is not known. We always assume the latter case.
237
212 if (rdata.userProfile != null) 238 if (rdata.userProfile != null)
213 { 239 {
214 Rest.Log.DebugFormat("{0} Profile obtained for agent {1} {2}", 240 Rest.Log.DebugFormat("{0} Profile obtained for agent {1} {2}",
@@ -217,11 +243,20 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
217 else 243 else
218 { 244 {
219 Rest.Log.DebugFormat("{0} No profile for {1}", MsgId, rdata.path); 245 Rest.Log.DebugFormat("{0} No profile for {1}", MsgId, rdata.path);
220 rdata.Fail(Rest.HttpStatusCodeNotFound,Rest.HttpStatusDescNotFound); 246 rdata.Fail(Rest.HttpStatusCodeNotFound,Rest.HttpStatusDescNotFound+": unrecognized user identity");
221 } 247 }
222 248
223 // If we get to here, then we have successfully obtained an inventory 249 // If we get to here, then we have effectively validated the user's
224 // for the specified user. 250 // identity. Now we need to get the inventory. If the server does not
251 // have the inventory, we reject the request with an appropriate explanation.
252 //
253 // Note that inventory retrieval is an asynchronous event, we use the rdata
254 // class instance as the basis for our synchronization.
255 //
256 // TODO
257 // If something went wrong in inventory processing the thread could stall here
258 // indefinitely. There should be a watchdog timer to fail the request if the
259 // response is not recieved in a timely fashion.
225 260
226 rdata.uuid = rdata.userProfile.ID; 261 rdata.uuid = rdata.userProfile.ID;
227 262
@@ -250,7 +285,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
250 { 285 {
251 Rest.Log.DebugFormat("{0} Inventory is not available [1] for agent {1} {2}", 286 Rest.Log.DebugFormat("{0} Inventory is not available [1] for agent {1} {2}",
252 MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); 287 MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
253 rdata.Fail(Rest.HttpStatusCodeServerError,Rest.HttpStatusDescServerError); 288 rdata.Fail(Rest.HttpStatusCodeServerError,Rest.HttpStatusDescServerError+": inventory retrieval failed");
254 } 289 }
255 290
256 } 291 }
@@ -258,7 +293,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
258 { 293 {
259 Rest.Log.DebugFormat("{0} Inventory is not available for agent [3] {1} {2}", 294 Rest.Log.DebugFormat("{0} Inventory is not available for agent [3] {1} {2}",
260 MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); 295 MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
261 rdata.Fail(Rest.HttpStatusCodeNotFound,Rest.HttpStatusDescNotFound); 296 rdata.Fail(Rest.HttpStatusCodeNotFound,Rest.HttpStatusDescNotFound+": no inventory for user");
262 } 297 }
263 298
264 // If we get here, then we have successfully retrieved the user's information 299 // If we get here, then we have successfully retrieved the user's information
@@ -292,7 +327,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
292 Rest.Log.DebugFormat("{0} Method {1} not supported for {2}", 327 Rest.Log.DebugFormat("{0} Method {1} not supported for {2}",
293 MsgId, rdata.method, rdata.path); 328 MsgId, rdata.method, rdata.path);
294 rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed, 329 rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed,
295 Rest.HttpStatusDescMethodNotAllowed); 330 Rest.HttpStatusDescMethodNotAllowed+": "+rdata.method+" not supported");
296 break; 331 break;
297 } 332 }
298 333
@@ -315,10 +350,19 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
315 350
316 rdata.writer.WriteStartElement(String.Empty,"Inventory",String.Empty); 351 rdata.writer.WriteStartElement(String.Empty,"Inventory",String.Empty);
317 352
353 // If there was only one parameter, then the entire
354 // inventory is being requested.
355
318 if (rdata.parameters.Length == 1) 356 if (rdata.parameters.Length == 1)
319 { 357 {
320 formatInventory(rdata, rdata.root, String.Empty); 358 formatInventory(rdata, rdata.root, String.Empty);
321 } 359 }
360
361 // If there are additional parameters, then these represent
362 // a path relative to the root of the inventory. This path
363 // must be traversed before we format the sub-tree thus
364 // identified.
365
322 else 366 else
323 { 367 {
324 traverseInventory(rdata, rdata.root, 1); 368 traverseInventory(rdata, rdata.root, 1);
@@ -332,33 +376,35 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
332 } 376 }
333 377
334 /// <summary> 378 /// <summary>
335 /// In the case of the inventory, and probably much else 379 /// In the case of the inventory, and probably in general,
336 /// the distinction between PUT and POST is not always 380 /// the distinction between PUT and POST is not always
337 /// easy to discern. Adding a directory can be viewed as 381 /// easy to discern. Adding a directory can be viewed as
338 /// an addition, or as a modification to the inventory as 382 /// an addition, or as a modification to the inventory as
339 /// a whole. 383 /// a whole. This is exacerbated by a lack of consistency
384 /// across different implementations.
385 ///
386 /// For OpenSim POST is an update and PUT is an addition.
340 /// 387 ///
341 /// The best distinction may be the relationship between 388 /// The best way to exaplain the distinction is to
342 /// the entity and the URI. If we view POST as an update, 389 /// consider the relationship between the URI and the
343 /// then the enity represents a replacement for the 390 /// entity in question. For POST, the URI identifies the
344 /// element named by the URI. If the operation is PUT, 391 /// entity to be modified or replaced.
345 /// then the URI describes the context into which the 392 /// If the operation is PUT,then the URI describes the
346 /// entity will be added. 393 /// context into which the new entity will be added.
347 /// 394 ///
348 /// As an example, suppose the URI contains: 395 /// As an example, suppose the URI contains:
349 /// /admin/inventory/Clothing 396 /// /admin/inventory/Clothing
350 /// Suppose the entity represents a Folder, called
351 /// "Clothes".
352 ///
353 /// A POST request will result in the replacement of
354 /// "Clothing" by "Clothes". Whereas a PUT request
355 /// would add Clothes as a sub-directory of Clothing.
356 /// 397 ///
357 /// This is the model followed by this implementation. 398 /// A POST request will result in some modification of
399 /// the folder or item named "Clothing". Whereas a PUT
400 /// request will add some new information into the
401 /// content identified by Clothing. It follows from this
402 /// that for PUT, the element identified by the URI must
403 /// be a folder.
358 /// </summary> 404 /// </summary>
359 405
360 /// <summary> 406 /// <summary>
361 /// PUT adds new information to the inventory at the 407 /// PUT adds new information to the inventory in the
362 /// context identified by the URI. 408 /// context identified by the URI.
363 /// </summary> 409 /// </summary>
364 410
@@ -376,7 +422,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
376 // exception. 422 // exception.
377 423
378 // It follows that we can only add information if the URI 424 // It follows that we can only add information if the URI
379 // has identified a folder. So only folder is supported 425 // has identified a folder. So only a type of folder is supported
380 // in this case. 426 // in this case.
381 427
382 if (typeof(InventoryFolderBase) == InventoryNode.GetType() || 428 if (typeof(InventoryFolderBase) == InventoryNode.GetType() ||
@@ -390,14 +436,19 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
390 Rest.Log.DebugFormat("{0} {1}: Resource(s) will be added to folder {2}", 436 Rest.Log.DebugFormat("{0} {1}: Resource(s) will be added to folder {2}",
391 MsgId, rdata.method, rdata.path); 437 MsgId, rdata.method, rdata.path);
392 438
393 // Reconstitute inventory sub-tree from the XML supplied in the entity. 439 // Reconstitute the inventory sub-tree from the XML supplied in the entity.
394 // This is a stand-alone inventory subtree, not yet integrated into the 440 // The result is a stand-alone inventory subtree, not yet integrated into the
395 // existing tree. 441 // existing tree. An inventory collection consists of three components:
442 // [1] A (possibly empty) set of folders.
443 // [2] A (possibly empty) set of items.
444 // [3] A (possibly empty) set of assets.
445 // If all of these are empty, then the PUT is a harmless no-operation.
396 446
397 XmlInventoryCollection entity = ReconstituteEntity(rdata); 447 XmlInventoryCollection entity = ReconstituteEntity(rdata);
398 448
399 // Inlined assest included in entity. If anything fails, 449 // Inlined assets can be included in entity. These must be incorporated into
400 // return failure to requestor. 450 // the asset database before we attempt to update the inventory. If anything
451 // fails, return a failure to requestor.
401 452
402 if (entity.Assets.Count > 0) 453 if (entity.Assets.Count > 0)
403 { 454 {
@@ -410,10 +461,12 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
410 Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}", 461 Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}",
411 MsgId, asset.ID, asset.Type, asset.Name); 462 MsgId, asset.ID, asset.Type, asset.Name);
412 Rest.AssetServices.AddAsset(asset); 463 Rest.AssetServices.AddAsset(asset);
464
413 if (Rest.DumpAsset) 465 if (Rest.DumpAsset)
414 { 466 {
415 Rest.Dump(asset.Data); 467 Rest.Dump(asset.Data);
416 } 468 }
469
417 } 470 }
418 471
419 } 472 }
@@ -424,11 +477,11 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
424 foreach (InventoryFolderBase folder in entity.Folders) 477 foreach (InventoryFolderBase folder in entity.Folders)
425 { 478 {
426 479
427 InventoryFolderBase found = null; 480 InventoryFolderBase found;
428 481
429 // If the parentID is zero, then this is going 482 // If the parentID is zero, then this folder is going
430 // into the root identified by the URI. The requestor 483 // into the root folder identified by the URI. The requestor
431 // may have already set the parent ID correctly, in which 484 // may have already set the parent ID explicitly, in which
432 // case we don't have to do it here. 485 // case we don't have to do it here.
433 486
434 if (folder.ParentID == LLUUID.Zero) 487 if (folder.ParentID == LLUUID.Zero)
@@ -437,7 +490,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
437 } 490 }
438 491
439 // Search the existing inventory for an existing entry. If 492 // Search the existing inventory for an existing entry. If
440 // we have once, we need to decide if it has really changed. 493 // we have one, we need to decide if it has really changed.
441 // It could just be present as (unnecessary) context, and we 494 // It could just be present as (unnecessary) context, and we
442 // don't want to waste time updating the database in that 495 // don't want to waste time updating the database in that
443 // case, OR, it could be being moved from another location 496 // case, OR, it could be being moved from another location
@@ -451,6 +504,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
451 if (xf.ID == folder.ID) 504 if (xf.ID == folder.ID)
452 { 505 {
453 found = xf; 506 found = xf;
507 break;
454 } 508 }
455 } 509 }
456 510
@@ -492,6 +546,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
492 if (xi.ID == item.ID) 546 if (xi.ID == item.ID)
493 { 547 {
494 found = xi; 548 found = xi;
549 break;
495 } 550 }
496 } 551 }
497 552
@@ -516,7 +571,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
516 Rest.Log.DebugFormat("{0} {1}: Resource {2} is not a valid context: {3}", 571 Rest.Log.DebugFormat("{0} {1}: Resource {2} is not a valid context: {3}",
517 MsgId, rdata.method, rdata.path, InventoryNode.GetType()); 572 MsgId, rdata.method, rdata.path, InventoryNode.GetType());
518 rdata.Fail(Rest.HttpStatusCodeBadRequest, 573 rdata.Fail(Rest.HttpStatusCodeBadRequest,
519 Rest.HttpStatusDescBadRequest); 574 Rest.HttpStatusDescBadRequest+": invalid resource context");
520 } 575 }
521 576
522 rdata.Complete(); 577 rdata.Complete();
@@ -531,7 +586,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
531 /// [1] It identifies the user whose inventory is to be 586 /// [1] It identifies the user whose inventory is to be
532 /// processed. 587 /// processed.
533 /// [2] It optionally specifies a subtree of the inventory 588 /// [2] It optionally specifies a subtree of the inventory
534 /// that is to be used to resolve an relative subtree 589 /// that is to be used to resolve any relative subtree
535 /// specifications in the entity. If nothing is specified 590 /// specifications in the entity. If nothing is specified
536 /// then the whole inventory is implied. 591 /// then the whole inventory is implied.
537 /// Please note that the subtree specified by the URI is only relevant 592 /// Please note that the subtree specified by the URI is only relevant
@@ -540,7 +595,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
540 /// elements will be implicitly referenced within the context identified 595 /// elements will be implicitly referenced within the context identified
541 /// by the URI. 596 /// by the URI.
542 /// If an element in the entity specifies an explicit parent folder, then 597 /// If an element in the entity specifies an explicit parent folder, then
543 /// that parent is effective, regardless of nay value specified in the 598 /// that parent is effective, regardless of any value specified in the
544 /// URI. If the parent does not exist, then the element, and any dependent 599 /// URI. If the parent does not exist, then the element, and any dependent
545 /// elements, are ignored. This case is actually detected and handled 600 /// elements, are ignored. This case is actually detected and handled
546 /// during the reconstitution process. 601 /// during the reconstitution process.
@@ -555,33 +610,54 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
555 610
556 Object InventoryNode = getInventoryNode(rdata, rdata.root, 1); 611 Object InventoryNode = getInventoryNode(rdata, rdata.root, 1);
557 612
558 // As long as we have a context, then we have something 613 // As long as we have a node, then we have something
559 // meaningful to do, unlike PUT. So reconstitute the 614 // meaningful to do, unlike PUT. So we reconstitute the
560 // subtree before doing anything else. Note that we 615 // subtree before doing anything else. Note that we
561 // etiher got a context or we threw an exception. 616 // etiher got a valid node or we threw an exception.
562 617
563 XmlInventoryCollection entity = ReconstituteEntity(rdata); 618 XmlInventoryCollection entity = ReconstituteEntity(rdata);
564 619
565 // Incorporate any inlined assets first 620 // Incorporate any inlined assets first. Any failures
621 // will terminate the request.
566 622
567 if (entity.Assets.Count != 0) 623 if (entity.Assets.Count > 0)
568 { 624 {
625 Rest.Log.DebugFormat("{0} Adding {1} assets to server",
626 MsgId, entity.Assets.Count);
627
569 foreach (AssetBase asset in entity.Assets) 628 foreach (AssetBase asset in entity.Assets)
570 { 629 {
571 // Asset was validated during the collection 630 Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}",
572 // process 631 MsgId, asset.ID, asset.Type, asset.Name);
632
633 // The asset was validated during the collection process
634
573 Rest.AssetServices.AddAsset(asset); 635 Rest.AssetServices.AddAsset(asset);
636
637 if (Rest.DumpAsset)
638 {
639 Rest.Dump(asset.Data);
640 }
641
574 } 642 }
575 } 643 }
576 644
577 /// <summary> 645 /// <summary>
578 /// URI specifies a folder to be updated. 646 /// The URI specifies either a folder or an item to be updated.
579 /// </summary> 647 /// </summary>
580 /// <remarks> 648 /// <remarks>
581 /// The root node in the entity must have the same 649 /// The root node in the entity will replace the node identified
582 /// UUID as the node identified by the URI. The 650 /// by the URI. This means the parent will remain the same, but
583 /// parentID if different indicates that the updated 651 /// any or all attributes associated with the named element
584 /// folder is actually being moved too. 652 /// will change.
653 ///
654 /// If the inventory collection contains an element with a zero
655 /// parent ID, then this is taken to be the replacement for the
656 /// named node. The collection MAY also specify an explicit
657 /// parent ID, in this case it MAY identify the same parent as
658 /// the current node, or it MAY specify a different parent,
659 /// indicating that the folder is being moved in addition to any
660 /// other modifications being made.
585 /// </remarks> 661 /// </remarks>
586 662
587 if (typeof(InventoryFolderBase) == InventoryNode.GetType() || 663 if (typeof(InventoryFolderBase) == InventoryNode.GetType() ||
@@ -592,7 +668,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
592 InventoryFolderBase xml = null; 668 InventoryFolderBase xml = null;
593 669
594 // Scan the set of folders in the entity collection for an 670 // Scan the set of folders in the entity collection for an
595 // entry that macthes the context folder. It is assumed that 671 // entry that matches the context folder. It is assumed that
596 // the only reliable indicator of this is a zero UUID ( using 672 // the only reliable indicator of this is a zero UUID ( using
597 // implicit context), or the parent's UUID matches that of the 673 // implicit context), or the parent's UUID matches that of the
598 // URI designated node (explicit context). We don't allow 674 // URI designated node (explicit context). We don't allow
@@ -617,14 +693,15 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
617 } 693 }
618 } 694 }
619 695
620 // More than one entry is ambiguous 696 // More than one entry is ambiguous. Other folders should be
697 // added using the PUT verb.
621 698
622 if (count > 1) 699 if (count > 1)
623 { 700 {
624 Rest.Log.DebugFormat("{0} {1}: Request for <{2}> is ambiguous", 701 Rest.Log.DebugFormat("{0} {1}: Request for <{2}> is ambiguous",
625 MsgId, rdata.method, rdata.path); 702 MsgId, rdata.method, rdata.path);
626 rdata.Fail(Rest.HttpStatusCodeBadRequest, 703 rdata.Fail(Rest.HttpStatusCodeBadRequest,
627 Rest.HttpStatusDescBadRequest); 704 Rest.HttpStatusDescBadRequest+": context is ambiguous");
628 } 705 }
629 706
630 // Exactly one entry means we ARE replacing the node 707 // Exactly one entry means we ARE replacing the node
@@ -679,7 +756,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
679 Rest.Log.DebugFormat("{0} {1}: Request should not contain any folders <{2}>", 756 Rest.Log.DebugFormat("{0} {1}: Request should not contain any folders <{2}>",
680 MsgId, rdata.method, rdata.path); 757 MsgId, rdata.method, rdata.path);
681 rdata.Fail(Rest.HttpStatusCodeBadRequest, 758 rdata.Fail(Rest.HttpStatusCodeBadRequest,
682 Rest.HttpStatusDescBadRequest); 759 Rest.HttpStatusDescBadRequest+": folder is not allowed");
683 } 760 }
684 761
685 if (entity.Items.Count > 1) 762 if (entity.Items.Count > 1)
@@ -687,7 +764,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
687 Rest.Log.DebugFormat("{0} {1}: Entity contains too many items <{2}>", 764 Rest.Log.DebugFormat("{0} {1}: Entity contains too many items <{2}>",
688 MsgId, rdata.method, rdata.path); 765 MsgId, rdata.method, rdata.path);
689 rdata.Fail(Rest.HttpStatusCodeBadRequest, 766 rdata.Fail(Rest.HttpStatusCodeBadRequest,
690 Rest.HttpStatusDescBadRequest); 767 Rest.HttpStatusDescBadRequest+": too may items");
691 } 768 }
692 769
693 xml = entity.Items[0]; 770 xml = entity.Items[0];
@@ -854,7 +931,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
854 { 931 {
855 Rest.Log.DebugFormat("{0} {1}: Request for {2} is ambiguous", 932 Rest.Log.DebugFormat("{0} {1}: Request for {2} is ambiguous",
856 MsgId, rdata.method, rdata.path); 933 MsgId, rdata.method, rdata.path);
857 rdata.Fail(Rest.HttpStatusCodeNotFound, Rest.HttpStatusDescNotFound); 934 rdata.Fail(Rest.HttpStatusCodeNotFound, Rest.HttpStatusDescNotFound+": request is ambiguous");
858 } 935 }
859 } 936 }
860 } 937 }
@@ -863,7 +940,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
863 940
864 Rest.Log.DebugFormat("{0} {1}: Resource {2} not found", 941 Rest.Log.DebugFormat("{0} {1}: Resource {2} not found",
865 MsgId, rdata.method, rdata.path); 942 MsgId, rdata.method, rdata.path);
866 rdata.Fail(Rest.HttpStatusCodeNotFound, Rest.HttpStatusDescNotFound); 943 rdata.Fail(Rest.HttpStatusCodeNotFound, Rest.HttpStatusDescNotFound+": resource "+rdata.path+" not found");
867 944
868 return null; /* Never reached */ 945 return null; /* Never reached */
869 946
@@ -931,7 +1008,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
931 1008
932 Rest.Log.DebugFormat("{0} Inventory does not contain item/folder: <{1}>", 1009 Rest.Log.DebugFormat("{0} Inventory does not contain item/folder: <{1}>",
933 MsgId, rdata.path); 1010 MsgId, rdata.path);
934 rdata.Fail(Rest.HttpStatusCodeNotFound,Rest.HttpStatusDescNotFound); 1011 rdata.Fail(Rest.HttpStatusCodeNotFound,Rest.HttpStatusDescNotFound+": no such item/folder");
935 1012
936 } 1013 }
937 1014
@@ -1061,6 +1138,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1061 TrashCan.Version = 1; 1138 TrashCan.Version = 1;
1062 TrashCan.Type = (short) AssetType.TrashFolder; 1139 TrashCan.Type = (short) AssetType.TrashFolder;
1063 TrashCan.ParentID = f.ID; 1140 TrashCan.ParentID = f.ID;
1141 TrashCan.Owner = f.Owner;
1064 Rest.InventoryServices.AddFolder(TrashCan); 1142 Rest.InventoryServices.AddFolder(TrashCan);
1065 } 1143 }
1066 } 1144 }
@@ -1070,7 +1148,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1070 { 1148 {
1071 Rest.Log.DebugFormat("{0} No Trash Can available", MsgId); 1149 Rest.Log.DebugFormat("{0} No Trash Can available", MsgId);
1072 rdata.Fail(Rest.HttpStatusCodeServerError, 1150 rdata.Fail(Rest.HttpStatusCodeServerError,
1073 Rest.HttpStatusDescServerError); 1151 Rest.HttpStatusDescServerError+": unable to create trash can");
1074 } 1152 }
1075 1153
1076 return TrashCan; 1154 return TrashCan;
@@ -1313,7 +1391,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1313 Rest.Log.DebugFormat("{0} Folder: unrecognized attribute: {1}:{2}", 1391 Rest.Log.DebugFormat("{0} Folder: unrecognized attribute: {1}:{2}",
1314 MsgId, ic.xml.Name, ic.xml.Value); 1392 MsgId, ic.xml.Name, ic.xml.Value);
1315 ic.Fail(Rest.HttpStatusCodeBadRequest, 1393 ic.Fail(Rest.HttpStatusCodeBadRequest,
1316 Rest.HttpStatusDescBadRequest); 1394 Rest.HttpStatusDescBadRequest+": unrecognized attribute");
1317 break; 1395 break;
1318 } 1396 }
1319 } 1397 }
@@ -1349,7 +1427,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1349 Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in folder {2}", 1427 Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in folder {2}",
1350 MsgId, ic.Item.Folder, result.ID); 1428 MsgId, ic.Item.Folder, result.ID);
1351 ic.Fail(Rest.HttpStatusCodeBadRequest, 1429 ic.Fail(Rest.HttpStatusCodeBadRequest,
1352 Rest.HttpStatusDescBadRequest); 1430 Rest.HttpStatusDescBadRequest+": invalid parent");
1353 } 1431 }
1354 1432
1355 } 1433 }
@@ -1457,7 +1535,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1457 Rest.Log.DebugFormat("{0} Item: Unrecognized attribute: {1}:{2}", 1535 Rest.Log.DebugFormat("{0} Item: Unrecognized attribute: {1}:{2}",
1458 MsgId, ic.xml.Name, ic.xml.Value); 1536 MsgId, ic.xml.Name, ic.xml.Value);
1459 ic.Fail(Rest.HttpStatusCodeBadRequest, 1537 ic.Fail(Rest.HttpStatusCodeBadRequest,
1460 Rest.HttpStatusDescBadRequest); 1538 Rest.HttpStatusDescBadRequest+": unrecognized attribute");
1461 break; 1539 break;
1462 } 1540 }
1463 } 1541 }
@@ -1570,7 +1648,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1570 { 1648 {
1571 Rest.Log.DebugFormat("{0} LLUID unimbedded asset must be inline", MsgId); 1649 Rest.Log.DebugFormat("{0} LLUID unimbedded asset must be inline", MsgId);
1572 ic.Fail(Rest.HttpStatusCodeBadRequest, 1650 ic.Fail(Rest.HttpStatusCodeBadRequest,
1573 Rest.HttpStatusDescBadRequest); 1651 Rest.HttpStatusDescBadRequest+": no context for asset");
1574 } 1652 }
1575 } 1653 }
1576 1654
@@ -1691,7 +1769,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1691 { 1769 {
1692 Rest.Log.ErrorFormat("{0} Unable to parse request", MsgId); 1770 Rest.Log.ErrorFormat("{0} Unable to parse request", MsgId);
1693 ic.Fail(Rest.HttpStatusCodeBadRequest, 1771 ic.Fail(Rest.HttpStatusCodeBadRequest,
1694 Rest.HttpStatusDescBadRequest); 1772 Rest.HttpStatusDescBadRequest+": request parse error");
1695 } 1773 }
1696 1774
1697 // Every item is required to have a name (via REST anyway) 1775 // Every item is required to have a name (via REST anyway)
@@ -1700,7 +1778,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1700 { 1778 {
1701 Rest.Log.ErrorFormat("{0} An item name MUST be specified", MsgId); 1779 Rest.Log.ErrorFormat("{0} An item name MUST be specified", MsgId);
1702 ic.Fail(Rest.HttpStatusCodeBadRequest, 1780 ic.Fail(Rest.HttpStatusCodeBadRequest,
1703 Rest.HttpStatusDescBadRequest); 1781 Rest.HttpStatusDescBadRequest+": item name required");
1704 } 1782 }
1705 1783
1706 // An item MUST have an asset ID. AssetID should never be zero 1784 // An item MUST have an asset ID. AssetID should never be zero
@@ -1713,7 +1791,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1713 Rest.Log.ErrorFormat("{0} Unable to complete request", MsgId); 1791 Rest.Log.ErrorFormat("{0} Unable to complete request", MsgId);
1714 Rest.Log.InfoFormat("{0} Asset information is missing", MsgId); 1792 Rest.Log.InfoFormat("{0} Asset information is missing", MsgId);
1715 ic.Fail(Rest.HttpStatusCodeBadRequest, 1793 ic.Fail(Rest.HttpStatusCodeBadRequest,
1716 Rest.HttpStatusDescBadRequest); 1794 Rest.HttpStatusDescBadRequest+": asset information required");
1717 1795
1718 } 1796 }
1719 1797
@@ -1751,7 +1829,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1751 Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in item {2}", 1829 Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in item {2}",
1752 MsgId, ic.Item.Folder, ic.Item.ID); 1830 MsgId, ic.Item.Folder, ic.Item.ID);
1753 ic.Fail(Rest.HttpStatusCodeBadRequest, 1831 ic.Fail(Rest.HttpStatusCodeBadRequest,
1754 Rest.HttpStatusDescBadRequest); 1832 Rest.HttpStatusDescBadRequest+": parent information required");
1755 } 1833 }
1756 1834
1757 } 1835 }
@@ -1825,6 +1903,22 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1825 if (ic.Item.InvType == (int) AssetType.Unknown) 1903 if (ic.Item.InvType == (int) AssetType.Unknown)
1826 ic.Item.InvType = (int) AssetType.ImageJPEG; 1904 ic.Item.InvType = (int) AssetType.ImageJPEG;
1827 break; 1905 break;
1906 case "tga" :
1907 if (parts[parts.Length - 2].IndexOf("_texture") != -1)
1908 {
1909 if (ic.Item.AssetType == (int) AssetType.Unknown)
1910 ic.Item.AssetType = (int) AssetType.TextureTGA;
1911 if (ic.Item.InvType == (int) AssetType.Unknown)
1912 ic.Item.InvType = (int) AssetType.TextureTGA;
1913 }
1914 else
1915 {
1916 if (ic.Item.AssetType == (int) AssetType.Unknown)
1917 ic.Item.AssetType = (int) AssetType.ImageTGA;
1918 if (ic.Item.InvType == (int) AssetType.Unknown)
1919 ic.Item.InvType = (int) AssetType.ImageTGA;
1920 }
1921 break;
1828 default : 1922 default :
1829 Rest.Log.DebugFormat("{0} Type was not inferred", MsgId); 1923 Rest.Log.DebugFormat("{0} Type was not inferred", MsgId);
1830 break; 1924 break;
@@ -1832,6 +1926,15 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
1832 } 1926 }
1833 } 1927 }
1834 1928
1929 /// If this is a TGA remember the fact
1930
1931 if (ic.Item.AssetType == (int) AssetType.TextureTGA ||
1932 ic.Item.AssetType == (int) AssetType.ImageTGA)
1933 {
1934 // TODO: DO we need to convert it? Or is it enough to flag
1935 // it appropriately?
1936 }
1937
1835 ic.reset(); 1938 ic.reset();
1836 1939
1837 } 1940 }