Java
spring
spring-boot
CORBA

Spring(Java)からCORBAサービスを呼び出してみる

More than 1 year has passed since last update.

Springを使っているアプリからCORBAサービスを呼び出す必要にせまられそうなので、どうすればいいのかな〜と思ってちょっと試してみました。

検証バージョン

  • Java SE 8 (JDK 1.8.0_121)
  • Spring Boot 1.5.6.RELEASE (Spring Framework 4.3.10.RELEASE)

JavaでCORBAサービスを作ってみる

まずIDLファイルを作ります。

Greeting.idl
module com {
  module example {
    module democorba {
      interface Greeting
      {
        string hello(in string message);
      };
    };
  };
};

つぎに、JDKから提供されているidljコンパイラを使ってJavaコードを生成します。

$ idlj -fall -td src/main/java src/main/resources/Greeting.idl
$ tree src/main/java
src/main/java
└── com
    └── example
        └── democorba
            ├── Greeting.java
            ├── GreetingHelper.java
            ├── GreetingHolder.java
            ├── GreetingOperations.java
            ├── GreetingPOA.java
            └── _GreetingStub.java

最後に、サービスの実装を行います。

package com.example.democorba.server;

import com.example.democorba.GreetingPOA;

public class GreetingImpl extends GreetingPOA {

  public String hello(String message) {
    return "Hello !! (" + message + ")";
  }

}

JavaでCORBAサービスを公開してみる

JDK(JRE)から提供されているorbdコマンドを利用して、作成したCORBAサービスを公開するためのクラスを作ります。

package com.example.democorba.server;

import com.example.democorba.Greeting;
import com.example.democorba.GreetingHelper;
import org.omg.CORBA.ORB;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.CosNaming.NamingContextPackage.CannotProceed;
import org.omg.CosNaming.NamingContextPackage.NotFound;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAHelper;
import org.omg.PortableServer.POAManagerPackage.AdapterInactive;
import org.omg.PortableServer.POAPackage.ServantNotActive;
import org.omg.PortableServer.POAPackage.WrongPolicy;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class GreetingServer {

  public static final String[] ORB_OPTIONS = new String[]{"-ORBInitialPort", "1050", "-ORBInitialHost", "localhost"};

  public static void main(String args[]) throws IOException, InterruptedException {

    List<String> orbdStartupCommands = new ArrayList<>();
    orbdStartupCommands.add("orbd");
    orbdStartupCommands.addAll(Arrays.asList(ORB_OPTIONS));

    Process orbdProcess = new ProcessBuilder(orbdStartupCommands).start();
    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
      System.out.println("GreetingService Exiting ...");
      orbdProcess.destroy();
    }));

    TimeUnit.SECONDS.sleep(1);

    try {
      bindService(ORB_OPTIONS);
    } catch (Exception e) {
      System.err.println("ERROR: " + e);
      e.printStackTrace(System.out);
    }

  }

  private static void bindService(String[] options) throws InvalidName, AdapterInactive, ServantNotActive, WrongPolicy, org.omg.CosNaming.NamingContextPackage.InvalidName, NotFound, CannotProceed {
    ORB orb = ORB.init(options, null);

    POA poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
    poa.the_POAManager().activate();

    GreetingImpl greeting = new GreetingImpl();

    org.omg.CORBA.Object ref = poa.servant_to_reference(greeting);
    Greeting href = GreetingHelper.narrow(ref);

    org.omg.CORBA.Object objRef =
      orb.resolve_initial_references("NameService");
    NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

    NameComponent path[] = ncRef.to_name("Greeting");
    ncRef.rebind(path, href);

    System.out.println("GreetingService ready started and waiting request ...");

    orb.run();
  }

}

作成したクラスを実行すると・・・

コンソール
GreetingService ready started and waiting request ...

となります。

停止は、IDEが提供している停止機能や「Ctrl+C」を使ってください。停止すると・・・

コンソール
...
GreetingService Exiting ...

となります。

JavaからCORBAサービスを呼び出してみる

CORBAサービスを呼び出すJUnitを作ってみます。

package com.example.democorba;

import org.hamcrest.core.Is;
import org.junit.Assert;
import org.junit.Test;
import org.omg.CORBA.ORB;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.CosNaming.NamingContextPackage.CannotProceed;
import org.omg.CosNaming.NamingContextPackage.NotFound;

public class GreetingTest {

  private static final String[] ORB_OPTIONS = new String[]{"-ORBInitialPort", "1050", "-ORBInitialHost", "localhost"};

  @Test
  public void test() throws InvalidName, CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName, NotFound {
    ORB orb = ORB.init(ORB_OPTIONS, null);

    org.omg.CORBA.Object objRef =
      orb.resolve_initial_references("NameService");
    NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

    Greeting greeting = GreetingHelper.narrow(ncRef.resolve_str("Greeting"));

    System.out.println("Obtained a handle on server object: " + greeting);

    String returnMessage = greeting.hello("I'm Kazuki!");

    Assert.assertThat(returnMessage, Is.is("Hello !! (I'm Kazuki!)"));

  }

}

Note:

クライアントで必要になるクラス・インタフェースは・・・

  • Greeting
  • GreetingOperations
  • _GreetingStub
  • GreetingHelper

の4つです。

Springの機能を使ってCORBAサービスを呼び出してみる

Spring Frameworkから提供されているJndiRmiProxyFactoryBeanを使うと、CORBAサービスのインターフェースを実装したBeanをDIコンテナ登録することができます。(=アプリケーションコードの中でCORBAを意識する必要はありません!!)

package com.example.democorba;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.remoting.rmi.JndiRmiProxyFactoryBean;

import javax.naming.Context;
import java.util.Properties;

@SpringBootApplication
public class DemoCorbaApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoCorbaApplication.class, args);
  }

  @Bean
  CommandLineRunner demo(Greeting greeting) {
    return args -> System.out.println(greeting.hello("Hi Shimizu."));
  }

  @Bean
  JndiRmiProxyFactoryBean greeting() {
    JndiRmiProxyFactoryBean factoryBean = new JndiRmiProxyFactoryBean();
    Properties properties = new Properties();
    properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory");
    properties.setProperty(Context.PROVIDER_URL, "iiop://localhost:1050");
    factoryBean.setJndiEnvironment(properties);
    factoryBean.setJndiName("Greeting");
    factoryBean.setServiceInterface(Greeting.class);
    return factoryBean;
  }

}

このクラスを実行すると・・・

コンソール
...

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.6.RELEASE)

2017-08-11 15:33:52.199  INFO 12777 --- [           main] c.e.democorba.DemoCorbaApplicationTests  : Starting DemoCorbaApplicationTests on Kazuki-no-MacBook-Pro.local with PID 12777 (started by shimizukazuki in /usr/local/apps/demo-corba)
2017-08-11 15:33:52.202  INFO 12777 --- [           main] c.e.democorba.DemoCorbaApplicationTests  : No active profile set, falling back to default profiles: default
2017-08-11 15:33:52.241  INFO 12777 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@3eb738bb: startup date [Fri Aug 11 15:33:52 JST 2017]; root of context hierarchy
Hello !! (Hi Shimizu.)
2017-08-11 15:33:52.906  INFO 12777 --- [           main] c.e.democorba.DemoCorbaApplicationTests  : Started DemoCorbaApplicationTests in 1.436 seconds (JVM running for 2.242)
2017-08-11 15:33:52.952  INFO 12777 --- [       Thread-3] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3eb738bb: startup date [Fri Aug 11 15:33:52 JST 2017]; root of context hierarchy

となります。

Note:

クライアントで必要になるクラス・インタフェースは・・・

  • Greeting
  • GreetingOperations
  • _GreetingStub

の3つです。(=GreetingHelperは不要です)

ちなみに・・・テストを書くなら以下のような感じになります。

package com.example.democorba;

import org.hamcrest.CoreMatchers;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoCorbaApplicationTests {

  @ClassRule
  public static OutputCapture outputCapture = new OutputCapture();

  @Test
  public void contextLoads() {
    outputCapture.expect(CoreMatchers.containsString("Hello !! (Hi Shimizu.)"));
  }

}

まとめ

とりあえずサービス呼び出すだけなら楽勝?っぽいけど、こんなんでいいのかな〜?

参考サイト