Unleashed Memories

同じ疑問を抱く人はやはりいるのね。

https://stackoverflow.com/questions/8075373/file-separator-vs-filesystem-getseparator-vs-system-getpropertyfile-separato

コード上でファイルセパレータを取得するには
java.io.File.separator
java.nio.file.FileSystems.getDefault().getSeparator();
System.getProperty(“file.separator”)
のうち、どれを使えばいいのか、という話。

これから作るシステムなら
java.nio.file.FileSystems.getDefault().getSeparator();
でいいんじゃないかと私は思いました。

Unleashed Memories

Falling Satellites

Spring Frameworkについて2つほど.
基礎中の基礎で書くにも値しないけど,まぁ,それなりに触るのは初めてレベルなので.

1つめ.
@Scheduled アノテーション。
検索してみたところSpring Bootの事例が中心だったので、Spring Frameworkの方。
バージョンによるのかファミリーによるのか、とりあえず大元の設定ファイルであるところのservlet-context.xml。
これにフラットな設定ファイル、大抵の場合はapplication.propertiesが指定済なことが前提。
何の仕掛けもなしに書くとこんな感じ。

<beans:bean id=”applicationProperties” class=”org.springframework.beans.factory.config.PropertiesFactoryBean”>
<beans:property name=”locations”>
<beans:list>
<beans:value>classpath:application.properties</beans:value>
/beans:list>
</beans:property>
</beans:bean>

application.propertiesに
cron.expression=0 */1 * * * *
とか記述。
cronの表現そのまんまでよい。
んで、.javaソースの方は
@Scheduled(cron = “${cron.expression}”)
を指定してやる。

2つめ
@Autowired アノテーション。
当然ながら突然指定しても期待通りの動きをしない。
というかNullPointerException がthrowされる。
Spring Frameworkから直接起動されるクラスから他の処理クラス、簡単に言えばControllerクラスからDAOクラスなりBLクラスを呼び出す際、処理クラスのインスタンスをnewで取得してはダメ。
これらも@Autowired アノテーションで定義しておき、それを参照してインスタンスを取得する。
簡単に書けばチェインしていけばよい。
もうちょっと書くと呼び出し元クラスの@Autowired アノテーションはservlet-context.xmlで定義されたものだけど、newで呼び出し先のインスタンスを取得してしまうとFrameworkは何をバインドすればよいのかわからない。
上記の例に従って、application.propertiesを例にすると呼び出し元クラスで@AutowiredされたBeanはSpring Framework起動の際に読み込んだもの。
但し、newすると新しいインスタンスがJVMによって生成されるため、そのインスタンスに紐付くapplication.propertiesは存在しない(Framework側からはわからない)ため、nullとなる。
ちょっとあやふやな文章だけど、つまり以下の通り。
https://stackoverflow.com/questions/19896870/why-is-my-spring-autowired-field-null
https://code.i-harness.com/en/q/12f9a26
機械翻訳:https://code.i-harness.com/ja/q/12f9a26

これでなるほど、と思ったわけで。

2つめと同じだけど、SpringFrameworkの@Transactional アノテーションについても、いきなりBL層で指定しても動作しない。
Frameworkから呼び出されるクラスから順次@Autowired アノテーションで呼び出し、呼び出される側は@Serviceなり@Coponentアノテーションを指定しておく。
また、@Transactional アノテーションはpublicメソッドじゃないと意味がないのでこれも注意。
基本的にリフレクションで動かしてるから、というのが私の理解。

Falling Satellites

Monday Morning Apocalypse

java JapaneseImperialCalendarというprivateクラスがSE6から追加になり、これで和暦を扱える(明治とかは怪しいらしいが)ようになっていたtとということを知った。
んで、今の仕事で和暦を扱うシーンがあったので、自前で実装していたら、上記クラスを使えというレビューでの指摘。
元号が変わったら処理を追記しなければならないというのが理由。
でも、上記のクラス使うと同じ条件の場合、JREの,というかJREのプロパティファイルの更新が必要になるんだけど、いいのかね?
まぁ、面倒だからしたがっておくけど。

Ravenheart

今までJavaからアクセスする対象といえばDBが主だったわけですが,今回はLDAPやADなんてのが多く,わからないことも多く.
これもそんなオハナシ

Microsoftの,というかWindowsのActive Directoryでは一度にサーチできる件数の上限が1000件と決まっているらしい.
M$曰く,想定外のアクセスやネットワークトラフィックを抑制するためのセイフティみたいなもんらしい.
ただ,処理によってはこれを超えて取得したい状況もあるわけで,今回はそれに該当しました.
まぁ,バッチ処理だからね,そういう無茶なこともあるさ.

んで,解決方法を模索してみたのだけど,なんかイマイチピンとくる手段がない.
NetWareだかがOpenLDAPに寄贈したドライバ使えばこの上限を外せるらしいんだけど,なんかなぁ・・・
結局原始的ながら,おそらくは応用も効くであろうPagingを使った処理と相成った.
まぁ,Javaの公式フォーラムで紹介されている方法なので,割合この手の実装に落ち着いた人もいるのではないかと推測.
フォーラムはココ

class paged {
public static void main(String[] args) {
Hashtable env = new Hashtable();
String adminName = “CN=Administrator,CN=Users,DC=antipodes,DC=com”;
String adminPassword = “XXXXXXXX”;
String searchBase = “DC=antipodes,DC=com”;
String searchFilter = “(&(objectClass=user)(mail=*))”;

env.put(Context.INITIAL_CONTEXT_FACTORY,”com.sun.jndi.ldap.LdapCtxFactory”);

//set security credentials, note using simple cleartext authentication
env.put(Context.SECURITY_AUTHENTICATION,”simple”);
env.put(Context.SECURITY_PRINCIPAL,adminName);
env.put(Context.SECURITY_CREDENTIALS,adminPassword);

//connect to my domain controller
env.put(Context.PROVIDER_URL, “ldap://mydc.antipodes.com:389”);
try {
// Create the initial directory context
LdapContext ctx = new InitialLdapContext(env,null);

// Create the search controls
SearchControls searchCtls = new SearchControls();

//Specify the attributes to return
String returnedAtts[]={“sn”,”givenName”,”mail”};
searchCtls.setReturningAttributes(returnedAtts);

//Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

//Set the page size and initialize the cookie that we pass back in subsequent pages
int pageSize = 500;
byte[] cookie = null;

//Request the paged results control
Control[] ctls = new Control[]{new PagedResultsControl(pageSize)};
ctx.setRequestControls(ctls);

//initialize counter to total the results
int totalResults = 0;

// Search for objects using the filter
do {
NamingEnumeration results = ctx.search(searchBase, searchFilter, searchCtls);

// loop through the results in each page
while (results != null && results.hasMoreElements()) {
SearchResult sr = (SearchResult)results.next();
//print out the name
System.out.println(“name: ” + sr.getName());

//increment the counter
totalResults++;
}
// examine the response controls
cookie = parseControls(ctx.getResponseControls());
// pass the cookie back to the server for the next page
ctx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, cookie,                Control.CRITICAL) });

} while ((cookie != null) && (cookie.length != 0));
ctx.close();
System.out.println(“Total entries: ” + totalResults);
} catch (NamingException e) {
System.err.println(“Paged Search failed.” + e);
} catch (java.io.IOException e) {
System.err.println(“Paged Search failed.” + e);
}
}

static byte[] parseControls(Control[] controls) throws NamingException {
byte[] cookie = null;
if (controls != null) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl)controls[i];
cookie = prrc.getCookie();
System.out.println(“>>Next Page \n”);
}
}
}
return (cookie == null) ? new byte[0] : cookie;
}
}

まるまる引用というのもどうかと思うが,まぁ,情報の冗長化だ.
が,インデントが全部壊れちゃうんだな・・・
一番面倒だったのは,JavaでWhile文を使う機会なんぞほとんどなかったので,それを飲み込むことだったかもしれない.
あと,上記のコードでは書かれていないが,NamingEnumerationは最後にはクローズしてやること.
私も今回はやってしまっていたのだが,NamingEnumerationは単なるListではなくてコネクションを保持しているので,使い終わったらクローズしておいてやらないと,そのうちGCの対象になってしまう.

Bridge Across Forever

たまにはエンジニアらしいことを.
てか,このトシでコード書く立場ってあんまりないと思うけど.

単発で動作させると問題のないJavaでコーディングしたバッチ処理.
HP-UX(これ旧環境)上で5多重のジョブとして動作させても問題はでなかったらしい.
# この時は立ち会っていませんでした.
しかし,新環境であるRHEL(厳密はは違うが,まぁ,同じだ)で10多重で動作させるとOracleへのコネクションタイムアウトが発生するという事象.
また,設計の段階から1本の処理から複数のコネクションを取得可能なような方式にはしていないので,これが悪さをしているのか,とか思ったけど,ジョブ毎にインスタンスが違うので,リソースの取り合いとかっつーわけでもない.

結論としては,Java1.5から発生してるんだか,表面化したバグらしいんだけど,バグではないよ,という結論になっているワケのわからん状態.
とりあえず回避方法としては実行時に以下のオプションを指定しろということらしい.

-Djava.security.egd=file:/dev/./urandom

まぁ,環境変数に指定する方が現実的だろう.
今回の仕事ではOracleへのアクセスがほとんどないので,上記の対応となった.
また,なぜか”dev/urandom”ではダメなので注意のこと.
一応Windows上では発生しないことになっていて,Linux上で発生する事象らしい.
上記の内容をそのまま当てはめるとHP-UXみたいな,言ってみればネイティブなUnix環境でも発生しないのかもしれない.
以下のエントリーで本事象の解決となったので,リンクを提示しておく.
LinuxサーバからOracle JDBC接続するとEnd of TNS data channelやConnection resetが発生する場合の対処法