Configuring a Glassfish/Sunapp CLUSTER Server on Windows

September 24, 2008

Ok, I know, in an ideal world we’d do this on Solaris but I have customers with a pile of windows boxes so we have to work with what they have.

Server 1 - The “Controller” (machine 1, 192.168.100.10)

1. Install the SUN Application server make sure you select

- Do not require username/password
- Create a windows service (otherwise it wont stay running)
- Do not start the server from the INSTALLATION PROGRAM, use control panel, administration tools, services and start the service from there.

2. Login to the GUI http://localhost:4848

3. Select ADD CLUSTER SUPPORT - you will have to restart the server. Do NOT do this through the windows instead restart the service - Start, Control Panel, Admin Tools, Services, find SUN APPLICATION SERVER and RESTART

4. Login to the GUI http://localhost:4848 - Click on CREATE NEW CLUSTER

Enter the name and click OK now the cluster has been created (in this case i’ll use cluster1)

5. Create the first NODE. (this has to be done at the dos prompt)

Start, RUN, CMD, OK

cd \Sun\appserver\bin<ENTER>

asadmin<ENTER>

You will get a asadmin> prompt.

on each machine in the cluster you have to create and start a node agent

create-node-agent –host localhost –port 4848 nodeagent1

create an instance for this node agent

create-instance –host localhost –port 4848 –nodeagent nodeagent1 –cluster cluster1 instance1

now start the node agent

start-node-agent –syncinstances=true nodeagent1
(just hit enter on the master password)

at this point you have created and set up the first cluster machine which will control the cluster - so all your cluster admin will be done from this machine.

Exit asadmin

exit

then exit the command box

exit

Setting up Cluster Server clients (machine 2, 192.168.100.11)

1. Install the SUN Application server make sure you select

- Do not require username/password
- Create a windows service (otherwise it wont stay running)
- Do not start the server from the INSTALLATION PROGRAM, use control panel, administration tools, services and start the service from there.

2. Login to the GUI http://localhost:4848

3. Select ADD CLUSTER SUPPORT - you will have to restart the server. Do NOT do this through the windows instead restart the service - Start, Control Panel, Admin Tools, Services, find SUN APPLICATION SERVER and RESTART

4. Create a node agent, start, run cmd ok

Start, RUN, CMD, OK

cd \Sun\appserver\bin<ENTER>

asadmin<ENTER>

You will get a asadmin> prompt.

on each machine in the cluster you have to create and start a node agent

create-node-agent –host 192.168.100.10 –port 4848 nodeagent2

create an instance for this node agent

create-instance –host 192.168.100.10 –port 4848 –nodeagent nodeagent2 –cluster cluster1 instance2

now start the node agent

start-node-agent –syncinstances=true nodeagent2
(just hit enter on the master password)

at this point you have created and set up a cluster “client”

Exit asadmin

exit

then exit the command box

exit

Now you have your two cluster machines working.

Deploying a Netbeans Project to the Cluster

1. Make sure it’s running locally
2. Change the database settings in netbeans to point to the LIVE database if it is different and make sure it runs still
3. Deploy the app to the main server in the cluster
4. Login to the GUI and go through the JDBC connectors and enable them for the cluster
5. Test the application in SINGLE USER mode (normally port 8080) and make sure it all works.
6. Go into APPLICATIONS, MANAGE TARGETS for your app and deploy it to the cluster

I will be putting up a tutorial on load balancing as well shortly.


Java Server Faces, SQL SERVER and CHAR FIELDS

September 18, 2008

I have modified the excellent JTDS driver to strip the spaces from CHAR FIELDS so that Java Server faces controls do not get confused when fields are of different lengths and also when you go to edit a field you don’t get a pile of spaces at the end of the text.

The problem.

Well I have a project where the people who originally designed the database were obviously monkeys. So they used CHAR fields throughout the database. But not all the same size, for example:-

TABLE 1 (SERVICE CODES) SERVICE CODE CHAR 2 JI

Then in an other table

TABLE 2 SERVICE CODE CHAR 50

This means that if you create a drop down box on a page with the service code list it would be padded and would not match the other table. I initially started modifying the SQL code to CAST service code as a CHAR to match the other one. Since there were 100 odd tables this meant masses of extra work to use Java Server Faces.

The other problem is that editing fields have extra spaces at the end of the data - what a nightmare.

So I pulled down the open source JTDS driver and rewrote it to trim all spaces from CHAR fields, thus making JSF work right and solving my SPACE problem.

The files are here

Source Code (converted into a Netbeans Project)

Note if you download and use this you do so at your own risk, no warranty, implied or otherwise is provided for this software.

Note 2: if you were using an OLD jdts driver you will need to remove the references from the SERVER as well as NETBEANS and use this new one - I might get round to renaming the driver to something else but if you find there are spaces where there should not be its probably because you are running the standard driver not the new one.

Note 3: If you just want the driver its in the “dist” subdirectory, you need the LIB folder as well.

Note 4: If you publish a project using this driver and modify the driver then publish it again, NB won’t change the driver on the glassfish server if it has the same name, so you’ll have to copy it over yourself.


Java Server Faces, Data Class (Parent/Child) (if you use JSF read this)

September 16, 2008

I’m working on a huge project with some multi tab screens and I noticed two things about the code, firstly my init code had a lot of changes to the default SQL providers, mainly for  things where tables had links to other tables, parent child relationships. The more I added, the slower it got  - plus my code got quite messy.

So - just to tidy up the code, I wrote a class below that has some functions for changing data providers. Guess what, not only was my code neater but the pages speeded up very noticably when loading. - Why not comment if you have a clue why, personally I think its something to do with the way java handles classes that are called a lot.

I declare one change object at the start of the JSF java code.

DataProviderSQLChanger change = new DataProviderSQLChanger();

Then I can use the change object whenever I like in the init code and throughout the page…

change.ChangeSQL(tblsubservicetypesDataProvider, "select * FROM tblsubservicetypes");

Functions

public void ChangeSQL(CachedRowSetDataProvider dataProvider, String sNewSQL)

This routine changes the SQL of a cached data provider - however it does look to see if the SQL your are submitting is what is already on the cached data provider so we don’t waste time reloading schemas etc.

public void ParentChildLink(
            CachedRowSetDataProvider parentDataProvider,
            String sParentFieldName,
            CachedRowSetDataProvider childDataProvider,
            String sChildFieldName,
            boolean bIsText)

 This Parentchildlink is for when you have a parent child relationship for example, when I have a “MAIN SUBFORM” Idea. It’s pretty straight forward (see the code for documentation and parameters).

public void ForceParentChildLink(
            String sKey,
            CachedRowSetDataProvider parentDataProvider,
            String sParentFieldName,
            CachedRowSetDataProvider childDataProvider,
            String sChildFieldName,
            boolean bIsText)

This is the same as parent child link but FORCES the Parent CachedRowSetDataProvider to look only to the record selected.

Anyway - here’s the class, have fun!

import com.sun.data.provider.impl.CachedRowSetDataProvider;
import java.sql.SQLException;
/**
 * This is an easier way to change a Data Providers SQL and manage data providers
 * By Paul Clevett http://www.netbeansboy.com
 * @author paulc
 */
public class DataProviderSQLChanger {
    /**
     * Changes the SQL Statement of a Dataprovider
     * If the sql statement is already set to that, just return, refreshing the data provider
     * @param dataProvider
     * @param sNewSQL
     */
    public void ChangeSQL(CachedRowSetDataProvider dataProvider, String sNewSQL) {
        // Is the dataproviders sql already set?
        if (!dataProvider.getCachedRowSet().getCommand().equals(sNewSQL)) {
            try {
                dataProvider.getCachedRowSet().setCommand(sNewSQL);
            } catch (SQLException ex) {
                System.out.println("SQL Error: " + ex);
            // Logger.getLogger(DataProviderSQLChanger.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
        dataProvider.refresh();
    }
    /**
     * Manage the Parent Child Link between two cached data providers
     * gives much clearer code, note that this routinedoes not change the parents
     * data provider's SQL unlike ForceParentChildLink
     * @param parentDataProvider    - Parent Data Provider
     * @param sParentFieldName      - Parent Field name
     * @param childDataProvider     - Child Data Provider
     * @param sChildFieldName       - Child Field name
     * @param bIsText               - if the link is a text link
     */
    public void ParentChildLink(
            CachedRowSetDataProvider parentDataProvider,
            String sParentFieldName,
            CachedRowSetDataProvider childDataProvider,
            String sChildFieldName,
            boolean bIsText) {
        // Sets up the link between parent and childe data providers
        String sOrderBy="";
        String sSQL = childDataProvider.getCachedRowSet().getCommand();
        if (sSQL.indexOf("ORDER BY")!=-1) sOrderBy = sSQL.substring(sSQL.indexOf("ORDER BY"));
        // Now remove any existing where's
       
        if (sSQL.indexOf("WHERE")!=-1) sSQL = sSQL.substring(0, sSQL.indexOf("WHERE") - 1);
        // Add the Query
        if (bIsText) {
           
            sSQL = sSQL.concat(" WHERE " + sChildFieldName + "='" + parentDataProvider.getValue(sParentFieldName).toString().trim() + "'");
           
        } else {
           
            sSQL = sSQL.concat(" WHERE " + sChildFieldName + "=" + parentDataProvider.getValue(sParentFieldName));
           
        }
        sSQL=sSQL.concat(sOrderBy);
       
        // Execute the query on the child
        ChangeSQL(childDataProvider,sSQL);
    }
   
    /**
     * Syncs up the parent/child relationship between two data providers with
     * a key
     * @param sKey                  - Parents Key Value or blank if the fieldname is the same as the sParentNameField
     * @param parentDataProvider    - Parents Data Provider
     * @param sParentFieldName      - Parents FieldName
     * @param childDataProvider     - Childs Data Provider
     * @param sChildFieldName       - Childs Field Name
     * @param bIsText               - Is the key Text or Numeric? (TRUE/FALSE)
     */
    public void ForceParentChildLink(
            String sKey,
            CachedRowSetDataProvider parentDataProvider,
            String sParentFieldName,
            CachedRowSetDataProvider childDataProvider,
            String sChildFieldName,
            boolean bIsText) {
        // Sets up the link between parent and childe data providers
        String sOrderBy="";
        String sSQL= parentDataProvider.getCachedRowSet().getCommand();
        if (sKey.equals("")) sKey=parentDataProvider.getValue(sParentFieldName).toString();
        if (sSQL.indexOf("ORDER BY")!=-1) sOrderBy = sSQL.substring(sSQL.indexOf("ORDER BY"));
        // Now remove any existing where's
       
        if (sSQL.indexOf("WHERE")!=-1) sSQL = sSQL.substring(0, sSQL.indexOf("WHERE") - 1);
        // Add the Query
        if (bIsText) {
           
            sSQL = sSQL.concat(" WHERE " + sParentFieldName + "='" + sKey + "'");
           
        } else {
           
            sSQL = sSQL.concat(" WHERE " + sParentFieldName + "=" + sKey);
           
        }
        sSQL=sSQL.concat(sOrderBy);
        // Force the parent over to look at the particular row
        ChangeSQL(parentDataProvider,sSQL);
       
       
        // Now the child
        sSQL = childDataProvider.getCachedRowSet().getCommand();
        if (sSQL.indexOf("ORDER BY")!=-1) sOrderBy = sSQL.substring(sSQL.indexOf("ORDER BY"));
        // Now remove any existing where's
       
        if (sSQL.indexOf("WHERE")!=-1) sSQL = sSQL.substring(0, sSQL.indexOf("WHERE") - 1);
        // Add the Query
        if (bIsText) {
           
            sSQL = sSQL.concat(" WHERE " + sChildFieldName + "='" + parentDataProvider.getValue(sParentFieldName) + "'");
           
        } else {
           
            sSQL = sSQL.concat(" WHERE " + sChildFieldName + "=" + parentDataProvider.getValue(sParentFieldName));
           
        }
        sSQL=sSQL.concat(sOrderBy);
       
        // Execute the query on the child
        ChangeSQL(childDataProvider,sSQL);
    }
   
   
   
}

Java Server Faces and Google Chrome — Goodbye IE!

September 3, 2008

When Firefox 3 came out I was hoping it would run JSF faster than IE did, instead it actually failed to run at all well so we just forgot about it and went back to sunny IE for our clients.

Today! I install Google Chrome… Actually I expected JSF not to work at all… let alone how it does.

JSF runs VERY VERY VERY Fast in Google Chrome, sorry, actually, the whole internet runs VERY VERY VERY FAST.

Our tests so far show perfect compatibilty with JSF and it turns the web browser into an application browser, apart from the fact we can perform more customisations of the browser and use it as a real tool for accessing the multiple JSF projects we have.

We can now see bottlenecks without running profiler. The time between the pages loading shows where the problems are. IE really struggled with massive amounts of componants on pages. 

GOOD JOB GOOGLE

If you’ve not tried Google Chrome please please do… hitch it up to your JSF application (or any web app) or your favorite website and just fall off your chair at the MARKED DIFFERENCE in speed. 

I would think once word gets out that people will not want to use IE any longer.