Replaced object load and update with direct HQL execution to resolve database locks...
[pithos-ms-client] / trunk / Pithos.Interfaces / ObjectInfo.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Diagnostics.Contracts;
5 using System.Dynamic;
6 using System.Globalization;
7 using System.IO;
8 using System.Linq;
9 using System.Text;
10 using Newtonsoft.Json;
11
12 namespace Pithos.Interfaces
13 {
14     [DebuggerDisplay("Name {Name}")]
15     public class ObjectInfo:DynamicObject 
16     {
17         private readonly List<string> _knownContainers= new List<string>{"trash"};
18         public string Name { get; set; }
19         
20         
21         public string Hash { get; set; }
22
23         public string X_Object_Hash { get { return Hash; } set { Hash = value; } }
24
25         [JsonProperty("x_object_uuid")]
26         public string UUID { get; set; }
27
28         public long Bytes { get; set; }
29         public string Content_Type { get; set; }
30         public DateTime Last_Modified { get; set; }
31
32         private Dictionary<string, string> _tags=new Dictionary<string, string>();
33         public Dictionary<string, string> Tags
34         {
35             get { return _tags; }
36             set { _tags = value; }
37         }
38
39         private Dictionary<string, string> _extensions=new Dictionary<string, string>();
40         public Dictionary<string, string> Extensions
41         {
42             get { return _extensions; }
43             set
44             {
45                 _extensions = value;
46                 ExtractKnownExtensions();
47             }
48         }
49         
50         
51         private Dictionary<string, string> _permissions=new Dictionary<string, string>();
52         [JsonProperty("x_object_sharing")]
53         [JsonConverter(typeof(PermissionConverter))]
54         public Dictionary<string, string> Permissions
55         {
56             get { return _permissions; }
57             set
58             {
59                 _permissions = value;                
60             }
61         }
62
63         /// <summary>
64         /// Version number
65         /// </summary>
66         [JsonProperty("x_object_version")]
67         public long? Version { get; set; }
68
69
70         /// <summary>
71         /// Shared object permissions can be Read or Write
72         /// </summary>
73         [JsonProperty("x_object_allowed_to")]
74         public string AllowedTo { get; set; }
75
76
77         /// <summary>
78         /// Version timestamp
79         /// </summary>
80         [JsonProperty("X_Object_Version_Timestamp"), JsonConverter(typeof(PithosDateTimeConverter))]
81         public DateTime? VersionTimestamp { get; set; }
82
83         [JsonProperty("X_Object_Modified_By")]
84         public string ModifiedBy { get; set; }
85
86
87         public Stream Stream { get; set; }
88
89         public string Account { get; set; }
90
91         public string Container { get; set; }
92
93         public string ContendDisposition { get; set; }
94
95         public string ContentEncoding { get; set; }
96
97         public string Manifest { get; set; }
98         
99         public bool IsPublic
100         {
101             get { return !String.IsNullOrWhiteSpace(PublicUrl); }
102             set
103             {
104                 if (!value)
105                     PublicUrl = null;
106                 else if (String.IsNullOrWhiteSpace(PublicUrl))
107                     PublicUrl="true";                
108             }
109         }
110
111         [JsonProperty("X_Object_Public")]
112         public string PublicUrl { get; set; }
113
114         public ObjectInfo()
115         {}
116
117         public ObjectInfo(string accountPath,string accountName,FileInfo fileInfo)
118         {
119             if (String.IsNullOrWhiteSpace(accountPath))
120                 throw new ArgumentNullException("accountPath");
121             if (string.IsNullOrWhiteSpace(accountName))
122                 throw new ArgumentNullException("accountName");
123             if (fileInfo == null)
124                 throw new ArgumentNullException("fileInfo");
125             Contract.EndContractBlock();
126
127             var relativeUrl = fileInfo.AsRelativeUrlTo(accountPath);
128             //The first part of the URL is the container
129             var slashIndex = relativeUrl.IndexOf('/');
130             var container = relativeUrl.Substring(0, slashIndex);
131             //The second is the file's url relative to the container
132             var fileUrl = relativeUrl.Substring(slashIndex + 1);
133
134             Account = accountName;
135             Container = container;
136             Name = fileUrl; 
137         }
138
139
140         private void ExtractKnownExtensions()
141         {
142             Version=GetLong(KnownExtensions.X_Object_Version);
143             VersionTimestamp = GetTimestamp(KnownExtensions.X_Object_Version_Timestamp);
144             ModifiedBy = GetString(KnownExtensions.X_Object_Modified_By);
145         }
146
147         private string GetString(string name)
148         {            
149             string value;
150             _extensions.TryGetValue(name, out value);
151             return value ;                        
152         }
153         
154         private long? GetLong(string name)
155         {
156             string version;
157             long value;
158             return _extensions.TryGetValue(name, out version) && long.TryParse(version, out value)
159                        ? (long?) value
160                        : null;
161         }
162
163         private DateTime? GetTimestamp(string name)
164         {
165             string version;
166             DateTime value;
167             if (_extensions.TryGetValue(name, out version) && 
168                 DateTime.TryParse(version,CultureInfo.InvariantCulture,DateTimeStyles.AdjustToUniversal, out value))
169             {
170                 return value;
171             }
172             return null;
173         }
174
175
176         public static ObjectInfo Empty = new ObjectInfo
177         {
178             Name = String.Empty,
179             Hash = String.Empty,
180             Bytes = 0,
181             Content_Type = String.Empty,
182             Last_Modified = DateTime.MinValue
183         };
184
185         public string RelativeUrlToFilePath(string currentAccount)
186         {
187             if (Name==null)
188                 throw new InvalidOperationException("Name can't be null");
189             if (String.IsNullOrWhiteSpace(currentAccount))
190                 throw new ArgumentNullException("currentAccount");
191             Contract.EndContractBlock();
192
193             if (this == Empty)
194                 return String.Empty;
195
196             var unescaped = Uri.UnescapeDataString(Name);
197             var path = unescaped.Replace("/", "\\");
198             var pathParts=new Stack<string>();
199             pathParts.Push(path);
200             if (!String.IsNullOrWhiteSpace(Container) && !_knownContainers.Contains(Container))
201                 pathParts.Push(Container);
202             if (!currentAccount.Equals(Account, StringComparison.InvariantCultureIgnoreCase))
203             {
204                 if (Account != null)
205                 {
206                     pathParts.Push(Account);
207                     pathParts.Push("others");
208                 }
209             }
210             var finalPath=Path.Combine(pathParts.ToArray());
211             return finalPath;
212         }
213
214         public override bool TrySetMember(SetMemberBinder binder, object value)
215         {
216             if (binder.Name.StartsWith("x_object_meta"))
217             {
218                 Tags[binder.Name] = value.ToString();
219             }
220             return false;
221         }
222
223         public string GetPermissionString()
224         {
225             if (Permissions==null)
226                 throw new InvalidOperationException();
227             Contract.EndContractBlock();
228
229             var permissionBuilder = new StringBuilder();
230             var groupings = Permissions.GroupBy(pair => pair.Value, pair => pair.Key);
231             foreach (var grouping in groupings)
232             {
233                 permissionBuilder.AppendFormat("{0}={1};", grouping.Key, String.Join(",", grouping));
234             }
235             var permissions = permissionBuilder.ToString().Trim(';');
236             return permissions;
237         }
238
239         public void SetPermissions(string permissions)
240         {
241             if (String.IsNullOrWhiteSpace(permissions))
242                 return;
243
244             var permDict=new Dictionary<string, string>();
245             var perms=permissions.Split(';');
246             foreach (var perm in perms)
247             {
248                 var permPairs=perm.Split('=');
249                 var right = permPairs[0];
250                 var users= permPairs[1].Split(new[]{','},StringSplitOptions.RemoveEmptyEntries);
251                 foreach (var user in users)
252                 {
253                     permDict[user] = right;
254                 }
255             }
256             Permissions = permDict;
257         }
258     }
259 }