/// <summary>
        /// This method is called just before a node is updated by the repository.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="node">The node which will be modified.</param>
        /// <param name="modifiedProperties">The updated properties of the node.</param>
        protected override void DoBeforeUpdate(IMansionContext context, Node node, IPropertyBag modifiedProperties)
        {
            // if the name has not changed we are not interested
            string newName;
            if (!modifiedProperties.TryGet(context, "name", out newName))
                return;

            // if the name has not changed after normalization we are not interested
            newName = TagUtilities.Normalize(newName);
            if (node.Pointer.Name.Equals(newName))
            {
                modifiedProperties.Remove("name");
                return;
            }
            modifiedProperties.Set("name", newName);

            // if the tag is renamed to another already existing tag, move all content to that existing tag and delete this one
            Node existingTag;
            var tagIndexNode = TagUtilities.RetrieveTagIndexNode(context);
            if (TagUtilities.TryRetrieveTagNode(context, tagIndexNode, newName, out existingTag))
            {
                // TODO: move all content to the existing tag

                // TODO: delete this tag
            }
        }
        /// <summary>
        /// Renders a navigation tree.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="navigationNode">Root <see cref="Node"/> of the navigation tree.</param>
        /// <param name="cssClasses">The CSS classes used for this navigation.</param>
        /// <returns>Returns the HTML of the navigation tree.</returns>
        public string Evaluate(IMansionContext context, Node navigationNode, string cssClasses)
        {
            // validate arguments
            if (context == null)
                throw new ArgumentNullException("context");
            if (navigationNode == null)
                throw new ArgumentNullException("navigationNode");
            if (string.IsNullOrEmpty(cssClasses))
                throw new ArgumentNullException("cssClasses");

            // get the current URL node
            var urlNode = context.Stack.Peek<Node>("UrlNode");

            // retrieve all the children of the navigation root node
            var navigationItemNodeset = RetrieveNavigationItemNodeset(context, navigationNode);

            // build the tree structure
            var navigationTree = BuildTreeStructure(context, navigationNode, navigationItemNodeset, urlNode.Pointer);

            // render the tree
            using (context.Stack.Push("ControlProperties", new PropertyBag
                                                           {
                                                           	{"cssClasses", cssClasses}
                                                           }))
                return RenderNavigationTree(context, navigationTree);
        }
		/// <summary>
		/// Builds the folder url of the specified <paramref name="folderNode"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="assetTypeNode">The asset type node.</param>
		/// <param name="folderNode">The asset folder node.</param>
		/// <returns>Returns the <see cref="Url"/>.</returns>
		public static Url GetUrl(IMansionContext context, Node assetTypeNode, Node folderNode)
		{
			// validate arguments
			if (context == null)
				throw new ArgumentNullException("context");
			if (assetTypeNode == null)
				throw new ArgumentNullException("assetTypeNode");
			if (folderNode == null)
				throw new ArgumentNullException("folderNode");

			// get the web context
			var webContext = context.Cast<IMansionWebContext>();

			// get the path
			var folderPath = GetPath(assetTypeNode, folderNode);

			// create an url
			var url = Url.CreateUrl(webContext);

			// create the relative path
			url.PathSegments = WebUtilities.CombineIntoRelativeUrl(StaticContentRequestHandler.Prefix, folderPath);
			url.CanHaveExtension = true;

			// create the url
			return url;
		}
        /// <summary>
        /// Generates a URL for <paramref name="node"/>.
        /// </summary>
        /// <param name="context">The <see cref="IMansionWebContext"/>.</param>
        /// <param name="node">The <see cref="Node"/> for which to generate the URL.</param>
        /// <returns>Returns the generated <see cref="Url"/>.</returns>
        public Url Generate(IMansionWebContext context, Node node)
        {
            // validate arguments
            if (context == null)
                throw new ArgumentNullException("context");
            if (node == null)
                throw new ArgumentNullException("node");

            // initialize the service
            Initialize(context);

            // get the node type
            var nodeType = typeService.Load(context, node.Pointer.Type);

            // get the generator
            NodeUrlGenerator generator;
            if (!generators.TryGetValue(nodeType, out generator))
                throw new InvalidOperationException(string.Format("Could not find url generator for type {0}, does the type exist?", nodeType.Name));

            // construct the base url
            var url = Url.CreateUrl(context);

            // generate the url
            generator.Generate(context, node, nodeType, url);

            // return the generated uri
            return url;
        }
		/// <summary>
		/// Prepares an insert query.
		/// </summary>
		/// <param name="context"></param>
		/// <param name="connection">The connection.</param>
		/// <param name="transaction">The transaction.</param>
		/// <param name="sourceNode"></param>
		/// <param name="targetParentNode"></param>
		/// <returns></returns>
		public void Prepare(IMansionContext context, SqlConnection connection, SqlTransaction transaction, Node sourceNode, Node targetParentNode)
		{
			// validate arguments
			if (connection == null)
				throw new ArgumentNullException("connection");
			if (transaction == null)
				throw new ArgumentNullException("transaction");
			if (sourceNode == null)
				throw new ArgumentNullException("sourceNode");
			if (targetParentNode == null)
				throw new ArgumentNullException("targetParentNode");

			// get the properties of the new node
			var newProperties = new PropertyBag(sourceNode);

			// if the target pointer is the same as the parent of the source node, generate a new name to distinguish between the two.
			if (sourceNode.Pointer.Parent == targetParentNode.Pointer)
			{
				// get the name of the node
				var name = sourceNode.Get<string>(context, "name");

				// change the name to indicate the copied node
				newProperties.Set("name", name + CopyPostfix);
			}

			// create an insert query
			command = context.Nucleus.CreateInstance<InsertNodeCommand>();
			command.Prepare(context, connection, transaction, targetParentNode.Pointer, newProperties);
		}
Beispiel #6
0
		/// <summary>
		/// </summary>
		/// <param name="context"></param>
		/// <param name="node"></param>
		/// <returns></returns>
		public bool Evaluate(IMansionContext context, Node node)
		{
			// valdidate arguments
			if (context == null)
				throw new ArgumentNullException("context");

			return node != null;
		}
        /// <summary>
        /// This method is called just before a node is updated by the repository.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="node">The node which will be modified.</param>
        /// <param name="modifiedProperties">The updated properties of the node.</param>
        protected override void DoBeforeUpdate(IMansionContext context, Node node, IPropertyBag modifiedProperties)
        {
            // get the variables
            string currentTheme;
            var hasCurrentTheme = node.TryGet(context, "theme", out currentTheme) && !string.IsNullOrEmpty(currentTheme);
            string newTheme;
            var hasNewTheme = modifiedProperties.TryGet(context, "theme", out newTheme) && !string.IsNullOrEmpty(newTheme);

            // do nothing when the page does not have a theme yet
            if (!hasCurrentTheme)
                return;

            // retrieve the schema of the current theme
            var currentThemeSchema = ColumnSchema.GetSchema(context, currentTheme);

            // retrieve the blocks of this page
            var repository = context.Repository;
            var blockNodeset = repository.Retrieve(context, repository.ParseQuery(context, new PropertyBag
                                                                                           {
                                                                                           	{"baseType", "Block"},
                                                                                           	{"parentSource", node}
                                                                                           }));

            // check if a new theme is selected
            if (hasNewTheme)
            {
                // retrieve the schema of the new theme
                var newThemeSchema = ColumnSchema.GetSchema(context, newTheme);

                // loop through the blocks to find obsolete ones
                foreach (var blockNode in blockNodeset.Nodes)
                {
                    // get the column of this block
                    var column = blockNode.Get<string>(context, "column");

                    // check if this block lived in the old theme
                    if (!currentThemeSchema.ContainsColumn(column))
                        continue;

                    // check if the column exists in the new theme as well
                    if (newThemeSchema.ContainsColumn(column))
                        continue;

                    // block is obsolete delete it
                    repository.Delete(context, blockNode.Pointer);
                }
            }
            else
            {
                // theme is removed, delete all the theme blocks
                foreach (var blockNode in blockNodeset.Nodes.Where(candidate => currentThemeSchema.ContainsColumn(candidate.Get<string>(context, "column"))))
                    repository.Delete(context, blockNode.Pointer);
            }

            base.DoBeforeUpdate(context, node, modifiedProperties);
        }
Beispiel #8
0
        /// <summary>
        /// Generates a URL for the node.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="node">The <see cref="Node"/> for which to generate the URL.</param>
        /// <returns>The <see cref="Uri"/> generated for the <paramref name="node"/>.</returns>
        public Url Evaluate(IMansionContext context, Node node)
        {
            // validate arguments
            if (context == null)
                throw new ArgumentNullException("context");
            if (node == null)
                throw new ArgumentNullException("node");

            // return the url
            return nodeUrlService.Generate(context.Cast<IMansionWebContext>(), node);
        }
		/// <summary>
		/// Builds the asset path of the specified <paramref name="folderNode"/>.
		/// </summary>
		/// <param name="assetTypeNode">The asset type node.</param>
		/// <param name="folderNode">The asset folder node.</param>
		/// <returns>Returns the path.</returns>
		public static string GetPath(Node assetTypeNode, Node folderNode)
		{
			// validate arguments
			if (assetTypeNode == null)
				throw new ArgumentNullException("assetTypeNode");
			if (folderNode == null)
				throw new ArgumentNullException("folderNode");

			// build the url
			return string.Join("/", new[] {"Assets"}.Concat(folderNode.Pointer.Path.Skip(assetTypeNode.Pointer.Depth - 1)));
		}
		/// <summary>
		/// Updates an existing node in this repository.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="node">The node which will be updated.</param>
		/// <param name="properties">The properties which to update.</param>
		protected override Node DoUpdateNode(IMansionContext context, Node node, IPropertyBag properties)
		{
			// update the node
			repository.UpdateNode(context, node, properties);

			// merge the properties
			node.Merge(properties);

			// return the updated node
			return node;
		}
Beispiel #11
0
		/// <summary>
		/// Checks whether the candidate child is a child of the parent.
		/// </summary>
		/// <param name="context"></param>
		/// <param name="child"></param>
		/// <param name="parent"></param>
		/// <returns></returns>
		public bool Evaluate(IMansionContext context, Node child, Node parent)
		{
			// validate arguments
			if (context == null)
				throw new ArgumentNullException("context");
			if (child == null)
				throw new ArgumentNullException("child");
			if (parent == null)
				throw new ArgumentNullException("parent");

			return child.Pointer.IsChildOf(parent.Pointer);
		}
        /// <summary>
        /// This method is called just before a node is created by the repository.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="parent">The parent node to which the new child will be added.</param>
        /// <param name="newProperties">The new properties of the node.</param>
        protected override void DoBeforeCreate(IMansionContext context, Node parent, IPropertyBag newProperties)
        {
            // check if the layout is set
            string layout;
            if (newProperties.TryGet(context, "layout", out layout))
                return;
            if (!parent.TryGet(context, "layout", out layout))
                layout = "OneColumnLayout";

            // set the layout
            newProperties.TrySet("layout", layout);
        }
        /// <summary>
        /// This method is called when an property which is not on the node is accessed. Useful for lazy loading properties.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="node">The <see cref="Node"/> which does not have the property..</param>
        /// <param name="propertyName">The name of the property being retrieved.</param>
        /// <param name="value">The missing value</param>
        protected override bool DoTryResolveMissingProperty(IMansionContext context, Node node, string propertyName, out object value)
        {
            // we do not care about any property except _tags
            if (!"_tags".Equals(propertyName, StringComparison.OrdinalIgnoreCase))
            {
                value = null;
                return false;
            }

            // initialize the _tags attribute
            value = TagUtilities.ToNames(context, node);
            return true;
        }
		/// <summary>
		/// Updates an existing node in this repository.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="node">The node which will be updated.</param>
		/// <param name="modifiedProperties">The properties which to update.</param>
		public void UpdateNode(IMansionContext context, Node node, IPropertyBag modifiedProperties)
		{
			// validate arguments
			if (context == null)
				throw new ArgumentNullException("context");
			if (node == null)
				throw new ArgumentNullException("node");
			if (modifiedProperties == null)
				throw new ArgumentNullException("modifiedProperties");
			CheckDisposed();

			// invoke template method
			DoUpdateNode(context, node, modifiedProperties);
		}
        /// <summary>
        /// Generates an URL for the <paramref name="node"/>.
        /// </summary>
        /// <param name="context">The <see cref="IMansionWebContext"/>.</param>
        /// <param name="node">The <see cref="Node"/> for which to generate the URL.</param>
        /// <param name="nodeType">The <see cref="ITypeDefinition"/> of the node.</param>
        /// <param name="url">The <see cref="Url"/> which to use to build the url.</param>
        public void Generate(IMansionWebContext context, Node node, ITypeDefinition nodeType, Url url)
        {
            // validate arguments
            if (context == null)
                throw new ArgumentNullException("context");
            if (node == null)
                throw new ArgumentNullException("node");
            if (nodeType == null)
                throw new ArgumentNullException("nodeType");
            if (url == null)
                throw new ArgumentNullException("url");

            // invoke template method
            DoGenerate(context, node, nodeType, url);
        }
Beispiel #16
0
		/// <summary>
		/// Creates an instance of <see cref="AssetType"/> from <paramref name="node"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="node">The <see cref="Node"/>.</param>
		/// <returns>Returns the created <see cref="AssetType"/>.</returns>
		public static AssetType Create(IMansionContext context, Node node)
		{
			// validate arguments
			if (context == null)
				throw new ArgumentNullException("context");
			if (node == null)
				throw new ArgumentNullException("node");

			return new AssetType
			       {
			       	Label = node.Pointer.Name,
			       	BasePath = "/" + node.Pointer.Name.ToLower() + "/",
			       	Node = node,
			       	Url = AssetUtil.GetUrl(context, node, node)
			       };
		}
		/// <summary>
		/// Creates an <see cref="AssetEntry"/> instance from <paramref name="node"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="folder">The <see cref="AssetFolder"/>.</param>
		/// <param name="node">The <see cref="Node"/>.</param>
		/// <returns>Returns the created <see cref="AssetEntry"/> instance.</returns>
		public static AssetEntry Create(IMansionContext context, AssetFolder folder, Node node)
		{
			//validate arguments
			if (context == null)
				throw new ArgumentNullException("context");
			if (folder == null)
				throw new ArgumentNullException("folder");
			if (node == null)
				throw new ArgumentNullException("node");

			return new AssetEntry
			       {
			       	AssetFolder = folder,
			       	Name = node.Pointer.Name,
			       	Size = node.Get<long>(context, "size", 0),
			       	ModificationDate = node.Get(context, "modified", DateTime.MinValue)
			       };
		}
        /// <summary>
        /// Generates an URL for the <paramref name="node"/>.
        /// </summary>
        /// <param name="context">The <see cref="IMansionWebContext"/>.</param>
        /// <param name="node">The <see cref="Node"/> for which to generate the URL.</param>
        /// <param name="nodeType">The <see cref="ITypeDefinition"/> of the node.</param>
        /// <param name="url">The <see cref="UriBuilder"/> which to use to build the url.</param>
        protected override void DoGenerate(IMansionWebContext context, Node node, ITypeDefinition nodeType, Url url)
        {
            // get the site node from the stack
            Node siteNode;
            if (!context.Stack.TryPeek("SiteNode", out siteNode))
                throw new InvalidOperationException("Could not find sitenode on the stack, please check application configuration.");

            // resolve the template page for this node
            Node templatePageNode;
            if (!portalService.TryResolveTemplatePage(context, siteNode, node, out templatePageNode))
                throw new InvalidOperationException(string.Format("Could not find template page for node {0} ({1})", node.Pointer.PathString, node.Pointer.PointerString));

            // construct the path
            var sitePathParts = templatePageNode.Pointer.Hierarchy.SkipWhile(candidate => !siteNode.Pointer.IsParentOf(candidate)).TakeWhile(candidate => candidate.Id != templatePageNode.Pointer.Id).ToArray();
            var contentPathParts = node.Pointer.Hierarchy.Skip(2).ToArray();

            url.PathSegments = new[] {node.Pointer.Id.ToString(CultureInfo.InvariantCulture)}.Concat(sitePathParts.Select(pointer => pointer.Name)).Concat(contentPathParts.Select(pointer => pointer.Name)).ToArray();
        }
		/// <summary>
		/// Creates a new node in this repository.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parent">The parent node.</param>
		/// <param name="newProperties">The properties of the node which to create.</param>
		/// <returns>Returns the created nodes.</returns>
		public Node CreateNode(IMansionContext context, Node parent, IPropertyBag newProperties)
		{
			// validate arguments
			if (context == null)
				throw new ArgumentNullException("context");
			if (parent == null)
				throw new ArgumentNullException("parent");
			if (newProperties == null)
				throw new ArgumentNullException("newProperties");
			CheckDisposed();

			// if no allowedRoleGuids are specified, copy the parens
			if (!newProperties.Contains("allowedRoleGuids"))
				newProperties.Set("allowedRoleGuids", parent.Get(context, "allowedRoleGuids", string.Empty));

			// invoke template method
			return DoCreateNode(context, parent, newProperties);
		}
        /// <summary>
        /// This method is called just before a node is updated by the repository.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="node">The node which will be modified.</param>
        /// <param name="modifiedProperties">The updated properties of the node.</param>
        protected override void DoBeforeUpdate(IMansionContext context, Node node, IPropertyBag modifiedProperties)
        {
            // check if the layout was not modified
            string newLayoutName;
            if (!modifiedProperties.TryGet(context, "layout", out newLayoutName))
                return;

            // check if there was no old layout
            string oldLayoutName;
            if (!node.TryGet(context, "layout", out oldLayoutName))
                return;

            // get the schemas
            var newColumnSchema = ColumnSchema.GetSchema(context, newLayoutName);
            var oldColumnSchema = ColumnSchema.GetSchema(context, oldLayoutName);

            // retrieve the blocks of this page
            var repository = context.Repository;
            var blockNodeset = repository.Retrieve(context, repository.ParseQuery(context, new PropertyBag
                                                                                           {
                                                                                           	{"baseType", "Block"},
                                                                                           	{"parentSource", node}
                                                                                           }));

            // loop through all the nodes
            foreach (var blockNode in blockNodeset.Nodes)
            {
                // check if this block was not in a column of the old schema so it wont have to move to the new schema
                var columnName = blockNode.Get<string>(context, "column");
                if (!oldColumnSchema.ContainsColumn(columnName))
                    continue;

                // check if the column is in the new schema as well so it wont have to move
                if (newColumnSchema.ContainsColumn(columnName))
                    continue;

                // move the block to the default column
                repository.Update(context, blockNode, new PropertyBag
                                                      {
                                                      	{"column", newColumnSchema.DefaultColumn}
                                                      });
            }
        }
        /// <summary>
        /// Generates an URL for the <paramref name="node"/>.
        /// </summary>
        /// <param name="context">The <see cref="IMansionWebContext"/>.</param>
        /// <param name="node">The <see cref="Node"/> for which to generate the URL.</param>
        /// <param name="nodeType">The <see cref="ITypeDefinition"/> of the node.</param>
        /// <param name="url">The <see cref="Url"/> which to use to build the url.</param>
        protected override void DoGenerate(IMansionWebContext context, Node node, ITypeDefinition nodeType, Url url)
        {
            // check if the site node has a prefered host header, or pick the first hostheader
            string preferedHostheader;
            String hostheaderString;
            if (node.TryGet(context, "preferedHostheader", out preferedHostheader) && !string.IsNullOrEmpty(preferedHostheader))
                url.HostName = preferedHostheader;
            else if (node.TryGet(context, "hostheaders", out hostheaderString))
            {
                var hostheaders = hostheaderString.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList();

                // if there are not hostheaders set or the current hostheader is in the hostheaders dont change the host
                if (hostheaders.Count == 0 || hostheaders.Contains(url.HostName, StringComparer.OrdinalIgnoreCase))
                    return;

                // set the new hostheader
                url.HostName = hostheaders[0];
            }
        }
		/// <summary>
		/// Creates an <see cref="AssetFolder"/> instance from the <paramref name="node"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="assetType">The <see cref="AssetType"/>.</param>
		/// <param name="node">The <see cref="Node"/>.</param>
		/// <returns>Returns the constructed <see cref="AssetFolder"/> instance.</returns>
		public static AssetFolder Create(IMansionContext context, AssetType assetType, Node node)
		{
			// validate arguments
			if (context == null)
				throw new ArgumentNullException("context");
			if (assetType == null)
				throw new ArgumentNullException("assetType");
			if (node == null)
				throw new ArgumentNullException("node");

			// create the folder
			return new AssetFolder
			       {
			       	AssetType = assetType,
			       	Path = "/" + node.Pointer.Name.ToLower() + "/",
			       	Label = node.Pointer.Name,
			       	Node = node,
			       	Url = AssetUtil.GetUrl(context, assetType.Node, node)
			       };
		}
        /// <summary>
        /// This method is called just after a node is created by the repository.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="parent">The parent node to which the new child was be added.</param>
        /// <param name="node">The created node.</param>
        /// <param name="newProperties">The properties from which the <paramref name="node"/> was constructed.</param>
        protected override void DoAfterCreate(IMansionContext context, Node parent, Node node, IPropertyBag newProperties)
        {
            // get the layout schema
            string layoutName;
            if (!node.TryGet(context, "layout", out layoutName))
                throw new InvalidOperationException(string.Format("Template page {0} ({1}) does not have a layout", node.Pointer.PathString, node.Pointer.PointerString));
            var layoutSchema = ColumnSchema.GetSchema(context, layoutName);

            // add the content detail block to the primary column
            context.Repository.Create(context, node, new PropertyBag
                                                     {
                                                     	{"name", "Content Detail Block"},
                                                     	{"type", "ContentDetailBlock"},
                                                     	{"approved", true},
                                                     	{"column", layoutSchema.DefaultColumn}
                                                     });

            // invoke base
            base.DoAfterCreate(context, parent, node, newProperties);
        }
        /// <summary>
        /// This method is called just after a node is updated by the repository.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="node">The modified node.</param>
        /// <param name="modifiedProperties">The properties which were set to the updated <paramref name="node"/>.</param>
        protected override void DoAfterUpdate(IMansionContext context, Node node, IPropertyBag modifiedProperties)
        {
            // loop over all the updated properties to find those who start with _propagate
            foreach (var propagatePropertyName in modifiedProperties.Names.Where(x => x.StartsWith(PropagatePrefix, StringComparison.OrdinalIgnoreCase)))
            {
                // get the name of the property being propagated
                var propagatedPropertyName = propagatePropertyName.Substring(PropagatePrefix.Length);

                // get the propagated property value
                var propagatedPropertyValue = modifiedProperties.Get<object>(context, propagatedPropertyName);

                // retrieve all the children nodes and update them all
                foreach (var childNode in context.Repository.Retrieve(context, new PropertyBag
                                                                               {
                                                                               	{"parentSource", node}, {"depth", "any"}
                                                                               }).Nodes)
                {
                    context.Repository.Update(context, childNode, new PropertyBag
                                                                  {
                                                                  	{propagatedPropertyName, propagatedPropertyValue}
                                                                  });
                }
            }
        }
		/// <summary>
		/// Deletes an existing node from this repository.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="node">The pointer to the node which will be deleted.</param>
		public void DeleteNode(IMansionContext context, Node node)
		{
			// validate arguments
			if (context == null)
				throw new ArgumentNullException("context");
			if (node == null)
				throw new ArgumentNullException("node");
			CheckDisposed();

			// invoke template method
			DoDeleteNode(context, node);
		}
        /// <summary>
        /// Retrieves the tag <see cref="Node"/> with name <paramref name="tagName"/>. Creates one when no exists.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="tagIndexNode">The tag index node.</param>
        /// <param name="tagName">The name of the tag.</param>
        /// <returns>Returns the <see cref="Node"/> representing the tag index.</returns>
        public static Node RetrieveTagNode(IMansionContext context, Node tagIndexNode, string tagName)
        {
            // validate arguments
            if (context == null)
                throw new ArgumentNullException("context");
            if (tagIndexNode == null)
                throw new ArgumentNullException("tagIndexNode");
            tagName = Normalize(tagName);
            if (string.IsNullOrEmpty(tagName))
                throw new ArgumentNullException("tagName");

            // get the repository
            var repository = context.Repository;

            // retrieve the tag or create it
            return repository.RetrieveSingleNode(context, new PropertyBag
                                                      {
                                                      	{"parentSource", tagIndexNode},
                                                      	{"name", tagName},
                                                      	{"type", "Tag"}
                                                      }) ?? repository.CreateNode(context, tagIndexNode, new PropertyBag
                                                                                                     {
                                                                                                     	{"name", tagName},
                                                                                                     	{"type", "Tag"},
                                                                                                     	{"approved", true},
                                                                                                     });
        }
        /// <summary>
        /// Tries to retrieve the tag <see cref="Node"/> with name <paramref name="tagName"/>.
        /// </summary>
        /// <param name="context">The <see cref="IMansionContext"/>.</param>
        /// <param name="tagIndexNode">The tag index node.</param>
        /// <param name="tagName">The name of the tag.</param>
        /// <param name="tagNode"></param>
        /// <returns>Returns true when the node was found, otherwise false.</returns>
        public static bool TryRetrieveTagNode(IMansionContext context, Node tagIndexNode, string tagName, out Node tagNode)
        {
            // validate arguments
            if (context == null)
                throw new ArgumentNullException("context");
            if (tagIndexNode == null)
                throw new ArgumentNullException("tagIndexNode");
            tagName = Normalize(tagName);
            if (string.IsNullOrEmpty(tagName))
                throw new ArgumentNullException("tagName");

            // get the repository
            var repository = context.Repository;

            // retrieve the node
            tagNode = repository.RetrieveSingleNode(context, new PropertyBag
                                                         {
                                                         	{"parentSource", tagIndexNode},
                                                         	{"name", tagName},
                                                         	{"type", "Tag"}
                                                         });
            return tagNode != null;
        }
		/// <summary>
		/// Deletes an existing node from this repository.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="node">The pointer to the node which will be deleted.</param>
		protected abstract void DoDeleteNode(IMansionContext context, Node node);
		/// <summary>
		/// Updates an existing node in this repository.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="node">The node which will be updated.</param>
		/// <param name="modifiedProperties">The properties which to update.</param>
		protected abstract void DoUpdateNode(IMansionContext context, Node node, IPropertyBag modifiedProperties);
		/// <summary>
		/// Creates a new node in this repository.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parent">The parent node.</param>
		/// <param name="newProperties">The properties of the node which to create.</param>
		/// <returns>Returns the created nodes.</returns>
		protected abstract Node DoCreateNode(IMansionContext context, Node parent, IPropertyBag newProperties);