Statistics
| Branch: | Revision:

root / trunk / Pithos.Core / FileState.cs @ b9f5b594

History | View | Annotate | Download (13.8 kB)

1
// -----------------------------------------------------------------------
2
// <copyright file="FileState.cs" company="GRNet">
3
// Copyright 2011 GRNET S.A. All rights reserved.
4
// 
5
// Redistribution and use in source and binary forms, with or
6
// without modification, are permitted provided that the following
7
// conditions are met:
8
// 
9
//   1. Redistributions of source code must retain the above
10
//      copyright notice, this list of conditions and the following
11
//      disclaimer.
12
// 
13
//   2. Redistributions in binary form must reproduce the above
14
//      copyright notice, this list of conditions and the following
15
//      disclaimer in the documentation and/or other materials
16
//      provided with the distribution.
17
// 
18
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
// POSSIBILITY OF SUCH DAMAGE.
30
// 
31
// The views and conclusions contained in the software and
32
// documentation are those of the authors and should not be
33
// interpreted as representing official policies, either expressed
34
// or implied, of GRNET S.A.
35
// </copyright>
36
// -----------------------------------------------------------------------
37

    
38
using System.Diagnostics.Contracts;
39
using System.IO;
40
using System.Threading.Tasks;
41
using Castle.ActiveRecord;
42
using Castle.ActiveRecord.Framework;
43
using Pithos.Core.Agents;
44
using Pithos.Interfaces;
45
using log4net;
46

    
47
namespace Pithos.Core
48
{
49
    using System;
50
    using System.Collections.Generic;
51
    using System.Linq;
52

    
53
    /// <summary>
54
    /// TODO: Update summary.
55
    /// </summary>
56
    [ActiveRecord]
57
    public class FileState:ActiveRecordLinqBase<FileState>
58
    {
59
        private static readonly ILog Log = LogManager.GetLogger("FileState");
60
        
61
        private string _filePath;
62
        private IList<FileTag> _tags=new List<FileTag>();
63

    
64
        [PrimaryKey(PrimaryKeyType.Guid)]
65
        public Guid Id { get; set; }
66

    
67
        [Property(Unique=true,UniqueKey="IX_FileState_FilePath")]
68
        public string FilePath
69
        {
70
            get { return _filePath; }
71
            set { _filePath = value.ToLower(); }
72
        }
73

    
74
        [Property]
75
        public FileOverlayStatus OverlayStatus { get; set; }
76

    
77
        [Property]
78
        public FileStatus FileStatus { get; set; }
79

    
80
        [Property]
81
        public string Checksum { get; set; }
82

    
83

    
84
        [Property]
85
        public long? Version { get; set; }
86

    
87
        [Property]
88
        public DateTime? VersionTimeStamp { get; set; }
89

    
90

    
91
        [Property]
92
        public bool IsShared { get; set; }
93

    
94
        [Property]
95
        public string SharedBy { get; set; }
96

    
97
        [Property]
98
        public bool ShareWrite { get; set; }
99

    
100

    
101
       [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true,Inverse=true)]
102
        public IList<FileTag> Tags
103
        {
104
            get { return _tags; }   
105
            set { _tags=value;}
106
        }
107

    
108
   
109
        public static FileState FindByFilePath(string absolutePath)
110
        {
111
            if (string.IsNullOrWhiteSpace(absolutePath))
112
                throw new ArgumentNullException("absolutePath");
113
            Contract.EndContractBlock();
114
            try
115
            {
116
                return Queryable.FirstOrDefault(s => s.FilePath == absolutePath.ToLower());
117
            }
118
            catch (Exception ex)
119
            {
120
                Log.Error(ex.ToString());
121
                throw;
122
            }
123
                
124

    
125
        }
126

    
127
        public static void DeleteByFilePath(string absolutePath)
128
        {
129
            if(string.IsNullOrWhiteSpace(absolutePath))
130
                throw new ArgumentNullException("absolutePath");
131
            Contract.EndContractBlock();
132
            
133
            Execute((session, instance) =>
134
                             {
135
                                 const string hqlDelete = "delete FileState where FilePath = :path";                                 
136
                                 var deletedEntities = session.CreateQuery(hqlDelete)
137
                                         .SetString("path", absolutePath.ToLower())
138
                                         .ExecuteUpdate();
139
                                 return deletedEntities;
140
                             },null);
141
            
142
        }
143

    
144
        public static void StoreFileStatus(string absolutePath, FileStatus newStatus)
145
        {
146
            if (string.IsNullOrWhiteSpace(absolutePath))
147
                throw new ArgumentNullException("absolutePath");
148
            Contract.EndContractBlock();
149

    
150
            Execute((session, instance) =>
151
            {
152
                const string hqlUpdate = "update FileState set FileStatus= :status where FilePath = :path  ";
153
                var updatedEntities = session.CreateQuery(hqlUpdate)
154
                        .SetString("path", absolutePath.ToLower())
155
                        .SetEnum("status", newStatus)
156
                        .ExecuteUpdate();
157
                if (updatedEntities == 0)
158
                {
159
                    var newState = new FileState { FilePath = absolutePath.ToLower(), Id = Guid.NewGuid(), FileStatus = newStatus };
160
                    newState.CreateAndFlush();
161
                }
162
                return null;
163
            }, null);
164

    
165
        }
166

    
167
        public static void StoreOverlayStatus(string absolutePath, FileOverlayStatus newStatus)
168
        {
169
            if (string.IsNullOrWhiteSpace(absolutePath))
170
                throw new ArgumentNullException("absolutePath");
171
            Contract.EndContractBlock();
172

    
173
            Execute((session, instance) =>
174
            {
175
                const string hqlUpdate = "update FileState set OverlayStatus= :status where FilePath = :path  ";
176
                var updatedEntities = session.CreateQuery(hqlUpdate)
177
                        .SetString("path", absolutePath.ToLower())
178
                        .SetEnum("status", newStatus)
179
                        .ExecuteUpdate();
180
                if (updatedEntities == 0)
181
                {
182
                    var newState = new FileState { FilePath = absolutePath, Id = Guid.NewGuid(), OverlayStatus = newStatus };
183
                    newState.CreateAndFlush();
184
                }
185
                return null;
186
            }, null);
187

    
188
        }
189

    
190
        public static void UpdateStatus(string absolutePath, FileStatus fileStatus, FileOverlayStatus overlayStatus)
191
        {
192
            if (string.IsNullOrWhiteSpace(absolutePath))
193
                throw new ArgumentNullException("absolutePath");
194
            Contract.EndContractBlock();
195

    
196
            Execute((session, instance) =>
197
            {
198
                const string hqlUpdate = "update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus where FilePath = :path  ";
199
                var updatedEntities = session.CreateQuery(hqlUpdate)
200
                        .SetString("path", absolutePath.ToLower())
201
                        .SetEnum("fileStatus", fileStatus)
202
                        .SetEnum("overlayStatus", overlayStatus)
203
                        .ExecuteUpdate();
204
                return updatedEntities;
205
            }, null);
206

    
207
        }
208
        public static void UpdateStatus(string absolutePath, FileStatus fileStatus)
209
        {
210
            if (string.IsNullOrWhiteSpace(absolutePath))
211
                throw new ArgumentNullException("absolutePath");
212
            Contract.EndContractBlock();
213

    
214
            Execute((session, instance) =>
215
            {
216
                const string hqlUpdate = "update FileState set FileStatus= :fileStatus where FilePath = :path  ";
217
                var updatedEntities = session.CreateQuery(hqlUpdate)
218
                        .SetString("path", absolutePath.ToLower())
219
                        .SetEnum("fileStatus", fileStatus)                        
220
                        .ExecuteUpdate();
221
                return updatedEntities;
222
            }, null);
223

    
224
        }
225

    
226
        public static void RenameState(string oldPath, string newPath)
227
        {
228
            if (string.IsNullOrWhiteSpace(oldPath))
229
                throw new ArgumentNullException("oldPath");
230
            Contract.EndContractBlock();
231

    
232
            Execute((session, instance) =>
233
            {
234
                const string hqlUpdate = "update FileState set FilePath= :newPath where FilePath = :oldPath  ";
235
                var updatedEntities = session.CreateQuery(hqlUpdate)
236
                        .SetString("oldPath", oldPath.ToLower())
237
                        .SetString("newPath", newPath.ToLower())                                          
238
                        .ExecuteUpdate();
239
                return updatedEntities;
240
            }, null);
241

    
242
        }
243

    
244
        public static void UpdateStatus(Guid id, FileStatus fileStatus)
245
        {
246
            Contract.EndContractBlock();
247

    
248
            Execute((session, instance) =>
249
            {
250
                const string hqlUpdate = "update FileState set FileStatus= :fileStatus where Id = :id  ";
251
                var updatedEntities = session.CreateQuery(hqlUpdate)
252
                        .SetGuid("id", id)
253
                        .SetEnum("fileStatus", fileStatus)                        
254
                        .ExecuteUpdate();
255
                return updatedEntities;
256
            }, null);
257

    
258
        }
259

    
260
        public static void UpdateChecksum(string absolutePath, string checksum)
261
        {
262
            if (string.IsNullOrWhiteSpace(absolutePath))
263
                throw new ArgumentNullException("absolutePath");
264
            Contract.EndContractBlock();
265

    
266
            Execute((session, instance) =>
267
            {
268
                const string hqlUpdate = "update FileState set Checksum= :checksum where FilePath = :path  ";
269
                var updatedEntities = session.CreateQuery(hqlUpdate)
270
                        .SetString("path", absolutePath.ToLower())
271
                        .SetString("checksum", checksum)                        
272
                        .ExecuteUpdate();
273
                return updatedEntities;
274
            }, null);
275

    
276
        }
277

    
278
        public static void ChangeRootPath(string oldPath,string newPath)
279
        {
280
            if (String.IsNullOrWhiteSpace(oldPath))
281
                throw new ArgumentNullException("oldPath");
282
            if (!Path.IsPathRooted(oldPath))
283
                throw new ArgumentException("oldPath must be an absolute path", "oldPath");
284
            if (string.IsNullOrWhiteSpace(newPath))
285
                throw new ArgumentNullException("newPath");
286
            if (!Path.IsPathRooted(newPath))
287
                throw new ArgumentException("newPath must be an absolute path", "newPath");
288
            Contract.EndContractBlock();
289

    
290
            //Ensure the paths end with the same character
291
            if (!oldPath.EndsWith("\\"))
292
                oldPath = oldPath + "\\";
293
            if (!newPath.EndsWith("\\"))
294
                newPath = newPath + "\\";
295

    
296
            using (new TransactionScope())
297
            {
298
                Execute((session, instance) =>
299
                            {
300
                                const string hqlUpdate =
301
                                    "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' ";
302
                                var renames=session.CreateQuery(hqlUpdate)
303
                                    .SetString("oldPath", oldPath.ToLower())
304
                                    .SetString("newPath", newPath.ToLower())
305
                                    .ExecuteUpdate();
306
                                return renames;
307
                            }, null);
308
            }
309
        }
310

    
311
        public static Task<FileState> CreateForAsync(string filePath,int blockSize,string algorithm)
312
        {
313
            if (blockSize <= 0)
314
                throw new ArgumentOutOfRangeException("blockSize");
315
            if (String.IsNullOrWhiteSpace(algorithm))
316
                throw new ArgumentNullException("algorithm");
317
            Contract.EndContractBlock();
318

    
319

    
320
            var fileState = new FileState
321
                                {
322
                                    FilePath = filePath.ToLower(), 
323
                                    OverlayStatus = FileOverlayStatus.Unversioned, 
324
                                    FileStatus = FileStatus.Created,
325
                                    Id=Guid.NewGuid()
326
                                };
327

    
328

    
329
            return fileState.UpdateHashesAsync(blockSize,algorithm);            
330
        }
331

    
332
        public async Task<FileState> UpdateHashesAsync(int blockSize,string algorithm)
333
        {
334
            if (blockSize<=0)
335
                throw new ArgumentOutOfRangeException("blockSize");
336
            if (String.IsNullOrWhiteSpace(algorithm))
337
                throw new ArgumentNullException("algorithm");
338
            Contract.EndContractBlock();
339
            
340
            //Skip updating the hash for folders
341
            if (Directory.Exists(FilePath))
342
                return this;
343

    
344
            var hash = await TaskEx.Run(() =>
345
            {
346
                var info = new FileInfo(FilePath);
347
                return info.CalculateHash(blockSize, algorithm);
348
            });
349

    
350
            Checksum = hash;
351
            
352
            return this;
353
        }
354
    }
355

    
356
    [ActiveRecord("Tags")]
357
    public class FileTag : ActiveRecordLinqBase<FileTag>
358
    {
359
        [PrimaryKey]
360
        public int Id { get; set; }
361

    
362
        [Property]
363
        public string Name { get; set; }
364

    
365
        [Property]
366
        public string Value { get; set; }
367

    
368
        [BelongsTo("FileStateId")]
369
        public FileState FileState { get; set; }
370

    
371
    }
372
   
373
}