context: /* IOR.cs
   * 
   * Project: IIOP.NET
   * IIOPChannel
   * 
   * WHEN      RESPONSIBLE
   * 15.01.03  Dominic Ullmann (DUL), dominic.ullmann -at- elca.ch
   * 
   * Copyright 2003 Dominic Ullmann
   *
   * Copyright 2003 ELCA Informatique SA
   * Av. de la Harpe 22-24, 1000 Lausanne 13, Switzerland
   * www.elca.ch
   * 
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  
  using System;
  using System.Diagnostics;
  using System.IO;
  using System.Collections;
  using System.Text;
  
  using Ch.Elca.Iiop.Cdr;
  using Ch.Elca.Iiop.Util;
  using Ch.Elca.Iiop.Idl;
  using Ch.Elca.Iiop.Marshalling;
  using omg.org.CORBA;
  using omg.org.IOP;
  using System.Collections.Generic;
  using System.Configuration;
  
  namespace Ch.Elca.Iiop.CorbaObjRef
  {
  
  
      /// <summary>
      /// This class represents a Corba IOR.
      /// </summary>
      public class Ior
      {
  
          #region IFields
  
          private readonly IorProfile[] m_profiles;
          private readonly string m_typId;
  
          #endregion IFields
          #region IConstructors
  
          /// <summary>
          /// creates an IOR from the IOR stringified form
          /// </summary>
          public Ior(string iorAsString)
          {
              // iorAsString contains only characters 0-9, A-F and IOR --> all of this are short characters
              if (iorAsString.StartsWith("IOR:"))
              {
                  MemoryStream memStream = new MemoryStream(StringConversions.Destringify(iorAsString, 4));
                  CdrInputStreamImpl cdrStream = new CdrInputStreamImpl(memStream);
                  byte flags = cdrStream.ReadOctet();
                  cdrStream.ConfigStream(flags, new GiopVersion(1, 2)); // giop dep operation are not used for IORs
                  List<IorProfile> profiles = new List<IorProfile>();
                  ParseIOR(cdrStream, out m_typId, profiles);
                  m_profiles = profiles.ToArray();
              }
              else
              {
                  throw new INV_OBJREF(9420, CompletionStatus.Completed_No);
              }
          }
  
          /// <summary>
          /// parses an IOR embedded in a GIOP message
          /// </summary>
          internal Ior(CdrInputStream cdrStream)
          {
              List<IorProfile> profiles = new List<IorProfile>();
              ParseIOR(cdrStream, out m_typId, profiles);
              m_profiles = profiles.ToArray();
          }
  
          /// <summary>
          /// creates an IOR from the typeName and the profiles
          /// </summary>
          internal Ior(string typeName, IorProfile[] profiles)
          {
              m_profiles = profiles ?? new IorProfile[0];
              m_typId = typeName;
          }
  
          #endregion IConstructors
          #region IProperties
  
          /// <summary>
          /// all profiles inside this ior.
          /// </summary>
          public IIorProfile[] Profiles
          {
              get
              {
                  return m_profiles;
              }
          }
  
          /// <summary>the TypeID of this IOR</summary>
          public string TypID
          {
              get
              {
                  return m_typId;
              }
          }
  
          /// <summary>the type represented by typeid, or null, if no type is known for
          /// the type id.</summary>
          public Type Type
          {
              get
              {
                  return Repository.GetTypeForId(m_typId);
              }
          }
  
          #endregion IProperties
          #region IMethods
  
          /// <summary>returns true, if this IOR represents a null reference</summary>
          /// <returns>true, if a IOR represents null reference, otherwise false</returns>
          public bool IsNullReference()
          {
              return (m_typId.Length == 0 && m_profiles.Length == 0);
          }
  
          private static void ParseIOR(CdrInputStream cdrStream, out string typId, List<IorProfile> profiles)
          {
              typId = cdrStream.ReadString();
              ulong nrOfProfiles = cdrStream.ReadULong();
              for (ulong i = 0; i < nrOfProfiles; i++)
              {
                  profiles.Add(ParseProfile(cdrStream));
              }
          }
  
          /// <summary>
          /// parses an IOR-profile embedded in a CDRStream
          /// </summary>
          /// <param name="cdrStream"></param>
          /// <returns></returns>
          private static IorProfile ParseProfile(CdrInputStream cdrStream)
          {
              int profileType = (int)cdrStream.ReadULong();
              switch (profileType)
              {
                  case 0:
                      IorProfile result = new InternetIiopProfile(cdrStream);
                      return result;
                  case 1:
                      return new MultipleComponentsProfile(cdrStream);
                  default:
                      // unsupported profile type
                      return new UnsupportedIorProfile(cdrStream, profileType);
              }
          }
  
          /// <summary>gets a stringified representation</summary>
          public override string ToString()
          {
              // encode the IOR to a CDR-stream, afterwards write it to the iorStream
              using (MemoryStream content = new MemoryStream()) {
                  byte flags = 0;
                  CdrOutputStream stream = new CdrOutputStreamImpl(content, flags);
                  stream.WriteOctet(flags); // writing the flags before the IOR
                  // write content to the IORStream
                  WriteToStream(stream);
  
                  return StringConversions.Stringify("IOR:", content.GetBuffer(), (int)content.Length);
              }
          }
  
          /// <summary>
          /// write this IOR to a CDR-Stream in non-stringified form
          /// </summary>
          internal void WriteToStream(CdrOutputStream cdrStream)
          {
              cdrStream.WriteString(m_typId);
              cdrStream.WriteULong((uint)m_profiles.Length); // nr of profiles
              for (int i = 0; i < m_profiles.Length; i++)
              {
                  m_profiles[i].WriteToStream(cdrStream);
              }
          }
  
          /// <summary>
          /// write a null IOR instance to a CDR-Stream in non-stringified form
          /// </summary>
          internal static void WriteNullToStream(CdrOutputStream cdrStream)
          {
              cdrStream.WriteString(string.Empty);
              cdrStream.WriteULong(0);
          }
  
          /// <summary>
          /// tries to find an internet-iop profile inside this ior.
          /// </summary>
          public IInternetIiopProfile FindInternetIiopProfile()
          {
              for (int i = 0; i < Profiles.Length; i++)
              {
                  if (Profiles[i].ProfileId == TAG_INTERNET_IOP.ConstVal)
                  {
                      return (IInternetIiopProfile)Profiles[i];
                  }
              }
              return null;
          }
  
          #endregion IMethods
  
      }
  
  
      /// <summary>
      /// the interface of all ior profiles.
      /// </summary>
      public interface IIorProfile
      {
  
          #region IProperties
  
          /// <summary>
          /// the id of the profile
          /// </summary>
          int ProfileId
          {
              get;
          }
  
          /// <summary>the list of tagged components</summary>
          TaggedComponentList TaggedComponents
          {
              get;
          }
  
          /// <summary>
          /// the giop version usable when connecting with this profile.
          /// </summary>
          GiopVersion Version
          {
              get;
          }
  
          /// <summary>
          /// the key of the target object.
          /// </summary>
          byte[] ObjectKey
          {
              get;
          }
  
          #endregion IProperties
          #region IMethods
  
          /// <summary>
          /// creates a tagged profile from this profile.
          /// </summary>
          TaggedProfile CreateTaggedProfile();
  
          /// <summary>
          /// returns true, if at least one tagged component with the given tag is present.
          /// </summary>
          bool ContainsTaggedComponent(int tag);
  
          /// <summary>
          /// returns one tagged component with the given tag, if present. Otherwise throws exception.
          /// </summary>
          TaggedComponent GetTaggedComponent(int tag);
  
          /// <summary>
          /// returns all tagged components with the given tag. If not present, returns an empty array.
          /// </summary>
          TaggedComponent[] GetTaggedComponents(int tag);
  
          #endregion IMethods
  
      }
  
      /// <summary>
      /// interface for internet iiop profile.
      /// </summary>
      public interface IInternetIiopProfile : IIorProfile
      {
  
          string HostName
          {
              get;
          }
  
          /// <summary>
          /// the port, the server is listening on.
          /// </summary>
          int Port
          {
              get;
          }
  
  
      }
  
  
      /// <summary>This class represents a profile in a CORBA-IOR</summary>
      /// <remarks>This class is non CLS compliant</remarks>
      internal abstract class IorProfile : IIorProfile
      {
  
          #region SFields
          #endregion SFields
          #region IFields
  
          protected GiopVersion m_giopVersion;
  
          protected byte[] m_objectKey;
  
          /// <summary>the tagged components in this profile</summary>
          protected TaggedComponentList m_taggedComponents = new TaggedComponentList();
  
          #endregion IFields
          #region IConstructors
  
          /// <summary>
          /// creates an IOR from the data in a stream
          /// </summary>
          /// <param name="stream">the stream containing the profile data</param>
          protected IorProfile(CdrInputStream stream)
          {
              ReadDataFromStream(stream);
          }
  
          /// <summary>
          /// creates a profile from the standard data needed
          /// </summary>
          public IorProfile(GiopVersion version, byte[] objectKey)
          {
              m_giopVersion = version;
              m_objectKey = objectKey;
          }
  
          #endregion IConstructors
          #region IProperties
  
          public GiopVersion Version
          {
              get
              {
                  return m_giopVersion;
              }
          }
  
          public byte[] ObjectKey
          {
              get
              {
                  return m_objectKey;
              }
          }
  
          /// <summary>the tagged components in this profile</summary>
          public TaggedComponentList TaggedComponents
          {
              get
              {
                  return m_taggedComponents;
              }
          }
  
          /// <summary>
          /// the id of the profile
          /// </summary>
          public abstract int ProfileId
          {
              get;
          }
  
          #endregion IProperties
          #region IMethods
  
          public void AddTaggedComponent(TaggedComponent component)
          {
              m_taggedComponents.AddComponent(component);
          }
  
          public void AddTaggedComponents(TaggedComponent[] components)
          {
              m_taggedComponents.AddComponents(components);
          }
  
          public bool ContainsTaggedComponent(int tag)
          {
              return m_taggedComponents.ContainsTaggedComponent(tag);
          }
  
          public TaggedComponent GetTaggedComponent(int tag)
          {
              return m_taggedComponents.GetComponent(tag);
          }
  
          public TaggedComponent[] GetTaggedComponents(int tag)
          {
              return m_taggedComponents.GetComponents(tag);
          }
  
          /// <summary>writes this profile into an encapsulation</summary>
          public abstract void WriteToStream(CdrOutputStream cdrStream);
  
          /// <summary>reads this profile data from a stream</summary>
          protected abstract void ReadDataFromStream(CdrInputStream cdrStream);
  
          /// <summary>creates a tagged profile representation for this profile.</summary>
          public abstract TaggedProfile CreateTaggedProfile();
  
          #endregion IMethods
          #region SMethods
          #endregion SMethods
  
      }
  
      /// <summary>
      /// the profile for IIOP connections
      /// </summary>
      /// <remarks>This class is not CLSCompliant</remarks>
      internal sealed class InternetIiopProfile : IorProfile, IInternetIiopProfile
      {
  
          #region IFields
  
          private string m_hostName;
          private ushort m_port;
  
          #endregion IFields
          #region IConstructors
  
          public InternetIiopProfile(GiopVersion version, string hostName, ushort port, byte[] objectKey)
              : base(version, objectKey)
          {
              m_hostName = hostName;
              m_port = port;
          }
  
          /// <summary>
          /// reads an InternetIIOPProfile from a cdr stream
          /// </summary>
          /// <param name="encapsulation"></param>
          public InternetIiopProfile(CdrInputStream dataStream)
              : base(dataStream)
          {
  
          }
  
          #endregion IConstructors
          #region IProperties
  
          /// <summary>returns the profile-id for this profile</summary>
          public override int ProfileId
          {
              get
              {
                  return TAG_INTERNET_IOP.ConstVal;
              }
          }
  
          public string HostName
          {
              get
              {
                  //Read IOR proxy from config file
                  string iorProxyHost = ConfigurationManager.AppSettings["ior_proxy_host"];
                  if (!string.IsNullOrEmpty(iorProxyHost))
                  {
                      return ConfigurationManager.AppSettings["ior_proxy_host"];
                  }
                  return m_hostName;
              }
          }
  
          public int Port
          {
              get
              {
                  return m_port;
              }
          }
  
          #endregion IProperties
          #region IMethods
  
          protected override void ReadDataFromStream(CdrInputStream inputStream)
          {
              // internet-iiop profile is encapsulated
              CdrEncapsulationInputStream encapsulation = inputStream.ReadEncapsulation();
              Debug.WriteLine("parse Internet IIOP Profile");
              byte giopMajor = encapsulation.ReadOctet();
              byte giopMinor = encapsulation.ReadOctet();
              m_giopVersion = new GiopVersion(giopMajor, giopMinor);
  
              Debug.WriteLine("giop-verion: " + m_giopVersion);
              m_hostName = encapsulation.ReadString();
              Debug.WriteLine("hostname: " + m_hostName);
              m_port = encapsulation.ReadUShort();
              Debug.WriteLine("port: " + m_port);
              uint objectKeyLength = encapsulation.ReadULong();
              m_objectKey = new byte[objectKeyLength];
              Debug.WriteLine("object key follows");
              for (uint i = 0; i < objectKeyLength; i++)
              {
                  m_objectKey[i] = encapsulation.ReadOctet();
                  Debug.Write(m_objectKey[i] + " ");
              }
              Debug.WriteLine("");
              // GIOP 1.1, 1.2:
              if (!(m_giopVersion.Major == 1 && m_giopVersion.Minor == 0))
              {
                  m_taggedComponents = new TaggedComponentList(encapsulation);
              }
  
              Debug.WriteLine("parsing Internet-IIOP-profile completed");
          }
  
          /// <summary>
          /// writes this profile to the cdrStream
          /// </summary>
          /// <param name="cdrStream"></param>
          /// <remarks>
          public override void WriteToStream(CdrOutputStream cdrStream)
          {
              // write the profile id of this profile
              cdrStream.WriteULong((uint)ProfileId);
              CdrEncapsulationOutputStream encapStream = GetProfileContentStream();
              // write the whole encapsulation to the stream
              cdrStream.WriteEncapsulation(encapStream);
          }
  
          private CdrEncapsulationOutputStream GetProfileContentStream()
          {
              CdrEncapsulationOutputStream encapStream = new CdrEncapsulationOutputStream(GiopHeader.GetDefaultHeaderFlagsForPlatform());
              encapStream.WriteOctet(m_giopVersion.Major);
              encapStream.WriteOctet(m_giopVersion.Minor);
              encapStream.WriteString(m_hostName);
              encapStream.WriteUShort(m_port);
              encapStream.WriteULong((uint)m_objectKey.Length);
              encapStream.WriteOpaque(m_objectKey);
              // the tagged components
              if (!(m_giopVersion.Major == 1 && m_giopVersion.Minor == 0))
              { // for GIOP >= 1.1, tagged components are possible
                  m_taggedComponents.WriteTaggedComponentList(encapStream);
              }
              return encapStream;
          }
  
          public override TaggedProfile CreateTaggedProfile()
          {
              TaggedProfile result = new TaggedProfile();
              result.tag = ProfileId;
              result.profile_data = GetProfileContentStream().GetEncapsulationData();
              return result;
          }
  
          #endregion IMethods
  
      }
  
      /// <summary>
      /// The multiple component profile.
      /// </summary>
      /// <remarks>
      /// This class is not CLSCompliant.
      /// </remarks>
      internal sealed class MultipleComponentsProfile : IorProfile
      {
  
          #region IConstructors
  
          public MultipleComponentsProfile()
              : base(new GiopVersion(1, 2), null)
          {
          }
  
          /// <summary>
          /// reads a multiple component profile data from a stream
          /// </summary>
          /// <param name="encapsulation"></param>
          public MultipleComponentsProfile(CdrInputStream inputStream)
              : base(inputStream)
          {
          }
  
          #endregion IConstructors
          #region IProperties
  
          /// <summary>returns the profile-id for this profile</summary>
          public override int ProfileId
          {
              get
              {
                  return TAG_MULTIPLE_COMPONENTS.ConstVal;
              }
          }
  
          #endregion IProperties
          #region IMethods
  
          protected override void ReadDataFromStream(CdrInputStream inputStream)
          {
              // internet-iiop profile is encapsulated
              CdrEncapsulationInputStream encapsulation = inputStream.ReadEncapsulation();
  
              Debug.WriteLine("parse Multiple component Profile");
              m_taggedComponents = new TaggedComponentList(encapsulation);
  
              Debug.WriteLine("parsing multiple components profile completed");
          }
  
          /// <summary>
          /// writes this profile to the cdrStream
          /// </summary>
          /// <param name="cdrStream"></param>
          /// <remarks>
          public override void WriteToStream(CdrOutputStream cdrStream)
          {
              // write the profile id of this profile
              cdrStream.WriteULong((uint)ProfileId);
              CdrEncapsulationOutputStream encapStream = GetProfileContentStream();
              // write the whole encapsulation to the stream
              cdrStream.WriteEncapsulation(encapStream);
          }
  
          private CdrEncapsulationOutputStream GetProfileContentStream()
          {
              CdrEncapsulationOutputStream encapStream = new CdrEncapsulationOutputStream(GiopHeader.GetDefaultHeaderFlagsForPlatform());
              // the tagged components
              m_taggedComponents.WriteTaggedComponentList(encapStream);
              return encapStream;
          }
  
          public override TaggedProfile CreateTaggedProfile()
          {
              TaggedProfile result = new TaggedProfile();
              result.tag = ProfileId;
              result.profile_data = GetProfileContentStream().GetEncapsulationData();
              return result;
          }
  
          #endregion IMethods
  
      }
  
      /// <summary>
      /// used to store information about an unsupported profile
      /// </summary>
      /// <remkars>This class is not CLSCompliant</remarks>
      internal sealed class UnsupportedIorProfile : IorProfile
      {
  
          #region IFields
  
          // that's equal to a omg.org.IOP.TaggedProfile
          private int m_profileId;
          private byte[] m_data;
  
          #endregion IFields
          #region IConstructors
  
          /// <summary>
          /// reads an unsupported profile from an encapsulation (created with the method readEncapsulation in
          /// CDRStream)
          /// </summary>
          /// <param name="encapsulation"></param>
          public UnsupportedIorProfile(CdrInputStream inputStream, int profileId)
              : base(inputStream)
          {
              m_profileId = profileId;
          }
  
          #endregion IConstructors
          #region IProperties
  
          /// <summary>returns the profile-id for this profile</summary>
          public override int ProfileId
          {
              get
              {
                  return m_profileId;
              }
          }
  
          #endregion IProperties
          #region IMethods
  
          protected override void ReadDataFromStream(CdrInputStream inputStream)
          {
              Debug.WriteLine("parse unsupported ior profile");
              uint length = inputStream.ReadULong();
              m_data = inputStream.ReadOpaque((int)length);
  
              Debug.WriteLine("parsing unsupported profile completed");
          }
  
          /// <summary>
          /// writes this profile to the cdrStream
          /// </summary>
          /// <param name="cdrStream"></param>
          /// <remarks>
          public override void WriteToStream(CdrOutputStream cdrStream)
          {
              // write the profile id of this profile
              cdrStream.WriteULong((uint)ProfileId);
              uint length = (uint)m_data.Length;
              cdrStream.WriteULong(length);
              cdrStream.WriteOpaque(m_data);
          }
  
          public override TaggedProfile CreateTaggedProfile()
          {
              TaggedProfile result = new TaggedProfile();
              result.tag = ProfileId;
              result.profile_data = m_data;
              return result;
          }
  
          #endregion IMethods
  
      }
  
  }
  
  #if UnitTest
  
  namespace Ch.Elca.Iiop.Tests
  {
  
      using NUnit.Framework;
      using Ch.Elca.Iiop.CorbaObjRef;
      using Ch.Elca.Iiop.Services;
  
      /// <summary>
      /// Unit-test for class Ior
      /// </summary>
      [TestFixture]
      public class IorTest
      {
  
          private Codec m_codec;
          private SerializerFactory m_serFactory;
  
          public IorTest()
          {
          }
  
          [SetUp]
          public void SetUp()
          {
              m_serFactory =
                  new SerializerFactory();
              CodecFactory codecFactory =
                  new Ch.Elca.Iiop.Interception.CodecFactoryImpl(m_serFactory);
              m_codec =
                  codecFactory.create_codec(
                      new omg.org.IOP.Encoding(ENCODING_CDR_ENCAPS.ConstVal, 1, 2));
              IiopUrlUtil iiopUrlUtil =
                  IiopUrlUtil.Create(m_codec, new object[] {
                      Services.CodeSetService.CreateDefaultCodesetComponent(m_codec)});
              m_serFactory.Initalize(new SerializerFactoryConfig(), iiopUrlUtil);
          }
  
          [Test]
          public void TestIorCreation()
          {
              string iorString = "IOR:0000000000000024524d493a48656c6c6f496e746572666163653a3030303030303030303030303030303000000000010000000000000050000102000000000c31302e34302e32302e3531001f9500000000000853617948656C6C6F0000000100000001000000200000000000010001000000020501000100010020000101090000000100010100";
  
gt:             Ior ior = new Ior(iorString);