-// -----------------------------------------------------------------------\r
-// <copyright file="CollectionExtensions.cs" company="GRNET">\r
-// Copyright 2011-2012 GRNET S.A. All rights reserved.\r
-// \r
-// Redistribution and use in source and binary forms, with or\r
-// without modification, are permitted provided that the following\r
-// conditions are met:\r
-// \r
-// 1. Redistributions of source code must retain the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer.\r
-// \r
-// 2. Redistributions in binary form must reproduce the above\r
-// copyright notice, this list of conditions and the following\r
-// disclaimer in the documentation and/or other materials\r
-// provided with the distribution.\r
-// \r
-// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS\r
-// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
-// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
-// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR\r
-// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\r
-// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\r
-// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
-// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
-// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
-// POSSIBILITY OF SUCH DAMAGE.\r
-// \r
-// The views and conclusions contained in the software and\r
-// documentation are those of the authors and should not be\r
-// interpreted as representing official policies, either expressed\r
-// or implied, of GRNET S.A.\r
-// </copyright>\r
-// -----------------------------------------------------------------------\r
-\r
+#region\r
+/* -----------------------------------------------------------------------\r
+ * <copyright file="CollectionExtensions.cs" company="GRNet">\r
+ * \r
+ * Copyright 2011-2012 GRNET S.A. All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * 2. Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS\r
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\r
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\r
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ * The views and conclusions contained in the software and\r
+ * documentation are those of the authors and should not be\r
+ * interpreted as representing official policies, either expressed\r
+ * or implied, of GRNET S.A.\r
+ * </copyright>\r
+ * -----------------------------------------------------------------------\r
+ */\r
+#endregion\r
using System.Collections.Concurrent;\r
+using System.Diagnostics.Contracts;\r
+using Pithos.Interfaces;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
\r
namespace Pithos.Core.Agents\r
{\r
- using System;\r
- using System.Collections.Generic;\r
- using System.Linq;\r
- using System.Text;\r
\r
/// <summary>\r
/// Extension methods for collections\r
/// </summary>\r
public static class CollectionExtensions\r
{\r
+ public static IEnumerable<T> Replace<T>(this IEnumerable<T> list,Func<T,bool> match, Func<T,IEnumerable<T>> generate)\r
+ {\r
+ foreach (var item in list)\r
+ {\r
+ if (match(item))\r
+ foreach (var newItem in generate(item))\r
+ {\r
+ yield return newItem;\r
+ }\r
+ else\r
+ yield return item;\r
+ }\r
+ }\r
+\r
+\r
/// <summary>\r
/// Remove the first message in a queue that matches the predicate\r
/// </summary>\r
+ /// <param name="queue">The queue</param>\r
/// <param name="predicate">The condition to match</param>\r
/// <remarks>Removes the first message that matches the predicate by dequeing all \r
/// messages and re-enqueing all except the first matching message</remarks>\r
\r
queue.AddFromEnumerable(temp);\r
}\r
+\r
+\r
+ /// <summary>\r
+ /// Return only the info objects that are below one of the filter Uris\r
+ /// </summary>\r
+ /// <param name="infos">ObjectInfo items to filter</param>\r
+ /// <param name="filterUris">List of filter Uris</param>\r
+ /// <returns>An enumerable of ObjectInfo items. If the list of filter Uris is empty or null, the original list is returned</returns>\r
+ public static IEnumerable<ObjectInfo> FilterBelow(this IEnumerable<ObjectInfo> infos,List<Uri> filterUris )\r
+ {\r
+ if (filterUris == null)\r
+ return infos;\r
+ if (filterUris.Count == 0)\r
+ return infos;\r
+ //Allow all objects whose Uris start with any of the filters \r
+ var filteredUris = from info in infos\r
+ where filterUris.Any(f => info.Uri.IsAtOrBelow(f)) \r
+ select info; \r
+ return filteredUris;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Return only the info objects that are directly below one of the filter Uris\r
+ /// </summary>\r
+ /// <param name="infos">ObjectInfo items to filter</param>\r
+ /// <param name="filterUris">List of filter Uris</param>\r
+ /// <returns>An enumerable of ObjectInfo items. If the list of filter Uris is empty or null, the original list is returned</returns>\r
+ public static IEnumerable<ObjectInfo> FilterDirectlyBelow(this IEnumerable<ObjectInfo> infos, List<Uri> filterUris)\r
+ {\r
+ if (filterUris == null)\r
+ return infos;\r
+ if (filterUris.Count == 0)\r
+ return infos;\r
+ //Allow all objects whose Uris start with any of the filters \r
+ var filteredUris = from info in infos\r
+ where filterUris.Any(f => info.Uri.IsAtOrDirectlyBelow(f)) \r
+ select info; \r
+ return filteredUris;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Checkes whether a Uri is below a root Uri\r
+ /// </summary>\r
+ /// <param name="target"></param>\r
+ /// <param name="root"></param>\r
+ /// <returns></returns>\r
+ public static bool IsAtOrBelow(this Uri target,Uri root)\r
+ {\r
+ if(root == null)\r
+ throw new ArgumentNullException("root");\r
+ if(target == null)\r
+ throw new ArgumentNullException("target");\r
+ Contract.EndContractBlock();\r
+\r
+ var targetSegments = target.Segments;\r
+ var rootSegments = root.Segments;\r
+\r
+ return InnerAtOrBelow(targetSegments, rootSegments);\r
+ }\r
+\r
+ private static bool InnerAtOrBelow(string[] targetSegments, string[] rootSegments)\r
+ {\r
+ //If the uri is shorter than the root, no point in comparing\r
+ if (targetSegments.Length < rootSegments.Length)\r
+ return false;\r
+ //If the uri is below the root, it should match the root's segments one by one\r
+ //If there is any root segment that doesn't match its corresponding target segment,\r
+ //the target is not below the root\r
+ //DON'T FORGET that Uri segments include the slashes. Must remove them to ensure proper checks\r
+ var mismatch = rootSegments\r
+ .Where((t, i) => !String.Equals(targetSegments[i].TrimEnd('/'), t.TrimEnd('/'),StringComparison.InvariantCultureIgnoreCase))\r
+ .Any();\r
+ return !mismatch;\r
+ }\r
+\r
+\r
+ /// <summary>\r
+ /// Checks whether a Uri is directly below a root Uri\r
+ /// </summary>\r
+ /// <param name="target"></param>\r
+ /// <param name="root"></param>\r
+ /// <returns></returns>\r
+ public static bool IsAtOrDirectlyBelow(this Uri target,Uri root)\r
+ {\r
+ if (root==null)\r
+ throw new ArgumentNullException("root");\r
+ if (target==null)\r
+ throw new ArgumentNullException("target");\r
+ Contract.EndContractBlock();\r
+\r
+ if (target.Equals(root))\r
+ return true;\r
+ return\r
+ //If the target is directly below the root, it will have exactly \r
+ //one segment more than the root \r
+ target.Segments.Length == root.Segments.Length + 1\r
+ //Ensure that the candidate target is indeed below the root\r
+ && target.IsAtOrBelow(root);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Checkes whether a file path is below a root path\r
+ /// </summary>\r
+ /// <param name="targetPath"></param>\r
+ /// <param name="rootPath"></param>\r
+ /// <returns></returns>\r
+ public static bool IsAtOrBelow(this string targetPath, string rootPath)\r
+ {\r
+ if(String.IsNullOrWhiteSpace(targetPath))\r
+ throw new ArgumentNullException("targetPath");\r
+ if(String.IsNullOrWhiteSpace(rootPath))\r
+ throw new ArgumentNullException("rootPath");\r
+ Contract.EndContractBlock();\r
+\r
+ var targetSegments = targetPath.Split('\\');\r
+ var rootSegments = rootPath.Split('\\');\r
+\r
+ return InnerAtOrBelow(targetSegments, rootSegments);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Checks whether a file path is directly below a root path\r
+ /// </summary>\r
+ /// <param name="targetPath"></param>\r
+ /// <param name="rootPath"></param>\r
+ /// <returns></returns>\r
+ public static bool IsAtOrDirectlyBelow(this string targetPath, string rootPath)\r
+ {\r
+ if (String.IsNullOrWhiteSpace(targetPath))\r
+ throw new ArgumentNullException("targetPath");\r
+ if (String.IsNullOrWhiteSpace(rootPath))\r
+ throw new ArgumentNullException("rootPath");\r
+ Contract.EndContractBlock();\r
+\r
+ if (targetPath==rootPath)\r
+ return true;\r
+ var targetSegments = targetPath.Split('\\');\r
+ var rootSegments = rootPath.Split('\\');\r
+\r
+ return\r
+ //If the target is directly below the root, it will have exactly \r
+ //one segment more than the root \r
+ targetSegments.Length == rootSegments.Length + 1\r
+ //Ensure that the candidate target is indeed below the root\r
+ && InnerAtOrBelow(targetSegments, rootSegments);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Returns the part of the target string that comes after the prefix string.\r
+ /// The target is not modified if it doesn't start with the prefix string\r
+ /// </summary>\r
+ /// <param name="target"></param>\r
+ /// <param name="prefix"></param>\r
+ /// <returns></returns>\r
+ public static string After(this string target,string prefix)\r
+ { \r
+ //If the prefix or the target are empty, return the target\r
+ if (String.IsNullOrWhiteSpace(prefix) || String.IsNullOrWhiteSpace(target))\r
+ return target;\r
+ if (target.StartsWith(prefix))\r
+ return target.Remove(0,prefix.Length);\r
+ return target;\r
+ }\r
}\r
+\r
+\r
}\r