Statistics
| Branch: | Revision:

root / trunk / Pithos.Interfaces / ObjectInfo.cs @ 43dd02a8

History | View | Annotate | Download (12.8 kB)

1
#region
2
/* -----------------------------------------------------------------------
3
 * <copyright file="ObjectInfo.cs" company="GRNet">
4
 * 
5
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or
8
 * without modification, are permitted provided that the following
9
 * conditions are met:
10
 *
11
 *   1. Redistributions of source code must retain the above
12
 *      copyright notice, this list of conditions and the following
13
 *      disclaimer.
14
 *
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.
19
 *
20
 *
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.
33
 *
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.
38
 * </copyright>
39
 * -----------------------------------------------------------------------
40
 */
41
#endregion
42
using System;
43
using System.Collections.Generic;
44
using System.Diagnostics;
45
using System.Diagnostics.Contracts;
46
using System.Dynamic;
47
using System.Globalization;
48
using System.IO;
49
using System.Linq;
50
using System.Text;
51
using Newtonsoft.Json;
52

    
53
namespace Pithos.Interfaces
54
{
55
    [DebuggerDisplay("Name {Name}")]
56
    public class ObjectInfo//:DynamicObject 
57
    {
58
        private readonly List<string> _knownContainers= new List<string>{"trash"};
59
        public string Name { get; set; }
60

    
61
        public string ETag { get; set; }
62

    
63
        public string Hash { get; set; }
64

    
65
        public string X_Object_Hash { get { return Hash; } set { Hash = value; } }
66

    
67
        [JsonProperty("x_object_uuid")]
68
        public string UUID { get; set; }
69

    
70
        public long Bytes { get; set; }
71
        public string Content_Type { get; set; }
72
        public DateTime Last_Modified { get; set; }
73

    
74
        private Dictionary<string, string> _tags=new Dictionary<string, string>();
75
        public Dictionary<string, string> Tags
76
        {
77
            get { return _tags; }
78
            set { _tags = value; }
79
        }
80

    
81
        private Dictionary<string, string> _extensions=new Dictionary<string, string>();
82
        public Dictionary<string, string> Extensions
83
        {
84
            get { return _extensions; }
85
            set
86
            {
87
                _extensions = value;
88
                ExtractKnownExtensions();
89
            }
90
        }
91
        
92
        
93
        private Dictionary<string, string> _permissions=new Dictionary<string, string>();
94
        [JsonProperty("x_object_sharing")]
95
        [JsonConverter(typeof(PermissionConverter))]
96
        public Dictionary<string, string> Permissions
97
        {
98
            get { return _permissions; }
99
            set
100
            {
101
                _permissions = value;                
102
            }
103
        }
104

    
105
        /// <summary>
106
        /// Version number
107
        /// </summary>
108
        [JsonProperty("x_object_version")]
109
        public long? Version { get; set; }
110

    
111

    
112
        /// <summary>
113
        /// Shared object permissions can be Read or Write
114
        /// </summary>
115
        [JsonProperty("x_object_allowed_to")]
116
        public string AllowedTo { get; set; }
117

    
118

    
119
        /// <summary>
120
        /// Version timestamp
121
        /// </summary>
122
        [JsonProperty("X_Object_Version_Timestamp"), JsonConverter(typeof(PithosDateTimeConverter))]
123
        public DateTime? VersionTimestamp { get; set; }
124

    
125
        [JsonProperty("X_Object_Modified_By")]
126
        public string ModifiedBy { get; set; }
127

    
128

    
129
        public Stream Stream { get; set; }
130

    
131

    
132
        public Uri StorageUri { get; set; }
133

    
134
        public string Account { get; set; }
135

    
136
        public string Container { get; set; }
137

    
138
        public Uri Uri
139
        {
140
            get
141
            {
142
                var relativeUrl=String.Format("{0}/{1}/{2}",Account, Container,Name);
143
                return StorageUri==null 
144
                    ? new Uri(relativeUrl,UriKind.Relative) 
145
                    : new Uri(StorageUri, relativeUrl);
146
            }
147
        }
148

    
149
        public string ContendDisposition { get; set; }
150

    
151
        public string ContentEncoding { get; set; }
152

    
153
        public string Manifest { get; set; }
154
        
155
        public bool IsPublic
156
        {
157
            get { return !String.IsNullOrWhiteSpace(PublicUrl); }
158
            set
159
            {
160
                if (!value)
161
                    PublicUrl = null;
162
                else if (String.IsNullOrWhiteSpace(PublicUrl))
163
                    PublicUrl="true";                
164
            }
165
        }
166

    
167
        [JsonProperty("X_Object_Public")]
168
        public string PublicUrl { get; set; }
169

    
170
        public string PreviousHash { get; set; }
171

    
172
        public ObjectInfo()
173
        {}
174

    
175
        public ObjectInfo(string accountPath,string accountName,FileSystemInfo fileInfo)
176
        {
177
            if (String.IsNullOrWhiteSpace(accountPath))
178
                throw new ArgumentNullException("accountPath");
179
            if (string.IsNullOrWhiteSpace(accountName))
180
                throw new ArgumentNullException("accountName");
181
            if (fileInfo == null)
182
                throw new ArgumentNullException("fileInfo");
183
            Contract.EndContractBlock();
184

    
185
            var relativeUrl = fileInfo.WithProperCapitalization().AsRelativeUrlTo(accountPath);
186
            //The first part of the URL is the container
187
            var slashIndex = relativeUrl.IndexOf('/');
188
            var container = relativeUrl.Substring(0, slashIndex);
189
            //The second is the file's url relative to the container
190
            var fileUrl = relativeUrl.Substring(slashIndex + 1);
191

    
192
            Account = accountName;
193
            Container = container;
194
            Name = fileUrl; 
195
        }
196

    
197

    
198
        private void ExtractKnownExtensions()
199
        {
200
            Version=GetLong(KnownExtensions.X_Object_Version);
201
            VersionTimestamp = GetTimestamp(KnownExtensions.X_Object_Version_Timestamp);
202
            ModifiedBy = GetString(KnownExtensions.X_Object_Modified_By);
203
        }
204

    
205
        private string GetString(string name)
206
        {            
207
            string value;
208
            _extensions.TryGetValue(name, out value);
209
            return value ;                        
210
        }
211
        
212
        private long? GetLong(string name)
213
        {
214
            string version;
215
            long value;
216
            return _extensions.TryGetValue(name, out version) && long.TryParse(version, out value)
217
                       ? (long?) value
218
                       : null;
219
        }
220

    
221
        private DateTime? GetTimestamp(string name)
222
        {
223
            string version;
224
            DateTime value;
225
            if (_extensions.TryGetValue(name, out version) && 
226
                DateTime.TryParse(version,CultureInfo.InvariantCulture,DateTimeStyles.AdjustToUniversal, out value))
227
            {
228
                return value;
229
            }
230
            return null;
231
        }
232

    
233

    
234
        public static ObjectInfo Empty = new ObjectInfo
235
        {
236
            Name = String.Empty,
237
            Hash = String.Empty,
238
            Bytes = 0,
239
            Content_Type = String.Empty,
240
            Last_Modified = DateTime.MinValue,
241
            Exists=false
242
        };
243

    
244
        private bool _exists=true;
245

    
246
        public bool Exists
247
        {
248
            get {
249
                return _exists;
250
            }
251
            set {
252
                _exists = value;
253
            }
254
        }
255

    
256

    
257
        public string RelativeUrlToFilePath(string currentAccount)
258
        {
259
            if (Name==null)
260
                throw new InvalidOperationException("Name can't be null");
261
            if (String.IsNullOrWhiteSpace(currentAccount))
262
                throw new ArgumentNullException("currentAccount");
263
            Contract.EndContractBlock();
264

    
265
            if (this == Empty)
266
                return String.Empty;
267

    
268
            var unescaped = Uri.UnescapeDataString(Name);
269
            var path = unescaped.Replace("/", "\\");
270
            var pathParts=new Stack<string>();
271
            pathParts.Push(path);
272
            if (!String.IsNullOrWhiteSpace(Container) && !_knownContainers.Contains(Container))
273
                pathParts.Push(Container);
274
            if (!currentAccount.Equals(Account, StringComparison.InvariantCultureIgnoreCase))
275
            {
276
                if (Account != null)
277
                {
278
                    pathParts.Push(Account);
279
                    pathParts.Push(FolderConstants.OthersFolder);
280
                }
281
            }
282
            var finalPath=Path.Combine(pathParts.ToArray());
283
            return finalPath;
284
        }
285

    
286
/*
287
        public override bool TrySetMember(SetMemberBinder binder, object value)
288
        {
289
            if (binder.Name.StartsWith("x_object_meta"))
290
            {
291
                Tags[binder.Name] = value.ToString();
292
            }
293
            return false;
294
        }
295
*/
296

    
297
        public string GetPermissionString()
298
        {
299
            if (Permissions==null)
300
                throw new InvalidOperationException();
301
            Contract.EndContractBlock();
302

    
303
            if (Permissions.Count == 0)
304
                return "~";
305
            var permissionBuilder = new StringBuilder();
306
            var groupings = Permissions.GroupBy(pair => pair.Value.Trim(), pair => pair.Key.Trim());
307
            foreach (var grouping in groupings)
308
            {
309
                permissionBuilder.AppendFormat("{0}={1};", grouping.Key, String.Join(",", grouping));
310
            }
311
            var permissions = Uri.EscapeDataString(permissionBuilder.ToString().Trim(';'));
312
            return permissions;
313
        }
314

    
315
        public void SetPermissions(string permissions)
316
        {
317
            if (String.IsNullOrWhiteSpace(permissions))
318
                return;
319
            
320
            Permissions = PermissionConverter.ParsePermissions(permissions);
321
        }
322

    
323
        //The previous values that correspond to a NoModification object
324
        //have the same account, container and possibly the same folder
325
        public bool CorrespondsTo(ObjectInfo other)
326
        {
327
            return other.Account == this.Account
328
                   && other.Container == this.Container
329
                   && (this.Name == null || other.Name.StartsWith(this.Name));
330
        }
331

    
332
        public bool IsWritable(string account)
333
        {
334
            //If the Allowed To header has no value, try to determine the Share permissions
335
            if (AllowedTo == null)
336
            {
337
                //If this file has no permissions defined, we can probably write it
338
                //This case should occur only when the info comes from a listing of the user's own files
339
                if (Permissions == null || Permissions.Count == 0)
340
                    return true;
341
                string perms;
342

    
343
                //Do we have an explicit write share to this account?
344
                return Permissions.TryGetValue(account, out perms) 
345
                    && perms.Equals("write",StringComparison.InvariantCultureIgnoreCase);
346
                
347
            }
348
            //Otherwise return the permissions specified by AllowedTo
349
            return AllowedTo.Equals("write",StringComparison.InvariantCultureIgnoreCase) ;
350
        }
351

    
352
        public ObjectInfo Previous { get; private set; }
353

    
354
        public bool IsDirectory
355
        {
356
            get
357
            {
358
                if (Content_Type == null)
359
                    return false;
360
                if (Content_Type.StartsWith(@"application/directory",StringComparison.InvariantCultureIgnoreCase))
361
                    return true;
362
                if (Content_Type.StartsWith(@"application/folder",StringComparison.InvariantCultureIgnoreCase))
363
                    return true;
364
                return false;
365
            }
366
        }
367

    
368
        public Uri AccountKey
369
        {
370
            get { return new Uri(StorageUri,"../" + Account); }
371
        }
372

    
373
        public ObjectInfo SetPrevious(ObjectInfo previous)
374
        {            
375
            Previous = previous;
376
            PreviousHash = previous.Hash;
377
            return this;
378
        }
379

    
380
        public bool? IsShared
381
        {
382
            get
383
            {
384
                if (Uri == null || StorageUri == null)
385
                    return null;
386
                var isShared = !Uri.ToString().StartsWith(StorageUri.ToString());
387
                return isShared;
388
            }
389
        }
390
    }
391
}