fan-1.0 /src/sys/dotnet/fan/sys/Service_.cs

Language C# Lines 282
MD5 Hash c34108972d14cfce5e2770796e862a77 Estimated Cost $4,933 (why?)
Repository https://bitbucket.org/bedlaczech/fan-1.0 View Raw File View Project SPDX
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
//
// Copyright (c) 2009, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   30 Mar 09  Andy Frank  Creation
//

using System.Collections;

namespace Fan.Sys
{
  /// <summary>
  /// Service mixin implementation methods.
  /// </summary>
  public class Service_
  {

  //////////////////////////////////////////////////////////////////////////
  // Registry
  //////////////////////////////////////////////////////////////////////////

    private static object m_lock = new object();
    private static Hashtable byService = new Hashtable();  // Service:State
    private static Hashtable byType = new Hashtable();     // Type:Node

    public static List list()
    {
      lock (m_lock)
      {
        Service[] array = new Service[byService.Count];
        byService.Keys.CopyTo(array, 0);
        return new List(Sys.ServiceType, array);
      }
    }

    public static Service find(Type t) { return find(t.qname(), true); }
    public static Service find(Type t, bool check) { return find(t.qname(), check); }
    public static Service find(string qname, bool check)
    {
      lock (m_lock)
      {
        Node node = (Node)byType[qname];
        if (node != null) return node.service;
        if (check) throw UnknownServiceErr.make(qname).val;
        return null;
      }
    }

    public static List findAll(Type t)
    {
      string qname = t.qname();
      List list = new List(Sys.ServiceType);
      lock (m_lock)
      {
        Node node = (Node)byType[qname];
        while (node != null)
        {
          list.add(node.service);
          node = node.next;
        }
      }
      return list.ro();
    }

    static bool isServiceType(Type t)
    {
      return t != Sys.ObjType && t != Sys.ServiceType && t.isPublic();
    }

  //////////////////////////////////////////////////////////////////////////
  // Identity
  //////////////////////////////////////////////////////////////////////////

    public static long hash(Service self)
    {
      return Env.cur().idHash(self);
    }

    // TODO - there appears to be a bug in my
    // emit code that mixins look for this method
    // on the impl class
    public static bool Equals(Service self, object that)
    {
      return self == that;
    }

    public static bool equals(Service self, object that)
    {
      return self == that;
    }

    public static bool isInstalled(Service self)
    {
      lock (m_lock)
      {
        return byService[self] != null;
      }
    }

    public static bool isRunning(Service self)
    {
      lock (m_lock)
      {
        State state = (State)byService[self];
        return state != null && state.running;
      }
    }

  //////////////////////////////////////////////////////////////////////////
  // Lifecycle
  //////////////////////////////////////////////////////////////////////////

    public static Service install(Service self)
    {
      try
      {
        List types = FanObj.@typeof(self).inheritance();
        lock (m_lock)
        {
          // if already installed, short circuit
          if (self.isInstalled()) return self;

          // add to byService map
          byService[self] = new State(self);

          // add to map for each type service implements
          for (int i=0; i<types.sz(); ++i)
          {
            Type t = (Type)types.get(i);
            if (!isServiceType(t)) continue;
            Node node = new Node(self);
            Node x = (Node)byType[t.qname()];
            if (x == null) byType[t.qname()] = node;
            else
            {
              while (x.next != null) x = x.next;
              x.next = node;
            }
          }
        }
      }
      catch (System.Exception e)
      {
        Err.dumpStack(e);
      }
      return self;
    }

    public static Service uninstall(Service self)
    {
      try
      {
        List types = FanObj.@typeof(self).inheritance();
        lock (m_lock)
        {
          // ensure service is stopped
          stop(self);

          // remove from byService map, it not installed short circuit
          if (byService[self] == null) return self;
          byService.Remove(self);

          // remove from map for each type implemented by service
          for (int i=0; i<types.sz(); ++i)
          {
            // get next type in inheritance and check if service type
            Type t = (Type)types.get(i);
            if (!isServiceType(t)) continue;

            // lookup linked list for that type
            Node node = (Node)byType[t.qname()];
            if (node == null) continue;

            // find this thread in the linked list
            Node last = null;
            bool cont = false;
            while (node.service != self)
            {
              last = node;
              node = node.next;
              if (node == null) { cont=true; break; }
            }
            if (cont) continue;

            // update the map or linked list
            if (last == null)
              byType[t.qname()] = node.next;
            else
              last.next = node.next;
          }
        }
      }
      catch (System.Exception e)
      {
        Err.dumpStack(e);
      }
      return self;
    }

    public static Service start(Service self)
    {
      State state = null;
      try
      {
        lock (m_lock)
        {
          // start implies install
          install(self);

          // if already running, short circuit
          state = (State)byService[self];
          if (state.running) return self;

          // put into the running state
          state.running = true;
        }

        // onStart callback (outside of lock)
        self.onStart();
      }
      catch (System.Exception e)
      {
        if (state != null) state.running = false;
        Err.dumpStack(e);
      }
      return self;
    }

    public static Service stop(Service self)
    {
      try
      {
        lock (m_lock)
        {
          // if not running, short circuit
          State state = (State)byService[self];
          if (state == null || !state.running) return self;

          // take out of the running state
          state.running = false;
        }

        // onStop (outside of lock)
        self.onStop();
      }
      catch (System.Exception e)
      {
        Err.dumpStack(e);
      }
      return self;
    }

    public static void onStart(Service self) {}

    public static void onStop(Service self) {}

  //////////////////////////////////////////////////////////////////////////
  // State/Node
  //////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Value for byService map
    /// </summary>
    internal class State
    {
      public State(Service s) { service = s; }
      public Service service;
      public bool running;
    }

    /// <summary>
    /// Value for byType map
    /// </summary>
    internal class Node
    {
      public Node(Service s) { service = s; }
      public Service service;
      public Node next;
    }
  }
}
Back to Top