/// <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="Zongsoft.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); }
internal static Type GetOwnerElementType(PluginTreeNode node) { var ownerNode = node.Tree.GetOwnerNode(node); if (ownerNode == null) { return(null); } var ownerType = ownerNode.ValueType; if (ownerType == null) { var owner = ownerNode.UnwrapValue(ObtainMode.Never); if (owner == null) { return(null); } ownerType = owner.GetType(); } var elementType = GetImplementedCollectionElementType(ownerType); if (elementType != null) { return(elementType); } MemberInfo[] members = null; var memberAttribute = ownerType.GetCustomAttribute <DefaultMemberAttribute>(true); if (memberAttribute != null) { members = ownerType.GetMember(memberAttribute.MemberName, BindingFlags.Public | BindingFlags.Instance); } else { var propertyAttribute = ownerType.GetCustomAttribute <DefaultPropertyAttribute>(true); if (propertyAttribute != null) { members = ownerType.GetMember(propertyAttribute.Name, BindingFlags.Public | BindingFlags.Instance); } } if (members != null && members.Length == 1) { switch (members[0].MemberType) { case MemberTypes.Field: return(GetImplementedCollectionElementType(((FieldInfo)members[0]).FieldType)); case MemberTypes.Property: return(GetImplementedCollectionElementType(((PropertyInfo)members[0]).PropertyType)); } } return(null); }
internal AppenderContext(object value, PluginTreeNode node, object container, PluginTreeNode containerNode, AppenderBehavior behaviour) { _syncRoot = new object(); _node = node ?? throw new ArgumentNullException(nameof(node)); _value = value; _container = container; _containerNode = containerNode; _behaviour = behaviour; }
internal PluginExtendedProperty(PluginElement owner, string name, PluginTreeNode valueNode, Plugin plugin) : base(owner, name, valueNode) { if (plugin == null) { throw new ArgumentNullException(nameof(plugin)); } _plugin = plugin; }
/// <summary> /// 获取指定节点的所有者对象。 /// </summary> /// <param name="node">要获取的所有者对象的节点。</param> /// <returns>返回指定节点的所有者对象,如果没有则返回空(null)。</returns> /// <remarks> /// <para>注意:该方法不会引起上级节点的创建动作,可确保在<see cref="Zongsoft.Plugins.IBuilder"/>构建器中使用而不会导致循环创建的问题。</para> /// </remarks> internal object GetOwner(PluginTreeNode node) { var ownerNode = this.GetOwnerNode(node); if (ownerNode != null) { return(ownerNode.Value); } return(null); }
internal protected PluginElementProperty(PluginElement owner, string name, PluginTreeNode valueNode) { if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentNullException(nameof(name)); } _name = name.Trim(); _owner = owner ?? throw new ArgumentNullException(nameof(owner)); _valueNode = valueNode ?? throw new ArgumentNullException(nameof(valueNode)); _rawValue = valueNode.FullPath; }
/// <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="Zongsoft.Plugins.PluginTreeNodeType.Builtin"/>并且已经构建完成则返回假(False)。</para> /// <para>如果符合上面的条件,则激发<seealso cref="Zongsoft.Plugins.PluginTree.Mounting"/>事件,挂入成功后激发<seealso cref="Zongsoft.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"); } //确认要挂载的路径对应的节点 PluginTreeNode node = this.EnsurePath(path, position); return(this.Mount(node, value)); }
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); }
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> /// <returns>如果成功卸载则返回被卸载的对象,否则返回空(null)。</returns> /// <exception cref="System.ArgumentNullException">当<paramref name="path"/>参数为空或全空字符串。</exception> /// <exception cref="System.ArgumentException">当<paramref name="path"/>参数对应的节点对象的<see cref="Zongsoft.Plugins.PluginTreeNode.Tree"/>属性与当前插件树对象不是同一个引用。</exception> /// <remarks> /// <para>如果<paramref name="path"/>参数指定的路径不存在,则返回失败。</para> /// <para>如果<paramref name="path"/>参数对应的<seealso cref="Zongsoft.Plugins.PluginTreeNode"/>对象的节点类型(即<seealso cref="Zongsoft.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); } }
/// <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); }
internal static Type GetOwnerElementType(PluginTreeNode node) { var ownerNode = node.Tree.GetOwnerNode(node); if (ownerNode == null) { return(null); } var ownerType = ownerNode.ValueType; if (ownerType == null) { var owner = ownerNode.UnwrapValue(ObtainMode.Never); if (owner == null) { return(null); } ownerType = owner.GetType(); } var elementType = GetImplementedCollectionElementType(ownerType); if (elementType != null) { return(elementType); } var attribute = ownerType.GetCustomAttribute <System.ComponentModel.DefaultPropertyAttribute>(true); if (attribute != null) { var property = ownerType.GetProperty(attribute.Name, BindingFlags.Public | BindingFlags.Instance); if (property != null) { return(GetImplementedCollectionElementType(property.PropertyType)); } } return(null); }
private void StartWorkers(PluginTreeNode node, string[] args) { if (node == null) { return; } object target = node.UnwrapValue(ObtainMode.Auto); if (target is IWorker worker && worker.Enabled) { worker.Start(args); } foreach (PluginTreeNode child in node.Children) { this.StartWorkers(child, args); } }
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); } }
private void StopWorkers(PluginTreeNode node) { if (node == null) { return; } foreach (PluginTreeNode child in node.Children) { this.StopWorkers(child); } object target = node.UnwrapValue(ObtainMode.Never); if (target is IWorker worker) { worker.Stop(); } }
internal AppenderContext(PluginContext pluginContext, object value, PluginTreeNode node, object container, PluginTreeNode containerNode, AppenderBehavior 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); }
internal object ResolvePath(string pathText, PluginTreeNode origin, ObtainMode obtainMode) { if (string.IsNullOrWhiteSpace(pathText)) { throw new ArgumentNullException(nameof(pathText)); } var expression = PluginPath.Parse(pathText); var node = origin.Find(expression.Path); if (node == null) { throw new PluginException($"Not found the PluginTreeNode with '{expression.Path}' path."); } try { //获取指定路径的目标对象 object target = node.UnwrapValue(obtainMode, this, null); if (target != null && expression.Members.Length > 0) { return(Reflection.MemberAccess.GetMemberValue <object>(target, expression.Members)); } return(target); } catch (Exception ex) { var fileName = string.Empty; if (origin != null && origin.Plugin != null) { fileName = System.IO.Path.GetFileName(origin.Plugin.FilePath); } throw new PluginException(string.Format("Resolve target error from '{0}' path in '{1}' plugin file.", pathText, fileName), ex); } }
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); } }
public bool Mount(PluginTreeNode node, object value) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (value is Builtin || value is PluginElement || value is PluginTree || value is PluginContext) { return(false); } //激发“Mounting”事件 this.OnMounting(new PluginMountEventArgs(node.FullPath, value)); //更新节点值 node.Value = value; //激发“Mounted”事件 this.OnMounted(new PluginMountEventArgs(node.FullPath, value)); return(true); }
internal Sitemap(Zongsoft.Plugins.PluginTreeNode sitemapNode) { if(sitemapNode == null) throw new ArgumentNullException("sitemapNode"); _sitemapNode = sitemapNode; }
internal object ResolvePath(string pathText, PluginTreeNode origin) { ObtainMode mode; return(this.ResolvePath(PluginPath.PreparePathText(pathText, out mode), origin, mode)); }
public object Build(PluginTreeNode node) { return(this.Build(node, null, null)); }
public object Build(PluginTreeNode node, object parameter) { return(this.Build(node, parameter, null)); }