Raspberry Pi Type B+にUSBメモリ増設

RaspberryPIを買って早1月以上。そろそろディスク容量も乏しくなってきました。もともと余っていた32GのMicroSDを挿していたのですが、データが増えるにつれてちょっと残りが寂しくなってきたので、上海問屋の64GUSBメモリを購入しました。

RaspberryPIはUSB3.0対応ではないので、USB2.0の安いものをチョイス。送料込みで3400円くらい。安い。。

早速挿してみました。フォーマット自体はFAT32。プラグアンドプレイなので差し込むだけでOK。コマンドラインからマウントしてやります

pi@raspberrypi ~ $ sudo fdisk -l

Disk /dev/mmcblk0: 31.7 GB, 31657558016 bytes
4 heads, 16 sectors/track, 966112 cylinders, total 61831168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000b5098

				Device Boot			Start				 End			Blocks	 Id	System
/dev/mmcblk0p1						8192			122879			 57344		c	W95 FAT32 (LBA)
/dev/mmcblk0p2					122880		61831167		30854144	 83	Linux

Disk /dev/sda: 64.5 GB, 64541949952 bytes
255 heads, 63 sectors/track, 7846 cylinders, total 126058496 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xc3072e18

	 Device Boot			Start				 End			Blocks	 Id	System
/dev/sda1							64	 126058495		63029216		c	W95 FAT32 (LBA)

pi@raspberrypi ~ $ sudo mount /dev/sda1 /mnt
pi@raspberrypi ~ $ df
ファイルシス	 1K-ブロック		 使用	 使用可 使用% マウント位置
rootfs						30311756 13465040 15569968	 47% /
/dev/root				 30311756 13465040 15569968	 47% /
devtmpfs						219832				0	 219832		0% /dev
tmpfs								44800			240		44560		1% /run
tmpfs								 5120				0		 5120		0% /run/lock
tmpfs								89580				0		89580		0% /run/shm
/dev/mmcblk0p1			 57288		 9896		47392	 18% /boot
/dev/sda1				 63012832		 2752 63010080		1% /mnt

こんだけ。マウント簡単。しかしここで問題が発生。

どうやら一般ユーザでは書き込めない模様。権限も変更できず。まあ、FATなので権限もクソもないのでどうしょうもないのでしょう。ちなみにROOTユーザなら読み書きOKですがそれだと使いづらいので、EXT4にフォーマットし直してやります

pi@raspberrypi ~ $ sudo fdisk /dev/sda

Command (m for help): d
Selected partition 1

Command (m for help): p

Disk /dev/sda: 64.5 GB, 64541949952 bytes
199 heads, 32 sectors/track, 19795 cylinders, total 126058496 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xc3072e18

	 Device Boot			Start				 End			Blocks	 Id	System

Command (m for help): n
Partition type:
	 p	 primary (0 primary, 0 extended, 4 free)
	 e	 extended
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-126058495, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-126058495, default 126058495): 
Using default value 126058495

Command (m for help): p

Disk /dev/sda: 64.5 GB, 64541949952 bytes
199 heads, 32 sectors/track, 19795 cylinders, total 126058496 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xc3072e18

	 Device Boot			Start				 End			Blocks	 Id	System
/dev/sda1						2048	 126058495		63028224	 83	Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

mkfsでフォーマット

pi@raspberrypi ~ $ sudo mkfs.ext3 /dev/sda1 
mke2fs 1.42.5 (29-Jul-2012)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
3940352 inodes, 15757056 blocks
787852 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=0
481 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
	4096000, 7962624, 11239424

Allocating group tables: done														
Writing inode tables: done														
Creating journal (32768 blocks): 
done
Writing superblocks and filesystem accounting information:				
done

pi@raspberrypi ~ $ mkdir /media/usb0
pi@raspberrypi ~ $ sudo mount /dev/sda1 /media/usb0
pi@raspberrypi ~ $ df
ファイルシス	 1K-ブロック		 使用	 使用可 使用% マウント位置
rootfs						30311756 13498480 15536528	 47% /
/dev/root				 30311756 13498480 15536528	 47% /
devtmpfs						219832				0	 219832		0% /dev
tmpfs								44800			240		44560		1% /run
tmpfs								 5120				0		 5120		0% /run/lock
tmpfs								89580				0		89580		0% /run/shm
/dev/mmcblk0p1			 57288		 9896		47392	 18% /boot
/dev/sda1				 61907956		53196 58703352		1% /media/usb0

pi@raspberrypi /media/usb0 $ sudo chmod 777 .
pi@raspberrypi /media/usb0 $ mkdir data

ついでにマウント先も変更しました

WindowsでJekyll環境構築

jekyllをご存知でしょうか?そこいら中に記事があるので詳細はググればわかりますが、簡単にいえば静的HTMLのジェネレータフレームワークです。

Rubyで作成されていますのでgemで簡単にインストールできます。

がちょっとハマったので備忘録。。

環境

  • Windows8.1

インストール

まずはRUBYを入れます。Windows用のRubyはいろいろありますが、

http://rubyinstaller.org/downloads/

こちらからWindows用のMSIをダウンロードしインストールします。

C:\Ruby21-x64にインストールした後には環境変数PATHにC:\Ruby21-x64\binを追加します。

そのままgemでインストールしようとすると以下のエラーが出ます

C:\>gem install jekyll
ERROR:	Error installing jekyll:
The 'yajl-ruby' native gem requires installed build tools.
Please update your PATH to include build tools or download the DevKit
from 'http://rubyinstaller.org/downloads' and follow the instructions
at 'http://github.com/oneclick/rubyinstaller/wiki/Development-Kit'

どうやらMakeできなよと怒られたようです

DevelopmentKitなるものを同じページからダウンロードします。

DevKit-mingw64-64-4.7.2-20130224-1432-sfx.exe

現在だとこれになります。

これをC直下にc:\devkitというフォルダを作成しその中に解凍します

その後以下のコマンドを実行

C:\devkit>ruby dk.rb init
[INFO] found RubyInstaller v2.1.3 at C:/Ruby21-x64
Initialization complete! Please review and modify the auto-generated
'config.yml' file to ensure it contains the root directories to all
of the installed Rubies you want enhanced by the DevKit.
C:\devkit>ruby dk.rb install
[INFO] Updating convenience notice gem override for 'C:/Ruby21-x64'
[INFO] Installing 'C:/Ruby21-x64/lib/ruby/site_ruby/devkit.rb'

これで準備が整いました

あとはgemでインストール

C:\devkit>gem install jekyll
Temporarily enhancing PATH to include DevKit...
Building native extensions.	This could take a while...
Successfully installed yajl-ruby-1.1.0
Fetching: posix-spawn-0.3.9.gem (100%)
Building native extensions.	This could take a while...
Successfully installed posix-spawn-0.3.9
Fetching: pygments.rb-0.6.0.gem (100%)
Successfully installed pygments.rb-0.6.0
Fetching: redcarpet-3.2.0.gem (100%)
Building native extensions.	This could take a while...
Successfully installed redcarpet-3.2.0
Fetching: blankslate-2.1.2.4.gem (100%)
Successfully installed blankslate-2.1.2.4
Fetching: parslet-1.5.0.gem (100%)
Successfully installed parslet-1.5.0
Fetching: toml-0.1.1.gem (100%)
Successfully installed toml-0.1.1
Fetching: jekyll-paginate-1.1.0.gem (100%)
Successfully installed jekyll-paginate-1.1.0
Fetching: jekyll-gist-1.1.0.gem (100%)
Successfully installed jekyll-gist-1.1.0
Fetching: coffee-script-source-1.8.0.gem (100%)
Successfully installed coffee-script-source-1.8.0
Fetching: execjs-2.2.2.gem (100%)
Successfully installed execjs-2.2.2
Fetching: coffee-script-2.3.0.gem (100%)
Successfully installed coffee-script-2.3.0
Fetching: jekyll-coffeescript-1.0.1.gem (100%)
Successfully installed jekyll-coffeescript-1.0.1
Fetching: sass-3.4.5.gem (100%)
Successfully installed sass-3.4.5
Fetching: jekyll-sass-converter-1.2.1.gem (100%)
Successfully installed jekyll-sass-converter-1.2.1
Fetching: ffi-1.9.6-x64-mingw32.gem (100%)
Successfully installed ffi-1.9.6-x64-mingw32
Fetching: rb-inotify-0.9.5.gem (100%)
Successfully installed rb-inotify-0.9.5
Fetching: rb-fsevent-0.9.4.gem (100%)
Successfully installed rb-fsevent-0.9.4
Fetching: hitimes-1.2.2.gem (100%)
Building native extensions.	This could take a while...
Successfully installed hitimes-1.2.2
Fetching: timers-4.0.1.gem (100%)
Successfully installed timers-4.0.1
Fetching: celluloid-0.16.0.gem (100%)
Successfully installed celluloid-0.16.0
Fetching: listen-2.7.11.gem (100%)
Successfully installed listen-2.7.11
Fetching: jekyll-watch-1.1.1.gem (100%)
Successfully installed jekyll-watch-1.1.1
Fetching: fast-stemmer-1.0.2.gem (100%)
Building native extensions.	This could take a while...
Successfully installed fast-stemmer-1.0.2
Fetching: classifier-reborn-2.0.1.gem (100%)
Successfully installed classifier-reborn-2.0.1
Fetching: jekyll-2.4.0.gem (100%)
Successfully installed jekyll-2.4.0
Parsing documentation for blankslate-2.1.2.4
Installing ri documentation for blankslate-2.1.2.4
Parsing documentation for celluloid-0.16.0
Installing ri documentation for celluloid-0.16.0
Parsing documentation for classifier-reborn-2.0.1
Installing ri documentation for classifier-reborn-2.0.1
Parsing documentation for coffee-script-2.3.0
Installing ri documentation for coffee-script-2.3.0
Parsing documentation for coffee-script-source-1.8.0
Installing ri documentation for coffee-script-source-1.8.0
Parsing documentation for execjs-2.2.2
Installing ri documentation for execjs-2.2.2
Parsing documentation for fast-stemmer-1.0.2
Installing ri documentation for fast-stemmer-1.0.2
Parsing documentation for ffi-1.9.6-x64-mingw32
Installing ri documentation for ffi-1.9.6-x64-mingw32
Parsing documentation for hitimes-1.2.2
Installing ri documentation for hitimes-1.2.2
Parsing documentation for jekyll-2.4.0
Installing ri documentation for jekyll-2.4.0
Parsing documentation for jekyll-coffeescript-1.0.1
Installing ri documentation for jekyll-coffeescript-1.0.1
Parsing documentation for jekyll-gist-1.1.0
Installing ri documentation for jekyll-gist-1.1.0
Parsing documentation for jekyll-paginate-1.1.0
Installing ri documentation for jekyll-paginate-1.1.0
Parsing documentation for jekyll-sass-converter-1.2.1
Installing ri documentation for jekyll-sass-converter-1.2.1
Parsing documentation for jekyll-watch-1.1.1
Installing ri documentation for jekyll-watch-1.1.1
Parsing documentation for listen-2.7.11
Installing ri documentation for listen-2.7.11
Parsing documentation for parslet-1.5.0
Installing ri documentation for parslet-1.5.0
Parsing documentation for posix-spawn-0.3.9
Installing ri documentation for posix-spawn-0.3.9
Parsing documentation for pygments.rb-0.6.0
Installing ri documentation for pygments.rb-0.6.0
Parsing documentation for rb-fsevent-0.9.4
Installing ri documentation for rb-fsevent-0.9.4
Parsing documentation for rb-inotify-0.9.5
Installing ri documentation for rb-inotify-0.9.5
Parsing documentation for redcarpet-3.2.0
Installing ri documentation for redcarpet-3.2.0
Parsing documentation for sass-3.4.5
Installing ri documentation for sass-3.4.5
Parsing documentation for timers-4.0.1
Installing ri documentation for timers-4.0.1
Parsing documentation for toml-0.1.1
Installing ri documentation for toml-0.1.1
Parsing documentation for yajl-ruby-1.1.0
Installing ri documentation for yajl-ruby-1.1.0
Done installing documentation for blankslate, celluloid, classifier-reborn, coff
ee-script, coffee-script-source, execjs, fast-stemmer, ffi, hitimes, jekyll, jek
yll-coffeescript, jekyll-gist, jekyll-paginate, jekyll-sass-converter, jekyll-wa
tch, listen, parslet, posix-spawn, pygments.rb, rb-fsevent, rb-inotify, redcarpe
t, sass, timers, toml, yajl-ruby after 16 seconds
26 gems installed

「構文解析中に不正なマルチバイト文字列がありました」のエラー

ちょっとはまってしまったのでメモ

Rの関数にsource関数というものがあります。予め共通処理を書いておいたファイルを読み込む機能です。サブルーチンみたいなものでしょうか?

そこでsourceする際に、エラーが出る場合があります

> source("http://localhost/test.R")
以下にエラー source("http://localhost/test.R") :
構文解析中に不正なマルチバイト文字列がありました (102 行)
追加情報:	警告メッセージ:
In grepl("\n", lines, fixed = TRUE) :
入力文字列 102 はこのロケールでは不適切です

どうやら、エンコーディングの問題みたいです

使っているファイルのエンコーディングに合わせて明示的に示してやる必要があります

> source("http://localhost/test.R",encoding="utf-8")

eclipse+activatorでデバッグをWindows環境で行う

PlayFramework2.3から従来のplayコマンドではなくactivatorコマンドに変更となりました。それに伴いデバッグ方法も変わってしまったので、以下に書き留めておきます

環境

  • Windows8.1
  • eclipse 4.3
  • scala2.11
  • jdk1.7

設定

%UserProfile%\.activator\activatorconfig.txtにファイルを作成します。通常ですと、

c:\users\username\.activator\activatorconfig.txt

になるかと思います

このファイルに以下を記述します。addressはデバッグ用のポートなので開いているポートならばなんでも構いません。

-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000

実行

プロジェクトのフォルダにコマンドラインからアクセスし、activatorで起動します。8000番ポートでデバッグ用にポートが開いているのがわかります

Z:\test_project>activator
Listening for transport dt_socket at address: 8000
[info] Loading project definition from Z:\workspace\qrapp_api\project
[info] Set current project to qrapp_api (in build file:/Z:/workspace/qrapp_api/)
[qrapp_api] $ run
--- (Running the application from SBT, auto-reloading is enabled) ---
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/utsubo/.ivy2/cache/ch.qos.logback/lo
gback-classic/jars/logback-classic-1.1.1.jar!/org/slf4j/impl/StaticLoggerBinder.
class]
SLF4J: Found binding in [jar:file:/C:/Users/utsubo/.ivy2/cache/org.slf4j/slf4j-n
op/jars/slf4j-nop-1.6.4.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorSta
ticBinder]
[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
(Server started, use Ctrl+D to stop and go back to the console...)

次にEclipseからプロジェクトを右クリックし、DebugConfigurationからRemoteJavaApplicationをダブルクリックします。ポート番号8000を確認しScalaDebugger(SocketAttach)を選択。起動します。ブラウザを開いてアプリケーションにアクセスすれば、ブレークポイントでデバッグ可能となります。

設定はこの辺りに詳しく書いています

http://stackoverflow.com/questions/19473941/cant-debug-with-typesafe-activator

PlayFramework+EclipseでViews.htmlエラー

いつも忘れるのでメモ

PlayFrameworkをEclipseで開発しているとこのエラーが必ず出ます

object Application extends Controller{
def index()=Action{implicit request=>
Ok(views.html.index())			 // <=この行が赤いラインでエラー表示される
}
}

これの解決方法ですがプロジェクトのプロパティからJavaBuildPathを選択し、LibrariesタブからAddClassFolderで targetーscala-2.11ーclass_managedを追加

F5を押してリフレッシュすれば治ります

これが赤いままだとUnitテストでClassNotFoundエラーが出ます

Application.scala

package controllers

import play.api._
import play.api.mvc._
import java.io._
import org.apache.batik.dom.svg._
import org.apache.batik.transcoder._
import org.apache.batik.transcoder.image._
import org.apache.batik.util.XMLResourceDescriptor;
import org.w3c.dom.Document
import java.awt.Rectangle
import org.apache.fop.svg.PDFTranscoder

import play.api.libs.iteratee._
import play.api.data._
import play.api.data.Forms._

case class Image(
	filename:String,
	scale:Int,
	imagetype:String,
	svg:String
)

object Application extends Controller {

	val imageDataForm = Form(
			mapping(
					"filename"->text,
					"scale"->number,
					"type"->text,
					"svg"->text
			)(Image.apply)(Image.unapply)
	)
	
	def index()=Action{implicit request =>
		Ok(views.html.index())
	}

	def makeImage()=Action{implicit request =>
		val image=imageDataForm.bindFromRequest.get
		
		val is=new ByteArrayInputStream(image.svg.getBytes())
		import scala.concurrent.ExecutionContext.Implicits._
		Ok.chunked(Enumerator.outputStream { os =>
			val tin=new TranscoderInput(is)	
			val tot=new TranscoderOutput(os)	
			getTranscoder(image.imagetype, 0.7f) match{
				case Some(x) =>{
					println("transcode:x="+x)
					x.transcode(tin,tot)
				}
				
				case _ => None			
			}
			os.flush
			os.close	
			println("flush")
		} >>> Enumerator.eof).withHeaders(
				"Content-Type" -> (image.imagetype),
				"Content-Disposition"->("attachment; filename="+image.filename)
		)	 
	}


	def getParameter(request:play.api.mvc.Request[play.api.mvc.AnyContent],str:String) = {
		request.queryString.get(str).flatMap(_.headOption) match {
			case Some(x) => x
			case None => ""
		}
	}
	
	def getDocument(is:InputStream):Document ={
				val parser = XMLResourceDescriptor.getXMLParserClassName()
				val f = new SAXSVGDocumentFactory(parser)
				val doc = f.createDocument("http://www.w3.org/2000/svg",is)
				return doc
	}
 
	def	getTranscoder( transcoderType:String,	keyQuality:Float ) :Option[Transcoder]={
		println("getTranscoder:"+transcoderType)
				transcoderType match{
					case "image/jpeg" =>Option(getJPEGTranscoder(keyQuality))
					case "image/png" => Option(getPNGTranscoder())
					case "application/pdf" => Option(new PDFTranscoder())
					case	_ => None
				}
		}
	
	def	getJPEGTranscoder( keyQuality:Float):JPEGTranscoder= {
				val jpeg = new JPEGTranscoder()
				jpeg.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, keyQuality)
				return jpeg
		}
 
		def	getPNGTranscoder() :PNGTranscoder={
				return new PNGTranscoder();
		}
}

index.scala.html





こんな感じでいけるかと思います

batikをPlayFrameworkで使う

batikとはSVGからPDFやPNG等へ変換するすごーく便利なJavaのライブラリです。これをPlayframeworkでWebアプリとして構築してみました

準備

batickで使用するJarファイルをダウンロードしてきます。

http://mvnrepository.com/artifact/batik

この辺りから落としてくれば十分です

batik-anim.jar

batik-svgpp.jar

batik-awt-util.jar

batik-swing.jar

batik-bridge.jar

batik-transcoder.jar

batik-codec.jar

batik-ttf2svg.jar

batik-css.jar

batik-util.jar

batik-dom.jar

batik-xml.jar

batik-ext-1.6-1.jar

batik.jar

batik-ext.jar

batik-extension.jar

batik-gui-util.jar

batik-gvt.jar

batik-parser.jar

batik-rasterizer.jar

batik-script.jar

batik-slideshow.jar

batik-squiggle.jar

batik-svg-dom.jar

batik-svggen.jar

pdf-transcoder.jar

js.jar

w3c.jar

気がついたらこれだけダウンロードしていました。全部いるのでしょうか?

今回はPDFとJPEGとPNGをパラメタで分けて出力します

Windows7 HomePremiumでRemoteDeskTopServer

Windows7 HomePremiumでRDTを使おうとした際のメモ

  • サーバ側

Windows7 Home Premium SP1

  • クライアント側

iMac OS 10.9

まず、Windows7側にパッチを当てます。この辺りを参考にConcurrent_RDP_Patcher.zipをダウンロードし、パッチを当てるだけ。チェックボックスは2つとも外してももんだありません。

http://blog.livedoor.jp/rappazubon/archives/51943235.html

http://orebibou.com/2014/05/windows-7-home-premium%E3%81%A7%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%82%92%E6%9C%89%E5%8A%B9%E5%8C%96%E3%81%99%E3%82%8B/

次にはまったのがMac側。最初↓のMicrosoftRemoteDesktopを使用し接続しようとしてもエラー。

https://itunes.apple.com/jp/app/microsoft-remote-desktop/id715768417?mt=12

mac側からnmapでWindowsのポートを調べても特に問題なく3389ポートは開いている。

実はこのMac側のクライアントが悪かったようです。こちら↓のRemoteDesktopConnectionを使用すると問題なくつながります。

http://www.microsoft.com/ja-jp/download/details.aspx?id=18140

参考まで

eclipseでTomcatの設定

いつも忘れてしまうのでメモ

環境

MacOS10.9
tomcat7

brew install tomcat7

java

oracle jdkをインストールし、シンボリックリンク

$ which java

/Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home//bin/java

eclipse kepler

インストール

EclipseのClassicをインストールするとサーバランタイムがインストールされずに、TOMCATアプリなど作成する際にデバッグに困ってしまいます。

サーバランタイムをインストールするには、予めBrewでTomcatをインストールした後に、ヘルプのinstall new softwareから

http://download.eclipse.org/releases/kepler

を選択し、いかの2つのプラグインをインストールします。

  • JST Server Adapters
  • JST Server Adapters Extensions

その後、環境設定ーServerーRuntimeEnvironmentsのaddでtomcatを追加するのですが、この際にディレクトリに以下を入力します

/usr/local/Cellar/tomcat7/7.0.55/libexec

これでサーバランタイムが設定可能となります。

この辺りの内容はこちらから引用しています

http://stackoverflow.com/questions/2000078/apache-tomcat-not-showing-in-eclipse-server-runtime-environments

http://stackoverflow.com/questions/17745834/unknown-version-of-tomcat-was-specified-with-tomcat-7-0-42

SQLiteにユーザ定義関数を追加しTOMCAT+DBCPで利用する

ユーザ定義関数の追加

SQLiteにはストアドプロシージャはなく、その代わりにユーザ定義関数を追加し、同様の処理を行うようにできます。


	
	public class TestFunc extends Function{
		@Override
		protected void xFunc() throws SQLException
		{
			try{
				String a = value_text(0);
				String b = value_text(1);
				result(Integer.parseInt(a)+Integer.parseInt(b));
			}catch(Exception e){
				throw new SQLException(e.getMessage());
			}
		}
	}

org.sqlite.Functionを継承したクラスを作成し、その中のxFuncをオーバラードしたメソッで実装する関数を定義しresultで戻します。

今回の場合には文字列で定義した数字を足しあわせて返すという関数を定義しました。

これを利用する際にはJDBCのコネクションに対しFunction.createでバインドしてやります


			InitialContext ic = new InitialContext();
			DataSource ds = (DataSource)ic.lookup("java:comp/env/test");
			Connection conn=ds.getConnection();
			conn.setAutoCommit(false);
			Function.create(conn,"my_func",new TestFunc());
	
			PreparedStatement stmt=conn.prepareStatement("select my_func(?,?)");
			stmt.setString(1,"1");
			stmt.setString(2,"3");
			ResultSet rs=stmt.executeQuery();
			while(rs.next()){
				out.println(rs.getString(1));
			}

バインドする際にSQL文内で呼ぶ関数名を同時に定義します。その後は通常のJDBCの処理と同じです。

DBCPで使う

DBCPで使うサンプルです

  • context.xml
				 	
  • TestServlet.java
public class TestServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	
	@Override
	public void init(ServletConfig sc) throws ServletException {
		super.init(sc);
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		doPost(req, res);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		res.setContentType("text/html;charset=utf-8");
		PrintWriter out=res.getWriter();
		
		//http://stackoverflow.com/questions/6489514/apache-commons-dbcp-connection-object-problem-thread-classcastexception-in-org
		//http://www.ksky.ne.jp/~snbhsmt/commons-dbcp.html
		//http://grokbase.com/t/tomcat/users/052spdat5s/tomcat-5-5-7-using-builtin-jdbc-connection-pool-cant-access-real-connection-accesstounderlyingconnectionallowed-true
		try{
			
			InitialContext ic = new InitialContext();

			BasicDataSource ds = (BasicDataSource)ic.lookup("java:comp/env/test");
								//ds.setAccessToUnderlyingConnectionAllowed(true);
								DelegatingConnection dcon=(DelegatingConnection)ds.getConnection();
			
								DelegatingStatement dstmt = (DelegatingStatement)dcon.createStatement();
								PoolableConnection pconn=(PoolableConnection)dstmt.getDelegate().getConnection();

								Connection conn=pconn.getInnermostDelegate();
			conn.setAutoCommit(false);
			Function.create(conn,"my_func",new TestFunc());
	
			PreparedStatement stmt=conn.prepareStatement("select my_func(?,?)");
			stmt.setString(1,"1");
			stmt.setString(2,"3");
			ResultSet rs=stmt.executeQuery();
			while(rs.next()){
				out.println(rs.getString(1));
			}
			dcon.close();// 140916 閉じ忘れるとTOMCAT起動時に止まる
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	public class TestFunc extends Function{
		@Override
		protected void xFunc() throws SQLException
		{
			try{
				String a = value_text(0);
				String b = value_text(1);
				result(Integer.parseInt(a)+Integer.parseInt(b));
			}catch(Exception e){
				throw new SQLException(e.getMessage());
			}
		}
	}
}

ここでのポイントはDBCPのコネクションプールからJDBCのコネクションを取得する際に実際のコネクションを取得してやる必要があります。

			BasicDataSource ds = (BasicDataSource)ic.lookup("java:comp/env/test");
						//ds.setAccessToUnderlyingConnectionAllowed(true);
						DelegatingConnection dcon=(DelegatingConnection)ds.getConnection();
			
						DelegatingStatement dstmt = (DelegatingStatement)dcon.createStatement();
						PoolableConnection pconn=(PoolableConnection)dstmt.getDelegate().getConnection();

						Connection conn=pconn.getInnermostDelegate();

この部分です。詳細は↓あたりを参考にしてください。

http://stackoverflow.com/questions/6489514/apache-commons-dbcp-connection-object-problem-thread-classcastexception-in-org

http://www.ksky.ne.jp/~snbhsmt/commons-dbcp.html

http://grokbase.com/t/tomcat/users/052spdat5s/tomcat-5-5-7-using-builtin-jdbc-connection-pool-cant-access-real-connection-accesstounderlyingconnectionallowed-true

なおJDBCはsqlite-jdbc-3.7.2.jarではなくsqlite-jdbc-3.8.5-pre1.jarを使用してください。Function.create内のinstanceofでconnectionが実コネクションかどうか判定しているのですが、JDBCが古いほうだと何故かここでエラーになってしまいます。

こんな感じでSQLite+DBCPでユーザ定義関数が追加できます。参考になれば幸いです

20140916追記

DelegateingConnectionを取得した際にコネクションを閉じ忘れるとTOMCAT起動時にエラーというか無限ループに陥ります。注意