Statistics
| Branch: | Revision:

root / trunk / Pithos.Interfaces / ObjectInfo.cs @ 1cc1e8c5

History | View | Annotate | Download (13 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
        [JsonProperty("hash")]
62
        public string ETag { get; set; }
63

    
64
        //public string Hash { get; set; }
65

    
66
/*
67
        public string X_Object_Hash { get { return Hash; } set { Hash = value; } }
68
*/
69

    
70
        public string X_Object_Hash { get; set; }
71

    
72
        [JsonProperty("x_object_uuid")]
73
        public string UUID { get; set; }
74

    
75
        public long Bytes { get; set; }
76
        public string Content_Type { get; set; }
77
        public DateTime Last_Modified { get; set; }
78

    
79
        private Dictionary<string, string> _tags=new Dictionary<string, string>();
80
        public Dictionary<string, string> Tags
81
        {
82
            get { return _tags; }
83
            set { _tags = value; }
84
        }
85

    
86
        private Dictionary<string, string> _extensions=new Dictionary<string, string>();
87
        public Dictionary<string, string> Extensions
88
        {
89
            get { return _extensions; }
90
            set
91
            {
92
                _extensions = value;
93
                ExtractKnownExtensions();
94
            }
95
        }
96
        
97
        
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
102
        {
103
            get { return _permissions; }
104
            set
105
            {
106
                _permissions = value;                
107
            }
108
        }
109

    
110
        /// <summary>
111
        /// Version number
112
        /// </summary>
113
        [JsonProperty("x_object_version")]
114
        public long? Version { get; set; }
115

    
116

    
117
        /// <summary>
118
        /// Shared object permissions can be Read or Write
119
        /// </summary>
120
        [JsonProperty("x_object_allowed_to")]
121
        public string AllowedTo { get; set; }
122

    
123

    
124
        /// <summary>
125
        /// Version timestamp
126
        /// </summary>
127
        [JsonProperty("X_Object_Version_Timestamp"), JsonConverter(typeof(PithosDateTimeConverter))]
128
        public DateTime? VersionTimestamp { get; set; }
129

    
130
        [JsonProperty("X_Object_Modified_By")]
131
        public string ModifiedBy { get; set; }
132

    
133

    
134
        public Stream Stream { get; set; }
135

    
136

    
137
        public Uri StorageUri { get; set; }
138

    
139
        public string Account { get; set; }
140

    
141
        public string Container { get; set; }
142

    
143
        public Uri Uri
144
        {
145
            get
146
            {
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);
151
            }
152
        }
153

    
154
        public string ContendDisposition { get; set; }
155

    
156
        public string ContentEncoding { get; set; }
157

    
158
        public string Manifest { get; set; }
159
        
160
        public bool IsPublic
161
        {
162
            get { return !String.IsNullOrWhiteSpace(PublicUrl); }
163
            set
164
            {
165
                if (!value)
166
                    PublicUrl = null;
167
                else if (String.IsNullOrWhiteSpace(PublicUrl))
168
                    PublicUrl="true";                
169
            }
170
        }
171

    
172
        [JsonProperty("X_Object_Public")]
173
        public string PublicUrl { get; set; }
174

    
175
        public string PreviousHash { get; set; }
176

    
177
        public ObjectInfo()
178
        {}
179

    
180
        public ObjectInfo(string accountPath,string accountName,FileSystemInfo fileInfo)
181
        {
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();
189

    
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);
196

    
197
            Account = accountName;
198
            Container = container;
199
            Name = fileUrl; 
200
        }
201

    
202

    
203
        private void ExtractKnownExtensions()
204
        {
205
            Version=GetLong(KnownExtensions.X_Object_Version);
206
            VersionTimestamp = GetTimestamp(KnownExtensions.X_Object_Version_Timestamp);
207
            ModifiedBy = GetString(KnownExtensions.X_Object_Modified_By);
208
        }
209

    
210
        private string GetString(string name)
211
        {            
212
            string value;
213
            _extensions.TryGetValue(name, out value);
214
            return value ;                        
215
        }
216
        
217
        private long? GetLong(string name)
218
        {
219
            string version;
220
            long value;
221
            return _extensions.TryGetValue(name, out version) && long.TryParse(version, out value)
222
                       ? (long?) value
223
                       : null;
224
        }
225

    
226
        private DateTime? GetTimestamp(string name)
227
        {
228
            string version;
229
            DateTime value;
230
            if (_extensions.TryGetValue(name, out version) && 
231
                DateTime.TryParse(version,CultureInfo.InvariantCulture,DateTimeStyles.AdjustToUniversal, out value))
232
            {
233
                return value;
234
            }
235
            return null;
236
        }
237

    
238

    
239
        public static ObjectInfo Empty = new ObjectInfo
240
        {
241
            Name = String.Empty,
242
            ETag= String.Empty,
243
            X_Object_Hash= String.Empty,
244
            Bytes = 0,
245
            Content_Type = String.Empty,
246
            Last_Modified = DateTime.MinValue,
247
            Exists=false
248
        };
249

    
250
        private bool _exists=true;
251

    
252
        public bool Exists
253
        {
254
            get {
255
                return _exists;
256
            }
257
            set {
258
                _exists = value;
259
            }
260
        }
261

    
262

    
263
        public string RelativeUrlToFilePath(string currentAccount)
264
        {
265
            if (Name==null)
266
                throw new InvalidOperationException("Name can't be null");
267
            if (String.IsNullOrWhiteSpace(currentAccount))
268
                throw new ArgumentNullException("currentAccount");
269
            Contract.EndContractBlock();
270

    
271
            if (this == Empty)
272
                return String.Empty;
273

    
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))
281
            {
282
                if (Account != null)
283
                {
284
                    pathParts.Push(Account);
285
                    pathParts.Push(FolderConstants.OthersFolder);
286
                }
287
            }
288
            var finalPath=Path.Combine(pathParts.ToArray());
289
            return finalPath;
290
        }
291

    
292
/*
293
        public override bool TrySetMember(SetMemberBinder binder, object value)
294
        {
295
            if (binder.Name.StartsWith("x_object_meta"))
296
            {
297
                Tags[binder.Name] = value.ToString();
298
            }
299
            return false;
300
        }
301
*/
302

    
303
        public string GetPermissionString()
304
        {
305
            if (Permissions==null)
306
                throw new InvalidOperationException();
307
            Contract.EndContractBlock();
308

    
309
            if (Permissions.Count == 0)
310
                return "~";
311
            var permissionBuilder = new StringBuilder();
312
            var groupings = Permissions.GroupBy(pair => pair.Value.Trim(), pair => pair.Key.Trim());
313
            foreach (var grouping in groupings)
314
            {
315
                permissionBuilder.AppendFormat("{0}={1};", grouping.Key, String.Join(",", grouping));
316
            }
317
            var permissions = Uri.EscapeDataString(permissionBuilder.ToString().Trim(';'));
318
            return permissions;
319
        }
320

    
321
        public void SetPermissions(string permissions)
322
        {
323
            if (String.IsNullOrWhiteSpace(permissions))
324
                return;
325
            
326
            Permissions = PermissionConverter.ParsePermissions(permissions);
327
        }
328

    
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)
332
        {
333
            return other.Account == this.Account
334
                   && other.Container == this.Container
335
                   && (this.Name == null || other.Name.StartsWith(this.Name));
336
        }
337

    
338
        public bool IsWritable(string account)
339
        {
340
            //If the Allowed To header has no value, try to determine the Share permissions
341
            if (AllowedTo == null)
342
            {
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)
346
                    return true;
347
                string perms;
348

    
349
                //Do we have an explicit write share to this account?
350
                return Permissions.TryGetValue(account, out perms) 
351
                    && perms.Equals("write",StringComparison.InvariantCultureIgnoreCase);
352
                
353
            }
354
            //Otherwise return the permissions specified by AllowedTo
355
            return AllowedTo.Equals("write",StringComparison.InvariantCultureIgnoreCase) ;
356
        }
357

    
358
        public ObjectInfo Previous { get; private set; }
359

    
360
        public bool IsDirectory
361
        {
362
            get
363
            {
364
                if (Content_Type == null)
365
                    return false;
366
                if (Content_Type.StartsWith(@"application/directory",StringComparison.InvariantCultureIgnoreCase))
367
                    return true;
368
                if (Content_Type.StartsWith(@"application/folder",StringComparison.InvariantCultureIgnoreCase))
369
                    return true;
370
                return false;
371
            }
372
        }
373

    
374
        public Uri AccountKey
375
        {
376
            get { return new Uri(StorageUri,"../" + Account); }
377
        }
378

    
379
        public ObjectInfo SetPrevious(ObjectInfo previous)
380
        {            
381
            Previous = previous;
382
            PreviousHash = previous.X_Object_Hash;
383
            return this;
384
        }
385

    
386
        public bool? IsShared
387
        {
388
            get
389
            {
390
                if (Uri == null || StorageUri == null)
391
                    return null;
392
                var isShared = !Uri.ToString().StartsWith(StorageUri.ToString());
393
                return isShared;
394
            }
395
        }
396
    }
397
}