//--- Methods --- internal void Add(string[] path, int level, DreamFeature feature) { // check if we reached the last part of the feature path if (level == path.Length) { // add feature to signature map SignatureMap.Add(feature); } else { string key = path[level]; DreamFeatureDirectory entry = null; // check if sub-feature already exists if (Subfeatures.TryGetValue(key, out entry)) { entry.Add(path, level + 1, feature); } else { DreamFeatureDirectory tree = new DreamFeatureDirectory(); tree.Add(path, level + 1, feature); Subfeatures.Add(key, tree); } } }
internal void Add(string[] path, int level, DreamFeatureDirectory features) { // check if we reached the last part of the feature path if(level == path.Length) { throw new ArgumentException(string.Format("feature path is already in use ({0})", string.Join("/", path))); } else { string key = path[level]; DreamFeatureDirectory entry = null; Subfeatures.TryGetValue(key, out entry); // check if added feature directory is a leaf node if(level == (path.Length - 1)) { // check if there was an existing sub-feature if(entry != null) { features.CopyAndMergeFrom(entry); Subfeatures[key] = features; } else { Subfeatures.Add(key, features); } } else { // check if a sub-feature needs to be created if(entry == null) { entry = new DreamFeatureDirectory(); Subfeatures.Add(key, entry); } entry.Add(path, level + 1, features); } } }
internal void CopyAndMergeFrom(DreamFeatureDirectory features) { SignatureMap.AddRange(features.SignatureMap); foreach (KeyValuePair <string, DreamFeatureDirectory> pair in features.Subfeatures) { DreamFeatureDirectory entry; if (Subfeatures.TryGetValue(pair.Key, out entry)) { entry.CopyAndMergeFrom(pair.Value); } else { Subfeatures.Add(pair.Key, pair.Value); } } }
//--- Methods --- internal void Add(string[] path, int level, DreamFeature feature) { // check if we reached the last part of the feature path if(level == path.Length) { // add feature to signature map SignatureMap.Add(feature); } else { string key = path[level]; DreamFeatureDirectory entry = null; // check if sub-feature already exists if(Subfeatures.TryGetValue(key, out entry)) { entry.Add(path, level + 1, feature); } else { DreamFeatureDirectory tree = new DreamFeatureDirectory(); tree.Add(path, level + 1, feature); Subfeatures.Add(key, tree); } } }
internal void Add(string[] path, int level, DreamFeatureDirectory features) { // check if we reached the last part of the feature path if (level == path.Length) { throw new ArgumentException(string.Format("feature path is already in use ({0})", string.Join("/", path))); } else { string key = path[level]; DreamFeatureDirectory entry = null; Subfeatures.TryGetValue(key, out entry); // check if added feature directory is a leaf node if (level == (path.Length - 1)) { // check if there was an existing sub-feature if (entry != null) { features.CopyAndMergeFrom(entry); Subfeatures[key] = features; } else { Subfeatures.Add(key, features); } } else { // check if a sub-feature needs to be created if (entry == null) { entry = new DreamFeatureDirectory(); Subfeatures.Add(key, entry); } entry.Add(path, level + 1, features); } } }
protected override Yield Stop(Result result) { if(!IsRunning) { result.Return(); yield break; } try { // BUG #810: announce to all root-level services that we're shutting down // dismiss all pending requests _requestQueue = null; // shutdown all services, except host and sub-services (the latter should be cleaned-up by their owners) _log.Debug("Stopping stand-alone services"); Dictionary<string, ServiceEntry> services; lock(_services) { services = new Dictionary<string, ServiceEntry>(_services); } foreach(KeyValuePair<string, ServiceEntry> entry in services) { if((entry.Value.Owner == null) && !(ReferenceEquals(this, entry.Value.Service))) { StopService(entry.Value.Service.Self); } } // now destroy support services _log.Debug("Stopping host"); } catch(Exception ex) { _log.ErrorExceptionMethodCall(ex, "Stop: host failed to deinitialize"); } // stop storage service if(_storage != null) { yield return _storage.Delete(new Result<DreamMessage>(TimeSpan.MaxValue)).CatchAndLog(_log); _storage = null; } // check if any inner services failed to stop foreach(KeyValuePair<string, ServiceEntry> entry in _services) { _log.WarnMethodCall("Stop: service did not shutdown", entry.Key); } // invoke base.Stop yield return Coroutine.Invoke(base.Stop, new Result()).CatchAndLog(_log); // deinitialize fields _blueprints = null; _registeredTypes.Clear(); _infos.Clear(); _activities.Clear(); _features = new DreamFeatureDirectory(); _services.Clear(); _aliases.Clear(); // mark host as not running Plug.RemoveEndpoint(this); _running = false; _shutdown.Set(); result.Return(); }
private DreamFeatureDirectory CreateServiceFeatureDirectory(IDreamService service, XDoc blueprint, XDoc config) { Type type = service.GetType(); string path = config["path"].Contents.ToLowerInvariant(); // add transport information XUri serviceUri = LocalMachineUri.AtAbsolutePath(path); config.Root.Elem("uri.self", serviceUri.ToString()); // compile list of active service features, combined by suffix int serviceUriSegmentsLength = serviceUri.Segments.Length; DreamFeatureDirectory directory = new DreamFeatureDirectory(); var methodInfos = GetMethodInfos(type); foreach(XDoc featureBlueprint in blueprint["features/feature"]) { string methodName = featureBlueprint["method"].Contents; string pattern = featureBlueprint["pattern"].AsText; // TODO (steveb): we should be a little more discerning here as this might trigger false positives bool atConfig = pattern.ContainsInvariantIgnoreCase("@config"); // locate method var methods = methodInfos[methodName]; if(methods.Count() > 1) { var found = string.Join(", ", methods.Select(m => m.DeclaringType.FullName + "!" + m.Name + "(" + string.Join(", ", m.GetParameters().Select(p => p.ParameterType.Name + " " + p.Name).ToArray()) + ")").ToArray()); throw new MissingMethodException(string.Format("found multiple definitions for {0}: {1}", methodName, found)); } if(methods.None()) { throw new MissingMethodException(string.Format("could not find {0} in class {1}", methodName, type.FullName)); } MethodInfo method = methods.First(); // determine access level DreamAccess access; switch(featureBlueprint["access"].AsText) { case null: case "public": access = DreamAccess.Public; break; case "internal": access = DreamAccess.Internal; break; case "private": access = DreamAccess.Private; break; default: throw new NotSupportedException(string.Format("access level is not supported ({0})", methodName)); } // parse pattern string string[] parts = pattern.Split(new[] { ':' }, 2); string verb = parts[0].Trim(); string signature = parts[1].Trim(); if(signature.Length == 0) { signature = string.Empty; } // add feature prologues List<DreamFeatureStage> stages = new List<DreamFeatureStage>(); stages.AddRange(_defaultPrologues); if(!atConfig) { DreamFeatureStage[] custom = service.Prologues; if(!ArrayUtil.IsNullOrEmpty(custom)) { stages.AddRange(custom); } } // add feature handler int mainStageIndex = stages.Count; stages.Add(new DreamFeatureStage(service, method, access)); // add feature epilogues if(!atConfig) { DreamFeatureStage[] custom = service.Epilogues; if(!ArrayUtil.IsNullOrEmpty(custom)) { stages.AddRange(custom); } } stages.AddRange(_defaultEpilogues); // create dream feature and add to service directory var paramAttributes = method.GetCustomAttributes(typeof(DreamFeatureParamAttribute), false).Cast<DreamFeatureParamAttribute>().ToArray(); DreamFeature feature = new DreamFeature(service, serviceUri, mainStageIndex, stages.ToArray(), verb, signature, paramAttributes); directory.Add(feature.PathSegments, serviceUriSegmentsLength, feature); } return directory; }
internal void CopyAndMergeFrom(DreamFeatureDirectory features) { SignatureMap.AddRange(features.SignatureMap); foreach(KeyValuePair<string, DreamFeatureDirectory> pair in features.Subfeatures) { DreamFeatureDirectory entry; if(Subfeatures.TryGetValue(pair.Key, out entry)) { entry.CopyAndMergeFrom(pair.Value); } else { Subfeatures.Add(pair.Key, pair.Value); } } }