2 /* -----------------------------------------------------------------------
3 * <copyright file="ObjectInfo.cs" company="GRNet">
5 * Copyright 2011-2012 GRNET S.A. All rights reserved.
7 * Redistribution and use in source and binary forms, with or
8 * without modification, are permitted provided that the following
11 * 1. Redistributions of source code must retain the above
12 * copyright notice, this list of conditions and the following
15 * 2. Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials
18 * provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
34 * The views and conclusions contained in the software and
35 * documentation are those of the authors and should not be
36 * interpreted as representing official policies, either expressed
37 * or implied, of GRNET S.A.
39 * -----------------------------------------------------------------------
43 using System.Collections.Generic;
44 using System.Diagnostics;
45 using System.Diagnostics.Contracts;
47 using System.Globalization;
51 using Newtonsoft.Json;
53 namespace Pithos.Interfaces
55 [DebuggerDisplay("Name {Name}")]
56 public class ObjectInfo//:DynamicObject
58 private readonly List<string> _knownContainers= new List<string>{"trash"};
59 public string Name { get; set; }
61 [JsonProperty("hash")]
62 public string ETag { get; set; }
64 //public string Hash { get; set; }
67 public string X_Object_Hash { get { return Hash; } set { Hash = value; } }
70 public string X_Object_Hash { get; set; }
72 [JsonProperty("x_object_uuid")]
73 public string UUID { get; set; }
75 public long Bytes { get; set; }
76 public string Content_Type { get; set; }
77 public DateTime Last_Modified { get; set; }
79 private Dictionary<string, string> _tags=new Dictionary<string, string>();
80 public Dictionary<string, string> Tags
83 set { _tags = value; }
86 private Dictionary<string, string> _extensions=new Dictionary<string, string>();
87 public Dictionary<string, string> Extensions
89 get { return _extensions; }
93 ExtractKnownExtensions();
98 private Dictionary<string, string> _permissions=new Dictionary<string, string>();
99 [JsonProperty("x_object_sharing")]
100 [JsonConverter(typeof(PermissionConverter))]
101 public Dictionary<string, string> Permissions
103 get { return _permissions; }
106 _permissions = value;
113 [JsonProperty("x_object_version")]
114 public long? Version { get; set; }
118 /// Shared object permissions can be Read or Write
120 [JsonProperty("x_object_allowed_to")]
121 public string AllowedTo { get; set; }
125 /// Version timestamp
127 [JsonProperty("X_Object_Version_Timestamp"), JsonConverter(typeof(PithosDateTimeConverter))]
128 public DateTime? VersionTimestamp { get; set; }
130 [JsonProperty("X_Object_Modified_By")]
131 public string ModifiedBy { get; set; }
134 public Stream Stream { get; set; }
137 public Uri StorageUri { get; set; }
139 public string Account { get; set; }
141 public string Container { get; set; }
147 var relativeUrl=String.Format("{0}/{1}/{2}",Account, Container,Name);
148 return StorageUri==null
149 ? new Uri(relativeUrl,UriKind.Relative)
150 : new Uri(StorageUri, relativeUrl);
154 public string ContendDisposition { get; set; }
156 public string ContentEncoding { get; set; }
158 public string Manifest { get; set; }
162 get { return !String.IsNullOrWhiteSpace(PublicUrl); }
167 else if (String.IsNullOrWhiteSpace(PublicUrl))
172 [JsonProperty("X_Object_Public")]
173 public string PublicUrl { get; set; }
175 public string PreviousHash { get; set; }
180 public ObjectInfo(string accountPath,string accountName,FileSystemInfo fileInfo)
182 if (String.IsNullOrWhiteSpace(accountPath))
183 throw new ArgumentNullException("accountPath");
184 if (string.IsNullOrWhiteSpace(accountName))
185 throw new ArgumentNullException("accountName");
186 if (fileInfo == null)
187 throw new ArgumentNullException("fileInfo");
188 Contract.EndContractBlock();
190 var relativeUrl = fileInfo.WithProperCapitalization().AsRelativeUrlTo(accountPath);
191 //The first part of the URL is the container
192 var slashIndex = relativeUrl.IndexOf('/');
193 var container = relativeUrl.Substring(0, slashIndex);
194 //The second is the file's url relative to the container
195 var fileUrl = relativeUrl.Substring(slashIndex + 1);
197 Account = accountName;
198 Container = container;
203 private void ExtractKnownExtensions()
205 Version=GetLong(KnownExtensions.X_Object_Version);
206 VersionTimestamp = GetTimestamp(KnownExtensions.X_Object_Version_Timestamp);
207 ModifiedBy = GetString(KnownExtensions.X_Object_Modified_By);
210 private string GetString(string name)
213 _extensions.TryGetValue(name, out value);
217 private long? GetLong(string name)
221 return _extensions.TryGetValue(name, out version) && long.TryParse(version, out value)
226 private DateTime? GetTimestamp(string name)
230 if (_extensions.TryGetValue(name, out version) &&
231 DateTime.TryParse(version,CultureInfo.InvariantCulture,DateTimeStyles.AdjustToUniversal, out value))
239 public static ObjectInfo Empty = new ObjectInfo
243 X_Object_Hash= String.Empty,
245 Content_Type = String.Empty,
246 Last_Modified = DateTime.MinValue,
250 private bool _exists=true;
263 public string RelativeUrlToFilePath(string currentAccount)
266 throw new InvalidOperationException("Name can't be null");
267 if (String.IsNullOrWhiteSpace(currentAccount))
268 throw new ArgumentNullException("currentAccount");
269 Contract.EndContractBlock();
274 var unescaped = Uri.UnescapeDataString(Name);
275 var path = unescaped.Replace("/", "\\");
276 var pathParts=new Stack<string>();
277 pathParts.Push(path);
278 if (!String.IsNullOrWhiteSpace(Container) && !_knownContainers.Contains(Container))
279 pathParts.Push(Container);
280 if (!currentAccount.Equals(Account, StringComparison.InvariantCultureIgnoreCase))
284 pathParts.Push(Account);
285 pathParts.Push(FolderConstants.OthersFolder);
288 var finalPath=Path.Combine(pathParts.ToArray());
293 public override bool TrySetMember(SetMemberBinder binder, object value)
295 if (binder.Name.StartsWith("x_object_meta"))
297 Tags[binder.Name] = value.ToString();
303 public string GetPermissionString()
305 if (Permissions==null)
306 throw new InvalidOperationException();
307 Contract.EndContractBlock();
309 if (Permissions.Count == 0)
311 var permissionBuilder = new StringBuilder();
312 var groupings = Permissions.GroupBy(pair => pair.Value.Trim(), pair => pair.Key.Trim());
313 foreach (var grouping in groupings)
315 permissionBuilder.AppendFormat("{0}={1};", grouping.Key, String.Join(",", grouping));
317 var permissions = Uri.EscapeDataString(permissionBuilder.ToString().Trim(';'));
321 public void SetPermissions(string permissions)
323 if (String.IsNullOrWhiteSpace(permissions))
326 Permissions = PermissionConverter.ParsePermissions(permissions);
329 //The previous values that correspond to a NoModification object
330 //have the same account, container and possibly the same folder
331 public bool CorrespondsTo(ObjectInfo other)
333 return other.Account == this.Account
334 && other.Container == this.Container
335 && (this.Name == null || other.Name.StartsWith(this.Name));
338 public bool IsWritable(string account)
340 //If the Allowed To header has no value, try to determine the Share permissions
341 if (AllowedTo == null)
343 //If this file has no permissions defined, we can probably write it
344 //This case should occur only when the info comes from a listing of the user's own files
345 if (Permissions == null || Permissions.Count == 0)
349 //Do we have an explicit write share to this account?
350 return Permissions.TryGetValue(account, out perms)
351 && perms.Equals("write",StringComparison.InvariantCultureIgnoreCase);
354 //Otherwise return the permissions specified by AllowedTo
355 return AllowedTo.Equals("write",StringComparison.InvariantCultureIgnoreCase) ;
358 public ObjectInfo Previous { get; private set; }
360 public bool IsDirectory
364 if (Content_Type == null)
366 if (Content_Type.StartsWith(@"application/directory",StringComparison.InvariantCultureIgnoreCase))
368 if (Content_Type.StartsWith(@"application/folder",StringComparison.InvariantCultureIgnoreCase))
374 public Uri AccountKey
376 get { return new Uri(StorageUri,"../" + Account); }
379 public ObjectInfo SetPrevious(ObjectInfo previous)
382 PreviousHash = previous.X_Object_Hash;
386 public bool? IsShared
390 if (Uri == null || StorageUri == null)
392 var isShared = !Uri.ToString().StartsWith(StorageUri.ToString());