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 ICollectionMatches { 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, ICollectionmatches) { 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, ICollectionmatches) { // 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, ICollectionmatches) { 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; DictionarylastLookup; 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
- SafePEFileHandle.cs
- ToolStripStatusLabel.cs
- ConnectionOrientedTransportChannelListener.cs
- ToolStripSeparatorRenderEventArgs.cs
- DataContractSerializer.cs
- PerformanceCounterPermissionEntry.cs
- CodeTypeReference.cs
- TextEndOfLine.cs
- CompilationUtil.cs
- PersonalizationProvider.cs
- SettingsPropertyIsReadOnlyException.cs
- DBAsyncResult.cs
- SqlInternalConnection.cs
- WaitingCursor.cs
- MemberAccessException.cs
- TabControl.cs
- RemoteCryptoTokenProvider.cs
- KeyValueConfigurationCollection.cs
- TransactionManagerProxy.cs
- CoreSwitches.cs
- ListDictionaryInternal.cs
- XmlCharCheckingReader.cs
- ChangeDirector.cs
- NativeMethodsCLR.cs
- UnionCqlBlock.cs
- WebPartConnection.cs
- Literal.cs
- HMACSHA384.cs
- WeakReferenceList.cs
- _AutoWebProxyScriptWrapper.cs
- KeyGestureConverter.cs
- BroadcastEventHelper.cs
- CharUnicodeInfo.cs
- ClientSideProviderDescription.cs
- TrustManagerPromptUI.cs
- InvalidCastException.cs
- RegistryKey.cs
- BooleanToSelectiveScrollingOrientationConverter.cs
- HashSetEqualityComparer.cs
- PopupRoot.cs
- DataSourceHelper.cs
- HandlerFactoryCache.cs
- GeneralTransformCollection.cs
- ArraySubsetEnumerator.cs
- SiteMap.cs
- ResourceReferenceKeyNotFoundException.cs
- PropertyGridCommands.cs
- UIElementCollection.cs
- XPathAncestorQuery.cs
- NameSpaceExtractor.cs
- SqlBulkCopyColumnMapping.cs
- DispatcherEventArgs.cs
- Journal.cs
- SqlFactory.cs
- PolygonHotSpot.cs
- StackSpiller.Bindings.cs
- DiscoveryClientElement.cs
- CommentEmitter.cs
- HMACRIPEMD160.cs
- RectangleConverter.cs
- BitmapEffect.cs
- HScrollProperties.cs
- XPathException.cs
- WeakReferenceKey.cs
- MetadataArtifactLoaderFile.cs
- SemanticBasicElement.cs
- UserPrincipalNameElement.cs
- DynamicPropertyHolder.cs
- DESCryptoServiceProvider.cs
- MutexSecurity.cs
- ApplicationInfo.cs
- UriWriter.cs
- SapiRecoContext.cs
- mediaclock.cs
- DataGridViewCellStyle.cs
- IProvider.cs
- TextSchema.cs
- RootProfilePropertySettingsCollection.cs
- dataobject.cs
- TemplateContent.cs
- MessageDroppedTraceRecord.cs
- CodeNamespaceImport.cs
- CallSiteOps.cs
- PerformanceCounterManager.cs
- shaperfactoryquerycachekey.cs
- MemberJoinTreeNode.cs
- ColorConvertedBitmap.cs
- ValueSerializerAttribute.cs
- BitmapMetadataEnumerator.cs
- EventPropertyMap.cs
- ImageSourceValueSerializer.cs
- Rotation3DAnimationUsingKeyFrames.cs
- LinqDataSourceView.cs
- NavigatingCancelEventArgs.cs
- StopStoryboard.cs
- WindowsListViewGroupHelper.cs
- DirectoryNotFoundException.cs
- ValueType.cs
- XmlEncoding.cs
- SqlInternalConnection.cs