ラベル j2ee の投稿を表示しています。 すべての投稿を表示
ラベル j2ee の投稿を表示しています。 すべての投稿を表示

2014年5月25日日曜日

Spring でのAsync処理 Queue



Queuingといえばメール送信や重たい処理を非同期で実行させる場合に
使わないと行けないというケースがあります。Spring には TaskExecutor という
非同期で処理を実行するQueueを取り扱うクラスがあります


これが何かと便利なので覚書


コマンド実行をQueueにするサンプル
asyncExecutorをautowiredして使います。


AsyncExecutor.java :

public class AsyncExecutor {

    String command;
   
    public void setCommand(String command) {
        this.command = command;
    }
   
    @Autowired
    private TaskExecutor taskExecutor;
   
    public void execute(File file) {
        taskExecutor.execute(new AsyncTask(file));
    }

    private class AsyncTask implements Runnable {
        File file;

        private AsyncTask(File file) {
            this.file = file;
        }

        public void run() {
            Runtime rt = Runtime.getRuntime();
            try {
                Process pr = rt.exec(command + " " + file.toString());
                pr.waitFor();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}



bean定義


    <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" p:corePoolSize="5"
          p:maxPoolSize="10" p:queueCapacity="100" p:waitForTasksToCompleteOnShutdown="true"/>
   
    <bean id="asyncExecutor" class="sample.AsyncExecutor">
        <property name="command" value=”/opt/jetty/bin/batch.sh"></property>    </bean>





MailをTaskExecutorでおくる例は下記参照
http://www.i-develop.be/blog/2010/10/01/execute-tasks-asynchronously-with-spring-3-0/


非同期処理は自分で実装するのは気が引けるのでSpringでの実装は助かります

2014年5月15日木曜日

Spring Batch Adminにスケジュール機能をつけてみる

前回、Spring Batch Adminについて触れましたが、
Springには 3.0からTaskSchedulerという機能がついているのでそれを使って
Spring Batch Adminにスケジュールをホストさせてみます。


あくまで、Spring Batch Adminの使っているtaskLauncherを
TaskSchedulerから使うというものでAdminからスケジュールを編集できるとかではありません。
あしからず。


RunScheduler.java :

@Component
public class RunScheduler {

   
    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    private ListableJobLocator jobLocator;

    private String jobName;
   
    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public void run() {

        try {

            String dateParam = new Date().toString();
            JobParameters param = new JobParametersBuilder().addString("date",
                    dateParam).toJobParameters();

            System.out.println(dateParam);

            Job job = jobLocator.getJob(jobName);

            JobExecution execution = jobLauncher.run(job, param);

        } catch (Exception e) {


 e.printStackTrace();
        }

    }
}




bean定義に次のようにスケジュールを定義します。
下の例では、テンプレートにあるsimpleJobを5分毎に実行します。

  <bean id="runScheduler" class="my.package.RunScheduler">
      <property name="jobName" value="simpleJob"/>
  </bean>
 
  <!-- Run every 5 minutes     -->
  <task:scheduled-tasks>
    <task:scheduled ref="runScheduler" method="run" cron="0 */5 * * * *" />
   </task:scheduled-tasks>




cronの記述方法については下記
http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-06



記事を書いていて気づいた、
このscheduler自体をJob化すればadminからスケジュールの開始、停止もできる

Spring Batch AdminのMySQL設定

バッチ実行にSpring Batchを利用しようかと検討しています。

jBatchがJavaEEに組み込まれたこともあり、
それに準拠した形でバッチを作ったほうがなにかと恩恵があるのかなと思ったというだけですが。

で、Spring BatchにはSpring Batch AdminというWebUIがあるので
使ってみます。あくまで、実行、停止、実行履歴が見れる程度のものです。
標準のdatabaseがhsqldbとなっているのでMySQLに変更します。

Adminのテンプレートでは
META-INF/batch-hsql.properties
というファイルがあるので次のファイルに変更します。


META-INF/batch-mysql.properties:



batch.jdbc.driver=com.mysql.jdbc.Driver
batch.jdbc.url=jdbc:mysql://localhost/test
batch.jdbc.user=user

batch.jdbc.password=
batch.jdbc.testWhileIdle=true
batch.jdbc.validationQuery=SELECT 1
batch.jdbc.maxActive=70
batch.jdbc.initialSize=20
batch.schema.script=classpath:/org/springframework/batch/core/schema-mysql.sql
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-mysql.sql
batch.business.schema.script=classpath:/business-schema-mysql.sql
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer

# Non-platform dependent settings that you might like to change
batch.data.source.init=false




batch.data.source.init=falseはdatabase初期化するかという設定です。
一番最初に起動するときのみtrueにする必要があります。

このままだと、遅いので dataSourceをoverrideします。
次のファイルを作成します。


META-INF/spring/batch/override/war-content.xml :

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


<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource”>
          <property name=”driverClassName” value=”${batch.jdbc.driver}” />
          <property name=”url” value=”${batch.jdbc.url}” />
          <property name=”username” value=”${batch.jdbc.user}” />
          <property name=”password” value=”${batch.jdbc.password}” />

          <property name=”initialSize” value=”${batch.jdbc.initialSize}”/>
          <property name=”maxActive” value=”${batch.jdbc.maxActive}”/>

</bean>
</beans>




実行時に引数を渡す必要があります。
 -DENVIRONMENT=mysql

なのでmaven でデバッグするときは 次のようになる
jetty:run  -Dmaven.surefire.debug test -DENVIRONMENT=mysql



せっかくなのでスケジュールに機能もつけてみました→

2014年5月13日火曜日

Jetty 9.1.* の設定について

jetty 9.1.*系以降jettyの一部がモジュール化され
設定項目体系が変わっています

設定方法についてをすこしまとめておきます。


1.httpsを有効化

ダウンロードしたアーカイブのdemo-base以下にあるstart.d/ssl.ini、https.iniが参考になります
demo-baseのstart.d/ssl.ini、https.iniを start.dにコピペして
環境に合わせて修正する


2. jetty-envを有効化

そのままでOKただし、pom.xmlにjetty関連のdependancyがある場合
loaderエラーになる可能性があるのでjetty pluginでのみ必要な物は
jetty plugin 以下のdependancyに移す


3. jspを有効化

start.iniの--module=jspのコメントを外す


4. servletを有効化

defaultでservletsモジュールは読み込まれないので
jetty-servlets を使う場合は、
start.iniに--module=servletsを追加

 
5. リクエストログの有効化

start.iniに--module=requestlogを追加


等々

9.1.4はログ出力のリンク回りがバグっているのかjetty.shが動かない場合があるので注意
多分9.1.5で修正ずか?


2014年4月11日金曜日

HttpServletRequestのthread内共有 Spring編

HttpServletRequestを参照しようとした時に
引数で渡さずに、static fieldのthread localに保存して
スレッド内から参照できるようにする方法を昔紹介していましたが、
Spring使用時には標準の機能としてすでにあります。


次のようにRequestContextHolderからHttpServletRequestを取得します。

        RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = 

(HttpServletRequest)attrs.resolveReference(RequestAttributes.REFERENCE_REQUEST);


web.xmlにlistenerを登録する必要があります。

web.xml:

    <listener>
      <listener-class>

     org.springframework.web.context.request.RequestContextListener
   </listener-class>
    </listener>



Spring 2.5以上が必要です
使い道としては、エラー出力にリクエスト情報を出すとか
エラーハンドルのためにいちいち、
リクエストを引数には渡せないのでthreadに保持しているものを参照します。


ThreadLocalに自分で保存する記事よりは
既存のものを使うべきでしょう

2014年3月28日金曜日

Spring Security Auto Login

Spring Security を利用してログインセッション管理を
している方も多いと思います。

Spring Securityデフォルトのままで使うと
アカウント作成後に一度ユーザにログインしてもらわないといけないとか
イケてないので、そういう時に自動でログインセッションを作成する方法です


アカウント作成後に次のようなメソッドを呼びます
AuthenticationProvideのBeanを指定します(自作クラスでも動きます)

    @Autowired
    AuthenticationProvider authenticationProvider;



HttpServletRequestを予め取得しておいて、username, passwordから
tokenを発行し、authenticationProviderに登録します

    private void doAutoLogin(String username, String password,
            HttpServletRequest request) {

        try {
            // Must be called from request filtered by Spring Security,
            // otherwise SecurityContextHolder is not updated
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                    username, password);
            token.setDetails(new WebAuthenticationDetails(request));
            Authentication authentication = this.authenticationProvider
                    .authenticate(token);
            // logger.debug("Logging in with [{}]",
            // authentication.getPrincipal());
            SecurityContextHolder.getContext()
                    .setAuthentication(authentication);
        } catch (Exception e) {
            SecurityContextHolder.getContext().setAuthentication(null);
            logger.error("Failure in autoLogin", e);
        }

    }


AutowiredしなくてもSecurityContextHolderからいけるかも
しれないですね。そのうちやってみよ。

2014年3月25日火曜日

Session Counter Listener

セッション数をカウントするServlet コンテナ用のListenerを自作したので共有
サービスのセッション数 を監視してーという人はどうぞ
thread safeなはず。 Java1.5以上必要です


SessionCounterListener.java:

public class SessionCounterListener implements HttpSessionListener {
    private static AtomicInteger totalActiveSessions = new AtomicInteger();

    public static int getTotalActiveSession() {
        return totalActiveSessions.get();
    }

    @Override
    public void sessionCreated(HttpSessionEvent arg0) {
        totalActiveSessions.incrementAndGet();
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent arg0) {
        totalActiveSessions.decrementAndGet();
    }
}


web.xmlにはListenerとして登録

web.xml :

 <listener>
        <listener-class>my.package.SessionCounterListener</listener-class>
</listener>


   

2014年2月22日土曜日

Jersey2.6(JAX-RS2.2) with Jetty9 セットアップ


JAX-RS2.*を使いたいと思って、Jersey2.6をJetty9に組み込もうとしたのですが、
四苦八苦したのでメモ

いろいろdependancyに入れすぎてたのが問題だったようです。
jsr311-apiをdependancyから取り除くとうまくいきました。

JAX-RS2.*では、Pojomappingを指定するのではなく
JAX-RS JSON Providerに対応するライブラリを追加することでJSONに対応します。
下の例では、jackson-jaxrs-json-providerを追加しています。

JavaEE3以上は、jersey-container-servlet-coreを使うよう言われますが
自分は以前のweb.xmlでの指定方法が好みなので
jersey-container-servletを使っています。


pom.xml :

 <略>

<properties>
    <java.version>1.7</java.version>
    <jettyVersion>9.1.2.v20140210</jettyVersion>
    <jerseyVersion>2.6</jerseyVersion>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
   
<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>${jettyVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>${jettyVersion}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jerseyVersion}</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>${jerseyVersion}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <version>2.2.3</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>${jettyVersion}</version>
                <configuration>
                    <webAppSourceDirectory>${basedir}/webapp</webAppSourceDirectory>
                    <webXmlFile>${basedir}/webapp/WEB-INF/web.xml</webXmlFile>
                    <jettyEnvXml>${basedir}/webapp/WEB-INF/jetty-env.xml</jettyEnvXml>
                    <contextPath>/</contextPath>
                </configuration>
            </plugin>
        </plugins>
    </build>




WEB-INF/web.xml:


<?xml version="1.0" encoding="UTF-8"?>
<web-app>

    <servlet>
        <servlet-name>jersey</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer
        </servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>パッケージ</param-value>
        </init-param>
        <load-on-startup>10</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jersey</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</web-app>




WEB-INF/jetty-env.xml:


<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">

  <Call name="setAttribute">
      <Arg>org.eclipse.jetty.webapp.configuration</Arg>
      <Arg>
          <Array type="java.lang.String">
              <Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
              <Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
              <Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
              <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
              <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
              <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
              <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
              <Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item>
          </Array>
      </Arg>
    </Call>
 

  <Set name="war"><SystemProperty name="jetty.home" default="."/>/</Set>
 
</Configure>

2013年9月21日土曜日

J2EE (jetty) アプリケーション初期化処理

J2EE のリスナーの話です

基本のリスナーの使い方は覚えないといけないなー
と思いながら全然すすまない

まずは初期化処理から
初期化時にはDBからマスタの読み込みとかします


package com.gauuud.StartUp;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;


public class InitDB implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //初期化処理       
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        //終了時処理

    }

}


web.xml :

<listener>     
        <listener-class>com.gauuud.StartUp.InitDB</listener-class>
</listener>


余談になりますが
マスタは起動時にメモリ上に全部読み込むようにするべきですよね
最近のサーバはメモリ多いし(マスタとか10Mもいかないだろうし
クラスタ構成が多いので更新時に再起動でサービスが止まることもないし