2010-10-25

SQLite on SQuirrel

為了要處理 firefox 資料肥大的問題, 得進去firefox 的place.sqlite看一下.
找了一下, 看有沒有 可以在 squirrel上面可以直接 使用的方法.

最簡單就是找到 sqlite jdbc driver 裝上去.
下載
1. SQLiteJDBC

設定

  1. Click on the Drivers tab on the left, and add a new driver

      Name : SQLite Driver
      Example URL : jdbc:sqlite://
      Website URL: http://www.zentus.com/sqlitejdbc/


  2. Click on the Extra Class Path tab. Click the Add button, then navigate and select the sqlitejdbc jar file.
  3. Click List Drivers and org.sqlite.JDBC will appear in the Class Name field.
  4. Click Button[Ok].

2010-09-29

log4j on Jboss

最近把 project 到了一個段落, 要回來處理一下 log 的問題.
看了很多篇文章, 都發現jboss 上面 要跑含 log4j 的code 像是會有點問題. 看很多網頁, 沒有真的去試試看還不知道會是怎樣. 是了一兩個在 jboss 5.0 jboss 4.0 的解決方案, 好像不是適用於 jboss 6.0 M3.
就硬著把 ${JBOSS_HOME}/server/default/deply 看一輪, 發現到有一個檔案 jboss-logging.xml 裡面有用到jboss 自己的 log , 還有幾個appended 是用 log4j. 想說那就來試試看吧.
想說不用太複雜可以跑就好, 就找 ${JBOSS_HOME}/server/standard/ 來改好了. 要把log4j.jar 放見 ${JBOSS_HOME}/server/stardand/lib 裡面, 發現哇勒 裡面已經有放 一個log4j.jar. 跟在default裡面的lib 不一樣, default/lib 裡面一個東西都沒有, 這邊居然有. 簡單寫一個 web app, 用到log4j 去放.

修改 ${JBOSS_HOME}/server/stardand/deploy/jboss-logging.xml
1. 我是選用 他原有的 FILE 下去修改 , 新增到 檔案裡頭

<size-rotating-file-handler
file-name="${jboss.server.log.dir}/app.log"
name="FILE-APP"
autoflush="true"
append="true"
rotate-size="500k"
max-backup-index="5">

<error-manager>
<only-once/>
</error-manager>

<formatter>
<pattern-formatter pattern="%d %-5p [%c] (%t) %m%n"/>
</formatter>
</size-rotating-file-handler>

2. 新增相對的 logger

<logger category="test.logger">
<level name="DEBUG"/>
<handlers>
<handler-ref name="CONSOLE"/>
<handler-ref name="FILE-APP"/>
</handlers>
</logger>

3. 撰寫測試 log4j 的code

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;

@WebServlet(name = "Test", urlPatterns = {"/Test"})
public class Test extends HttpServlet {

private static Logger log = Logger.getLogger("test.logger");

/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
log.debug("Log Debug");
log.info("Log Info");
} finally {
out.close();
}
}

// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/**
* Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/**
* Returns a short description of the servlet.
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}



測試一下, 發現很正常, 可以在jboss container 下面, 正常的使用.不用像 jboss docs 裡面寫得, 得用 jboss 包過得 Logger 下去做事情.

ps: 測試的過程中, 我將 standard/lib/log4j.jar copy to default/lib/ 來使用

2010-09-09

JBoss 啟動參數

一開始裝好 jboss 大概都只會用 ${JBOSS_HOME}/bin/run.bat. 這樣的用法大概就是啟動 ${JBOSS_HOME}/server/default 的設定. 不過現在 已經從 Installation and getting started guide 研究出下參數啟動.

run.bat -b 192.168.1.1
這樣的下法, 可以讓server 以外的可以連近來, 最早在做測試的時候都是用localhost , 直到要連接兩台的時候發現怎樣都過不去. 以為是防火牆, 還是那個東西沒有打開. 後來發現, 原來jboss 初始值是讓你在 開發用的. 要等到正式啟用在給他相對應的ip , 這是為了安全性考量.

run.bat -c stardand
這樣的下法, 就可以啟動 ${JBOSS_HOME}/server/stardand 的server .

2010-08-31

Jboss JMS Bridge (Jboss to Jboss)

今天開始測試 Jboss JMS Bridge.
看過不少的document後, 看起來 jboss bridge 是用內建JNDI 幫你連接到 Remote JMS Server. 等於省掉了程式開發者自己連接 JNDI等等的 JMS 事項. 另外一個好處就是, Local and Remote 各有一個Queue , 然後 AP server 幫你作保證送達的工作.
下面用到的範例都是從 HornetQ Example 拿出來改得, 因為有些並非原廠文件寫得那樣.

先來運用原廠的 單機兩個Queue作 JMS bridge.
  • /queue/source 是用來接收client 送出來的 message
  • /queue/target 是用來接收 /queue/source 轉送過來的message
  • jms-bridge-jboss-beans.xml 是在jee server 下面 設定的bridge beans

首先 在 hornetq-jms.xml 新增兩個 queue

<queue name="source">
<entry name="/queue/source"/>
</queue>
<queue name="target">
<entry name="/queue/target"/>
</queue>

新增一個 jms-bridge-jboss-beans.xml 到 ${JBOSS_HOME}/server/default/deploy/hornetq
要注意的地方, 在原廠的設定中 target 的 user and password 是沒有設定的. 沒有設定是沒辦法正常使用的, 所以我把 guest/guest 加進去才可以正常運作.

<?xml version="1.0" encoding="UTF-8"?>

<deployment xmlns="urn:jboss:bean-deployer:2.0">

<bean name="JMSBridge" class="org.hornetq.jms.bridge.impl.JMSBridgeImpl">
<!-- HornetQ must be started before the bridge -->
<depends>HornetQServer</depends>
<constructor>
<!-- Source ConnectionFactory Factory -->
<parameter>
<inject bean="SourceCFF"/>
</parameter>
<!-- Target ConnectionFactory Factory -->
<parameter>
<inject bean="TargetCFF"/>
</parameter>
<!-- Source DestinationFactory -->
<parameter>
<inject bean="SourceDestinationFactory"/>
</parameter>
<!-- Target DestinationFactory -->
<parameter>
<inject bean="TargetDestinationFactory"/>
</parameter>
<!-- Source username (no username here) -->
<parameter><null /></parameter>
<!-- Source password (no password here)-->
<parameter><null /></parameter>
<!-- Target username (no username here)-->
<parameter>guest</parameter>
<!-- Target password (no password here)-->
<parameter>guest</parameter>
<!-- Selector -->
<parameter><null /></parameter>
<!-- Interval to retry in case of failure (in ms) -->
<parameter>5000</parameter>
<!-- Maximum number of retries to connect to the source and target -->
<parameter>10</parameter>
<!-- Quality of service -->
<parameter>ONCE_AND_ONLY_ONCE</parameter>
<!-- Maximum batch size -->
<parameter>1</parameter>
<!-- Maximum batch time (-1 means infinite) -->
<parameter>-1</parameter>
<!-- Subscription name (no subscription name here)-->
<parameter><null /></parameter>
<!-- client ID (no client ID here)-->
<parameter><null /></parameter>
<!-- concatenate JMS messageID to the target's message header -->
<parameter>true</parameter>
<!-- register the JMS Bridge in the AS MBeanServer -->
<parameter>
<inject bean="TheMBeanServer"/>
</parameter>
<parameter>org.hornetq:service=JMSBridge</parameter>
</constructor>
<property name="transactionManager">
<inject bean="RealTransactionManager"/>
</property>
<!--<property name="transactionManagerLocatorClass">org.hornetq.integration.jboss.tm.JBoss5TransactionManagerLocator</property>
<property name="transactionManagerLocatorMethod">getTm</property>-->
</bean>

<!-- SourceCFF describes the ConnectionFactory used to connect to the source destination -->
<bean name="SourceCFF" class="org.hornetq.jms.bridge.impl.JNDIConnectionFactoryFactory">
<constructor>
<parameter>
<inject bean="JNDI" />
</parameter>
<parameter>/ConnectionFactory</parameter>
</constructor>
</bean>

<!-- TargetCFF describes the ConnectionFactory used to connect to the target destination -->
<bean name="TargetCFF" class="org.hornetq.jms.bridge.impl.JNDIConnectionFactoryFactory">
<constructor>
<parameter>
<inject bean="JNDI" />
</parameter>
<parameter>/ConnectionFactory</parameter>
</constructor>
</bean>

<!-- SourceDestinationFactory describes the Destination used as the source -->
<bean name="SourceDestinationFactory" class="org.hornetq.jms.bridge.impl.JNDIDestinationFactory">
<constructor>
<parameter>
<inject bean="JNDI" />
</parameter>
<parameter>/queue/source</parameter>
</constructor>
</bean>

<!-- TargetDestinationFactory describes the Destination used as the target -->
<bean name="TargetDestinationFactory" class="org.hornetq.jms.bridge.impl.JNDIDestinationFactory">
<constructor>
<parameter>
<inject bean="JNDI" />
</parameter>
<parameter>/queue/target</parameter>
</constructor>
</bean>

<!-- JNDI is a Hashtable containing the JNDI properties required -->
<!-- to connect to the sources and targets JMS resrouces -->
<bean name="JNDI" class="java.util.Hashtable">
<constructor class="java.util.Map">
<map class="java.util.Hashtable" keyClass="java.lang.String"
valueClass="java.lang.String">
<entry>
<key>java.naming.factory.initial</key>
<value>org.jnp.interfaces.NamingContextFactory</value>
</entry>
<entry>
<key>java.naming.provider.url</key>
<value>jnp://localhost:1099</value>
</entry>
<entry>
<key>java.naming.factory.url.pkgs</key>
<value>org.jboss.naming:org.jnp.interfaces"</value>
</entry>
</map>
</constructor>
</bean>

</deployment>


接下測試 兩台不同 AP Server 作為 bridge
  • AP1 新增 /queue/source
  • AP2 新增 /queue/target
  • AP1 新增 jms-bridge-jboss-beans.xml
這一部份直接進入 AP1 jms-bridge-jboss-beans.xml 的設定. 其實跟單機的部份很像. 只不過jndi 的部份需要另外新增. 新增了一個 JNDI-Remote 的 設定檔, 就是告知 AP1 如何連接到 AP2 的JNDI 設定. 當然, target 的 ConnectionFactory and Queue 都要改指向新的 jndi 設定.
在測試的過程中, 發現 第一次設定好以後. 發現message 根本沒有送過去, 就這樣反覆的把AP1 shutdown and start 好幾次以後, 突然message 都傳送到 AP2 了. 搞不清楚怎樣發生的就在繼續測試下去. 最後得到一個結論, 那就是Ap Start 以後, 要接過一小段時間以後, 才會開始傳送Message 而不是 馬上就動工.


<?xml version="1.0" encoding="UTF-8"?>

<deployment xmlns="urn:jboss:bean-deployer:2.0">

<bean name="JMSBridge" class="org.hornetq.jms.bridge.impl.JMSBridgeImpl">
<!-- HornetQ must be started before the bridge -->
<depends>HornetQServer</depends>
<constructor>
<!-- Source ConnectionFactory Factory -->
<parameter>
<inject bean="SourceCFF"/>
</parameter>
<!-- Target ConnectionFactory Factory -->
<parameter>
<inject bean="TargetCFF"/>
</parameter>
<!-- Source DestinationFactory -->
<parameter>
<inject bean="SourceDestinationFactory"/>
</parameter>
<!-- Target DestinationFactory -->
<parameter>
<inject bean="TargetDestinationFactory"/>
</parameter>
<!-- Source username (no username here) -->
<parameter><null /></parameter>
<!-- Source password (no password here)-->
<parameter><null /></parameter>
<!-- Target username (no username here)-->
<parameter>guest</parameter>
<!-- Target password (no password here)-->
<parameter>guest</parameter>
<!-- Selector -->
<parameter><null /></parameter>
<!-- Interval to retry in case of failure (in ms) -->
<parameter>5000</parameter>
<!-- Maximum number of retries to connect to the source and target -->
<parameter>10</parameter>
<!-- Quality of service -->
<parameter>ONCE_AND_ONLY_ONCE</parameter>
<!-- Maximum batch size -->
<parameter>1</parameter>
<!-- Maximum batch time (-1 means infinite) -->
<parameter>-1</parameter>
<!-- Subscription name (no subscription name here)-->
<parameter><null /></parameter>
<!-- client ID (no client ID here)-->
<parameter><null /></parameter>
<!-- concatenate JMS messageID to the target's message header -->
<parameter>true</parameter>
<!-- register the JMS Bridge in the AS MBeanServer -->
<parameter>
<inject bean="TheMBeanServer"/>
</parameter>
<parameter>org.hornetq:service=JMSBridge</parameter>
</constructor>
<property name="transactionManager">
<inject bean="RealTransactionManager"/>
</property>
<!--<property name="transactionManagerLocatorClass">org.hornetq.integration.jboss.tm.JBoss5TransactionManagerLocator</property>
<property name="transactionManagerLocatorMethod">getTm</property>-->
</bean>

<!-- SourceCFF describes the ConnectionFactory used to connect to the source destination -->
<bean name="SourceCFF" class="org.hornetq.jms.bridge.impl.JNDIConnectionFactoryFactory">
<constructor>
<parameter>
<inject bean="JNDI" />
</parameter>
<parameter>/ConnectionFactory</parameter>
</constructor>
</bean>

<!-- TargetCFF describes the ConnectionFactory used to connect to the target destination -->
<bean name="TargetCFF" class="org.hornetq.jms.bridge.impl.JNDIConnectionFactoryFactory">
<constructor>
<parameter>
<inject bean="JNDI-Remote" />
</parameter>
<parameter>/ConnectionFactory</parameter>
</constructor>
</bean>

<!-- SourceDestinationFactory describes the Destination used as the source -->
<bean name="SourceDestinationFactory" class="org.hornetq.jms.bridge.impl.JNDIDestinationFactory">
<constructor>
<parameter>
<inject bean="JNDI" />
</parameter>
<parameter>/queue/source</parameter>
</constructor>
</bean>

<!-- TargetDestinationFactory describes the Destination used as the target -->
<bean name="TargetDestinationFactory" class="org.hornetq.jms.bridge.impl.JNDIDestinationFactory">
<constructor>
<parameter>
<inject bean="JNDI-Remote" />
</parameter>
<parameter>/queue/target</parameter>
</constructor>
</bean>

<!-- JNDI is a Hashtable containing the JNDI properties required -->
<!-- to connect to the sources and targets JMS resrouces -->
<bean name="JNDI" class="java.util.Hashtable">
<constructor class="java.util.Map">
<map class="java.util.Hashtable" keyClass="java.lang.String"
valueClass="java.lang.String">
<entry>
<key>java.naming.factory.initial</key>
<value>org.jnp.interfaces.NamingContextFactory</value>
</entry>
<entry>
<key>java.naming.provider.url</key>
<value>jnp://localhost:1099</value>
</entry>
<entry>
<key>java.naming.factory.url.pkgs</key>
<value>org.jboss.naming:org.jnp.interfaces"</value>
</entry>
</map>
</constructor>
</bean>
<bean name="JNDI-Remote" class="java.util.Hashtable">
<constructor class="java.util.Map">
<map class="java.util.Hashtable" keyClass="java.lang.String"
valueClass="java.lang.String">
<entry>
<key>java.naming.factory.initial</key>
<value>org.jnp.interfaces.NamingContextFactory</value>
</entry>
<entry>
<key>java.naming.provider.url</key>
<value>jnp://localhost:2099</value>
</entry>
<entry>
<key>java.naming.factory.url.pkgs</key>
<value>org.jboss.naming:org.jnp.interfaces"</value>
</entry>
</map>
</constructor>
</bean>
</deployment>

2010-08-23

設定 Oracle XA DataSource

直接在 ${Jboss}\server\default\deploy 下面新增 oracel-xa-ds.xml
Jboss 會自動生效 不用重新開機

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<xa-datasource>
<jndi-name>jdbc/TestDataSource</jndi-name>
<!-- uncomment to enable interleaving <interleaving/> -->
<isSameRM-override-value>false</isSameRM-override-value>
<xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
<xa-datasource-property name="URL">jdbc:oracle:thin:@localhost:1521:xe</xa-datasource-property>
<xa-datasource-property name="User">root</xa-datasource-property>
<xa-datasource-property name="Password">root</xa-datasource-property>
<!-- Uses the pingDatabase method to check a connection is still valid before handing it out from the pool -->
<!--valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker</valid-connection-checker-class-name-->
<!-- Checks the Oracle error codes and messages for fatal errors -->
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name>
<!-- Oracles XA datasource cannot reuse a connection outside a transaction once enlisted in a global transaction and vice-versa -->
<no-tx-separate-pools/>

<!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
<metadata>
<type-mapping>Oracle10i</type-mapping>
</metadata>
</xa-datasource>

<mbean code="org.jboss.resource.adapter.jdbc.vendor.OracleXAExceptionFormatter"
name="jboss.jca:service=OracleXAExceptionFormatter">
<depends optional-attribute-name="TransactionManagerService">jboss:service=TransactionManager</depends>
</mbean>

</datasources>