Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Dispatcher / QueryMatcher.cs / 1 / QueryMatcher.cs
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System;
using System.ServiceModel.Channels;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.ServiceModel.Diagnostics;
internal enum QueryCompilerFlags
{
None = 0x00000000,
InverseQuery = 0x00000001
}
internal struct QueryResult
{
QueryProcessor processor;
bool result;
internal QueryResult(QueryProcessor processor)
{
this.processor = processor;
this.result = this.processor.Result;
}
internal QueryResult(bool result)
{
this.processor = null;
this.result = result;
}
#if NO
internal ICollection Matches
{
get
{
return this.processor.ResultSet;
}
}
#endif
internal QueryProcessor Processor
{
get
{
return this.processor;
}
}
internal bool Result
{
get
{
return this.result;
}
}
internal MessageFilter GetSingleMatch()
{
Collection matches = processor.ResultList;
MessageFilter match;
switch (matches.Count)
{
default:
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MultipleFilterMatchesException(SR.GetString(SR.FilterMultipleMatches), null, matches));
case 0:
match = null;
break;
case 1:
match = matches[0];
break;
}
return match;
}
}
///
///
///
internal abstract class QueryMatcher
{
static IFunctionLibrary[] defaultFunctionLibs; // The set of function libraries that our XPath compiler will link to
static XPathNavigator fxCompiler; // fx compiler
protected int maxNodes; // Maximum # of nodes that we will process while performing any individual match
protected Opcode query; // root opcode - this is where query evaluation starts
protected int subExprVars; // the number of subexpr node sequences the processing context must hold
// Processor Pool
protected WeakReference processorPool;
internal class QueryProcessorPool
{
QueryProcessor processor;
internal QueryProcessorPool()
{
}
internal QueryProcessor Pop()
{
QueryProcessor p = this.processor;
if (null != p)
{
this.processor = (QueryProcessor) p.next;
p.next = null;
return p;
}
return null;
}
internal void Push(QueryProcessor p)
{
p.next = this.processor;
this.processor = p;
}
}
static QueryMatcher()
{
QueryMatcher.defaultFunctionLibs = new IFunctionLibrary[] { new XPathFunctionLibrary() };
// For some incomprehensible reason, the Framework XPath compiler requires an instance of an XPath navigator
// to compile an xpath. This compiler uses a dummy xml document to create a navigator
XmlDocument doc = new XmlDocument();
doc.LoadXml("");
QueryMatcher.fxCompiler = doc.CreateNavigator();
}
internal QueryMatcher()
{
this.maxNodes = int.MaxValue;
this.query = null;
this.processorPool = new WeakReference(null);
this.subExprVars = 0;
}
#if NO
internal QueryMatcher(QueryMatcher matcher)
{
this.processorPool = new WeakReference(null);
this.maxNodes = matcher.maxNodes;
this.query = matcher.query;
this.subExprVars = matcher.subExprVars;
}
#endif
internal bool IsCompiled
{
get
{
return (null != this.query);
}
}
internal int NodeQuota
{
get
{
return this.maxNodes;
}
set
{
DiagnosticUtility.DebugAssert(value > 0, "");
this.maxNodes = value;
}
}
#if NO
internal Opcode RootOpcode
{
get
{
return this.query;
}
set
{
DiagnosticUtility.DebugAssert(null != value, "");
this.query = value;
}
}
#endif
internal int SubExprVarCount
{
get
{
return this.subExprVars;
}
}
///
/// Compile the given filter to run on an external (fx) xpath engine
///
internal static OpcodeBlock CompileForExternalEngine(XPathMessageFilter filter)
{
// Compile...
XPathExpression xpathExpr = QueryMatcher.fxCompiler.Compile(filter.XPath);
// Fx will bind prefixes and functions here.
if (null != filter.namespaces)
{
// There's a bug in System.Xml.XPath. If we pass an XsltContext to SetContext it won't throw if there's
// an undefined prefix.
if(filter.namespaces is XsltContext)
{
// Lex the xpath to find all prefixes used
XPathLexer lexer = new XPathLexer(filter.XPath, false);
while (lexer.MoveNext())
{
string prefix = lexer.Token.Prefix;
if (prefix.Length > 0 && filter.namespaces.LookupNamespace(prefix) == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XsltException(SR.GetString(SR.FilterUndefinedPrefix, prefix)));
}
}
}
xpathExpr.SetContext(filter.namespaces);
}
//
// FORCE the function to COMPILE - they won't bind namespaces unless we check the return type
//
if (XPathResultType.Error == xpathExpr.ReturnType)
{
// This should never be reached. The above property should throw if there's an error
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XPathException(SR.GetString(SR.FilterCouldNotCompile, filter.XPath)));
}
OpcodeBlock codeBlock = new OpcodeBlock();
MatchSingleFxEngineOpcode op = new MatchSingleFxEngineOpcode();
op.XPath = xpathExpr;
op.Filter = filter;
codeBlock.Append(op);
return codeBlock;
}
///
/// Compile the given filter for evaluation using the internal engine.
///
/// Caller customizes optimizations via the flags parameter
/// Every xpath expression has a return type
/// The opcode block we execute to evaluate
internal static OpcodeBlock CompileForInternalEngine(XPathMessageFilter filter, QueryCompilerFlags flags, IFunctionLibrary[] functionLibs, out ValueDataType returnType)
{
return QueryMatcher.CompileForInternalEngine(filter.XPath.Trim(), filter.namespaces, flags, functionLibs, out returnType);
}
internal static OpcodeBlock CompileForInternalEngine(string xpath, XmlNamespaceManager nsManager, QueryCompilerFlags flags, IFunctionLibrary[] functionLibs, out ValueDataType returnType)
{
OpcodeBlock codeBlock;
returnType = ValueDataType.None;
if (0 == xpath.Length)
{
// 0 length XPaths always match
codeBlock = new OpcodeBlock();
codeBlock.Append(new PushBooleanOpcode(true)); // Always match by pushing true on the eval stack
}
else
{
// Try to parse the xpath. Bind to default function libraries
// The parser returns an expression tree
XPathParser parser = new XPathParser(xpath, nsManager, functionLibs);
XPathExpr parseTree = parser.Parse();
if (null == parseTree)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.CouldNotParseExpression));
}
returnType = parseTree.ReturnType;
// Compile the expression tree
XPathCompiler compiler = new XPathCompiler(flags);
codeBlock = compiler.Compile(parseTree);
}
return codeBlock;
}
///
/// Compile for the internal engine - use default function libraries
///
internal static OpcodeBlock CompileForInternalEngine(XPathMessageFilter filter, QueryCompilerFlags flags, out ValueDataType returnType)
{
return QueryMatcher.CompileForInternalEngine(filter, flags, QueryMatcher.defaultFunctionLibs, out returnType);
}
internal static OpcodeBlock CompileForInternalEngine(string xpath, XmlNamespaceManager ns, QueryCompilerFlags flags, out ValueDataType returnType)
{
return QueryMatcher.CompileForInternalEngine(xpath, ns, flags, QueryMatcher.defaultFunctionLibs, out returnType);
}
internal SeekableXPathNavigator CreateMessageNavigator(Message message, bool matchBody)
{
SeekableXPathNavigator nav = message.GetNavigator(matchBody, this.maxNodes);
// Position the navigator at the root element
// This allows a caller to run relative XPaths on message
nav.MoveToRoot();
return nav;
}
///
/// Checks the context pool for a generic navigator first. If none is available, creates a new one
///
internal SeekableXPathNavigator CreateSeekableNavigator(XPathNavigator navigator)
{
return new GenericSeekableNavigator(navigator);
}
internal SeekableXPathNavigator CreateSafeNavigator(SeekableXPathNavigator navigator)
{
INodeCounter counter = navigator as INodeCounter;
if(counter != null)
{
counter.CounterMarker = this.maxNodes;
counter.MaxCounter = this.maxNodes;
}
else
{
navigator = new SafeSeekableNavigator(navigator, this.maxNodes);
}
return navigator;
}
///
/// Checks the context pool for a processor first. If none is available, creates a new one
///
internal QueryProcessor CreateProcessor()
{
QueryProcessor p = null;
lock(this.processorPool)
{
QueryProcessorPool pool = this.processorPool.Target as QueryProcessorPool;
if(null != pool)
{
p = pool.Pop();
}
}
if (null != p)
{
p.ClearProcessor();
return p;
}
return new QueryProcessor(this);
}
internal QueryResult Match(MessageBuffer messageBuffer, ICollection matches)
{
Message message = messageBuffer.CreateMessage();
QueryResult result;
try
{
result = this.Match(message, true, matches);
}
finally
{
message.Close();
}
return result;
}
internal QueryResult Match(Message message, bool matchBody, ICollection matches)
{
QueryProcessor processor = this.CreateProcessor();
processor.ResultSet = matches;
processor.EnsureFilterCollection();
try
{
processor.Eval(this.query, message, matchBody);
}
catch(XPathNavigatorException e)
{
throw TraceUtility.ThrowHelperError(e.Process(this.query), message);
}
catch(NavigatorInvalidBodyAccessException e)
{
throw TraceUtility.ThrowHelperError(e.Process(this.query), message);
}
return new QueryResult(processor);
}
///
/// Execute matches over the given seekable navigator. If the navigator is not safe, wrap it with one that is
///
internal QueryResult Match(SeekableXPathNavigator navigator, ICollection matches)
{
// If the matcher places restrictions on the # of nodes we will inspect, and the navigator passed does
// not do any nodecounting itself, we must make that navigator safe by wrapping it
if (this.maxNodes < int.MaxValue)
{
navigator = this.CreateSafeNavigator(navigator);
}
QueryProcessor processor = this.CreateProcessor();
processor.ResultSet = matches;
processor.EnsureFilterCollection();
try
{
processor.Eval(this.query, navigator);
}
catch(XPathNavigatorException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(this.query));
}
catch(NavigatorInvalidBodyAccessException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(this.query));
}
return new QueryResult(processor);
}
///
/// Execute matches over the given navigator by wrapping it with a Seekable Navigator
///
internal QueryResult Match(XPathNavigator navigator, ICollection matches)
{
SeekableXPathNavigator nav = this.CreateSeekableNavigator(navigator);
return this.Match(nav, matches);
}
#if FILTER_SELECT
internal string Select(Message message, bool selectBody)
{
QueryProcessor processor = this.CreateProcessor();
processor.IsSelect = true;
processor.Eval(this.query, message, selectBody);
string result = processor.SelectResults;
this.ReleaseProcessor(processor);
return result;
}
internal string Select(MessageBuffer messageBuffer)
{
Message message = messageBuffer.CreateMessage();
string result = null;
try
{
result = this.Select(message, true);
}
finally
{
message.Close();
}
return result;
}
#endif
///
/// Release the given processor and place it back in the context pool
///
internal void ReleaseProcessor(QueryProcessor processor)
{
lock (this.processorPool)
{
QueryProcessorPool pool = this.processorPool.Target as QueryProcessorPool;
if (null == pool)
{
pool = new QueryProcessorPool();
this.processorPool.Target = pool;
}
pool.Push(processor);
}
}
internal void ReleaseResult(QueryResult result)
{
if (null != result.Processor)
{
result.Processor.ResultSet = null;
this.ReleaseProcessor(result.Processor);
}
}
///
/// Trim all pool
///
internal virtual void Trim()
{
if(this.query != null)
{
this.query.Trim();
}
}
}
internal enum XPathFilterFlags
{
None = 0x00,
AlwaysMatch = 0x01, // filter always matches
IsFxFilter = 0x02, // filter is matched using the framework engine
}
///
/// A matcher used to evalute single XPath filters
///
internal class XPathFilterMatcher : QueryMatcher
{
XPathFilterFlags flags;
static PushBooleanOpcode matchAlwaysFilter; // used for compiling xpaths that always match - i.e. xpath.Length == 0
static OpcodeBlock rootFilter; // used for compiling "/"
static XPathFilterMatcher()
{
XPathFilterMatcher.matchAlwaysFilter = new PushBooleanOpcode(true); //dummy
ValueDataType returnType;
XPathFilterMatcher.rootFilter = QueryMatcher.CompileForInternalEngine("/", null, QueryCompilerFlags.None, out returnType);
XPathFilterMatcher.rootFilter.Append(new MatchQueryResultOpcode());
}
internal XPathFilterMatcher()
: base()
{
this.flags = XPathFilterFlags.None;
}
#if NO
internal XPathFilterMatcher(XPathFilterMatcher matcher)
: base(matcher)
{
this.flags = matcher.flags;
}
#endif
internal bool IsAlwaysMatch
{
get
{
return (0 != (this.flags & XPathFilterFlags.AlwaysMatch));
}
}
internal bool IsFxFilter
{
get
{
return (0 != (this.flags & XPathFilterFlags.IsFxFilter));
}
}
///
/// If the xpath is an empty string, there is nothing to compile and the filter always matches
/// If not, try to compile the filter for execution within the filter engine's own query processor
/// If that query processor cannot accept the filter (it doesn't fall within the class of xpaths it can handle),
/// then revert to the fall-back solution - the slower Fx engine
///
internal void Compile(XPathMessageFilter filter)
{
if (null == this.query)
{
// Try to compile for the internal engine first
try
{
this.CompileForInternal(filter);
}
catch (QueryCompileException)
{
// Catch and eat compilation errors. We respond to internal compilation errors by dropping down
// to the framework and letting it try
}
if (null == this.query)
{
// Try for an external engine that might work..
this.CompileForExternal(filter);
}
}
}
///
/// Compile this xpath to run on an external (fx) xpath engine
///
internal void CompileForExternal(XPathMessageFilter filter)
{
MatchSingleFxEngineOpcode op = (MatchSingleFxEngineOpcode)QueryMatcher.CompileForExternalEngine(filter).First;
this.query = op;
this.flags |= XPathFilterFlags.IsFxFilter;
}
///
/// Compile for the internal engine with default flags
/// By defalt, we compile an xpath to run stand alone, with standard optimizations
///
internal void CompileForInternal(XPathMessageFilter filter)
{
this.query = null;
string xpath = filter.XPath.Trim();
if (0 == xpath.Length)
{
// Empty xpaths always match. Same for xpaths that refer to the root only
// We will evaluate such filters with minimal overhead. However, we
// don't want a null value for this.query, so we stick a dummy value in there
this.query = XPathFilterMatcher.matchAlwaysFilter;
this.flags |= (XPathFilterFlags.AlwaysMatch);
}
else if (1 == xpath.Length && '/' == xpath[0])
{
this.query = XPathFilterMatcher.rootFilter.First;
this.flags |= (XPathFilterFlags.AlwaysMatch);
}
else
{
ValueDataType returnType;
OpcodeBlock codeBlock = QueryMatcher.CompileForInternalEngine(filter, QueryCompilerFlags.None, out returnType);
// Inject a final opcode that will place the query result on the query context
// This query is now ready for execution STAND ALONE
codeBlock.Append(new MatchQueryResultOpcode());
this.query = codeBlock.First;
}
this.flags &= ~XPathFilterFlags.IsFxFilter;
}
internal QueryResult Match(MessageBuffer messageBuffer)
{
Message message = messageBuffer.CreateMessage();
QueryResult result;
try
{
result = this.Match(message, true);
}
finally
{
message.Close();
}
return result;
}
internal QueryResult Match(Message message, bool matchBody)
{
if (this.IsAlwaysMatch)
{
// No need to do any expensive query evaluation if we know that the query will always match
return new QueryResult(true);
}
return base.Match(message, matchBody, null);
}
internal QueryResult Match(SeekableXPathNavigator navigator)
{
if (this.IsAlwaysMatch)
{
// No need to do any expensive query evaluation if we know that the query will always match
return new QueryResult(true);
}
// Is it a filter that we will evaluate using the framework engine?
// We can evaluate that without having to allocate a query processor
if (this.IsFxFilter)
{
return new QueryResult(this.MatchFx(navigator));
}
return base.Match(navigator, null);
}
internal QueryResult Match(XPathNavigator navigator)
{
DiagnosticUtility.DebugAssert(null != this.query, "");
if (this.IsAlwaysMatch)
{
return new QueryResult(true);
}
// Is it a filter that we will evaluate using the framework engine?
// We can evaluate that without having to allocate a query processor
if (this.IsFxFilter)
{
return new QueryResult(this.MatchFx(navigator));
}
return base.Match(navigator, null);
}
///
/// Evaluates the filter over infosets surfaced via the given navigator by using the Fx engine
/// We assume that the filter was pre-compiled using the framework engine
///
internal bool MatchFx(XPathNavigator navigator)
{
INodeCounter counter = navigator as INodeCounter;
if (counter == null)
{
navigator = new SafeSeekableNavigator(new GenericSeekableNavigator(navigator), this.NodeQuota);
}
else
{
counter.CounterMarker = this.NodeQuota;
counter.MaxCounter = this.NodeQuota;
}
DiagnosticUtility.DebugAssert(null != this.query && OpcodeID.MatchSingleFx == this.query.ID, "");
try
{
return ((MatchSingleFxEngineOpcode)this.query).Match(navigator);
}
catch(XPathNavigatorException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(this.query));
}
catch(NavigatorInvalidBodyAccessException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e.Process(this.query));
}
}
}
internal class InverseQueryMatcher : QueryMatcher
{
SubExprEliminator elim;
Dictionary lastLookup;
internal InverseQueryMatcher()
: base()
{
this.elim = new SubExprEliminator();
this.lastLookup = new Dictionary();
}
internal void Add(XPathMessageFilter filter, bool forceExternal)
{
DiagnosticUtility.DebugAssert(null != filter, "");
// Compile the new filter
bool compiled = false;
OpcodeBlock codeBlock = new OpcodeBlock();
codeBlock.Append(new NoOpOpcode(OpcodeID.QueryTree));
if (!forceExternal)
{
try
{
ValueDataType returnType = ValueDataType.None;
// Try to compile and merge the compiled query into the query tree
codeBlock.Append(QueryMatcher.CompileForInternalEngine(filter, QueryCompilerFlags.InverseQuery, out returnType));
codeBlock.Append(new MatchMultipleFilterResultOpcode(filter));
compiled = true;
// Perform SubExpression Elimination
codeBlock = new OpcodeBlock(this.elim.Add(filter, codeBlock.First));
this.subExprVars = this.elim.VariableCount;
}
catch (QueryCompileException)
{
// If the filter couldn't be compiled, we drop down to the framework engine
}
}
if (!compiled)
{
// Compilation failed. Try the framework
codeBlock.Append(QueryMatcher.CompileForExternalEngine(filter));
}
// Merge the compiled query into the query tree
QueryTreeBuilder builder = new QueryTreeBuilder();
this.query = builder.Build(this.query, codeBlock);
// To de-merge this filter from the tree, we'll have to walk backwards up the tree... so we
// have to remember the last opcode that is executed on behalf of this filter
this.lastLookup[filter] = builder.LastOpcode;
}
internal void Clear()
{
foreach(XPathMessageFilter filter in this.lastLookup.Keys)
{
this.Remove(this.lastLookup[filter], filter);
this.elim.Remove(filter);
}
this.subExprVars = this.elim.VariableCount;
this.lastLookup.Clear();
}
internal void Remove(XPathMessageFilter filter)
{
DiagnosticUtility.DebugAssert(this.lastLookup.ContainsKey(filter), "");
this.Remove(this.lastLookup[filter], filter);
this.lastLookup.Remove(filter);
// Remove filter from subexpr eliminator
this.elim.Remove(filter);
this.subExprVars = this.elim.VariableCount;
}
void Remove(Opcode opcode, XPathMessageFilter filter)
{
switch (opcode.ID)
{
default:
opcode.Remove();
break;
case OpcodeID.MatchMultipleFilterResult:
((MatchMultipleFilterResultOpcode)opcode).Remove(filter);
break;
}
}
internal override void Trim()
{
base.Trim();
elim.Trim();
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- BeginStoryboard.cs
- RestHandler.cs
- DynamicUpdateCommand.cs
- StorageSetMapping.cs
- ConstrainedDataObject.cs
- NotifyParentPropertyAttribute.cs
- BasicExpandProvider.cs
- LinkedResourceCollection.cs
- MenuItem.cs
- Error.cs
- XsdCachingReader.cs
- ByteFacetDescriptionElement.cs
- InteropBitmapSource.cs
- WebPartCancelEventArgs.cs
- NameTable.cs
- TiffBitmapDecoder.cs
- TextEditorSelection.cs
- AnnotationResourceChangedEventArgs.cs
- MbpInfo.cs
- QilSortKey.cs
- SafeRightsManagementPubHandle.cs
- AspCompat.cs
- QilFactory.cs
- SuspendDesigner.cs
- TreeWalker.cs
- RoutingBehavior.cs
- HuffCodec.cs
- CookielessHelper.cs
- EventToken.cs
- StrongNameHelpers.cs
- uribuilder.cs
- BaseTemplateParser.cs
- StrokeDescriptor.cs
- HwndKeyboardInputProvider.cs
- DataContractSerializerSection.cs
- MailBnfHelper.cs
- BidOverLoads.cs
- ArrayTypeMismatchException.cs
- ImageDrawing.cs
- HandoffBehavior.cs
- AvTrace.cs
- HotSpotCollection.cs
- PersonalizationStateInfo.cs
- WebPartZoneCollection.cs
- Win32.cs
- StatusBarItem.cs
- SchemaCollectionPreprocessor.cs
- StaticExtensionConverter.cs
- QualifiedCellIdBoolean.cs
- FontSourceCollection.cs
- WebServiceData.cs
- TextChange.cs
- SymLanguageVendor.cs
- TextElementEnumerator.cs
- SingleConverter.cs
- XsdValidatingReader.cs
- SignedXml.cs
- DataPagerFieldItem.cs
- MarkupExtensionParser.cs
- BitSet.cs
- SoapEnumAttribute.cs
- HttpResponseWrapper.cs
- DesignTimeParseData.cs
- ReferenceSchema.cs
- PageAsyncTaskManager.cs
- smtpconnection.cs
- HtmlInputImage.cs
- KerberosTokenFactoryCredential.cs
- EventSourceCreationData.cs
- CapabilitiesState.cs
- ApplicationContext.cs
- ControlBuilderAttribute.cs
- SchemaHelper.cs
- XNodeValidator.cs
- EntityDataSourceWrapper.cs
- peersecuritysettings.cs
- MimePart.cs
- TextTreeInsertUndoUnit.cs
- MultiAsyncResult.cs
- WebPartsPersonalizationAuthorization.cs
- TextBounds.cs
- DocumentViewer.cs
- SimpleTextLine.cs
- Pair.cs
- CompositeDataBoundControl.cs
- FatalException.cs
- PrincipalPermissionMode.cs
- MimeBasePart.cs
- InitializerFacet.cs
- Calendar.cs
- EncodingFallbackAwareXmlTextWriter.cs
- ActivityStatusChangeEventArgs.cs
- InstanceDescriptor.cs
- OdbcEnvironmentHandle.cs
- SHA256Managed.cs
- VisualStateManager.cs
- Propagator.JoinPropagator.JoinPredicateVisitor.cs
- RemotingService.cs
- TextRangeEditLists.cs
- ExpressionBuilder.cs