Monday, December 20, 2010

Work with sound jCaptcha in servlet, Part 1 - Setup FreeTTS

I have been working on jCaptcha recently. In addition to image captcha, I need to implement sound/audio captcha for 508 compliance. jCaptcha has an example here. However, I ran into two problems with the example. Firstly, there was an error when I used one instance (then changed captcha engine) for image and sound captcha. I ended up creating separate instances for image and sound captcha. Secondly, image and sound captcha don't share the same text sources so they are in fact two independent captchas. This is confusing since what the users see is not what they hear. But it seems to be a known problem and I have to live that. Otherwise, I would need to write my own implementation of WordGenerator to make sure to use the same text before passing it to captcha engine.

Note that jCaptcha depends on FreeTTS for sound. Here are the steps to setup FreeTTS for jCaptcha.
  1. Download and unzip jCaptcha. I used 1.2.2.
  2. Run jcaptcha.exe in /lib
  3. Copy all jars to your jCaptcha project classpath
  4. Set system property directly. This saves the trouble to mess with FreeTTS configuration.
            String voiceClasses = System.getProperty("freetts.voices"); // another one "freetts.voicesfile"
if (voiceClasses == null) {
System.setProperty("freetts.voices", "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory");
voiceClasses = System.getProperty("freetts.voices");
}
log.info("freetts.voices:" + voiceClasses);

String bundle = "toddlist";
DictionaryReader reader = new FileDictionary(bundle);
WordGenerator generator = new DictionaryWordGenerator(reader);

SoundConfigurator soundConfig = new FreeTTSSoundConfigurator("kevin16", VOICE_PACKAGE, 1.0f, 100, 100);

WordToSound word2sound = new FreeTTSWordToSound(soundConfig, 3, 6);

CaptchaFactory[] factories = new CaptchaFactory[]{new GimpySoundFactory(generator, word2sound)};

CaptchaEngine captchaEngine = new GenericCaptchaEngine(factories);

instance = new GenericManageableCaptchaService(captchaEngine, 180,
180000, 75000);



With these limitations, my code compiled and passed the unit tests. Now this is the part one of the story. Stayed tuned for part 2.

Read a file from classpath

I need to read a file from classpath. It is well documented to do this by
getClass().getClassLoader().getResourceAsStream()

But this returns an InputStream. What if I need a File? It turns out that I can use getResource() instead of getResourceAsStream(), to create a URL and then get a URI to create a File.
URL fileUrl = getClass().getClassLoader().getResource("test.txt");
File file = new File(new URI(fileUrl.toString()));

Friday, December 10, 2010

Where does System.out.print() output go in OAS?

Just to be clear, you are not supposed to use SOP. Use logging instead. Commons logging, java.util.logging, log4j, slf4j, you name it. However, what if third-party code has SOP and you wonder where the output goes when deployed in OAS (Oracle Application Server).

OAS actually dumps the output to opmn log under OAS. In my local installation, it is C:\product\10.1.3.1\OracleAS_1\opmn\logs\default_group~home~default_group~1.log. Just be aware it saves almost all output so the file could be huge.

Wednesday, December 1, 2010

Start OC4J with -userThreads

I have an application deployed on OC4J. It uses quartz to schedule a job. The job connects to the database through JNDI. The JNDI is defined through Enterprise Manager. When started, the log showed the following error.

Javax.naming.NamingException: Not in an application scope - start Orion with the -userThreads switch if using user-created threads

It turns out that I need to add "-userThreads" to OC4J options to overcome this. I did this through EM > Administration > Server properties, and then add "-userThreads" to OC4J options. The error was gone after a restart.

Tuesday, November 16, 2010

Java applet logging

The chances are that you are already using Apache commons logging and log4j in your application. A new challenge is how you do logging for Applet. By that I mean, dumping the output to applet Java console.

Good news is that you don't need to change your code at all. In addition, I think it is overkill to include log4j.properties and log4j.jar as part of client code for Java applet. Without them, commons logging will simply pick default Java logging and it works like a charm.
Log log = LogFactory.getLog(getClass());

The catch is to make sure to use the correct logging level. On the client side, Java logging is defined here. The default logging level is info.
C:\Program Files\Java\jdk1.6.0_20\jre\lib\logging.properties

.level= INFO
So you want to use at least log.info(), instead of log.debug(), to see anything in the Java applet console. Otherwise, the setting has to be changed in logging.properties. It is just not realistic to ask every end user to do it.

Compile options in Ant javac task

Recently I was tasked to migrate a code base from JDK 1.4 to 1.6. As part of this work, I need to take care of deprecated methods and unchecked types in collections. To verify, I turned on the options in ANT javac task as below. Note the use of deprecation="on" and <compilerarg value="-Xlint:unchecked"/>.

        <javac destdir="${build.dir}" source="1.6" target="1.6" debug="true"
deprecation="on" failonerror="true">
<src path="${src.dir}"/>
<classpath refid="master-classpath"/>
<compilerarg value="-Xlint:unchecked"/>
</javac>

Monday, November 15, 2010

Create a connection pool to MySQL in OC4J

It is quite easy to create a connection pool/datasource to an Oracle database in OAS EM (Enterprise Manager). You simply do that in OC4J > Administration > JDBC Resources. However, it is not that straight forward to do that with a third party database, in my case, MySQL. Basically, you need to provide mySQL jdbc driver and make sure to use the correct parameters.

This is the obscure part. The creation of connection pool/datasource in EM is via the ascontrol application. So we need to let it know how to load mySQL jdbc driver. There are two steps. Firstly, copy mysql-connector-java-5.1.13-bin.jar to
C:\product\10.1.3.1\OracleAS_1\j2ee\home\applications\ascontrol\ascontrol\WEB-INF\lib. Secondly, edit C:\product\10.1.3.1\OracleAS_1\j2ee\home\applications\ascontrol\META-INF\orion-application.xml and comment out the "remove-inherited" section like below.

   <imported-shared-libraries>
<!--
<remove-inherited name="global.libraries"/>
-->
<import-shared-library name="oracle.xml.security"/>
</imported-shared-libraries>



Everything is pretty straight forward after this. To create a connection pool, remember to use "com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource" for "Connection Factory Class" and similar to "jdbc:mysql://localhost:3306/test" for "JDBC URL". You can create a datasource the same way after a connection pool is created.

Reference:
http://forums.oracle.com/forums/thread.jspa?threadID=680574