slim3-user-japanに投稿出来ない
slim3について質問があったのでディスカッションに投稿したら投稿エラーで弾かれた。投稿者を制限してるのかなー?最近スパムも多いみたいだし・・・。
投稿しようとした内容はfilterInMemory、sortInMemory関連。
filterInMemory、sortInMemory がサポートされたけれど、InMemory処理後に特定範囲の値の取得は独自で実装する事になるのかな?offsetInMemory、limitInMemoryみたいなメソッドが用意されると良いのにな。
Gyaoを全画面で見る
IE8のズーム機能でおk
PersistenceManagerインスタンスの寿命
Google App Engine for Java アプリのレスポンスが5秒程待たされる場合があるのですが、原因を調べてみるとPersistenceManagerインスタンスの取得に時間がかかってしまい結果レスポンスが落ちるようです。
PersistenceManagerインスタンスはおよそ2分程でその寿命が尽きてしまいその後インスタンス取得の処理が走ると新たにインスタンスを生成しています。PersistenceManagerインスタンスの取得は高価で新規のインスタンス取得には大体2秒程度かかります。アプリケーションが常に動いているならばインスタンスの寿命が尽きる事はないのですが、私のアプリのようにあまり使用されていない場合は頻繁にPersistenceManagerインスタンスの寿命が尽きてしまいます。
そこでインスタンスの寿命が尽きてしまわないようcronで定期的にPersistenceManagerインスタンスを取得するようにしました。ソースは以下のような感じ。
package simplebookmarks.servlet; import java.io.IOException; import java.util.logging.Logger; import javax.jdo.PersistenceManager; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import simplebookmarks.PMF; public class CronServlet extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(CronServlet.class.getName()); public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { PersistenceManager pm = null; try { pm = PMF.get().getPersistenceManager(); } finally { pm.close(); } logger.info("PMF.get().getPersistenceManager() : ok."); req.getRequestDispatcher("/cron.jsp").forward(req, resp); } }
cron.xmlはこんな感じで。
<?xml version="1.0" encoding="UTF-8"?> <cronentries> <cron> <url>/cron</url> <description>Pool the instance every 2 minutes</description> <schedule>every 2 minutes</schedule> </cron> </cronentries>
これで快適にアプリを利用出来るようになりました。
*ひょっとしたら何かしらオプション指定でインスタンスの寿命を延ばすことが出来るかも?
JDOクエリで例外とその対応
Google App Engine for Java 少しずつ勉強しています。
JDOでBigTableへの問い合わせを下記のようなコードで書いていました。
String query = "select from " + Collection.class.getName() + " where author == '" + user.getEmail() + "'" + " order by displayOrder"; List<Collection> collections = (List<Collection>) pm.newQuery(query).execute();
一応動いているんですが頻繁に例外が発生します。こんな感じで。
09-30 11:41PM 28.654 com.google.appengine.repackaged.com.google.common.base.FinalizableReferenceQueue$SystemLoader loadFinalizer: Not allowed to access system class loader. 09-30 11:41PM 28.667 com.google.appengine.repackaged.com.google.common.base.internal.Finalizer getInheritableThreadLocalsField: Couldn't access Thread.inheritableThreadLocals. Reference finalizer threads will inherit thread local values. 09-30 11:41PM 28.669 com.google.appengine.repackaged.com.google.common.base.FinalizableReferenceQueue <init>: Failed to start reference finalizer thread. Reference cleanup will only occur when new references are created. java.lang.reflect.InvocationTargetException
どうして・・・。理由が分からなくてずっとほったらかしにしていたのですがGAE/Jのドキュメントを読んでいると下記のような書き方も出来るようなので試してみました。
Query query = pm.newQuery(Collection.class); query.setFilter("author == authorParam"); query.setOrdering("displayOrder asc"); query.declareParameters("String authorParam"); List<Collection> collections = (List<Collection>) query.execute(user.getEmail());
すると例外が発生しなくなりました!(今のところ)。アプリがサクサク動いています。これぞGAE/Jだと言わんばかり!
JDOQL 文字列の構文だとその解釈に問題が出たりするのかな?。誰か詳しい人教えて下さい <(_ _)>
と言う訳でクエリは javax.jdo.Query を用いて組み立てるのが吉らしいです。
追記その1:例外はやっぱり出てしまいました。でも前よりは少なくなったような?しばらく様子見と勉強。Memcache を利用するとかの話じゃないよなぁ・・・。
追記その2:id:higayasuoさんよりコメントを頂きました。Finalizerは無視していいとの事。
シンプルなオンラインブックマーク Simple Bookmarks
http://simplebookmarks.appspot.com/
単一項目のチェックボックスを複数使うには
サブミットされるフォームデータにチェックされなかった項目は含まれないため, 繰り返しの中にチェックボタンしか項目がない場合, 繰り返しの数を正確に判定できない場合があります. これを回避するには,繰り返しの中に隠し項目を含めるようにします.
例:テンプレートHTML (foo.html)
<input type="hidden" id="optionItemsSave" /> <div id="optionItems"> <label> <input type="checkbox" id="checked" value="dummy" /> <span id="name" te:omittag="true">dummy</span> </label> <input type="hidden" id="name-2" value="dummy" /> </div>
隠し項目を含めるイメージがソースを読まないと想像付きにくいかも。とりあえずメモ。
単一のチェックボックスでdisabledを適応させる
disabled属性はリクエストパラメータに含まれません。そのため、サーバー側からチェックされていないように見えます。
hiddenに値を持たせ、disabled属性の値を@PageScopeで持つ事でdisable属性の付いたcheckboxの値を扱う事が出来ます。
checkbox.html
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>checkbox disabled.</title> </head> <body> <form id="cform"> <input type="checkbox" id="c1" name="c1" disabled="disabled"/>c1<br/> <input type="checkbox" id="c2" name="c2" disabled="disabled"/>c2<br/> <input type="checkbox" id="c3" name="c3"/>c3<br/> <input type="submit"/> <input type="hidden" id="c1hidden"/> <input type="hidden" id="c2hidden"/> <input type="hidden" id="c3hidden"/> </form> </body> </html>
CheckboxPage.java
package example.teeda; import org.seasar.teeda.extension.annotation.scope.PageScope; public class CheckboxPage { public boolean c1; public boolean c2; public boolean c3; @PageScope public boolean c1Disabled; @PageScope public boolean c2Disabled; @PageScope public boolean c3Disabled; public Class initialize() { //チェックボックスの値 c1 = true; c2 = false; c3 = false; //チェックボックスのdisabledプロパティ c1Disabled = true; c2Disabled = true; c3Disabled = false; return null; } public Class prerender() { System.out.println("c1:" + c1); System.out.println("c2:" + c2); System.out.println("c3:" + c3); return null; } public boolean getC1hidden() { return c1; } public boolean getC2hidden() { return c2; } public boolean getC3hidden() { return c3; } public void setC1hidden(boolean b) { if (c1Disabled) { c1 = b; } } public void setC2hidden(boolean b) { if (c2Disabled) { c2 = b; } } public void setC3hidden(boolean b) { if (c3Disabled) { c3 = b; } } }
--user-data-dirオプションを簡単に追加するスクリプト
先日エントリーした「Google Chrome アプリケーションショートカットを個別のユーザーデータで起動する」にある--user-data-dirオプションを簡単に追加するvbsスクリプトを書きました。アプリケーションのショートカットを作成後、下記スクリプトにドラッグ&ドロップで追加されます。ユーザーデータフォルダはsUserDataFolder = "hogehoge"のhogehogeを書き換えればいくつも作る事ができます。
ユーザーデータフォルダ設定 - hogehoge - .vbs
Option Explicit Dim sUserDataFolder sUserDataFolder = "hogehoge" Call Main(WScript.Arguments) Private Sub Main(oArgs) If oArgs.Count = 0 Then WScript.Echo "ショートカットをこのアイコンへドラッグ&ドロップしてください。" Exit Sub End If WScript.Echo SetUserDataFolder(oArgs) End Sub Private Function SetUserDataFolder(oArgs) Dim WshShell, re, i, flg, oShellLink, oMatchesLnk, oMatchesChrome, oMatchesUserDataDir, sOption sOption = " --user-data-dir=" & Chr(34) & "..\User Data\" & sUserDataFolder & Chr(34) flg = False Set WshShell = WScript.CreateObject("WScript.Shell") Set re = new RegExp re.Global = True For i = 0 To oArgs.Count - 1 re.Pattern = "(.lnk)" Set oMatchesLnk = re.Execute(oArgs(i)) If oMatchesLnk.Count = 1 Then Set oShellLink = WshShell.CreateShortcut(oArgs(i)) re.Pattern = "chrome.exe" Set oMatchesChrome = re.Execute(oShellLink.TargetPath) If oMatchesChrome.Count = 1 Then If oMatchesChrome(0) = "chrome.exe" Then flg = True re.Pattern = "--user-data-dir" Set oMatchesUserDataDir = re.Execute(oShellLink.Arguments) If oMatchesUserDataDir.Count = 0 Then With oShellLink oShellLink.Arguments = sOption & " " & .Arguments Call oShellLink.Save() End With End If End If End If End If Next If flg Then SetUserDataFolder = "ユーザーデータフォルダ " & sOption & " を設定しました。" Else SetUserDataFolder = "ユーザーデータフォルダを設定出来ませんでした。" End If End Function