using System;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Xml;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.BizTalk.Message.Interop;
namespace Company.BizTalk.PipelineComponents
{
/// <summary>
/// Custom component for adding a default namespace to a document.
/// It is possible to define a namespace for an explicit root element by defining
/// the root element and the namespace like this:
/// RootElement1 = Navision_SOC
/// Namespace1 = http://www.business.com/BizTalk/Common/v100
/// Adds namespace http://www.business.com/BizTalk/Common/v100 to an XmL document
/// with rootelement Navision_SOC.
/// RootElement1 and RootElement2 in combination with Namespace1 and Namespace2
/// work simular.
/// It is also possible to define a default namespace.
/// If a rootelement isn't defined to by one of the above rootelements, then the
/// default namespace is used.
/// </summary>
[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[System.Runtime.InteropServices.Guid("6BC4F961-EF65-4190-BC6D-F57AA063D938")]
[ComponentCategory(CategoryTypes.CATID_Decoder)]
public class NamespaceAdderComponent :
Microsoft.BizTalk.Component.Interop.IComponent,
IBaseComponent, IPersistPropertyBag, IComponentUI
{
#region Properties
/// <summary>
/// First root element to look for.
/// </summary>
private string _RootElement1;
/// <summary>
/// First root element to look for.
/// </summary>
public string RootElement1
{
get
{
return _RootElement1;
}
set
{
_RootElement1 = value;
}
}
/// <summary>
/// Namespace to be used for the first defined root element.
/// </summary>
private string _Namespace1;
/// <summary>
/// Namespace to be used for the first defined root element.
/// </summary>
public string Namespace1
{
get
{
return _Namespace1;
}
set
{
_Namespace1 = value;
}
}
/// <summary>
/// Second root element to look for.
/// </summary>
private string _RootElement2;
/// <summary>
/// Second root element to look for.
/// </summary>
public string RootElement2
{
get
{
return _RootElement2;
}
set
{
_RootElement2 = value;
}
}
/// <summary>
/// Namespace to be used for the second defined root element.
/// </summary>
private string _Namespace2;
/// <summary>
/// Namespace to be used for the second defined root element.
/// </summary>
public string Namespace2
{
get
{
return _Namespace2;
}
set
{
_Namespace2 = value;
}
}
/// <summary>
/// Namespace to be used if root element does not match any of the previous
/// root elements.
/// </summary>
private string _DefaultNamespace;
/// <summary>
/// Namespace to be used if root element does not match any of the previous
/// root elements.
/// </summary>
public string DefaultNamespace
{
get
{
return _DefaultNamespace;
}
set
{
_DefaultNamespace = value;
}
}
#endregion
#region IBaseComponent members
/// <summary>
/// Name of the component
/// </summary>
[Browsable(false)]
public string Name
{
get
{
return "NamespaceAdderComponent";
}
}
/// <summary>
/// Version of the component
/// </summary>
[Browsable(false)]
public string Version
{
get
{
return "1.0.0.0";
}
}
/// <summary>
/// Description of the component
/// </summary>
[Browsable(false)]
public string Description
{
get
{
return "Adds a namespace to the root element, using the root element"
+ "to decide what namespace to add";
}
}
#endregion
#region IPersistPropertyBag members
/// <summary>
/// Gets class ID of component for usage from unmanaged code.
/// </summary>
/// <param name="classid">Class ID of the component.</param>
public void GetClassID(out System.Guid classid)
{
classid = new System.Guid("6BC4F961-EF65-4190-BC6D-F57AA063D938");
}
/// <summary>
/// Not implemented.
/// </summary>
public void InitNew()
{
}
/// <summary>
/// Loads configuration properties for the component.
/// </summary>
/// <param name="pb">Configuration property bag.</param>
/// <param name="errlog">Error status.</param>
public virtual void Load(Microsoft.BizTalk.Component.Interop.IPropertyBag pb,
int errlog)
{
object val = null;
// Read the first root element from the property bag
val = this.ReadPropertyBag(pb, "RootElement1");
if (val != null)
{
this._RootElement1 = ((string)(val));
}
// Read the first namespace from the property bag
val = this.ReadPropertyBag(pb, "Namespace1");
if (val != null)
{
this._Namespace1 = ((string)(val));
}
// Read the second root element from the property bag
val = this.ReadPropertyBag(pb, "RootElement2");
if (val != null)
{
this._RootElement2 = ((string)(val));
}
// Read the second namespace from the property bag
val = this.ReadPropertyBag(pb, "Namespace2");
if (val != null)
{
this._Namespace2 = ((string)(val));
}
// Read the default root element from the property bag
val = this.ReadPropertyBag(pb, "DefaultNamespace");
if (val != null)
{
this.DefaultNamespace = ((string)(val));
}
}
/// <summary>
/// Saves the current component configuration into the property bag.
/// </summary>
/// <param name="pb">Configuration property bag.</param>
/// <param name="fClearDirty">Not used.</param>
/// <param name="fSaveAllProperties">Not used.</param>
public virtual void Save(Microsoft.BizTalk.Component.Interop.IPropertyBag pb,
bool fClearDirty, bool fSaveAllProperties)
{
// Save the first root element
this.WritePropertyBag(pb, "RootElement1", this.RootElement1);
// Save the first namespace
this.WritePropertyBag(pb, "Namespace1", this.Namespace1);
// Save the second root element
this.WritePropertyBag(pb, "RootElement2", this.RootElement2);
// Save the second namespace
this.WritePropertyBag(pb, "Namespace2", this.Namespace2);
// Save the default root element
this.WritePropertyBag(pb, "DefaultNamespace", this.Namespace2);
}
#region utility functionality
/// <summary>
/// Reads property value from property bag.
/// </summary>
/// <param name="pb">Property bag.</param>
/// <param name="propName">Name of property.</param>
/// <returns>Value of the property.</returns>
private object ReadPropertyBag(
Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName)
{
object val = null;
try
{
pb.Read(propName, out val, 0);
}
catch (System.ArgumentException)
{
return val;
}
catch (System.Exception e)
{
throw new System.ApplicationException(e.Message);
}
return val;
}
/// <summary>
/// Writes property values into a property bag.
/// </summary>
/// <param name="pb">Property bag.</param>
/// <param name="propName">Name of property.</param>
/// <param name="val">Value of property.</param>
private void WritePropertyBag(
Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName,
object val)
{
try
{
pb.Write(propName, ref val);
}
catch (System.Exception e)
{
throw new System.ApplicationException(e.Message);
}
}
#endregion
#endregion
#region IComponentUI members
/// <summary>
/// Component icon to use in BizTalk Editor.
/// </summary>
[Browsable(false)]
public IntPtr Icon
{
get
{
return IntPtr.Zero;
}
}
/// <summary>
/// The Validate method is called by the BizTalk Editor during the build
/// of a BizTalk project.
/// </summary>
/// <param name="obj">An Object containing the configuration properties.
/// </param>
/// <returns>The IEnumerator enables the caller to enumerate through a
/// collection of strings containing error messages. These error messages
/// appear as compiler error messages. To report successful property
/// validation, the method should return an empty enumerator.</returns>
public System.Collections.IEnumerator Validate(object obj)
{
return null;
}
#endregion
#region IComponent members
/// <summary>
/// IComponent.Execute method is used to initiate
/// the processing of the message in this pipeline component.
/// </summary>
/// <param name="pc">Pipeline context.</param>
/// <param name="inmsg">Input message.</param>
/// <returns>Original input message.</returns>
public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(
Microsoft.BizTalk.Component.Interop.IPipelineContext pc,
Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
{
// Create the message that will be sent out when processing is done
IBaseMessage pOutMessage = null;
// Create an empty XML document
XmlDocument xmlDocument = new XmlDocument();
// Boolean indicating if the namespace has been set
bool isNamespaceSet = false;
try
{
// Get the data of the XML message
xmlDocument.Load(inmsg.BodyPart.Data);
}
catch (Exception e)
{
throw new Exception("Error converting message to xml", e);
}
// Check if we specified the first root element
// If we did, check if it is this document's root element
if (!string.IsNullOrEmpty(_RootElement1)
&& xmlDocument.DocumentElement.Name == _RootElement1 )
{
// Set the namespace for this message
pOutMessage = SetNamespace(inmsg, xmlDocument, _Namespace1);
// The namespace has been set
isNamespaceSet = true;
}
// Check if the namespace was allready set earlier
// If not, check if we specified a second root element
// If we did, check if it is this document's root element
if (!isNamespaceSet
&& !string.IsNullOrEmpty(_RootElement2)
&& xmlDocument.DocumentElement.Name == _RootElement2)
{
// Set the namespace for this message
pOutMessage = SetNamespace(inmsg, xmlDocument, _Namespace2);
// The namespace has been set
isNamespaceSet = true;
}
// Check if the namespace was allready set earlier
if (!isNamespaceSet)
{
// Set the namespace for this message
pOutMessage = SetNamespace(inmsg,_DefaultNamespace,
xmlDocument);
}
// Check if setting the namespace went ok
if (pOutMessage == null)
{
// If not, set the output message to be the same as the input message
pOutMessage = inmsg;
}
// Go to the start of the output message
pOutMessage.BodyPart.Data.Position = 0;
// Return the message for further processing in the pipeline
return pOutMessage;
}
/// <summary>
/// Set the namespace of a XML message.
/// </summary>
/// <param name="pInMessage">The message in which we want to set the
/// namespace.</param>
/// <param name="defaultNamespace">The namespace we want to set.</param>
/// <param name="XmlDocument">The data of the xml message.</param>
/// <returns>Original input message.</returns>
private IBaseMessage SetNamespace(IBaseMessage pInMessage,
string defaultNamespace,XmlDocument xmlDocument)
{
// Check if a namespace was provided
if (!string.IsNullOrEmpty(defaultNamespace))
{
// Used to set the namespace
string systemPropertiesNamespace =
"http://schemas.microsoft.com/BizTalk/2003/system-properties";
// Promotion of the messagetype
string messageType = defaultNamespace + "#" +
xmlDocument.DocumentElement.Name;
pInMessage.Context.Promote("MessageType",
systemPropertiesNamespace, messageType);
// Used to set the xmlns namespace
string xmlnsNS = "http://www.w3.org/2000/xmlns/";
// Add the namespace to the xml document
XmlAttribute attributeNode = xmlDocument.CreateAttribute("xmlns",
xmlnsNS);
attributeNode.Value = defaultNamespace;
xmlDocument.DocumentElement.SetAttributeNode(attributeNode);
// We will write the new XML into the message
pInMessage.BodyPart.Data = new MemoryStream();
// Save the XML into the message
xmlDocument.Save(pInMessage.BodyPart.Data);
// Go to the start of the message
pInMessage.BodyPart.Data.Position = 0;
}
// Return the message
return pInMessage;
}
#endregion
}
}
|