きしだのはてな このページをアンテナに追加 RSSフィード

2018-05-07(月) Javaのライセンスの現状をまとめた

Javaのライセンスの現状をまとめた 01:35  Javaのライセンスの現状をまとめたを含むブックマーク

なんか、「Javaが有償化された」「無償サポートがなくなった」「Oracleと契約するかJavaをやめるか」のような話がちらほら流れるようになってきて、事実とは異なってたり誤解があったり状況が妥当に伝わってない気がするなと思ったので、現状についてまとめてみた。

ちょっと話をする機会があったのと、現実問題としてちゃんと自分でも把握しておく必要もあったので。

もし他にもサポート提供する企業があるとか、そうは言っても現実的にはこうなんじゃね?みたいな話があればツッコミおねがいします。

Javaのサポートについてのまとめ - Qiita

2018-05-03(木) JShellを使ってJava2Dであそぶ

[]JShellを使ってJava2Dであそぶ 05:03 JShellを使ってJava2Dであそぶを含むブックマーク

JShellを使ってJava2Dであそんでみました。楽しい。


Javaが初めての人はこちらもどうぞ。

JShellで始めるJava - Javaの世界を覗いてみる - Qiita


ということで、まずjavax.swing.*をimport

jshell> import javax.swing.*

JFrameを用意

jshell> var f=new JFrame("guruguru")
f ==> javax.swing.JFrame[frame0,0,0,0x0,invalid,hidden, ... tPaneCheckingEnabled=true]

そして、画像を表示するためのJLabelを用意

jshell> var label=new JLabel()
label ==> javax.swing.JLabel[,0,0,0x0,invalid,alignmentX=0. ... rticalTextPosition=CENTER]

画像としてBufferedImageを用意してますが、BufferedImageまで入力して[Shift]+[Tab]からの[i]を押すとimportのおすすめが出るので[1]を押してimportします。

jshell> var image=new BufferedImage
0: 何もしない
1: import: java.awt.image.BufferedImage
選択:
Imported: java.awt.image.BufferedImage


で、こんな感じでBufferedImageを用意

jshell> var image=new BufferedImage(400,300,BufferedImage.TYPE_INT_RGB)
image ==> BufferedImage@5ccddd20: type = 1 DirectColorModel ... 0 yOff = 0 dataOffset[0] 0

画像はImageIconを介してIconとしてJLabelに追加します。

jshell> label.setIcon(new ImageIcon(image))

labelをJFrameに追加したら、show()で表示

jshell> f.add(label)
$7 ==> javax.swing.JLabel[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.0,bo...sition=CENTER]

jshell> f.show()

録画領域からはみでていたので移動

jshell> f.setLocation(20,40)

packすると画面サイズが調整されます。

jshell> f.pack()

描画を行うためにGraphics2Dを取得

jshell> var g=image.createGraphics()
g ==> sun.java2d.SunGraphics2D[font=java.awt.Font[famil ... .Color[r=255,g=255,b=255]]

描画色を設定するのだけど、Colorはjava.awt.Colorなので、また[Shift]+[Tab]して[i]を押してimportを補完

jshell> g.setColor(Color
0: 何もしない
1: import: java.awt.Color
選択:
Imported: java.awt.Color

ここでは赤に設定します。

jshell> g.setColor(Color.RED)

線を引いてみる

jshell> g.drawLine(20,20,300,200)

labelをrepaintすると表示されます

jshell> label.repaint()

青で四角を描く

jshell> g.setColor(Color.BLUE)

jshell> g.fillRect(50,40,200,100)

jshell> label.repaint()

crearRectで一旦消去

jshell> g.clearRect(0,0,400,300)

jshell> label.repaint()

モアレを表示してみる。

jshell> IntStream.range(0,30).map(y->y*10).forEach(y->g.drawLine(0,y,400,300-y))

jshell> label.repaint()

画面消去

jshell> g.clearRect(0,0,400,300)

jshell> label.repaint()

ここもAffineTransformで[Shift]+[Tab]を押したあと[i]を押してjava.awt.geom.AffineTransformをimportしています。

{〜}の中は;(セミコロン)で行を終わらせる必要があるので注意。

で、最後の[}]を入力したら、ぐるぐる。

jshell> for(int i=0; i< 100;++i){
   ...> g.clearRect(0,0,400,300);

   ...> g.setTransform(AffineTransform.getRotateInstance(Math.PI*i/100,200,150));
   ...> g.fillRect(0,0,400,300);
   ...> label.repaint();
   ...> Thread.sleep(30);
   ...> }

最後に/listをしてぐるぐるに26というidが振られているのを確認して/26としてもう一度ぐるぐる。


Graphics2Dの使い方は、ドキュメント見て

https://docs.oracle.com/javase/jp/9/docs/api/java/awt/Graphics2D.html

トラックバック - http://d.hatena.ne.jp/nowokay/20180503

2018-04-23(月) Hyper-Vで仮想スイッチを作るとWavesのオーディオプラグインが死ぬ

Hyper-Vで仮想スイッチを作るとWavesのオーディオプラグインが死ぬ 05:38  Hyper-Vで仮想スイッチを作るとWavesのオーディオプラグインが死ぬを含むブックマーク

Hyper-Vで仮想スイッチを作るとWavesのライセンスが無効になってしまいます。


どうも、WavesのライセンスはMACアドレスと結びつけているようで、Hyper-Vで別のMacアドレスのネットワークができることで別デバイスと認識されてしまうらしい。

Waves License Center(WLC)でライセンスが無効になる ( その他趣味 ) - 音響・映像・電気設備が好き - Yahoo!ブログ


ということで、追加した仮想スイッチを一旦削除するとライセンスが復活。そこでライセンスをクラウドに退避、仮想スイッチを作り直してライセンスを結び付けることで復活しました。


恐らくVirtualBoxなどで仮想ネットワークカードを作っても同じではないかと。

気をつけよう。

あと、これを利用して、常に同じMACアドレスの仮想スイッチと結びつくようにしておけば、マシンが変わってもライセンスを引き継げるぽい。

linear_pcm0153linear_pcm0153 2018/05/20 22:01 こんばんは、リンク先を書いているlinear_pcm0153です。

記事には書いていませんが、実はそんな事しなくても、NICの設定でMACアドレスは変更できます。PCがクラッシュしても、ライセンスを救出する事が可能です。

2018-04-22(日) GraalVMでRust動かしたりレイトレをネイティブコンパイルしたり

[][]GraalVMでRust動かしたりレイトレをネイティブコンパイルしたり 02:17 GraalVMでRust動かしたりレイトレをネイティブコンパイルしたりを含むブックマーク

GraalVMが正式にリリースされました。結構話題になってますね。

GraalVMは、JavaベースJITとAoT、そしてASTエンジンTruffleの複合体です。(かな?)

GraalVM


ということで、Rust動かしたりJavaで書いたレイトレコードをネイティブコンパイルしたりしてみました。


Hyper-VUbuntuを用意する

ほんとはWindows Subsystem of Linux(WSL)でやりたかったのだけど、WSL上でJavaがちゃんと動いてくれなかったのであきらめました。

で、VirtualBox使うかなと思ったけど、Hyper-Vを無効にしないといけなくて、Hyper-Vを無効にするとDockerが動かなくなるのでやだなーと思ってたのだけど、普通にHyper-VUbuntuたちあげればいいのではーと思ってやってみました。


普通に使えますが、画面サイズ調整やフォルダ共有、クリップボード共有など、VirtualBoxのほうが使いやすいですね。

Macの場合はCE版ではなくOracle版を使うといいと思います。


RustをGraalVMで動かす

ASTエンジンTruffleというのは、プログラム言語を構文木に落として、最適化・実行する処理エンジンです。

JavaバイトコードLLVMのビットコードよりも抽象度が高く言語の構造が残っているため、最適化がやりやすいということを狙ってます。(たぶん)

で、そこでLLVMのビットコードをTruffleコードに変換するというSulongというツールもあるので、Rustも動きます。ライブラリなんかは、x86コードをLLVMビットコードに変換してTruffleコードに変換して動かすらしい。変態。


で、こんな感じでRustコードをmain.rsという名前で用意します。

fn main() {
  println!("Hello rust! fib(8) is {}", fib(8));
}

fn fib(i:i64) -> i64 {
  if i < 2 {
    i
  } else {
    fib(i - 2) + fib(i - 1)
  }
}

とりあえず普通にコンパイルして動かしてみます。

$ rustc main.rs
$ ./main
Hello rust! fib(8) is 21

では、これをLLVMのビットコードを吐きだしてGraalVMで動かしてみます。

$ rustc --emit=llvm-bc main.rs
$ ls -l main.*
-rw-rw-r-- 1 naoki naoki 6860  4月 23 01:37 main.bc
-rw-rw-r-- 1 naoki naoki  146  4月 23 01:36 main.rs
$ graalvm-1.0.0-rc1/bin/lli --lib $(rustc --print sysroot)/lib/libstd-* main.bc
Hello rust! fib(8) is 21

動きました!


Haskellでもいけるかなと思ったけど、LLVM3.5が必要っぽく、パッケージが3.7からしかないっぽく、とりあえずあきらめ。


レイトレをネイティブコンパイルしてみる

GraalVMにはAoTコンパイラもあります。AoTというのはAhead of Timeで、事前コンパイルのことです。これを使ってJavaコードをネイティブコンパイルしてみます。

それなりに処理量があるコードということで、こないだ作ったレイトレを動かしてみます。

kishida/smallpt4j: smallpt Java port


最新版はいろいろいじってて複数ソースに分かれてたりするので、初期のものを使います。

https://github.com/kishida/smallpt4j/blob/original/src/main/java/naoki/smallpt/SmallPT.java


パッケージをデフォルトパッケージに変更しておきます。また。FastMathを使っているのでjava.lang.Math.*をstatic importしてこちらを使います。

で、普通にコンパイルして実行

$ graalvm-1.0.0-rc1/bin/javac SmallPT.java
$ graalvm-1.0.0-rc1/bin/java SmallPT

画像ができました。

f:id:nowokay:20180423023819p:image

今回は早く終わるよう、画像を荒くしたままにしてます。


ではネイティブコンパイルを。

ネイティブコンパイルにはzlib.hが必要なので、とってきます。

$ sudo apt install zlib1g-dev

そしてnative-imageでコンパイル

$ graalvm-1.0.0-rc1/bin/javac SmallPT.java 
$ graalvm-1.0.0-rc1/bin/native-image SmallPT
Build on Server(pid: 7220, port: 26681)
   classlist:     166.86 ms
       (cap):     544.93 ms
       setup:     803.27 ms
    analysis:   3,460.75 ms
error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Unsupported method java.lang.ClassLoader.getParent() is reachable: The declaring class of this element has been substituted, but this element is not present in the substitution class
To diagnose the issue, you can add the option -H:+ReportUnsupportedElementsAtRuntime. The unsupported element is then reported at run time when it is accessed the first time.

なんかエラー。

ImageIOがだめっぽい。動的にクラスロードしてるからだろうな。


ということで、ImageIOをやめてオリジナルのsmallptと同様にppmを吐き出すように変更します。

        try(BufferedWriter bw = Files.newBufferedWriter(Paths.get("image.ppm"));
            PrintWriter pw = new PrintWriter(bw)) {
            pw.printf("P3\n%d %d\n%d\n", w, h, 255);
            for (Vec v : c) {
                pw.printf("%d %d %d ", toInt(v.x), toInt(v.y), toInt(v.z));
            }
        }

ということで、全体のコードはこちらに

SmallPT4j without ImageIO


改めてJavaで動かします。

$ graalvm-1.0.0-rc1/bin/javac SmallPT.java 
$ graalvm-1.0.0-rc1/bin/java SmallPT 
JVM:1.8.0_161 sample:40
Samples:40 Type:master Time:PT24.042S

これをネイティブコンパイル

$ graalvm-1.0.0-rc1/bin/native-image SmallPT
Build on Server(pid: 7220, port: 26681)
   classlist:     167.94 ms
       (cap):     592.71 ms
       setup:     808.36 ms
  (typeflow):   2,479.49 ms
   (objects):     875.25 ms
  (features):      24.48 ms
    analysis:   3,439.52 ms
    universe:     134.33 ms
     (parse):     318.66 ms
    (inline):     550.73 ms
   (compile):   2,101.23 ms
     compile:   3,249.17 ms
       image:     466.18 ms
       write:     120.34 ms
     [total]:   8,412.47 ms
$ ls -l smallpt
-rwxrwxr-x 1 naoki naoki 5696832  4月 23 02:27 smallpt

こんどは いけました。ネイティブファイルができてますね。そして5MB。案外小さい。


実行してみます。

$ rm image.ppm 
$ ./smallpt 
JVM:null sample:40
Samples:40 Type:master Time:PT37.341S
$ ls -l image.ppm
-rw-rw-r-- 1 naoki naoki 8244655  4月 23 02:28 image.ppm

というか、遅くなっている。。。24秒だったのが37秒に。


ついでに、通常のOpenJDKで動かしてみます。

$ jdk1.8.0_171/bin/java SmallPT 
JVM:1.8.0_171 sample:40
Samples:40 Type:master Time:PT18.565S
$ jdk-10.0.1/bin/java SmallPT 
JVM:10.0.1 sample:40
Samples:40 Type:master Time:PT16.400068S

GraalVMのJVMより速いし、JDK10はさらに速い!


ということでこんな感じに。

GraalVM native-imageJDK8 JDK10
1.8.0_161null 1.8.0_17110.0.1
24.04237.34118.56516.400068

というか、Durationの精度もJDK10であがってますね。


ということで、いろいろやってみました。

Swingアプリも試してみたけど、AppContextの初期化でインプットメソッドの処理をしようとしたときに動的クラスロードしてるっぽくてそこでダメですね。

まだまだ問題はありそうだけど、もっと開発が進むと面白そう。

トラックバック - http://d.hatena.ne.jp/nowokay/20180422

2018-04-09(月) マイクロサービスフレームワークArmeriaを始める

[]マイクロサービスフレームワークArmeriaを始める 05:43 マイクロサービスフレームワークArmeriaを始めるを含むブックマーク

Armeriaのチュートリアルを書いてみる

https://line.github.io/armeria/index.html


RESTサーバーとして使う

まずは、プロジェクトを用意します。

dependencyにcom.linecorp.armeria:armeria:0.62.0を追加します。

mavenの場合、次のようなpom.xmlを用意します。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation=
           "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>armeria_tutorial</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>com.linecorp.armeria</groupId>
            <artifactId>armeria</artifactId>
            <version>0.62.0</version>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>10</maven.compiler.source>
        <maven.compiler.target>10</maven.compiler.target>
    </properties>
</project>

sourceやtargetは環境に合わせて設定してください。1.8以降で動くはず。


まずは、簡単なHTTP RESTサーバーを書いてみます。

package tutorial;

import com.linecorp.armeria.common.HttpResponse;
import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.common.MediaType;
import com.linecorp.armeria.server.Server;
import com.linecorp.armeria.server.ServerBuilder;
import java.util.concurrent.CompletableFuture;

public class BasicServer {
    public static void main(String[] args) {
        ServerBuilder sb = new ServerBuilder();
        sb.http(8080);
        
        sb.service("/hello", (ctx, res) -> HttpResponse.of(
                HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, "Hello!!"));
        
        Server server = sb.build();
        CompletableFuture<Void> future = server.start();
        future.join();
    }
}

http://localhost:8080/helloにアクセスしてみます。

f:id:nowokay:20180410054052p:image


詳しくはこちらを

https://line.github.io/armeria/server-basics.html


アノテーションでサービスを定義する

serviceメソッドでURLとサービスを結び付けていましたが、通常のクラスにアノテーションを付けたメソッドとしてサービスを定義することもできます。

package tutorial;

import com.linecorp.armeria.common.HttpResponse;
import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.common.MediaType;
import com.linecorp.armeria.server.annotation.Get;
import com.linecorp.armeria.server.annotation.Param;

public class MyService {
    @Get("/service")
    public HttpResponse service() {
        return HttpResponse.of(
                HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, "My Service");
    }
    @Get("/greet/:name")
    public HttpResponse greet(@Param("name") String name) {
        return HttpResponse.of(
                HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, "Hello " + name);
    }
}

BasicServerに追加します。

        sb.annotatedService(new MyService());

f:id:nowokay:20180410054049p:image


詳しくはこのあたり

https://line.github.io/armeria/server-annotated-service.html


Thriftサーバーとして使う

ThriftのIDLを書きます。

/src/main/thriftにhello.thriftファイルを置きます。

namespace java tutorial.thrift.hello

service HelloService {
  string hello(1:string name)
}

これをthriftコンパイラJavaコードを生成します。

ここからダウンロードします

https://thrift.apache.org/download


$ thrift -out src/main/java --gen java src/main/thrift/hello.thrift

こんな感じのソースが生成されます。

/**
 * Autogenerated by Thrift Compiler (0.11.0)
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 *  @generated
 */
package tutorial.thrift.hello;

@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-04-10")
public class HelloService {

  public interface Iface {

    public java.lang.String hello(java.lang.String name) throws org.apache.thrift.TException;

  }
...

実際はmavenプラグインを使ってmaven上でコンパイルできるようにしたほうがいいけど、このあたりを見てがんばる感じで。

https://stackoverflow.com/questions/18767986/how-can-i-compile-all-thrift-files-thrift-as-a-maven-phase


できたinterfaceを実装したコードを書きます。

package tutorial;

import org.apache.thrift.TException;
import tutorial.thrift.hello.HelloService;

public class HelloServiceImpl implements HelloService.Iface {

    @Override
    public String hello(String name) throws TException {
        return String.format("Hello %s!!!", name);
    }

}

ArmeriaでThriftを使うためにdependencyにarmeria-thriftを追加します。

        <dependency>
            <groupId>com.linecorp.armeria</groupId>
            <artifactId>armeria-thrift</artifactId>
            <version>0.62.0</version>
        </dependency>

そしたらserviceとして追加します。ここでは別サーバーとして追加してみましょう。

future.join()で処理がブロックしてしまうので、そこは消してまとめてjoinします。

        CompletableFuture<Void> tfuture = new ServerBuilder()
                .http(8081)
                .service("/hello", THttpService.of(new HelloServiceImpl()))
                .build()
                .start();
        
        CompletableFutures.allAsList(Arrays.asList(
                future, tfuture)).join();

詳しくはこちらを。

https://line.github.io/armeria/server-thrift.html


DocServiceを使う

しかしながら、クライアント作るまで動かせないのは不便ですね。

そこでArmeriaではDocServiceというのが用意されています。

        CompletableFuture<Void> tfuture = new ServerBuilder()
                .http(8081)
                .service("/hello", THttpService.of(new HelloServiceImpl()))
                .serviceUnder("/docs", new DocService())
                .build()
                .start();

serviceUnderにするのを忘れないように。


http://localhost:8081/docsにアクセスすると、呼び出しが行えます。

f:id:nowokay:20180410054046p:image


ただ、いきなりJSONを入力しろと言われても何を入れていいかわからないので、サンプルが欲しいところ。ということで、DocserviceBuilderを使います。

                .serviceUnder("/docs", new DocServiceBuilder()
                    .exampleRequest(new HelloService.hello_args("naoki"))
                    .build())

パラメータも用意されて、ボタンを押すと実行されました。

f:id:nowokay:20180410054042p:image


詳しくはこちらを。

https://line.github.io/armeria/server-docservice.html


Thriftクライアントとして使う

さて、ではThriftサーバーを呼びだしてみましょう。

        HelloService.Iface helloService = Clients.newClient(
                "tbinary+http://localhost:8081/hello",
                HelloService.Iface.class);
        sb.service("/thello/{name}", (ctx, res) -> HttpResponse.of(
                HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8,
                helloService.hello(ctx.pathParam("name"))));

呼び出せてる感じ。

f:id:nowokay:20180410054040p:image


詳しくはここを

https://line.github.io/armeria/client-thrift.html


HTTPクライアントとして使う

さて、最後にHTTPクライアントとしても使ってみます。

まずはHttpClientライブラリを。

        HttpClient httpClient = HttpClient.of("http://localhost:8080");
        
        CompletableFuture<Void> hfuture = new ServerBuilder()
                .http(8082)
                .service("/hello", (ctx, res) ->{
                    CompletableFuture<AggregatedHttpMessage> msg =
                            httpClient.get("/hello").aggregate();
                    return HttpResponse.of(
                            HttpStatus.OK,
                            MediaType.PLAIN_TEXT_UTF_8,
                            msg.get().content().toStringAscii());
                })
                .build()
                .start();
        
        CompletableFutures.allAsList(Arrays.asList(
                future, tfuture, hfuture)).join();

Retrofitを使う

実際は、HTTP呼び出しは結構多いのでRetrofitでメソッドに結び付けたい。

ということで、armeria-retrofit2をdependencyに加えます。また、Retrofitで使うconverterやadapterも追加しておきます。

        <dependency>
            <groupId>com.linecorp.armeria</groupId>
            <artifactId>armeria-retrofit2</artifactId>
            <version>0.62.0</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>converter-scalars</artifactId>
            <version>2.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>adapter-java8</artifactId>
            <version>2.4.0</version>
        </dependency>

HTTP呼び出しをメソッドとして定義します。

package tutorial;

import java.util.concurrent.CompletableFuture;
import retrofit2.http.GET;
import retrofit2.http.Path;

public interface MyHttp {
    @GET("/hello")
    CompletableFuture<String> hello();
    
    @GET("/thello/{name}")
    CompletableFuture<String> hello(@Path("name") String name);
}

このメソッドを使ってHTTP呼び出し。

        Retrofit retrofit = new ArmeriaRetrofitBuilder()
                .baseUrl("http://localhost:8080/")
                .addConverterFactory(ScalarsConverterFactory.create())
                .addCallAdapterFactory(Java8CallAdapterFactory.create())
                .build();
        MyHttp myHttp = retrofit.create(MyHttp.class);
        
        CompletableFuture<Void> hfuture = new ServerBuilder()
                .http(8082)
                .service("/hello", (ctx, res) ->HttpResponse.of(
                        HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8,
                        myHttp.hello().get()))
                .service("/hello/{name}", (ctx, res) -> HttpResponse.of(
                        HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8,
                        myHttp.hello(ctx.pathParam("name")).get()))
                .build()
                .start();