SyntaxHighlighter

2011年2月13日日曜日

root化しました

昨年の6月ぐらいからHTC Desire (X06HT)を使っていたんですが、とうとうroot取得しました。

スマートフォンは最初の1台目で、もし壊れてしまうと致命的となるんで、保証対象外となるroot化はせずにいたんですが、とうとう知的欲求に勝てず、root化に踏み切ってしまいました。

goldcardの手法は、SDカードを用意するとかなにやらめんどくさかったので、unrevoked3を利用してroot化に成功しました。

以下、簡単に手順を残しておきます。
  1. 本体のUSB接続モードを「USBデバッグ」(「設定」→「アプリケーション」→「開発」の画面からチェックを入れる)にする
  2. リカバリモード(HOMEボタン+電源ON)で起動し、PCにUSBで繋ぐ
  3. PCのHTC Syncをアンインストールし、PCにドライバーを入れ直す
  4. 本体をPCから外し、本体を再起動する
  5. unrevoked3をダウンロードし、reflasher.exeを実行する
  6. リカバリーモードで再起動&通常の再起動が何回か行われ、以下の画面のようになれば終了です。
      成功していれば、アプリ一覧に「Superuser Permissions」という忍者アイコンのアプリが追加されます。
    意外なほどあっけなくroot化してしまいました。

    助長する訳ではないんですが、スマートフォンなんてPCと同じだと考えると、PCが壊れたら基本保証なんてないわけで、かつカーネルの再コンパイルやレジストリをいじって使いやすくするなどの普段やっていることとあまり変わらない気がしてます。

    さて、これからようやく本格的にAndroidをいじってみようと思います。

    2011年1月31日月曜日

    Eclipseの起動時にInitializing Java Toolingがいつまでたっても終わらない場合の対処法

    Eclipseの起動時にInitializing Java Toolingが1%のままで、いつまでたっても終わらない場合があります。

    Eclipseに-cleanオプションをつけたり、何度か起動を繰り返すうちにうまく動作するようになったりするする場合もありますが、このInitializing Java Toolingがハングする現象は、ワークスペースでオープンしているプロジェクト数が多い場合に発生するようです。

    どうにもならない場合、workspaceの.metadataフォルダを削除して初期化すれば良いのですが、プラグインの設定も削除されてしまいますので、プロジェクトに関する情報だけ削除(.metadata/.plugins/org.eclipse.core.resourcesフォルダの下にあるファイルを全て削除)し、Eclipseを起動してから必要なプロジェクトをインポートすれば、比較的被害は少なくて済みます。

    でも、基本的には、必要なプロジェクトだけを開いて作業するようにしましょう。

    2011年1月30日日曜日

    CASのJASPIC(JSR-196)モジュール

    先日の「GlassFishでCasLoginModuleを動かしてみた」のエントリーのあと、JASPIC(JSR-196)のモジュールを作ってみました。

    http://code.google.com/p/cas-jaspic/

    とりあえず、HTTP profileのみで、SOAP profileについては現在調査中です。
    加えて、GlassFishでしか動作確認しません。(JBossに関しては、メッセージエクスチェンジをするとエラーと判断されるようで、動作しません。orz)

    まだプロジェクトの運営自体こなれてませんが、何かご意見があれば、コメントお願いします。

    2011年1月20日木曜日

    JSFのManagedBeanをFacesContextから取得する

    前回は、「いにゃの場合: BeanManagerからManagedBeanを取得する」でCDIのManagedBean取得を説明したが、今回はFacesContextからJSFのManagedBeanを取得する方法をメモしておきます。

    前回と同じManagedBeanを例として考えると、

    package sample;
    import java.util.Date;
    import javax.enterprise.context.RequestScoped;
    import javax.inject.Named;
    
    @RequestScoped
    @Named("test1")
    public class TestBean1 {
     public Date getDate() {
      return new Date();
     }
    }
    

    こんな感じ

    FacesContext ctx = FacesContext.getCurrentInstance();
    ELContext context = ctx.getELContext();
    ELResolver resolver = context.getELResolver();
    TestBean1 bean = (TestBean1)resolver.getValue(
      context, null, "test1");
    

    JSFではなくJSPのpageContextを利用する場合、以下のようにELContextを取得すればOKです。
    ELContext context = pageContext.getELContext();
    

    resolver#getValueの第2引数は、ベースのオブジェクトを指定します。
    beanのプロパティ"date"を取得するのであれば、以下のようにします。

    Date date = (Date)resolver.getValue(context, bean, "date");
    

    BeanManagerからManagedBeanを取得する

    CDI(JSR-299)を利用すれば、ServletやJSFのManagedBean、EJBなどにコンテナがDIしてくれるけど、DIではなく、直接CDIで管理しているManagedBeanを取得する方法をメモしておきます。

    これを知っていると、DIできないコンポーネントでManagedBeanを利用(例えば、JSFやJSPのスクリプトレット内)できたりします。

    例として、以下のようなManagedBeanがあったとします。

    package sample;
    import java.util.Date;
    import javax.enterprise.context.RequestScoped;
    import javax.inject.Named;
    
    @RequestScoped
    @Named("test1")
    public class TestBean1 {
     public Date getDate() {
      return new Date();
     }
    }
    

    これを以下のように取得する。

    InitialContext ic = new InitialContext();
    BeanManager manager =
      (BeanManager)ic.lookup("java:comp/BeanManager");
    
    Set<Bean<?>> beans = manager.getBeans(
      TestBean1.class,
      new AnnotationLiteral<Default>() {});
    
    Bean<?> bean = manager.resolve(beans);
    TestBean1 obj = (TestBean1)manager.getReference(
      bean,
      TestBean1.class,
      manager.createCreationalContext(bean));
    

    9行目のresolveは、5行目でBeanが1つに絞られているからできるのであり、もし絞られていないようであれば、5行目で取得したSet<Bean<?>>をQualifierやNameから要求にあったBeanを取得してgetReferenceを行えば良いです。

    また、EL名で取得したい場合は、5行目を
    Set<Bean<?>> beans = manager.getBeans("test1");
    
    のようにすれば良いです。

    2011年1月17日月曜日

    GlassFishでCasLoginModuleを動かしてみた

    CASのJAASモジュールであるCasLoginModuleをGlassFishで動かしてみました。

    CASのticketは1度しかバリデーションできない(あたりまえか)ので、セッションが利用できないrealmではオブジェクト(この場合、ticketなど)を保持できないので、全てのアクセスで同じticketを使いまわす→2回目以降のバリデーションでエラーになると思われる。
    ProgrammaticLoginとか、HttpServletRequest#login(V3.0~)もrealmを利用するので、LoginContextで取得したSubjectを解析し、Assertionとかを取得して制御するようにしてみた。
    JBossやTomcat用のintegrationモジュールも似たことやってるし、それを参考に作ってみた。

    1. CAS Clientのjarファイルをコンテナに配備
      • cas-client-core-3.1.xx.jar
      • commons-logging-1.1.jar
      これを${com.sun.aas.instanceRoot}/lib/extとかにおいておく。
    2. ログイン構成ファイルにcasのLoginModuleを登録する
    3. デフォルトでは、${com.sun.aas.instanceRoot}/config/login.confというのがログイン構成ファイルで指定してあるので、そこに以下のエントリを追加する。
      cas {
        org.jasig.cas.client.jaas.CasLoginModule required
        ticketValidatorClass="org.jasig.cas.client.validation.Cas20ProxyTicketValidator"
        casServerUrlPrefix="http://localhost/cas-server"
        defaultRoles="";
      };
      詳しくは以下のjavadocに書いてあります。 http://www.jarvana.com/jarvana/view/org/jasig/cas/client/cas-client-core/3.1.11/cas-client-core-3.1.11-javadoc.jar!/org/jasig/cas/client/jaas/CasLoginModule.html ※defaultRolesはoptionalと書いてあるけど、何も指定していないとNPEになります。 上記の設定ができたら、GlassFishを再起動します。
    4. フィルターを作成する
    5. /**
       *
       */
      package test;
      
      import java.io.IOException;
      import java.security.GeneralSecurityException;
      import java.security.Principal;
      
      import javax.security.auth.Subject;
      import javax.security.auth.login.LoginContext;
      import javax.servlet.FilterChain;
      import javax.servlet.ServletException;
      import javax.servlet.ServletRequest;
      import javax.servlet.ServletResponse;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletRequestWrapper;
      import javax.servlet.http.HttpServletResponse;
      import javax.servlet.http.HttpSession;
      
      import org.jasig.cas.client.jaas.AssertionPrincipal;
      import org.jasig.cas.client.jaas.ServiceAndTicketCallbackHandler;
      import org.jasig.cas.client.util.AbstractCasFilter;
      import org.jasig.cas.client.util.CommonUtils;
      import org.jasig.cas.client.validation.Assertion;
      
      /**
       * @author hisato
       * 
       */
      public final class WebAuthenticationFilter extends AbstractCasFilter {
      
       public class WebAuthenticationRequestWrapper extends
         HttpServletRequestWrapper {
      
        private Principal principal = null;
      
        /**
         * @param request
         */
        public WebAuthenticationRequestWrapper(HttpServletRequest request,
          Principal principal) {
         super(request);
         this.principal = principal;
        }
      
        /*
         * (non-Javadoc)
         * @see javax.servlet.http.HttpServletRequestWrapper#getUserPrincipal()
         */
        @Override
        public Principal getUserPrincipal() {
         return this.principal;
        }
       }
      
       public static final String CONST_CAS_LAST_TICKET = "_const_cas_last_ticket_";
      
       public static final String CONST_CAS_LOGIN_SUBJECT = "_const_cas_login_subject_";
      
       /*
        * (non-Javadoc)
        * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
        * javax.servlet.ServletResponse, javax.servlet.FilterChain)
        */
       @Override
       public void doFilter(ServletRequest servletRequest,
         ServletResponse servletResponse, FilterChain chain)
         throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpSession session = request.getSession();
        if (session != null) {
         String ticket = CommonUtils.safeGetParameter(request,
           getArtifactParameterName());
         Assertion assertion = (Assertion) session
           .getAttribute(CONST_CAS_ASSERTION);
         AssertionPrincipal principal = null;
         if (assertion != null) {
          request = new WebAuthenticationRequestWrapper(request,
            assertion.getPrincipal());
         }
         if (ticket != null
           && !ticket.equals(session
             .getAttribute(CONST_CAS_LAST_TICKET))) {
          try {
           String service = constructServiceUrl(request, response);
           LoginContext lc = new LoginContext(
             "cas",
             new ServiceAndTicketCallbackHandler(service, ticket));
           lc.login();
           Subject subject = lc.getSubject();
           for (Principal p : subject.getPrincipals()) {
            if (p instanceof AssertionPrincipal) {
             principal = (AssertionPrincipal) p;
             break;
            }
           }
           if (principal != null) {
            session.setAttribute(CONST_CAS_LOGIN_SUBJECT,
              subject);
            session.setAttribute(CONST_CAS_ASSERTION,
              principal.getAssertion());
            session.setAttribute(CONST_CAS_LAST_TICKET, ticket);
            request = new WebAuthenticationRequestWrapper(request,
              principal);
           } else {
            throw new GeneralSecurityException(
              "Web authentication did not produce CAS AssertionPrincipal.");
           }
          } catch (GeneralSecurityException e) {
           response.sendError(HttpServletResponse.SC_FORBIDDEN,
             e.getMessage());
          }
         }
         if (request.getUserPrincipal() == null) {
          session.removeAttribute(CONST_CAS_LOGIN_SUBJECT);
          session.removeAttribute(CONST_CAS_ASSERTION);
          session.removeAttribute(CONST_CAS_LAST_TICKET);
         }
        }
        chain.doFilter(request, response);
       }
      }
      
    6. アプリケーションにフィルターを設定する

    クラスローダーは子を優先するようにしておく必要がありました。
    1.をスキップして、casのjarファイルをアプリケーションに放り込んでおけば、クラスローダーの設定はどっちでも良いようです。

    とりあえず、コンテナー依存のコードはないので、GlassFish以外でも多分動くと思われます。

    でも、UserPrincipalと、デフォルトロールのマッピングぐらいしかできないです。
    (配備記述子で設定したグループとロールのマッピングはやってくれるはずがないw)

    まぁ認証(Authorization)だけならこれでもいいけど、承認(Authentication)をちゃんとやるなら、JSR-196でメッセージ認証を実装した方がいい気がします。

    そのうち作ってみます~。

    2011年1月13日木曜日

    Blogaway

    Bloggerに引越ししたので、携帯(Android)からも投稿できるようにBlogawayというアプリケーションをインストールしてみた。

    使いやすいんだけど...Draftが編集できない...。

    どうもPCで編集したDraftがアプリから編集できないようだ。
    せっかく携帯から投稿できるように引っ越したのに...でも、他のアプリに比べて使いやすそうなので、まぁしょうがないか。

    アプリの評価に対応希望とコメントしておこうかな。

    SyntaxHighlighterを導入してみた

    早速Bloggerをカスタマイズしてたんだけど、コードとか綺麗に表示したくてSyntaxHighlighterを導入したみた。

    ダウンロードしたスクリプトとCSSをアップロードして...といっても、アップロードするところがないので、スクリプトとスタイルを1つにまとめてデザインからガジェット(HTML/JavaScript)を追加してみた。

    package sample;
    
    public class TestClass {
      public String echo(String msg) {
        return msg;
      }
    }
    

    まぁこんな感じ。

    2011年1月9日日曜日

    トランザクションの厳密さについて考えてみた

    今月からお仕事で新しいプロジェクトに就く予定です。

    要求というか、プロジェクトで目指すものについても、関係者それぞれのイメージが全く違っている状態なので、そもそもこのプロジェクトを開始して良いものかと悩むところです。

    少なくとも、今までの経験上、嫌な感じのするプロジェクトですわ~orz

    で、今のところ、うちの会社のワークフロー・エンジンをベースにヒューマンタスクを制御するエンジンを目指す予定なのですが、EJBとJPAを利用したものを...と思っていたんですが、昨今のクラウド事情で、ここ数日GAE上に展開できるかを検討してました。
    特にスケーラビリティに関しては、元々のワークフロー・エンジンに限界があるのが分かっていましたので、どうにかならないかと思ってGAEの勉強していたんですが、結構面白いですねぇ。

    BASEトランザクションという考えが今までの非クラウドアプリケーションにない考え方で、いままでACIDでどうやって整合性を保つかという側面でしか考えていなかったので、すごく新鮮でした。
    • Basically Available
    • Soft-State
    • Eventual Consistency
    BASEトランザクションについては、この資料が一番解りやすかったです。

    よくよく考えたら、ACIDや分散トランザクションで厳密にConsistencyを確保させても、そんなに厳密さを要求する場面って結構少ない気がします。
    Soft-Stateなデータを読み込んで処理したって、アプリのAvailabilityをある程度確保しようとしたら、悲観的ロックなんて利用できないです。また、JPAのエンティティをリモート環境にDTOとして利用するなど、トランザクション境界外に持っていったら、Soft-Stateなデータとあんまり変わらない気がする...。

    そもそも今まで盲目的に信じていたACIDでなくて、十分なんとかなるし、2pcなど分散トランザクションを利用していた場合は、ネットワーク障害などでHeuristic例外が発生し得ることを考えたら、そんなに厳密さっていらないんじゃないかと思ってしまいます。

    結局は、適材適所なわけで、アプリケーションの要件によるんですが、見方を変えればいろんな可能性が考えれて面白いと思います。

    Bloggerにお引越し

    最近、仕事のプロジェクトが一段落し、ちょっと余裕が出てきたので、ブログを更新しようと思っていたんですが、他のブログサイトの自分のブログはAndroidアプリ対応されていないので、Bloggerにお引越しすることにしました。

    なぜ、Androidアプリ対応が必要なのかというと、家では娘にこれっぽちも時間を空けてもらえないため、基本、会社の通勤時間などに投稿する必要があるからです!

    前のブログも何ヶ月も投稿していなかった理由は、家では(娘が寝た後しか)時間を使えないからです。(ちなみに、今は寝てますw)

    基本、プログラミングなど技術に関連することのみ書いていく予定です。
    あんまり面白くないかも~、と思うので、自分の知り合いには知らせず、細々と続けていきたいなぁと思ってます。