Dec 29, 2008

Unicode and preg_replace()

When you're dealing with PHP and finally start using unicode instead of whatever non-unicode encodings, you might find a some of your symbols being transformed into rubbish, especially when dealing with non-latin alphabet.

The answer is to use a “u” flag in the expression string:

$s = preg_replace('/\s/u', $s);

Dec 16, 2008

sfGuardPlugin: Database Prefix

With symfony, it's kinda funny to search for documentation, since it's widely distributed across wiki, book, and various external sources, like Propel website.

That is why when you need something small and easy, but you don't know how to do this, it's usually faster to try that yourself first, search for an answer later. This is actually not the way I prefer to do stuff, so I will share some experiences about how to do small stuff in symfony.

So, the problem is, I have a single database on my web hosting available. However, I came across a situation where I needed two separate sets of sfGuardUser-s. To achieve this, I had to go the usual way — add a prefix to the tables.

All I had to do was to add “prfx_” to all the tables mentioned in <project-name>/plugins/sfGuardPlugin/config/schema.yml and then rebuild stuff with propel:

symfony propel:build-all

or, if you want to keep your existing data, rename tables in database manually, and then...

symfony propel:build-sql
symfony propel:build-form
symfony propel:build-model

...and you're set.

Sep 3, 2008

Google Chrome

Ah, I just love this thing.

Here're just some of the pros things I really like:
  • Cougar-fast javascript;

  • Interface leaves it all for the pages — my normal setup of firefox only has address bar, search bar, tab bar, status bar;

  • It combines sweet feats from all the browsers: options menu was a lot like Firefox, expandable textareas/inputs are somewhat safarish, “most used pages” are similar to Opera, etc;

  • It seems smart (for instance: I don't need to install a separate 250KB extension to open links from tab in the only sane way — next to parent tab);

The only bad thing I've noticed so far is that I couldn't turn the spellchecker off. I can't wait to see this thing in Linux. Firefox is too slow, Opera is too ugly, Epiphany is too primitive. Although Chrome might also not be the cure: usually, many Google's apps work not very well in X. Like, Picasa trying to mimick Windows interface looks as ugly as Opera, Google Earth can be very unstable depending on version (probably due to 3D rendering issues). Maybe Chrome won't be following their steps on that.

Also, it's kinda funny to hear all the “this is Google's way of controlling you”, “Google's way of showing you ads”, “Google's way of collecting your personal information”. In the world, where ninety-five percent of decisions about what to eat, what to wear, what music to listen, what to do after work is dictated by the monster of society, where certain agencies can obtain whatever information they need about whatever person they're interested in about one hour, it's truly sick to blather about privacy in that way.

Aug 20, 2008

Wicket + Spring (with JDBC) Configuration

In the next several paragraphs of symbols, I'll explain how to configure Spring and Wicket frameworks to work together, and even how to use JdbcDaoSupport, Spring's nice and handy JDBC tool.

I prefer not to deal with automatic configurations generated by Wicket or Spring IDE plugins, but to create the application from scratch. I will be using the NetBeans IDE. In a nutshell, all we'll have to do, is download some libraries, put some of them in Tomcat's lib folder, the rest in the classpath, and make a couple of modifications to web.xml and applicationContext.xml files.


Libraries


First of all, you will need Wicket and Spring libraries. If you download Spring with all dependencies, most probably, you won't have to download anything else (except mysql-connector, if you don't already have it).

Specific jars are:

aspectjrt-1.x.jar
cglib-nodep-2.x.jar
log4j-1.x.jar
slf4j-api-1.x.jar
slf4j-log4j12-1.x.jar
spring-2.x.jar
wicket-1.3.x.jar
wicket-ioc-1.3.x.jar
wicket-spring-1.3.x.jar
wicket-spring-annot-1.3.x.jar

Those jars listed above you should add to the libraries of your NetBeans project.

These three you have to put in $CATALINA_HOME/lib folder. Don't put them in classpath unless you've got several hours to find out why doesn't anything work.

commons-logging-1.1.x.jar
ehcache-1.2.x.jar
mysql-connector-java-5.1.x-bin.jar


context.xml


Hope you've already created a NetBeans project and selected a “Web Application” at certain point.

First thing to do, is describe a database resource so we could access it via JNDI. To do this, put in the META-INF/context.xml something like this:

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/Chicago">
<!-- database resource -->
<Resource
name="jdbc/Chicago"
auth="Container"
driverClassName="com.mysql.jdbc.Driver"
type="javax.sql.DataSource"

username="database_user"
password="database_pass"
url="jdbc:mysql://localhost/my_database"

maxWait="10000"
maxActive="60"
minIdle = "0"
maxIdle="30"

removeAbandoned="true"
removeAbandonedTimeout="120"

testOnBorrow="false"
testOnReturn="false"
testWhileIdle="true"
validationQuery="SELECT 1"
timeBetweenEvictionRunsMillis="59000"
minEvictableIdleTimeMillis="58000"
/>
</Context>


Such resource configuration will tell your servlet container (namely, Tomcat) to keep alive JDBC connections and reconnect to avoid IO exceptions when connection isn't being used for a long time.


applicationContext.xml


You will now have to create a WEB-INF/applicationContext.xml file for Spring configuration.

Here's what you might want to put there:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/Chicago"/>
</bean>

<!-- Wicket WebApplication setup -->
<bean id="wicketApplication" class="com.mycorp.chicago.ChicagoApplication">
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="userDaoTarget" class="com.mycorp.chicago.user.JdbcUserDao">
<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="userDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
<property name="proxyTargetClass" value="true"/>
<property name="target" ref="userDaoTarget" />
<property name="transactionAttributes">
<props>
<prop key="save">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="*">PROPAGATION_REQUIRED,-Exception,readOnly</prop>
</props>
</property>
</bean>
</beans>


What we just did there,

a) configured a dataSource object which is used in JdbcDaoSupport, to lookup database resource via JNDI;

b) told Spring to use Acegi filter on HTTP requests (Acegi is Spring's security framework, we'll deal with it in the next episode);

c) created a proxy DAO bean.


web.xml



We now must ask container to invoke Spring filter on certain requests. This is what we do in WEB-INF/web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Lianet Application</display-name>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<filter>
<filter-name>Spring Application Factory Filter</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>Spring Application Factory Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>

</web-app>



UserDao.java and JdbcUserDao.java


For Spring injection to work, we create an interface of the DAO and its JDBC implementation. These I will keep in com.mycorp.chicago.user package.

/*
* UserDao.java
*/

package com.mycorp.chicago.user;

import java.io.Serializable;

/**
*
*/
public interface UserDao extends Serializable /* UserDetailsService */ {

public void test();

}




/*
* JdbcUserDao.java
*/

package com.mycorp.chicago.user;

import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

/**
*
*/
public class JdbcUserDao extends JdbcDaoSupport implements UserDao {

public void test() {
getJdbcTemplate().query("SELECT name FROM my_table WHERE id=1", new RowMapper() {

public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
String name = rs.getString("name");
System.out.println("Got object name: " + name);
return null;
}

});
}

}


You probably have already got the idea that to have all the preceding work, you'll need a MySQL database “my_database” with a “my_table” table with the latter consisting of at least an integer `id` and a varchar `name` fields.


IndexPage.java


Now let's inject our brand new UserDao in some Wicket component. Say, an index page of the app. I'll put it in the com.mycorp.chicago.web.page package.


/*
* Index.java
*/

package com.mycorp.chicago.web.page;

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.spring.injection.annot.SpringBean;
import com.mycorp.chicago.user.UserDao;

/**
* Main page of the application.
*/
public class IndexPage extends WebPage {

@SpringBean(name="userDao")
private UserDao userDao;


public IndexPage() {
add(new Label("sampleLabel", "This is a text which is also a model."));
userDao.test();
}
}



IndexPage.html


By default, HTML template is stored along with the java source.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<span wicket:id="sampleLabel">Sample label</span>
</body>
</html>



ChicagoApplication.java


Now all that is left is the actual WebApplication of Wicket.

/*
* ChicagoApplication.java
*/

package com.mycorp.chicago;

import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import com.mycorp.chicago.web.page.IndexPage;

/**
*
*/
public class ChicagoApplication extends WebApplication {

@Override
public Class getHomePage() {
return IndexPage.class;
}

@Override
public void init() {
super.init();
addComponentInstantiationListener(new SpringComponentInjector(this));
}

}



Enjoy


That's it. Now all that is left is to hit F6 button and wait for results. If you get a ClassNotFound exception, you probably forgot to add certain library. Wicket runtime exceptions are usually easy to fix since Wicket is very verbose in development mode.

Aug 18, 2008

Jackrabbit on JBoss with JNDI & RMI

We recently decided to use JCR, specifically, it's Apache implementation, JackRabbit. What's already done, is a web application running on Tomcat servlet container. One of the most obvious ways to tie those two, is to deploy JackRabbit on JBoss and expose it via JNDI.

Configuring JBoss Server


First, you need to download JBoss Application Server. Its installation in Ubuntu is as easy as extracting the downloaded jar/zip to the directory where you want JBoss to sit, and setting the JBOSS_HOME variable to that directory in ~/.bashrc.

To deploy JackRabbit, you need to obtain jackrabbit-jca.rar and jackrabbit-rmi.jar from JackRabbit downloads page and jcr-1.0.jar.

Note: The .rar archive contains all JackRabbit dependencies, including concurrent.jar.

You will also need to download the jcr-ds.xml. Edit the file so the <rar-name>jackrabbit-jca.rar</rar-name> property would contain the actual name of the rar you've downloaded (I had jackrabbit-jca-1.4.rar) and the homeDir property would point to the directory where you want JackRabbit to store its stuff.

To complete deployment, you now need to put jackrabbit-jca.rar, jackrabbit-rmi.jar and jcr-ds.xml files to $JBOSS_HOME/server/default/deploy and jcr-1.0.jar to $JBOSS_HOME/server/default/lib.

Note: Apparently, you should be careful about renaming the jcr-ds.xml file. I tried to name it “jcr-ds-1.4.xml” and kept getting JackRabbit deployed incompletely. Once I renamed it back to “jcr-ds.xml”, everything went smoothly.

To start JBoss, do $JBOSS_HOME/bin/run.sh.

Configuring Client


Now you might wanna check your JCR repository. You will need to create a simple function I found in the mail archive:

private static Session getJackrabbitSession() throws RepositoryException {
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.put(Context.PROVIDER_URL, "jnp://localhost:1099");
env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");

try {
InitialContext ctx = new InitialContext(env);
ClientAdapterFactory adapter = new ClientAdapterFactory();
RemoteRepository rr;
rr = (RemoteRepository) ctx.lookup("jnp://localhost:1099/jcrServer");
Repository repository = adapter.getRepository(rr);
Credentials credJBoss = new SimpleCredentials("username", "password".toCharArray());
return repository.login(credJBoss);
} catch (NamingException ex) {
ex.printStackTrace();
}

return null;
}


For that code to work, you will need jcr-1.0.jar, jackrabbit-jcr-rmi.jar, jnp-client.jar and jboss-common.jar libraries in your classpath. The latter two can be found in $JBOSS_HOME/client and $JBOSS_HOME/lib respectively.

If you've done everything correct, and are lucky enough, the “first hops” from Jackrabbit introduction should work fine, with appropriate changes to obtaining Session object done.

Jul 29, 2008

Deploying Django Project on Ubuntu Server

I've recently had to deploy a pretty simple Django application on Ubuntu server, and here're a few tips for myself in the future doing this once again.

For starters, there's a Jeff Baier's tutorial which covers most steps. There're, however, a couple of things I had to learn the hard way.

First, if you wish to use a stable version of Django, instead of dealing with subversion and compilation, just install it from repositories:

$ sudo apt-get install python-django

If you do so, your admin media will be in the following directory:

/usr/share/python-support/python-django/django/contrib/admin/media

Second, in your .py files don't use relative imports. If you have a project named “project_one” and two applications, “app_one” and “app_two” applications, this will work on local django server, but won't work in production:

import app_one.Something

Instead, you must always do

import project_one.app_one.Something

Third, mind the paths to your media files. It's better to adjust them before deployment so they look the same on your development localhost and production server, otherwise you might have problems during deployment.

I'm mentioning this here because django's default recommended media/admin-media url configuration is somewhat doesn't makes this easier.

Finally, keep in mind that out-of-the-box MySQL databases are not UTF-8 which is not very good if you have any language in db besides English. Unless you won't unicode-enable your MySQL server before you create your tables structure, you will have to change encoding of all the tables after.

Pretty much that is it, which actually seems really smooth deployment process to me, so another score for Django.

Jun 3, 2008

MSSQL + PHP in Ubuntu 8.04

Following comments to this post, I got MS SQL working with PHP.

$ apt-get install freetds-dev tdsodbc php5-sybase
$ nano /etc/odbcinst.ini
[FreeTDS]
Description = FreeTDS 0.61-5 Deb
Driver = /usr/lib/odbc/libtdsodbc.so
Setup = /usr/lib/odbc/libtdsS.so
FileUsage = 1
CPTimeout = 5
CPReuse = 5


$ nano /etc/odbc.ini
[Products]
Description = Products on The MSSQL Server
Driver = FreeTDS
Servername = FSData
Database = Products
Port = 1433

May 21, 2008

A Lame Way To Clip Skin Highlights

I'm no professional or even advanced-amateur photographer, but sometimes people ask me to make photos. Since I do suck at that, and I don't have my own studio stuffed with lights, softboxes and stuff, I often take photos of people poorly lit with lots of highlights on their skin. There's a lame way to remove those.

I'm not sure if it's possible to achieve this using just curves or levels, here's how I do it.

1. Go to Levels and move the center slider to the right as far as neccessary so highlighted areas turn white and not-so-highlighted areas turn dark. Sometimes instead of moving center slider, you will need to gather black, white and center slide in the middle.

2. Increase Contrast until you have a dark background with islands of white highlighted areas. Sometimes background is completely black, and you can just delete it after magic wand selection. Sometimes you need to select white by colour and delete inverted selection.

3. Fill alhpa-selection of remaining areas with skin colour you can pick from not-highlighted parts. Depending on different parts of face illumination, you may want to fill highlighted areas with different colours.

4. The next is up to blur and opacity tuning.

May 1, 2008

Ubuntu 8.04 Wireless

I googled out the wireless/ndiswrapper problem. The solution, quoting Ankur Srivastava's blog post, is as simple as this:

$ nano /etc/rc.local
then put
rmmod ssb
modprobe ndiswrapper

before exit 0...
...then
$ shutdown -r now

And your wireless is there.

Update: Apparently, these actions aren't needed if you're using kernel 2.6.24-17. After update from 8.04 original 2.6.24-16, wireless had not worked until I removed those lines from rc.local.

Apr 24, 2008

Last Insert Id Without Extra SELECT in Spring

If you have a table with auto_increment for an id, you often need to get this id immediately after a new instance has been created.

The easy way to do this is to perform a SELECT LAST_INSERT_ID() query. However, most of the time you want as less database requests as possible. There is a way to avoid LAST_INSERT_ID() code using Spring's JDBC support.


final String DEF_INSERT_USER_QUERY = "insert into users (username, password) values (?,?)";
final String firstname = createdUser.getFirstname();
final String lastname = createdUser.getLastname();

KeyHolder keyHolder = new GeneratedKeyHolder();
getJdbcTemlpate().update(new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection connection)
throws SQLException {
PreparedStatement ps = connection.prepareStatement(DEF_INSERT_USER_QUERY,
new String[] {"firstname", "lastname"});
ps.setString(1, firstname);
ps.setString(2, lastname);
return ps;
}
}, keyHolder);

createdUser.setId(keyHolder.getKey().intValue());

Apr 16, 2008

Change J2EE version of NetBeans Project

A java project I've been working was initially started as J2EE1.4 one, but finally had to be moved to J2EE5. Apparently, there's no GUI way to do this in NetBeans (nor 6 neither 5.5).

When you select Project->Properties->Run, J2EE version is just displayed in a text field which value I couldn't change. Maybe this is a bug of NetBeans, maybe this is an intentional limitation.

Anyway, after some painful hours spent in moving classes and configs into a newly created J2EE5 project and fighting errors popped, I just took an advice of a fellow developer, checked how things are done in project.properties file and put j2ee.version=1.5 instead of 1.4.

Apr 7, 2008

Firefox Memory Management Mystery

Firefox's appetite for memory is a well-known problem, especially in the latest 2.0.x versions. However, I never experienced it while I was using it on Windows. The browser never ate more than one and a half hundred megabytes.

I started to suffer from it only when I switched to Ubuntu a couple years ago. In fact, latest version with all the plugins (TMP+Firebug+Webdeveloper+DownThemAll) enabled, consumed up to four hundred megabytes of RAM so I even had to switch to Epiphany to be able to keep other greedy processes running.

But now, on the HP laptop with the same Ubuntu 7.10 the same Firefox 2.0.0.13 acts as it did in the Windows days — one and a half hundred megs no matter how many pages are opened.

I guess, this mystery will never be unriddled.

Mar 12, 2008

“Not A Fish” Method Actually Works

There's this article on Wired about how you can stop hiccups by “reminding yourself that you're not a fish”. I'm not sure if anyone from comments actually believed in it, but ow-emm-gee, it works perfectly.

Just now I had hiccups which had stopped the second I told myself: “hey, I'm not a fish, I have no gills”. Science indeed works.

Feb 28, 2008

100% Height Div in Firefox

It was a surprise for me to find out that this is actually a problem with tricks and hacks involved.

Once I wanted to make 100% height div, I've found lots of “solutions”, all of which were either ie-only or involved render the div as a table cell or caused it to be exactly 100% of the screen height, ignoring the height of the actual content (which might be bigger), or caused scrollbar to appear even though content was fitting in one screen.

Although none of the solutions was perfect, when properly combined they actually do the thing.

General concepts are:
— Make html and body elements 100% high to allow inner blocks height setup;
— Set container's height to auto and min-height to 100% to avoid content overflow;
— Don't put content in the container itself but use it as a wrapper to allow padding without scrollbar

So here it goes: 100% height div for both IE and Firefox.
View source to see how it's done.

Feb 27, 2008

«Connection is read-only» Exception

I've ran into funny exception recently. I've a function updating database table using Spring's JdbcTemplate and for some reason there was this exception:

java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1056)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1973)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1940)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1925)
at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:101)
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:773)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:566)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:767)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:825)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:833)
at com.myapplication.user.JdbcUserDao.saveData(JdbcUserDao.java:511)

...


There wasn't much about it on the Internet, but apparently, the problem occures when the JdbcUserDao is configured as proxy bean and saveData method (or any other method making updates to database) is missing its PROPAGATION_REQUIRED flag in the applicationContext.xml.

Feb 26, 2008

***

This blog will probably mostly consist of solutions for coding problems I've faced but for which I couldn't find direct answers on the Internet.

Googling the problem is the first thing I do after I can't figure it out for myself, and usually there's a blog post entitled with exact same words I used as a search query. In most cases that post solves the problem, but sometimes Google has nothing to offer (yes, even on the second page).

After several hours (or minutes) of hard (or enjoyable) work, the problem is solved and I can share my explorations with people all over the world. Although most likely I'll share them with myself a couple weeks later since I'm so forgetful.

Anyway, I guess it is now clear why this way of blogging looks like putting missing pieces of the puzzle in place for me.

Since now I am still in the beginning of the long way of all sorts of coding, some things may seem unwise, but again, I prefer to think of this as of some sort of draft notebook used just to keep random instructions, links or thoghts in one place.