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