A Meta View of Data: Metadata


Metadata is one of those terms that usually receives a quick confirming nod when explained. At the same time, it is one of those terms that almost always requires an explanation. Basically, metadata is data about data, or even data about objects. In other words, information that might be used to identify or describe something is metadata.

Say that you are coding a mainframe COBOL batch program. When the program is complete, you might also create a JCL Job structure to use for program execution. Then, if I was to come along behind you and browse the PDS library where your JCL Job is saved and open the JCL Job, I would be able to "read" your JCL, right? What would I know at that point? Just from "reading" your JCL, I would be able find out several facts.

The very first JCL statement in every JCL Job describes (at a minimum) the Job name of the JCL Job. Typically, I would also be able to find out the input class and message class values, chargeback /accounting information, execution priority, and whether the "type of run" will be held or not. I could possibly obtain all of that information just from the first JCL statement: the Job statement. If I were to look further into the JCL Job at other JCL statements, I would be able to obtain even more pieces of descriptive information (e.g., which load libraries are referenced, the names of any cataloged procedures being used, and possibly the names of the programs being executed).

That's right. All of the descriptive information, the data about the JCL Job, is metadata. Now, imagine if you were to write a mainframe batch utility program to read the PDS member (the one that actually contains the JCL Job) as text data. Your utility program would be able to take the text line by line, and display/report on the so-called metadata. All right, how about another confirming nod? Thanks. Let's now see how metadata is accessed on the .NET platform.

.NET Supports Metadata with Reflection

Fortunately, there is no need to write your own program to do the low-level data mining needed for gathering metadata. .NET provides a namespace specifically designed to gather metadata. Naturally, the namespace, System.Reflection , contains delegates, interfaces, classes, enumerations, and structures. The mainframe JCL analogy had the JCL Job as the focal point for metadata excavation. With .NET, the assembly (.exe or .dll) becomes the target for exploration using the System.Reflection namespace.

start sidebar
Adding Metadata with Attributes

Attributes make up a special breed of metadata for your .NET applications. There are two groups of attributes: intrinsically available attributes and custom attributes that you create yourself. Take a look at your assembly manifest sometime (using the ILDASM tool or programmatically via reflection). You will see the metadata provided by attributes. You can use attributes to further document/ describe your application. Attributes also have other uses. For example, you can use them to help manage your production deployments through version control (I further discuss deployment in Chapter 17). That is not all. When you combine the use of attributes with metadata, you can easily choose to add compiler directives to your application. You see, the support for metadata is an important feature in .NET.

end sidebar
 

Each time you use the ILDASM tool, you get a taste of what "reflection" looks like. Recall that the first page displayed when the ILDASM tool is used simply describes the assembly. It is after drilling down that you get to the actual Microsoft intermediate language (MSIL). To demonstrate this, you will use the two sample code assemblies created earlier in this chapter in the section "Demonstrating How to Access Data in Text Files": SystemIOExampleCobol.exe and SystemIOExampleVB.exe. As shown in Figures 10-1 and 10-2, the first page displayed with the ILDASM tool basically describes each respective assembly.

click to expand
Figure 10-1: The ILDASM display of SystemIOExampleCobol.exe
click to expand
Figure 10-2: The ILDASM display of SystemIOExampleVB.exe

As you look at each assembly's ILDASM display, are you reminded of the mainframe analogy of looking inside a JCL Job? Good. Now you will take a look at some sample code to understand the programmatic access of metadata.

Using the System.Reflection Namespace

I have created two sample projects: MetaDataExampleVB and MetaDataExampleCobol. You will see that each project programmatically accesses the metadata for the System.Text.StringBuilder class that is contained in the Microsoft assembly mscorlib.dll.

To help prepare for the demonstration code, please review the ILDASM display shown in Figure 10-3. You will notice that even the Microsoft assembly mscorlib.dll is not immune to this type of metadata observation. The ILDASM tool uses reflection to display the types contained in the mscorlib.dll assembly. The StringBuilder class is one of the types.

click to expand
Figure 10-3: The ILDASM display of mscorlib.dll for the System.Text.StringBuilder class

VB .NET Metadata Example

The code in Listing 10-8 demonstrates the use of two System.Reflection classes: System.Reflection.MemberInfo and System.Reflection.Assembly . The code was copied from the MetaDataExampleVB.exe sample project.

Listing 10-8: MetaDataExampleVB.exe Project Demonstrating the Use of the System.Reflection Namespace to Obtain Metadata
start example
 Module Module1 Sub Main()       'Create Objects from System.Reflection Namespace        Dim myMemberInfoArray() As System.Reflection.MemberInfo       Dim myAssembly As System.Reflection.Assembly           Dim MyTypes() As System.Type       Dim MyType As System.Type       Dim indexA As Integer       Dim indexB As Integer           'Create Object from StringBuilder Class       Dim sb As New System.Text.StringBuilder()           'Get the Type associated with the StringBuilder       MyType = sb.GetType       'Get the Assembly associated with the StringBuilder Type       myAssembly = myAssembly.GetAssembly(MyType)       'Get the Types found in the Assembly       MyTypes = myAssembly.GetTypes()           For indexA = 0 To UBound(MyTypes)       'Select specific Type for further processing          If MyTypes(indexA).Name = "StringBuilder" Then          'Display appropriate Information          Console.WriteLine(MyTypes(indexA).FullName)          'Get members found in the selected Type          myMemberInfoArray = MyTypes(indexA).GetMembers()             For indexB = 0 To myMemberInfoArray.Length - 1             'Display appropriate Information                   sb.Length = 0                 With sb                  .Append("MemberType - ")                   .Append(" ")                   .Append(myMemberInfoArray(indexB).MemberType.ToString())                   .Append(" ")                   .Append("Name -")                   .Append(" ")                   .Append(myMemberInfoArray(indexB).ToString())                   .Append(" ")                   Console.WriteLine(.ToString())                   End With                 Next indexB              'Exit Loop after StringBuilder Type is located              Exit For              End If           Next           Console.ReadLine()     End Sub End Module 
end example
 

COBOL .NET Metadata Example

With a little practice, using the reflection namespaces is not very difficult. The sample code in Listing 10-9 demonstrates exactly how to go about doing so. Please take a moment to read the code. I will assume that you are continuing to approach your .NET retraining with a bilingual flavor. With that understanding, I am sure you will find the comparisons between the two sample projects (MetaDataExampleVB.exe in Listing 10-8 and MetaDataExampleCobol.exe in Listing 10-9) rather interesting and informative.

Listing 10-9: MetaDataExampleCobol.exe Project Demonstrating the Use of the System.Reflection Namespace Objects
start example
 000010 IDENTIFICATION DIVISION. 000020* This is an example of how to use the  000030* System.Reflection Classes to obtain MetaData 000040 PROGRAM-ID. MAIN. 000050 ENVIRONMENT DIVISION. 000060 CONFIGURATION SECTION. 000070 REPOSITORY. 000080* .NET Framework Classes 000090    CLASS SYS-sb AS "System.Text.StringBuilder" 000100    CLASS SYS-MyString As "System.String" 000110    CLASS SYS-MyInt As "System.Int32" 000120    CLASS SYS-MyType As "System.Type" 000130    CLASS SYS-MyTypes As "System.Type[]" 000140    CLASS SYS-myMemberInfoItem As "System.Reflection.MemberInfo" 000150    ENUM ENUM-myMemberTypes As "System.Reflection.MemberTypes" 000160    CLASS SYS-myMemberInfoArray As "System.Reflection.MemberInfo[]" 000170    CLASS SYS-myAssembly As "System.Reflection.Assembly" 000180    PROPERTY PROP-Length as "Length" 000190    PROPERTY PROP-FullName as "FullName" 000200    PROPERTY PROP-Name as "Name" 000210    PROPERTY PROP-MemberType as "MemberType". 000230* 000240 DATA DIVISION. 000250 WORKING-STORAGE SECTION. 000260   77 sb OBJECT REFERENCE SYS-sb. 000270   77 MyString OBJECT REFERENCE SYS-MyString. 000280   77 MyInt OBJECT REFERENCE SYS-MyInt. 000290   77 MyType OBJECT REFERENCE SYS-MyType. 000300   77 MyTypes OBJECT REFERENCE SYS-MyTypes. 000310   77 MyTypeItem OBJECT REFERENCE SYS-MyType. 000320  000330* Reference Objects from System.Reflection Namespace  000340   77 myMemberInfoItem OBJECT REFERENCE SYS-myMemberInfoItem. 000350   77 myMemberInfoArray OBJECT REFERENCE SYS-myMemberInfoArray. 000360   77 myAssembly OBJECT REFERENCE SYS-myAssembly. 000370   77 myMemberTypes OBJECT REFERENCE ENUM-myMemberTypes. 000380  000390   77 indexA PIC S9(9) COMP-5. 000400   77 indexB PIC S9(9) COMP-5. 000410   77 ArrayBoundaryA PIC S9(9) COMP-5. 000420   77 ArrayBoundaryB PIC S9(9) COMP-5. 000430   77 MyDisplayString PIC X(100). 000440   01 NULL-X PIC X(1). 000450 LINKAGE SECTION. 000460 000470 PROCEDURE DIVISION. 000480  000490* Create Object from StringBuilder Class 000500   SET sb to SYS-sb::"NEW" () 000510* Get the Type associated with the StringBuilder  000520   SET MyType TO sb::"GetType" ()  000530* Get the Assembly associated with the StringBuilder Type 000540   SET myAssembly TO SYS-myAssembly::"GetAssembly" (MyType) 000550* Get the Types found in the Assembly  000560   SET MyTypes TO myAssembly::"GetTypes" ()  000570  000580   SET MyInt to MyTypes::"GetUpperBound" (0) 000590   SET ArrayBoundaryA to MyInt 000600   PERFORM VARYING indexA  000610     FROM 0 BY 1 UNTIL indexA >= ArrayBoundaryA 000620* Select specific Type for further processing 000630              INVOKE MyTypes "Get" USING BY VALUE indexA RETURNING MyTypeItem 000640* Display appropriate Information 000650           SET MyDisplayString to PROP-Name of MyTypeItem 000660          IF MyDisplayString = "StringBuilder" Then 000670                 SET MyDisplayString to PROP-FullName of MyTypeItem 000680                 Display MyDisplayString 000690* Get members found in the selected Type 000700              SET myMemberInfoArray to MyTypeItem::"GetMembers" () 000710              SET MyInt to PROP-Length of myMemberInfoArray 000720              SET ArrayBoundaryB to MyInt 000730                 PERFORM VARYING indexB  000740                   FROM 0 BY 1 UNTIL indexB >= (ArrayBoundaryB - 1) 000750                   INVOKE myMemberInfoArray "Get"  000760                   USING BY VALUE indexB RETURNING myMemberInfoItem 000770  000780                 SET myMemberTypes to PROP-MemberType of myMemberInfoItem 000790                 SET MyString to myMemberInfoItem::"ToString" () 000800                 SET PROP-Length of sb to 0 000810* Display appropriate Information 000820                 INVOKE sb "Append" USING BY VALUE "MemberType - " 000830                            RETURNING sb 000840                 INVOKE sb "Append" USING BY VALUE " " 000850                            RETURNING sb 000860                 INVOKE sb "Append" USING BY VALUE myMemberTypes 000870                            RETURNING sb 000880                 INVOKE sb "Append" USING BY VALUE " " 000890                            RETURNING sb 000900                 INVOKE sb "Append" USING BY VALUE "Name -" 000910                            RETURNING sb 000920                 INVOKE sb "Append" USING BY VALUE " " 000930                            RETURNING sb 000940                 INVOKE sb "Append" USING BY VALUE MyString 000950                            RETURNING sb 000960                 INVOKE sb "Append" USING BY VALUE " " 000970                            RETURNING sb 000980                 SET MyDisplayString to sb::"ToString" () 000990                 DISPLAY MyDisplayString 001000             END-PERFORM 001010* Exit Perform after StringBuilder Type is located 001020              EXIT PERFORM 001030           End-IF 001040    END-PERFORM 001050    DISPLAY "Enter X and Press Enter to Exit.". 001060    ACCEPT NULL-X.  001070 END PROGRAM MAIN. 
end example
 

Why Care About Metadata and Reflection?

Why speak about .NET's support for metadata? The answer to this question is different for each person. For myself , I see this as a great opportunity to easily document an assembly. Basically, the assembly ends up documenting itself. You can capture metadata and write the information to a text file (using System.IO.TextWriter). Then, you can archive the text file for application documentation.

For a better idea of the "documentation" that is automatically available, run either sample project (MetaDataExampleVB.exe or MetaDataExampleCobol.exe). Your console display will reveal some of the metadata that is available for this mscorlib.dll assembly, specifically for the StringBuilder type. I have included a small portion of that display in Listing 10-10.

Listing 10-10: A Portion of the Metadata Captured from the mscorlib.dll Assembly
start example
 System.Text.StringBuilder MemberType -    Method  Name -     Int32 GetHashCode() MemberType -    Method  Name -     Boolean Equals(System.Object) MemberType -    Method  Name -     System.String ToString() MemberType -    Method  Name -     Int32 get_Capacity() MemberType -    Method  Name -     Void set_Capacity(Int32) MemberType -    Method  Name -     Int32 get_MaxCapacity() MemberType -    Method  Name -     Int32 EnsureCapacity(Int32) . . . MemberType -    Method  Name - System.Type GetType() MemberType -    Constructor Name -  Void .ctor() MemberType -    Constructor Name -  Void .ctor(Int32) MemberType -    Constructor Name -  Void .ctor(System.String) MemberType -    Constructor Name -  Void .ctor(System.String, Int32) . . . MemberType -    Property    Name -  Int32 Capacity MemberType -    Property    Name -  Int32 MaxCapacity MemberType -    Property    Name -  Int32 Length MemberType -    Property    Name -  Char Chars [Int32] 
end example
 

As you can see, with metadata and .NET's reflection technology, an application moves closer to being " self-documenting ." I see that as being a great thing with great potential. Learn to leverage your metadata.




COBOL and Visual Basic on .NET
COBOL and Visual Basic on .NET: A Guide for the Reformed Mainframe Programmer
ISBN: 1590590481
EAN: 2147483647
Year: 2003
Pages: 204

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net