venerdì 5 settembre 2008

ISPCONFIG SUPHP and OPEN_BASEDIR

I'm a system administrator of a linux hosting server (ubuntu 8.0.4).
I chose to adopt ispconfig together with suphp.
I had PEAR not working, and in phpinfo() the variable open_basedir pointed only to the root of the hosting space (something like /var/www/web7).
I needed to add /tmp and /usr/share/php to each open_basedir vhost, but with suphp you use php CGI, so you can't use php_admin_value.
I was going crazy too to find out where open_basedir was set: not in Vhosts_ispconfig.conf, not in php.ini ....
I found the way out looking at /etc/suphp.conf at the line:

x-httpd-php=php:/home/admispconfig/ispconfig/tools/suphp/usr/bin/php-wrapper

So I took a look at php-wrapper, and there it was:

exec php-cgi -d open_basedir=${BASEDIR} -d upload_tmp_dir=${TMPDIR} -d session.save_path=${SESSDIR} -d safe_mode=${SAFE_MODE}

where BASEDIR=`dirname ${DOCUMENT_ROOT}`
So, if you have the same problem as I, define a new variable:

OPEN_BASEDIR="/tmp:/usr/share/php:"${BASEDIR}

and put it in the above line as follows:

exec php-cgi -d open_basedir=${OPEN_BASEDIR} -d upload_tmp_dir=${TMPDIR} -d session.save_path=${SESSDIR} -d safe_mode=${SAFE_MODE}

NOTE: if you successively upgrade ispconfig package, remember to re-apply the above patch.

domenica 27 luglio 2008

Web character encoding: many places to config it right

I start this entry only with few out-of-order notes: I'll put more info when I have more time.
To avoid surprises, choose UTF-8 and don't leave defaults: configure all the pieces you use.
For me, they are:
- tomcat 5.5: in server.xml, for all your connectors, set:
connectionTimeout="20000"
redirectPort="8443"

URIEncoding="UTF-8"
useBodyEncodingForURI="true"

/>
(see: http://tomcat.apache.org/tomcat-5.5-doc/config/http.html)
(see for SEAM: https://cloud.prod.atl2.jboss.com/jira/browse/JBSEAM-3148?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel)

- in JSF+facelets: (encoding of xml files + view + meta)
- to check, in browser you have to see meta and http header (mind double headers-> correct IIS or APACHE)
- html form: add accept-encoding

A must read: http://www.javaworld.com/javaworld/jw-04-2004/jw-0419-multibytes.html?page=7

mercoledì 12 dicembre 2007

Seam Spring and connections lost

Using high level frameworks as seam and spring, you think you are safe from dangerous things like loosing open connections to your db .... but it happened.
I don't know why yet, but using spring transactions with seam and an hibernate transaction manager my webapp was eating connections, expecially when starting (and not ending) long running conversations. Reload many times the page with @Begin and my webapp was lost.
My solution was to switch to JTA, and it was really simple when:

1) found the right hint at http://archives.free.net.ph/message/20071121.214555.86512d04.en.html to choose the right JTA implementation for my postgresDB (that for now is not in the supported list of BTM, I hope for the better ;-) );
2) read BTM article to configure it in spring;
3) downloaded latest jdbc driver for postgres, with a must have fix.

IMPORTANT:
you have to configure hibernate.connection.release_mode to after_statement (with JTA) beacause Spring changes default to on_close, and long running conversations keep the hibernate session open (and hopefully disconnected from db connection).
Moreover, as written in Seam docs, set hibernate.transaction.flush_before_completion to true, so to flush the session before commit of surrounding transaction.

<!-- I have this in my hibernate.cfg.xml -->
<property name="hibernate.connection.release_mode">after_statement</property>
<property name="hibernate.transaction.flush_before_completion">true</property>



OTHER NEEDED CONFIGURATIONS:
---------------------------------------------------------------
Spring's application.xml:

<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init" destroy-method="close">
<property name="className" value="org.postgresql.xa.PGXADataSource" />
<property name="uniqueName" value="pgsql" />
<property name="minPoolSize" value="0" />
<property name="maxPoolSize" value="${db.maxActive}" />
<property name="driverProperties">
<props>
<prop key="databaseName">ibusiness_web</prop>
<prop key="user">${db.user}</prop>
<prop key="password">${db.pwd}</prop>
</props>
</property>
</bean>

<!-- Bitronix Transaction Manager embedded configuration -->
<bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices">
<property name="serverId" value="spring-btm" />
</bean>

<!-- create BTM transaction manager -->
<bean id="BitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig,dataSource" destroy-method="shutdown" />


<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="configLocation" value="/WEB-INF/classes/hibernate.cfg.xml" />
</bean>

<bean id="seamSessionFactory" class="org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean">
<property name="sessionName" value="hibernateSession"/>
</bean>

<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="seamSessionFactory" />
</property>
</bean>


<!-- Spring JtaTransactionManager -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager" />
<property name="userTransaction" ref="BitronixTransactionManager" />
</bean>


-----------------------------
Seam's components.xml:


<persistence:managed-hibernate-session name="hibernateSession" auto-create="true" session-factory="#{sessionFactory}"/>
<spring:spring-transaction platform-transaction-manager="#{transactionManager}"/>
<spring:context-loader config-locations="/WEB-INF/application.xml"/>




---------------------------------------------------------------
NOTE: in application.xml use as reference for other beans seamSessionFactory as the only sessionFactory. sessionFactory is defined in Spring only to be wrapped by Seam in components.xml.
---------------------------------------------------------------

Thanks to spring, I didn't change a line of code, and very few of xml.
Thanks to seam, now I can leverage its long running conversations to improve my app.

Thanks to google and all of you who share their good and bad experiences, so I do now.

Seam and asynchronous email send

Over the past 3 months I've ported a JSF 1.1 business application written last year to Seam.
I'll talk of the hurdles I met, expecially porting from myfaces 1.1 to JSF RI 1.2, but now I just want to share with you my few successes.
In seam you can send an email using facelets as template engine. You can do it in same thread that displays you page, but due to high latency of smtp servers and other reasons, it's better to send it asynchronously.
My webapp is a POJO webapp, built upon spring,hibernate and seam.
All you have to do to spawn a new thread is to annotate your method with @Asynchronous, but watch out !
If your code was already working when doing it inside the display thread, now it surely will break.
WHY:
1) when seam spawns a thread, you loose the previous event/page/conversation context, so you have to put the objects you use inside the email template in a new context:

@Asynchronous
public void send(Account account) {
try {
Contexts.getConversationContext().set("account", account);
Renderer.instance().render("/email/activatedaccount.jsf");
} catch (Exception e) {
e.printStackTrace();
}

2) you loose your webapp relative paths too: if inside a display thread seam uses the ServletContext to retrieve the full path to your email template (and the resources it uses). Inside a spawned thread seam replaces the servletContext with a mockContext which resamble a ResourceBundle strategy to find resources in the classpath. So you have to move /email dir in WEB-INF/classes, togheter with the resources it uses (logo images etc..).

3) I happened to use one backing bean to process the page action, and call a send(account) method of the same class. When I marked that method @Asynchronous and debugged inside Eclipse, I saw the thread was the tomcat's one, not a new spawned one. I solved it moving the send method in another class and calling it in a new istance:


public String approve(Account account) {
...
architectMailer.send(account);
...
}

4) There's a bug (fixed in next release, perhaps already in 2.0.1 CR of tonight) about inline images not being displayed in thunderbird, but only attached. Don't go crazy, it's not your fault: wait for next release.

My 2 cents

Hope this helps

giovedì 16 novembre 2006

Let's start !

Hello ! This is my first and only blog.
I'm a java developer since 1999, and a PC enthusiast by the time of Commodore VIC 20.
I managed to see (and use) basic (Vic20, Sinclair QL, early VB), motorola assembler 68000, lisp , Pascal, Turbo C and assembler 386, C++.
Now I'm fond of Java (again and ever more), C++ and Linux, and I'm looking forward to buy a Mac and put inside Linux, VMware and Windows to be really multiplatform (and test).
As a team leader and consultant, I meet many young developers that really don't know why things work the way they do, so they cannot understand what appens when something goes wrong: I'm talking about linkers, mapped I/O, TCP-IP protocol and nowadays the difference between multitasking and multithreading (in a multicore world), and virtual memory and sector and clusters etc...
OK, I feel old and should be if more often than ever I meet colleagues younger than me ...
And it's a good thing young developers want to learn new things like Ruby on Rails etc.. Me too.
But you can't forget the history of IT industry, the good and the bad things done, and learn by studying not only by doing (an excuse of IT manager not to invest and pay for knowledge improvement of his workers, and for developers not to take their job seriously).
My lesson learnt , the one I find leading my actions as a professional is:
know what you're doing, and learn to do it better, the right way (that's why the title for my blog).
I get upset when someone says "it just works, so it is OK".
If I you do something good (or bad) and you don't know why, sooner or later it will explode in your face.
Don't invent the wheel each time, but improve what you previously did.
Reuse your knowledge, and improve it.
Code reuse is less important, but don't re-engineer too often: take a decision and carry on it before changing idea.
You are your best capital.