Statistics
| Branch: | Revision:

root / trunk / Pithos.Core / FileState.cs @ 73cdd135

History | View | Annotate | Download (12.4 kB)

1
// -----------------------------------------------------------------------
2
// <copyright file="FileState.cs" company="Microsoft">
3
// TODO: Update copyright text.
4
// </copyright>
5
// -----------------------------------------------------------------------
6

    
7
using System.Diagnostics.Contracts;
8
using System.IO;
9
using System.Threading.Tasks;
10
using Castle.ActiveRecord;
11
using Castle.ActiveRecord.Framework;
12
using Pithos.Core.Agents;
13
using Pithos.Interfaces;
14
using log4net;
15

    
16
namespace Pithos.Core
17
{
18
    using System;
19
    using System.Collections.Generic;
20
    using System.Linq;
21

    
22
    /// <summary>
23
    /// TODO: Update summary.
24
    /// </summary>
25
    [ActiveRecord]
26
    public class FileState:ActiveRecordLinqBase<FileState>
27
    {
28
        private static readonly ILog Log = LogManager.GetLogger("FileState");
29
        
30
        private string _filePath;
31
        private IList<FileTag> _tags=new List<FileTag>();
32

    
33
        [PrimaryKey(PrimaryKeyType.Guid)]
34
        public Guid Id { get; set; }
35

    
36
        [Property(Unique=true,UniqueKey="IX_FileState_FilePath")]
37
        public string FilePath
38
        {
39
            get { return _filePath; }
40
            set { _filePath = value.ToLower(); }
41
        }
42

    
43
        [Property]
44
        public FileOverlayStatus OverlayStatus { get; set; }
45

    
46
        [Property]
47
        public FileStatus FileStatus { get; set; }
48

    
49
        [Property]
50
        public string Checksum { get; set; }
51

    
52

    
53
        [Property]
54
        public long? Version { get; set; }
55

    
56
        [Property]
57
        public DateTime? VersionTimeStamp { get; set; }
58

    
59

    
60
        [Property]
61
        public bool IsShared { get; set; }
62

    
63
        [Property]
64
        public string SharedBy { get; set; }
65

    
66
        [Property]
67
        public bool ShareWrite { get; set; }
68

    
69

    
70
       [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true,Inverse=true)]
71
        public IList<FileTag> Tags
72
        {
73
            get { return _tags; }   
74
            set { _tags=value;}
75
        }
76

    
77
   
78
        public static FileState FindByFilePath(string absolutePath)
79
        {
80
            if (string.IsNullOrWhiteSpace(absolutePath))
81
                throw new ArgumentNullException("absolutePath");
82
            Contract.EndContractBlock();
83
            try
84
            {
85
                return Queryable.FirstOrDefault(s => s.FilePath == absolutePath.ToLower());
86
            }
87
            catch (Exception ex)
88
            {
89
                Log.Error(ex.ToString());
90
                throw;
91
            }
92
                
93

    
94
        }
95

    
96
        public static void DeleteByFilePath(string absolutePath)
97
        {
98
            if(string.IsNullOrWhiteSpace(absolutePath))
99
                throw new ArgumentNullException("absolutePath");
100
            Contract.EndContractBlock();
101
            
102
            Execute((session, instance) =>
103
                             {
104
                                 const string hqlDelete = "delete FileState where FilePath = :path";                                 
105
                                 var deletedEntities = session.CreateQuery(hqlDelete)
106
                                         .SetString("path", absolutePath.ToLower())
107
                                         .ExecuteUpdate();
108
                                 return deletedEntities;
109
                             },null);
110
            
111
        }
112

    
113
        public static void StoreFileStatus(string absolutePath, FileStatus newStatus)
114
        {
115
            if (string.IsNullOrWhiteSpace(absolutePath))
116
                throw new ArgumentNullException("absolutePath");
117
            Contract.EndContractBlock();
118

    
119
            Execute((session, instance) =>
120
            {
121
                const string hqlUpdate = "update FileState set FileStatus= :status where FilePath = :path  ";
122
                var updatedEntities = session.CreateQuery(hqlUpdate)
123
                        .SetString("path", absolutePath.ToLower())
124
                        .SetEnum("status", newStatus)
125
                        .ExecuteUpdate();
126
                if (updatedEntities == 0)
127
                {
128
                    var newState = new FileState { FilePath = absolutePath, Id = Guid.NewGuid(), FileStatus = newStatus };
129
                    newState.CreateAndFlush();
130
                }
131
                return null;
132
            }, null);
133

    
134
        }
135

    
136
        public static void StoreOverlayStatus(string absolutePath, FileOverlayStatus newStatus)
137
        {
138
            if (string.IsNullOrWhiteSpace(absolutePath))
139
                throw new ArgumentNullException("absolutePath");
140
            Contract.EndContractBlock();
141

    
142
            Execute((session, instance) =>
143
            {
144
                const string hqlUpdate = "update FileState set OverlayStatus= :status where FilePath = :path  ";
145
                var updatedEntities = session.CreateQuery(hqlUpdate)
146
                        .SetString("path", absolutePath.ToLower())
147
                        .SetEnum("status", newStatus)
148
                        .ExecuteUpdate();
149
                if (updatedEntities == 0)
150
                {
151
                    var newState = new FileState { FilePath = absolutePath, Id = Guid.NewGuid(), OverlayStatus = newStatus };
152
                    newState.CreateAndFlush();
153
                }
154
                return null;
155
            }, null);
156

    
157
        }
158

    
159
        public static void UpdateStatus(string absolutePath, FileStatus fileStatus, FileOverlayStatus overlayStatus)
160
        {
161
            if (string.IsNullOrWhiteSpace(absolutePath))
162
                throw new ArgumentNullException("absolutePath");
163
            Contract.EndContractBlock();
164

    
165
            Execute((session, instance) =>
166
            {
167
                const string hqlUpdate = "update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus where FilePath = :path  ";
168
                var updatedEntities = session.CreateQuery(hqlUpdate)
169
                        .SetString("path", absolutePath.ToLower())
170
                        .SetEnum("fileStatus", fileStatus)
171
                        .SetEnum("overlayStatus", overlayStatus)
172
                        .ExecuteUpdate();
173
                return updatedEntities;
174
            }, null);
175

    
176
        }
177
        public static void UpdateStatus(string absolutePath, FileStatus fileStatus)
178
        {
179
            if (string.IsNullOrWhiteSpace(absolutePath))
180
                throw new ArgumentNullException("absolutePath");
181
            Contract.EndContractBlock();
182

    
183
            Execute((session, instance) =>
184
            {
185
                const string hqlUpdate = "update FileState set FileStatus= :fileStatus where FilePath = :path  ";
186
                var updatedEntities = session.CreateQuery(hqlUpdate)
187
                        .SetString("path", absolutePath.ToLower())
188
                        .SetEnum("fileStatus", fileStatus)                        
189
                        .ExecuteUpdate();
190
                return updatedEntities;
191
            }, null);
192

    
193
        }
194

    
195
        public static void RenameState(string oldPath, string newPath)
196
        {
197
            if (string.IsNullOrWhiteSpace(oldPath))
198
                throw new ArgumentNullException("oldPath");
199
            Contract.EndContractBlock();
200

    
201
            Execute((session, instance) =>
202
            {
203
                const string hqlUpdate = "update FileState set FilePath= :newPath where FilePath = :oldPath  ";
204
                var updatedEntities = session.CreateQuery(hqlUpdate)
205
                        .SetString("oldPath", oldPath.ToLower())
206
                        .SetString("newPath", newPath.ToLower())                                          
207
                        .ExecuteUpdate();
208
                return updatedEntities;
209
            }, null);
210

    
211
        }
212

    
213
        public static void UpdateStatus(Guid id, FileStatus fileStatus)
214
        {
215
            Contract.EndContractBlock();
216

    
217
            Execute((session, instance) =>
218
            {
219
                const string hqlUpdate = "update FileState set FileStatus= :fileStatus where Id = :id  ";
220
                var updatedEntities = session.CreateQuery(hqlUpdate)
221
                        .SetGuid("id", id)
222
                        .SetEnum("fileStatus", fileStatus)                        
223
                        .ExecuteUpdate();
224
                return updatedEntities;
225
            }, null);
226

    
227
        }
228

    
229
        public static void UpdateChecksum(string absolutePath, string checksum)
230
        {
231
            if (string.IsNullOrWhiteSpace(absolutePath))
232
                throw new ArgumentNullException("absolutePath");
233
            Contract.EndContractBlock();
234

    
235
            Execute((session, instance) =>
236
            {
237
                const string hqlUpdate = "update FileState set Checksum= :checksum where FilePath = :path  ";
238
                var updatedEntities = session.CreateQuery(hqlUpdate)
239
                        .SetString("path", absolutePath.ToLower())
240
                        .SetString("checksum", checksum)                        
241
                        .ExecuteUpdate();
242
                return updatedEntities;
243
            }, null);
244

    
245
        }
246

    
247
        public static void ChangeRootPath(string oldPath,string newPath)
248
        {
249
            if (String.IsNullOrWhiteSpace(oldPath))
250
                throw new ArgumentNullException("oldPath");
251
            if (!Path.IsPathRooted(oldPath))
252
                throw new ArgumentException("oldPath must be an absolute path", "oldPath");
253
            if (string.IsNullOrWhiteSpace(newPath))
254
                throw new ArgumentNullException("newPath");
255
            if (!Path.IsPathRooted(newPath))
256
                throw new ArgumentException("newPath must be an absolute path", "newPath");
257
            Contract.EndContractBlock();
258

    
259
            //Ensure the paths end with the same character
260
            if (!oldPath.EndsWith("\\"))
261
                oldPath = oldPath + "\\";
262
            if (!newPath.EndsWith("\\"))
263
                newPath = newPath + "\\";
264

    
265
            using (new TransactionScope())
266
            {
267
                Execute((session, instance) =>
268
                            {
269
                                const string hqlUpdate =
270
                                    "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' ";
271
                                var renames=session.CreateQuery(hqlUpdate)
272
                                    .SetString("oldPath", oldPath.ToLower())
273
                                    .SetString("newPath", newPath.ToLower())
274
                                    .ExecuteUpdate();
275
                                return renames;
276
                            }, null);
277
            }
278
        }
279

    
280
        public static Task<FileState> CreateForAsync(string filePath,int blockSize,string algorithm)
281
        {
282
            if (blockSize <= 0)
283
                throw new ArgumentOutOfRangeException("blockSize");
284
            if (String.IsNullOrWhiteSpace(algorithm))
285
                throw new ArgumentNullException("algorithm");
286
            Contract.EndContractBlock();
287

    
288

    
289
            var fileState = new FileState
290
                                {
291
                                    FilePath = filePath, 
292
                                    OverlayStatus = FileOverlayStatus.Unversioned, 
293
                                    FileStatus = FileStatus.Created,
294
                                    Id=Guid.NewGuid()
295
                                };
296

    
297

    
298
            return fileState.UpdateHashesAsync(blockSize,algorithm);            
299
        }
300

    
301
        public Task<FileState> UpdateHashesAsync(int blockSize,string algorithm)
302
        {
303
            if (blockSize<=0)
304
                throw new ArgumentOutOfRangeException("blockSize");
305
            if (String.IsNullOrWhiteSpace(algorithm))
306
                throw new ArgumentNullException("algorithm");
307
            Contract.EndContractBlock();
308
            
309
            //Skip updating the hash for folders
310
            if (Directory.Exists(FilePath))
311
                return Task.Factory.FromResult(this);
312

    
313
            var results = Task.Factory.StartNew(() =>
314
            {
315
                var info = new FileInfo(FilePath);
316
                return info.CalculateHash(blockSize, algorithm);
317
            });
318

    
319
            var state=results.Then(hash =>
320
            {
321
                Checksum = hash;
322
                return Task.Factory.FromResult(this);
323
            });
324
            
325
            return state;
326
        }
327
    }
328

    
329
    [ActiveRecord("Tags")]
330
    public class FileTag : ActiveRecordLinqBase<FileTag>
331
    {
332
        [PrimaryKey]
333
        public int Id { get; set; }
334

    
335
        [Property]
336
        public string Name { get; set; }
337

    
338
        [Property]
339
        public string Value { get; set; }
340

    
341
        [BelongsTo("FileStateId")]
342
        public FileState FileState { get; set; }
343

    
344
    }
345
   
346
}