2017年5月1日月曜日

cocos2d-x JNI(Java) の に関する覚書

調べたりした結果をずらずらと並べます

cocos2d-x 3.x系 android studioでのJNI headerの作成

cd proj.android-studio

 javah -classpath "app/build/intermediates/classes/debug/:../cocos2d/cocos/platform/android/libcocos2dx/build/intermediates/classes/debug:$ANDROID_SDK_ROOT/platforms/android-23/android.jar" -d "app/jni/NativeBridge" org.cocos2dx.cpp.AppActivity

#android-sdkのバージョンは環境に合わせてください
#一度ビルドする
#app/jni/NativeBridgeにheaderファイルが作成されます


SDKBOX Admobプラグインの位置修正

Admobプラグインは位置が上下左右固定なのでマージンを指定したい場合
次のようなコードで変更できてる模様 
 
ViewGroup rootView = AppActivity.getRootView(context);
if(rootView != null)
{
    for (int i = 0; i < rootView.getChildCount(); i++) {

        ViewGroup view = (ViewGroup)rootView.getChildAt(i);

        for (int j = 0; j < view.getChildCount(); j++ ) {
            if (view.getChildAt(j) instanceof AdView) {
                View child = view.getChildAt(j);
                int height = child.getBottom() - child.getTop();

                ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) child.getLayoutParams();
                lp.bottomMargin = 60 * height / 50;
                child.setLayoutParams(lp);
            }
        }

    }
}


追記予定...

2017年4月29日土曜日

cocos2d-x <- android UIスレッドからの値の取得

cocos2d-xなどでAndroidのUIスレッドから値を直接取得したいという場合
例えば、 クリップボードから取得する場合とか
runOnUiThreadから処理したのちにcallbackを呼ぶ 必要があります

大変面倒なのでwaitを使ってブロッキング処理をしてみましょう
ということでBlockingOnUIRunnableを少し改良してGeneric型を返すようにしてみました


BlockingOnUIRunnable.java

 
/**
 * Blocking Runnable executing on UI thread
 *
 * @author
 *
 */
public class BlockingOnUIRunnable<t>
{
    // Activity
    private Activity activity;

    // Event Listener
    private BlockingOnUIRunnableListener<t> listener;

    // UI runnable
    private Runnable uiRunnable;

    public T retValue;

    /**
     * Class initialization
     * @param activity Activity
     * @param listener Event listener
     */
    public BlockingOnUIRunnable( Activity activity, BlockingOnUIRunnableListener<t> listener )
    {
        this.activity = activity;
        this.listener = listener;

        uiRunnable = new Runnable()
        {
            public void run()
            {
                // Execute custom code
                if ( BlockingOnUIRunnable.this.listener != null ) {
                    retValue = BlockingOnUIRunnable.this.listener.onRunOnUIThread();
                }

                synchronized ( this )
                {
                    this.notify();
                }
            }
        };
    }


    /**
     * Start runnable on UI thread and wait until finished
     */
    public void startOnUiAndWait()
    {
        synchronized ( uiRunnable )
        {
            // Execute code on UI thread
            activity.runOnUiThread( uiRunnable );

            // Wait until runnable finished
            try
            {
                uiRunnable.wait();
            }
            catch ( InterruptedException e )
            {
                e.printStackTrace();
            }
        }
    }

}
 
 
 

BlockingOnUIRunnableListener.java

 
/**
 * Events for blocking runnable executing on UI thread
 *
 * @author
 *
 */
public interface BlockingOnUIRunnableListener<t>
{

    /**
     * Code to execute on UI thread
     */
    public T onRunOnUIThread();
}


使い方 


BlockingOnUIRunnable<String> actionRunnable 
  = new BlockingOnUIRunnable<String>( {{context}}, new BlockingOnUIRunnableListener()
{
    public String onRunOnUIThread()
    {
        ClipboardManager clipboard = (ClipboardManager) {{context}}.getSystemService(Context.CLIPBOARD_SERVICE);
        if (clipboard.hasPrimaryClip()) {
            ClipData data = clipboard.getPrimaryClip();
            ClipDescription description = clipboard.getPrimaryClipDescription();
            if (data != null && description != null && description.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN))
                return String.valueOf(data.getItemAt(0).getText());
        }
        
        return "";
    }
} );

actionRunnable.startOnUiAndWait();
return actionRunnable.retValue;
 
 
 
{{context}}はActivityのcontext, Cocos2dxActivity.getContext()等から取得する値 startOnUiAndWait()で処理を待って retValueから戻り値を取得します
wait中はGLThreadが停止するので重たい処理には使えません

2016年2月12日金曜日

node.js サービス化 on ubuntu

ここから抜粋

/etc/init
以下にyourprogram.confとしてファイル作成

#yourprogram.conf
description "node.js server"
author      "kvz - http://kevin.vanzonneveld.net"

# used to be: start on startup
# until we found some mounts weren't ready yet while booting:
start on started mountall
stop on shutdown

# Automatically Respawn:
respawn
respawn limit 99 5

script
    # Not sure why $HOME is needed, but we found that it is:
    export HOME="/root"

    exec sudo -u www-data /usr/bin/node /where/yourprogram.js >> /var/log/node.log 2>&1
end script

post-start script
   # Optionally put a script here that will notifiy you node has (re)started
   # /root/bin/hoptoad.sh "node.js has started!"
end script
 
 
##/usr/local/bin/node → /usr/bin/nodeに修正
## ユーザwww-dataは作成しておく 
 
init-checkconf /etc/init/yourprogram.conf
を実行してみる
failed to ask Upstart to check conf fileと出るが
/tmpフォルダにinit-checkconf-upstart-outputが出力されているので
何もエラーがなければOkのはず
 
 
下記コマンドで実行 
start yourprogram   
停止
stop yourprogram 

いまさらながら Linq to SQL

必要だったのでLinq to SQL 触ってみましたが
いろいろ細かいところが面倒だったので
対応した内容をメモ


 Binary形式の比較ができない


下記のようなクラスを作成し

 public static class BinaryComparer
    {
        public static int Compare(this Binary b1, Binary b2)
        {
            throw new NotImplementedException();
        }
    }


where内で使う

hoge.Where(row =>BinaryComparer.Compare(binary, row.binary_column) == 0) ;



PropertyInfoを使ったカラム指定



public static Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(
             PropertyInfo property, TValue value)
        {
            var param = Expression.Parameter(typeof(TItem));
            var body = Expression.Equal(Expression.Property(param, property),
                Expression.Constant(value));
            return Expression.Lambda<Func<TItem, boo>>(body, param);
        }


次のように利用する

hoge.Where(PropertyEquals<hogetype, byte>(propertyInfo, somebyte));


上記だとnullableに対応していないので
nullable対応版

public static Expression<Func<TItem, bool>> NullablePropertyEquals<TItem, TValue>(
             PropertyInfo property, TValue? value) where TValue : struct
        {
            var param = Expression.Parameter(typeof(TItem));
            var body = Expression.Equal(
                    Expression.Property(param, property),
                    Expression.Constant(value, typeof (TValue?)));
            return Expression.Lambda<Func<TItem, bool>>(body, param);
        }

nullableでしか動かないので注意
両方に対応したメソッドも作れるような気はするけど
取りあえずここまで




2015年10月27日火曜日

Orvibo S20

電源をWifi(LAN)上で操作できるデバイスです
外出することが多くなりそうなので導入
ただ、心配なのが操作するアプリがLAN外から操作する場合に
製造元のサーバーを経由するということ
中国のよくわからないメーカーなので心もとない
ということでハックされたスクリプトで操作することに



情報元はここです
https://stikonas.eu/wordpress/2015/02/24/reverse-engineering-orvibo-s20-socket/


結論から言うと下記PHPファイルで操作できる

<?php
ob_start();
error_reporting(E_ALL | E_STRICT);

$server = 'IPADDRESS';
$port = 10000;
$macAddress = 'AC:CF:23:56:6C:24';
$twenties = '202020202020';
$ma = strtolower(implode('',explode(':',$macAddress)));
$maReverse = strtolower(implode('',array_reverse(explode(':',$macAddress))));
$subscribe = pack('H*','6864001e636c' . $ma . $twenties . $maReverse . $twenties);
$on = pack('H*','686400176463' . $ma . $twenties . '0000000001');
$off = pack('H*','686400176463' . $ma . $twenties . '0000000000');

//Create a UDP socket
if(!($sock = socket_create(AF_INET, SOCK_DGRAM, 0))) {
    $errorcode = socket_last_error();
    $errormsg = socket_strerror($errorcode);
    die("Couldn't create socket: [$errorcode] $errormsg <br />");
}

echo "Socket created <br />";

// Bind the source address
if(!socket_bind($sock, "0.0.0.0" , $port)) {
    $errorcode = socket_last_error();
    $errormsg = socket_strerror($errorcode);
    die("Error binding socket. Error code was " . $errorcode . " and error message was " . $errormsg);
}

echo "Socket bound. Waiting for incoming data.<br />";

echo "Sending subscribe packet ..";
socket_sendto($sock, $subscribe, strlen($subscribe), 0, $server, $port);
sleep(2);
echo "Sending ON packet ..";
socket_sendto($sock, $on, strlen($on), 0, $server, $port);
sleep(2);
echo "Sending OFF packet ..";
//socket_sendto($sock, $off, strlen($off), 0, $server, $port);



ob_flush();
//Do some communication, this loop can handle multiple clients
while(1) {
    //Receive some data
    $r = socket_recvfrom($sock, $buf, 512, 0, $remote_ip, $remote_port);
    $buf = ascii2hex($buf);
    echo "Data from " . $remote_ip . ": " . $buf . "<br />";
       ob_flush();
}

function ascii2hex($ascii) {
    $hexadecimal = '';
    for ($i = 0; $i < strlen($ascii); $i++) {
        $byte = strtoupper(dechex(ord($ascii{$i})));
        $byte = str_repeat('0', 2 - strlen($byte)).$byte;
        $hexadecimal.=$byte." ";
    }
    return $hexadecimal;
}

socket_close($sock);

?>

TODO Ctrl+Cしないと終了しない

2015年10月26日月曜日

iPhoneでのOpenSSHの安全な設定

いつもiPhoneにOpenSSH入れる時に見ていたサイトから
いつの間にか記事がなくなっていたのでメモしておく


●ssh でユーザーmobileにアクセスする


ssh mobile@ipaddress

デフォルトのパスワードはalpine


●rootのパスワード変更


su
passwd
新しいパスワード


●共通鍵の生成


ssh-keygen -t rsa
保存先は空白
任意のパスフレーズ
 

autorized_keyに保存する
 
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
rm ~/.ssh/id_rsa.pub
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys


 ●秘密キーの設置

作成したid_rsaをPCもしくはMacに持ってくる
WinSCPやFileZilla等利用

 OpenSSHの場合はそのまま、puttyの場合はputty-genで置換する必要がある



●SSHdの設定を変更する

 該当行を次のように変更

sudo vim /etc/ssh/sshd_config #vimはcydiaからインストールしておく

# HostKey for protocol version 1
#HostKey /etc/ssh/ssh_host_key #version1は使わない   
PermitRootLogin no #rootユーザではログインさせない   

#RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys #公開鍵方式を使う   

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no #パスワード認証は行わない



ちなみにviのコマンド(i:インサートモード,esc:ノーマルモード,x:一文字削除,dd:行削除,:wq:保存,:q!:保存せずに閉じる)


● サービスの再起動


su 
launchctl unload /Library/LaunchDaemons/com.openssh.sshd.plist
launchctl load /Library/LaunchDaemons/com.openssh.sshd.plist

2015年2月21日土曜日

Windows 8 スリープからの自動復帰を切る

自宅のメインマシンはWindows 8機で基本的にスリープで運用しています。
スリープまたは休止状態から勝手に復帰するようになって
睡眠を妨げるようになったのでイラついた勢いで設定を見直しました


原因として考えられるのは、
WakeOnLan
マウス等デバイスの (誤)操作
タスクスケジュールの実行

 

1.原因究明


直近の起動理由を知るには次のコマンドを実行します

>powercfg lastwake


マウスでの実行であれば次のような出力
切ってみましたが効果なし

Wake History [0]
  Wake Source Count - 1
  Wake Source [0]
    Type: Device
    Instance Path: ACPI\PNP0303\4&6
    Friendly Name:
    Description: 標準 PS/2 キーボー
    Manufacturer: (標準キーボード)



復帰予定のスケジュールを探す

>powercfg waketimers


次のような出力があります。
原因はmcupdate_scheduledというスケジュールのようです。


Timer set by [SERVICE] \Device\HarddiskVolume1\Windows\System32\svchost.exe (Sys
temEventsBroker) expires at 3:31:08 on 2015/02/18.
  Reason: Windows は、スリープ状態の解除を要求したスケジュールされたタスク 'NT T
ASK\Microsoft\Windows\Media Center\mcupdate_scheduled' を実行します。


2.スリープ解除をきる


WakeOnLanの場合、

 デバイスマネージャから対象のネットワークアダプタのプロパティを開く
電源の管理タブから
” Magic Packetでのみ、コンピュータのスタンバイ状態を解除できるようにする”
 のチェックを外すか選択できない状態にする


マウス、キーボードの場合、

デバイスマネージャから対象のデバイスのプロパティを開く
電源の管理タブの ”このデバイスで、コンピュータのスタンバイ状態を解除できるようにする”
のチェックを外す


スケジュールの場合、

”管理ツール>タスクスケジューラ”から対象のスケジュール(mcupdate_scheduled)を捜し
条件タブの”タスクを実行するためにスリープを解除する”のチェックを外す

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



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