internal PluginExtendedProperty(PluginElement owner, string name, PluginTreeNode valueNode, Plugin plugin) { if (owner == null) { throw new ArgumentNullException("owner"); } if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentNullException("name"); } if (valueNode == null) { throw new ArgumentNullException("valueNode"); } if (plugin == null) { throw new ArgumentNullException("plugin"); } _owner = owner; _name = name.Trim(); _valueNode = valueNode; _rawValue = valueNode.FullPath; _plugin = plugin; _syncRoot = new object(); }
/// <summary> /// 挂载对象到插件树中。 /// </summary> /// <param name="path">要挂载的路径。</param> /// <param name="value">要挂载的对象。</param> /// <param name="position">当挂载路径对应的叶子节点不存在时,由该参数确认其插入的位置,如果该参数为空(null)或空字符串则默认追加到同级节点的最后。</param> /// <returns>挂载成功则返回真(True)否则返回假(False)。</returns> /// <remarks> /// <para>注意:如果<paramref name="path"/>参数指定的路径对应的插件树节点已经存在,并且节点类型为<seealso cref="Tiandao.Plugins.PluginTreeNodeType.Builtin"/>并且已经构建完成则返回假(False)。</para> /// <para>如果符合上面的条件,则激发<seealso cref="Tiandao.Plugins.PluginTree.Mounting"/>事件,挂入成功后激发<seealso cref="Tiandao.Plugins.PluginTree.Mounted"/>事件。</para> /// <para>如果<paramref name="path"/>参数指定的路径不存在,则创建它并挂载由<paramref name="value"/>参数指定的对象。</para> /// </remarks> public bool Mount(string path, object value, string position) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException("path"); } //查找要挂载的路径对应的节点,如果路径查找失败则获取到的是空(null) PluginTreeNode node = this.Find(path); //如果指定挂载路径的节点是已经构建完成的构件则本次挂载操作失败,并返回假(false) if (node != null && node.NodeType == PluginTreeNodeType.Builtin && ((Builtin)node.Value).IsBuilded) { return(false); } //激发“Mounting”事件 this.OnMounting(new PluginMountEventArgs(path, value)); if (node == null) { this.MountItem(path, value, position); } else { node.Value = value; } //激发“Mounted”事件 this.OnMounted(new PluginMountEventArgs(path, value)); return(true); }
/// <summary> /// 卸载指定插件树节点对应的自定义对象。 /// </summary> /// <param name="node">指定要卸载对象的挂靠节点。</param> /// <returns>如果成功卸载则返回被卸载的对象,否则返回空(null)。</returns> /// <exception cref="System.ArgumentNullException">当<paramref name="node"/>参数为空(null)。</exception> /// <exception cref="System.ArgumentException">当<paramref name="node"/>参数的<see cref="Tiandao.Plugins.PluginTreeNode.Tree"/>属性与当前插件树对象不是同一个引用。</exception> /// <remarks> /// <para>注意:当前该方法的实现是不完备的,请谨慎使用!</para> /// <para>将<paramref name="node"/>参数指定的节点对象的Value属性置空,导致该节点类型成为路径节点(即空节点)。</para> /// <para>如果<paramref name="node"/>参数指定的节点对象没有子节点了,则将该节点从插件树中删除,否则保留。</para> /// </remarks> public object Unmount(PluginTreeNode node) { if (node == null) { return(null); } if (!object.ReferenceEquals(node.Tree, this)) { throw new ArgumentException(); } //以永不构建的方式获取当前节点的目标对象 var value = node.UnwrapValue(ObtainMode.Never, null); //将当前节点置空 node.Value = null; //判断当前节点是否为叶子节点,如果是则将其删除 if (node.Children.Count == 0) { node.Remove(); } //返回被卸载的目标对象 return(value); }
/// <summary> /// 获取指定节点的所有者对象。 /// </summary> /// <param name="node">要获取的所有者对象的节点。</param> /// <returns>返回指定节点的所有者对象,如果没有则返回空(null)。</returns> /// <remarks> /// <para>注意:该方法不会引起上级节点的创建动作,可确保在<see cref="Tiandao.Plugins.IBuilder"/>构建器中使用而不会导致循环创建的问题。</para> /// </remarks> internal object GetOwner(PluginTreeNode node) { var ownerNode = this.GetOwnerNode(node); if (ownerNode != null) { return(ownerNode.Value); } return(null); }
private void UnmountItem(Plugin plugin, string path) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException("path"); } PluginTreeNode node = this.Find(path); if (node != null) { this.UnmountItem(plugin, node); } }
/// <summary> /// 生成指定插件节点对应的目标对象。 /// </summary> /// <param name="node">指定要构建的插件树节点。</param> /// <param name="parameter">调用者需要传递给构建器的参数对象。</param> /// <param name="build">由调用者指定的构建委托,如果为空则使用对应的构建器的构建动作。</param> /// <returns>返回构建成功的目标,如果指定的<paramref name="node"/>类型不是<see cref="PluginTreeNodeType.Builtin"/>则返回节点的<see cref="PluginTreeNode.Value"/>属性值。</returns> public object Build(PluginTreeNode node, object parameter, Action <Builders.BuilderContext> build) { if (node == null) { throw new ArgumentNullException("node"); } if (_status != PluginTreeStatus.Loaded) { throw new InvalidOperationException(); } return(node.Build(parameter, build)); }
internal PluginTree(PluginContext context) { if (context == null) { throw new ArgumentNullException("context"); } _syncRoot = new object(); _loader = null; _context = context; _status = PluginTreeStatus.None; _resolver = new PluginResolver(this); _rootNode = new PluginTreeNode(this); }
/// <summary> /// 卸载指定路径的自定义对象。 /// </summary> /// <param name="path">指定要卸载的路径。</param> /// <returns>如果成功卸载则返回被卸载的对象,否则返回空(null)。</returns> /// <exception cref="System.ArgumentNullException">当<paramref name="path"/>参数为空或全空字符串。</exception> /// <exception cref="System.ArgumentException">当<paramref name="path"/>参数对应的节点对象的<see cref="Tiandao.Plugins.PluginTreeNode.Tree"/>属性与当前插件树对象不是同一个引用。</exception> /// <remarks> /// <para>如果<paramref name="path"/>参数指定的路径不存在,则返回失败。</para> /// <para>如果<paramref name="path"/>参数对应的<seealso cref="Tiandao.Plugins.PluginTreeNode"/>对象的节点类型(即<seealso cref="Tiandao.Plugins.PluginTreeNode.NodeType"/>属性)不是自定义对象,则返回失败。</para> /// <para>有关本方法的卸载逻辑请参考<see cref="Unmount(PluginTreeNode)"/>重载方法。</para> /// </remarks> public object Unmount(string path) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException("path"); } PluginTreeNode node = this.Find(path); if (node == null) { return(null); } return(this.Unmount(node)); }
protected virtual void OnStop() { if (string.IsNullOrEmpty(_startupPath)) { return; } //获取启动路径对应的节点对象 PluginTreeNode startupNode = _applicationContext.PluginContext.PluginTree.Find(_startupPath); //停止启动路径下的所有工作者 if (startupNode != null) { this.StopWorkers(startupNode); } }
public object Build(string path, object parameter, Action <Builders.BuilderContext> build) { if (_status == PluginTreeStatus.None) { throw new InvalidOperationException(); } PluginTreeNode node = this.Find(path); if (node == null) { return(null); } return(this.Build(node, parameter, build)); }
/// <summary> /// 获取或创建指定路径的插件树节点。 /// </summary> /// <param name="path">要获取或创建的插件路径。</param> /// <param name="position">当创建指定路径对应的叶子节点时,由该参数确认其插入的位置,如果该参数为空(null)或空字符串则默认追加到同级节点的最后。</param> /// <param name="existed">输出参数,如果指定的路径已存在则返回真(true),否则返回假(false)。</param> /// <returns>返回存在的或者新建的节点对象,如果指定的<paramref name="path"/>路径参数是已存在的,则返回其对应的节点对象否则新建该节点。</returns> public PluginTreeNode EnsurePath(string path, string position, out bool existed) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException("path"); } existed = true; PluginTreeNode node = _rootNode; string[] parts = path.Split('/'); lock (_syncRoot) { for (int i = 0; i < parts.Length; i++) { string part = parts[i]; if (string.IsNullOrEmpty(part)) { if (node == _rootNode) { continue; } else { throw new PluginException("Invlaid '" + path + "' path."); } } PluginTreeNode child = node.Children[part]; if (child == null) { child = new PluginTreeNode(this, part); node.Children.Insert(child, position); existed = false; } node = child; } } return(node); }
/// <summary> /// 查找指定路径的插件树节点。 /// </summary> /// <param name="path">指定的路径。</param> /// <returns>如果查找成功则返回对应的插件树节点对象,否则返回空(null)。</returns> /// <exception cref="System.ArgumentNullException">当<paramref name="path"/>参数为空或全空格字符串。</exception> public PluginTreeNode Find(string path) { if (string.IsNullOrWhiteSpace(path)) { return(null); } return(_rootNode.Find(path.Split('/'))); //剔除路劲参数的前后空白字符 path = path.Trim(); int current = -1; int last = path.IndexOf('/'); PluginTreeNode node = _rootNode; do { int start = last < 0 ? 0 : last + 1; current = path.IndexOf('/', start); int length = current < 0 ? path.Length - start : current - start; string part = path.Substring(start, length); if (string.IsNullOrEmpty(part)) { return(node); } else { node = node.Children[part]; if (node == null) { return(null); } } if (current < path.Length - 1) { last = current; } } while(current > 0); return(node); }
private void UnmountItem(Plugin plugin, PluginTreeNode node) { if (node == null) { return; } if (plugin != null) { foreach (PluginTreeNode child in node.Children) { this.UnmountItem(plugin, child); } } if (node.NodeType == PluginTreeNodeType.Custom) { this.Unmount(node); return; } if (node.NodeType == PluginTreeNodeType.Builtin) { Builtin builtin = (Builtin)node.Value; if (string.ReferenceEquals(builtin.Plugin, plugin)) { IBuilder builder = node.Plugin.GetBuilder(builtin.BuilderName); if (builder != null) { builder.Destroy(Builders.BuilderContext.CreateContext(builder, builtin, this)); } plugin.UnregisterBuiltin(builtin); node.Value = null; } } if (node.Children.Count < 1 && node.Parent != null) { node.Parent.Children.Remove(node); } }
internal AppenderContext(PluginContext pluginContext, object value, PluginTreeNode node, object container, PluginTreeNode containerNode, AppenderBehaviour behaviour) { if (pluginContext == null) { throw new ArgumentNullException("pluginContext"); } if (node == null) { throw new ArgumentNullException("node"); } _syncRoot = new object(); _pluginContext = pluginContext; _node = node; _value = value; _container = container; _containerNode = containerNode; _behaviour = behaviour; }
public PluginTreeNode GetOwnerNode(PluginTreeNode node) { if (node == null) { return(null); } var parent = node.Parent; if (parent == null) { return(null); } if (parent.NodeType == PluginTreeNodeType.Empty) { return(this.GetOwnerNode(parent)); } return(parent); }
private void EnsureNodes(PluginTreeNode node) { if (node == null) { return; } if (node.NodeType == PluginTreeNodeType.Builtin) { if (!((Builtin)node.Value).IsBuilded) { node.Build(); } return; } foreach (var child in node.Children) { this.EnsureNodes(child); } }
private void StopWorkers(PluginTreeNode node) { if (node == null) { return; } foreach (PluginTreeNode child in node.Children) { this.StopWorkers(child); } object target = node.UnwrapValue(ObtainMode.Never, this, null); if (target is IWorker) { IWorker worker = (IWorker)target; if (!worker.Disabled) { worker.Stop(); } } }
private void StartWorkers(PluginTreeNode node, string[] args) { if (node == null) { return; } object target = node.UnwrapValue(ObtainMode.Auto, this, null); if (target is IWorker) { IWorker worker = (IWorker)target; if (!worker.Disabled) { worker.Start(args); } } foreach (PluginTreeNode child in node.Children) { this.StartWorkers(child, args); } }
internal object ResolvePath(string text, PluginTreeNode current, ObtainMode obtainMode) { PluginPathType pathType; string path; string[] memberNames; if (!PluginPath.TryResolvePath(text, out pathType, out path, out memberNames)) { throw new PluginException(string.Format("Resolve ‘{0}’ plugin-path was failed.", text)); } PluginTreeNode node = null; switch (pathType) { case PluginPathType.Rooted: node = _pluginTree.RootNode; break; case PluginPathType.Parent: node = current.Parent; break; case PluginPathType.Current: node = current; break; } if (node != null && (!string.IsNullOrWhiteSpace(path))) { node = node.Find(path); } //注意:如果没有找到指定路径的对象不需要写日志,在ServicesParser解析中需要先在默认工厂查询指定路径的服务如果查找失败则查找服务工厂集 if (node == null) { return(null); } try { //获取指定路径的目标对象 object target = node.UnwrapValue(obtainMode, this, null); if (target != null && memberNames.Length > 0) { return(Tiandao.Common.Converter.GetValue(target, memberNames)); } return(target); } catch (Exception ex) { var fileName = string.Empty; if (current != null && current.Plugin != null) { fileName = System.IO.Path.GetFileName(current.Plugin.FilePath); } throw new PluginException(FailureCodes.InvalidPath, string.Format("Resolve target error from '{0}' path in '{1}' plugin file.", text, fileName), ex); } }
public object Build(PluginTreeNode node) { return(this.Build(node, null, null)); }
public object Build(PluginTreeNode node, object parameter) { return(this.Build(node, parameter, null)); }