My last article on How To Create A JSON Web Service in ASP.NET did not attract much interest so it is time to step it up a notch. To make this article more interesting I’m going to create a new web service in Fujitsu NetCOBOL. As far as I know, there are no examples on the Internet on how to do anything meaningful with the .NET Framework using the COBOL language. Although you can use many programming languages with .NET nobody really uses anything other than C# and VB.NET.
Let’s suppose your company has senior management who often travel to Germany. Most of your expertise is in the COBOL programming language because the company has been using COBOL for years. And lets assume any new work must be done in COBOL as well to maintain the corporate IT culture. The executive puts in a request for a web service to help him find brothels while in Germany. You already have a web service that supplies him with client addresses from a contact database. He can’t easily find information on brothels in Germany because he does not read German so you’ll be maintaining a database of their locations.
Below is the database schema that we will be using for a database named Laufhaus with one table named ErosCenters:
column_name | data_type | numeric_precision | character_maximum_length | is_nullable | column_default |
---|---|---|---|---|---|
ID | int | 10 | NO | ||
BrothelName | nvarchar | 255 | YES | ||
Street | nvarchar | 255 | YES | ||
City | nvarchar | 255 | YES | ||
PostalCode | nvarchar | 6 | YES | ||
Phone | nvarchar | 25 | YES | ||
Link | nvarchar | 255 | YES | ||
Latitude | nvarchar | 50 | YES | ||
Longitude | nvarchar | 50 | YES |
Fujitsu NetCOBOL supplies an utility program which will add the necessary XML nodes to your web.config file for the database connection. This program will error until you run another utility program to update the machine.config. This was not well documented. Run the following command first: C:\Program Files\Common Files\Fujitsu NetCOBOL for .NET Runtime V3.0\Runtime\x86>setupconfig.exe /install
This will add the following section to your web.config file:
1: <fujitsu.cobol>
2: <runtime>
3: <sqlSettings>
4: <connectionScope>
5: <add key="@SQL_CONNECTION_SCOPE" value="APPLICATION_DOMAIN" />
6: </connectionScope>
7: <serverList>
8: <server name="SERVER1" type="adonet" description="SERVER1">
9: <add key="@SQL_DATASRC" value="LocalSqlServer" />
10: <add key="@SQL_USERID" value="sa" />
11: <add key="@SQL_PASSWORD" value="HIFDOBLHCFAPANBFLOJCNNMLDDHO" />
12: </server>
13: </serverList>
14: <sqlDefaultInf>
15: <add key="@SQL_DATASRC" value="LocalSqlServer" />
16: <add key="@SQL_USERID" value="sa" />
17: <add key="@SQL_PASSWORD" value="HIFDOBLHCFAPANBFLOJCNNMLDDHO" />
18: </sqlDefaultInf>
19: </sqlSettings>
20: </runtime>
21: </fujitsu.cobol>
You can create a ASP.NET web service using COBOL as the language. It took me hours of experimentation to figure out how to turn a simple “Hello World” demo program into an actual web service. I had to work through how to make the database connection, how to return XML instead of a string, how to return multiple records, how to create an .NET object within COBOL, and how to call an object method. It was a hell of a lot of fun though to work in COBOL. As you can see this program is far more wordy than an equivalent program in C# would be.
1: IDENTIFICATION DIVISION.
2: CLASS-ID. CLASS-THIS AS "Service" INHERITS CLASS-WEBSERVICE
3: CUSTOM-ATTRIBUTE CA-WEBSERVICE CA-WEBSERVICEBINDING.
4: ENVIRONMENT DIVISION.
5: CONFIGURATION SECTION.
6: SPECIAL-NAMES.
7: CUSTOM-ATTRIBUTE CA-WEBSERVICE
8: CLASS CLASS-WEBSERVICEATTRIBUTE
9: PROPERTY PROP-NAMESPACE IS N"http://www.williamsportwebdeveloper.com"
10: CUSTOM-ATTRIBUTE CA-WEBSERVICEBINDING
11: CLASS CLASS-WEBSERVICEBINDINGATTR
12: PROPERTY PROP-CONFORMSTO IS PROP-BASICPROFILE1_1 OF ENUM-WSIPROFILES
13: CUSTOM-ATTRIBUTE CA-WEBMETHOD
14: CLASS CLASS-WEBMETHODATTRIBUTE
15: .
16: REPOSITORY.
17: CLASS CLASS-STRING AS "System.String"
18: CLASS CLASS-WEBMETHODATTRIBUTE AS "System.Web.Services.WebMethodAttribute"
19: CLASS CLASS-WEBSERVICE AS "System.Web.Services.WebService"
20: CLASS CLASS-WEBSERVICEATTRIBUTE AS "System.Web.Services.WebServiceAttribute"
21: CLASS CLASS-WEBSERVICEBINDINGATTR AS "System.Web.Services.WebServiceBindingAttribute"
22: CLASS CLASS-SQLPROCEDURE AS "Microsoft.SqlServer.Server.SqlProcedureAttribute"
23: CLASS CLASS-XML AS "System.Xml.XmlDocument"
24: CLASS CLASS-STRING-BUILDER AS "System.Text.StringBuilder"
25: ENUM ENUM-WSIPROFILES AS "System.Web.Services.WsiProfiles"
26: PROPERTY PROP-BASICPROFILE1_1 AS "BasicProfile1_1"
27: PROPERTY PROP-CONFORMSTO AS "ConformsTo"
28: PROPERTY PROP-NAMESPACE AS "Namespace"
29: .
30: OBJECT.
31: DATA DIVISION.
32: WORKING-STORAGE SECTION.
33: 01 MSG PIC X(1200).
34: 01 WK-BROTHEL-NAME PIC X(255).
35: 01 WK-STREET PIC X(255).
36: 01 WK-CITY PIC X(255).
37: 01 WK-POSTAL-CODE PIC X(6).
38: 01 WK-PHONE PIC X(255).
39: 01 WK-LINK PIC X(255).
40: 01 WK-LATITUDE PIC X(50).
41: 01 WK-LONGITUDE PIC X(50).
42: 01 WK-STRING OBJECT REFERENCE CLASS-STRING.
43: 01 WK-STRING-BUILDER OBJECT REFERENCE CLASS-STRING-BUILDER.
44: PROCEDURE DIVISION.
45:
46: METHOD-ID. NEW.
47: PROCEDURE DIVISION.
48: *> Uncomment the following line if using designed components.
49: *> INVOKE SELF "InitializeComponent".
50: END METHOD NEW.
51:
52: METHOD-ID. GET-BROTHELS AS "GetBrothels" CUSTOM-ATTRIBUTE CA-WEBMETHOD.
53: DATA DIVISION.
54: WORKING-STORAGE SECTION.
55: *> There must be enough fields for the number of columns.
56: EXEC SQL BEGIN DECLARE SECTION END-EXEC.
57: 01 BROTHEL-LIST.
58: 02 BROTHEL-NAME PIC X(255).
59: 02 STREET PIC X(255).
60: 02 CITY PIC X(255).
61: 02 POSTAL-CODE PIC X(6).
62: 02 PHONE PIC X(25).
63: 02 LINK PIC X(255).
64: 02 LATITUDE PIC X(50).
65: 02 LONGITUDE PIC X(50).
66: 01 NUMBER-OF-RECORDS PIC S9(9) COMP-5.
67: 01 SQLINFOA.
68: 02 SQLERRD PIC S9(9) COMP-5 OCCURS 6 TIMES.
69: 01 SQLSTATE PIC X(5).
70: EXEC SQL END DECLARE SECTION END-EXEC.
71: LINKAGE SECTION.
72: 01 RET-VAL OBJECT REFERENCE CLASS-STRING.
73: 01 RET-VAL-XML OBJECT REFERENCE CLASS-XML.
74: PROCEDURE DIVISION RETURNING RET-VAL-XML.
75: EXEC SQL WHENEVER NOT FOUND GO TO :P-END END-EXEC.
76: EXEC SQL
77: DECLARE CUR1 CURSOR FOR SELECT BrothelName, Street, City, PostalCode, Phone, Link, Latitude, Longitude FROM ErosCenters
78: END-EXEC.
79: P-START.
80: EXEC SQL CONNECT TO 'SERVER1' AS 'CNN1' END-EXEC.
81: EXEC SQL
82: SELECT COUNT(*) INTO :NUMBER-OF-RECORDS FROM ErosCenters
83: END-EXEC.
84: EXEC SQL OPEN CUR1 END-EXEC.
85: *> CREATE AN STRING BUILDER OBJECT
86: INVOKE CLASS-STRING-BUILDER "NEW" RETURNING WK-STRING-BUILDER.
87: *> CALL THE OBJECT METHOD
88: SET WK-STRING TO "<ErosCenters>"
89: INVOKE WK-STRING-BUILDER "Append" USING BY VALUE WK-STRING.
90: PERFORM P-LOOP NUMBER-OF-RECORDS TIMES.
91: P-LOOP.
92: EXEC SQL
93: FETCH CUR1 INTO :BROTHEL-LIST
94: END-EXEC.
95: *> MOVE SQLERRD(3) TO MSG.
96: *> MOVE BROTHEL-LIST TO MSG.
97: MOVE BROTHEL-NAME TO WK-BROTHEL-NAME.
98: MOVE STREET TO WK-STREET.
99: MOVE CITY TO WK-CITY.
100: MOVE POSTAL-CODE TO WK-POSTAL-CODE.
101: MOVE PHONE TO WK-PHONE.
102: MOVE LINK TO WK-LINK.
103: MOVE LATITUDE TO WK-LATITUDE.
104: MOVE LONGITUDE TO WK-LONGITUDE.
105: *> CONSTRUCT XML STRING
106: SET WK-STRING TO CLASS-STRING::"Concat"(N"<Brothel><Name>" WK-BROTHEL-NAME N"</Name>").
107: INVOKE WK-STRING-BUILDER "Append" USING BY VALUE WK-STRING.
108: SET WK-STRING TO CLASS-STRING::"Concat"(N"<Street>" WK-STREET N"</Street>").
109: INVOKE WK-STRING-BUILDER "Append" USING BY VALUE WK-STRING.
110: SET WK-STRING TO CLASS-STRING::"Concat"(N"<City>" WK-CITY N"</City>").
111: INVOKE WK-STRING-BUILDER "Append" USING BY VALUE WK-STRING.
112: SET WK-STRING TO CLASS-STRING::"Concat"(N"<PostalCode>" WK-POSTAL-CODE N"</PostalCode>").
113: INVOKE WK-STRING-BUILDER "Append" USING BY VALUE WK-STRING.
114: SET WK-STRING TO CLASS-STRING::"Concat"(N"<Phone>" WK-PHONE N"</Phone>").
115: INVOKE WK-STRING-BUILDER "Append" USING BY VALUE WK-STRING.
116: SET WK-STRING TO CLASS-STRING::"Concat"(N"<Link>" WK-LINK N"</Link>").
117: INVOKE WK-STRING-BUILDER "Append" USING BY VALUE WK-STRING.
118: SET WK-STRING TO CLASS-STRING::"Concat"(N"<Latitude>" WK-LATITUDE N"</Latitude>").
119: INVOKE WK-STRING-BUILDER "Append" USING BY VALUE WK-STRING.
120: SET WK-STRING TO CLASS-STRING::"Concat"(N"<Longitude>" WK-LONGITUDE N"</Longitude></Brothel>").
121: INVOKE WK-STRING-BUILDER "Append" USING BY VALUE WK-STRING.
122: P-END.
123: SET WK-STRING TO "</ErosCenters>"
124: INVOKE WK-STRING-BUILDER "Append" USING BY VALUE WK-STRING.
125: EXEC SQL CLOSE CUR1 END-EXEC.
126: EXEC SQL ROLLBACK WORK END-EXEC.
127: EXEC SQL DISCONNECT DEFAULT END-EXEC.
128: *> INVOKE SELF "GetData" .
129: *> CREATE AN XMLDOCUMENT OBJECT
130: INVOKE CLASS-XML "NEW" RETURNING RET-VAL-XML.
131: *> CALL THE OBJECT METHOD
132: SET WK-STRING TO WK-STRING-BUILDER::"ToString".
133: INVOKE RET-VAL-XML "LoadXml" USING BY VALUE WK-STRING.
134: END METHOD GET-BROTHELS.
135:
136: METHOD-ID. GET-DATA AS "GetData".
137: PROCEDURE DIVISION.
138: MOVE "Hello" & " World" TO MSG.
139: END METHOD GET-DATA.
140:
141: END OBJECT.
142: END CLASS CLASS-THIS.
Instead of a C# using namespace, you must alias a class in the REPOSITORY section. You define your string variables in the WORKING-STORAGE SECTION. Line 80 is where the database connection is being made. Then there is a query to determine how many records there are which tells you how many times to perform a routine. The database fields are moved to working storage strings which are then concatenated with XML tags. As you can see, just getting COBOL to build a string is hard work. A XmlDocument is created on line 130 and its LoadXml method is called to load the string that was built. This is what the web service returns.
1: <?xml version="1.0" encoding="utf-8"?>
2: <ErosCenters>
3: <Brothel>
4: <Name>Laufhaus Vitalia</Name>
5: <Street>Helene-Wessel-Bogen 16</Street>
6: <City>Munich</City>
7: <PostalCode>80939</PostalCode>
8: <Phone>+49 (0) 89 35818865</Phone>
9: <Link>http://www.laufhaus-vitalia.de</Link>
10: <Latitude>48.197147</Latitude>
11: <Longitude>11.592529</Longitude>
12: </Brothel>
13: <Brothel>
14: <Name>Maison d'envie</Name>
15: <Street>Danziger Strasse 61</Street>
16: <City>Berlin</City>
17: <PostalCode>10435</PostalCode>
18: <Phone>030 417 259 20</Phone>
19: <Link>http://www.danziger61.de</Link>
20: <Latitude>52.540201</Latitude>
21: <Longitude>13.422267</Longitude>
22: </Brothel>
23: <Brothel>
24: <Name>Laufhaus Eros</Name>
25: <Street>Ulmer Strasse 16</Street>
26: <City>Goppingen</City>
27: <PostalCode>73107</PostalCode>
28: <Phone>07161-50 60 180</Phone>
29: <Link>http://wwwlaufhaus-eros.de</Link>
30: <Latitude>48.699458</Latitude>
31: <Longitude>9.663935</Longitude>
32: </Brothel>
33: </ErosCenters>
I’ve used Eiffel for the .NET Framework but I would prefer COBOL since it can be used with the .NET Framework 2.0 and Visual Studio 2005. I learned COBOL in community college but never got the chance to use it professionally.
Please note that the brothel locator web service is intended as a joke. I just thought it would entice programmers to check out COBOL for the .NET Framework. My serious articles are often ignored. Nobody has actually requested this web service and it will not be used. It was purely a programming exercise. The nature of the data in the database is unimportant compared to the interesting choice of programming language and the technical challenge of making this work in COBOL.
Pingback: Brothel Locator Web Service In COBOL – Williamsport Web Developer … | Mobile Phone Street
Pingback: Brothel Locator Web Service In COBOL – Williamsport Web Developer … | developer