Exemple #1
0
        /// <summary>
        /// Constructor to create an SapIDocDefinition when the segment contents are already known
        /// Note: The c-Header and the exported Structure do not contain an IDoc description. The description is only
        /// found in the XSD (which does not contain enough information to create an SapIDocDefinition).
        /// </summary>
        /// <param name="name">Name of IDoc type</param>
        /// <param name="controlRecord">The Control Record Segment</param>
        /// <param name="dataRecord">The Data Record Segment</param>
        /// <param name="segments">The Segments of the IDoc</param>
        private SapIDocDefinition(
            string name,
            SapIDocSegment controlRecord,
            SapIDocSegment dataRecord,
            Dictionary <string, SapIDocSegment> segments)
        {
            Logger.DebugFormat("========== Creating {0} with dictionary of Segments ==========", GetType().Name);

            #region Argument Check

            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentException("IDoc name cannot be empty.", "name");
            }

            if (controlRecord == null)
            {
                throw new ArgumentNullException("controlRecord");
            }

            if (dataRecord == null)
            {
                throw new ArgumentNullException("dataRecord");
            }

            if (segments == null)
            {
                throw new ArgumentNullException("segments");
            }

            #endregion

            this.Name          = name;
            this.ControlRecord = controlRecord;
            this.DataRecord    = dataRecord;
            this.Segments      = segments;
        }
Exemple #2
0
        ///// <summary>
        ///// The IDoc description e.g. "BAPI Outbound;Meter Asset Standing Data Updates".
        ///// Note that this property can only be set when an instance of the class is created.
        ///// Note that this property can be found in the XSD definition, but not in the C-Header definition or the
        ///// Structure definition.
        ///// </summary>
        ////public string Description
        ////{
        ////    get { return _idocDescription; }
        ////    private set
        ////    {
        ////        if (String.IsNullOrEmpty(value))
        ////        {
        ////            throw new SapIDocException("IDoc description cannot be empty."); // This might cause problems if they haven't bothered to enter a description.
        ////        }
        ////        _log.Debug("IDoc description: {0}", value);
        ////        _idocDescription = value;
        ////    }
        ////}

        #endregion

        #region Public Methods

        /////// <summary>
        /////// Create an IDoc definition from an XSD file that has been exported from SAP.
        /////// </summary>
        /////// <param name="path">The XSD filename</param>
        /////// <returns>Returns a new IDocDefinion object.</returns>
        ////public static SapIDocDefinition LoadXsd(string path)
        ////{
        ////    // Read file contents
        ////    XElement definition;
        ////    try
        ////    {
        ////        definition = XElement.Load(path);
        ////    }
        ////    catch (Exception e)
        ////    {
        ////        string msg = String.Format("Problem reading file {0}", path);
        ////        throw new SapIDocException(msg, e);
        ////    }
        ////    return new SapIDocDefinition(definition);
        ////}

        /// <summary>
        /// Reads an IDoc Definition (C-Header) from the file system, and creates an SapIDocDefinition object.
        /// </summary>
        /// <param name="path">A file containing the IDoc Definition as a C Header.</param>
        /// <returns>A new SapIDocDefinition object</returns>
        public static SapIDocDefinition LoadHeader(string path)
        {
            Logger.DebugFormat("Calling {0} with file: {1}", MethodBase.GetCurrentMethod().GetQualifiedName(), path);

            SapIDocSegment controlRecord = null;
            SapIDocSegment dataRecord    = null;
            var            segments      = new Dictionary <string, SapIDocSegment>();

            if (!File.Exists(path))
            {
                throw new SapIDocException(string.Format("Could not find C Header file: {0}", path));
            }

            Logger.DebugFormat("C Header file contents:{0}{1}", Environment.NewLine, File.ReadAllText(path));

            // Convert the C code to XML (srcml) so it can be easily processed.
            var srcml = ConvertCToSrcml(path);

            // The src2srcml command adds "src:" namespace prefixes to all elements.
            var nsm = new XmlNamespaceManager(new NameTable());

            nsm.AddNamespace("src", "http://www.sdml.info/srcML/src");
            //// Note that XPathSelectElement does not use the default namespace (""), will always return NULL if you query an XML document that has a default namespace.
            nsm.AddNamespace("cpp", "http://www.sdml.info/srcML/cpp");

            // Extract the field definitions from each IDoc segment (typedef/struct).
            var structsXml = srcml.XPathSelectElements("/src:typedef", nsm);

            foreach (var seg in structsXml)
            {
                var segmentName        = seg.XPathSelectElement("./src:name", nsm).Value.ToUpper();
                var tmpSegDescComment  = seg.XPathSelectElement("./src:type/src:struct/src:comment", nsm).Value;
                var segmentDescription = tmpSegDescComment.Substring(3, tmpSegDescComment.Length - (3 + 2)).TrimEnd();
                //// remove start/end block-comment, and any trailing whitespace.
                var currentSegment = new SapIDocSegment(segmentName, segmentDescription);
                //// must Add() each field to this separately.

                var fieldsXml =
                    seg.XPathSelectElements("./src:type/src:struct/src:block/src:decl_stmt", nsm).ToArray();
                var commentsXml =
                    seg.XPathSelectElements("./src:type/src:struct/src:block/src:comment", nsm).ToArray();
                if (fieldsXml.Count() != commentsXml.Count())
                {
                    throw new SapIDocException(
                              "Each field definition in the C-Header should have a matching comment.");
                }

                int fieldStartPos; // The starting position changes if it is a data segment.
                switch (segmentDescription)
                {
                case "IDoc Control Record for Interface to External System":
                    fieldStartPos = 0;
                    controlRecord = currentSegment;
                    break;

                case "IDoc Data Record for Interface to External System":
                    fieldStartPos = 0;
                    dataRecord    = currentSegment;
                    break;

                case "IDoc Status Record for Interface to External System":
                    Logger.Debug("Skipping Status Record definition, as this is not needed to read an IDoc.");
                    continue;

                default:
                    fieldStartPos = dataRecord.EnsureNotNull()["SDATA"].StartPosition;
                    segments.Add(segmentName, currentSegment);
                    break;
                }

                foreach (var fld in fieldsXml.Zip(commentsXml, (field, comment) => new { field, comment }))
                {
                    var fieldName =
                        fld.field.XPathSelectElement("./src:decl/src:name/src:name", nsm).Value.ToUpperInvariant();
                    var fieldLength = Convert.ToInt32(
                        fld.field.XPathSelectElement("./src:decl/src:name/src:index/src:expr", nsm).Value);
                    var tmpFldDescComment = fld.comment.Value;
                    var fieldDescription  = tmpFldDescComment
                                            .Substring(3, tmpFldDescComment.Length - (3 + 2))
                                            .TrimEnd();
                    //// remove start/end block-comment, and any trailing whitespace.
                    currentSegment.Add(new SapIDocField(fieldName, fieldDescription, fieldStartPos, fieldLength));
                    fieldStartPos += fieldLength;
                }
            }

            //// To get the IDoc name, look for the comment that says "/* Segment structures for IDoc type ZISUPODMAS_BAPIZBUSMASSENDEM01 */".
            //// Note that there is no IDoc description in the C-Header or the exported Structure.
            var tmpIdocName = srcml
                              .XPathSelectElement("//src:comment[contains(., 'Segment structures for IDoc type')]", nsm)
                              .Value;
            var idocName = tmpIdocName.Substring(36, tmpIdocName.Length - (36 + 2)).TrimEnd();

            //// remove start/end block-comment, and any trailing whitespace.

            return(new SapIDocDefinition(idocName, controlRecord, dataRecord, segments));
        }