/// <summary> /// Sets the message schema strong name and message type. /// </summary> /// <param name="context">Pipeline context.</param> /// <param name="messageType">Message type.</param> /// <param name="message">Message instance.</param> /// <param name="docSpec">Document specification.</param> public static void SetDocProperties(IPipelineContext pContext, string messageType, IBaseMessage pInMsg, ref string docSpec) { try { pInMsg.Context.Promote(BtsProperties.MessageType.Name, BtsProperties.MessageType.Namespace, (object)messageType); IDocumentSpec documentSpecByType = pContext.GetDocumentSpecByType(messageType); if (documentSpecByType == null) { return; } pInMsg.Context.Write(DasmProperties.DocumentSpecName.Name, DasmProperties.DocumentSpecName.Namespace, (object)null); pInMsg.Context.Write(BtsProperties.SchemaStrongName.Name, BtsProperties.SchemaStrongName.Namespace, (object)documentSpecByType.DocSpecStrongName); docSpec = docSpec == null ? (docSpec = documentSpecByType.DocSpecName) : docSpec; } catch (DocumentSpecException ex) { // Todo log this error DECore.TraceProvider.Logger.TraceInfo(ex.ToString()); } catch (COMException ex) { // Todo log this errors DECore.TraceProvider.Logger.TraceInfo(ex.ToString()); } catch (Exception ex) { DECore.TraceProvider.Logger.TraceError(ex); throw; } }
private XmlSchema GetMatchingSchema(IPipelineContext pipelineContext, Stream xmlStream) { XmlSchema schema = null; IDocumentSpec documentSpecByType = null; string docType = Utils.GetDocType(MarkableForwardOnlyEventingReadStream.EnsureMarkable(xmlStream)); try { documentSpecByType = pipelineContext.GetDocumentSpecByType(docType); } catch (Exception) { return(null); } XmlSchemaSet schemaSet = (documentSpecByType as IDocumentSpec2).GetSchemaSet(); if (schemaSet.Count == 0) { return(null); } foreach (XmlSchema schema2 in schemaSet.Schemas()) { if (docType.Contains(schema2.TargetNamespace + "#")) { schema = schema2; } } return(schema); }
void IDisassemblerComponent.Disassemble(IPipelineContext pContext, IBaseMessage pInMsg) { innerDasm.EnvelopeSpecNames = this.EnvelopeSpecNames; //Important not to add the DocumentSpecNames to the inner disassembler as it will not allow messages //that we want to ignore, that is not the same as AllowUnrecognizedMessage = true as UnrecognizedMessage //means a message without corresponding installed schema //This is also why i could not sublass XmlDasmComp innerDasm.AllowUnrecognizedMessage = true; innerDasm.ValidateDocument = this.ValidateDocument; innerDasm.RecoverableInterchangeProcessing = this.RecoverableInterchangeProcessing; SchemaList documents = this.DocumentSpecNames; foreach (Schema item in documents) { IDocumentSpec documentSpec = pContext.GetDocumentSpecByName(item.SchemaName); string[] messageParts = documentSpec.DocType.Split(new char[] { '#' }); MessageType msgType = new MessageType { RootName = messageParts[1] , TargetNamespace = messageParts[0] }; if (messageTypes.ContainsKey(msgType) == false) { messageTypes.Add(msgType, documentSpec); } } innerDasm.Disassemble(pContext, pInMsg); }
public void CanLoadDocSpecWithPromotedProperties() { DocSpecLoader loader = new DocSpecLoader(); IDocumentSpec docSpec = loader.LoadDocSpec(typeof(Schema2_WPP)); Assert.IsNotNull(docSpec); }
/// <summary> /// Sets the message schema strong name and message type. /// </summary> /// <param name="context">Pipeline context.</param> /// <param name="message">Message instance.</param> public static void SetDocProperties(IPipelineContext context, IBaseMessage msg) { if (context == null) { throw new ArgumentNullException("context"); } if (msg == null) { throw new ArgumentNullException("msg"); } object obj = msg.Context.Read(BtsProperties.SchemaStrongName.Name, BtsProperties.SchemaStrongName.Namespace); if (obj != null && string.Compare(obj.ToString(), "Microsoft.XLANGs.BaseTypes.Any, Microsoft.XLANGs.BaseTypes, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", true, CultureInfo.CurrentCulture) == 0) { msg.Context.Write(BtsProperties.SchemaStrongName.Name, BtsProperties.SchemaStrongName.Namespace, (object)null); } string DocSpecName = (string)msg.Context.Read(BtsProperties.SchemaStrongName.Name, BtsProperties.SchemaStrongName.Namespace) ?? string.Empty; DECore.TraceProvider.Logger.TraceInfo(string.Format("Schema strong name is {0} after first context read.", new object[1] { obj })); string str = (string)msg.Context.Read(BtsProperties.MessageType.Name, BtsProperties.MessageType.Namespace) ?? string.Empty; DECore.TraceProvider.Logger.TraceInfo(string.Format("Document message type is {0} after first context read.", new object[1] { (object)str })); if (!string.IsNullOrEmpty(str)) { return; } if (!string.IsNullOrEmpty(DocSpecName)) { IDocumentSpec documentSpec = (IDocumentSpec)null; try { documentSpec = context.GetDocumentSpecByName(DocSpecName); } catch (DocumentSpecException ex) { // Todo Log this Error DECore.TraceProvider.Logger.TraceInfo(ex.ToString()); } catch (COMException ex) { // todo Log this erro DECore.TraceProvider.Logger.TraceInfo(ex.ToString()); } if (documentSpec != null) { str = documentSpec.DocType; } } msg.Context.Write(BtsProperties.MessageType.Name, BtsProperties.MessageType.Namespace, (object)str); DECore.TraceProvider.Logger.TraceInfo(string.Format("Message type is {0}.", new object[1] { (object)str })); }
/// <summary> /// Adds a document specification to the context /// </summary> /// <param name="docSpec">Specification to add</param> private void AddDocSpecToContext(IDocumentSpec docSpec) { IConfigurePipelineContext ctxt = (IConfigurePipelineContext) Context; ctxt.AddDocSpecByType(docSpec.DocType, docSpec); // Pipelines referencing local schemas in the same // assembly don't have use the assembly qualified name // of the schema when trying to find it. ctxt.AddDocSpecByName(docSpec.DocSpecStrongName, docSpec); ctxt.AddDocSpecByName(docSpec.DocSpecName, docSpec); }
/// <summary> /// Adds a new document specification to the list /// of Known Schemas for this pipeline. /// </summary> /// <remarks> /// Adding known schemas is necessary so that /// document type resolution works in the disassembler/assembler /// stages. Notice that this overload does NOT do automatic checking /// for multiple roots. /// </remarks> /// <param name="typeName"> /// The fully qualified (namespace.class) name of /// the schema /// </param> /// <param name="assemblyName"> /// The partial or full name of the assembly /// containing the schema /// </param> public void AddDocSpec(string typeName, string assemblyName) { if (String.IsNullOrEmpty(typeName)) throw new ArgumentNullException("typeName"); if (String.IsNullOrEmpty(assemblyName)) throw new ArgumentNullException("assemblyName"); IDocumentSpec spec = LoadDocSpec(typeName, assemblyName); AddDocSpecToContext(spec); }
public IDocumentSpec GetDocumentSpecByType(string docType) { IDocumentSpec spec = (IDocumentSpec)this.typeToDocSpecMap[docType]; if (spec == null) { throw new COMException(); } return(spec); }
/// <summary> /// Adds a new document specification to the context /// </summary> /// <param name="type">XML namespace#root</param> /// <param name="documentSpec">Document Spec</param> public void AddDocSpecByType(string type, IDocumentSpec documentSpec) { if (type == null) throw new ArgumentNullException("type"); if (documentSpec == null) throw new ArgumentNullException("documentSpec"); if (!_docSpecsByType.ContainsKey(type)) _docSpecsByType.Add(type, documentSpec); }
public IDocumentSpec GetDocumentSpecByName(string docspecName) { IDocumentSpec spec = (IDocumentSpec)this.nameToDocSpecMap[docspecName]; if (spec == null) { throw new COMException(); } return(spec); }
// // IConfigurePipelineContext Members // /// <summary> /// Adds a new document specification to the context /// </summary> /// <param name="name">CLR Type name</param> /// <param name="documentSpec">Document Spec</param> public void AddDocSpecByName(string name, IDocumentSpec documentSpec) { if (name == null) throw new ArgumentNullException("name"); if (documentSpec == null) throw new ArgumentNullException("documentSpec"); if (!_docSpecsByName.ContainsKey(name)) _docSpecsByName.Add(name, documentSpec); }
public void CanAddNoTargetNSDocSpec() { ReceivePipelineWrapper pipeline = PipelineFactory.CreateEmptyReceivePipeline(); pipeline.AddDocSpec(typeof(NoNS)); IDocumentSpec docSpec = pipeline.GetKnownDocSpecByType("Root"); Assert.IsNotNull(docSpec); }
//Add schema public void addppDocSpec(Type schemaType) { if (schemaType == null) { throw new ArgumentNullException("schemaType"); } Type[] roots = getSchRoots(schemaType); foreach (Type root in roots) { IDocumentSpec docSpec = getSchemaSpec(root); docSpecinMsgContxt(docSpec); } }
public void CanAddDocSpecByName() { ReceivePipelineWrapper pipeline = PipelineFactory.CreateEmptyReceivePipeline(); pipeline.AddDocSpec("SampleSchemas.Schema1_NPP+Root", "SampleSchemas"); IDocumentSpec docSpec = pipeline.GetKnownDocSpecByName(typeof(Schema1_NPP.Root).AssemblyQualifiedName); Assert.IsNotNull(docSpec); docSpec = pipeline.GetKnownDocSpecByType("http://SampleSchemas.Schema1_NPP#Root"); Assert.IsNotNull(docSpec); }
//Add schema from assembly public void addppDocSpec(string typeName, string assemblyName) { if (String.IsNullOrEmpty(typeName)) { throw new ArgumentNullException("typeName"); } if (String.IsNullOrEmpty(assemblyName)) { throw new ArgumentNullException("assemblyName"); } IDocumentSpec spec = getSchemaSpec(typeName, assemblyName); docSpecinMsgContxt(spec); }
/// <summary> /// Adds a new document specification to the list /// of Known Schemas for this pipeline. /// </summary> /// <remarks> /// Adding known schemas is necessary so that /// document type resolution works in the disassembler/assembler /// stages /// </remarks> /// <param name="schemaType">Type of the document schema to add</param> public void AddDocSpec(Type schemaType) { if (schemaType == null) { throw new ArgumentNullException("schemaType"); } DocSpecLoader loader = new DocSpecLoader(); Type[] roots = GetSchemaRoots(schemaType); foreach (Type root in roots) { IDocumentSpec docSpec = loader.LoadDocSpec(root); AddDocSpecToContext(docSpec); } }
/// <summary> /// Adds a new document specification to the list /// of Known Schemas for this pipeline. /// </summary> /// <remarks> /// Adding known schemas is necessary so that /// document type resolution works in the disassembler/assembler /// stages /// </remarks> /// <param name="schemaType">Type of the document schema to add</param> public void AddDocSpec(Type schemaType) { if (schemaType == null) { //16042014 return; //16042014 throw new ArgumentNullException("schemaType"); } Type[] roots = GetSchemaRoots(schemaType); foreach (Type root in roots) { IDocumentSpec docSpec = LoadDocSpec(root); AddDocSpecToContext(docSpec); } }
IBaseMessage GetNextMessage(IPipelineContext pContext) { IBaseMessage outMsg = null; if (childReader == null || childReader.EOF) { baseMsg = innerDasm.GetNext(pContext); if (baseMsg == null) { return(baseMsg); } childReader = XmlReader.Create(baseMsg.BodyPart.GetOriginalDataStream()); } while (childReader.Read()) { MessageType msgType = new MessageType { RootName = childReader.LocalName , TargetNamespace = childReader.NamespaceURI }; if (messageTypes.ContainsKey(msgType)) { currDocument = messageTypes[msgType]; //Is used XmlTranslatorStream as it is the only one i could find that takes an XmlReader as input //At this point i did not want to write my own custom stream // XmlTranslatorStream trans = new XmlTranslatorStream(childReader.ReadSubtree()); outMsg = CreateMessage(pContext, childReader); break; } } if (outMsg == null) { outMsg = GetNextMessage(pContext); //make sure there is no more messages in base queue } return(outMsg); //return null if the message is null, but check if there exists more enveloped messages }
private string GetSourceMessageMatchingMapName(ArrayList mapList, string btsMsgType, IPipelineContext context) { string mapName = string.Empty; if (mapList.Count > 1) { foreach (string map in mapList) { try { Type type = Type.GetType(map); TransformMetaData transformMetaData = TransformMetaData.For(type); SchemaMetadata sourceSchemaMetadata = transformMetaData.SourceSchemas[0]; string mapSourceSchemaName = sourceSchemaMetadata.SchemaName; IDocumentSpec documentSpec = context.GetDocumentSpecByType(btsMsgType); string msgSourceSchemaName = documentSpec.DocType; Logger.WriteTrace("Map Source Schema Name: " + mapSourceSchemaName); Logger.WriteTrace("Msg Source Schema Name: " + msgSourceSchemaName); if (string.Compare(mapSourceSchemaName, msgSourceSchemaName, false, CultureInfo.CurrentCulture) == 0) { Logger.WriteTrace("Match found: " + map); mapName = map; break; } } catch (Exception) { } } } else { mapName = mapList[0].ToString(); } return(mapName); }
/// <summary> /// Wrapper To perform XmlValidation /// </summary> /// <param name="docSpec">The Document NameSpec derieved for the message</param> /// <param name="maxErrorCount">maximum number of Schema validation errors to be captured</param> /// <param name="stream">Stream representation of the incoming message</param> /// <param name="messageType">Message Type of the incoming message</param> /// <param name="messageId">Id of the incoming message</param> public void ValidationWrapper(IDocumentSpec docSpec, int maxErrorCount, VirtualStream stream, string messageType, string messageId) { XmlSchemaSet schemas = new XmlSchemaSet(); try { foreach (var schema in docSpec.GetSchemaCollection()) { schemas.Add(schema); } } catch (XmlSchemaException ex) { string errorDescription = string.Format("An error occured while loading the schemas. Error Message: {0} \r\nLine: {1}, Position: {2} \r\n", ex.Message, ex.LineNumber, ex.LinePosition); throw new Exception(errorDescription); } catch (Exception sysEx) { throw new Exception("An error occured while loading the schemas. Error detail: " + sysEx.ToString()); } Validate(stream, schemas, maxErrorCount, messageType, messageId); }
public static IInitializeDocumentSpec InitializeDocumentSpec(IDocumentSpec documentSpec, string documentSpecName, string schemaFileName, ArrayList propertyAnnotations) { IInitializeDocumentSpec spec = (IInitializeDocumentSpec)documentSpec; XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(new XmlTextReader(schemaFileName)); string documentType = GetDocumentType(xmlDocument); string targetNamespace = GetTargetNamespace(xmlDocument); string bodyXPath = GetBodyXPath(xmlDocument); Hashtable schemaList = new Hashtable(); schemaList.Add(targetNamespace, new FileStream(schemaFileName, FileMode.Open, FileAccess.Read)); spec.Initialize(targetNamespace, documentSpecName, documentType, bodyXPath, schemaList); NameTable nameTable = new NameTable(); XmlNamespaceManager nsmgr = new XmlNamespaceManager(nameTable); nsmgr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema"); nsmgr.AddNamespace("b", "http://schemas.microsoft.com/BizTalk/2003"); Hashtable hashtable2 = new Hashtable(); Hashtable hashtable3 = new Hashtable(); foreach (XmlNode node in xmlDocument.SelectNodes("/xs:schema/xs:annotation/xs:appinfo/b:imports/b:namespace", nsmgr)) { hashtable2.Add(node.Attributes["prefix"].InnerText, node.Attributes["uri"].InnerText); string innerText = node.Attributes["location"].InnerText; if (new FileInfo(innerText).Exists) { XmlDocument document2 = new XmlDocument(); document2.Load(innerText); hashtable3.Add(node.Attributes["uri"].InnerText, document2); } } foreach (XmlNode node2 in xmlDocument.SelectNodes("/xs:schema//xs:annotation/xs:appinfo/b:properties/b:property[not(@distinguished='true')]", nsmgr)) { PropertyAnnotation annotation = new PropertyAnnotation(); string str5 = node2.Attributes["name"].InnerText; annotation.Name = str5.Split(new char[] { ':' })[1]; annotation.Namespace = (string)hashtable2[str5.Split(new char[] { ':' })[0]]; annotation.XPath = node2.Attributes["xpath"].InnerText; annotation.XSDType = null; XmlDocument document3 = (XmlDocument)hashtable3[annotation.Namespace]; if (document3 != null) { XmlNode node3 = document3.SelectSingleNode(string.Format(CultureInfo.CurrentCulture, "/xs:schema/xs:element[@name='{0}']", new object[] { annotation.Name }), nsmgr); if (node3 != null) { XmlNode node4 = node3.Attributes["type"]; if (node4 != null) { string[] strArray = node4.InnerText.Split(new char[] { ':' }); if (2 == strArray.Length) { annotation.XSDType = strArray[1]; } else if (1 == strArray.Length) { annotation.XSDType = strArray[0]; } } } } if (annotation.XSDType == null) { annotation.XSDType = "string"; } if (propertyAnnotations != null) { propertyAnnotations.Add(annotation); } spec.AddAnnotation(annotation); } return(spec); }
public void AddDocSpecByName(string name, IDocumentSpec docSpec) { this.nameToDocSpecMap.Add(name, docSpec); }
public void AddDocSpecByType(string type, IDocumentSpec docSpec) { this.typeToDocSpecMap.Add(type, docSpec); }
/// <summary> /// Adds a new document specification to the context /// </summary> /// <param name="type">XML namespace#root</param> /// <param name="documentSpec">Document Spec</param> public void AddDocSpecByType(string type, IDocumentSpec documentSpec) { if ( type == null ) throw new ArgumentNullException("type"); if ( documentSpec == null ) throw new ArgumentNullException("documentSpec"); if ( !_docSpecsByType.ContainsKey(type) ) _docSpecsByType.Add(type, documentSpec); }
/// <summary> /// Examine the incoming message and determine which document spec name (specifically which strong name) to assign. /// </summary> /// <param name="pContext"></param> /// <param name="pInMsg"></param> /// <returns></returns> public bool Probe(IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg) { bool handled = false; //the messagetype is not unique, which is why the biztalk resolver fails. However, the docSpecName IS unique as it contains //the FQN, eg the docspecName for the SAM unLockBAResponse is ES.FS.WG.SAM.Schemas.SAMSchemas.SAMServiceSchemas.SamServiceService_servlet_x2esam_x2eedscs_x2eeds_x2ecom+unLockBAResponse //Whereas the docSpecName for the STAX unLockBAResponse is ES.FS.WG.STAX.Schemas.SAMSchemas.SamServiceService_servlet_x2esam_x2eedscs_x2eeds_x2ecom+unLockBAResponse. string rootNodeName = string.Empty; string messageType = GetMessageType(pInMsg, out rootNodeName); //Is this a messageType we know how to handle //ie does the messageType exist in the schema assembly we are resolving to. //NOTE: If the schema contains only a single root node, the docSpecName does NOT include the rootNodeName string docSpecName = string.Empty; if (_multiElementSchema) { docSpecName = string.Format("{0}.{1}+{2}", DocSpecQN, DocSpecClassName, rootNodeName); } else { docSpecName = string.Format("{0}.{1}", DocSpecQN, DocSpecClassName); } string docSpecStrongName = string.Format("{0}, {1}", docSpecName, AssemblyStrongName); IDocumentSpec docSpec = null; try { //determine if this is a valid doc spec name by loading the doc spec (effectively queries the BT mgt database for us) //look up from Biztalk to ensure strongname is valid, if lookup fails an exception is thrown docSpec = pContext.GetDocumentSpecByName(docSpecStrongName); //first check the cache, if not in cache retrieve from Biztalk and place in cache //if it is in the cache, it is inherently a valid docSpecStrongName as it must have already been looked up from Biztalk //so no need to do anything further, just assign the strong name to the message //if (!StrongNameCache.ContainsKey(rootNodeName)) //{ // //look up from Biztalk to ensure strongname is valid, if lookup fails an exception is thrown // docSpec = pContext.GetDocumentSpecByName(docSpecStrongName); // //if capacity reached, remove the first entry added to the cache. // if (StrongNameCache.Count == CacheCapacity) // { // string keyToRemove = StrongNameCache.ElementAt(0).Key; // StrongNameCache.Remove(keyToRemove); // } // StrongNameCache[rootNodeName] = docSpec.DocSpecStrongName; //} //make sure the incoming message matches the docSpec we found handled = (docSpec.DocType == messageType); } catch (Exception) { //consume the exception and return false (not handled by this component) //_logger.DebugFormat("XmlSchemaResolver:: Probe: Message not being handled {0}, DocSpecName {1}", messageType, docSpecStrongName); } if (handled) { pInMsg.Context.Write("DocumentSpecName", "http://schemas.microsoft.com/BizTalk/2003/xmlnorm-properties", docSpecStrongName); } else { handled = _xmlDissambler.Probe(pContext, pInMsg); } return(handled); }
// // IConfigurePipelineContext Members // /// <summary> /// Adds a new document specification to the context /// </summary> /// <param name="name">CLR Type name</param> /// <param name="documentSpec">Document Spec</param> public void AddDocSpecByName(string name, IDocumentSpec documentSpec) { if ( name == null ) throw new ArgumentNullException("name"); if ( documentSpec == null ) throw new ArgumentNullException("documentSpec"); if ( !_docSpecsByName.ContainsKey(name) ) _docSpecsByName.Add(name, documentSpec); }
public static bool TryGetDocumentSpecByType(this IPipelineContext pipelineContext, string docType, out IDocumentSpec documentSpec) { try { documentSpec = pipelineContext.GetDocumentSpecByType(docType); return(true); } catch (COMException exception) { documentSpec = null; // test HResult for Finding the document specification by message type "..." failed. Verify the schema deployed properly. if (exception.HResult == E_SCHEMA_NOT_FOUND) { return(false); } if (_logger.IsWarnEnabled) { _logger.Warn(string.Format("SafeGetDocumentSpecByType({0}) has failed.", docType), exception); } throw; } }
/// <summary> /// processes the inbound message part /// </summary> /// <param name="pc"></param> /// <param name="inmsg"></param> /// <param name="outmsg"></param> /// <param name="part"></param> private void ProcessPart(IPipelineContext pc, IBaseMessage inmsg, IBaseMessage outmsg, IBaseMessagePart part) { IDocumentSpec docSpec = null; Stream dataStream = part.GetOriginalDataStream(); MarkableForwardOnlyEventingReadStream eventingDataStream = new MarkableForwardOnlyEventingReadStream(dataStream); XmlSchemaCollection schemaCollection = new XmlSchemaCollection(new NameTable()); schemaCollection.ValidationEventHandler += new ValidationEventHandler(this.ValidationCallBack); // retrieve the assigned document schemas to validate against SchemaList docSchemas = this.DocumentSchemas; // retrieve the namespace this document adheres to string contextProperty = (string)outmsg.Context.Read(XmlCompleteValidator._documentSpecNameProperty.Name.Name, XmlCompleteValidator._documentSpecNameProperty.Name.Namespace); // if the inbound message has a namespace, if (contextProperty != null && contextProperty.Length > 0) { // clear the original schemas to validate against docSchemas.Clear(); string[] contextSchemas = contextProperty.Split(new char[] { '|' }); // set it's schemas foreach (string schemaName in contextSchemas) { docSchemas.Add(new Schema(schemaName)); } } #region retrieve validation schemas, shamelessly copied from the original XmlValidator pipeline component bool validateSchemas = this.DocumentSchemas != null && this.DocumentSchemas.Count > 0; if (validateSchemas && this.DocumentSchemas.Count == 1 && this.DocumentSchemas[0].SchemaName.Length == 0) { validateSchemas = false; } if (validateSchemas) { foreach (Schema s in docSchemas) { try { docSpec = pc.GetDocumentSpecByName(s.SchemaName); } catch (COMException e) { throw new XmlCompleteValidatorException( ExceptionType.CANNOT_GET_DOCSPEC_BY_NAME, e.ErrorCode.ToString("X") + ": " + e.Message, new string[] { s.SchemaName }); } if (docSpec == null) { throw new XmlCompleteValidatorException( ExceptionType.CANNOT_GET_DOCSPEC_BY_NAME, string.Empty, new string[] { s.SchemaName }); } XmlSchemaCollection coll = docSpec.GetSchemaCollection(); schemaCollection.Add(coll); } } else { try { docSpec = pc.GetDocumentSpecByType(Utils.GetDocType(eventingDataStream)); } catch (COMException e) { throw new XmlCompleteValidatorException( ExceptionType.CANNOT_GET_DOCSPEC_BY_TYPE, e.ErrorCode.ToString("X") + ": " + e.Message, new string[] { Utils.GetDocType(eventingDataStream) }); } if (docSpec == null) { throw new XmlCompleteValidatorException( ExceptionType.CANNOT_GET_DOCSPEC_BY_TYPE, string.Empty, new string[] { Utils.GetDocType(eventingDataStream) }); } schemaCollection = docSpec.GetSchemaCollection(); } #endregion // the most critical line within this component, assign an // XmlEventingValidationStream to ensure the inbound messagestream is validated // and events can be assigned which allow us to capture any erros that might occur XmlEventingValidationStream validatingStream = new XmlEventingValidationStream(eventingDataStream); // add the schemas we'd like to validate the inbound message against validatingStream.Schemas.Add(schemaCollection); // assign a validation event which will accumulate any errors within the inbound message validatingStream.ValidatingReader.ValidationEventHandler += new ValidationEventHandler(XmlMessageValidationCallBack); // and assign the AfterLastReadEvent, which fires upon reading the last piece of information // from the inbound message stream and pushes all accumulated error information out into // the eventviewer and onto the HAT context by throwing an exception which contains the errors validatingStream.AfterLastReadEvent += new AfterLastReadEventHandler(validatingStream_AfterLastReadEvent); // duplicate the inbound message part by creating a new one and copying it's properties IBaseMessageFactory messageFactory = pc.GetMessageFactory(); IBaseMessagePart messagePart = messageFactory.CreateMessagePart(); // if the inbound message exists and has a body part, copy the part properties // into the outbound messagepart if (inmsg != null && inmsg.BodyPart != null) { messagePart.PartProperties = PipelineUtil.CopyPropertyBag(inmsg.BodyPart.PartProperties, messageFactory); } // set the outbound charset messagePart.Charset = "UTF-8"; // set the outbound content type messagePart.ContentType = "text/xml"; // and assign the outbound datastream messagePart.Data = validatingStream; // finally, copy existing message parts CopyMessageParts(pc, inmsg, outmsg, messagePart, false); }
/// <summary> /// Executes the logic for this component. /// </summary> /// <param name="pContext">Pipeline context</param> /// <param name="pInMsg">Input message</param> /// <returns>Outgoing message</returns> private IBaseMessage ExecuteInternal(IPipelineContext pContext, IBaseMessage pInMsg) { // Check arguments if (null == pContext) { throw new ArgumentNullException("pContext"); } if (null == pInMsg) { throw new ArgumentNullException("pInMsg"); } if (null == pInMsg.BodyPart) { throw new ArgumentNullException("pInMsg.BodyPart"); } if (null == pInMsg.BodyPart.GetOriginalDataStream()) { throw new ArgumentNullException("pInMsg.BodyPart.GetOriginalDataStream()"); } // // The logic behind this component is as follows: // 1. Create a seekable read-only stream over the input message body part stream // (because input message can be both large and stream can be non-seekable, // so it should have small memory footprint and change stream positions). // 2. Create a new outgoing message, new body part for it, assign seekable read-only stream // to the new body part, clone body part properties, clone message context. // 3. Get a schema for the input message or based on schemas specified during // design time. // 4. Load stream into XmlDocument. // 5. Walk through promoted properties and distinguished fields and promote/write // them to the message context of the outgoing message. // 6. Return outgoing message. // // // 1. Create a seekable read-only stream over the input message body part stream. // // Create a virtual stream, using GetOriginalDataStream() method on the IBaseMessagePart because // this call doesn't clone stream (instead of IBaseMessagePart.Data property). SeekableReadOnlyStream stream = new SeekableReadOnlyStream(pInMsg.BodyPart.GetOriginalDataStream()); // // 2. Create a new outgoing message, copy all required stuff. // // Create a new output message IBaseMessage outMessage = pContext.GetMessageFactory().CreateMessage(); // Copy message context by reference outMessage.Context = pInMsg.Context; // Create new message body part IBaseMessagePart newBodyPart = pContext.GetMessageFactory().CreateMessagePart(); // Copy body part properties by references. newBodyPart.PartProperties = pInMsg.BodyPart.PartProperties; // Set virtual stream as a data stream for the new message body part newBodyPart.Data = stream; // Copy message parts CopyMessageParts(pInMsg, outMessage, newBodyPart); // // 3. Get a schema for the message. // // Initialize schema map SchemaMap schemaMap = new SchemaMap(this.documentSchemaList); // Get message type from the message data stream string messageType = GetMessageType(stream); // Get a document spec from based on the message type IDocumentSpec documentSpec = schemaMap[messageType]; if (null == documentSpec) { documentSpec = pContext.GetDocumentSpecByType(messageType); } // Promote BTS.MessageType message context property to allow orchestration schedule instances be activated // on produced message. outMessage.Context.Promote(messageTypeWrapper.Name.Name, messageTypeWrapper.Name.Namespace, messageType); // // 4. Load document stream into XmlDocument. // // Save new message stream's current position long position = stream.Position; // Load document into XmlDocument XmlDocument document = new XmlDocument(); document.Load(stream); // Restore the 0 position for the virtual stream Debug.Assert(stream.CanSeek); // Restore new message stream's current position stream.Position = position; // // 5. Walk through promoted properties/distinguished fields and promote/write them. // // Walk through and promote properties IEnumerator annotations = documentSpec.GetPropertyAnnotationEnumerator(); while (annotations.MoveNext()) { IPropertyAnnotation annotation = (IPropertyAnnotation)annotations.Current; XmlNode propertyNode = document.SelectSingleNode(annotation.XPath); if (propertyNode != null) { // Promote context property to the message context as a typed value outMessage.Context.Promote(annotation.Name, annotation.Namespace, promotingMap.MapValue(propertyNode.InnerText, annotation.XSDType)); } } // Walk through and write distinguished fields IDictionaryEnumerator distFields = documentSpec.GetDistinguishedPropertyAnnotationEnumerator(); // IDocumentSpec.GetDistinguishedPropertyAnnotationEnumerator() can return null if (distFields != null) { while (distFields.MoveNext()) { DistinguishedFieldDefinition distField = (DistinguishedFieldDefinition)distFields.Value; XmlNode distFieldNode = document.SelectSingleNode(distField.XPath); if (distFieldNode != null) { // Write distinguished field to the message context as a string value outMessage.Context.Write(distField.XPath, Globals.DistinguishedFieldsNamespace, distFieldNode.InnerText); } } } // // 6. Return outgoing message. // return(outMessage); }
public static bool TryGetDocumentSpecByType(this IPipelineContext pipelineContext, string docType, out IDocumentSpec documentSpec) { if (pipelineContext == null) { throw new ArgumentNullException(nameof(pipelineContext)); } try { documentSpec = pipelineContext.GetDocumentSpecByType(docType); return(true); } catch (COMException exception) { documentSpec = null; if ((uint)exception.ErrorCode == (uint)HResult.ErrorSchemaNotFound) { return(false); } if (_logger.IsWarnEnabled) { _logger.Warn($"SafeGetDocumentSpecByType({docType}) has failed.", exception); } throw; } }
public bool Probe(IPipelineContext pContext, IBaseMessage pInMsg) { // Check arguments if (null == pContext) { throw new ArgumentNullException("pContext"); } if (null == pInMsg) { throw new ArgumentNullException("pInMsg"); } // We need to determine a document schema to use based on message content. For the sake of simplicity of this // sample, we will check the first two characters in input stream and map them to some schema message types we // have predefined. The more sofisticated component could use UI configuration options to map identification // text located at specified offsets in message stream and having specified length, which could map to specified // message type or document spec type name. // Check whether input message doesn't have a body part or it is set to null, fail probe in those cases if (null == pInMsg.BodyPart || null == pInMsg.BodyPart.GetOriginalDataStream()) { return(false); } SeekableReadOnlyStream stream = new SeekableReadOnlyStream(pInMsg.BodyPart.GetOriginalDataStream()); Stream sourceStream = pInMsg.BodyPart.GetOriginalDataStream(); // Check if source stream can seek if (!sourceStream.CanSeek) { // Create a virtual (seekable) stream SeekableReadOnlyStream seekableStream = new SeekableReadOnlyStream(sourceStream); // Set new stream for the body part data of the input message. This new stream will then used for further processing. // We need to do this because input stream may not support seeking, so we wrap it with a seekable stream. pInMsg.BodyPart.Data = seekableStream; // Replace sourceStream with a new seekable stream wrapper sourceStream = pInMsg.BodyPart.Data; } // Preserve the stream position long position = sourceStream.Position; char [] signature = new char[2]; try { // Read signature from a stream StreamReader reader = new StreamReader(sourceStream); if (reader.Read(signature, 0, signature.Length) < signature.Length) { return(false); } // Don't close stream reader to avoid closing of underlying stream } finally { // Restore the stream position sourceStream.Position = position; } // Get message type from signature string messageType = GetMessageType(new string(signature)); // Fail if message type is unknown if (null == messageType) { return(false); } // Get document spec from the message type IDocumentSpec documentSpec = pContext.GetDocumentSpecByType(messageType); // Instead of loading schema to get a document spec type name we could change implementation to return defined // during a design time document spec type name and directly specify it in the call below: // Write document spec type name to the message context so Flat File disassembler could access this property and // do message processing for a schema which has document spec type name we've discovered pInMsg.Context.Write(DocumentSpecNamePropertyName, XmlNormNamespaceURI, documentSpec.DocSpecStrongName); // Delegate call to Flat File disassembler return(disassembler.Probe(pContext, pInMsg)); }
/// <summary> /// Execute the Custom Logic To Do the Schema Validation /// </summary> /// <param name="pContext">Pipeline context</param> /// <param name="pInMsg">Input message to the pipeline</param> /// <returns>Output message</returns> public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg) { _logger.Debug("PipelineComponent::XmlValidator: Executing validation pipeline component."); int maxErrorCount = 20; //Parse the maxErrorCount property value to int Int32.TryParse(_maxErrorCount, out maxErrorCount); string messageType = Convert.ToString(pInMsg.Context.Read(Constants.MessageTypePropName, Constants.SystemPropertiesNamespace)); string messageId = Convert.ToString(pInMsg.MessageID); string fileName = Convert.ToString(pInMsg.Context.Read(Constants.ReceivedFileNamePropName, Constants.FileAdapterPropertiesNameSpace)); fileName = PipelineHelper.GetFileNameWithoutExtension(fileName); XmlValidatorHelper helper = new XmlValidatorHelper(); // (maxErrorCount, fileName); helper.Logger = _logger; if (pContext == null) { throw new ArgumentNullException("Pipeline Context is null"); } if (pInMsg == null) { throw new ArgumentNullException("Incoming Message in null"); } //Create OutMessage //Invoke the XMLValidator Validate Method var originalStream = pInMsg.BodyPart.GetOriginalDataStream(); Stream seekableStream; if (!originalStream.CanSeek) { seekableStream = new ReadOnlySeekableStream(originalStream); pInMsg.BodyPart.Data = seekableStream; } else { seekableStream = originalStream; } IDocumentSpec docSpec = null; try { docSpec = pContext.GetDocumentSpecByType(messageType); //Use a temperory Disposable Virtual Stream using (VirtualStream virtusalStream = new VirtualStream()) { seekableStream.CopyTo(virtusalStream); virtusalStream.Position = 0; helper.ValidationWrapper(docSpec, maxErrorCount, virtusalStream, messageType, messageId); } //var errorProcessStatus = null; // helper.ProcessStatus; ////Check if validation Helper has caught any errors //if (errorProcessStatus.Errors != null && errorProcessStatus.Errors.Count() > 0) //{ // return CreateOutputMessageWrapper(pContext, pInMsg, errorProcessStatus, fileName); //} //else //{ // //Need to move the wrapped seekable stream to beginning and assign to the BodyPart as incoming message is not seekable // seekableStream.Seek(0, SeekOrigin.Begin); // // Track the stream so that it can be disposed when the message is finially finished with // pContext.ResourceTracker.AddResource(pInMsg.BodyPart.Data); return(pInMsg); //} } catch (Exception ex) { string errorMessage = string.Format("RequestId: {0} ErrorMessage: {1}", fileName, ex.Message); _logger.Error(errorMessage); return(pInMsg); } }