Concurrency Update (jsr166e)のご紹介

この記事はJava Advent Calendar 2012 の 18 日目の記事です。
昨日は @torutk さんによる「Javaで地図表示ーGeoToolsを使って」でした。
明日は @Akira Koyasu さんです。


Duke からのSeason’s Greetings! ビデオ



Java に関して何を記載しようかと悩んでいたのですが、やはり Java SE 8 のネタが良いかと思い、Java SE 8 に含まれる予定の「Concurrency Update (jsr166e)」について、かんたんにご紹介したいと思います。

Java SE 8 に含まれる予定の機能一覧は下記に記載されております。
JEP (JDK Enhancement-Proposal)

上記をご覧頂くと様々な機能拡張が施される事をご確認頂けますが、並行処理についても下記の JEP として更新される予定のようですので、少しだけご紹介したいと思います。

JEP : 155 Concurrency Updates (jsr166e)

Java SE に含まれる並行処理用の API は Java SE 5 に JSR 166: Concurrency Utilities として、java.util.concurrent パッケージで提供されました。その後、Java SE 6, 7 でもこれらのライブラリはアップデートされ、直近では Java SE 7 で jsr-166y として Fork/Join フレームワークが追加された事は記憶に新しいかと思います。

さて、Java SE 8 では jsr-166 はさらに進化して jsr-166e として機能拡張が施されようとしています。ちなみに「jsr-166e」の「e」は「Eight」つまり「8」を意味しております。jsr-166e で提供される API の一覧は下記をご参照ください。

jsr-166e で追加される予定の API 一覧

JSR-166e の主な拡張ポイント:
● ConcurrentHashMap に対するキャッシュ指向の機能拡張
● スケーラブルで更新可能な変数
● ForkJoinPool に対する改良

これらを簡単にご紹介します。

「ConcurrentHashMap」について
ConcurrentHashMap は Java SE 5 に導入されて以降、様々な所で使われてきました。しかし ConcurrentHashMap は必要以上にメモリを消費するという問題もあり、Java SE 8 に導入予定の ConcurrentHashMap は少ないメモリで効率的に利用できるようです。またシーケンシャル処理も、並行処理もサポートし大量のコンテンツを扱う場合に有効に働きます。


ConcurrentHashMapV8 の API リファレンス

ConcurrentHashMapV8 のソースコード

「スケーラブルで更新可能な変数」
Adder(加算用の機能) について
Adder として追加される、DoubleAdder, LongAdder は Java SE 8 では java.util.concurrent.atomic パッケージ内に含まれる予定です。ここで追加される Adder (加算用の機能)はとても高性能な並行処理対応のプリミティブの加算用の機能を提供します。それぞれサンプルのコードが下記より入手できます。

DoubleAdder
LongAdder
LongAdderTable

ソースコードはコチラから 参照できます。

DoubleAdderDemo のサンプル
LongAdderDemo のサンプル

上記の、LongAdderDemo を私の環境で実行した所、複数のスレッドで AtomicLong で 10,000,000 まで加算していく場合と、LongAdder を使用して加算していく場合で下記の違いがありました。この結果を見てもわかる通り、並列で加算を行う場合、AtomicLong よりも、LongAdder を使用した方が高速に動作する事がお分かりいただけるかと思います。

Doug Lea によって書かれた LongAdder のコード:

/*
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

import java.util.concurrent.Phaser;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import jsr166e.LongAdder;

public class LongAdderDemo {
    static final int INCS_PER_THREAD = 10000000;
    static final int NCPU = Runtime.getRuntime().availableProcessors();
    static final ExecutorService pool = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        System.out.println("Warmup...");
        int half = NCPU > 1 ? NCPU / 2 : 1;
        casTest(half, 1000);
        adderTest(half, 1000);

        for (int reps = 0; reps < 2; ++reps) {
            System.out.println("Running...");
            for (int i = 1; i <= NCPU * 2; i <<= 1) {
                casTest(i, INCS_PER_THREAD);
                adderTest(i, INCS_PER_THREAD);
            }
        }
        pool.shutdown();
    }

    static void casTest(int nthreads, int incs) {
        System.out.print("AtomicLong ");
        Phaser phaser = new Phaser(nthreads + 1);
        AtomicLong a = new AtomicLong();
        for (int i = 0; i < nthreads; ++i)
            pool.execute(new CasTask(a, phaser, incs));
        report(nthreads, incs, timeTasks(phaser), a.get());
    }

    static void adderTest(int nthreads, int incs) {
        System.out.print("LongAdder  ");
        Phaser phaser = new Phaser(nthreads + 1);
        LongAdder a = new LongAdder();
        for (int i = 0; i < nthreads; ++i)
            pool.execute(new AdderTask(a, phaser, incs));
        report(nthreads, incs, timeTasks(phaser), a.sum());
    }

    static void report(int nthreads, int incs, long time, long sum) {
        long total = (long)nthreads * incs;
        if (sum != total)
            throw new Error(sum + " != " + total);
        double secs = (double)time / (1000L * 1000 * 1000);
        long rate = total * (1000L) / time;
        System.out.printf("threads:%3d  Time: %7.3fsec  Incs per microsec: %4d\n",
                          nthreads, secs, rate);
    }

    static long timeTasks(Phaser phaser) {
        phaser.arriveAndAwaitAdvance();
        long start = System.nanoTime();
        phaser.arriveAndAwaitAdvance();
        phaser.arriveAndAwaitAdvance();
        return System.nanoTime() - start;
    }

    static final class AdderTask implements Runnable {
        final LongAdder adder;
        final Phaser phaser;
        final int incs;
        volatile long result;
        AdderTask(LongAdder adder, Phaser phaser, int incs) {
            this.adder = adder;
            this.phaser = phaser;
            this.incs = incs;
        }

        public void run() {
            phaser.arriveAndAwaitAdvance();
            phaser.arriveAndAwaitAdvance();
            LongAdder a = adder;
            for (int i = 0; i < incs; ++i)
                a.increment();
            result = a.sum();
            phaser.arrive();
        }
    }

    static final class CasTask implements Runnable {
        final AtomicLong adder;
        final Phaser phaser;
        final int incs;
        volatile long result;
        CasTask(AtomicLong adder, Phaser phaser, int incs) {
            this.adder = adder;
            this.phaser = phaser;
            this.incs = incs;
        }

        public void run() {
            phaser.arriveAndAwaitAdvance();
            phaser.arriveAndAwaitAdvance();
            AtomicLong a = adder;
            for (int i = 0; i < incs; ++i)
                a.getAndIncrement();
            result = a.get();
            phaser.arrive();
        }
    }
}

MaxUpdater
また、Adder (加算器)と同様に、並行処理の中でハイ・パフォーマンスに最大値を取得する API も追加されます。

DoubleMaxUpdater
LongMaxUpdater

ForkJoinPool について
新機能の追加の他、パフォーマンスが大幅に改善されています。これによって、今まで扱う場所が限定されていた ForkJoinPool が、開発場面の色々な場面で利用できるようになるようです。

最後に、
Java SE 8 では ConcurrentHashMap 等の並行処理機能も拡張・追加されていますので、ご興味ある方は是非チェックしてみてください。

2012年12月18日 at 10:30 午後

Java EE 7 WebSocket Client Sample Application with JavaFX

この記事はJavaEE Advent Calendar 2012の14日目の記事です。
昨日は @noriand さんによる「Spring on Glassfish」でした。
明日は@kokuzawaさんです。

2013 年 5 月 13 日追記:本ソースコードは、WebSocket の仕様が完全に FIX する前に記載したコードのため、既に記載している内容のコードでは動かなくなっています。新しい API の詳細は、javax.websocketパッケージ、javax.websocket.serverをご参照ください。

さて、今年は何を書こうかととてもなやんでいた所、昨日の深夜12時過ぎに、
@skrb さんから、「@yoshioterada 寺田さん、JavaFX Advent Calednarに登録していないようですけど…. GlassFish と JavaFX を絡めて、両方のAdvent Calendar に登録するのでもいいですよww」

とおっしゃって頂き(敷居があがり (^_^;) )、以前のセミナーで説明した Java の WebSocket のクライアント側の実装をご紹介しようという事で書いてみます。

※ また、本プログラムは、Java EE 7 に含まれる予定の WebSocket API を利用している事から、現時点での実装方法のサンプルとなります。Java SEE 7 の正式リリース時には API 等が変更される可能性も多いにありますので、どうぞその点はご注意ください。

サーバ側の実装コードは、先日、WebSocket Twitter タイムライン・取得サンプルのエントリで記載しました。このエントリを記載した後にも既に GlassFish v4 の b66 では API が若干変わっていますので、あくまでの参考としてご参照ください。

今回は、このサーバ側の実装をそのまま利用して、クライアント側のプログラムを JavaFX (Java のアプリケーション)として動作させるというのが今回のブログの趣旨となります。
作成する JavaFX の WebSocket アプリの動作は下記のようなイメージです。この JavaFX アプリケーションは、ボタンを押下すると WebSocket のサーバに接続しサーバから送信されるメッセージを受信し TextArea 内に表示するという内容です。



アプリケーションの実行例

準備:
本プログラムを動作させるためには、下記のライブラリが必要になります。

* grizzly-framework-2.2.19.jar
* grizzly-http-2.2.19.jar
* grizzly-http-server-2.2.19.jar
* grizzly-websocket-2.2.19.jar
* tyrus-servlet-1.0-b08.jar
* javax.net.websocket-1.0-b08.jar

Grizzly 関連の jar ファイルはコチラから御入手ください。
※ Grizzly とは GlassFish のサーバ・エンジンを司る汎用サーバ・フレームワークで Grizzly のライブラリを利用する事で自身で低レベルのソケットプログラムを記載する事なく、ネットワーク通信のプログラムを記載する事が可能になります。今回クライアント側からサーバ側に対してネットワーク接続を行うために、この Grizzly のライブラリを内部的に利用します。

また、tyrus と javax.net.websocket の jar につきましては、https://maven.java.net/ からここで説明した内容と同様の方法でそれぞれのライブラリを検索して頂き、御入手ください。

それでは、NetBeans を使用して JavaFX のアプリケーションを作成しましょう。
まず、NetBeans から新規プロジェクトを作成します。

ここでは、プロジェクト名として「JavaFX-WebSocket」という名前で作成します。
次に、準備の所で入手した全ライブラリを本プロジェクトのライブラリ内に配置し利用できるようにします。

ここでは、”JavaFXWebSocket.java”、”Sample.fxml”、”SampleController.java”の3つのファイルが作成されていますので、これらを編集してプログラムを作っていきます。

まず、JavaFX SceneBuilder を使用してデザインを作成します。今回はとても簡単にするために、画面サイズを調整し、Label, TableView を貼付けます。また、TableView に対して ID として “table” を設定します。また、TableView 内の TableColumn に対して column
の ID を設定します。

できあがった、Sample.fxml は下記の通りです。

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="453.0" xmlns:fx="http://javafx.com/fxml" fx:controller="javafx.websocket.SampleController">
  <children>
    <Button fx:id="button" layoutX="326.0" layoutY="365.0" onAction="#handleButtonAction" text="Start TimeLine" />
    <Label fx:id="label" layoutX="126.0" layoutY="120.0" minHeight="16.0" minWidth="69.0" />
    <Label layoutX="14.0" layoutY="14.0" prefWidth="292.0" text="WebScoket Twitter TimeLine Client Smaple" underline="true" />
    <TableView fx:id="table" layoutX="14.0" layoutY="45.0" prefHeight="311.0" prefWidth="425.0">
      <columns>
        <TableColumn id="" maxWidth="445.0" prefWidth="445.0" text="メッセージ一覧" fx:id="column" />
      </columns>
    </TableView>
  </children>
</AnchorPane>

次にコードを実装していきます。まず、JavaFXWebSocket.java についてはデフォルトのまま一切編集を加えずにそのまま利用します。

package javafx.websocket;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class JavaFXWebSocket extends Application {
    
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("Sample.fxml"));
        
        Scene scene = new Scene(root);
        
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

次に、SampleController.java を編集します。@FXML TableView table は、Sample.fxml に追加した TableView と一対一で対応します。次に、ボタンが押下された際の処理を実装しますが、Button が押下された時の処理は別スレッドで実装します。別スレッドで実装しないと、処理が終了するまで処理が専有してしまうため他に一切処理ができなくなります。ボタンが押下された際の処理は、javafx.concurrent.Service を継承したクラスで実装します。(※ JavaFX では非同期処理を javafx.concurrent.Service, javafx.concurrent.Task 等を利用して実装します。)

package javafx.websocket;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javax.websocket.ClientEndpointConfiguration;
import javax.websocket.DefaultClientConfiguration;
import javax.websocket.DeploymentException;
import org.glassfish.tyrus.client.ClientManager;

public class SampleController implements Initializable {

    @FXML
    private TableView table;

    @FXML
    private TableColumn<RowData,String> column;
    
    @FXML
    private void handleButtonAction(ActionEvent event) {
        TwitterCheckService thread = new TwitterCheckService(table);
        thread.start();
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        table.setEditable(true);
        column.setResizable(true);
        column.setCellValueFactory(new PropertyValueFactory<RowData, String>("message"));
    }

    class TwitterCheckService extends Service {

        private TableView table;
        private CountDownLatch messageLatch = null;

        public TwitterCheckService(TableView table) {
            this.table = table;
        }

        @Override
        protected Task createTask() {
            Task<Void> task = new Task<Void>() {
                @Override
                protected Void call() throws Exception {
                    messageLatch = new CountDownLatch(1);
                    try {
                        URI clientURI = new URI("ws://localhost:8080/TwitterTimeLine/twitter");
//            ClientContainer cliContainer = ContainerProvider.getClientContainer();
                        ClientManager cliContainer = org.glassfish.tyrus.client.ClientManager.createClient();

                        ClientEndpointConfiguration clientConfig = new DefaultClientConfiguration();
                        cliContainer.connectToServer(new TwitterClient(table), clientURI);
                        messageLatch.await(1, TimeUnit.SECONDS);
                    } catch (DeploymentException | URISyntaxException | InterruptedException ex) {
                        Logger.getLogger(SampleController.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    return null;
                }
            };
            return task;
        }
    }
}

上記のクラスにおいて、初期化の initialize メソッド中に、column.setCellValueFactory(new PropertyValueFactory(“message”));
を記載しており、ここで Table の各行で表示する内容を設定しています。実際に各行で表示される内容は RowData の message に設定される内容を表示します。message は 単なる String 型ではなく、javafx.scene.text.Text 型としていますが、これは Table の各セルで文字列の改行が自動的になされないため、Text でラッピングし Text#setWrappingWidth で文字列の長さを調整しています。

package javafx.websocket;

import javafx.scene.text.Text;

public class RowData {

    private Text message;

    public RowData(Text message) {
        this.message = message;
        message.setWrappingWidth(400);
    }

    public Text getMessage() {
        return message;
    }

    public void setMessage(Text message) {
        this.message = message;
    }
}

また、SampleController クラスの中で、WebSocket のクライアント側の実装として重要な部分を下記に抜粋します。まず、コメントしている側のコードなのですが、本来 WebSocket のクライアントの実装として推奨されるのはコメントしてある側のコードです。ClientContainer を ContainerProvider.getClientContainer() から取得するというのが正しい実装で、実際に利用するクラスは、システム・プロパティに
“webocket.clientcontainer.classname=実際のクラス名” という記載を行う事でプロパティから読み込みます。しかし、今回エラーが発生してし取得する事ができなかったため、ClientContainer の実装(ClientManager)を直接、org.glassfish.tyrus.client.ClientManager.createClient() から取得しています。

            URI clientURI = new URI("ws://localhost:8080/TwitterTimeLine/twitter");
//            ClientContainer cliContainer = ContainerProvider.getClientContainer();
            ClientManager cliContainer = org.glassfish.tyrus.client.ClientManager.createClient();

            ClientEndpointConfiguration clientConfig = new DefaultClientConfiguration();
            cliContainer.connectToServer(new TwitterClient(table), clientURI);
            messageLatch.await(20, TimeUnit.SECONDS);

また、cliContainer.connectToServer(new TwitterClient(table), clientURI) で記載している TwitterClient(table) は、WebSocket のサーバ側の実装では @WebSocketEndpoint のアノテーションが付加されたクラスと同じ働きをするクライアント側の実装を行っているクラスと認識していただければと思います。下記に TwitterClient クラスの実装を記載します。

package javafx.websocket;

import javafx.collections.ObservableList;
import javafx.scene.control.TableView;
import javafx.scene.text.Text;
import javax.websocket.Session;
import javax.websocket.WebSocketClient;
import javax.websocket.WebSocketClose;
import javax.websocket.WebSocketMessage;
import javax.websocket.WebSocketOpen;

@WebSocketClient
public class TwitterClient {

    TableView table;
    ObservableList<RowData> list;

    public TwitterClient(TableView table) {
        this.table = table;
    }

    @WebSocketOpen
    public void onOpen(Session session) {
        System.out.println("Connection had opened.");
    }

    @WebSocketMessage
    public void onMessage(String message) {
        if (message.length() == 0) {
            return;
        }
        // Table 内で文字列を改行するために String を Text で Wrap
        Text text = new Text(message);

        list = table.getItems();
        list.add(0,new RowData(text));
    }

    @WebSocketClose
    public void closeConnection(Session session) {
        System.out.println("Connection had closed.");
    }
}

サーバ側で WebSocket のコードを実装する場合は、@WebSocketEndpoint アノテーションを付加していました、クライアント側はその代わりに、@WebSocketClient アノテーションを付加したクラスを実装します。実際に記載する内容は、@WebSocketEndpoint の内容と同等で、@WebSocketOpen, @WebSocketMessage, @WebSocketClose のアノテーションを付加したメソッドをそれぞれ実装します。このプログラムでは、サーバ側からメッセージが配信されてき、サーバ側に対してメッセージを送信する必要はありませんので、実際に
は @WebSocketMessage を付加した public void onMessage(String message) メソッドの部分が重要になります。ここでは、サーバ側からメッセージが配信された場合、受信 した文字列を Text text = new Text(message) でラッピングし、現在 Table に設定されている Item を抜き出した後、Table の先頭行に RowData を追加しています。

この程度のプログラムであれば、特に難しい事を考えなくても簡単に、クライアント側の WebSocket プログラムを作成する事ができるかと思います。

最後に、
今年は Java EE の単独で Advent Calendar が作成された事に対してとても嬉しく思うと共に、作成してくださった、@megascus さん本当にありがとうございました。
Java EE 7 は、来年の春頃にリリースされますが、WebSocket の他にもとても便利になった API などが多数提供される予定です。いち早く、Java EE 7 の各機能を試してみたい方は GlassFish v4 の開発ビルドをダウンロードしていただく事で試していただく事もできます。是非今から Java EE 7 にお備えください。

Technology JSR Spec Lead Links JavaOne 2012で発表
Java EE 7 Platform 342 Linda DeMichiel,
Bill Shannon
http://javaee-spec.java.net/
Java Persistence 2.1 338 Linda DeMichiel http://jpa-spec.java.net/ Java Persistence 2.1: What’s New
JAX-RS 2.0 339 Marek Potociar, Santiago Pericas-Geertsen http://jax-rs-spec.java.net/ JAX-RS 2.0: New and Noteworthy in the RESTful Web Services API
Servlet 3.1 340 Rajiv Mordani, Shing Wai Chan http://servlet-spec.java.net What’s New in Servlet 3.1: An Overview
JSF 2.2 344 Ed Burns http://jsf-spec.java.net/ What’s New in JSF: A Complete Tour of JSF 2.2
JMS 2.0 343 Nigel Deakin http://jms-spec.java.net What’s New in Java Message Service 2.0
EL 3.0 341 Kin-Man Chung http://el-spec.java.net JSR 341: Expression Language 3.0
EJB 3.2 345 Marina Vatkina http://java.net/projects/ejb-spec/ Enterprise JavaBeans Today and Tomorrow
JSON API 1.0 353 Jitendra Kotamraju http://json-processing-spec.java.net JSR 353: Java API for JSON Processing
Concurrency Utilities for Java EE 1.0 236 Anthony Lai http://concurrency-ee-spec.java.net
CDI 1.1 346 Pete Muir (RedHat), Sivakumar Thyagarajan (Oracle) JSR-346 Public Review The Contexts and Dependency Injection API: Next Steps for the Platform and Future Directions
Bean Validation 1.1 349 Emmanuel Bernard (RedHat), Jagadish Ramu (Oracle), Ed Burns(Oracle) beanvalidation.org
github repository
英語のビデオ
Web Sockets API 1.0 356 Danny Coward (Oracle) http://java.net/projects/websocket-spec 参照実装プロジェクト(tyrus) HTML5 WebSocket and Java
JCache 107 Brian Oliver (Oracle), Greg Luck (Terracotta) project page , javadocs
Batch Processing 1.0 352 Chris Vignola (IBM), Mahesh Kannan (Oracle) Java Batch for Cost-Optimized Business Efficiency

2012年12月14日 at 7:52 午後 3件のコメント

Java Developer News Letter の第2号配信


皆様、
Java Developer Newsletter
というメール・マガジンが存在している事はご存知でしょうか?Java Developer Newsletter では、オラクルより Java に関する情報をお届けする、メールマガジンで、エンタープライズ Java から組み込み Java まで幅広いジャンルの情報をお届けする内容となっています。

以前、Sun の頃に SDC 会員として Java に関する情報を入手されていらっしゃった方は、是非改めて上記のメール・マガジンにご登録頂き Java に関する情報を是非入手してください。今日は、Java Developer News が出来て2度目の配信となるようです。 ご存知なかった方も是非この機会にご入会ください。

2012年11月20日 at 2:14 午後 1件のコメント

Java SE 7 へのアップグレードのお願い

昨年、Java SE 7 が正式にリリースされました。また Java SE 6 の製品終了(End Of Life)が来年 2013 年 2 月に控えている旨、各種セミナーでご案内をさせて頂いております。Java SE 6 の EoL を迎える前に是非、Java SE 7 の環境へご移行ください。

Java の EOL ポリシーにつきましては、公式にドキュメントが記載されております。英語サイト、日本語サイトを下記に示しますのでどうぞ内容をご参照ください。

http://www.oracle.com/technetwork/java/eol-135779.html (英語版)
http://www.oracle.com/technetwork/jp/java/eol-135779-ja.html (日本語版)

本記述内容はオラクル製 Java VM を利用している場合について記載しておりますが、Java SE の EOL はオラクルの Java VM 製品のサポート期間の終了日を表してまして、この EoL の日程の後は、仮にセキュリティ脆弱性を含む Java VM に起因した不具合が発生した場合、もしくは仮に新しい HW、OS のバージョンが各社よりリリースされた場合も一切更新版は提供されません。

そこで、大変恐れ入りますが、Java SE 7 へのアップデートを是非行っていただけますよう宜しくお願いします。仮に、上記 EOL の期間になった後も、過去の Java VM に対する不具合(セキュリティ脆弱性対応、バグ修正)対応を入手したい場合は、別途オラクルとサポート契約を締結していただく事でその期間を延長する事が可能ですので、日本オラクルへお問い合わせください。

また、 2012/11/01 に「Java 6のJava 7への自動アップデート」の内容が OTN サイトで公開されています。こちらの記載内容も十分ご確認ください。

Java 6のJava 7への自動アップデート

特に Windows 環境で JRE の i586 版をご利用の場合、インストール済の JRE 6 が JRE 7 に置き換わる (JRE 6 は削除される) 可能性について FAQ 内に言及されておりますので、i586 版で Java Application, Applet, JavaWeb Start 等のサービスを提供している方はご注意ください。

対象の JRE (Windows 32 bit 版のみ)
Windows x86 Kernel 0.87 MB jre-6uXX-windows-i586-iftw-k.exe
Windows x86 Online 0.87 MB jre-6uXX-windows-i586-iftw.exe
Windows x86 Offline 16.19 MB jre-6uXX-windows-i586.exe

FAQ :
Java 6からJava 7への自動アップデートの実行後にシステムに入っているのは、どのバージョンのJavaですか。

Answer :
Javaの自動アップデート・プロセスにより、ユーザーのWindowsマシンのJavaは最新バージョンにアップデートされます。JRE 6からJRE 7への自動アップデート中、ユーザーが所有するJava 6のバージョンが1種類ならば、自動アップデート・プロセスでJRE 6はJRE 7の最新バージョンに置き換えられ、JRE 7だけがシステムに残ります。

FAQ :
JRE 6をシステムで有効にするためにはJRE 7を削除する必要がありますか。または、両方を残すことができますか。

Answer :
それぞれの場合によって異なります。デフォルトでは、WebブラウザやWeb Startを介してアクセスするJavaアプリケーションは、システム上の最新バージョンのJavaを使用します。必要とするJavaのバージョンをアプ リケーションで指定することは可能です。アプリケーションがどのバージョンを使用するのか、実行しているシステムによって判定される場合、JRE 6とJRE 7を所有しているときにはJRE 7だけが使用されます。アプリケーションでJRE 6の使用を指定してある場合、JRE 6とJRE 7の両方を所有していてもJRE 6が使用されます。

上記 1 番目の FAQ、JRE 6 の置き換えは Windows 環境で i586 版をご利用頂いている利用者の方々が対象となります(Windows x64 版には影響はありません)。

最後に、Java SE 6 以前のバージョンでサービスを提供されていらっしゃる場合、来年の 2 月以降アップデートは提供されませんので(オラクルとの Java SE に関するサポート契約締結を除いた場合)、この機会に是非、既存アプリケーションを Java SE 7 で動作確認・検証を行って頂き、Java SE 7 へのご移行をご検討ください。

ご参考:
i586 版の JRE のコントロールパネルとインストール場所の例

64 bit 版の JRE のコントロールパネルとインストール場所の例


2012年11月14日 at 4:04 午後 1件のコメント

Java EE 6 に関する概要紹介セミナー開催のお知らせ

この度、富士通ラーニングメディア様 主催の無料セミナーで、Java EE 6 の技術概要を紹介をする事になりました (会場は日本オラクル 13 F)。

本セミナーは、今まで私の Java EE 6 関連セミナーにお越し頂いた方には重複内容になりますのでご登録頂かなくても良いかと思われます。
本セミナーは、これから Java EE 6 の採用をご検討頂いている皆様、Java EE 6 ではどのような事ができるのか等、概要を理解したい開発者、もしくは意思決定者、育成担当者、新人教育のコンテンツ選定者の皆様に是非ご参加頂ければ幸いです。

今まで私のセミナーにご参加頂いた皆様におかれましては、是非、同僚、上司にご紹介頂ければ幸いです。

最後に、富士通ラーニングメディア様では新たにJava EE 6 に関するトレーニング・コース も新設されます。
直近の開催日程は:2012/12/21、2013/01/23、2013/02/19 で、それぞれ1日コースとなっております。今企業で採用をご検討頂いている皆様は是非、これらのセミナーの御受講もご検討ください。

2012年11月13日 at 12:27 午後

WebSocket Twitter タイムライン・取得サンプル

WebSocket と Twitter4J を使った、Twitter のタイムライン取得 WebSocket サンプルアプリケーションのサンプルコードを公開致します。

2013 年 5 月 13 日追記:本ソースコードは、WebSocket の仕様が完全に FIX する前に記載したコードのため、既に記載している内容のコードでは動かなくなっています。新しい WebSocket の API では @WebSocketEndpoint アノテーションの代わりに @ServerEndpoint アノテーション等を使用します。 詳しくは、javax.websocketパッケージ、javax.websocket.serverをご参照ください。

Java EE 7 の WebSocket の概要は下記をご参照ください。

下記は、2012 年 11 月現在、 JSR-356 の Java API for WebSocket の標準仕様で開発・検討中の API 、また Twitter4J 2.2.6 を利用し実装したサンプルコードです。正式リリース時には下記で記載した内容(アノテーションや引数等)が変更される可能性もありますので、ご注意ください。

本、プログラムは現在開発中の GlassFish の開発ビルド GlassFish v4 b58 で動作しています (既に最新の b61では @WebSocketEndpoint のコンテキスト・ルートの設定方法が変更されています。ただし b61 は少し挙動が不安定なため b58 でデモを実施しています)。

WebSocket はクライアントとサーバ間で双方向・全二重が可能な HTTP のアップグレード・プロトコルを使用して通信を行います。

一度、WebSocket の接続が確立した後は、下記それぞれのライフサイクルに応じた処理をアノテーションを付加してかんたんに実装する事ができます。

  • 接続確立時
  • メッセージ受信時
  • エラー発生時
  • 接続切断時

下記に、今回の Twitter のタイムラインを取得するサンプルのコードを記載します。@WebSocketEndpoint アノテーションをクラスに付加し、引数に接続する URL のコンテキスト・ルートを指定します。これにより、この例では、ws://WEBSOCKET-SERVER/APP_NAME/twitter でアクセスされたリクエストに対して処理を行います。
@WebSocketOpen, @WebSocketClose のアノテーションが付加されたメソッドではそれぞれ下記の処理を行います。

  • @WebSocketOpen:クライアントが接続をしてきた際に、リモート・エンドポイント(クライアント)の情報(Session)を配列に挿入
  • @WebSocketClose:クライアントが切断された際に、配列からリモート・エンドポイント(クライアント)の情報(Session)を削除
package jp.co.oracle;


import javax.net.websocket.Session;
import javax.net.websocket.annotations.WebSocketClose;
import javax.net.websocket.annotations.WebSocketEndpoint;
import javax.net.websocket.annotations.WebSocketOpen;

@WebSocketEndpoint(path = "/twitter")
public class TwitterWebSocket {

    @WebSocketOpen
    public void initOpen(Session session) {
        System.out.println("client had accessed" + session.getRemote().toString());
        TwitterClientSingleton.peers.add(session);
    }

    @WebSocketClose
    public void closeWebSocket(Session session) {
        System.out.println("client had cut the connect" + session.getRemote().toString());
        TwitterClientSingleton.peers.remove(session);
    }
}

次に、Twitter のメッセージを受信した際に、接続されている全てのクライアントに対してメッセージを配信するコードを下記に示します。下記は、Twitter4J の Streaming API を使用し、またシングルトン EJB として実装しています。本クラスはアプリケーションの起動時にアプリケーション・サーバが自動的に初期化するように @Startup のアノテーションを付加しています。また、シングルトン EJB が EJB コンテナによって初期化された後に @PostConstruct を付加したメソッド initTwitterStream() が呼び出されます。この initTwitterStream() メソッド中では Twitter4J の Stream API を利用して、Twitter の Stream をオープンしています。(ここでは簡単の為、検索キーワードとして “java” を静的に埋め込んでいます)

また、Twitter4J では StatusAdapter#onStatus() のメソッドで、フィルターにマッチしたメッセージを受信する事ができますので、そのメソッド内で全接続クライアントに対してシーケンシャルでメッセージを配信しています(もちろん JSON 形式などに変換して配信する事も可能ですが、簡単のため単純な文字列で送信しています)。

(※ 仮に、サーバ側で(チャット等のように)クライアント側から何らかのメッセージを受け取りたい場合は、@WebSocketMessage を付加したメソッドを実装していただく事でクライアントから情報を受信する事もできます。)

package jp.co.oracle;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.net.websocket.Session;
import twitter4j.FilterQuery;
import twitter4j.Status;
import twitter4j.StatusAdapter;
import twitter4j.TwitterStream;
import twitter4j.TwitterStreamFactory;
import twitter4j.User;

@Startup
@Singleton
public class TwitterClientSingleton extends StatusAdapter {

    private static TwitterStream twStream = null;
    public static Set<Session> peers = null;

    static {
        peers = Collections.synchronizedSet(new HashSet());
    }

    @PostConstruct
    public void initTwitterStream() {
        //Twitter Stream の初期化
        twStream = TwitterStreamFactory.getSingleton();
        FilterQuery filter = new FilterQuery();
        filter.track(new String[]{"#dev459"});
        twStream.addListener(this);
        twStream.filter(filter);
    }

    @Override
    public void onStatus(Status status) {
        //Twitter のフィルターに引っかかった場合
        User user = status.getUser();
//        if (status.getUser().getLang().equals("ja")) {
            String resStr = "@" + user.getScreenName() + " : " + status.getText();
                    System.out.println(resStr);
            try {
                for (Session peer : peers) {
                    peer.getRemote().sendString(resStr);
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
//        }
    }
}

最後に、View の部分を下記に記載します。View の部分は、今回の場合はとても簡単なサンプルですので、単なる HTML でも JSF でも、何で実装しても問題ないかと思います。下記の例では私は JSF を使って(XHTML として)実装しています。この例では、サーバからメッセージを受信した際に、onMessage () が呼び出され、結果としてテーブルの先頭行に着信メッセージを追加していっています。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>Twitter TimeLine Sample</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>Twitter TimeLine Sample</title>
        <style type="text/css">
            table,td,th { 
                width: 700px;
                border-collapse: collapse; 
                border: 1px black solid; 
            }
        </style>

        <script language="javascript" type="text/javascript">
            var wsUri = "ws://localhost:8080/TwitterTimeLine/twitter";
            var websocket = new WebSocket(wsUri);
            websocket.onopen = function(evt) { onOpen(evt) };
            websocket.onmessage = function(evt) { onMessage(evt) };
            websocket.onerror = function(evt) { onError(evt) };

            var  numberOfMessage;

            function init() {
                numberOfMessage = 0;
            }
            function onOpen(evt) {
                ;
            }

            function onMessage(evt) {                                        
                writeToScreen(evt.data);                    
                numberOfMessage++;
            }

            function onError(evt) {
                writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
            }
            

            function writeToScreen(messages) {
                var table = document.getElementById("TBL"); 
                var row = table.insertRow(0);  
                var cell1 = row.insertCell(0); 
                
                var textNode = document.createTextNode(messages);

                var z = numberOfMessage%2;
                if(z==1){
                    cell1.style.backgroundColor="#ADD8E6" ;
                }
                cell1.appendChild(textNode);
            }

            window.addEventListener("load", init, false);
        </script>
    </h:head>
    <h:body>
        <h2>Twitter タイムライン<BR/>WebSocket サンプル・アプリケーション!!</h2>
        <TABLE BORDER="1" ID="TBL">            
        </TABLE>
    </h:body>
</html>

このサンプルを実行するためには、事前に Twitter のコンシュマー・キーや、アクセス・トークン等を事前に入手しておく必要があります。Twitter より入手した情報をWEB-INF/classes ディレクトリ配下に twitter4j.properties ファイルを作成し、下記のように記載してください。


# To change this template, choose Tools | Templates
# and open the template in the editor.
debug=false
oauth.consumerKey=*********************
oauth.consumerSecret=****************************************
oauth.accessToken=********-****************************************
oauth.accessTokenSecret=******

また、本プログラムを実行するためには、下記のライブラリが必要です。

  • Twitter4J コアライブラリ: twitter4j-core-2.2.6.jar
  • Twitter4J Streaming ライブラリ: twitter4j-stream-2.2.6.jar
  • WebSocket : tyrus-servlet.jar (GlassFish-INSTALL/glassfish/modules 配下に存在)
  • EJB : (GlassFish-INSTALL/glassfish/modules 配下に存在)
  • CDI : (GlassFish-INSTALL/glassfish/modules 配下に存在)

念のため、NetBeans プロジェクトのディレクトリ構成も公開します。

最後に、
上記のサンプルコードをご参照頂き、シングルトン EJB と WebSocket を利用する事でとても簡単にそして効率的に、バックエンド・リソース(応用として:DBのカラム変更チェック等)のモニタリング・アプリケーションが作成できる事がお分かりいただけるかと思います。

実行例:

今までは同じ情報を参照(例えば DB カラム)するために、参照したいクライアントの数だけ、HTTP リクエストを送信し、SQL のクエリを実行していましたが、WebSocket を利用すると1つのモニタリングアプリをサーバ側に作成する事で、効率良く、そして最小のデータサイズでリアルタイムに情報を送受信できるようになります。

WebSocket は Java EE 7 で新規追加される技術の中でも特に注目すべき技術です。
WebSocket にご興味のある方は是非、開発中の GlassFish v4 と NetBeans を使って試してみてください。

2012年11月12日 at 6:58 午後 3件のコメント

JavaOne 報告会 & JJUG CCC

11 月 9 日の JavaOne 報告会と 11 月 10 日の JJUG CCC と2日続けて、Java に関するセミナーを開催致しました。JavaOne 報告会では Java EE 7 に関連するシンプル化された技術(JSON, Batch, JMS 2.0, EL 3.0)情報をお届けし、JJUG CCC では、今の Java のトレンドと、Java EE プラットフォームにおける HTML 5 対応と題し、JSF 2.2, WebSocket そして研究開発中のプロジェクトである、Project Avatar についてご紹介致しました。
下記にそれぞれで発表した内容を公開致しましたので、どうぞご参照ください。

(※ ファイルアップ時にフォント情報が壊れてしまっており、私がプレゼン時に使用したフォントと異なる点につきまして、どうかご了承ください。)

11 月 9 日 JavaOne 報告会でご紹介した内容(JSON, Batch, JMS 2.0 , EL 3.0):

11 月 10 日 JJUG CCC でご紹介した内容 (Java のトレンド)

11 月 10 日 JJUG CCC でご紹介した内容 (HTML 5 : JSF 2.2, WebSocket, Avatar)

2012年11月12日 at 1:40 午後

GlassFIsh v3.1.2.2でJSF 2.2を試す方法

現在、GlassFish の最新バージョンは Java EE 6 に準拠した GlassFish v3.1.2.2 です (2012 年 10 月 20 日時点)。

来年の春頃に Java EE 7 が正式にリリースされますが、Java EE 7 に含まれる JSF 2.2 の新機能をいち早く試したい方は GlassFish v3.1.2.2 の環境に対して、下記の手順に従っていただく事で環境を構築する事ができます。

※ ただし、ここでご紹介する内容はあくまでも Java EE 7 の正式リリース前に、事前検証を目的としてのみご使用ください。本番環境への適用は決してなさらないでください。

1. まず始めに、下記のサイトにアクセスしてください。
https://maven.java.net/

2. サイトにアクセスすると下記の画面が表示されます。
 検索フィールドに下記の文字列を入力して検索を実行してください。
 org.glassfish:javax.faces:2.2.0-SNAPSHOT


3. 検索を実行すると下記の結果が得られます。
 ここで、javax.faces-2.2.0-SNAPSHOT.jarを選択し、下右画面のタブよりArtifact Information を選択します。

4. タブを選択すると下記の画面が表示されます。
 ここで、Download ボタンを押下してください。


5. ボタンを押下すると JSF 2.2 の SNAPSHOT が入手できます。

 ダウンロードファイル:javax.faces-2.2.0-20121018.092111-181.jar

6. ダウンロードが完了すると、GlassFish v3.1.2.2 に含まれる JSF 2.1 を JSF 2.2 に置き換えます。

# pwd (GlassFish のモジュールの配置場所)
$GF_INSTALL/glassfish-3.1.2.2/glassfish/modules ($GF_INSTALL はインストールした場所)
# mv javax.faces.jar .. (JSF 2.1 のバックアップ)
# mv ~/Downloads/javax.faces-2.2.0-20121018.092111-181.jar ./javax.faces.jar (JSF 2.2 に置き換え)

7. GlassFish を再起動してください。
 起動時の server.log ログを確認すると正しく更新されている場合、下記のようにMojarra 2.2.0 (-SNAPSHOT 20121018-0139)という文字列が表示されているかと思います。
情報: Grizzly Framework 1.9.50 started in: 1ms – bound to [0.0.0.0:8181]
情報: Initiating Jersey application, version ‘Jersey: 1.11.1 03/31/2012 06:49 PM’
情報: REST00001: Listening to REST requests at context: /management/domain
情報: The Admin Console is already installed, but not yet loaded.
情報: The Admin Console is starting. Please wait.
情報: JMX005: JMXStartupService had Started JMXConnector on JMXService URL service:jmx:rmi://192.168.11.5:8686/jndi/rmi://192.168.11.5:8686/jmxrmi
情報: ?????? ” ? Mojarra 2.2.0 (-SNAPSHOT 20121018-0139) ???????

8. 実際に JSF 2.2 のコードが動くか確認してみましょう。
Maven プロジェクトの場合、pom.xml に下記の2項目を追加してください。

    <repositories>
        <repository>   
            <id>jvnet-nexus-snapshots</id>   
            <name>jvnet-nexus-snapshots</name>   
            <url>https://maven.java.net/content/repositories/snapshots/</url> 
        </repository>
    </repositories>
    <dependencies>
  ............
        <dependency>   
            <groupId>org.glassfish</groupId>   
            <artifactId>javax.faces</artifactId>   
            <version>2.2.0-SNAPSHOT</version>   
            <scope>provided</scope> 
        </dependency> 
    </dependencies>

9. CDI を利用する場合、WEB-INF 配下に bean.xml ファイルを作成します。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

10. JSF 2.2 対応のページを作成 (ファイルアップロード用のタグ:<h:inputFile>)

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        <h:form prependId="false" enctype="multipart/form-data">
            <h:inputFile id="fileUpload" value="#{test.upfile}"/>
            <h:commandButton value="upload" action="#{test.doUpload}"/>
        </h:form>
    </h:body>
</html>

11. CDI のバッキング Bean の作成

import java.io.IOException;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.servlet.http.Part;

@Named(value = "test")
@RequestScoped
public class TestManagedBean {

    private Part upfile;

    public Part getUpfile() {
        return upfile;
    }

    public void setUpfile(Part upfile) {
        this.upfile = upfile;
    }

    public TestManagedBean() {
    }

    public String doUpload() {
        try {
            String fileName = getFilename(upfile);
            upfile.write(fileName);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return "";
    }

    private String getFilename(Part part) {
        for (String cd : part.getHeader("Content-Disposition").split(";")) {
            if (cd.trim().startsWith("filename")) {
                return cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
            }
        }
        return null;
    }
}

アプリケーションを実行すると、指定したファイルがサーバ側で保存されている事を確認できます。

これで、JSF 2.2 の検証環境ができましたので、JSF 2.2 の新機能を試したい方は上記の方法に従って検証してみてください。まだ開発が進行中の物ですので、機能不足や信頼性に掛けますが、実際にコードを書きながら試す事ができるようになるため有用かと思います。

2012年10月20日 at 2:24 午前

Welcome to JavaOne 2012 by Japanese

今年の JavaOne 2012 San Francisco の基調講演で流されたビデオの日本語翻訳のキャプション付きを公開致します。

英語の歌詞はこちら
****************************************************************
Interweb our thoughts together
with a language that’s better than ever
we connect like 321
everyone is having fun
playing games
chat all day
calculate your future dates
viewing things in 3 dimensions
is their something I didn’t mention?
(auto tune) this software speaks to us all!!!
you’re coding with you’re coding with you’re coding with java
sip of coffee, keep you up
this syntax will not trip you up,
java!
Matching up with everyone
compatible like moon and sun
get your dose of vitamin
C + + + +
plug it in and see it swirl
everyone around the world
communicating, executing,
beautifying, multiplying,
(auto tune) this software speaks to us all!!!
you’re coding with you’re coding with you’re coding with java
sip of coffee, keep you up
this syntax will not trip you up,
java!
****************************************************************

関西弁バージョンも作ってみました。

Special Thanks to Reiko Saito-san.

2012年10月17日 at 6:07 午後

年末までの Java 関連イベントについて

年末までに私が参加予定の Java 関連イベントにつきまして下記にご案内致します。

特に各地方(東京も含む)で開催する JavaOne 報告会では、ラッキーな方に本場アメリカから持ち帰ってきたお土産を差し上げるイベント等も企画しております。是非この機会に最新の Java の動向を入手してください。

東京では、11/09, 11/10 に連日で Java に関する大きなイベントを開催する予定です。11/09 と 11/10 はそれぞれ別の内容が提供されますので、ご都合のつく方は是非両日ともご参加ください。

10/31 Oracle Days Tokyo 2012 (ウェスティンホテル東京)
11/3 JavaOne 報告会@岡山 (岡山県立図書館)
11/9 JavaOne 報告会@東京(グリー)
11/10 JJUG CCC@東京(ベルサール三田)
11/21 JavaOne 報告会@名古屋 (オラクル中部支社)
11/17 JavaOne 報告会@札幌
11/24 JavaOne 報告会@沖縄 (琉球大学)
11/29 JJUG ナイトセミナー@東京 (日本オラクル)
12/01 JavaOne 報告会@大阪
12/07 JavaOne 報告会@福岡 (オラクル福岡支社)
12/08 オープンソースカンファレンス福岡
12/13 GlassFish 勉強会&忘年会@東京
01/26 JavaOne 報告会@富山

2012年10月16日 at 11:12 午後

Older Posts Newer Posts


Java Champion & Evangelist

Translate

ご注意

このエントリは個人の見解であり、所属する会社の公式見解ではありません

カレンダー

2026年2月
 1
2345678
9101112131415
16171819202122
232425262728  

カテゴリー

clustermap

ブログ統計情報

  • 1,314,015 hits

Feeds

アーカイブ