ActionData CreateTwoLevelTreeXOfY(int countFirstLevel, int countSecondLevel) { ActionData source = new ActionData(); source.Tag = "firstfloor"; for (int i = 0; i < countFirstLevel; i++) { ActionData children = new ActionData(); children.Tag = i.ToString(); //StreamWriter sw = new StreamWriter(children.Content); //sw.WriteLine("Hello Dave"); //sw.Flush(); children.DisplayName = "Hello Dave.txt"; children.FileName = CreateFile("Hello Dave.txt"); source.Nested.Add(children); } ActionData anotherLevel = new ActionData(); anotherLevel.Tag = "2ndFloor"; for (int i = 0; i < countSecondLevel; i++) { ActionData children = new ActionData(); children.Tag = i.ToString(); //StreamWriter sw = new StreamWriter(children.Content); //sw.WriteLine("Hello Dave"); //sw.Flush(); children.DisplayName = "Hello Dave.txt"; children.FileName = CreateFile("Hello Dave.txt"); anotherLevel.Nested.Add(children); } source.Nested.Add(anotherLevel); return source; }
/// <summary> /// Loads a node traversal path into a node. To create intricate trees, call /// multiple times with different paths(or the same even). /// The entries items are copied to the Tag field of the newly created nodes. /// </summary> /// <param name="root"></param> /// <param name="entries"></param> /// <param name="start"></param> void LoadIntoTree(ActionData root, object[] entries, int start) { for(int i = start; i < entries.Length; i++) { string s = entries[i].ToString(); ActionData newItem = new ActionData(); newItem.Tag = s; if (s.StartsWith("folder", StringComparison.InvariantCultureIgnoreCase)) { LoadIntoTree(newItem, entries, i + 1); i = entries.Length; } else { newItem.DisplayName = "Hello Dave.txt"; newItem.FileName = CreateFile("Hello Dave.txt"); } root.Nested.Add(newItem); } }
/// <summary> /// This method searches for an Action corresponding to /// a) the required ResolvedAction <paramref name="resAction"/> /// b) the required ContentItem within <paramref name="item"/> /// /// When given a flat list of ResolvedAction items, we need to find the corresponding action in the heirarchy beneath the /// ContentItems, in order to use the properties that are specific to that Content. /// </summary> /// <param name="pro"> </param> /// <param name="item"></param> /// <param name="resAction"></param> /// <param name="folderAction"> </param> /// <returns></returns> private static PolicyResponseAction FindContentAction(PolicyResponseObject pro, ActionData item, ResolvedAction resAction, bool folderAction) { List<IContentItem> contents = new List<IContentItem>(resAction.ContentCollection); IContentItem content; if (!folderAction) { content = contents.Find(delegate(IContentItem temp) { return ((ContentItem) (temp)).File.ContentId == item.Underworld.ContentId; }); } else { content = contents[0]; } PolicyResponseAction pra = null; pra = GetActionOfTypeFromContentItem(pro, content, resAction.ResponseAction.Type); if (pra == null) Debug.Assert(false, "Should not get here - unless the ResolvedAction and the ActionData params were not related in the first place"); return pra; }
/// <summary> /// Executes actions specified in the PolicyResponseObject. Supports both file and folder based /// actions. /// </summary> /// <param name="pro">PolicyResponseObject with ResolvedActions and ContentItems</param> /// <param name="container">ContentItems in a hierarchy structure</param> /// <returns></returns> public IUniversalRequestObject ExecuteActions(IPolicyResponseObject pro, ref IContainer container) { MimeEngine mimeEngine = new MimeEngine(); mimeEngine.ProgressCallback = _progressCallback; PolicyResponseObject realPro = pro as PolicyResponseObject; if (realPro == null) throw new PolicyEngineException("Invalid policy response object passed to the ActionExecuter"); // for now just do this fudge - cull this at earliest opportunity Laku 25/07/07 // the handling of the block and alert actions should be within the action processor if (ContainsBlockAction(realPro.ResolvedActionCollection)) { container.Files.Clear(); return CreateOutputUro(realPro, container); } #region process resolved actions // builds the master list of items into a hierarchy ActionData masterData = new ActionData(container, GetReadableContent); List<Guid> collections = new List<Guid>(); PolicyResponseAction pra = null; ActionData workingSet = null; try { foreach (ResolvedAction resAction in pro.ResolvedActionCollection) { if (resAction.ContentCollection.Count <= 0) continue; pra = resAction.ResponseAction as PolicyResponseAction; if (pra.IsExceptionAction) { mimeEngine.ExceptionAction = pra; continue; } if (pra.Action.Capabilities.SupportsMime && !mimeEngine.Actions.ContainsKey(resAction)) { mimeEngine.Actions[resAction] = GetActionOfTypeFromContentItem(realPro, resAction.ContentCollection[0], resAction.ResponseAction.Type).InternalProperties as ActionPropertySet; if (masterData.FileType == FileType.Email) continue; } collections.Clear(); ActionData.GetAllCollectionId(masterData, collections); workingSet = new ActionData(masterData, new Predicate<ActionData>(delegate(ActionData item) { string supportedFileType = FileTypeToSupportedFileTypeString(item.FileType); if (item.FileType == FileType.Folder || item.FileType == FileType.Selection) return true; if (!pra.Action.SupportedFileCollection.Supports(supportedFileType)) return false; if (item.Underworld != null && item.Underworld.Parent != null) { IFile parent = item.Underworld.Parent as IFile; if (parent != null && parent.FileType == FileType.ZIP)// && !pra.Action.SupportedFileCollection.Supports(".zip")) if (Array.IndexOf(pra.Action.SupportedFileCollection.UnsupportedFiles(), ".zip") >= 0) return false; } foreach (ContentItem ci in resAction.ContentCollection) { if (ci.File.UniqueIdentifier == item.Underworld.UniqueIdentifier && pra.Action.SupportedFileCollection.Supports(supportedFileType)) { return true; } } return false; }), GetReadableContent); if (ActionUtils.DoesActionSupportFolders((resAction.ResponseAction as PolicyResponseAction).Action)) { //magic IActionProperty prop = null; ActionData firstLevelData = workingSet.Nested[0] as ActionData; if (workingSet.Nested.Count > 0) pra = FindContentAction(realPro, firstLevelData, resAction, true); bool bZipAllFolder = false; if (pra.InternalProperties.SystemProperties.TryGetValue("FileType", out prop)) { if (workingSet.FileType == FileType.Email) prop.Value = ".email"; else { prop.Value = ".fld"; IActionProperty zipAttr = null; if (pra.InternalProperties.TryGetValue("ZIPAttachedFiles", out zipAttr) && (bool) zipAttr.Value) { bZipAllFolder = true; if (workingSet.Nested.Count > 0) RemoveZipFilesInFolder(workingSet.Nested[0] as ActionData, pro, false); } } } ExecuteAction(pra, workingSet); if (masterData.Nested.Count > 0 && bZipAllFolder) { RemoveZipFilesInFolder(masterData.Nested[0] as ActionData, pro, true); } } else { foreach (ActionData item in workingSet.GetAllLeafs()) { PolicyResponseAction actionToExecute = FindContentAction(realPro, item, resAction, false); ExecuteAction(actionToExecute, item); } } ActionData.Merge(masterData, workingSet, true); ActionData.PruneEmptyCollections(masterData, collections); pra.Executed = true; } } catch (AbortActionException abortThis) { // handle abort scenario PolicyActionException somethingWrong = new PolicyActionException(string.Format(CultureInfo.InvariantCulture, "Operation was aborted by action {0}", pra.Type), abortThis); somethingWrong.ExceptionHandling = ActionExceptionHandling.Abort; throw somethingWrong; } catch (Exception e) { throw CreateActionException(pra.Type, realPro, e, false); } #endregion if (masterData.Nested.Count != 0) container = ContentToPackedContainer(masterData); else container.Files.Clear(); // Synchronise the URO with the changes to the attachments IUniversalRequestObject outputUro = CreateOutputUro(realPro, container); try { // The MIME actions will modify the URO directly mimeEngine.ExecuteActions(outputUro); UniversalResponseObjectHelper.CopyProperties(outputUro, realPro.UniversalRequestObject); UniversalResponseObjectHelper.CopyRouting(outputUro, realPro.UniversalRequestObject); } catch (AbortActionException abortThis) { // handle abort scenario PolicyActionException somethingWrong = new PolicyActionException(string.Format(CultureInfo.InvariantCulture, "Operation was aborted by action {0}", pra.Type), abortThis); somethingWrong.ExceptionHandling = ActionExceptionHandling.Abort; throw somethingWrong; } catch (Exception e) { throw CreateActionException(pra.Type, realPro, e, true); } return outputUro; }
private void ExecuteAction(PolicyResponseAction pra, ActionData item) { string displayName = null; if (item.Underworld != null) { displayName = item.Underworld.DisplayName; } else { item.Properties.TryGetValue("FileName", out displayName); } Logger.LogDebug("Pre-Execute: " + displayName); OnBeforeExecuteHandler(pra.Action.Name, item.DisplayName); try { Dictionary<string, string> streamProperties = item.Properties; item.FileName = pra.Action.Execute(item, pra.InternalProperties as ActionPropertySet); item.DisplayName = streamProperties["DisplayName"]; } catch (Exception e) { OnAfterExecuteHandler(pra.Action.Name, item.DisplayName); if (e is AbortActionException) { throw; } string message = "ActionExecution: Exception on " + pra.Type + ". Message: " + e.Message; PolicyActionException pae = new PolicyActionException(message, e); pae.ContentId = displayName; throw pae; } OnAfterExecuteHandler(pra.Action.Name, item.DisplayName); Logger.LogDebug("Post-Execute: " + displayName); }
private bool RemoveZipFilesInFolder(ActionData data, IPolicyResponseObject pro, bool bRemoved) { if (data.FileType == FileType.Folder) { int i = 0; while (i < data.Nested.Count) { if (!RemoveZipFilesInFolder(data.Nested[i] as ActionData, pro, bRemoved)) ++i; } } else if (data.FileType == FileType.ZIP) { foreach (ResolvedAction resAction in pro.ResolvedActionCollection) { foreach (ContentItem ci in resAction.ContentCollection) { if (ContainedinPRO(data.Properties["FileName"], ci.File as File)) { if (!bRemoved) return false; if (data.Parent.Nested.Count > 0) { data.Parent.Nested.Remove(data); return true; } } } } if (!bRemoved && data.Parent.Nested.Count > 0) { data.Parent.Nested.Remove(data); return true; } } return false; }
private void ExecuteAction(IUniversalRequestObject outputUro, IResolvedAction actionInfo, List<string> actionsApplied) { PolicyResponseAction resAction = actionInfo.ResponseAction as PolicyResponseAction; // ReSharper disable ConditionIsAlwaysTrueOrFalse if (outputUro == null || actionInfo == null || resAction == null) // ReSharper restore ConditionIsAlwaysTrueOrFalse { return; } IAction3 action = resAction.Action; IFile emailFile; using (Stream stream = GetMimeStream(outputUro)) { emailFile = new File(stream, resAction.Type); } ActionData data = new ActionData(emailFile, GetReadableContent) { AttachmentFiles = outputUro.Attachments }; Logger.LogDebug("Pre-Execute: MIME"); Logger.LogDebug("ProcessActions: action " + resAction.Type); // shame no policySetInfo name OnBeforeExecuteHandler(resAction.Name, emailFile.FileName); if (!_emailActions[actionInfo].SystemProperties.ContainsKey("FileType")) { _emailActions[actionInfo].SystemProperties["FileType"] = new Action.ActionProperty("FileType", typeof(string), PropertyDisplayType.TextBox, true, false, ".email", true); } _emailActions[actionInfo].SystemProperties["FileType"].Value = ".email"; using (Stream modifiedStream = action.ExecuteMime(data, _emailActions[actionInfo])) { if (null == modifiedStream) { throw new PolicyException("Invalid mime stream"); } UpdateUroOriginalContentBytes(outputUro, modifiedStream); } foreach (RequestAttachment ra in outputUro.Attachments) { if (ra.File == null) { ra.File = new FCS.Lite.Interface.File(ra.FileName, ra.Name); } } bool isUserOverriden = resAction.InternalProperties.Modified; resAction.Executed = true; actionsApplied.Add(resAction.Name); Logger.LogDebug("Post-Execute: MIME"); UpdateActionEntity(resAction, isUserOverriden); OnAfterExecuteHandler(resAction.Name, emailFile.FileName); }
public void ExecuteMime_Abort() { IActionWrapperClass wrapper = new IActionWrapperClass(new MimeOnlyAction()); ActionData testData = new ActionData(); testData.AttachmentFiles = new Collection<IRequestAttachment>(); ActionPropertySet props = new ActionPropertySet(); testData.Properties[IActionWrapperClass.ABORT] = bool.FalseString; Stream output = wrapper.ExecuteMime(testData, props); Assert.IsNotNull(output, "Although abort property was present, the value was not true. Hence no exception expected."); testData.Properties[IActionWrapperClass.ABORT] = bool.TrueString; try { //execute output = wrapper.ExecuteMime(testData, props); } catch (AbortActionException) { Assert.IsTrue(true, "Expecting to arrive here when abort property was added"); return; } Assert.Fail("Should have thrown an abort exception"); }
public void MergeASpawnDeleteEmptyFolders() { //setup ActionData source = CreateTwoLevelTreeXOfY(5, 6); ActionData subTree = new ActionData(source, new Predicate<ActionData>( delegate(ActionData item) { int id = 0; if (int.TryParse(item.Tag.ToString(), out id)) { if (id % 2 == 0) return true; } return false; } ), null); subTree.Nested.Clear(); //execute ActionData.Merge(source, subTree, true); //verify Assert.AreEqual(3, source.Nested.Count, "Incorrect number of children in source"); //find one with folder int countFolders = 0; ActionData childFolder = null; foreach (ActionData item in source.Nested) { if (item.Nested.Count != 0) { childFolder = item; countFolders++; } } Assert.AreEqual(1, countFolders, "Only expecting one folder"); Assert.AreEqual(3, childFolder.Nested.Count, "Nested folder has incorrect count"); }
public void Execute_Abort() { IActionWrapperClass wrapper = new IActionWrapperClass(new BasicAction()); ActionData testData = new ActionData(); testData.Tag = "Execute_Abort.txt"; testData.DisplayName = "Execute_Abort.txt"; string file = CreateFile("Execute_Abort.txt"); testData.FileName = file; testData.Properties["DisplayName"] = "Execute_Abort.txt"; ActionPropertySet props = new ActionPropertySet(); testData.Properties[IActionWrapperClass.ABORT] = bool.FalseString; string output = wrapper.Execute(testData, props); Assert.IsTrue(!String.IsNullOrEmpty(output) && System.IO.File.Exists(output) , "Although abort property was present, the value was not true. Hence no exception expected."); testData.Properties[IActionWrapperClass.ABORT] = bool.TrueString; try { //execute testData.FileName = CreateFile("Execute_Abort.txt"); output = wrapper.Execute(testData, props); } catch (AbortActionException) { Assert.IsTrue(true, "Expecting to arrive here when abort property was added"); return; } Assert.Fail("Should have thrown an abort exception"); }
public void Execute() { //setup IActionWrapperClass wrapper = new IActionWrapperClass(new BasicAction()); ActionData testData = new ActionData(); //testData.Content = new MemoryStream(); testData.Tag = "Execute.txt"; testData.DisplayName = "Execute.txt"; string file = CreateFile("Execute.txt"); testData.FileName = file; testData.Properties["DisplayName"] = "Execute.txt"; ActionPropertySet props = new ActionPropertySet(); //execute string output = wrapper.Execute(testData, props); Assert.IsTrue(output == file, "Input file and output file should be the same."); Assert.IsTrue(!String.IsNullOrEmpty(output) && System.IO.File.Exists(output)); Assert.AreEqual(1, int.Parse(testData.Properties["ExecuteCalled"]), "Execute should be called only once"); }
public void IdPropertyMatchesContentId() { using (MemoryStream str = new MemoryStream(Encoding.Unicode.GetBytes("DummyContent"))) { Workshare.Policy.Engine.File file = new Workshare.Policy.Engine.File(str, "DummyFile"); file.ContentId = Guid.NewGuid().ToString(); Predicate<IContainer> dummyContainerTest = delegate { return true; }; ReadableContentRequest dummyRequestMethod = delegate { return null; }; ActionData actionData = new ActionData( file, dummyContainerTest, dummyRequestMethod); Assert.AreEqual(file.ContentId, actionData.Id.ToString(), "Expect ActionData.Id to match fi.ContentId when passing a file object in ActionData constructor."); } }
public void NestedSubTree() { // setup object[] tree = new object[] { 1, 2, 3, 4, "folder1", 5, 6, 7, 8, 9, "folder2", "foobar", "hello", "you", "folder3", 12, 14 }; object[] anotherLevel = new object[] { 4, 1, "folder12", 6 }; object[] yal = new object[] { "folder5", "folder6", "folder7", 24, 26, 28 }; ActionData root = new ActionData(); root.Tag = "root"; LoadIntoTree(root, tree, 0); LoadIntoTree(root, anotherLevel, 0); LoadIntoTree(root, yal, 0); Assert.AreEqual(9, root.Nested.Count, "should be 6 items and 3 folders"); //execute ActionData subTree = new ActionData(root, new Predicate<ActionData>(delegate(ActionData item) { int i = 1; if (int.TryParse(item.Tag.ToString(), out i)) { if (i % 2 == 0) return true; } return false; }), null); //verify foreach (ActionData data in root.GetAllLeafs()) { int i = 1; if(int.TryParse(data.Tag.ToString(), out i)) { Assert.IsTrue(i % 2 > 0, "Incorrect item found in subtree: tag: {0}", data.Tag); } } }
public ActionData(IContainer ic, Predicate<IContainer> venn, ReadableContentRequest readContentDelegate) : this() { myIC = ic as File; filename = ic.FileName; RetrieveContent = readContentDelegate; if (myIC == null && ic is Workshare.FCS.Lite.Interface.File) { myIC = new File(ic as Workshare.FCS.Lite.Interface.File); } if (!string.IsNullOrEmpty(myIC.ContentId)) { try { uniqueID = new Guid(myIC.ContentId); } catch (System.FormatException fe) { Logger.LogInfo(fe); } } PopulateStream(); foreach (IContainer c in ic.Files) { if (!venn(c) && c.Files.Count == 0) continue; ActionData childNode = new ActionData(c, venn, readContentDelegate); childNode.parent = this; nested.Add(childNode); } }
public void ExecuteMime() { //setup IActionWrapperClass wrapper = new IActionWrapperClass(new MimeOnlyAction()); ActionData testData = new ActionData(); testData.AttachmentFiles = new Collection<IRequestAttachment>(); ActionPropertySet props = new ActionPropertySet(); //execute Stream output = wrapper.ExecuteMime(testData, props); //verify StreamReader sr = new StreamReader(output); string exeOutput = sr.ReadToEnd().TrimEnd('\r', '\n'); Assert.AreEqual(typeof(MimeOnlyAction).FullName, exeOutput, "Expecting full typename to be written to the stream"); Assert.AreEqual(1, int.Parse(testData.Properties["ExecuteCalled"]), "Execute should be called only once"); }
/// <summary> /// This creates a subtree rooted at root containing all the nodes of /// root for which the Predicate returns true. root is modified such that /// the nodes (if not containers) are deleted from it. /// </summary> /// <param name="root">source tree</param> /// <param name="venn">node evaluation function</param> public ActionData(IActionData3 node, Predicate<ActionData> venn, ReadableContentRequest readContentDelegate) : this() { ActionData root = node as ActionData; if (root == null) return; myIC = root.myIC; rawContent = root.rawContent; streamProperties = root.streamProperties; tag = root.tag; RetrieveContent = readContentDelegate; filename = root.filename; displayname = root.displayname; List<ActionData> toRemove = new List<ActionData>(); uniqueID = root.uniqueID; foreach (ActionData c in root.Nested) { if (!venn(c) && c.nested.Count == 0) continue; if (c.nested.Count == 0) toRemove.Add(c); ActionData reassignedChild = new ActionData(c, venn, readContentDelegate); Nested.Add(reassignedChild); reassignedChild.parent = this; } foreach (ActionData c in toRemove) { root.Nested.Remove(c); } }
public void CreatingAContentSubTree() { //setup ActionData source = CreateTwoLevelTreeXOfY(4, 3); //execute ActionData newSubTree = new ActionData(source, new Predicate<ActionData>( delegate(ActionData item) { if (item.Tag.ToString().Equals("2")) return true; return false; }), null); //verify Assert.AreEqual(4, source.Nested.Count, "Incorrect number in subtree"); Assert.AreEqual(source.Id, newSubTree.Id, "subtree not pegged at root."); Assert.AreEqual(2, newSubTree.Nested.Count, "Incorrect number of child items in new tree."); Assert.AreEqual((source.Nested[3] as ActionData).Id, (newSubTree.Nested[1] as ActionData).Id, "Incorrect folder level."); //TODO: verify the trees are disjoint }