root / trunk / Pithos.Core / FileState.cs @ f3d080df
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 |
} |