home ホーム search 検索 -  login ログイン  | help ヘルプ

find 検索

91 - 100 / 1297    [|<]  [|<]  [<]  1  2  3  4  5  6  7  8  9  10   [>]  [>|][>|]
タイトル/名前 更新者 更新日
日記/2015/02/08/EC2のインスタンス内から自分にattachしてるEBSをsnapshotを取る msakamoto-sf 2015-02-08 01:14:51
Java/JRebelの下調べメモ msakamoto-sf 2015-02-08 01:11:51
Java/JNDIのDNSサービスプロバイダによる名前解決 msakamoto-sf 2015-02-08 00:58:37
Java/Socket, InetAddressにおけるDNS名前解決の仕組みと networkaddress.cache.ttl msakamoto-sf 2015-02-08 00:16:40
Java/文字コードメモ3 msakamoto-sf 2015-02-08 00:12:03
Java/文字コードメモ2 msakamoto-sf 2015-02-08 00:11:31
Java/文字コードメモ1 msakamoto-sf 2015-02-08 00:11:03
日記/2015/02/07/Bloggerでプログラムソースコードのsyntaxハイライト(SyntaxHighlighter, Code Prettify) msakamoto-sf 2015-02-07 19:25:13
日記/2015/02/07/NetBeansでプロジェクトのバックグラウンドスキャンを止めるか無効化したい msakamoto-sf 2015-02-07 18:06:09
読書メモ/「起動プログラム ブート・ローダ入門」 msakamoto-sf 2015-02-07 17:55:32
ソート項目 / ソート順     1ページ 件ずつ表示

日記/2015/02/08/EC2のインスタンス内から自分にattachしてるEBSをsnapshotを取る  

所有者: msakamoto-sf    作成日: 2015-02-08 01:12:11
カテゴリ: AWS 
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2015-02-08 01:14:51
md5:501402cfd60ee59ad4b5b8d60f91c513
sha1:3e0ad73a09353635e8b0fc79c7d05717112fad05

Java/JRebelの下調べメモ  

所有者: msakamoto-sf    作成日: 2015-02-08 01:09:40
カテゴリ: Java 

EclipseやNetBeansからServletアプリをTomcat上でローカルデバッグするとき、Javaソース編集してclass更新された後のHotSwapが時々失敗する。
JRebelという有償製品が、HotSwapを安定して動かせるようになるらしい。
購入する前の、調査メモです。

ユーザの声:

技術的に関連してそうなもの:

クラスファイルの更新監視ということであれば、ファイル更新の監視関連トピック:

こんなのもある:

JavaのClassLoaderの闇は深いので、有償製品で楽できるなら、それに頼るのもありか。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2015-02-08 01:11:51
md5:36ba38eeb0ace00ad936553cbea6c5d0
sha1:8825c0ee7ca46d874e330fe6e5167095035d8614

Java/JNDIのDNSサービスプロバイダによる名前解決  

所有者: msakamoto-sf    作成日: 2015-02-08 00:55:49
カテゴリ: DNS Java ネットワーク 

Java/Socket, InetAddressにおけるDNS名前解決の仕組みと networkaddress.cache.ttl ではSocket, InetAddressによるDNS名前解決を追ったが、最終的に取得できるのはIPアドレスのみだった。

DNSのレコード単位で問い合わせを行ったり、DNSサーバを指定したい場合は、JNDIのDNSサービスプロバイダを利用できる。

この記事では、JNDIのDNSサービスプロバイダを使ったDNSサーバ問い合わせ処理のサンプルコードを紹介する。


サンプルコードの実行環境 : Win7 64bit + Oracle JDK 1.8.0.31

JNDIで使えるDNSサービスプロバイダの実装(Javaソース):

参考資料:


サンプルコード

JndiDnsTest1.java : OSのDNSサーバ設定を使用する。

JndiDnsTest1.java: "google.com" を取得

import java.util.Properties;
 
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
 
public class JndiDnsTest1 {
 
    public static void main(String[] args) throws Exception {
        // see: http://www.ibm.com/developerworks/jp/websphere/library/was/was_jndi/1.html
        Properties env = new Properties();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.dns.DnsContextFactory");
        DirContext ictx = new InitialDirContext(env);
        Attributes attrs = ictx.getAttributes("google.com");
        NamingEnumeration<?> allAttr = attrs.getAll();
        while (allAttr.hasMore()) {
            Attribute attr = (Attribute) allAttr.next();
            System.out.println("Attribute: " + attr.getID());
            NamingEnumeration<?> values = attr.getAll();
            while (values.hasMore())
                System.out.println("Value: " + values.next());
        }
    }
}

実行結果:

Attribute: A
Value: 216.58.220.174
Attribute: NS
Value: ns3.google.com.
Value: ns2.google.com.
Value: ns4.google.com.
Value: ns1.google.com.
Attribute: MX
Value: 30 alt2.aspmx.l.google.com.
Value: 40 alt3.aspmx.l.google.com.
Value: 20 alt1.aspmx.l.google.com.
Value: 10 aspmx.l.google.com.
Value: 50 alt4.aspmx.l.google.com.

→ getAttributes()の引数を "www.google.com" にしてみる:

Attributes attrs = ictx.getAttributes("www.google.com");

実行結果:

Attribute: A
Value: 173.194.38.208
Value: 173.194.38.210
Value: 173.194.38.211
Value: 173.194.38.212
Value: 173.194.38.209

→ AレコードとMXレコードだけに絞ってみる。

Attributes attrs = ictx.getAttributes("google.com", new String[] { "MX", "A" });

※やってみたが、取れたり取れなかったりしたので、スキップ。

JndiDnsTest2.java : DNSサーバを指定

JndiDnsTest2.java: DNSサーバのアドレスは、ご利用のプロバイダのアドレスなどに書き換えて試して下さい。

package jdk8scratch;
 
import java.util.Properties;
 
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
 
public class JndiDnsTest2 {
 
    public static void main(String[] args) throws Exception {
        // see: http://www.ibm.com/developerworks/jp/websphere/library/was/was_jndi/1.html
        Properties env = new Properties();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.dns.DnsContextFactory");
        env.put(Context.PROVIDER_URL, "dns://xxx.yyy.zzz.www");
        DirContext ictx = new InitialDirContext(env);
        Attributes attrs = ictx.getAttributes("google.com");
        NamingEnumeration<?> allAttr = attrs.getAll();
        while (allAttr.hasMore()) {
            Attribute attr = (Attribute) allAttr.next();
            System.out.println("Attribute: " + attr.getID());
            NamingEnumeration<?> values = attr.getAll();
            while (values.hasMore())
                System.out.println("Value: " + values.next());
        }
    }
}

実行結果:

Attribute: AAAA
Value: 2404:6800:4004:807::1002
Attribute: A
Value: 173.194.126.165
Value: 173.194.126.164
Value: 173.194.126.169
Value: 173.194.126.168
Value: 173.194.126.162
Value: 173.194.126.160
Value: 173.194.126.163
Value: 173.194.126.166
Value: 173.194.126.161
Value: 173.194.126.167
Value: 173.194.126.174
Attribute: NS
Value: ns3.google.com.
Value: ns1.google.com.
Value: ns2.google.com.
Value: ns4.google.com.
Attribute: MX
Value: 30 alt2.aspmx.l.google.com.
Value: 50 alt4.aspmx.l.google.com.
Value: 40 alt3.aspmx.l.google.com.
Value: 20 alt1.aspmx.l.google.com.
Value: 10 aspmx.l.google.com.

→ NSとAAAAレコードだけに絞ってみる。

Attributes attrs = ictx.getAttributes("google.com", new String[] { "NS", "AAAA" });

実行結果:

Attribute: AAAA
Value: 2404:6800:4004:812::200e
Attribute: NS
Value: ns4.google.com.
Value: ns1.google.com.
Value: ns3.google.com.
Value: ns2.google.com.

Context.INITIAL_CONTEXT_FACTORY に指定する値は "com.sun.jndi.dns.DnsContextFactory" と "com.example.jndi.dns.DnsContextFactory" のどちらが正?

2015-02-07時点:
JDK7,8の日本語/英語ドキュメント:

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.example.jndi.dns.DnsContextFactory");
                                          ^^^^^^^^^^^

JDK6の日本語/英語ドキュメント:

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
                                          ^^^^^^^

正解:"com.sun.jndi.dns.DnsContextFactory"の方。JDK8で "com.example"にしたら以下の例外発生:

Caused by: java.lang.ClassNotFoundException: com.example.jndi.dns.DnsContextFactory


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2015-02-08 00:58:37
md5:4ca5c091ea242d5d240da14fe288c427
sha1:ffecd9fa3a864c61a39de50266ed0168ca770d74

Java/Socket, InetAddressにおけるDNS名前解決の仕組みと networkaddress.cache.ttl  

所有者: msakamoto-sf    作成日: 2015-02-08 00:12:49
カテゴリ: DNS Java ネットワーク 

JavaでのSocketおよびInetAddressを使ったプログラミングで、DNSの名前解決はどのように行われているのか、ソースなどを追いかけてみた。



Socket(String host, int port)での名前解決の仕組み

三行で結論:

  1. java.net.Socketのコンストラクタ "Socket(String host, int port)"
  2. →内部的には "java.net.InetAddress#getByName(String host)" を呼んでる。
  3. →最終的にはnative(=JNI)に辿り着き、今回はそこでギブアップ。

まず "Socket(String host, int port)" コンストラクタでの名前解決の使い方を見てみる。

DnsTest1.java:

import java.net.InetAddress;
import java.net.Socket;
 
public class DnsTest1 {
    public static void main(String[] args) {
        try (Socket socket = new Socket("www.google.com", 80)) {
            InetAddress ia = socket.getInetAddress();
            System.out.println(ia.getHostAddress());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

実行結果:

216.58.220.228

名前解決がどうなっているのか?JDKのソースから、このコンストラクタのソースを確認してみる。

public Socket(String host, int port)
        throws UnknownHostException, IOException
    {
        this(host != null ? new InetSocketAddress(host, port) :
             new InetSocketAddress(InetAddress.getByName(null), port),
             (SocketAddress) null, true);
    }

"host"がnullでなければ、"new InetSocketAddress(host, port)" を呼び出している。

public InetSocketAddress(String hostname, int port) {
        checkHost(hostname);
        InetAddress addr = null;
        String host = null;
        try {
            addr = InetAddress.getByName(hostname);
        } catch(UnknownHostException e) {
            host = hostname;
        }
        holder = new InetSocketAddressHolder(host, addr, checkPort(port));
    }

アドレスを"InetAddress.getByName(hostname)"でInetAddressを取得している。

InetAddress.getByName(String host):

public static InetAddress getByName(String host)
        throws UnknownHostException {
        return InetAddress.getAllByName(host)[0];
    }

試しに、InetAddress.getAllByName() を使ってみる。
DnsTest2.java:

import java.net.InetAddress;
 
public class DnsTest2 {
    public static void main(String[] args) throws Exception {
        InetAddress[] ias = InetAddress.getAllByName("www.google.com");
        for (InetAddress ia : ias) {
            System.out.println(ia.getHostAddress());
        }
    }
}

実行結果:

173.194.38.211
173.194.38.212
173.194.38.209
173.194.38.210
173.194.38.208

"InetAddress.getAllByName(host)"からの流れだが、途中はスキップし、"getAddressesFromNameService(String host, InetAddress reqAddr)"の呼び出しまで進めてみる。

private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr)
        throws UnknownHostException
    {
        /* ... */
            try {
                for (NameService nameService : nameServices) {
                    try {
                        addresses = nameService.lookupAllHostAddr(host);
                        success = true;
                        break;
                    } catch (UnknownHostException uhe) {
                    /* ... */

"nameService" は "sun.net.spi.nameservice.NameService" のListになっており、NameServiceはinterfaceとなっている。

InetAddress.java中の、"nameService"の初期化処理周りのコードを見てみる:

/* Used to store the name service provider */
    private static List<NameService> nameServices = null;
 
    static {
        // create the impl
        impl = InetAddressImplFactory.create();
 
        // get name service if provided and requested
        String provider = null;;
        String propPrefix = "sun.net.spi.nameservice.provider.";
        int n = 1;
        nameServices = new ArrayList<NameService>();
        provider = AccessController.doPrivileged(
                new GetPropertyAction(propPrefix + n));
        while (provider != null) {
            NameService ns = createNSProvider(provider);
            if (ns != null)
                nameServices.add(ns);
 
            n++;
            provider = AccessController.doPrivileged(
                    new GetPropertyAction(propPrefix + n));
        }
 
        // if not designate any name services provider,
        // create a default one
        if (nameServices.size() == 0) {
            NameService ns = createNSProvider("default");
            nameServices.add(ns);
        }
    }

簡単にまとめると、以下のような処理になっている。

  1. "impl" staticメンバに、InetAddressImplのインスタンスを "InetAddressImplFactory.create()" メソッドで生成してセット。
  2. Javaのプロパティで "sun.net.spi.nameservice.provider.1", "sun.net.spi.nameservice.provider.2", ... の順で探していき、指定されているプロバイダ名があれば、InetAddress.createNSProvider()でインスタンスを生成して、nameServicesに追加する。
  3. "createNSProvider("default")" で取得したデフォルトのNameServiceインスタンス(provider)をnameServicesに追加する。

JDK付属のJRE内を "sun.net.spi.nameservice.provider" でgrepしてみたが、特に設定は見つからなかった。
よって、デフォルトの環境では "createNSProvider("default")" で取得したデフォルトのNameServiceインスタンスを使っていると考えられる。

そこで、InetAddress.createNSProvider()の実装を見てみて、"default"を引数に渡した時の挙動を確認する:

private static NameService createNSProvider(String provider) {
        if (provider == null)
            return null;
 
        NameService nameService = null;
        if (provider.equals("default")) {
            // initialize the default name service
            nameService = new NameService() {
                public InetAddress[] lookupAllHostAddr(String host)
                    throws UnknownHostException {
                    return impl.lookupAllHostAddr(host);
                }
                public String getHostByAddr(byte[] addr)
                    throws UnknownHostException {
                    return impl.getHostByAddr(addr);
                }
            };
        } else {
            /* ... "default" 以外のNameServiceプロバイダの生成 ... */
        }
 
        return nameService;
    }

"default" providerの場合、InetAddressの "impl" staticメンバに呼び出しを委譲した NameService インスタンスを生成している。
"impl" は InetAddressImpl の実装であり、 "lookupAllHostAddr()" と "getHostByAddr()" に委譲している。これらの実装を追うため、まず、"InetAddressImplFactory#create()" のソースを確認する。
InetAddressImplFactoryはInetAddress.java内で定義されていた:

/*
 * Simple factory to create the impl
 */
class InetAddressImplFactory {
 
    static InetAddressImpl create() {
        return InetAddress.loadImpl(isIPv6Supported() ?
                                    "Inet6AddressImpl" : "Inet4AddressImpl");
    }
 
    static native boolean isIPv6Supported();
}

native(=JNI)の isIPv6Supported() に応じて、Inet4AddressImplかInet6AddressImplかに、クラスの実体を切り替えている。
今回はInet4AddressImplのソースを確認してみる。

java/net/Inet4AddressImpl.java:

class Inet4AddressImpl implements InetAddressImpl {
    public native String getLocalHostName() throws UnknownHostException;
    public native InetAddress[]
        lookupAllHostAddr(String hostname) throws UnknownHostException;
    public native String getHostByAddr(byte[] addr) throws UnknownHostException;
    private native boolean isReachable0(byte[] addr, int timeout, byte[] ifaddr, int ttl) throws IOException;
    /* ... */

肝心の "lookupAllHostAddr()" などが軒並み native(=JNI) になっている。今回はJNIのソースまでは追い切れないため、Socket -> InetAddress 経由での名前解決処理についてはここで打ち切る。

InetAddressでの名前解決処理をカスタマイズするには

InetAddressでの名前解決処理をカスタマイズするには、これまで見てきた内容を整理すると以下のようになる。

  1. sun.net.spi.nameservice.NameService を実装する。
    1. https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/sun/net/spi/nameservice/NameService.java
    2. また、以下のクラスも実装しないと駄目っぽい。
    3. https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/sun/net/spi/nameservice/NameServiceDescriptor.java
  2. "sun.net.spi.nameservice.provider.N" のJavaプロパティに、実装したprovider名を指定する。
    1. これについても、正確にどういう名前を指定すればよいのかについてはInetAddressのソースなど要確認。SPIに沿ってるぽいので、そのへんも要確認。

また実装サンプルと思わしきコードがあるので、これも参考になる。

"networkaddress.cache.ttl" はどこで使われているのか?

JavaのDNSキャッシュとして "%JAVA_HOME%\lib\security\java.security" に設定する"networkaddress.cache.ttl"という値がある。InetAddressのJavaDocに説明がある。

  • https://docs.oracle.com/javase/jp/8/api/java/net/InetAddress.html
    • デフォルトは「実装に固有の期間キャッシュ」する。
    • -1 だと「ずっとキャッシュする」(キャッシュポイゾニング対策になる)
    • 1以上ならキャッシュ秒数
    • 0ならキャッシュ期間0秒なので毎回問い合わせになりそう。

これまで見てきたように、Javaにおける名前解決は以下の2種類の実装が提供されている。

  1. (Socketコンストラクタ ->) "InetAddress#getByName()" -> native(JNI)
  2. JNDI DNS プロバイダ

では、"networkaddress.cache.ttl" はどちらで使われているか?

結論から言うと、そもそもこのプロパティ値、InetAddressのJavaDocに記載されているのだから、InetAddressでの名前解決で使われる。
JNDI DNS プロバイダについては、sunパッケージ/com.sunパッケージのjavaソースも含めてgrepした範囲では使われている様子は確認できなかった。

"networkaddress.cache.ttl" についてsunパッケージ/com.sunパッケージも含めてJavaソースをgrepしてみると、以下のJavaファイルで参照していた。
sun/net/InetAddressCachePolicy.java: (openjdk7 : https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/sun/net/InetAddressCachePolicy.java )

package sun.net;
 
import java.security.PrivilegedAction;
import java.security.Security;
 
public final class InetAddressCachePolicy {
 
    // Controls the cache policy for successful lookups only
    private static final String cachePolicyProp = "networkaddress.cache.ttl";
    private static final String cachePolicyPropFallback =
        "sun.net.inetaddr.ttl";
 
    // Controls the cache policy for negative lookups only
    private static final String negativeCachePolicyProp =
        "networkaddress.cache.negative.ttl";
    private static final String negativeCachePolicyPropFallback =
        "sun.net.inetaddr.negative.ttl";
 
    public static final int FOREVER = -1;
    public static final int NEVER = 0;
 
    /* default value for positive lookups */
    public static final int DEFAULT_POSITIVE = 30;
 
    /* ... */
    static {
        Integer tmp = null;
 
        try {
            tmp = new Integer(
              java.security.AccessController.doPrivileged (
                new PrivilegedAction<String>() {
                  public String run() {
                      return Security.getProperty(cachePolicyProp);
                  }
              }));
        } catch (NumberFormatException e) {
            // ignore
        }
        if (tmp != null) {
            cachePolicy = tmp.intValue();
            if (cachePolicy < 0) {
                cachePolicy = FOREVER;
            }
            propertySet = true;
        } else {
            /* ... */
            } else {
                /* No properties defined for positive caching. If there is no
                 * security manager then use the default positive cache value.
                 */
                if (System.getSecurityManager() == null) {
                    cachePolicy = DEFAULT_POSITIVE;
                }
            }
        /* ... */

ポイントとしては、このソースコードだと "networkaddress.cache.ttl" or "sun.net.inetaddr.ttl" が指定されていればその値を使うが、どこにも指定が無ければ、DEFAULT_POSITIVE, つまり30秒が名前解決のキャッシュTTLとなる。

現在の実行環境では実際にどの値なのか確認するため、以下のようなGroovyスクリプトを作成し、OracleJDK8のJRE環境で実行してみた。
https://gist.github.com/msakamoto-sf/733aa7a2d0b461766b77

実行結果:

groovy t_networkaddress_cache_ttl.groovy
30       # positive cache は30秒
10       # negative cache は10秒
false    # positive cache 設定は未設定だった。
true     # negative cache は設定されてた。

Javaでは以下のようになる。設定の未設定・設定有りについては省略。
DnsTest3.java:

import sun.net.InetAddressCachePolicy;
 
public class DnsTest3 {
    public static void main(String[] args) throws Exception {
        System.out.println(InetAddressCachePolicy.get());
        System.out.println(InetAddressCachePolicy.getNegative());
    }
}

※Eclipse上で "Access restriction on class due to restriction on required library rt.jar" というエラーが発生した場合は、 Windows -> Preferences -> Java -> Compiler -> Errors/Warnings で "Forbidden reference (access rules)" を Warning または Ignore に設定する。

実際に実行環境の jre/lib/security/java.security を見てみると、以下のように "networkaddress.cache.ttl" はコメントアウトされていて未設定、 "networkaddress.cache.negative.ttl" は10秒に設定されていた。

...

#
# The Java-level namelookup cache policy for successful lookups:
#
# any negative value: caching forever
# any positive value: the number of seconds to cache an address for
# zero: do not cache
#
# default value is forever (FOREVER). For security reasons, this
# caching is made forever when a security manager is set. When a security
# manager is not set, the default behavior in this implementation
# is to cache for 30 seconds.
#
# NOTE: setting this to anything other than the default value can have
#       serious security implications. Do not set it unless
#       you are sure you are not exposed to DNS spoofing attack.
#
#networkaddress.cache.ttl=-1

# The Java-level namelookup cache policy for failed lookups:
#
# any negative value: cache forever
# any positive value: the number of seconds to cache negative lookup results
# zero: do not cache
#
# In some Microsoft Windows networking environments that employ
# the WINS name service in addition to DNS, name service lookups
# that fail may take a noticeably long time to return (approx. 5 seconds).
# For this reason the default caching policy is to maintain these
# results for 10 seconds.
#
#
networkaddress.cache.negative.ttl=10

...

InetAddressCachePolicy クラス名で sun/com.sun パッケージ含めたJDKのJavaソースをgrepしたところ、 "java/net/InetAddress.java" でのみ使われていた。
InetAddressの中に Cache クラスというのがネストされて定義されており、その中で参照されている。

/**
     * A cache that manages entries based on a policy specified
     * at creation time.
     */
    static final class Cache {
        private LinkedHashMap<String, CacheEntry> cache;
        private Type type;
 
        enum Type {Positive, Negative};
 
        /**
         * Create cache
         */
        public Cache(Type type) {
            this.type = type;
            cache = new LinkedHashMap<String, CacheEntry>();
        }
 
        private int getPolicy() {
            if (type == Type.Positive) {
                return InetAddressCachePolicy.get();
            } else {
                return InetAddressCachePolicy.getNegative();
            }
        }
        /* ... */

"networkaddress.cache.ttl" のデフォルト値は?

"networkaddress.cache.ttl" はDNSサーバが返すTTLとどう連携するか?

これはあくまでも「Javaライブラリのレイヤーで名前解決したのをキャッシュする期間」である。そして、InetAddress経由の名前解決は、デフォルトではnative(=JNI)の実装になってしまい、その内部までは調べきれなかった。
そのため、以下のようなケースではどうなるか、確認していない。

  • DNSのNSレコードのTTLは数秒になっているのに、SecurityManager付き + "networkaddress.cache.ttl=-1" でJavaを起動した場合。
    • → 最初に名前解決したのがずっとキャッシュされてしまい、DNS側のTTLの設定値とは無関係な動きになってしまうのか?

この点を確認するのであれば、自前で sun.net.spi.nameservice.NameService 及び NameServiceDescriptor を実装して名前解決の要求があったらlogするようにして、それを "sun.net.spi.nameservice.provider.N" あたりに設定すれば良いだろう。
個人的な想像だが、 NameService の lookupAllHostAddr() や getHostByAddr() はDNSサーバからのTTL情報をやりとりできるメソッドシグネチャになってないため、DNSのTTLは InetAddress のキャッシュ処理とは連携出来ないのではないか、と予想される。つまりまず "networkaddress.cache.ttl" によるキャッシュ期間がチェックされ、それがexpireされて始めてDNS問い合わせが発生する。この時DNSサーバからのTTL情報をどう扱うかは、NameServiceの実装に依存することが予想される。

参考資料

networkaddress.cache.ttl 関連:

ネットワーク関連のJavaプロパティ

Eclipse上でプログラミングしている時に、sun.net や com.sun 以下のパッケージやクラスを参照しようとして "Access restriction on class due to restriction on required library rt.jar" みたいなエラーが発生した時

sun/com.sunなどのパッケージを含んだJavaソース

OpenJDK7ミラーソース



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2015-02-08 00:16:40
md5:b80edda6584addecc35afea019d3ae53
sha1:8f1312a6fc6dd77605fafc337827211621d29b05

Java/文字コードメモ3  

所有者: msakamoto-sf    作成日: 2011-12-03 22:38:52
カテゴリ: Java 

使っているJavaのデフォルトの文字セット、および利用できる文字セットの標準名と別名を一覧出力します。

意外にも、MacOSX(Lion, 10.7.2)のJava(JDK 1.6.0_29)のデフォルトはShift_JISになっていた。



プレーンテキスト形式でダウンロード
現在のバージョン : 3
更新者: msakamoto-sf
更新日: 2015-02-08 00:12:03
md5:57108b3018cb4cd9d19308db4102cf52
sha1:a7362dbe033fcabec724986588a4f7b2bcf2839d

Java/文字コードメモ2  

所有者: msakamoto-sf    作成日: 2006-03-14 13:44:36
カテゴリ: Java 

Shift_JIS, MS932, Windows-31J の取り扱いについて実験する。

これらは特にサーバーサイドのJavaを扱う上で何かと文字化けの原因として取りざたされている。今回示す例では、日本語の自然文で普通に使用される '' ~ '' が簡単に文字化けしてしまっている。
特にややこしいのが"Shift_JIS"と"MS932"(CP932)系の違いである。
Windows上でのShift_JISは、正確にはShift_JISをベースとして空いている外字領域にNECやIBM由来の特殊な文字を配置したエンコーディングであり、これが "CodePage932", CP932ともMS932とも、Windows-31JともMS-Kanjiとも呼ばれているエンコーディングである。

今回の記事で例示している中で、「~」「・」は本来のShift_JISに配置されているため、これだけならコンパイル時にソースファイルのエンコーディングを「Shift_JIS」と指定してもWarningは出ない。(Warningは出ないが、実際に実行してみると文字化けする。この原因は後述。)
「㈱」が混じると、こちらはCP932で13区74点、つまり本来Shift_JISには無い外字領域に配置された文字になるため、"Shift_JIS"を指定すると文字がマップできないとWarningが出力される。

"~"や"㈱"が混じったJavaソースを用意する。

public class EncodingW31 {
    public static void main(String[] args) {
        System.out.println("Windows-31J ~・㈱");
    }
}

コンパイルし、実行してみる。

ケース1:Shift_JISとしてコンパイル・実行

画像/Java/java_charactercode_2_1.jpg

上図に示すとおり、見事に文字化けしている。下はclassファイルをUTF-8対応のエディタで文字コード自動認識で開いた図。

画像/Java/java_charactercode_2_2.jpg

ケース2:MS932、あるいはWindows-31Jとしてコンパイル・実行

画像/Java/java_charactercode_2_3.jpg

上図の通り、文字化けせずに表示できた。なお、エディタで開いてみると先と同じく、自動認識ではSJISと判定されてしまった。

なお、こちらの例では"MS932"としていしてコンパイルしたが、 "Windows-31J"を指定しても同じクラスファイルが生成された。 (MD5チェックサムが同一)

結論

サーバーサイドで入力される文字コードがSJISが想定された場合は、"Shift_JIS"で受け取るのではなく"Windows-31J"あるいは"MS932"として受け取るべきである。

日本語版Windowsにより生成されたCP932の文字列を受け取ることが想定される場合は、"Shift_JIS"で受け取るのではなく"Windows-31J"あるいは"MS932"として受け取るとよいだろう。
Webアプリケーションの場合で、入力フォームがUTF-8やEUC-JPの文字コードで構成される場合は、クライアント=Webブラウザが入力フォームと同じ文字コードに変換して送信すると予想されるため、"UTF-8"や"EUC-JP"で受け取るとよいだろう。

補足:「㈱」無しで"Shift_JIS"でコンパイルしても文字化けする理由

「㈱」無しで "-encoding Shift_JIS" とした場合、コンパイルでこそWarningは出ないが、実際にうごかしてみるとやはり文字化けしてしまう。これは"~"(1区33点, 0x8160)のマッピングが原因である。
Javaは"~"について、Shift_JISとMS932で異なるUnicodeコードポイントにマッピングする。

  • Shift_JIS -> U+301C, WAVE DASH (UTF-8: 0xE3809C)
  • MS932 -> U+FF5E, FULLWIDTH TILDE (UTF-8: 0xEFBD9E)

これが、外部からの入力をJavaの内部に変換する場合のマッピングとなる。

そしてJavaの内部でのWAVE DASH, FULLWIDTH TILDEを外の世界にマッピングするときが問題となる。

  • U+301C(WAVE DASH) -> "MS932" 以外のみ Shift_JISの0x8160にマッピング可能
  • U+FF5E(FULLWIDTH TILDE) -> "MS932" のみ Shift_JISの0x8160にマッピング可能

Windows用のJavaVMで普通にSystem.out.println()する場合はMS932が「内→外」変換として使われる(PrintStreamの文字列出力は、プラットフォームのデフォルトの文字エンコーディングを使ってバイトに変換される)。
従って、"-encodign Shift_JIS"でコンパイルしたclassファイル中の「~」(U+301C WAVE DASH)はMS932ではマップされないため、"?"として文字化けすることになる。

参考(Windows-31JとJava関連)

参考 ("~"での文字化け, JavaでのUnicodeのマッピング問題など)



プレーンテキスト形式でダウンロード
現在のバージョン : 3
更新者: msakamoto-sf
更新日: 2015-02-08 00:11:31
md5:2b4232deb271a6de2dd430f119270174
sha1:c5bf27f36fbdbc5487e275fd76ae8bc8e233081e

Java/文字コードメモ1  

所有者: msakamoto-sf    作成日: 2006-03-14 13:36:24
カテゴリ: Java 

Javaソースコード中に埋め込まれた文字列が、実際にコンパイルされると内部で本当にUTF-8になるのか確認してみる。
プラットフォームはWindowsXP + JDK 1.5

重要:Javaクラスファイル中のUTF-8についての追加情報を本文末に追記したので、そちらも必ず参照のこと。

SJISで記述→コンパイル

EncodingSJIS.java:
public class EncodingSJIS {
    public static void main(String[] args) {
        System.out.println("ShiftJISの日本語表示文字列です。");
    }
}
DOS> javac -encoding Shift_JIS EncodingSJIS.java
DOS> java -cp . EncodingSJIS
ShiftJISの日本語表示文字列です。

EUC-JPで記述→コンパイル

public class EncodingEUC {
    public static void main(String[] args) {
        System.out.println("EUC-JPの日本語表示文字列です。");
    }
}
DOS> javac -encoding EUC-JP EncodingEUC.java
DOS> java -cp . EncodingEUC
EUC-JPの日本語表示文字列です。 

クラスファイルの内部を見てみる。

拡張子を.txtにして(しなくとも良いが)、UTF-8に対応したエディタで文字コードをUTF-8で指定して開いてみる。

  • EncodingSJIS.class

画像/Java/java_charactercode_1_sjis.jpg

  • EncodingEUC.class

画像/Java/java_charactercode_1_euc.jpg

いずれも、文字コードがUTF-8としてエディタに認識され*1、実際に日本語文字列が読み込めている。

推察と追試験

以上より、 -encoding オプションをコンパイル時に指定することによりプラットフォームのデフォルトでない文字コードでも、クラスファイルコンパイル時にUTF-8に変換されて内部表現されることが分かった。

では、あえて-encodingで間違ったエンコーディングを指示するとどうなるか?
画像/Java/java_charactercode_1_plus.jpg

上図のように、コンパイル時に文字コードの検出で警告が表示されるが、クラスファイルは生成される。また、実行すると文字化けしていることが分かる。

実際にクラスファイルをエディタで開いてみると、下図のようになり、エディタの文字コードの自動認識も失敗していることが分かる。
画像/Java/java_charactercode_1_plus2.jpg

結論

  1. "-encoding" オプションによりソースコードの文字コードを明示してコンパイルできる。
  2. コンパイル時にUTF-8の内部表現に変換される。
  3. "-encoding" オプションで間違ったエンコーディングを指定した場合、文字コードで警告が出るがクラスファイルは生成される。ただし、内部表現では文字化けが発生する。

どうでもいいですが、文字コードとエンコーディングをもうちょっと意識して使い分けたいです。勉強しなくちゃ・・・。

Javaクラスファイル中のUTF-8について等

元々Javaクラスファイル中の文字列がUTF-8である、というのは、たまたまクラスファイルをsakuraエディタで開いてみた時、日本語部分がきちんと表示されたのがUTF-8で開いたときだったからと言う経験に基づいた推測にすぎなかった。

実際にJavaVM仕様書を見てみると、classファイル中での文字列はUTF-8で表現するよう記述されている。
この記事では最初からUTF-8であることが分かっていたような順番で書いてしまっているが、実際は先に経験上UTF-8で文字化けしないことが分かっており、その後仕様書で確認したところUTF-8で合っていた、という順序だった。

ただしUTF-8と表記されていても、classファイル中でのUTF-8は標準とは若干異なるエンコーディングになっている。

There are two differences between this format and the "standard" UTF-8 format. First, the null byte (byte)0 is encoded using the 2-byte format rather than the 1-byte format, so that Java virtual machine UTF-8 strings never have embedded nulls. Second, only the 1-byte, 2-byte, and 3-byte formats are used. The Java virtual machine does not recognize the longer UTF-8 formats.

The Unicode strings, despite the moniker "UTF-8 string", are not actually encoded according to the Unicode standard, although it is similar. There are two differences (see UTF-8 for a complete discussion). The first is that the codepoint U+0000 is encoded as the two-byte sequence C0 80 (in hex) instead of the standard single-byte encoding 00. The second difference is that supplementary characters (those outside the BMP at U+10000 and above) are encoded using a surrogate-pair construction similar to UTF-16 rather than being directly encoded using UTF-8. In this case each of the two surrogates is encoded separately in UTF-8. For example U+1D11E is encoded as the 6-byte sequence ED A0 B4 ED B4 9E, rather than the correct 4-byte UTF-8 encoding of f0 9d 84 9e.

ポイントとしては 標準のUTF-8ではなくUTF-8によく似ているが若干異なるエンコーディングを行っている点。U+0000のNULL文字など、VMSpecの方に詳細なコードポイントの範囲と変換方式が載っている。

BMP(=UCS-2)の外のコードポイントについての記述がVMSpecとWikipediaとで異なる点が気になる。
VMSpecの方では

Second, only the 1-byte, 2-byte, and 3-byte formats are used.
The Java virtual machine does not recognize the longer UTF-8 formats.

として、単に「認識せず」としか書かれていない。
UTF-8で3バイトまでの範囲となると U+0000 から U+FFFF までになるので、UCS-4でのBMP(=UCS-2)の範囲になり、JavaVM内部ではUnicode(UCS-2)の文字集合が使われている、という話と一応矛盾はしないが、Wikipediaの記述とずれがある。
Wikipedia側の記述:

The second difference is that supplementary characters (those outside the BMP at U+10000 and
above) are encoded using a surrogate-pair construction similar to UTF-16 rather than
being directly encoded using UTF-8.

これについては、WebのVMSpecの方が記述が古くなっているのが原因らしい。WikipediaのReferenceにはJSR202へのリンクがあるが、これが Java Class File Formatの最新版となっている。

こちらを確認したところ、

Characters with code points above U+FFFF (so-called supplementary characters)
are represented by separately encoding the two surrogate code units of their
UTF-16 representation.

としてU+10000以降のコードポイントの変換方法がきちんと掲載されている。Wikipediaの説明はこちらを参考にしていると思われる。

今回は「たまたま」通常のUTF-8と同じエンコードになる範囲の文字列だったため、sakuraエディタで開いて文字化けせずに済んだだけだったことが分かる。

http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html
上記VMSpecのドキュメントは、Web上でJavaVMの仕様を確認できる便利なページではあるが、今回のようにJSRの方で更新されている部分もあるため注意が必要かもしれない。


*1: エディタ画面右下部分参照

プレーンテキスト形式でダウンロード
現在のバージョン : 3
更新者: msakamoto-sf
更新日: 2015-02-08 00:11:03
md5:3cbb27b9f5a0d532bf0c86034d6df58c
sha1:6fd5f65e71251513ddf55bcf99305606059f2c84

日記/2015/02/07/Bloggerでプログラムソースコードのsyntaxハイライト(SyntaxHighlighter, Code Prettify)  

所有者: msakamoto-sf    作成日: 2015-02-07 19:20:10
カテゴリ: HTML 

SyntaxHighlighter:

Code Prettify:

SyntaxHighlighterでのトラブル:

SyntaxHighlighterの現在の開発はこちら:


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2015-02-07 19:25:13
md5:b60162e2d826d4b2874c1e91f777250e
sha1:6b5cdce93d748be67c55ef4a0f5a260b2ef75bc3

日記/2015/02/07/NetBeansでプロジェクトのバックグラウンドスキャンを止めるか無効化したい  

所有者: msakamoto-sf    作成日: 2015-02-07 18:01:53
カテゴリ: NetBeans 

結構なんとかしてほしい、と思ってる人が多いようだ。

が、どうもNetBeansの必須機能として、プロジェクトのバックグラウンドスキャンが必要らしく、無効化したり止めるような簡単なというか、NetBeans公式の方法は無いらしい。(唯一、プロジェクトをcloseしておけばOK、程度)

一応プラグインで自動的なバックグラウンドスキャンを無効化し、必要になった時だけ実行できるようにするプラグインもあるにはあるが、開発用ビルドでないと動かないとかなんとかで、普段使いには出来そうにない。(ので、試してもない)

2015年2月時点、NetBeans 8.0.2 まででの結論→諦める。


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2015-02-07 18:06:09
md5:1117029f55d8d71b5e331ebded7ff1b5
sha1:406d476fa47d793c7c744c3aff5086f76eb7e8a1

読書メモ/「起動プログラム ブート・ローダ入門」  

所有者: msakamoto-sf    作成日: 2015-02-07 17:48:54
カテゴリ: Assembler C言語 読書 

2009年頃までにだらだらと読んだ一冊。
複数のCPUアーキテクチャでのブートシーケンスについて説明し、ブートローダの開発で必要な知識をまとめてくれてる。

複数種類のアーキテクチャを扱っている分、それぞれのアーキテクチャについての解説は薄い。あくまでもブートローダをどうするか?という点に絞ったノウハウ書なので、必要に応じて読むタイプの本。
またその内容から、初心者や入門者を対象とはしておらず、組み込みシステムの開発経験を前提としている。

正直、この本が「勉強になった」というよりは、この本に関連した周辺知識を深めてくと、OSやカーネルレイヤーにも親しみやすくなるという一冊。

併せて読みたい:

あとブートローダで忘れちゃいけない一冊:

※これ、FreeBSDのブートプロセス解説したバージョンもあったんだけど、そちらはさすがに新装版は無いか・・・。


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2015-02-07 17:55:32
md5:cbfa1fe6f331fb0ae9ddb5420a751f04
sha1:ce6bcf96fbe9fa0f8b390d0db4c1cbc20221a3c3