Found a better way to enable SSL in Sinatra than "Sinatra+Thin+SSL". This is a generic way and does not require Thin.
2014年12月16日火曜日
2014年10月1日水曜日
Sinatra + Thin + SSL
Finally found a way to enable SSL in Sinatra + Thin.
# [2014/12/16]
# Found a better way.
# See "Sinatra + SSL".
Start this script (sinatra+thin+ssl.rb) then type:
# [2014/12/16]
# Found a better way.
# See "Sinatra + SSL".
Start this script (sinatra+thin+ssl.rb) then type:
curl -k https://localhost/and you will see "Hello, SSL."
2014年9月20日土曜日
MissingTableException on Google Cloud SQL
If you are using JDO to access Google Cloud SQL and suffering from MissingTableException like below:
and if your table names contain lowercase letters, probably the issue can be solved by setting "datanucleus.identifier.case" properly.
"JDO : Datastore Identifiers" says "By default, DataNucleus will capitalise names". Therefore, if your table names contain lowercase letters, "datanucleus.identifier.case" should be set explicitly.
The valid values for "datanucleus.identifier.case" are UpperCase, LowerCase or PreserveCase (or MixedCase; See Change "datanucleus.identifier.case" 'PreserveCase' to be 'MixedCase' to be match internal namings). So, for example, your jdoconfig.xml will have to have the entry like the following.
If you are developing your GAE application on Windows or Mac OS X, you may not encounter this case sensitivity problem until you deploy your application onto GAE. See "9.2.2 Identifier Case Sensitivity" (MySQL Reference Manual) for details.
org.datanucleus.store.rdbms.exceptions.MissingTableException: Required table missing : "`TABLE NAME`" in Catalog "" Schema "". DataNucleus requires this table to perform its persistence operations. Either your MetaData is incorrect, or you need to enable "datanucleus.autoCreateTables"
and if your table names contain lowercase letters, probably the issue can be solved by setting "datanucleus.identifier.case" properly.
"JDO : Datastore Identifiers" says "By default, DataNucleus will capitalise names". Therefore, if your table names contain lowercase letters, "datanucleus.identifier.case" should be set explicitly.
The valid values for "datanucleus.identifier.case" are UpperCase, LowerCase or PreserveCase (or MixedCase; See Change "datanucleus.identifier.case" 'PreserveCase' to be 'MixedCase' to be match internal namings). So, for example, your jdoconfig.xml will have to have the entry like the following.
<property name="datanucleus.identifier.case" value="LowerCase"/>
If you are developing your GAE application on Windows or Mac OS X, you may not encounter this case sensitivity problem until you deploy your application onto GAE. See "9.2.2 Identifier Case Sensitivity" (MySQL Reference Manual) for details.
2014年7月19日土曜日
JDO:カラムサイズは十分大きいのにデータが保存できないという問題を解消する方法
JDO を使っているときに表示される次のようなエラーメッセージは、
保存しようとしているデータのサイズが、対応するデータベーステーブルのカラムのデータサイズよりも大きいということを意味している。しかし、カラムサイズが十分大きくてもこのエラーが起きることがある。例えば、対応するカラムの型を TEXT で定義しているにもかかわらず(MySQL 的には TEXT は 65535 まで OK であるにもかかわらず)、上記のようなエラーが出てしまうことがある。
この問題は、@Column アノテーションに length を追加して、最大長を指定すれば解消するようだ。具体的には、
となっているところを、
というような具合に変更する。
Attempt to store value "{DATA}" in column "`{COLUMN-NAME}`" that has maximum length of 255. Please correct your data!
保存しようとしているデータのサイズが、対応するデータベーステーブルのカラムのデータサイズよりも大きいということを意味している。しかし、カラムサイズが十分大きくてもこのエラーが起きることがある。例えば、対応するカラムの型を TEXT で定義しているにもかかわらず(MySQL 的には TEXT は 65535 まで OK であるにもかかわらず)、上記のようなエラーが出てしまうことがある。
この問題は、@Column アノテーションに length を追加して、最大長を指定すれば解消するようだ。具体的には、
@Persistent @Column(name = "comment") private String comment;
となっているところを、
@Persistent
@Column(name = "comment", length = 65535)
private String comment;
というような具合に変更する。
2014年7月10日木曜日
JDO Enum Mapping
Java Data Objects 3.0 (JSR 243) の仕様によると、Enum の値をストレージに永続化する際、ストレージでの型が数値型であれば Enum.ordinal() メソッドの返す値が、文字列型であれば Enum.name() メソッドの返す値が用いられるとのこと。 (15.1 Column Elements / Mapping enums)
Enum にマッピングされるカラムのデフォルトの jdbc-type は VARCHAR なので、ordinal() の値を使いたいときは、当該カラムに対して明示的に jdbc-type を指定したほうがよい。有効な jdbc-type は次のとおりで、全て大文字か全て小文字かのどちらかで指定する。 (18.4 ELEMENT column)
DataNucleus は、name() や ordinal() ではない別の値で Enum を永続化する拡張を提供している。下記は、「JDO : Persistable Field Types」 に挙げられている例である。
name() で永続化する場合は 「"RED", "GREEN", "BLUE", "YELLOW"」、 ordinal() で永続化する場合は 「0, 1, 2, 3」 であるが、上記の例のようにすれば、「1, 3, 5, 8」 という値で永続化される。
ただ、ここに誤りやすいポイントがある。DataNucleus の拡張を使う場合、値のデータ型は short でなければならないようだ。例えば上記の実装で getEnumByValue(short value) となっているところを getEnumByValue(int value) に変更すると、拡張機能が動作しない。逆にデータサイズを小さくする getEnumByValue(byte value) でも、やはり動作しない。ただ、ストレージでの型は必ずしも SMALLINT でなくてもよいようだ。
例えば、ClientType という enum を定義し、PUBLIC と CONFIDENTIAL というエントリーを持たせ、それぞれ 1, 2 という値で永続化したい場合、その実装は次のようになる。
この ClientType 型のフィールドを持つ ClientEntity クラスを定義するとすれば次のような感じになる。
ClientEntity クラスに対応するテーブル "client" を MySQL で定義するならば、次のような感じ。
Enum にマッピングされるカラムのデフォルトの jdbc-type は VARCHAR なので、ordinal() の値を使いたいときは、当該カラムに対して明示的に jdbc-type を指定したほうがよい。有効な jdbc-type は次のとおりで、全て大文字か全て小文字かのどちらかで指定する。 (18.4 ELEMENT column)
CHAR, VARCHAR, LONGVARCHAR, NUMERIC, DECIMAL, BIT, TINYINT, SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, BINARY, VARBINARY, LONGVARBINARY, DATE, TIME, TIMESTAMP
DataNucleus は、name() や ordinal() ではない別の値で Enum を永続化する拡張を提供している。下記は、「JDO : Persistable Field Types」 に挙げられている例である。
public enum MyColour
{
RED((short)1), GREEN((short)3), BLUE((short)5), YELLOW((short)8);
private short value;
private MyColour(short value)
{
this.value = value;
}
public short getValue()
{
return value;
}
public static MyColour getEnumByValue(short value)
{
switch (value)
{
case 1:
return RED;
case 3:
return GREEN;
case 5:
return BLUE;
default:
return YELLOW;
}
}
}
@Extensions({
@Extension(vendorName="datanucleus",
key="enum-getter-by-value", value="getEnumByValue"),
@Extension(vendorName="datanucleus",
key="enum-value-getter", value="getValue")
})
MyColour colour;
name() で永続化する場合は 「"RED", "GREEN", "BLUE", "YELLOW"」、 ordinal() で永続化する場合は 「0, 1, 2, 3」 であるが、上記の例のようにすれば、「1, 3, 5, 8」 という値で永続化される。
ただ、ここに誤りやすいポイントがある。DataNucleus の拡張を使う場合、値のデータ型は short でなければならないようだ。例えば上記の実装で getEnumByValue(short value) となっているところを getEnumByValue(int value) に変更すると、拡張機能が動作しない。逆にデータサイズを小さくする getEnumByValue(byte value) でも、やはり動作しない。ただ、ストレージでの型は必ずしも SMALLINT でなくてもよいようだ。
例えば、ClientType という enum を定義し、PUBLIC と CONFIDENTIAL というエントリーを持たせ、それぞれ 1, 2 という値で永続化したい場合、その実装は次のようになる。
public enum ClientType
{
PUBLIC((short)1),
CONFIDENTIAL((short)2);
private static final ClientType[] mValues = values();
private final short mValue;
private ClientType(short value)
{
mValue = value;
}
public short getValue()
{
return mValue;
}
public static ClientType getByValue(short value)
{
if (value < 1 || mValues.length < value)
{
return null;
}
return mValues[value - 1];
}
}
この ClientType 型のフィールドを持つ ClientEntity クラスを定義するとすれば次のような感じになる。
@PersistenceCapable(
identityType = IdentityType.APPLICATION,
table = "client",
detachable = "true")
public class ClientEntity
{
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Column(name = "number")
private int number;
@Persistent(defaultFetchGroup = "true")
@Column(name = "client_type", jdbcType = "TINYINT")
@Extensions({
@Extension(vendorName = "datanucleus",
key = "enum-getter-by-value", value = "getByValue"),
@Extension(vendorName = "datanucleus",
key = "enum-value-getter", value = "getValue")
})
private ClientType clientType;
public int getNumber()
{
return number;
}
public ClientType getClientType()
{
return clientType;
}
public void setClientType(ClientType clientType)
{
this.clientType = clientType;
}
}
ClientEntity クラスに対応するテーブル "client" を MySQL で定義するならば、次のような感じ。
CREATE TABLE client
(
number INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
client_type TINYINT UNSIGNED NOT NULL DEFAULT 1
);
2014年4月19日土曜日
2 の 256 乗を計算してみた
2256 を十進数で表すと 78 桁で、無量大数の十億倍くらいの値であることが分かりました。
ちゃんとした方法でランダムに生成した 256 ビットのハッシュ値が偶然ぶつかるかもしれないなんてことを心配するのは馬鹿げていることを理解しました。いや、馬鹿げているのは理解していたのですけど、実際に計算してみると、どれだけ途方もなく馬鹿げているのかが分かった、という話です。
どれくらい大きな数字なのか例えで考えてみます。
ちなみに、Java の long は 64 ビットで 10 進数だと 20 桁 (2000 京弱)。10 億人が毎秒消費なら1000 年くらいで使い切る計算。秒間 10 億を千年。それを超えるような想定をしなければならないシステムを作ることはないでしょうね。推測可能でよい ID なら、long で連番振っておけば十分でしょうね。
※Blogger の都合でサロゲートペアの文字が化けるため、平仮名で表記。 Blogger もうやだ・・・。
どれくらい大きな数字なのか例えで考えてみます。
- 太陽の寿命が来るまで今から 50 億年のあいだ、
- 100 億人の人が、
- 毎ナノ秒 1 兆個の数値を消費していく活動があり、
- その活動を、太陽系が属するこの銀河系の全ての星(~2,000 億くらい)でおこなうと、
ちなみに、Java の long は 64 ビットで 10 進数だと 20 桁 (2000 京弱)。10 億人が毎秒消費なら1000 年くらいで使い切る計算。秒間 10 億を千年。それを超えるような想定をしなければならないシステムを作ることはないでしょうね。推測可能でよい ID なら、long で連番振っておけば十分でしょうね。
21 | = | 2 |
22 | = | 4 |
23 | = | 8 |
24 | = | 16 |
25 | = | 32 |
26 | = | 64 |
27 | = | 128 |
28 | = | 256 |
29 | = | 512 |
210 | = | 1,024 |
211 | = | 2,048 |
212 | = | 4,096 |
213 | = | 8,192 |
214 | = | 16,384 |
215 | = | 32,768 |
216 | = | 65,536 |
217 | = | 131,072 |
218 | = | 262,144 |
219 | = | 524,288 |
220 | = | 1,048,576 (7 桁) |
= | 104 万 8576 | |
221 | = | 2,097,152 (7 桁) |
= | 209 万 7152 | |
222 | = | 4,194,304 (7 桁) |
= | 419 万 4304 | |
223 | = | 8,388,608 (7 桁) |
= | 838 万 8608 | |
224 | = | 16,777,216 (8 桁) |
= | 1677 万 7216 | |
225 | = | 33,554,432 (8 桁) |
= | 3355 万 4432 | |
226 | = | 67,108,864 (8 桁) |
= | 6710 万 8864 | |
227 | = | 134,217,728 (9 桁) |
= | 1 億 3421 万 7728 | |
228 | = | 268,435,456 (9 桁) |
= | 2 億 6843 万 5456 | |
229 | = | 536,870,912 (9 桁) |
= | 5 億 3687 万 912 | |
230 | = | 1,073,741,824 (10 桁) |
= | 10 億 7374 万 1824 | |
231 | = | 2,147,483,648 (10 桁) |
= | 21 億 4748 万 3648 | |
232 | = | 4,294,967,296 (10 桁) |
= | 42 億 9496 万 7296 | |
248 | = | 4,281,474,976,710,656 (16 桁) |
= | 4281 兆 4749 億 7671 万 656 | |
264 | = | 18,446,744,073,709,551,616 (20 桁) |
= | 1844 京 6744 兆 737 億 955 万 1616 | |
2128 | = | 340,282,366,920,938,463,463,374,607,431,768,211,456 (39 桁) |
= | 340 澗 2823 溝 6692 穣 938 じょ※ 4634 垓 6337 京 4607 兆 4317 億 6821 万 1456 |
|
2256 | = | 115,792,089,237,316,195,423,570,985,008,687,907,853, 269,984,665,640,564,039,457,584,007,913,129,639,936 (78 桁) |
= | 1157920892 無量大数 3731 不可思議 6195 那由他 4235 阿僧祇 7098 恒河沙 5008 極 6879 載 785 正 3269 澗 9846 溝 6564 穣 564 じょ※ 394 垓 5758 京 4007 兆 9131 億 2963 万 9936 |
※Blogger の都合でサロゲートペアの文字が化けるため、平仮名で表記。 Blogger もうやだ・・・。
2014年3月17日月曜日
AccessControlException when using local MySQL for Google Cloud SQL
If you are developing an application for Google App Engine + Google Cloud SQL and using local MySQL during development, you may encounter AccessControlExeption like below.
Reading the stack trace, you will find the point where Thread is created.
Below is an excerpt from the source code of executeInternal method.
So, check your jdoconfig.xml. If DatastoreReadTimeoutMillis and/or DatastoreWriteTimeoutMillis are configured, comment them out during development.
java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "modifyThreadGroup")This exception is raised when your application tries to use Thread because Google App Engine does not allow application to use Thread.
Reading the stack trace, you will find the point where Thread is created.
at java.lang.Thread.<init>(Thread.java:444) at java.util.TimerThread.<init>(Timer.java:499) at java.util.Timer.<init>(Timer.java:101) at java.util.Timer.<init>(Timer.java:146) at com.mysql.jdbc.ConnectionImpl.getCancelTimer(ConnectionImpl.java:392) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2195)From the information above, it can be guessed that a Thread instance will not be created if PreparedStatement.executeInternal method does not call ConnectionImpl.getCancelTimer method.
Below is an excerpt from the source code of executeInternal method.
if (locallyScopedConnection.getEnableQueryTimeouts() && this.timeoutInMillis != 0 && locallyScopedConnection.versionMeetsMinimum(5, 0, 0)) { timeoutTask = new CancelTask(this); locallyScopedConnection .getCancelTimer() .schedule(timeoutTask, this.timeoutInMillis);The code snippet indicates that getCancelTimer method is not called if timeouts are not set.
So, check your jdoconfig.xml. If DatastoreReadTimeoutMillis and/or DatastoreWriteTimeoutMillis are configured, comment them out during development.
登録:
投稿 (Atom)