Developing Entity Beans
Gopalan Suresh Raj

Note
To work with any of these samples, you will need the following:
.........................................JDK 1.1.6 or higher (I use JDK 1.1.7B)
.........................................
Swing 1.1 or higher for JDK 1.1 (required if you wanna use the HomeBase GUI)
.........................................
The HomeBase (Scunthorpe version 0.5.1) - a free EJB Server from Iona
To work with the EJB Servlet client, you will need
.........................................
JSDK 2.0 or higher

The Steps involved in developing and deploying an Entity Bean is

1. Set up your Data Source to the Database
2. Define your Home Interface.
3. Define your Remote Interface.
4. Develop your EntityBean
5. Define a Primary Key class
*** Note : From this point onwards, whatever we do becomes vendor (HomeBase) specific ***
6. Define your Deployment Descriptor
7. Compile your classes and generate the Container code using the tools provided by the vendor
8. Startup your Server

A four-tier Architecture for a Typical Bank

Figure shows what we are trying to ultimately accomplish in these pages here.

1. Set up your Data Source to the Database

The example program requires a database table named CHECKINGS --the DML of which is shown below-- with the following fields:

CREATE TABLE CHECKINGS      
  ACCOUNT_NUMBER Number  
  CUSTOMER_NAME Text  
  BALANCE Currency  
      *primary key (ACCOUNT_NUMBER)

 

2. Define your Home Interface

Bank\CheckingsHome.java
package Bank;

import javax.ejb.*;
import java.rmi.*;

public interface CheckingsHome extends EJBHome {
 
  Checkings create (int accountNo, String customer) throws CreateException,RemoteException;
  Checkings create (int accountNo, String customer, double startingBalance) throws CreateException,RemoteException;
  Checkings findByPrimaryKey (CheckingsPK accountNo) throws FinderException, RemoteException;
}

3. Define your Remote Interface

Bank\Checkings.java
package Bank;

import javax.ejb.*;
import java.rmi.*;

public interface Checkings extends EJBObject {
 
  void credit (double amount) throws RemoteException;
  void debit (double amount) throws RemoteException;
  double getBalance () throws RemoteException;
  public int getAccountNumber () throws RemoteException;
  public String getCustomerName () throws RemoteException;
 
}

4. Develop your EntityBean

Bank\CheckingsBean.java
package Bank;

import java.rmi.*;
import javax.ejb.*;
import java.util.*;

public class CheckingsBean implements EntityBean {
 
  protected EntityContext _entityContext;
 
  public    int           account_number;
//ACCOUNT_NUMBER
  public    String        customer_name;  
//CUSTOMER_NAME
  public    double        balance;        
//BALANCE
 
  public int getAccountNumber () {
    return this.account_number;
  }
 
  public String getCustomerName () {
    return this.customer_name;
  }
 

  public void credit ( double amount ) {
    System.out.println ("==============Invoking CheckingsBean::credit");
    System.out.println ("==============changing CheckingsBean::balance from " + balance);
    if ( amount > 0 ) {
      balance += amount;
    }
    System.out.println(" to " + balance);
  }

  public void debit ( double amount ) {
    System.out.println ("==============Invoking CheckingsBean::debit");
    System.out.println ("==============changing CheckingsBean::balance from " + balance);
    if ( (amount > 0) && (balance >= amount) ) {
      balance -= amount;
    }
    System.out.println (" to " + balance);
  }

  public double getBalance () {
    System.out.println ("==============Invoking CheckingsBean::getBalance");
    System.out.println ("==============CheckingsBean::balance is " + balance);
    return this.balance;
  }

  public CheckingsBean () {
    System.out.println ("==============Invoking CheckingsBean::CheckingsBean");
    try {
      jbInit ();
    }
    catch (Exception e) {
      e.printStackTrace ();
      System.out.println ("==============CheckingsBean::CheckingsBean - jbInit failed");
    }
  }

  // Container managed beans return void
  public void ejbCreate ( int accountNo, String customer)
    throws RemoteException, CreateException
{
 
    System.out.println ("==============Invoking 2 parameter CheckingsBean::ejbCreate");
    this.account_number = accountNo;
    this.customer_name  = customer;
    this.balance   = 0d;

    System.out.println ("======================================================");
    System.out.println ("CheckingsBean::account_number =" + this.account_number);
    System.out.println ("CheckingsBean::customer_name =" + this.customer_name);
    System.out.println ("CheckingsBean::balance =" + this.balance);
    System.out.println ("======================================================");
  }

  public void ejbPostCreate ( int accountNo, String customer)
    throws RemoteException, CreateException
{
 
    System.out.println ("======================================================");
    System.out.println ("Invoking 2 parameter CheckingsBean::ejbPostCreate");
    System.out.println ("CheckingsBean::account_number =" + this.account_number);
    System.out.println ("CheckingsBean::customer_name =" + this.customer_name);
    System.out.println ("CheckingsBean::balance =" + this.balance);
    System.out.println ("======================================================");
  }

  public void ejbCreate( int accountNo, String customer, double balance)
    throws RemoteException, CreateException
{
 
    System.out.println ("Invoking 3 parameter CheckingsBean::ejbCreate");
    this.account_number = accountNo;
    this.customer_name  = customer;
    this.balance   = balance;
    System.out.println ("======================================================");
    System.out.println ("CheckingsBean::account_number =" + this.account_number);
    System.out.println ("CheckingsBean::customer_name =" + this.customer_name);
    System.out.println ("CheckingsBean::balance =" + this.balance);
    System.out.println ("======================================================");
  }

  public void ejbPostCreate ( int accountNo, String customer, double balance)
    throws RemoteException, CreateException
{
 
    System.out.println ("======================================================");
    System.out.println ("Invoking 3 parameter CheckingsBean::ejbPostCreate");
    System.out.println ("CheckingsBean::account_number =" + this.account_number);
    System.out.println ("CheckingsBean::customer_name =" + this.customer_name);
    System.out.println ("CheckingsBean::balance =" + this.balance);
    System.out.println ("======================================================");
  }

  public void ejbActivate () throws RemoteException {
    System.out.println ("==============Invoking CheckingsBean::ejbActivate======");
  }

  public void ejbLoad () throws RemoteException {
    System.out.println ("==============Invoking CheckingsBean::ejbLoad==========");
  }

  public void ejbPassivate () throws RemoteException {
    System.out.println ("==============Invoking CheckingsBean::ejbPassivate=====");
  }

  public void ejbRemove () throws RemoteException, RemoveException {
    System.out.println ("==============Invoking CheckingsBean::ejbRemove========");
  }

  public void ejbStore () throws RemoteException {
    System.out.println ("==============Invoking CheckingsBean::ejbStore=========");
  }

  public void setEntityContext (EntityContext context) throws RemoteException {
    System.out.println ("==============Invoking CheckingsBean::setEntityContext=");
    this._entityContext = context;
  }

  public void unsetEntityContext () throws RemoteException {
    System.out.println ("==============Invoking CheckingsBean::unsetEntityContext");
    this._entityContext = null;
  }

  private void jbInit () throws Exception {
    System.out.println ("==============Invoking CheckingsBean::jbInit============");
  }
}

5. Define a Primary Key class

Bank\CheckingsPK.java
package Bank;

import java.util.*;
public class CheckingsPK implements java.io.Serializable {
 
  public int account_number;

  public CheckingsPK() {
    System.out.println("Invoking CheckingsPK::CheckingsPK");
  }

  public CheckingsPK(int accountNo) {
    System.out.println("Invoking CheckingsPK::CheckingsPK");
    account_number = accountNo;
  }
}

 

*** Note : From this point onwards, whatever we do becomes vendor (HomeBase) specific ***

 

6. Write the Deployment Descriptor for your Server

Note that the deployment descriptor also specifies the properties of a certain Savings Entity Bean and a Teller Session Bean. Don't be surprised. The code for the Savings Entity Bean is included in the zip file and can be downloaded and is very similar to the Checkings Entity Bean. The steps to develop the Teller Session Bean can be seen at the Developing a Session Bean link. I am using two entity beans (Checkings and Savings) to show how workflow between two entity beans can be co-ordinated and managed by a single session bean (Teller) that creates and manages the entity beans.

conf\Bank.ejbml
<ejbml>

  <!---------------------------------------------------------->
  <!------- Checkings Entity Bean             ---------------->
  <!---------------------------------------------------------->

  <entity-bean
    name="Checkings"
    descriptor="Bank/CheckingsDeployment"
    package="Bank"
    home="Bank.CheckingsHome"
    remote="Bank.Checkings"
    bean="Bank.CheckingsBean"
    primary-key="Bank.CheckingsPK"
    tx-attribute="TX_SUPPORTS"
  >
    <property
      name="databasePassword"
      value="mouse"
    />
    <property
      name="dataSourceName"
      value="Checkings"
    />
    <property
      name="databaseUser"
      value="user"
    />
    <property
      name="databaseTable"
      value="checkings"
    />
    <container-managed
      storage-helper="com.ejbhome.generator.helpers.RelationalPersistenceCodeHelper"
      table="checkings"
      data-source="Checkings"
      user="user"
      password="mouse"
    >
      <field
        name="balance"
      />
      <field
        name="customer_name"
      />
      <field
        name="account_number"
      />
    </container-managed>
  </entity-bean>

  <!---------------------------------------------------------->
  <!------- Savings Entity Bean               ---------------->
  <!---------------------------------------------------------->

  <entity-bean
    name="Savings"
    descriptor="Bank/SavingsDeployment"
    package="Bank"
    home="Bank.SavingsHome"
    remote="Bank.Savings"
    bean="Bank.SavingsBean"
    primary-key="Bank.SavingsPK"
    tx-attribute="TX_SUPPORTS"
  >
    <property
      name="databasePassword"
      value="mouse"
    />
    <property
      name="dataSourceName"
      value="Checkings"
    />
    <property
      name="databaseUser"
      value="user"
    />
    <property
      name="databaseTable"
      value="savings"
    />
    <container-managed
      storage-helper="com.ejbhome.generator.helpers.RelationalPersistenceCodeHelper"
      table="savings"
      data-source="Checkings"
      user="user"
      password="mouse"
    >
      <field
        name="balance"
      />
      <field
        name="customer_name"
      />
      <field
        name="account_number"
      />
    </container-managed>
  </entity-bean>

  <!---------------------------------------------------------->
  <!------- Teller Session Bean               ---------------->
  <!---------------------------------------------------------->

  <session-bean
    name="Teller"
    descriptor="Bank/TellerDeployment"
    package="Bank"
    home="Bank.TellerHome"
    remote="Bank.Teller"
    bean="Bank.TellerBean"
    type="stateful"
    timeout="3484"
    tx-attribute="TX_SUPPORTS"
  >
  </session-bean>
 
</ejbml>
 

7. Compile your classes and generate the Container code using the tools provided by the vendor

MS-DOS Command Prompt

E:\MyProjects\AccountEJB>cd Bank

E:\MyProjects\AccountEJB\Bank>javac *.java

E:\MyProjects\AccountEJB\Bank>cd ..

E:\MyProjects\AccountEJB>java com.ejbhome.Deployer .\conf\Bank.ejbml
EJBHome EJB Deployer version 0.5.1 (Scunthorpe)
(c) Copyright IONA Technologies PLC 1999. All Rights Reserved.
Windows NT x86 4.0
A nonfatal internal JIT (3.00.072b(x)) error 'regvarHI' has occurred in :
'com/ejbhome/Deployer.<init> (Ljava/util/Properties;Ljava/util/Vector;)V':
Please report this error in detail to http://java.sun.com/cgi-bin/bugreport

Deploying: Checkings...
Generating: IonaCheckingsHome...done.
Generating: IonaRemoteCheckings...done.
Generating: IonaCheckingsBean...done.
Generating: IonaCheckingsContext...done.
Implementing Communications: Home Stubs & Skels...done.
Implementing Communications: Remote Stubs & Skels...done.
Compiling: IonaCheckingsHome.java...done.
Compiling: IonaRemoteCheckings.java...done.
Compiling: IonaCheckingsBean.java...done.
Compiling: IonaCheckingsContext.java...done.
Compiling: IonaCheckingsHome_Stub.java...done.
Compiling: IonaCheckingsHome_Skel.java...done.
Compiling: IonaRemoteCheckings_Stub.java...done.
Compiling: IonaRemoteCheckings_Skel.java...done.
Deploying: Savings...
Generating: IonaSavingsHome...done.
Generating: IonaRemoteSavings...done.
Generating: IonaSavingsBean...done.
Generating: IonaSavingsContext...done.
Implementing Communications: Home Stubs & Skels...done.
Implementing Communications: Remote Stubs & Skels...done.
Compiling: IonaSavingsHome.java...done.
Compiling: IonaRemoteSavings.java...done.
Compiling: IonaSavingsBean.java...done.
Compiling: IonaSavingsContext.java...done.
Compiling: IonaSavingsHome_Stub.java...done.
Compiling: IonaSavingsHome_Skel.java...done.
Compiling: IonaRemoteSavings_Stub.java...done.
Compiling: IonaRemoteSavings_Skel.java...done.
Deploying: Teller...
Generating: IonaTellerHome...done.
Generating: IonaRemoteTeller...done.
Generating: IonaTellerBean...done.
Generating: IonaTellerContext...done.
Implementing Communications: Home Stubs & Skels...done.
Implementing Communications: Remote Stubs & Skels...done.
Compiling: IonaTellerHome.java...done.
Compiling: IonaRemoteTeller.java...done.
Compiling: IonaTellerBean.java...done.
Compiling: IonaTellerContext.java...done.
Compiling: IonaTellerHome_Stub.java...done.
Compiling: IonaTellerHome_Skel.java...done.
Compiling: IonaRemoteTeller_Stub.java...done.
Compiling: IonaRemoteTeller_Skel.java...done.

E:\MyProjects\AccountEJB>


8. Startup your Server

MS-DOS Command Prompt

E:\MyProjects\AccountEJB>
E:\MyProjects\AccountEJB>java com.ejbhome.Server
com.ejbhome.server.EnterpriseServer, initializing.
com.ejbhome.server.EnterpriseServer.fireContainerAdded() at (Compiled Code)
com.ejbhome.VendorConfiguration.<init>() at (VendorConfiguration.java:57)
com.ejbhome.VendorConfiguration.getSystemCodeHelper() at (VendorConfiguration.java:174)
com.ejbhome.VendorConfiguration.getTransactionCodeHelper() at (VendorConfiguration.java:138)
com.ejbhome.VendorConfiguration.getCommsCodeHelper() at (VendorConfiguration.java:163)
com.ejbhome.VendorConfiguration.getTracingCodeHelper() at (VendorConfiguration.java:152)
com.ejbhome.VendorConfiguration.getPersistenceCodeHelper() at (VendorConfiguration.java:125)
com.ejbhome.VendorConfiguration.getSessionPassivationCodeHelper() at (VendorConfiguration.java:185)
com.ejbhome.VendorConfiguration.getVendorPrefix() at (VendorConfiguration.java:100)
starting RMI registry on port 1099...
RMI registry on port 1099, has started.
com.ejbhome.server.EnterpriseServer.bindDataSources() at (Compiled Code)
com.ejbhome.naming.spi.rmi.RMICtx.<init>() at (RMICtx.java:20)
registering XA data sources
com.ejbhome.sql.XADataSourceImpl.<init>(jdbc:odbc:Checkings,{password=mouse, user=user}) at (XADataSourceImpl.java:75)
com.ejbhome.naming.spi.rmi.RMICtx.bind() at (RMICtx.java:168)
com.ejbhome.server.EnterpriseServer.fireDataSourceAdded() at (Compiled Code)
registered: Checkings -> jdbc:odbc:Checkings, as an XA pooled data source [main]
com.ejbhome.sql.XADataSourceImpl.<init>(jdbc:odbc:Savings,{password=mouse, user=user}) at (XADataSourceImpl.java:75)
com.ejbhome.naming.spi.rmi.RMICtx.bind() at (RMICtx.java:168)
com.ejbhome.server.EnterpriseServer.fireDataSourceAdded() at (Compiled Code)
registered: Savings -> jdbc:odbc:Savings, as an XA pooled data source [main]
com.ejbhome.naming.spi.rmi.RMICtx.<init>() at (RMICtx.java:20)
loading beans from: Bank.ejbml
com.ejbhome.server.EnterpriseServer$2.startElement(ejbml) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(entity-bean) at (EnterpriseServer.java:228)
com.ejbhome.VendorConfiguration.getHomeContainerClassName() at (VendorConfiguration.java:226)
com.ejbhome.VendorConfiguration.getVendorPrefix() at (VendorConfiguration.java:100)
com.ejbhome.container.AbstractEJBHome.<init>() at (AbstractEJBHome.java:136)
com.ejbhome.naming.spi.rmi.RMICtx.<init>() at (RMICtx.java:20)
com.ejbhome.naming.spi.rmi.RMICtx.lookup("Checkings") at (RMICtx.java:35)
com.ejbhome.naming.spi.rmi.RMICtx.bind() at (RMICtx.java:168)
registered Bank.IonaCheckingsHome, as: Checkings.
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(container-managed) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(entity-bean) at (EnterpriseServer.java:228)
com.ejbhome.VendorConfiguration.getHomeContainerClassName() at (VendorConfiguration.java:226)
com.ejbhome.VendorConfiguration.getVendorPrefix() at (VendorConfiguration.java:100)
com.ejbhome.container.AbstractEJBHome.<init>() at (AbstractEJBHome.java:136)
com.ejbhome.naming.spi.rmi.RMICtx.<init>() at (RMICtx.java:20)
com.ejbhome.naming.spi.rmi.RMICtx.lookup("Checkings") at (RMICtx.java:35)
com.ejbhome.naming.spi.rmi.RMICtx.bind() at (RMICtx.java:168)
registered Bank.IonaSavingsHome, as: Savings.
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(container-managed) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(session-bean) at (EnterpriseServer.java:228)
com.ejbhome.VendorConfiguration.getHomeContainerClassName() at (VendorConfiguration.java:226)
com.ejbhome.VendorConfiguration.getVendorPrefix() at (VendorConfiguration.java:100)
com.ejbhome.container.AbstractEJBHome.<init>() at (AbstractEJBHome.java:136)
com.ejbhome.naming.spi.rmi.RMICtx.bind() at (RMICtx.java:168)
registered Bank.IonaTellerHome, as: Teller.
finished loading beans from: Bank.ejbml
loading beans from: Checkings.ejbml
com.ejbhome.server.EnterpriseServer$2.startElement(ejbml) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(entity-bean) at (EnterpriseServer.java:228)
com.ejbhome.VendorConfiguration.getHomeContainerClassName() at (VendorConfiguration.java:226)
com.ejbhome.VendorConfiguration.getVendorPrefix() at (VendorConfiguration.java:100)
com.ejbhome.container.AbstractEJBHome.<init>() at (AbstractEJBHome.java:136)
com.ejbhome.naming.spi.rmi.RMICtx.bind() at (RMICtx.java:168)
registered Bank.IonaCheckingsHome, as: checkings.
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(container-managed) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (EnterpriseServer.java:228)
finished loading beans from: Checkings.ejbml
loading beans from: Savings.ejbml
com.ejbhome.server.EnterpriseServer$2.startElement(ejbml) at (EnterpriseServer.java:228)
com.ejbhome.server.EnterpriseServer$2.startElement(entity-bean) at (EnterpriseServer.java:228)
com.ejbhome.VendorConfiguration.getHomeContainerClassName() at (VendorConfiguration.java:226)
com.ejbhome.VendorConfiguration.getVendorPrefix() at (VendorConfiguration.java:100)
com.ejbhome.container.AbstractEJBHome.<init>() at (AbstractEJBHome.java:136)
com.ejbhome.naming.spi.rmi.RMICtx.bind() at (RMICtx.java:168)
registered Bank.IonaSavingsHome, as: savings.
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (Compiled Code)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (Compiled Code)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (Compiled Code)
com.ejbhome.server.EnterpriseServer$2.startElement(property) at (Compiled Code)
com.ejbhome.server.EnterpriseServer$2.startElement(container-managed) at (Compiled Code)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (Compiled Code)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (Compiled Code)
com.ejbhome.server.EnterpriseServer$2.startElement(field) at (Compiled Code)
finished loading beans from: Savings.ejbml
loading beans from: Teller.ejbml
com.ejbhome.server.EnterpriseServer$2.startElement(ejbml) at (Compiled Code)
com.ejbhome.server.EnterpriseServer$2.startElement(session-bean) at (Compiled Code)
com.ejbhome.VendorConfiguration.getHomeContainerClassName() at (VendorConfiguration.java:226)
com.ejbhome.VendorConfiguration.getVendorPrefix() at (VendorConfiguration.java:100)
com.ejbhome.container.AbstractEJBHome.<init>() at (AbstractEJBHome.java:136)
com.ejbhome.naming.spi.rmi.RMICtx.bind() at (RMICtx.java:168)
registered Bank.IonaTellerHome, as: teller.
finished loading beans from: Teller.ejbml


The Server is now up and ready and is waiting for connections from the client.

click here to go to
My EJB HomePage...

click here to go to
My Advanced Java Tutorial Page...

 

About the Author...
Gopalan Suresh Raj is a Software Architect, Developer and an active Author. He is contributing author to a couple of books "Enterprise Java Computing-Applications and Architecture" and "The Awesome Power of JavaBeans". His expertise spans enterprise component architectures and distributed object computing. Visit him at his Web Cornucopia© site (http://www.execpc.com/~gopalan) or mail him at gopalan@execpc.com.

Go to the Component Engineering Cornucopia page

This site was developed and is maintained by Gopalan Suresh Raj

This page has been visited times since September 21,1998.

Last Updated : Mar 27, '99

If you have any questions, comments, or problems regarding this site, please write to me I would love to hear from you.


Copyright (c) 1997-99, Gopalan Suresh Raj - All rights reserved. Terms of use.

All products and companies mentioned at this site are trademarks of their respective owners.