JavaでSCP
とりあえずやってみたってだけで、あってるかは不明。
ちゃんと使うには、もっと中身を覗いていかないとだめかも。
ライブラリ
ganymed-ssh-2 というのを使ってみる。
https://code.google.com/p/ganymed-ssh-2/
バージョンは(Mavenであがってた)262というもの。
ドキュメントがあまりなさそう(古いのはリソースがけっこうある?)で、妄想だけで作ってくのは辛いです・・・
サンプル
public static void main(String[] args) { Connection conn = null; try { conn = new Connection("xxx.xxx.xxx.xxx"); conn.connect(); boolean auth = conn.authenticateWithPassword("hoge", "foo"); if (!auth) { System.err.println("auth error."); return; } File file = new File("C:/tmp/sample.txt"); SCPClient scp = conn.createSCPClient(); try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); SCPOutputStream out = scp.put(file.getName(), file.length(), "/home/hoge/", null);) { IOUtils.copy(in, out); // Commons IOを使う手抜き } } catch(IOException e) { e.printStackTrace(); } finally { if (conn != null) { conn.close(); } } }
ConnectionクラスはAutoCloseableを実装してない・・・Java7からだしね・・・
Spring Batchでエラー時だけ特定の処理をする設定
こんな感じ?
<batch:job id="testJob"> <batch:step id="test1"> <batch:tasklet ref="hogeTasklet" /> <batch:end on="*" /> <!-- 次のstepがある場合は以下 <batch:next on="*" to="test2" /> --> <batch:next on="FAILED" to="errorStep" /> </batch:step> <batch:step id="errorStep"> <batch:tasklet ref="errorTasklet" /> </batch:step> </batch:job>
でも、今後stepが増えた際に、すべてのところでこういう風に書くのめんどいような。
StepListener使ったほうがいいのかなー。
ジェネリクスむずかしい
ちょっと悩んだメモ。
あくまでイメージコード
public void hoge1(List<? extends Serializable> list) { // List<List<? extends Serializable> では受け取れない List<?> list2 = foo(list); } public void hoge2(List<String> list) { List<List<String>> list2 = foo(list); } public <T extends Serializable> void hoge3(List<T> list) { List<List<T>> foo = foo(list); } public <T> List<List<T>> foo(List<T> list) { List<List<T>> result = new ArrayList<>(); result.add(list); return result; }
何を悩んだのかというと
インタフェースの定義としてどちらにしておくべきなのか?
public interface Foo { void hoge(List<? extends Serializable> list); <T extends Serializable> void hoge(List<T> list); }
使う側からすれば変わらないような気がするけど・・・
これだと使う側に影響はある
なので意味はある。
public interface Foo { List<? extends Serializable> bar1(List<? extends Serializable> list); <T extends Serializable> List<T> bar2(List<T> list); }
public void use() { Foo foo = ・・・ List<String> list = new ArrayList<>(); // List<String>で受けられない List<? extends Serializable> bar1 = foo.bar1(list); // List<String>で受けられる List<String> bar2 = foo.bar2(list); }
bar1は、引数の?と戻り値の?が一緒の型であるって定義はしていない・・・から?
riak-java-clientを使う
RiakにJavaからアクセスするためのライブラリ https://github.com/basho/riak-java-client
をちょっと触ったのでメモ。
LowレベルとHighレベルの2種類のAPIがあるけど、今回は手軽に試せるHighレベルの方で。
つっこむデータの定義
アノテーションで色々指定できる。
IDはアノテーションでなくても指定するインタフェースがあるけど、とりあえずお試しなので。
デフォだとJSON形式で保存されて、マッピングなどは勝手にやってくれる。
基本的な型だったりネストとかしても、とりあえず大丈夫。
public class User { @RiakKey // Key public String id; @RiakIndex(name = "age") // Secondary Index public long age; @RiakLinks // Link public Collection<RiakLink> links; }
処理
色々とはしょってるけど、まぁイメージってことで。
IRiakClient client = null; try { client = RiakFactory.pbcClient("host", port); Bucket bucket = client.fetchBucket("test").execute(); User user = new User(); // ・・・略 bucket.store(user).execute(); // 1件取得 User fetchUser = bucket.fetch("1000", User.class).execute(); // 複数件取得 List<MultiFetchFuture<User>> list = bucket.multiFetch(Arrays.asList(new String[]{"1000", "1001"}), User.class).execute(); // indexで取得 List<String> ids = bucket.fetchIndex(IntIndex.named("age_int")).from(30).to(50).execute(); } catch (Exception e) { e.printStackTrace(); } finally { client.shutdown(); }
HiveのmetastoreにPostgreSQLを使う
とりあえず試しにやってみただけメモ。
よくわからずやってるので、無駄なものとかあるかも。
手順
- PostgreSQLを入れて、よしなに設定する。
- Hiveについてくるscripts/metastore/upgrade/hive-schema-x.x.x.postgres.sqlを流す。
- hive/lib にPostgreSQLのJDBCドライバのjarファイルを入れる。
- hive-site.xmlを修正する。
<property> <name>hive.metastore.local</name> <value>true</value> </property> <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:postgresql://xxx:5432/xxx</value> </property> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>org.postgresql.Driver</value> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>xxx</value> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>xxx</value> </property>
で、、、
なんとなく設定できたみたいなんだけど、hive上で「show tables;」とやるとエラーが出る。
create tableやselectなどは問題なし。
エラーはこんな感じ
ERROR exec.FetchTask (SessionState.java:printError(365)) - FAILED: Error in metadata: MetaException(message:Got exception: javax.jdo.JDODataStoreException Error executing JDOQL query "SELECT "THIS"."TBL_NAME" AS NUCORDER0 FROM "TBLS" "THIS" LEFT OUTER JOIN "DBS" "THIS_DATABASE_NAME" ON "THIS"."DB_ID" = "THIS_DATABASE_NAME"."DB_ID" WHERE "THIS_DATABASE_NAME"."NAME" = ? AND (LOWER("THIS"."TBL_NAME") LIKE ? ESCAPE '\\' ) ORDER BY NUCORDER0 " : ERROR: エスケープシーケンスが無効です ヒント: エスケープ文字は空か1文字でなければなりません。.) org.apache.hadoop.hive.ql.metadata.HiveException: MetaException(message:Got exception: javax.jdo.JDODataStoreException Error executing JDOQL query "SELECT "THIS"."TBL_NAME" AS NUCORDER0 FROM "TBLS" "THIS" LEFT OUTER JOIN "DBS" "THIS_DATABASE_NAME" ON "THIS"."DB_ID" = "THIS_DATABASE_NAME"."DB_ID" WHERE "THIS_DATABASE_NAME"."NAME" = ? AND (LOWER("THIS"."TBL_NAME") LIKE ? ESCAPE '\\' ) ORDER BY NUCORDER0 " : ERROR: エスケープシーケンスが無効です ヒント: エスケープ文字は空か1文字でなければなりません。.)
原因は、PostgreSQL 9.1からstandard_conforming_stringsの設定がoffからonに変わったためのよう。
http://www.postgresql.org/docs/9.1/static/release-9-1.html
postgresql.conf を変更したらエラーは出ないようになったけど、色々と不安だらけだ・・・
今が年の何週目か
ある日がその年の何週目かということについて。
というよりかは、年の1週目っていつよ?ってお話。
まずはISO8601の定義。
- D は曜日を表し、月曜日が 1、日曜日は 7 である。
〜略〜
- ある年における、「最初の木曜日を含む週が、その年の第1週である。」と規定されている。
これはJIS X 0301にも例示されている通り、
- 「第1週は事実上、1月4日を含む週である。」という基準認識に等しい。
- 年初において以下の曜日に該当する場合、その日は新年の曜日としては扱わず、あくまで旧年最終週の曜日として扱う、という事を意味する。
- 1月1日金曜日・1月2日土曜日・1月3日日曜日
曜日は月曜日からで、1/4を含む週が1週目になるとのこと。
で、Javaのドキュメント。
WEEK_OF_YEAR フィールドに対して計算される値の範囲は、1 から 53 です。年の第 1 週は、その年から少なくとも getMinimalDaysInFirstWeek() 日を含む getFirstDayOfWeek() で始まるもっとも早い 7 日間です。このように第 1 週は getMinimalDaysInFirstWeek()、getFirstDayOfWeek() の値、および 1 月 1 日の曜日により変化します。ある年の第 1 週から翌年の第 1 週までの週は、必要に応じて 2 から 52 または 53 まで順に番号が付けられます。
http://java.sun.com/javase/ja/6/docs/ja/api/java/util/GregorianCalendar.html
とうわけで、このようにする必要がある?
Calendar calendar = new GregorianCalendar(); calendar.setMinimalDaysInFirstWeek(4); calendar.setFirstDayOfWeek(Calendar.MONDAY); calendar.set(2010, Calendar.JANUARY, 1); System.out.println(calendar.get(Calendar.WEEK_OF_YEAR)); →53
めんどくさい・・・