Moved Pithos data and logs from the GRNET folder under AppData to a GRNET\PITHOS...
[pithos-ms-client] / trunk / Pithos.Core / Agents / FileEventIdleBatch.cs
1 #region
2 /* -----------------------------------------------------------------------
3  * <copyright file="FileEventIdleBatch.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.IO;
45 using System.Linq;
46 using System.Reflection;
47 using log4net;
48
49 namespace Pithos.Core.Agents
50 {
51     public class FileEventIdleBatch
52     {
53
54         //Requirements
55         //------------
56         //* The class should group workflow actions according to file name and type
57         //* The class should pass all batched actions to a continuation when
58         //* the batch is triggered.
59         //* Actions should not survice a trigger
60
61         private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62
63         private readonly IdleBatch<FileSystemEventArgs> _idleBatch;
64         private readonly Action<Dictionary<string, FileSystemEventArgs[]>> _callback;
65
66         public FileEventIdleBatch(int idleTimeout, Action<Dictionary<string, FileSystemEventArgs[]>> callback)
67         {
68             _callback = callback;
69             _idleBatch = new IdleBatch<FileSystemEventArgs>(idleTimeout, Process);
70         }
71
72         public void Post(FileSystemEventArgs arg)
73         {
74             if (Log.IsDebugEnabled)
75                 Log.DebugFormat("Batch Post  {0}:{1}", arg.ChangeType.ToString("g"), arg.FullPath);
76
77             _idleBatch.Post(arg);
78         }
79
80         public void ForceTrigger()
81         {
82             _idleBatch.ForceTrigger();
83         }
84
85
86         protected virtual void Process(FileSystemEventArgs[] args)
87         {
88             var dict = new Dictionary<string, FileSystemEventArgs[]>();
89             foreach (var arg in args)
90             {
91
92                 if (arg.ChangeType == WatcherChangeTypes.Created )
93                     dict[arg.FullPath] = new[] { arg };
94                 else if (arg.ChangeType == WatcherChangeTypes.Renamed)
95                 {
96                     var renamedArg = (RenamedEventArgs)arg;
97                     FileSystemEventArgs[] oldValue;
98                     if (dict.TryGetValue(renamedArg.OldFullPath, out oldValue))
99                     {
100                         dict.Remove(renamedArg.OldFullPath);
101                         var last = oldValue.Last();
102                         if (last.ChangeType == WatcherChangeTypes.Created)
103                         {
104                             var createRenamed = new FileSystemEventArgs(WatcherChangeTypes.Created, Path.GetDirectoryName(renamedArg.FullPath),
105                                                                         renamedArg.Name);
106                             dict[renamedArg.FullPath] = new[] {createRenamed};
107                         }
108                         else
109                             dict[renamedArg.FullPath] = new[] { renamedArg };
110                     }
111                     else
112                         dict[renamedArg.FullPath] = new[] { renamedArg};
113                 }
114                 else
115                 {
116                     FileSystemEventArgs[] oldValue;
117                     var hasValue=dict.TryGetValue(arg.FullPath, out oldValue);
118                     var last = hasValue?oldValue.LastOrDefault():null;
119                     
120                     if (last==null || last.ChangeType == WatcherChangeTypes.Changed)
121                     {
122                         dict[arg.FullPath] = new[] { arg};
123                     }
124                     else if (arg.ChangeType == WatcherChangeTypes.Deleted)
125                     {
126                         if (last.ChangeType == WatcherChangeTypes.Created)
127                             dict.Remove(arg.FullPath);
128                         else
129                         {
130                             dict[arg.FullPath] = new[] { arg };
131                         }
132                     }
133                     else if (last.ChangeType == WatcherChangeTypes.Renamed && arg.ChangeType == WatcherChangeTypes.Changed)
134                     {
135                         var newValue = oldValue.Concat(new[] { arg }).ToArray();
136                         dict[arg.FullPath] = newValue;
137                     }
138
139                 }
140             }
141             _callback(dict);
142         }
143
144     }
145
146 }