Skip to content

Commit

Permalink
Esent model now included in Xbim.Ifc again so we don't default to Mem…
Browse files Browse the repository at this point in the history
…oryModel.

Added some guards/logging to Esent & Heurisrstic ModelProvider infrastructure when used under non WIndows o/s
  • Loading branch information
andyward committed Feb 2, 2023
1 parent 1315fd5 commit b3fce6f
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 34 deletions.
11 changes: 3 additions & 8 deletions Tests/DefaultModelProviderFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,11 @@ public DefaultModelProviderFactoryTests(ITestOutputHelper testOutputHelper)

XbimServices xbimServices;

[Fact(Skip = "Need to re-consider the requirement - should it be explicit")]
public void ShouldProvideHeuristicModelProvider_When_XBIM_Esent_Loaded()
[Fact]
public void ShouldProvideHeuristicModelProvider_In_IfcStore()
{
xbimServices.ConfigureServices(s => s.AddXbimToolkit());
var serviceProvider = xbimServices.ServiceProvider;


IModelProviderFactory factory = serviceProvider.GetRequiredService<IModelProviderFactory>();

var modelProvider = factory.CreateProvider();
var modelProvider = IfcStore.ModelProviderFactory.CreateProvider();

Assert.IsType<HeuristicModelProvider>(modelProvider);
}
Expand Down
13 changes: 0 additions & 13 deletions Tests/DependencyInjectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,6 @@ public void ThirdParty_modelProviders_resolve()
provider.Should().BeOfType<DummyModelProvider>();
}

[Fact(Skip ="Brittle due to use of singleton state")]
public void IfcStore_resolves_defined_provider()
{
XbimServices.Current.Rebuild();

SuT.ConfigureServices(s => s.AddXbimToolkit(opt => opt.UseEsentModel()));

var provider = IfcStore.ModelProviderFactory.CreateProvider();
XbimServices.Current.Rebuild();

provider.Should().BeOfType<EsentModelProvider>();
}


[Fact]
public void Logging_can_be_added()
Expand Down
9 changes: 8 additions & 1 deletion Xbim.IO.Esent/Esent/EsentModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
using Xbim.Common.Configuration;
using Xbim.Common.Metadata;
using Xbim.Common.Step21;
using System.Runtime.InteropServices;

namespace Xbim.IO.Esent
{
/// <summary>
/// IModel implementation for Esent DB based model support
/// </summary>

/// <remarks>Esent is a data storage system deployed automatically on Microsoft Windows machines.
/// Consequently this IModel is only supported on Windows Operating Systems</remarks>
public class EsentModel : IModel, IFederatedModel, IDisposable
{
#region Fields
Expand Down Expand Up @@ -99,6 +101,11 @@ private EsentModel(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory ?? XbimServices.Current.GetLoggerFactory();
Logger = _loggerFactory.CreateLogger<EsentModel>();
if(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Logger.LogCritical("Esent is Windows only and not supported on {OS}", RuntimeInformation.OSDescription);
throw new NotSupportedException("Esent is not supported on this operating system");
}
}

protected void Init(IEntityFactory factory)
Expand Down
10 changes: 10 additions & 0 deletions Xbim.IO.Esent/EsentModelProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Xbim.Common.Exceptions;
using Xbim.Common.Configuration;
using Xbim.Common.Step21;
using System.Runtime.InteropServices;

namespace Xbim.IO.Esent
{
Expand All @@ -23,6 +24,10 @@ public EsentModelProvider() : this(default)
public EsentModelProvider(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory ?? XbimServices.Current.GetLoggerFactory();
if (!IsEsentSupported())
{
_logger.LogWarning("EsentModel is only compatible with Windows platforms. Please use another ModelProvider.");
}
}

public override StoreCapabilities Capabilities => new StoreCapabilities(isTransient: false, supportsTransactions: true);
Expand Down Expand Up @@ -231,5 +236,10 @@ private EsentModel CreateEsentModel(XbimSchemaVersion schema, int codePageOverri
}

public string DatabaseFileName { get; set; }

private static bool IsEsentSupported()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
}
}
}
53 changes: 42 additions & 11 deletions Xbim.IO.Esent/HeuristicModelProvider.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
Expand All @@ -10,12 +9,11 @@
using Xbim.IO;
using Xbim.IO.Esent;
using Xbim.IO.Memory;
using System.Runtime.InteropServices;

namespace Xbim.Ifc
{

// IMPORTANT: if we ever rename this provider we need to update the DefaultModelProviderFactory, since
// this is the default provider when the assembly is loaded, and it's discovered by Name through reflection

/// <summary>
/// The <see cref="HeuristicModelProvider"/> encapsulates the underlying <see cref="IModel"/> implementations we use
Expand All @@ -24,10 +22,13 @@ namespace Xbim.Ifc
/// <remarks>This store permits a <see cref="MemoryModel"/> to be used where it's appropriate, while switching to an
/// <see cref="EsentModel"/> when persistance is required, or a source model is above a size threshold.
/// The store also permits a <see cref="MemoryModel"/> to persisted.
///
/// Since EsentModel only supports the Windows platform this provider is not suitable for use on non-Windows Operating Systems
/// </remarks>
public class HeuristicModelProvider : BaseModelProvider
{
private readonly ILoggerFactory _loggerFactory;
private readonly ILogger _logger;

public HeuristicModelProvider() : this(default)
{
Expand All @@ -37,6 +38,12 @@ public HeuristicModelProvider() : this(default)
public HeuristicModelProvider(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory ?? XbimServices.Current.GetLoggerFactory();
_logger = _loggerFactory.CreateLogger<HeuristicModelProvider>();

if(!IsEsentSupported())
{
_logger.LogWarning("EsentModel is only compatible with Windows operating systems. Please use another ModelProvider.");
}
}

/// <summary>
Expand All @@ -52,8 +59,6 @@ public HeuristicModelProvider(ILoggerFactory loggerFactory)
public override StoreCapabilities Capabilities => new StoreCapabilities(isTransient: false, supportsTransactions: true);




/// <summary>
/// Closes a Model store, releasing any resources
/// </summary>
Expand Down Expand Up @@ -168,13 +173,25 @@ public override XbimSchemaVersion GetXbimSchemaVersion(string modelPath)
public override IModel Open(Stream stream, StorageType dataType, XbimSchemaVersion schema, XbimModelType modelType,
XbimDBAccess accessMode = XbimDBAccess.Read, ReportProgressDelegate progDelegate = null, int codePageOverride = -1)
{

if(modelType == XbimModelType.EsentModel && ! IsEsentSupported())
{
modelType = XbimModelType.MemoryModel;
_logger.LogWarning("EsentModel not support on this platform. Falling back to memory model where possible");
}

//any Esent model needs to run from the file so we need to create a temporal one
var xbimFilePath = Path.GetTempFileName();
xbimFilePath = Path.ChangeExtension(xbimFilePath, ".xbim");

switch (dataType)
{
case StorageType.Xbim:
if(modelType == XbimModelType.MemoryModel)
{
throw new NotSupportedException($"Cannot open xbim file with a Memory Model");
}

//xBIM file has to be opened from the file so we need to create temporary file if it is not a local file stream
var localFile = false;
var fileStream = stream as FileStream;
Expand Down Expand Up @@ -281,23 +298,27 @@ public override IModel Open(string path, XbimSchemaVersion schemaVersion, double

if (storageType == StorageType.Xbim) //open the XbimFile
{
if(!IsEsentSupported())
{
throw new NotSupportedException($"Cannot open xbim file on this platform");
}
var model = CreateEsentModel(schemaVersion, codePageOverride);
model.Open(path, accessMode, progDelegate);
return model;
}
else //it will be an IFC file if we are at this point
{
var fInfo = new FileInfo(path);
double ifcMaxLength = (ifcDatabaseSizeThreshHold ?? DefaultIfcDatabaseSizeThreshHoldMb) * 1024 * 1024;
var file = new FileInfo(path);
double ifcMaxFileLength = (ifcDatabaseSizeThreshHold ?? DefaultIfcDatabaseSizeThreshHoldMb) * 1024 * 1024;
// we need to make an Esent database, if ifcMaxLength<0 we use in memory
if (ifcMaxLength >= 0 && fInfo.Length > ifcMaxLength)
if (ExceedsThreshold(file, ifcMaxFileLength) && IsEsentSupported())
{
var tmpFileName = Path.GetTempFileName();
var model = CreateEsentModel(schemaVersion, codePageOverride);
// We delete the XBIM on close as the consumer is not controlling the generation of the XBIM file
if (model.CreateFrom(path, tmpFileName, progDelegate, keepOpen: true, deleteOnClose: true))
return model;
return model;

throw new FileLoadException(path + " file was not a valid IFC format");
}
else //we can use a memory model
Expand All @@ -321,6 +342,16 @@ public override IModel Open(string path, XbimSchemaVersion schemaVersion, double
}
}

private static bool ExceedsThreshold(FileInfo file, double maxLength)
{
return maxLength >= 0 && file.Length > maxLength;
}

private static bool IsEsentSupported()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
}

/// <summary>
/// Persists the model to a permanent store
/// </summary>
Expand Down
10 changes: 9 additions & 1 deletion Xbim.Ifc/IfcStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Xbim.Common;
using Xbim.Common.Configuration;
using Xbim.Common.Exceptions;
Expand Down Expand Up @@ -72,7 +73,14 @@ static IfcStore()
{
if(!XbimServices.Current.IsBuilt)
{
XbimServices.Current.ConfigureServices(s => s.AddXbimToolkit());
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
XbimServices.Current.ConfigureServices(s => s.AddXbimToolkit(opt => opt.UseHeuristicModel()));
}
else
{
XbimServices.Current.ConfigureServices(s => s.AddXbimToolkit(opt => opt.UseMemoryModel()));
}
}
ModelProviderFactory = XbimServices.Current.ServiceProvider.GetRequiredService<IModelProviderFactory>();
}
Expand Down
1 change: 1 addition & 0 deletions Xbim.Ifc/Xbim.Ifc.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<ProjectReference Include="..\Xbim.Common\Xbim.Common.csproj" />
<ProjectReference Include="..\Xbim.Ifc2x3\Xbim.Ifc2x3.csproj" />
<ProjectReference Include="..\Xbim.Ifc4\Xbim.Ifc4.csproj" />
<ProjectReference Include="..\Xbim.IO.Esent\Xbim.IO.Esent.csproj" />
<ProjectReference Include="..\Xbim.IO.MemoryModel\Xbim.IO.MemoryModel.csproj" />
</ItemGroup>
<ItemGroup>
Expand Down

0 comments on commit b3fce6f

Please sign in to comment.