Sunday, March 18, 2012

Axis C/C++ for Client/Server Apps

Axis is a c++ implementation of a runtime engine with client and server support for web applications. It features a soap engine. A WSDL2WS tool is used to generate client and server side stubs. Client side apps are written to produce output from a server side implementation. The below program is a calculator client side app. A subsequent server app exists to produce results from queries from the client app.
The classpath icludes the following jars:
 <AxisCPP Install dir>/lib/axis/wsdl2ws.jar: Contains the main WSDL2Ws code.
<AxisCPP Install dir>/lib/axisjava/axis.jar: Contains the Axis java code which WSDL2Ws is
based on
<AxisCPP Install dir>/lib/axisjava/commons-discovery.jar:
<AxisCPP Install dir>/lib/axisjava/commons-logging.jar;
<AxisCPP Install dir>/lib/axisjava/jaxrpc.jar;
<AxisCPP Install dir>/lib/axisjava/saaj.jar;
<AxisCPP Install dir>/lib/axisjava/wsdl4j.jar
java org.apache.axis.wsdl.wsdl2ws.WSDL2Ws Calculator.wsdl -lc++ -sclient
The above  command generates the client side stub. The *.cpp are then made into a client side service by the below instruction.

g++ *.cpp -I<Axis installation directory>/include -L<Axis installation
directory>/lib -ldl -laxiscpp_client -ocalculator

The calculator service is invoked by the:
./calculator add 10 5 http://localhost/axis/Calculator command.

#include "Calculator.hpp"
#include <axis/AxisException.hpp>
#include <iostream>
bool IsNumber (const char *p);
static void
usage (char *programName, char *defaultURL)
{
    cout << "\nUsage:\n"
 << programName << " [-? | div number1 number2 [service_url]] " << endl
 << "    -?             Show this help.\n"
 << "    service_url    URL of the service.\n"
 << "    Default service URL is assumed to be " << defaultURL << endl;
}
int
main (int argc, char *argv[])
{
    char endpoint[256];
    char original[256];
    const char *server = "localhost";
    const char *port = "80";
    const char *op = 0;
    const char *p1 = 0;
    const char *p2 = 0;
    int i1 = 0, i2 = 0;
    int iResult;
    // Set default service URL
    sprintf (endpoint, "http://localhost/axis/calculator");
    sprintf (original, endpoint);
    try
    {
 if (argc == 1)
 {
     usage (argv[0], endpoint);
     return 2;
 }
 if (argc > 1)
 {
     if (!strncmp (argv[1], "-", 1))
     {
  // Check for - only so that it works for
  //-?, -h or --help; -anything
  usage (argv[0], endpoint);
  return 2;
     }
     //less than minimum number of args OR greater than maximum number of args
     else if (argc < 4 || argc > 5)
     {
  usage (argv[0], endpoint);
  return 2;
     }
     else if (argc == 5)
     {
  sprintf (endpoint, argv[4]);
     }
 }
 cout << endl << " Using service at " << endpoint << endl << endl;
 Calculator ws (endpoint);
 op = argv[1];
 p1 = argv[2];
 p2 = argv[3];
 if (!IsNumber (p1))
 {
     printf ("Invalid value for first <parameter> %s\n\n", p1);
     usage (argv[0], original);
     return 2;
 }
 if (!IsNumber (p2))
 {
     printf ("Invalid value for second <parameter> %s\n\n", p2);
     usage (argv[0], original);
     return 2;
 }
 i1 = atoi (p1);
 i2 = atoi (p2);
 if (strcmp (op, "add") == 0)
 {
     iResult = ws.add (i1, i2);
     printf ("%d\n", iResult);
 }
 else if (strcmp (op, "sub") == 0)
 {
     iResult = ws.sub (i1, i2);
     printf ("%d\n", iResult);
 }
 else if (strcmp (op, "mul") == 0)
 {
     iResult = ws.mul (i1, i2);
     printf ("%d\n", iResult);
 }
 else if (strcmp (op, "div") == 0)
 {
     iResult = ws.div (i1, i2);
     printf ("%d\n", iResult);
 }
 else
 {
     printf ("Invalid operation %s\n\n", op);
     usage (argv[0], original);
     return 2;
 }
    }
    catch (AxisException & e)
    {
 printf ("Exception : %s\n", e.what ());
    }
    catch (exception & e)
    {
 printf ("Unknown exception has occured\n");
    }
    catch (...)
    {
 printf ("Unknown exception has occured\n");
    }
    return 0;
}
bool
IsNumber (const char *p)
{
    for (int x = 0; x < strlen (p); x++)
    {
 if (!isdigit (p[x]))
     return false;
    }
    return true;
}

A WSDL Client for a StockQuotes.wsdl file

When writing client apps for wsdl files the standard library for input/output alongwith parsers-wsdl, schema, and xml are put into use. The below program uses a WSDL c++ web services client library-WSDLPULL to create web services client for a StockQuotes.wsdl xml file. Methods such as setWSDLUri, setOperation, setValue and getValue insert and retrieve data from the xml and make it available to the client application.
/*
 * File:   WSDL_Client.cpp
 * Author: WSDL_Client
 *
 * Created on March 8, 2012, 2:21 AM
 */
#include <stdlib.h>
#include <WsdlInvoker.h>
#include <SchemaParser.h>
#include <XMLSerializer.h>
/*
 *
 */
int main(int argc, char** argv) {
WsdlInvoker invoker;
  if (!invoker.setWSDLUri("StockQuotes.wsdl")) {
    std::cerr<<invoker.errors()<<std::endl; return 2;
  }
 std::vector<std::string> ops;
  invoker.getOperations(ops);
  if(!invoker.setOperation("GetStockQuotes")){
      std::cerr<<"Error calling GetStockQuotes "<<std::endl;
      return 2;
   }
 if (invoker.status()){
       std::string ticker("XYZ");
       if (!invoker.setValue("QuoteTicker",(void*)(&ticker))){
            std::cerr<<"Incorrect input value "<<ticker<<std::endl;
            return 2;
       }
        if (invoker.invoke()){
         Schema::Type type;
         void *val = invoker.getValue("OpenPrice",type);
         //type is a string
         cout<<*((std::string*)val)<<std::endl;
   }
std::vector<std::string> stocks
     stocks.push_back("IBM");
     stocks.push_back("YHOO");
     stocks.push_back("MSFT");
     stocks.push_back("MOT");
     //4 occurrences of the <QuoteTicker> element
     invoker.setValue("QuoteTicker",stocks);
 int getNextInput(std::string & param ,Schema::Type & type,int & min,int & max);
    return (EXIT_SUCCESS);
}
<s:element name="GetQuotes"><s:complexType><s:sequence><s:element minOccurs="0" maxOccurs="1" name="QuoteTicker" type="s:string" />
</s:sequence></s:complexType></s:element><s:element name="GetQuotesResponse"> <s:complexType>
<s:sequence>   <s:element minOccurs="0" maxOccurs="1" name="GetQuotesResult" type="s0:ArrayOfQuote" />
</s:sequence>
</s:complexType></s:element><s:complexType name="ArrayOfQuote">
<s:sequence><s:element minOccurs="0" maxOccurs="unbounded" name="Quote" type="s0:Quote" />
</s:sequence>
</s:complexType><s:complexType name="Quote">
<s:sequence><s:element minOccurs="0" maxOccurs="1" name="CompanyName" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="StockTicker" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="StockQuote" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="LastUpdated" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="Change" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="OpenPrice" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="DayHighPrice" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="DayLowPrice" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="Volume" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="MarketCap" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="YearRange" type="s:string" />
</s:sequence></s:complexType><s:element name="ArrayOfQuote" nillable="true" type="s0:ArrayOfQuote" /></s:schema>
<message name="GetQuotesSoapIn"><part name="parameters" element="s0:GetQuotes" />
</message>
<message name="GetQuotesSoapOut"><part name="parameters" element="s0:GetQuotesResponse" /></message>
<portType name="StockQuotesSoap"><operation name="GetStockQuotes">
<input name="GetQuotes" message="s0:GetQuotesSoapIn" />
<output name="GetQuotes" message="s0:GetQuotesSoapOut" /></operation></portType>

Cout and the IOStream Object Library

The Cout command is instrumental in programming input/output classes in the iostream library. The c++config.h file in the \MinGW\lib\gcc\mingw32\4.6.1\include\c++\bits directory has links to the iostream object and have to be included accordingly.
#include<iostream>
using namespace std;
//#include<c++config.h>
int io_stream_check(){
    cout<<"Hello World";
    //std::cout << "Hello world" << std::endl;
    return 0;
}

Saturday, March 17, 2012

Makefiles in C++ Project

A Makefile is used by the make command to create object or assembly files with rules, dependencies and target directory paths to direct output to a given set of pre-determined locations or items. A typical makefile is named Make1.make with an output of Make1.out for a project comprising of three cpp and one .h files.

# Make1.make -- this is a comment line, ignored by make utility
Make1.out : main1.o mylib.o openfile.o
g++ -o lab1.out main1.o mylib.o openfile.o
# above, we are saying lab1.out depends on main1.o, mylib.o and openfile.o
# and to create lab1.out we give the g++ command as shown on the next line
# which starts with a TAB although you cannot see that .
# note that the command : g++ -o lab1.out main1.o mylib.o openfile.o
# creates an executable file named lab1.out from the 3 object files respectively.
main1.o: main1.cpp openfile.h mylib.h
g++ -c main1.cpp
# above we are saying main1.o depends on main1.cpp openfile.h and mylib.h
# and to compile only main1.cpp if and only if main1.cpp or openfile.h or mylib.h
# have changed since the last creation of main1.o
mylib.o: mylib.cpp mylib.h
g++ -c mylib.cpp
# above we are saying mylib.o depends on mylib.cpp and mylib.h
# so if either mylib.cpp or mylib.h CHANGED since creating mylib.o
# comple mylib.cpp again
openfile.o: openfile.cpp openfile.h
g++ -c openfile.cpp
# above we are saying openfile.o depends on openfile.cpp and openfile.h
# so if either openfile.cpp or openfile.h has CHANGED since creating
# openfile.o, compile only (again) openfile.cpp
clean:
&nbps rm *.o Make1.out
# above we are stating how to run the rule for clean, no dependencies,
# what we want is when we ask to do a "make -f lab1.make clean"
# that will not do anything except remove executable and object files
# so we can "clean out" our directory of unneeded large files.
# we only do a make clean when we want to clean up the files.
# END OF MAKE FILE

The g++.exe Command Line Argument

Once the include files are set in the editor options, the commands are to be installed into the directories, namely the bin directories.
•gcc-g++ (bin and dll) for C++
•gcc-objc (bin and dll) for Objective C
•gcc-gfortran (bin and dll) for Fortran 90/95
•gcc-java (not yet available) for Java
•gcc-ada (bin and dll) for Ada
g++.exe -m32    -o dist/Debug/MinGW-Windows/application_1 build/Debug/MinGW-Windows/First.o build/Debug/MinGW-Windows/IoStream_Demo.o build/Debug/MinGW-Windows/First.o. The make command compiles a cpp file to create an obj file to be run  by the above command.


 

Working with the MinGW Compiler

Depending on the editor you choose, the MinGW compiler provides comprehensive C++ classes and functions for all general purposes and needs. The C:\MinGW\include contains the libraries for files io.h, conio.h, stdio.h.

#include<io.h>
#include <conio.h>
#include <stdio.h>
int First(){
    int SW_SHOWMAXIMIZED=3;
    int i;
    int j;
    int iarray[6]={4,0,2,6,8,9};
    for(i=0;i<6;i++)
    {printf("Hello World-%d\n",iarray[i]);}
    }
    printf("%d",j);
    return 0;
    }

Starting with a Simple Win32 API Window

The Win32 API is the gateway to programming the system APIs and provides classes and functions for activating inbuilt system commands and procedures. The program below creates a simple window allowing the user to set the size, color, icon and other properties. Controls can be set on such windows and functions such as PostMessage and SendMessage can be run on such windows.
#include <windows.h>
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
char szClassName[ ] = "WindowsApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)
{
    HWND hwnd;
    MSG messages;
    WNDCLASSEX wincl;
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;
    //wincl.style = CS_DBLCLKS;
    wincl.style= CS_HREDRAW | CS_VREDRAW;
    wincl.cbSize = sizeof (WNDCLASSEX);
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;
    wincl.cbClsExtra = 0;
    wincl.cbWndExtra = 0;
    wincl.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE;
    if (!RegisterClassEx (&wincl))
        return 0;

    hwnd = CreateWindowEx (
           0,
           szClassName,
           "Windows App",
           WS_OVERLAPPEDWINDOW,
           CW_USEDEFAULT,
           CW_USEDEFAULT,
           744,
           575,
           HWND_DESKTOP,
           NULL,
           hThisInstance,
           NULL
           );
    ShowWindow (hwnd, nFunsterStil);
    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    return messages.wParam;
}
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_DESTROY:
            PostQuitMessage (0);
            break;
        default:
            return DefWindowProc (hwnd, message, wParam, lParam);
    }
    return 0;
}