takaiwa.net

Android、Java、Web系、Linux、マラソン等の備忘録

2012/01/17

DropboxのJava版APIで過去リビジョンのファイルを取得できない現象について

0 件のコメント

最近はソースや開発環境はDropbox配下に置き、マシンが変ろうともDropboxで同期させればおkということでなくてはならないDropboxですが、APIの正式版バージョン1が昨年10月に出たということで、使ってみました。

環境



  • Eclipse:Eclipse IDE for Java Developers Indigo Service Release 1

  • JDK:1.6.0_30

  • Dropbox SDKs:Java v1.2.2

WS000375

SDKと言いつつも、Javaに関して言えばjarファイルとソースが入っているだけなので、DropboxのサイトでAPP KEY/SECRETを入手して、jarをビルドパスに通してアクセストークンKEY/SECRETを入手すればDropboxへアクセスできます。

アクセストークン KEY/SECRETの取得はこちらを参考にしました。

・Dropbox Java API で遊ぶ - ザネリは列車を見送った
http://zaneli.hatenablog.com/entry/2011/12/10/123559

サンプルソース


Dropboxの魅力の一つとして、いくつか履歴を残してくれます。間違ってファイルを変更しても、履歴が残っている間なら復元が可能です。APIを使って過去リビジョンのファイルをダウンロードするサンプルソースを作成しました。test.txtファイルに関して変更した過去10件分のファイルをDropboxから取得しローカルへ保存するプログラムです。

public class GetOldFile {

private static final String APP_KEY = "あなたのAPPキー";
private static final String APP_SECRET = "あなたのAPPシークレット";

private static final String TOKEN_KEY = "あなたのアクセストークンキー";
private static final String TOKEN_SECRET = "あなたのアクセストークンシークレット";
/**
* @param args
*/
public static void main(String[] args) {
AppKeyPair appKeys =
new AppKeyPair(APP_KEY, APP_SECRET);
AccessTokenPair tokens =
new AccessTokenPair(TOKEN_KEY, TOKEN_SECRET);
WebAuthSession session =
new WebAuthSession(appKeys, AccessType.DROPBOX, tokens);
DropboxAPI<WebAuthSession> api =
new DropboxAPI<WebAuthSession>(session);

// Dropboxディレクトリ配下のパス
String path = "/develop/test.txt";

try {
// 10件分のファイル変更情報を取得
List<DropboxAPI.Entry> entries = api.revisions(path, 10);

for(DropboxAPI.Entry entry: entries) {
System.out.println(entry.modified + " - " + entry.rev);

FileOutputStream fos =
new FileOutputStream("D:/logs/" + entry.rev + ".txt", false);
// Dropboxよりリビジョンを指定してローカルへファイルを保存
api.getFile(path, entry.rev, fos, null);
fos.close();
}
} catch (DropboxException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}


ところが!ローカルに保存したファイルすべてが同じ内容でした。どれも最新版test.txt。Javadocを見ても、




・DropboxAPI
https://www.dropbox.com/static/developers/dropbox-java-sdk-1.2.2-docs/index.html




WS000376



getFileメソッドの使い方は間違っている気がしない。フォーラムで検索しようにも、英語でなんとキーワードを打てばよいのやら。。



ふと、SDK内のソースDropboxAPI.javaを開いてみました。



WS000377


getFileメソッドの中身はgetFileStreamメソッドが担っているということで、



WS000378



getFileStreamメソッド付近でパラメータの「rev」で検索すると、上図にもわかるようにヒットしない(青色マークされない)=実装されてない!ずこーー



実装後記



ということで、実装されるのを待ちましょうかね。iOS版の方には入っているみたいな記述をチラっと見たので、自分で中身を実装すれば取得できるかもしれませんが、少なくともJava版のこのバージョン1.2.2では、過去のファイルは取得できない作りということで。



あと、開発者が欲しがる機能として、Dropbox配下のファイルに変更があったらアプリ側に通知してくれるようなAPIがないそうです。もしくは、最近変更されたファイル一覧を取得できるAPI。フォーラムのある人によれば、ここは規模が小さいし実装おせーから仕方ねー。みたいなアドバイスもありましたw



じゃぁ、Dropboxへファイルを追加すると、メールを送ってくれたり、PDFに変更してくれたりするここのサービスは、どのように実装してるんでしょうかね?ファイルを総なめしてメタ情報を取得してるんでしょうか?




・Automate your Dropbox
http://dropboxautomator.wappwolf.com/




先日メールを飛ばすよう試してみましたが、思った動きをしませんでした。Dropboxを使ったアプリは開発者側にとってはまだまだ環境が揃っていないような印象を感じます。



ちなみに、変更履歴一覧は個人であれば取得できなくもありません。DropboxのWebサイトへログインして、



WS000380



イベントタブをクリック、ページの下の方に、



WS000381



「このフィードを購読」というRSSが配信されているので、このURLでXMLを解析等すれば変更情報を取得できますが、取得できもて10件~20件程度で、短期間に更新があっった場合は、



WS000382



こんな風にまとめられるので、扱い辛いです。



というわけで待ちましょうか。。


PR:仕事を便利にする!クラウド活用TIPS―いつでも、どこでも、クラウド仕事スタイル

2012/01/13

Eclipse系IDEのプロジェクトに手持ちの依存するライブラリ(JARファイル)を 追加

0 件のコメント

ある外部JARファイルをビルドパスに追加してそのJARファイルのクラスを使う処理を記述後、サーバを動かしてみると以下のようなエラーが。

org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: org/apache/thrift/transport/THttpClient


ビルドパスへ追加してコンパイル通ってるのに。。
と思っていましたが、mavenプロジェクトなので、そちらへ追加が必要のようです。



環境




・SpringSourceの公式サンプルをSTS上のサーバで実行する | とびこみ日記
http://takaiwa.net/archives/1029




この回で追加したmvc-basicとかmvc-ajaxの環境



[追加したいJARファイル]
・libthrift-1.0-SNAPSHOT.jar



プロジェクトの依存するライブラリを追加



Springsource tool suite(EclipseベースのIDE。以下STS)のプロジェクト上で右クリックし、[Maven] –> [Add Dependency]を選択。JARファイルのキーワード”thrift”と入力してみるも、検索にヒットしない。( ゚Д゚)?



WS000369
※画像はEclipse IDE for Java Developersのものです



セントラルリポジトリに存在しないのでダウンロードできないとの事。手動でローカル(ローカルリポジトリ)へ追加する必要がるものの、EclipseベースのIDEでGUI操作により追加する方法を探すも、見つからない。。



どうやらコマンドで入れろ的な事なので、しぶしぶコマンドで追加しました。




[参考]



・Eclipse 3.4.2とm2eclipseでMavenを使ったJavaのライブラリ管理 - public static void main
http://d.hatena.ne.jp/Kishi/20090228/1235813480





・Guide to installing 3rd party JARs
http://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html




mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> \
-DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=<packaging>


STSは入れたけど、mavenなんか入れてないぜ。。どこでコマンド打つんだとSTSのインストールディレクトリを探してたら、mvnがありました。



こんな感じのディレクトリ



D:\apl\springsource-tool-suite-2.8.1.RELEASE-e3.7.1-win32-x86_64\springsource\apache-maven-3.0.3\bin


コマンドプロンプトを起動して、cdコマンドで上記ディレクトリまで移動し、mvn install~のコマンドを実行すると、見事ローカルリポジトリへコピーされました。



D:\apl\springsource-tool-suite-2.8.1.RELEASE-e3.7.1-win32-x86_64\springsource\ap
ache-maven-3.0.3\bin>mvn install:install-file -Dfile="D:\lib\libthrift-1.0-SNAPSHOT.jar" -DgroupId=
org.apache.thrift -DartifactId=thrift -Dversion=1.0 -Dpackaging=jar
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-install-plugin:2.3.1:install-file (default-cli) @ standalone-po
m ---
[INFO] Installing D:\lib\libthrift-1.0-SNAPSHOT.jar to C:\Users\prog\.m2\repository\org\apache\thrift\thrift\1.0\thrift-1.0.jar
[INFO] Installing C:\Users\prog\AppData\Local\Temp\mvninstall6141724568259733641
.pom to C:\Users\prog\.m2\repository\org\apache\thrift\thrift\1.0\thrift-1.0.pom

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.704s
[INFO] Finished at: Fri Jan 13 00:03:59 JST 2012
[INFO] Final Memory: 3M/122M
[INFO] ------------------------------------------------------------------------


この時グループIDの記述が気に入らなかったので、mvnでinstallコマンド打てるのならアンインストールもできるだろと思ってましたが、ググれどググれど見つからず。。
(正確にはよくわからず。。)



エクスプローラでローカルリポジトリの場所まで行って直接Deleteしました。(上記コマンドは気に入る版です)
このままでは、STS上でAdd Dependencyをしても見つけてくれないので、認識してもらう作業を。
STS上のメニュー[Window] – [Show view] – [Other..]とたどります。その中にMavenのビューがあるので、選択して



WS000366




OKボタン押下。
Maven Repositoriesビューが表示されるので、



WS000367





ローカルリポジトリの所で、右クリック[Rebuild Index]を選択。



リビルドが始まるので少々待ちます。


WS000368



リビルドが終わると、


WS000370



先ほど追加したものが表示されてます。これをもって、プロジェクト上で、、[Maven] –> [Add Dependency]を選択し、”thrift”と入力すると



WS000371



見つける事ができました。これでOKボタンを押下し、冒頭で述べたサーバを起動させると「java.lang.NoClassDefFoundError」と言われる事なく動作させることができました。



Maven関連書籍,SpringによるWebアプリケーションスーパーサンプル 第2版

2012/01/09

Server Adaptorを使ってSpringsource tool suiteにJettyサーバを追加&その起 動スピードについて

0 件のコメント

Springsource tool suite(以下STS)上でTomcatサーバを起動させてWebアプリケーションの動作確認をしていると、とにかく起動が遅い(´ヘ`;) Jettyだったら一瞬で起動するのに。。

というわけで、STSにJettyを入れて起動させてみたいと思います。

まず、Jettyが必要になるわけですが、現時点で公開されているServer AdaptorがJettyバージョン6でないとダメのようで。。

・Downloading Jetty - Jetty - Codehaus
http://irc.codehaus.org/display/JETTY/Downloading+Jetty

WS000350

6で最新のjetty-6.1.26.zipをダウンロードします。ダウンロードが完了したら任意のディレクトリへ解凍しておきます。

次に、STSのServersビュー上で右クリック →  New → Server

ws000347

デフォルトではJettyのServer Adaptorは入っていないので、右上の「Download additional server Adaptors」リンクで追加します。

WS000349

そうすると、ダウンロード可能なServer Adaptorを探してくれるようですが、これが長い。。止まってんじゃないの?ってくらい長いですが、気長に待ってれば「Jetty Generic Server Adaptor」が表示されます。

WS000344

これを選択してNextボタンを押下するとダウンロードしてリスタートを要求されたはず。。。STSの再起動が終わると、再びServersビューより右クリック → New → Serverと選択します。今度は、「Jetty 6」というのが表示されているので、

WS000351

選択して、Nextボタンを押下します。

WS000353

Jetty Homeの場所を求められるので、パスをきってもいいですが、今回はBrowseボタンでディレクトリを設定しました。start.jarが入ってるディレクトリを選択します。でNextボタンを押下します。

WS000354

次の設定はデフォルトのもので良いので、Nextボタンを押下します。

WS000355

該当のプロジェクトを「Add >」 ボタンで追加してFinishボタンを押下します。そうすると、Serversビューに追加されます。
Serversビューのサーバースタートボタンを押して、Jettyを起動してみると。。

あれ!?起動が全然早くない(´o`;)


実際にどれくらいスピードが違うかというと、ざっくり計ってみました。左手にAndroidアプリのストップウォッチを表示させ、右手にServerスタートボタンに照準を合わせたマウスを持ち、同時に押し、Webアプリケーションがブラウザで表示できるようになった所でストップウォッチ止めました。

サーバ名 時間
Jetty 6 約25秒
Tomcat V7.0.22(直接DLしたもの) 約11秒
VMware vFabric tc Server Developer Edition (Runtime) v2.6 約11秒


Adapterで使うJetty全然遅いじゃないか。。せっかく入れたサーバですが、デバッグに使うにはちょっと厳しいですね。ちなみに、バージョンは違いますが、Eclipse IDE for Java Developersの環境に構築している埋め込みのJetty 8サーバは3秒で起動します(;-∀-) 埋め込んで使えって事ですね。。

一応、我が非力なPCのスペックは、

  • CPU:Celeron E3400 2.6GHz
  • メモリ:8GB
  • OS:Win7
  • 補助記憶装置:HDD 3.5inch 1TB 32MB 7200rpm
CPUをグレードアップさせ、補助記憶装置をSSDにすればスピードにストレスを感じなくなるでしょう。。結論はTomcatままで良かったということで。

メモ:CPU,内蔵型SSD

2012/01/07

Spring Frameworkでlog4jやAOPロギング

0 件のコメント

いろいろ試行錯誤したので、できた所までの覚え書き。

環境

  • SpringSource Toole Suite :2.8.1.RELEASE
  • JDK:1.6.0_30

実装のベース

Spring Frameworkへのロギングについてはググればいろいろ出てくると思いますが、今回試行錯誤したのはSpring Source公式サンプルの

・Samples | SpringSource.org
http://www.springsource.org/samples

「Spring Framework Samples」のmvc-ajaxプロジェクトへの実装。導入と動かし方等は過去の記事で。

log4j.xmlを操作してみる

まず、サーバを実行すると

WS000340

このようなログがコンソールへ出力されます。日付が入っていないので、試しに日付が出るようにlog4j.xmlを修正してみたいと思います。
ディレクトリで言うと、{保存先のディレクトリ}mvc-ajax\trunk\src\main\resources\log4j.xml

パッケージエクスプローラで言うと、src/main/resourcesに入っています。後は以下のように日付フォーマットを記述して

  <!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}%-5p: %c - %m%n" />
</layout>
</appender>


サーバを起動させると、日付が挿入されました。


WS000341




次にこれをファイルに出力してみます。これもlog4j.xmlへ以下を追加します。



    <appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="D:/logs/mvc-ajax.log" />
<param name="MaxFileSize" value="1024KB" />
<param name="MaxBackupIndex" value="10" />
<param name="Append" value="true" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d{yyyy/MM/dd HH:mm:ss} %p:%r:%c:%m%n" />
</layout>
</appender>


設定の詳細については、log4jのリファレンスにて。。D:/logs/mvc-ajax.logへログファイルが出力される設定です。このままではファイルは出力されないので、同ファイルのRoot Loggerへ1行追加します。



  <!-- Root Logger -->
<root>
<priority value="warn" />
<appender-ref ref="console" />
<appender-ref ref="FILE" />
</root>


これでサーバを起動すると、コンソールとファイルへlog4jのログが出力されます。



オリジナルのログを出力する



上記では、デフォルトで出力されるログについてですが、任意の場所で出力できるようJavaコードを修正してみたいと思います。動作を確認しやすいようにAccountController.javaを対象にします。importへorg.apache.log4j.Loggerを記述。インスタンス生成時とGetリクエストが呼ばれたタイミングでログを出力するようにしてみます。



public class AccountController {
private static Logger logger = Logger.getLogger(AccountController.class);

private Map<Long, Account> accounts = new ConcurrentHashMap<Long, Account>();

private Validator validator;

@Autowired
public AccountController(Validator validator) {
logger.info("create instance");
this.validator = validator;
}

@RequestMapping(method=RequestMethod.GET)
public String getCreateForm(Model model) {
logger.info("GET Request");
model.addAttribute(new Account());
return "account/createForm";
}


このままでは、エラーは出ませんが埋め込んだロギングを認識しません。log4j.xmlへorg.springframework.samples.mvc.ajax.account配下のクラスでログ出力するように以下の記述を追加します。



  <logger name="org.springframework.samples.mvc.ajax.account">
<level value="info" />
</logger>


これでサーバを起動したタイミングで、



2012-01-07 04:05:05 INFO : org.springframework.samples.mvc.ajax.account.AccountController - create instance



という出力や、クリックしたタイミングで、



WS000342



2012-01-07 04:05:36 INFO : org.springframework.samples.mvc.ajax.account.AccountController - GET Request



のように表示されます。



アスペクト指向(AOP)でロギングを自動的に埋め込む



コードをいじらなくても、AOPでメソッドの最初と終りにログを埋め込める魔法のようなやり方だと思ってましたが、なかなか一筋縄にいかず、とりあえずできた方法を掲載します。このmvc-ajaxというサンプルでなく、単にAOPの実装を動かしてみたい場合は、ググればもっと簡単なやり方があるのでそちらを。。



まず、mvc-ajaxはデフォルトでアスペクト指向を使えないので、mavenへdependencyを追加してやります。



mvc-ajaxのプロジェクト右クリック → Maven → Add Dependencyを選択します。



WS000343



aspectで検索かけると2件ヒットするので、2件とも追加します。



そして以下の3ファイルをorg.springframework.samples.mvc.ajax.accountへ追加します。




  • IHoge.java・・・・・・Hogehoge.javaのインタフェース。ロギングしたいメソッドを記述します


  • Hogehoge.java・・・・ロギングされるクラス。


  • MethodLogger.java・・Hogehoge.javaへ埋め込むロギング処理



せっかくベースとなるAccoutController.javaがあるのでそちらへロギングを埋め込もうとしましたが、エラーが出て実装できないのでHogehoge.javaへロギングを埋め込み、AccountControllerから呼び出す形でログを出力したいと思います。



IHoge.java



package org.springframework.samples.mvc.ajax.account;

public interface IHoge {
public void testMethod();
}


Hogehoge.java



package org.springframework.samples.mvc.ajax.account;

public class Hogehoge implements IHoge{

public void testMethod() {
System.out.println("hello world!");
}
}


MethodLogger.java



package org.springframework.samples.mvc.ajax.account;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Component
@Aspect
public class MethodLogger {

@Around("execution(* org.springframework.samples.mvc.ajax.account.Hogehoge.*(..))")
public Object timeMethod(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();

Logger.getLogger(this.getClass()).info("Method Start");

stopWatch.start();

Object retVal = joinPoint.proceed();

stopWatch.stop();

StringBuffer logMessageStringBuffer = new StringBuffer();
logMessageStringBuffer.append(joinPoint.getTarget().getClass().getName());
logMessageStringBuffer.append(".");
logMessageStringBuffer.append(joinPoint.getSignature().getName());
logMessageStringBuffer.append("(");
logMessageStringBuffer.append(joinPoint.getArgs());
logMessageStringBuffer.append(")");
logMessageStringBuffer.append(" execution time: ");
logMessageStringBuffer.append(stopWatch.getTotalTimeMillis());
logMessageStringBuffer.append(" ms");
logMessageStringBuffer.append(" end");

Logger.getLogger(this.getClass()).info(logMessageStringBuffer.toString());

return retVal;
}
}


この処理の、@Around("execution(* org.springframework.samples.mvc.ajax.account.Hogehoge.*(..))")でロギングを埋め込みたいメソッドを指定しています。今回はワイルドカードを使ってHogehogeクラス全てのメソッドへ適用するようにしています。で、処理開始と処理終了のロギングをObject retVal = joinPoint.proceed();の前後で行っている所がポイントです。この前後にLogger.getLogger(this.getClass()).info("Method Start");のようなメソッドの開始(または終了)だと分かる処理を記述してやります。



これらの処理をbeen定義ファイルで有効にするにはservlet-context.xmlを修正してやります。ちゃんと実装する場合には、このファイルではなく別途been定義ファイルを作成した方が良いような記述を見受けました。以下beansのタグ内とaopタグbeanタグを追加します。



<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

(中略)

<aop:aspectj-autoproxy />

<bean class="org.springframework.samples.mvc.ajax.account.Hogehoge" />

</beans>


で最後にAccountControllerからメソッド呼び出しの処理を追加します。今回はGetリクエスト処理内へ追加しました。



public class AccountController {
private static Logger logger = Logger.getLogger(AccountController.class);

private Map<Long, Account> accounts = new ConcurrentHashMap<Long, Account>();

private Validator validator;

@Autowired
private IHoge hoge;

@Autowired
public AccountController(Validator validator) {
logger.info("create instance AccountController");
this.validator = validator;
}

@RequestMapping(method=RequestMethod.GET)
public String getCreateForm(Model model) {
logger.info("GET Request AccountController");

this.hoge.testMethod();

model.addAttribute(new Account());
return "account/createForm";
}


private IHoge hogeを定義し、このインタフェースへロギング対象ということで@Autowiredを記述。Getリクエストを受けてthis.hoge.testMethod()のメソッドを呼び出しすよう修正しました。



これでサーバを起動し、



WS000342



クリックすると、メソッド呼び出しで以下のようにログが出力されます。



2012-01-07 04:48:40 INFO : org.springframework.samples.mvc.ajax.account.MethodLogger - Method Start

hello world!


2012-01-07 04:48:40 INFO : org.springframework.samples.mvc.ajax.account.MethodLogger - org.springframework.samples.mvc.ajax.account.Hogehoge.testMethod([Ljava.lang.Object;@4f13f501) execution time: 0 ms end




太字の部分が埋め込まれたロギング出力です。



AccountControllerクラスでHogehogeクラスをnewしてインスタンスを生成した場合だとロギングは埋め込まれません。必ずインタフェースからメソッドを呼び出す必要があります。これがSpring Frameworkの思想との事ですが、自由にロギングを追加/削除できるイメージでしたが、このやり方だとある程度最初からAOPを意識した実装にしておかないといけないですね。。(´ヘ`;)