//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Globalization;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
{
///
/// Context object containing key properties needed to query for SMO objects
///
public class SmoQueryContext
{
private Server server;
private Database database;
private SmoObjectBase parent;
private SmoWrapper smoWrapper;
private ValidForFlag validFor = 0;
///
/// Creates a context object with a server to use as the basis for any queries
///
///
public SmoQueryContext(Server server, IMultiServiceProvider serviceProvider)
: this(server, serviceProvider, null)
{
}
internal SmoQueryContext(Server server, IMultiServiceProvider serviceProvider, SmoWrapper serverManager)
{
this.server = server;
ServiceProvider = serviceProvider;
this.smoWrapper = serverManager ?? new SmoWrapper();
}
///
/// The server type
///
public SqlServerType SqlServerType { get; set; }
///
/// The server SMO will query against
///
public Server Server {
get
{
return GetObjectWithOpenedConnection(server);
}
}
///
/// Optional Database context object to query against
///
public Database Database {
get
{
return GetObjectWithOpenedConnection(database);
}
set
{
database = value;
}
}
///
/// Parent of a give node to use for queries
///
public SmoObjectBase Parent {
get
{
return GetObjectWithOpenedConnection(parent);
}
set
{
parent = value;
}
}
///
/// A query loader that can be used to find objects
/// for specific SMO types
///
public IMultiServiceProvider ServiceProvider { get; private set; }
///
/// Helper method to cast a parent to a specific type
///
///
///
public T ParentAs()
where T : TreeNode
{
return Parent as T;
}
///
/// Gets the if available, by looking it up
/// from the
///
///
///
/// Thrown if the is not set or the
/// isn't available from that provider
///
public ObjectExplorerService GetObjectExplorerService()
{
if (ServiceProvider == null)
{
throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet);
}
ObjectExplorerService service = ServiceProvider.GetService();
if (service == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
SqlTools.Hosting.SR.ServiceNotFound, nameof(ObjectExplorerService)));
}
return service;
}
///
/// Copies the context for use by another node
///
/// New Parent to set
/// new with all fields except the same
public SmoQueryContext CopyWithParent(SmoObjectBase parent)
{
SmoQueryContext context = new SmoQueryContext(this.Server, this.ServiceProvider, this.smoWrapper)
{
database = this.Database,
Parent = parent,
SqlServerType = this.SqlServerType,
ValidFor = ValidFor
};
return context;
}
///
/// Indicates which platforms the server and database is valid for
///
public ValidForFlag ValidFor
{
get
{
if(validFor == 0)
{
validFor = ServerVersionHelper.GetValidForFlag(SqlServerType, Database);
}
return validFor;
}
set
{
validFor = value;
}
}
private T GetObjectWithOpenedConnection(T smoObj)
where T : SmoObjectBase
{
if (smoObj != null)
{
EnsureConnectionOpen(smoObj);
}
return smoObj;
}
///
/// Ensures the server objects connection context is open. This is used by all child objects, and
/// the only way to easily access is via the server object. This should be called during access of
/// any of the object properties
///
public void EnsureConnectionOpen(SmoObjectBase smoObj)
{
if (!smoWrapper.IsConnectionOpen(smoObj))
{
// We have a closed server connection. Reopen this
// Note: not currently catching connection exceptions. Expect this to bubble
// up to calling methods and be logged there as this would be happening there in any case
smoWrapper.OpenConnection(smoObj);
}
}
}
}