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月17日木曜日

UUID <-> Base64 変換する Jackson用wrapperクラス

データベースでUUIDを何かと使うのですが、
JSONで出力すると'afb055a0-c18f-11e3-8b27-b1398a321474'みないな
文字列になってちょっと長いですし、
UUIDだというのがバレバレでそこはかとなく心配になります。

なので、JSONマッパーに渡すUUIDをwrapしてBase64としてマップするクラスを作ったので共有
表題にある通りJackson向けです


@JsonValueアノテーションをつけることで
このクラスをシリアライズする際にtoString()が呼ばれBase64化された値を返します

デシリアライズ 時には、
UUIDBase64(String uuidBase64)で初期化されUUIDBase64クラスとしてマップされます。


UUIDBase64.java :

import java.nio.ByteBuffer;
import java.util.UUID;

import org.apache.commons.codec.binary.Base64;
import org.codehaus.jackson.annotate.JsonValue;
import org.codehaus.jackson.annotate.JsonIgnore;

public class UUIDBase64 {
   
    @JsonIgnore
    private final UUID uuid;

    public UUIDBase64(UUID uuid) {
        this.uuid = uuid;
    }

    public UUIDBase64(String uuidBase64) {
        byte[] bytes = Base64.decodeBase64(uuidBase64);
        ByteBuffer bb = ByteBuffer.wrap(bytes);
        this.uuid = new UUID(bb.getLong(), bb.getLong());
    }
   
    @JsonValue
    public String toString(){
        if (uuid == null)
            return null;
       
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(uuid.getMostSignificantBits());
        bb.putLong(uuid.getLeastSignificantBits());           
        return Base64.encodeBase64URLSafeString(bb.array());
    }
   
    public UUID getUUID() {
        return this.uuid;
    }
   
    public static UUIDBase64 fromUUID(UUID uuid) {
        return new UUIDBase64(uuid);
    }
   
    public static UUIDBase64 fromBase64(String str) {
        return new UUIDBase64(str);
    }

}


次のように変換されます

class User {
    UUIDBase64 id;
}

<-> { "id" : "base64の文字列" }

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>


   

Cassandra3.x CQLでBlobを扱う

CassandraでのBlobの扱いに半日ぐらい使ったので覚書


Cassandra3.0、datastax driver 2.0
でCQLを利用してBlobを扱う場合、
bindにByteBufferをかまさないといけません。
それと、row.getBytes()で取得したByteBufferをそのままarray()しても
ゴミの入ったbyte[]になってしまいます。

なので、次のようにする
bind時
byte[] byteArray;
prepare(cql).bind(ByteBuffer.wrap(byteArray));

取得時
import com.datastax.driver.core.utils.Bytes;
byte[] byteArray = Bytes.getArray(row.getBytes("bytes"));

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>

2014年2月12日水曜日

Maven での デバッグ

Mavenでのデバッグ方法が検索しても見当たらなかったので
書き留めておきます。



Eclipseを利用している、m2eclipseをインストールしている前提です。


1.プロジェクトを右クリック>Debug As>Maven build...



2.Goalsに goal -Dmaven.surefire.debug test を設定


例) java ファイルを実行する場合
exec:java -Dmaven.surefire.debug test [-Dexec.mainClass="クラス名"] [-Dexec.args="引数"]

例) jettyを実行する場合
jetty:run -Dmaven.surefire.debug test


3.ParameterにName:forkCount Value:0を追加
これがないと、デバッグ用のポートをリスニングするのを回避



Maven v2.0.8 以降はmaven.surefire.debugを利用すれば
ポートを指定したリモートデバッグの必要はありません。
(実はずっとリモートデバッグしていた…)

2014年1月31日金曜日

Java 8を使ってみる(使用編・Stream編1)

Java 8には、Streamというクラスが追加されています。
面倒くさい説明を少々しますので飛ばす人はこちらへ→スキップ


StreamはC#でいうIEnumbleに準ずるもので、中間処理を実行しても実際の絞り込みは
実行されず、終端処理を呼び出された際に実行されるというものです。

下の例のような記述ができます。

int sumOfRedWeights  = blocks.stream().filter(b -> b.getColor() == RED)
                                           .mapToInt(b -> b.getWeight())
                                           .sum();

ここでは、blocksをgetColor()==REDで絞り込み(filter)、
getWeight()を抽出して(mapToInt)合計しています(sum)。
中間処理のfilter、mapToIntでは絞込は行われず、
終端処理のsumが呼ばれる際に遅延的に実行されます。


言い換えると、繰り返し処理を関数的に記述できるようになるというところでしょうか。
また、終端処理まで状態を保持しないため並列化にも適しています。
stream()のかわりにparallelStream()を使うことによって、処理を並列的に実行します。
サーバではもともとマルチスレッドなので他のコアも処理してたりして、
あまり恩恵ないかもしれないですが、可読性と並列化が捗りますね\(^o^)/。



ということで、
StreamとSQLのクエリと比較してみましょう。


単純なSELECTでTestMember.idのみを抽出する

//SQL
SELECT TestMember.id

//Listに変換
List list = members.stream().map(TestMember::getId)
        .collect(Collectors.toList());


//Setに変換
Set set = members.stream().map(TestMember::getId)
        .collect(Collectors.toCollection(TreeSet::new));


TestMember::getIdは関数渡しでメソッドを渡しています。
map中でgetIdを呼び出した値を利用しています。

 

Member.weightの合計を求める

//SQL
SELECT sum(TestMember.weight)



total = members.stream()
        .mapToInt(x -> x.getWeight())
        .sum();

合計を求める方法には、Collectorを使う方法もあります

int total = members.stream()
        .collect(Collectors.summingInt(x -> x.getWeight()));


平均を求める

//SQL
SELECT avg(TestMember.weight)



double average = members.stream()
        .mapToInt(x -> x.getWeight())
        .average()   
        .orElse(0d);

orElse()というメソッドが出てきました。
average()は、OptionalDoubleというNull許容なオブジェクトを返します。
OptionalDoubleのNullの場合のデフォルト値を指定してdoubleを返すのがorElse()です。
OptionalDoubleは、C#でいうところのdouble?ですね。


切り出し

何番目の要素を指定して取り出すということもできます。


//SQL
SELECT TestMember.weight LIMIT 1

members.stream()
.mapToInt(x -> x.getWeight())
.findFirst()
.orElse(0);


//SQL
SELECT * OFFSET 1 LIMIT 2
members.stream()
.skip(1)
.limit(2).toArray(); 



グループ・パーティション

Stream には group byや partitioned byに当たるメソッドもあります

//グループ分け
Map         = members.stream()
                    .collect(Collectors.groupingBy(x -> x.getPart()));


同じpartのTestMemberをpart毎のマップにする。


本当は、groupingByには関数渡しで、TestMember::getPartとできるはずが、
エラーになっちゃいますね。


//パーティション
Map        members.stream()
                .collect(Collectors.partitioningBy(s -> s.getId() >= 5));




その他

条件に一致したものが一件でもある

boolean match = members.stream().anyMatch(b -> b.getId() > 5);

countを使うより軽いはず?


weightでソートする
ソートをstream、ラムダ式で実装してみた

members.stream().sorted((r,l) -> {
       return Integer.compare(r.weight, l.weight);
}).collect(Collectors.toList());   

ソートするだけならもっと効率のいい方法があるかな
parallelStreamが使えるから早いのか?むむ?



今回使ったプロジェクト->StreamSample.zip

次回もStream編がつづく

2014年1月28日火曜日

OpenCV for iOS 1/27, 2014 ビルド

1/27, 2014現在のgitリポジトリからダウンロードした
OpenCV はiOS向けにはそのままだとビルドできません。
そのための修正をメモ 


ソース修正

https://stackoverflow.com/questions/16983696/how-to-build-opencv-2-4-9-for-ios/17025423#17025423

対象ファイルの指定行を追加修正

3rdParty/libjpeg/CMakeLists.txt:12, jmemansi.c をビルドから除く(これはすでに適応済み?)

if(ANDROID OR IOS)
  ocv_list_filterout(lib_srcs jmemansi.c)
else()
  ocv_list_filterout(lib_srcs jmemnobs.c)
endif() 
 
modules/world/CMakeLists.txt:105 追加
ocv_list_filterout(objlist jmemansi) # <<= dirty fix
 
 

arm64対応

https://stackoverflow.com/questions/18976893/how-to-compile-opencv-for-ios7-arm64 

arm64ビルドは諦めて、armv7, armv7sのみのビルドに変更する

opencv/3rdparty/zlib/ にある gzlib.c, gzread.c, gzwrite.c  のincludeに追加

#include <unistd.h>
 
opencv/platforms/ios/build_framework.py  行99、100: 変更

targets = ["iPhoneOS", "iPhoneOS", ""iPhoneSimulator", "iPhoneSimulator"] 
archs = ["armv7", "armv7s", "i386", "x86_64"]

arm64を削除します
なくても、iPhone5sでも動く(プロジェクトがarmv7,armv7sでビルドされる場合)ので取りあえずなしでビルド




ビルドする


ビルド環境のパスを通す
sudo ln -s /Applications/Xcode.app/Contents/Developer /Developer
 
cmakeない場合は、portからinstall
sudo port install cmake

 
ビルド
python platforms/ios/build_framework.py ios



※モバイル系の記事は人気あるなあ

2014年1月23日木曜日

Java 8を使ってみる (Timeクラス編)

Java 8を使ってみよう 3回目は、Timeクラスです。


前回はインターフェースを扱いました。流れ的に次はラムダ式かStreamかと思ったのですが、
まとめるのが難しいので先に箸休めでTimeクラスを紹介します。


さて、Dateクラス使うの面倒臭いと思いませんか。
日付処理をしようとするとCalendarクラスを使わないといけないし、
差分とかとっていろいろしたいけど…、
という要望に答えた、CalenerクラスとDateクラス(+α)を統合した
のがJava 8からのTimeクラスです。



DateTime


時間を表すクラスには、いくつかあります。
代表的なのは、
LocalDateTime : タイムゾーンを含まない、日時
ZonedDateTime : タイムゾーンを含む、日時
になります。
ほかにもいろいろ追加されてますが、ここではLocalDateTimeを扱います。


日付処理


今日の3時のDateクラスを作成したいとなった時に今までは、
Calendarクラスを使っていました。

Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 3);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);

Date date = cal.getTime();


LocalDateTimeでは、クラスに日付処理が組み込まれているので、
Calendarのようなクラスを呼ぶ必要はありません。

 LocalDateTime datetime = LocalDateTime.now()
                .withHour(3).withMinute(0).withSecond(0).withNano(0);

指定日時のDateも作成しやすくなりました。

LocalDateTime datetime1 = LocalDateTime.of(2014, 5, 21, 1, 12);


一行で書けます。Javaではちょっと前から、一行で書くというのに
狂信的な人たちがいますね。





日付差分


Dateクラスは比較がafter,beforeくらいだったのですが
Java 8からは、専用のクラスが追加されてかなり拡張されています。
むしろこちらの方が嬉しい

ふたつのLocalDateTimeクラスの差分をDurationクラスで表せます。

Duration duration = Duration.between(datetime, datetime1);

このdurationは、datetimeからdatetime1までのナノ秒を保持しています。
LocalDateTimeクラスに、plusすることでdurationの秒数を追加できます。

LocalDateTime datePlused = datetime.plus(duration);

他にもminusとかできます。


Durationがあると、C#のTimeSpanのようなことができます。
この記事の内容をTimeSpanからDurationに置き換えると次のようになる。

public static final TimeSpan TIMESPAN = TimeSpan.Days(7);



Duration duration1 = Duration.ofDays(1);


で現在と差分を足したDateを求めるには、

Date date = TIMESPAN.getDate(new Date());
 


now.plus(duration1);

とすればいい。


何に利用するかというと主に
Memcachedに渡すExpireの 定義とかです。


Memcached.get(key, new Memgetable<String>() {
    public String get() {
        return value;
    }
}, TIMESPAN.getDate(new Date()));



Memcached.get(key, () -> {
        return value;
 }, Date.from(now.plus(duration1).toInstant());

こんな風に記述ができます。


まだ、*DateTimeに対応してないのでDateに直さないといけないのが面倒


つづく




2014年1月20日月曜日

Java 8を使ってみる(使用編・インターフェース)

準備編のつづきです。
今回はJava 8 を実際に使ってみましょう。


重みづけ抽選のロジック(以下RandomUtil)を、Java 8だとどうなるのか見ていきます。
ここでは、主にインターフェースの変更点についてみていきます。


FunctionalInterface


Java 8はインターフェースにFunctionalInterfaceというものが追加されました。
インターフェースに対して@FunctionalInterface宣言をするまたは、
一つのメソッドのみ定義するとFunctionalInterfaceと認識されます

RandomUtilだと、

public interface Weight<T> {
    int getWeight(T temp) ;
}

はJava 8ではFunctionalInterfaceとなります。

@FunctionalInterface
public interface Weight<T> {
    int getWeight(T temp) ;
}

と宣言をつけたものと同じ意味です。


FunctionalInterfaceにはラムダ式を渡すことができます。


TestMember member = RandomUtil.weightedRandom(members,
                    new Weight<TestMember>() {
                        public int getWeight(TestMember m) {
                            return m.weight;
                        }
                    });

以前までは、上記のように関数を渡していたのですが、
ラムダ式を渡すようにすると、次のように簡略化できます。

TestMember member = RandomUtil.weightedRandom(members,
                    m -> {
                        return m.weight;
                    });



Default Method


また、インターフェースにDefaultMethodを追加できるようになりました。


public interface Weight<T> {
    default int getWeight(T temp) {
        return 1;
    }
}

上のように定義した場合、

TestMember member = RandomUtil.weightedRandom(members,
                    new Weight<TestMember>() { });

とすると、getWeight の定義をしなくてもDefaultMethodとして定義している
メソッドが呼ばれます。ちなみに、DefaultMethodを定義していると
FunctionalInterfaceにはできません。



つづく


使用したプロジェクト:RandomUtil1.zip








2014年1月19日日曜日

Java 8を使ってみる(準備編)

遅ればせながら、Java8を触ってみようと思います。
以前、昨年の5月かそれぐらいに、一度動かしてみようと思っていたのですが
対応するIDEもなく、あきらめて日数がかなりたってしまいました。


Java 8の特徴は、なんといってもラムダ式の導入と
C#でIEnumbleにあたるStreamを導入し、Linqのような実装ができるようになるということです。
C#もつかう身としてJavaでLinqポイ実装ができるのは感慨もひとしおです。



まずは、Java 8が動作する環境を作ります。
Java 8はまだ正式リリースではないので、あくまでも試験的なものです。


Java 8 JDKのインストール


JDK 8 Early Access Releasesをダウンロードします。

https://jdk8.java.net/download.html

から環境に適したものをダウンロード、インストールします。


Eclipseのインストール


Eclipseというか、Spring Tool SuiteにJava8 supportのプラグインが
すでに入ったものがあるのでそれを利用します。


http://dist.springsource.com/snapshot/STS/nightly-distributions.html

上記のURLから
Spring Tool Suite - based on Eclipse 4.3 - including Java8 support
とあるところから、環境に適したものをダウンロードして、適当な場所に解凍します。



Eclipseの設定


解凍したフォルダにあるSTS.exeを起動します。
起動したらまず、JDkのパスを通しましょう

Window[メニュー] > Preferences > Java > InstalledJREs

からインストールしたJDK 8 ("C:\Program Files\Java\jdk1.8.0")を追加します。



プロジェクトの追加


Java 8に対応したプロジェクトを追加してみましょう
プロジェクト追加する際に、
Use an execution environment JREからJavaSE-1.8を選びます。
これで、プロジェクトでJava 8が利用できます。


準備編はここまで、使用編につづきます


2014年1月18日土曜日

Windows8 でのmecab javaバインディング ビルド

mecabとjavaバインディングをビルドしたのでそのメモ
環境は、Windows 8.1 x64, Visual C++ 2010 Express
           mecab0.996

インストール


Windows Software Development Kit (SDK) for Windows 8.1 をインストール
http://msdn.microsoft.com/en-US/windows/desktop/bg162891


mecabソースをダウンロード
https://mecab.googlecode.com/files/mecab-java-0.996.tar.gz
https://mecab.googlecode.com/files/mecab-0.996.tar.gz


 

libmecabビルド

 

 Configure

Configureする必要がるのか?
取り敢えず、MsysでConfigureする

cd mecab-0.996
./configure

make.bat修正


mecab-0.996/src/make.bat のパスを環境に合わせて修正
私の環境では次のように、上三行を変更

Set PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin;%PATH%
Set INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include;%INCLUDE%
Set LIB=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib;%LIB%


libmecab.dllを作成

mecab-0.996/src/make.batを実行

mecab-0.996にlibmecab.dllができる


 

 

Javaバインディング



用意されてるバインディング(MeCab_wrap.cxx)だと動かないので
自分で作成する

mecab-0.996/src/mecab.h を修正する

「#ifndef SIWG」を「#ifndef SWIG」に全部修正(何か所かある)

swigを実行する

cd mecab-0.996\swig
swig -java -package org.chasen.mecab -c++ MeCab.i

MeCab_wrap.cxxが生成される
swigがない場合はここから、パスを通しても完全パス指定でもOK


MeCab_wrap.dllを作成


mecab-java-0.997に作成したlibmecab.dllとMeCab_wrap.cxxをコピー
下のようなコマンドを実行する。パスは環境に合わせて変更

Set PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin;%PATH%
Set INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include;%INCLUDE%
Set LIB=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib;%LIB%


cl /EHsc /LD /I mecab-0.996\src /I "C:\Program Files (x86)\Java\jdk1.7.0_09\include" /I "C:\Program Files (x86)\Java\jdk1.7.0_09\include\win32" MeCab_wrap.cxx libmecab.dll


 

動作確認

libmecab.dllとMeCab_wrap.dllをコピーして 
適当なサンプルを実行


参考サイト:
http://ftablog.s56.xrea.com/index.php?itemid=167
内容はほぼ同じ(Windows7,mecab0.97)

2014年1月17日金曜日

Android NDKビルド環境をUbuntu Serverに作ってみた

AndroidのNDKビルド用の環境はWindowsやMac上でも作れるのですが、
Windowsだとcygwinとか面倒くさいし
Macだとたまにldtoolがないとか怒られるので
VMWare上のUbuntuに作成することにしました。
これだとコピペで環境を保存したり増やしたりえきるので便利ですね。


VMWare上にすでにUbuntuがインストールされていることが前提です。
Serverなのは消費メモリが少ないとかリソースの問題です。

Build環境
sudo apt-get install build-essential

1.Javaのインストール

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get install oracle-java7-installer 
 
 

2. Android NDKインストール

 
Android NDKをダウンロードします 

tar -xvjof android-ndk-r9c-linux-x86_64.tar.bz2
sudo mv ./android-ndk-r9c /usr/local/
echo 'export PATH=$PATH:/usr/local/android-ndk-r9c' >> .bashrc 
echo 'export NDKROOT=/usr/local/android-ndk-r9c' >> .bashrc 
 
 


3. Android SDK インストール

 
Android SDKをダウンロードします
unzip adt-bundle-linux-x86_64-20131030.zip
sudo mv adt-bundle-linux-x86_64-20131030 /usr/local/

echo 'export PATH=$PATH:/usr/local/adt-bundle-linux-x86_64-20131030/sdk/tools' >> .bashrc 
echo 'export PATH=$PATH:/usr/local/adt-bundle-linux-x86_64-20131030/sdk/platform-tools' >> .bashrc 
 


ライセンス許可

Android SDKの実行には最初にライセンスの認証が必要です
 
cd /usr/local/adt-bundle-linux-x86_64-20131030/sdk/tools
echo "y" | ./android update sdk --no-ui


 

SDK一覧

次のコマンドでSDKの一覧が表示されます
./android list sdk

 

SDKアップデート

必要なSDKをインストール、アップデートします
android update sdk -u --filter platform-tools,android-16,android-8,extra-android-support

 
 
動かしてみる
ndk-buildを実行してみる 
 
 

4.ビルドする際のメモ

 
個人的にAndroid.mkを利用するよりも
Configure時にSysroot, CC, CFLAG, LD, AR等を指定して
クロスコンパイルするほうがiOSと同じ要領なので楽

lib作成時にだいたいは次のようにして、static libraryを作って
あとで、static libraryを参照するAndroid.mkでsoにします
 
build.sh :  
 
BINPATH=$NDK_ROOT/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin
export CROSS_COMPILE=$BINPATH/arm-linux-androideabi
export CC=${CROSS_COMPILE}-gcc
export CXX=${CROSS_COMPILE}-g++
export LD=${CROSS_COMPILE}-ld
export AR=${CROSS_COMPILE}-ar
export CFLAGS="--sysroot $SYSROOT -std=gnu99 -L$LIB_DIR -L${NDK_ROOT}/usr/lib -I${NDK_ROOT}/usr/include"
 
./configure --prefix="一時フォルダ" --enable-static --disable-shared --host=arm-linux-androideabi

 
 
※おそらくConfigure時にarm-linux-androideabiの定義がないと怒られるので
下のリンクからconfigure.guess, configure.subをダウンロードして
configureのあるフォルダに移動、上書きします 
http://git.savannah.gnu.org/gitweb/?p=automake.git;a=blob_plain;f=lib/config.guess
http://git.savannah.gnu.org/gitweb/?p=automake.git;a=blob_plain;f=lib/config.sub


 
Android.mk : 
この辺りが参考になるかと 
https://groups.google.com/forum/#!topic/android-group-japan/NMoJAioGi04



2014年1月15日水曜日

Windows 実行時、引数の最大長

Windowsでexeを実行する際の引数の最大長について
調べたのでメモ

 Windowsのバージョンによっても違いますが
ここではWindows7以降の話



実行ファイルに渡すことのできる引数の最大長 32767 文字
これはUnicodeの制限から来ています

CMD.EXEからの実行の場合、
実行ファイル名も含めて、 8192文字
CMD.EXEの制限です

C#.net等からProcessを作成する場合、2048文字(たぶん)
UseShellExecute = falseにすればいいという噂もありますが、確認できませんでした



CMD.EXEから8192文字 以上の引数を実行 できないのは
結構ネックです。batファイルが実行できないですから。
CMD.EXEではなく、Shellを変更して,PowerShellやMsysを利用すれば
32767 文字まで利用可能なようです。
なので、batで動かない時はpsに拡張子を変更しましょう。


※長い引数を使うよりは、なるべくファイルで渡すべきですが