Lab

2

Middleware Platforms

CORBA Stock Quoter Service


Systems Architecture Group

Abgabe bis zum 09.06.2014   9.00 über Goya

Zur Einführung soll eine einfache Börsenanwendung mit Hilfe von CORBA realisiert werden. Die Anwendung gliedert sich in einen Server, der Informationen über Aktien (z.B. Kurse) bereitstellt, und einem Client, der diese Informationen abfragen kann.

Teil A - Server

Der Server soll folgende Funktionalitäten bereitstellen:

  • Erzeugen eines CORBA Objekts, das die Schnittstelle Quoter_Factory besitzt, und Ablegen der zugehörigen IOR im Dateisystem (Dateiname quoter_factory.ior).
  • Mittels der Quoter_Factory lassen sich unter Angabe eines Namens (z.B. "Dow Jones", "Reuters") neue Quoter Objekte erzeugen (Methode create_quoter()).
  • Ein Quoter besitzt einen Namen (Attribut quoter_name) und liefert den aktuellen Kurs einer Aktie unter Angabe deren Namens (Methode get_quote()).
  • Das von der Quoter_Factory erzeugte Objekt implementiert zusätzlich die Schnittstelle StockQuoter, die genauere Informationen zu einer Aktie in Form eines StockInfo Objekts liefert.

Verwenden Sie bitte folgende IDL-Schnittstellendefinitionen.

module stocks

{

  struct StockInfo {

    string name;

    string symbol;

    string ISIN;

    enum StockType {

      common_stock,

      preferred_stock,

      tresury_stock

    } type;

    struct StockQuote {

      long high;

      long low;

      long last;

    } quote;

  };

 

  exception InvalidStock {};

  exception InvalidQuoter {};

 

  interface Quoter {

    readonly attribute string quoter_name;

    long get_quote (in string stock_name)

      raises (InvalidStock);

  };

 

      interface StockQuoter : Quoter {

    StockInfo get_stock_info (in string stock_name)

      raises (InvalidStock);

      };

 

  interface QuoterFactory {

    Quoter create_quoter (in string name)

      raises (InvalidQuoter);

  };

};

Implementationssprache für den Server ist C++ unter Verwendung von MICO CORBA (http://www.mico.org, Installation siehe unten). Zur Vereinfachung liefern alle Quoter gleiche Daten, die fest programmiert sein können. Dabei sollen mindestens die folgenden Sätze abfragbar sein:

Name

Symbol

ISIN

Stock Type

High

Low

Last

3M MMM US88579Y1010 CS 75 69 71
Boeing BA US0970231058 CS 68 64 67
Hewlett-Packard HPQ US4282361033 PS 31 31 31
Intel INTC US4581401001 TS 29 27 27

 Teil B – Client

Der Client ist eine Konsolenanwendung (console application), die dem Nutzer eine einfache Kommandozeile bietet. Er soll in der Sprache Java mit Hilfe des integrierten Java ORB realisiert werden.

Der Client besteht konzeptuell aus 2 Teilen: einem "Bibliotheksteil" und der Nutzerschnittstelle. Der Bibliotheksteil implementiert die nachfolgende Java-Schnittstelle und interagiert mit dem Server über die in IDL definierte Schnittstelle. Die Aufgabe des Bibliotheksteils ist das Transformieren der eingehenden Aufrufe (auf der unten stehenden Java-Schnittstelle) in Aufrufe an den Server (über die IDL-Schnittstelle).

Die Nutzerschnittstelle stellt dem Benutzer eine Kommandozeile zur Verfügung und interagiert mit dem Bibliotheksteil über die nachfolgende Java-Schnittstelle. Bitte definieren Sie die Kommandosprache selbst. Die Implementierungsklasse für das Interface ClientQuoterFactory soll den Namen ClientQuoterFactoryImpl tragen und das ORB-Objekt als einzigen Parameter für den Konstruktor verwenden (siehe dazu die Methode setUp() der Unittest-Klasse).

Diese Zweiteilung des Client ist nicht CORBA-typisch. Sie ist nötig, um sowohl Client als auch Server mit einem Unittest unter Java testen zu können (siehe dazu die unten aufgeführte Testklasse und die Variablen _serverFactory und _clientFactory).

package stocks.client;

 

public class InvalidStockException extends Exception {}

public class InvalidQuoterException extends Exception {}

 

public interface ClientStock {

      public static final int common_stock = 0;

      public static final int preferred_stock = 1;

      public static final int tresury_stock = 2;

 

      String getName();

      String getSymbol();

      String getISIN();

      int getStockType();

      long getHigh();

      long getLow();

      long getLast();

}

 

public interface ClientStockQuoter {

        String getQuoterName();

       

        ClientStock getStock ( String stock_name)

          throws InvalidStockException;

}

 

public interface ClientQuoterFactory {

      ClientStockQuoter create_quoter (String name)

            throws InvalidQuoterException;

}

Abgabe und Bewertung

Begründen Sie die von Ihnen getroffenen Design-Entscheidungen und beschreiben Sie aufgetretene Besonderheiten und Probleme. Benutzen Sie dafür eine HTML Datei mit dem Namen index.html. Abzugeben sind weiterhin die Quelltexte der Lösung und ein Ant Skript mit dem Namen build.xml, das die Quellen mit den gängigen Werkzeugen automatisiert übersetzt (Bitte die Targets compile, test und clean definieren. Der Server wird jeweils separat von Hand gestartet.).

Der Server soll mit einem Shell-Script build.bat/build.sh übersetzt werden. Sie können davon ausgehen, dass die Umgebungsvariable MICO_HOME auf das Installtionsverzeichnis des MICO ORB gesetzt ist, dass das Verzeichnis MICO_HOME/bin im Suchpfad PATH und MICO_HOME/lib im Bibliothekspfad LD_LIBRARY_PATH ist und dass make/nmake verfügbar ist. Bitte schreiben sie ein weiteres Script server.sh/server.bat, dass den Server startet. Bitte reichen Sie die geforderten Dateien in ein ZIP Archiv gepackt ein.

Für Test und Bewertung kommt die Unit-Test-Bibliothek jUnit (www.junit.org) zum Einsatz. Die geforderte Funktionalität wird anhand von 10 Unit-Tests überprüft, von denen Ihnen vorab die folgenden 5 zur Verfügung stehen.

package stocks.test;

import java.io.BufferedReader;

import java.io.DataInputStream;

import java.io.FileInputStream;

import java.io.InputStreamReader;

import org.omg.CORBA.ORB;

 

import stocks.*;

import stocks.StockInfoPackage.StockType;

import stocks.client.*;

import junit.framework.TestCase;

import org.junit.*;

  

public class StockQuoterTest extends TestCase {

      QuoterFactory _serverFactory = null;

      ClientQuoterFactory _clientFactory = null;

  ORB _orb = null;

 

  public static void main(String[] args) {

    junit.textui.TestRunner.run(StockQuoterTest.class);

  }

 

  public StockQuoterTest(String name) {

    super(name);

  }

 

  @Before

  protected void setUp() throws Exception {

    super.setUp();

 

    String[] args = null;

    _orb = ORB.init(args,null);

   

    _clientFactory = new ClientQuoterFactoryImpl(_orb);

 

    String filename = "quoter_factory.ior";

    FileInputStream fis = new FileInputStream(filename);

    BufferedReader d = new BufferedReader(new InputStreamReader(fis));

    String ior = d.readLine();

   

    org.omg.CORBA.Object obj = _orb.string_to_object(ior);

    _serverFactory = QuoterFactoryHelper.narrow(obj);

  }

 

  @After

  protected void tearDown() throws Exception {

    super.tearDown();

   

    _clientFactory = null;

    _serverFactory = null;

    _orb = null;

  }

 

  @Test

  public void test1() throws Exception {

    String name = "Dow Jones";

    Quoter dowjones = _serverFactory.create_quoter(name);

    assertEquals( name, dowjones.quoter_name() );

   

    int iQuote = dowjones.get_quote("Boeing");

    assertEquals( 67, iQuote );

  }

 

  @Test

  public void test2() throws Exception {

    Quoter obj = _serverFactory.create_quoter("Dow Jones");

    StockQuoter dowjones = StockQuoterHelper.narrow(obj);

  }

 

  @Test

  public void test3() throws Exception {

    Quoter obj = _serverFactory.create_quoter("Dow Jones");

    StockQuoter dowjones = StockQuoterHelper.narrow(obj);

   

    String name = "Intel";

    StockInfo intel = dowjones.get_stock_info(name);

    assertEquals( name, intel.name );

    assertEquals( "INTC", intel.symbol );

    assertEquals( "US4581401001", intel.ISIN );

    assertEquals( StockType._tresury_stock, intel.type.value() );

    assertEquals( 29, intel.quote.high );

    assertEquals( 27, intel.quote.low );

    assertEquals( 27, intel.quote.last );

  }

 

  @Test

  public void test6() throws Exception {

    String name = "Dow Jones";

    ClientStockQuoter dowjones = _clientFactory.create_quoter(name);

    assertEquals( name, dowjones.getQuoterName() );

   

    ClientStock boeing = dowjones.getStock("Boeing");

    assertEquals( 67, boeing.getLast() );

  }

 

  @Test

  public void test7() throws Exception {

    ClientStockQuoter dowjones = _clientFactory.create_quoter("Dow Jones");

 

    String name = "Intel";

    ClientStock intel = dowjones.getStock(name);

    assertEquals( name, intel.getName() );

    assertEquals( "INTC", intel.getSymbol() );

    assertEquals( "US4581401001", intel.getISIN() );

    assertEquals( ClientStock.tresury_stock, intel.getStockType() );

    assertEquals( 29, intel.getHigh() );

    assertEquals( 27, intel.getLow() );

    assertEquals( 27, intel.getLast() );

  }

}

Hinweise

Behandeln Sie auch Fehler- und Ausnahmesituationen entsprechend. Bedenken Sie, dass unter Umständen auch mehrere Clients gleichzeitig auf den Server zugreifen können.

Da die IDL-Schnittstelle fest vorgegeben ist, können Sie Ihren Server bzw. Client auch mit denen anderer Praktikumsgruppen betreiben. Für die CORBA IDL existieren weitere Sprachabbildungen, beispielsweise für Python, Pascal, TCL, Perl, C, Ada, etc. (siehe http://en.wikipedia.org/wiki/Corba). Interessierte Praktikumsgruppen können zusätzlich Client oder Server in diesen Sprachen realisieren.

Benötigte Software

Java SDK 1.5 oder höher. Der IDL-Compiler für die Übersetzung nach Java heißt idlj.

MICO CORBA

MICO lässt sich mit GCC/Linux oder unter Windows mit GCC/Cygwin oder dem MS Visual C++ Compiler übersetzen.
Die Installation unter Linux wird empfohlen:

  1. Quellen herunterladen (mico-2.3.13.tar.gz)

  2. Auspacken: tar -xzf mico-2.3.13.tar.gz, in das erzeugte Verzeichnis wechseln

  3. Konfigurieren: ./configure --prefix=MICO_HOME --disable-coss --disable-shared --enable-minimum-corba --enable-thread --enable-pthreads
    Dabei ist MICO_HOME mit dem Pfad zu ersetzen, in dem MICO installiert werden soll!

  4. Übersetzen: make

  5. Installieren: make install
    Als letzte Meldung auf der Kommandozeile erhält man dabei den Fehler, dass ldconfig nicht auf /etc/ld.so.cache~ zugreifen kann. Dieser Fehler kann ignoriert werden.

  6. Ggf. Pfade anpassen (siehe dazu MICO_HOME/lib/mico-setup.sh)

Nach erfolgreicher Installation sind in MICO_HOME/bin Wrapper-Scripte für die Aufrufe von Compiler, Linker & Co. zu finden. Diese Scripte haben den Prefix "mico-", beispielsweise mico-c++ für den C++-Compiler. Für die Übersetzung sollten möglichst diese Scripte verwendet werden, da sie die benötigten Pfade, Bibliotheken usw. an die zugrunde liegenden Werkzeuge weitergeben.

Literatur

Michi Henning, Steve Vinoski: "Advanced CORBA(R) Programming with C++" [amazon]


Legal disclaimer. .  © 2024 Humboldt-Universität zu Berlin, Computer Science Department, Systems Architecture Group. Contact: sar@informatik.hu-berlin.de .