Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 0 additions & 115 deletions Src/Common/Filters/FiltersTests/TestPersistence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

using System;
using System.Collections;
using System.IO;
using System.Xml;
using NUnit.Framework;
using SIL.LCModel.Core.Text;
Expand Down Expand Up @@ -407,118 +406,4 @@ public void PersistReverseComparer()
Assert.That(rcOut.SubComp is IntStringComparer, Is.True);
}
}

/// <summary>
/// Tests persisting a list of ManyOnePathSortItems
/// </summary>
[TestFixture]
public class ManyOnePathSortItemsPersistenceTests : MemoryOnlyBackendProviderTestBase
{
private ISilDataAccess m_sda;
private ArrayList m_list;
private ILexEntry m_le1;
private ILexEntry m_le2;

public override void FixtureSetup()
{
base.FixtureSetup();

m_sda = Cache.DomainDataByFlid;
}

public override void FixtureTeardown()
{
m_sda = null;

base.FixtureTeardown();
}

public override void TestSetup()
{
base.TestSetup();


IManyOnePathSortItem mopsi = new ManyOnePathSortItem(Cache.LangProject);
m_list = new ArrayList();
m_list.Add(mopsi);
var leFactory = Cache.ServiceLocator.GetInstance<ILexEntryFactory>();
UndoableUnitOfWorkHelper.Do("undoit", "redoit", Cache.ActionHandlerAccessor, () =>
{
m_le1 = leFactory.Create();
m_le2 = leFactory.Create();
});
mopsi = new ManyOnePathSortItem(Cache.LangProject.LexDbOA.Hvo, new int[] { m_le1.Hvo, m_le2.Hvo }, new int[] { 2, 3 });
m_list.Add(mopsi);
}

/// <summary>
/// Test persisting a list of ManyOnePathSortItems.
/// </summary>
[Test]
public void PersistMopsiList()
{
var mopsi = (IManyOnePathSortItem)m_list[m_list.Count - 1];
using (var stream = new MemoryStream())
{
var objRepo = Cache.ServiceLocator.ObjectRepository;
var originalPersistData = mopsi.PersistData(objRepo);
using (var writer = new StreamWriter(stream))
{
ManyOnePathSortItem.WriteItems(m_list, writer, objRepo);
stream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(stream))
{
var items = ManyOnePathSortItem.ReadItems(reader, objRepo);
Assert.That(items.Count, Is.EqualTo(m_list.Count));
mopsi = (IManyOnePathSortItem)items[0];
Assert.That(mopsi.KeyObject, Is.EqualTo(Cache.LangProject.Hvo));
Assert.That(mopsi.PathLength, Is.EqualTo(0));
// Root object is key object, if no path.
Assert.That(mopsi.RootObjectHvo, Is.EqualTo(Cache.LangProject.Hvo));
Assert.That(mopsi.RootObjectUsing(Cache), Is.EqualTo(Cache.LangProject));
// PathObject(0) is also the key, if no path.
Assert.That(mopsi.PathObject(0), Is.EqualTo(Cache.LangProject.Hvo));
mopsi = (IManyOnePathSortItem)items[1];
Assert.That(mopsi.KeyObject, Is.EqualTo(Cache.LangProject.LexDbOA.Hvo));
Assert.That(mopsi.PathLength, Is.EqualTo(2));
Assert.That(mopsi.PathFlid(0), Is.EqualTo(2));
Assert.That(mopsi.PathFlid(1), Is.EqualTo(3));
Assert.That(mopsi.PathObject(0), Is.EqualTo(m_le1.Hvo));
Assert.That(mopsi.PathObject(1), Is.EqualTo(m_le2.Hvo));
Assert.That(mopsi.PathObject(2), Is.EqualTo(Cache.LangProject.LexDbOA.Hvo), "Index one too large yields key object.");
Assert.That(mopsi.RootObjectHvo, Is.EqualTo(m_le1.Hvo));
Assert.That(mopsi.RootObjectUsing(Cache), Is.EqualTo(m_le1));
Assert.That(mopsi.KeyObjectUsing(Cache), Is.EqualTo(Cache.LangProject.LexDbOA));
Assert.That(mopsi.PersistData(objRepo), Is.EqualTo(originalPersistData));
}
}
}
}

/// <summary>
/// Test persisting a list of ManyOnePathSortItems.
/// </summary>
[Test]
public void PersistMopsiList_BadGUID()
{
// Now make one containing a bad GUID.
using (var stream = new MemoryStream())
{
var objRepo = Cache.ServiceLocator.ObjectRepository;
using (var writer = new StreamWriter(stream))
{
ManyOnePathSortItem.WriteItems(m_list, writer, objRepo);
writer.WriteLine(Convert.ToBase64String(Guid.NewGuid().ToByteArray()));
// fake item, bad guid
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(stream))
{
var items = ManyOnePathSortItem.ReadItems(reader, objRepo);
Assert.That(items, Is.Null);
}
}
}
}
}
}
2 changes: 0 additions & 2 deletions Src/Common/Filters/IManyOnePathSortItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,5 @@ public interface IManyOnePathSortItem
int PathLength { get; }
int PathObject(int index);
int PathFlid(int index);
// This is in the interface only for internal use.
string PersistData(ICmObjectRepository repo);
}
}
238 changes: 0 additions & 238 deletions Src/Common/Filters/ManyOnePathSortItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

using System;
using System.Collections;
using System.IO;
using System.Text;
using SIL.LCModel;

namespace SIL.FieldWorks.Filters
Expand Down Expand Up @@ -223,241 +221,5 @@ public int PathLength
return m_pathObjects.Length;
}
}

string PersistGuid(Guid guid)
{
return Convert.ToBase64String(guid.ToByteArray());
}

/// <summary>
/// A representation that can be used to create an equivalent LazyManyOnePathSortItem.
/// Keep consistent with the LazyManyOnePathSortItem constructor and PersisData.
/// </summary>
public string PersistData(ICmObjectRepository repo)
{
StringBuilder builder = new StringBuilder();
builder.Append(PersistGuid(repo.GetObject(m_hvoItem).Guid));
if (PathLength > 0)
{
for (int i = 0; i < m_pathObjects.Length; i++)
{
builder.Append(";");
builder.Append(m_pathFlids[i]);
builder.Append(";");
builder.Append(PersistGuid(repo.GetObject(m_pathObjects[i]).Guid));
}
}
return builder.ToString();
}

/// <summary>
/// Write a collection of IManyOneSortItems in a form that can be reconstituted by ReadItems.
/// </summary>
public static void WriteItems(ArrayList items, StreamWriter output, ICmObjectRepository repo)
{
foreach (IManyOnePathSortItem item in items)
output.WriteLine(item.PersistData(repo));
output.Flush();
}

/// <summary>
/// Build a collection of IManyOneSortItems from data written by WriteItems.
/// </summary>
public static ArrayList ReadItems(StreamReader input, ICmObjectRepository repo)
{
try
{
var result = new ArrayList();
while (!input.EndOfStream)
result.Add(new LazyManyOnePathSortItem(input.ReadLine(), repo));
return result;

}
// If we find a guid we don't recognize as a valid object, the actual data is somehow
// not consistent with what we saved, so discard the saved information.
catch (InvalidObjectGuidException)
{
return null;
}
// Likewise, if anything goes wrong with reading the file, we'll just rebuild the index.
catch (IOException)
{
return null;
}
// Also if the file has been corrupted somehow with invalid Base64 data, we'll rebuild
// the index. See FWR-1110.
catch (FormatException)
{
return null;
}
// This occurs if an input line has an even number of chunks (semi-colon-separated). LT-11240.
// This again indicates the file is corrupt and we will just rebuild the index.
catch (IndexOutOfRangeException)
{
return null;
}
// If the string representing a GUID that we read from the file doesn't produce
// a byte array exactly 8 bytes long, we get this (FWR-2890). Similar to FormatException,
// if the file is corrupt we'll just rebuild the index.
// Review JohnT: is this a case where we should just catch all exceptions? But then
// if someone introduces a defect the program may just slow down without our ever
// realizing why.
catch (ArgumentException)
{
return null;
}
}
}

/// <summary>
/// Private marker class so we can catch the specific problem of seeking an HVO for an unknown
/// (probably deleted object) guid.
/// </summary>
class InvalidObjectGuidException : ApplicationException
{

}

/// <summary>
/// This alternative implementation is used when restoring a saved list of mopsis.
/// The main point of it is to be able to restore a list of Imopsis, but NOT actually create the
/// objects until they are needed for something. Accordingly, it mainly stores ICmObjectIds
/// rather than CmObjects or HVOs, though the variables are ICmObjectOrIds so we can
/// retrieve the objects efficiently once they are real.
/// </summary>
class LazyManyOnePathSortItem : IManyOnePathSortItem
{
/// <summary>
/// The actual item that we are sorting, filtering, etc. by.
/// </summary>
ICmObjectOrId m_item;

/// <summary>
/// The repository that can interpret ICmObjectOrIds and give ICmObjects.
/// </summary>
private ICmObjectRepository m_repo;

/// <summary>
/// Array of objects in the path. m_pathObjects[0] is one of the original list items.
/// m_pathObjects[n+1] is an object in property m_pathFlids[n] of m_pathObjects[n].
/// m_item is an object in property m_pathFlids[last] of m_pathObjects[last].
/// </summary>
ICmObjectOrId[] m_pathObjects;
int[] m_pathFlids;

public LazyManyOnePathSortItem(string persistInfo, ICmObjectRepository repo)
{
m_repo = repo;
var chunks = persistInfo.Split(';');
m_item = ParseGuidRep(repo, chunks[0]);
if (chunks.Length > 1)
{
var pathLen = chunks.Length/2;
m_pathObjects = new ICmObjectOrId[pathLen];
m_pathFlids = new int[pathLen];
for (int i = 0; i < pathLen; i++)
{
m_pathFlids[i] = int.Parse(chunks[i*2 + 1]);
m_pathObjects[i] = ParseGuidRep(repo, chunks[i * 2 + 2]);
}
}
}

/// A representation that can be used to create an equivalent LazyManyOnePathSortItem later.
/// Keep consistent with the ManyOnePathSortItem PersistData (and our constructor).
/// </summary>
public string PersistData(ICmObjectRepository repo)
{
StringBuilder builder = new StringBuilder();
builder.Append(PersistGuid(m_item));
if (PathLength > 0)
{
for (int i = 0; i < m_pathObjects.Length; i++)
{
builder.Append(";");
builder.Append(m_pathFlids[i]);
builder.Append(";");
builder.Append(PersistGuid(m_pathObjects[i]));
}
}
return builder.ToString();
}

private string PersistGuid(ICmObjectOrId item)
{
return Convert.ToBase64String(item.Id.Guid.ToByteArray());
}

private ICmObjectOrId ParseGuidRep(ICmObjectRepository repo, string chunk)
{
var result = repo.GetObjectOrIdWithHvoFromGuid(new Guid(Convert.FromBase64String(chunk)));
if (result == null)
throw new InvalidObjectGuidException();
return result;
}

public ICmObject RootObjectUsing(LcmCache cache)
{
if (m_pathObjects == null)
return RealKeyObject();
var result = m_pathObjects[0].GetObject(m_repo);
// makes future updates more efficient, if it was an ID.
// I believe locking is not necessary, since even if two threads update this,
// both will update it to the same thing.
m_pathObjects[0] = result;
return result;
}

public int RootObjectHvo
{
get {
var objOrId = m_pathObjects == null ? m_item : m_pathObjects[0];
return m_repo.GetHvoFromObjectOrId(objOrId);
}
}

public int KeyObject
{
get
{
return m_repo.GetHvoFromObjectOrId(m_item);
}
}

public ICmObject KeyObjectUsing(LcmCache cache)
{
return RealKeyObject();
}

private ICmObject RealKeyObject()
{
var temp = m_item.GetObject(m_repo);
m_item = temp; // locking not needed, all threads will update to same thing
return temp;
}

public int PathLength
{
get
{
if (m_pathObjects == null)
return 0;
return m_pathObjects.Length;
}
}

public int PathObject(int index)
{
if (m_pathObjects == null && index == 0)
return KeyObject;
if (index == m_pathObjects.Length)
return KeyObject;
return m_repo.GetHvoFromObjectOrId(m_pathObjects[index]);
}

public int PathFlid(int index)
{
return m_pathFlids[index];
}
}
}
2 changes: 0 additions & 2 deletions Src/LexText/Lexicon/FLExBridgeListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1437,8 +1437,6 @@ private static FwXWindow RefreshCacheWindowAndAll(LexTextApp app, string fullPro
(FwXWindow)manager.ReopenProject(manager.Cache.ProjectId.Name, appArgs).ActiveMainWindow;
if (IsVernacularSpellingEnabled(newAppWindow.PropTable))
WfiWordformServices.ConformSpellingDictToWordforms(newAppWindow.Cache);
//clear out any sort cache files (or whatever else might mess us up) and then refresh
newAppWindow.ClearInvalidatedStoredData();
newAppWindow.RefreshDisplay();
return newAppWindow;
}
Expand Down
Loading
Loading