5/16/2011

5. Add persistence: Example App using Seam 3, RichFaces 4 on eclipse

Building example application seam 3 + richfaces 4 series
5. Add persisistence



1. Add persistence.xml in WebContent/WEB-INF/classes/META-INF

1.1 create classes/META-INF directory on WebContent/WEB-INF directory
1.2 create persistence.xml in WebContent/WEB-INF/classes/META-INF
(you need to configure this file to fit with your environment)



<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">

<persistence-unit name="test">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/testDatasource</jta-data-source>
<properties>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
<property name="hibernate.connection.username" value="test"/>
<property name="hibernate.connection.password" value="test"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle9iDialect" />
</properties>
</persistence-unit>

</persistence>




2. Add test-ds.xml (datasource) in JBOSS deploy directory
(you need to configure this file to fit with your environment)


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE datasources
PUBLIC "-//JBoss//DTD JBOSS JCA Config 1.5//EN"
"http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd">
<datasources>
<local-tx-datasource>
<jndi-name>testDatasource</jndi-name>
<use-java-context>true</use-java-context>
<connection-url>jdbc:oracle:thin:@hostname:1521:SID</connection-url>
<driver-class>oracle.jdbc.OracleDriver</driver-class>
<user-name>test</user-name>
<password>test</password>
<max-pool-size>100</max-pool-size>
</local-tx-datasource>
</datasources>



3. If oracle, make sure ojdbc15-xxx.jar or relevant file is placed in $JBOSS_HOME/server/default/lib (if using default)
For other database place driver jar file in there.

4. create data model (this is just example. you will need to setup your own database and table)

I placed ZoneCodes.java in seam3-test/src/com/test directory



package com.test;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "zone_codes")
public class ZoneCodes {

@Id
@Column(name = "zone_code")
private String code;

@Column(name = "zone_description")
private String description;

public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}



5. create controller

I placed ZoneController.java in seam3-test/src/com/test directory


package com.test;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateful;
import javax.enterprise.inject.Produces;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.jboss.seam.faces.context.RenderScoped;
import org.jboss.seam.international.status.Messages;

/**
* This class performs search and outject result
*/
@Named
@Stateful
@RenderScoped
public class ZoneController {
@PersistenceContext
private EntityManager em;

@Inject
Messages messages;

private List zoneCodes = new ArrayList();

/**
* Perform search
* This retrieves all ZoneCodes from database
*/
public void search() {
Query q = em.createQuery("from ZoneCodes");
zoneCodes = q.getResultList();
messages.info("Search completed. {0} records found", zoneCodes.size());
}

/**
* Reset results
*/
public void reset() {
zoneCodes = new ArrayList();
}

// out-jection
@Produces
@Named
public List getZoneCodes() {
return zoneCodes;
}
}


The difference between Seam 2 and Seam 3 is quite significant.


Most of major concept in Seam 2 are absorbed in CDI (jboss 6 comes with it), and Seam 3 is providing extras on top of it.


So, when I made seam 3 working on JBoss 6, most of major seam 2 concepts absorbed into CDI. That ands up some people complaining that this article is not seam 3 exemple. Instead it is just CDI example.


I agree. So, I had to provide Seam 3 is still working on my example. Hence, I added couple of 'seam 3' specific features in it.



6. Add index_db.xhtml in WebContent directory



<!DOCTYPE composition 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"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<f:view>
<h:head>
</h:head>
<h:body styleClass="page">
<h1>Persistence test</h1>

<h:form id="zoneSelectionForm">
<div>
<h:form id="searchForm" prependId="false">
<a4j:commandButton id="search" value="Search" action="#{zoneController.search}" render=":searchResults"/>
#{' '}
<a4j:commandButton id="reset" value="Clear" action="#{zoneController.reset}" render=":searchResults"/>
</h:form>
</div>

<h:panelGroup id="searchResults">
<h:messages />
<h:dataTable id="zones" value="#{zoneCodes}" var="zone" rendered="#{not empty zoneCodes}">
<h:column>
<f:facet id="nameFct" name="header">Code</f:facet>
#{zone.code}
</h:column>
<h:column>
<f:facet id="addrFct" name="header">Description</f:facet>
#{zone.description}
</h:column>
</h:dataTable>
</h:panelGroup>
</h:form>

</h:body>
</f:view>

</html>


7. deploy it onto Jboss 6

8. http://localhost:8080/seam3-test/index_db.xhtml

Sample output is like below


4. add primfaces: Example App using Seam 3, RichFaces 4 on eclipse

Building example application seam 3 + richfaces 4 series
4. Add primefaces

1. add jar file
This is quite simple.

You can just add primefaces-3.0.M1.jar (or latest) in WebContent/WEB-INF/lib directory
, and you are ready to use it.

2. add index_primefaces.xml in WebContent directory

<!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"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.prime.com.tr/ui">
<f:view>
<h:head>
</h:head>
<h:body styleClass="page">
<h1>Primefaces test</h1>

<div>
<p:tooltip global="true"/>

<h:panelGrid columns="1" cellpadding="5">
<h:form>
<p:commandButton value="Submit" title="Click to save" type="button" />

<h:outputLink value="#" title="Go to">
<h:outputText value="Link" />
</h:outputLink>

<p:inputText title="This is a required field" />
</h:form>
</h:panelGrid>
</div>
</h:body>
</f:view>
</html>



3. deploy it onto Jboss 6

4. http://localhost:8080/seam3-test/index_primefaces.xhtml

3. add taglib: Example App using Seam 3, RichFaces 4 on eclipse

Building example application seam 3 + richfaces 4 series
3. Add custom taglib


If you are already using custome taglib on jsf1.2 with facelet, there is nothing changed. You can reuse existing taglib as it is.

1. To setup seam 3 + richfaces 4 check

Building example application seam 3 + richfaces 4 series
3. Add custom taglib


2. add following configuration on web.xml

<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/taglib_test/taglib_test.taglib.xml</param-value>
</context-param>


3. create custom tag

3.1 create taglib_test directory on WebContent
3.2 create taglib_test.taglib.xml file in WebContent/taglib_test directory

<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>http://test.com/tl_test</namespace>
<tag>
<tag-name>test_panel</tag-name>
<source>taglib_test.xhtml</source>
</tag>
</facelet-taglib>

3.3 create taglib_test.xhtml file in WebContent/taglib_test directory

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich">
<rich:panel header="Tag lib testing">
This is testing for custom taglib. This is remained same as before in JSF 1.2.
</rich:panel>
</ui:composition>


4. create index_with_taglib.xhtml in WebContent directory

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich"
xmlns:tt="http://test.com/tl_test"
template="template.xhtml">

<ui:define name="content">
<h1>Seam 3 taglib test</h1>

<tt:test_panel />

</ui:define>
</ui:composition>


5. deploy it onto Jboss 6

6. http://localhost:8080/seam3-test/index_with_taglib.xhtml

2. Apply template: Example App using Seam 3, RichFaces 4 on eclipse

Building example application seam 3 + richfaces 4 series
2. Apply template


1. To setup seam 3 + richfaces 4 check

Building example application seam 3 + richfaces 4


2. add template.xhtml on WebContent directory

<!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"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<f:view>
<h:head>
</h:head>
<h:body>
<ui:insert name="content"/>
</h:body>
</f:view>
</html>

3. add index_with_template.xhtml on WebContent directory

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
template="template.xhtml">

<ui:define name="content">
<h1>Seam 3 template test</h1>

<rich:panel header="Richfaces running on JBoss AS 6">
<ul>
<li>RichFaces is a component library for JSF and an advanced framework</li>
<li>for easily integrating AJAX capabilities into business applications.</li>
</ul>
</rich:panel>
</ui:define>
</ui:composition>


4. deploy it onto Jboss 6

5. http://localhost:8080/seam3-test/index_with_template.xhtml

1. Setup: Example App Seam 3, RichFaces 4 on eclipse without maven

Building example application seam 3 + richfaces 4 series
1. setup seam 3 + richfaces 4


1. Start eclipse
2. New -> Dynamic Web Project




3. copy the following files into WebContent/WEB-INF/lib

3.1 seam 3 dependent files

commons-beanutils-1.8.0.jar
commons-digester-2.1.jar
commons-logging-1.1.1.jar
joda-time-1.6.jar
picketlink-idm-api-1.5.0.Alpha02.jar
picketlink-idm-common-1.5.0.Alpha02.jar
picketlink-idm-core-1.5.0.Alpha02.jar
picketlink-idm-spi-1.5.0.Alpha02.jar
seam-catch-3.0.0.Final.jar
seam-config-xml-3.0.0.Final.jar
seam-faces-3.0.0.Final.jar
seam-international-3.0.0.Final.jar
seam-persistence-3.0.0.Final.jar
seam-security-3.0.0.Final.jar
seam-servlet-3.0.0.Final.jar
seam-solder-3.0.0.Final.jar


3.2 richfaces related files

cssparser-0.9.5.jar
guava-r09.jar
richfaces-components-api-4.0.0.Final.jar
richfaces-components-ui-4.0.0.Final.jar
richfaces-core-api-4.0.0.Final.jar
richfaces-core-impl-4.0.0.Final.jar
sac-1.3.jar



4. create web.xml on WebContent/WEB-INF directory


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">

<display-name>Seam test</display-name>

<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>


</web-app>


5. Add index.xhtml on WebContent directory


<!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"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:rich="http://richfaces.org/rich">
<f:view>
<h:head>
</h:head>
<h:body styleClass="page">
<h1>Seam 3 test</h1>

<rich:panel header="Richfaces running on JBoss AS 6">
<ul>
<li>RichFaces is a component library for JSF and an advanced framework</li>
<li>for easily integrating AJAX capabilities into business applications.</li>
</ul>
</rich:panel>
</h:body>
</f:view>
</html>

6. deploy it onto Jboss 6

7. http://localhost:8080/seam3-test/index.xhtml

2/01/2011

Make modalPanel appear on top of pdf

<rich:modalPanel id="menu_help_view" autosized="true"
        overlapEmbedObjects="true">

12/21/2010

Fire onchange event on IE





Typical way to make 'enter' key working on certain field is


<rich:hotKey
key="return"
handler="#{rich:element('clearance_agent_id')}.onchange()"
selector="#land_lto_id" />


However, this doesn't work on IE.

To make it work you can add a trick.


<rich:hotKey
key="return"
handler="#{rich:element('clearance_agent_id')}.focus();#{rich:element('clearance_agent_id')}.onchange()"
selector="#land_lto_id" />


11/15/2010

How to get OracleConnection from T4CConnection or Proxy


java.sql.Connection t4Connection = BorrowedConnectionProxy.getWrappedConnection(conn);
OracleConnection oracleConn = (OracleConnection) t4Connection;
context = new DefaultContext((OracleConnection) oracleConn);

10/21/2010

Seam: Manual Transaction



1. start a nested conversation and set em flush mode to manual before showing popup.

@Begin(nested = true, flushMode = FlushModeType.MANUAL)
public void prepareEdit() {}

2. when click save button, end conversation and flush em.

@End
public void saveEdit() {
xxxService.update(WhatEverObjectYouAreEditing);
dbHelperService.flush();

// If the current object needs to updated on session scope, raise event
Events.instance().raiseEvent(eventName, WhatEverObjectYouAreEditing)

// Then the parent action should listen to the eventName, so the object can be reloaded.
}

3. when click cancel button, end conversation and refresh data

@End
public void cancel() {
dbHelperService.refresh(WhatEverObjectYouAreEditing);
}

Couple of things to remember
1. Conversation vs Transaction
- Transaction is not started when conversation starts
- You can only specify transaction will be maintained manually when conversation starts. (That definition will be cleared when conversation ends)
- Transaction will be committed when you execute.
- When transaction ends, dirty object will be cleared if not commited.

2. Flush vs Commit
- When executing a method, you can flush any time.
- Flush updates database to reflect the changes in objects in memory.
: However, it is still not committed yet.
: Unless flushes, database will not see the change.

- When the execution ends, transaction will be commited automatically.
- You can run flush, but cannot run commit




Create Textarea with maxlength validation



<script type="text/javascript">
function textCounter(fieldstr, countfieldstr, maxlimit){
field = document.getElementById(fieldstr);
countfield = document.getElementById(countfieldstr);

if (field.value.length > maxlimit) {
// if too long, trim it!
field.value = field.value.substring(0, maxlimit);
} else {
// update 'characters left' counter
countfield.value = maxlimit - field.value.length;
}
}
</script>

<h:form id="myform">
<h:inputTextarea id="myarea"
onkeydown="textCounter('myform:myarea','myform:myarea_remline',100);"
onkeyup="textCounter('myform:myarea','myform:myarea_remline',100);"
onfocus="textCounter('myform:myarea','myform:myarea_remline',100);"
disabled="#{disabled}"/>
<br/>
<h:inputText id="myarea_remline" value="100" size="4" maxlength="4" disabled="true"/> characters remaining
</h:form>

s:link, s:button excution order on action and view attribute


s:button and s:link can have both 'action' and 'view' attributes.

When both are given, it will try to excute 'action' first, then 'view' next.
However, if action returns something, it will be forwarded to the 'something'
If, action returns nothing, it will proceed to 'view'.



rule

  • 1. execute action

  • 1.1 if action returns -> redirect to the page

  • 1.2 if action doesn't return -> try to call 'view'

8/12/2010

How to call database store procedure with return parameter from EJB3


@Resource(mappedName = "java:/myDatasource")
private DataSource ds;

public void callSetLoginUserId(String userId) throws Exception {
Connection conn = null;
CallableStatement st = null;
try {
String sql = "{ ? = call my_pkg.create_user(?) }";
conn = ds.getConnection();
st = conn.prepareCall(sql);
st.registerOutParameter(1, Types.BIGINT);
st.setString(2, "username");
st.execute();
Long userId = st.getLong(1);
}
catch(Exception e) {
log.error("calling my_pkg.create_user has failed", e);
throw e;
}
finally {
try {
if (st != null) {
st.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
// ignore
}
}

4/16/2009

Richfaces: submit when enter key pressed


<a4j:form>
<h:inputText id="quick_search_client_id" value="#{searchCont.clientId}"/>

<a4j:commandButton type="submit" value="Search"
action="#{searchCont.search}" id="searchButton"/>
...
</a4j:form>

<rich:hotKey key="return"
handler="#{rich:element('searchButton')}.click()"
selector="#quick_search_client_id"/>

11/18/2008

JBoss - set deployment order (run ejb first)

%JBOSS_HOME%\server\default\conf\xmldesc\org.jboss.deployment.MainDeployer-xmbean.xml

search for EnhancedSuffixOrder

set decriptor value like this
<value value="250:.rar,300:-ds.xml,400:.jar,500:.ear,540:.war,550:.jse,650:.bsh"/>

ear moved before war and value changed to 540.

10/30/2008

valangValidator script example

<bean id="registrationValidator" class="org.springmodules.validation.valang.ValangValidator">
<property name="valang">
<value><![CDATA[
{ userName : ? is not blank : 'User Name: required.' }
{ userName : matches('\\w+',?) == true: 'User Name: Only Alpha-Numeric Characters' }
{ userName : matches('\\w+',?) == true: 'User Name: Only Alpha-Numeric Characters' }
{ userName : length(?) > 6 : 'User Name: Not between 6 - 12 characters.' }
{ userName : length(?) < 12 : 'User Name: Not between 6 - 12 characters.' }
{ firstName : ? is not blank : 'First Name: required.' }
{ firstName : matches('\\w+',?) == true: 'First Name: Only Alpha-Numeric Characters' }
{ lastName : ? is not blank : 'Last Name: required.' }
{ lastName : matches('\\w+',?) == true: 'Last Name: Only Alpha-Numeric Characters' }
{ email : ? is not blank : 'E-Mail: required.' }
{ email : email(?) == true: 'E-Mail: Not A valid Address' }
{ password : ? is not blank : 'Password: required.' }
{ password : matches('\\w+',?) == true: 'Password: Only Alpha-Numeric Characters' }
{ password : length(?) > 6 : 'Password: Not between 6 - 12 characters.' }
{ password : length(?) < 12 : 'Password: Not between 6 - 12 characters.' }
{ confirmPassword : ? is not blank : 'Confirm Password: required.' }
{ confirmPassword : matches('\\w+',?) == true: 'Confirm Password: Only Alpha-Numeric Characters' }
{ city : ? is not blank : 'City: required.' }
{ age : matches('\\d+',?) == true: 'Age: Only Numeric Characters' }
{ age : ? is not blank : 'Age: required.' }
]]></value>
</property>
</bean>

9/30/2008

xstream: custom converter

marshal/unmarshal


private String toXML(Application app) throws Exception {
XStream xStream = new XStream(new DomDriver());
xStream.registerConverter(new ApplicationConverter());
xStream.alias("application", Application.class);
return xStream.toXML(app);
}

private Application toApplication(String xml) throws Exception {
XStream xStream = new XStream(new DomDriver());
xStream.registerConverter(new ApplicationConverter());
xStream.alias("application", Application.class);
return (Application) xStream.fromXML(xml);
}

class ApplicationConverter implements Converter {
private static final String FULLDATE_FORMAT = "dd/MM/yyyy HH:mm:ss";

/** Marshall xml into application object */
public void marshal(Object obj,
HierarchicalStreamWriter writer,
MarshallingContext context) {
Application app = (Application) obj;
pushContent(writer, "applicationId", app.getApplicationId());
DateFormat formatter = new SimpleDateFormat(FULLDATE_FORMAT);
pushContent(writer, "createdDate", formatter.format(app.getCreatedDate()));
pushMapContent(writer, app.getFields());
}

/** Push content into xml */
private void pushContent(HierarchicalStreamWriter writer,
String key, Object value) {
writer.startNode(key);
writer.setValue(value.toString());
writer.endNode();
}

/** Push map content into xml */
private void pushMapContent(HierarchicalStreamWriter writer, Map map) {
Iterator iter = map.keySet().iterator();
while(iter.hasNext()) {
String key = (String) iter.next();
Object value = map.get(key);
writer.startNode(key);
if (value instanceof Map) {
pushMapContent(writer, (Map) value);
}
else if (value instanceof String) {
writer.setValue((String) value);
}
writer.endNode();
}
}

/** Unmarshall application into xml */
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
Application app = new Application();
DateFormat formatter = new SimpleDateFormat(FULLDATE_FORMAT);

while (reader.hasMoreChildren()) {
reader.moveDown();
try {
if ("applicationId".equals(reader.getNodeName())) {
app.setApplicationId(reader.getValue());
}
else if ("createdDate".equals(reader.getNodeName())) {
app.setCreatedDate(formatter.parse(reader.getValue()));
}
else {
popMapContent(reader, app.getFields());
}
}
catch(ParseException e) {
LOG.debug("Parsing date for "+reader.getNodeName()+" has failed", e);
}
reader.moveUp();
}
return app;
}

/** Pop xml into map content */
private void popMapContent(HierarchicalStreamReader reader,
Map map) {
if (reader.hasMoreChildren()) {
Map childMap = new TreeMap();
map.put(reader.getNodeName(), childMap);
while (reader.hasMoreChildren()) {
reader.moveDown();
popMapContent(reader, childMap);
reader.moveUp();
}
}
else {
map.put(reader.getNodeName(), reader.getValue());
}
}

public boolean canConvert(Class clazz) {
return clazz.equals(Application.class);
}
}

9/16/2008

spring: configure mail

Add mailService in applicationContext.xml

<!-- Mail service -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="your.smtphost.com"/>
<property name="port" value="25"/>
<property name="username" value="yourusername"/>
<property name="password" value="yourpassword"/>
</bean>
<bean id="mailManager" class="com.onlineforms.MailManager">
<property name="mailSender" ref="mailSender"/>
<property name="from" value="Joseph.Seo@macquarie.com"/>
<property name="to" value="Joseph.Seo"/>
<property name="subject" value="Testing"/>
</bean>

Implement MailManager

public class MailManager {

private JavaMailSender mailSender;
private String from;
private String to;
private String subject;

//// getters/setters blah blah

/**
* Send simple email
* @param message
*/
public void send(String message) {
SimpleMailMessage mailMsg = new SimpleMailMessage();
mailMsg.setFrom(getFrom());
mailMsg.setTo(getTo());
mailMsg.setSubject(getSubject());
mailSender.send(mailMsg);
}

}

jboss 4.2.x: Setup virtual directory, Setup static directory, Setup external directory

%JOSS_HOME%/server/XXX/deploy/jboss-web.deployer/server.xml

Add the following line under <Host> tag.

<Context path="/images" appBase=""
docBase="C:/dev/workspace/images"
debug="99" reloadable="true">
</Context>

9/05/2008

hibernate: many-to-many mapping with mapping-table

<set name="items" table="campaignlist" >
<key column="campaign_id"/>
<many-to-many class="Item" column="mediaitem_id"/>
</set>

OR

<bag name="otherOptions" table="JOB_FINISHING_OPTION">
<key column="JOB_ID"/>
<many-to-many class="com.au.fxa.dsc.soms.model.PrintFinishOption" column="POC_ID"/>
</bag>

9/03/2008

struts2, freemarker: load template from memory



1. register in struts.xml


2. Extends FreeMarkerManager
public class FreeMarkerManager extends FreemarkerManager {
protected TemplateLoader getTemplateLoader(ServletContext servletContext) {
FormTemplateLoader templateLoader = new FormTemplateLoader();

return new MultiTemplateLoader(new TemplateLoader[]{
templateLoader,
new WebappTemplateLoader(servletContext),
new StrutsClassTemplateLoader()
});
}
}

3. Implement TemplateLoader
public class FormTemplateLoader implements TemplateLoader {
public Object findTemplateSource(String name) {
// getTemplates() returns map containing template list with template name as key
source = (String) getTemplates().get(name);
lastModified = System.currentTimeMillis();
return source;
}

...
}