Discussions

EJB design: Passing a Session Bean reference to a Java Class. Design Questi

  1. I have a session bean that I am using to get Categories from the ebay API for my
    application. The categories are returned as an XML stream. I used SAX to write a
    parser to parse the XML stream and then insert the categories into a database. I have
    an entity bean that handles the insertion. What I did was pass a reference to the bean
    class of the session bean in the constructor for the XML parser so I could call the method
    to insert into the database after the parser has seen each category. My question is, is
    this considered bad design passing a reference to the bean to the java class. It is
    packaged in the same JAR with the beans. Here is the code.

    ***********************
    THE XML PARSER
    ***********************
    package ebaycategories;

    import org.xml.sax.SAXException;
    import org.xml.sax.helpers.DefaultHandler;
    import javax.xml.parsers.SAXParserFactory;
    import javax.xml.parsers.SAXParser;
    import org.xml.sax.Attributes;
    import java.io.*;

    public class EbayCategoryParser extends DefaultHandler
    {

      //this is the bean reference
      private EbayCategoryUpdaterBean updaterRef;
      private SAXParserFactory factory;
      private SAXParser parser;
      
      private CategoryElement ebay;
      private CategoryElement ebaytime;
      private CategoryElement categories;
      private CategoryElement version;
      private CategoryElement updategmttime;
      private CategoryElement updatetime;
      private CategoryElement category;
      private CategoryElement categoryid;
      private CategoryElement categorylevel;
      private CategoryElement categoryname;
      private CategoryElement categoryparentid;
      private CategoryElement isexpired;
      private CategoryElement isintlautosfixed;
      private CategoryElement isvirtual;
      private CategoryElement leafcategory;
      
      private EbayCategory ebayCategory;
      
      public EbayCategoryParser(EbayCategoryUpdaterBean ref)
      {
        updaterRef=ref;
      
        try
        {
          factory=SAXParserFactory.newInstance();
          parser=factory.newSAXParser();
        }
        catch(Exception EX)
        {
        }
        
        ebay=new CategoryElement("eBay");
        ebaytime=new CategoryElement("EbayTime");
        categories=new CategoryElement("Categories");
        version=new CategoryElement("Version");
        updategmttime=new CategoryElement("UpdateGMTTime");
        updatetime=new CategoryElement("UpdateTime");
        category=new CategoryElement("Category");
        categoryid=new CategoryElement("CategoryId");
        categorylevel=new CategoryElement("CategoryLevel");
        categoryname=new CategoryElement("CategoryName");
        categoryparentid=new CategoryElement("CategoryParentId");
        isexpired=new CategoryElement("IsExpired");
        isintlautosfixed=new CategoryElement("IsIntlAutosFixed");
        isvirtual=new CategoryElement("IsVirtual");
        leafcategory=new CategoryElement("LeafCategory");
      }
      
      public void parseCategories(InputStream is)
      {
        try
        {
          parser.parse(is,this);
        }
        catch(Exception EX)
        {
        }
      }
      
      public void startElement(String URI, String localName,
    String qName, Attributes attributes)
    throws SAXException
      {
        if(qName==ebay.getName())ebay.changeState();
        if(qName==ebaytime.getName())ebaytime.changeState();
        if(qName==categories.getName())categories.changeState();
        if(qName==version.getName())version.changeState();
        if(qName==updategmttime.getName())updategmttime.changeState();
        if(qName==updatetime.getName())updatetime.changeState();
        if(qName==category.getName())
        {
          ebayCategory=new EbayCategory();
          category.changeState();
        }
        if(qName==categoryid.getName())categoryid.changeState();
        if(qName==categorylevel.getName())categorylevel.changeState();
        if(qName==categoryname.getName())categoryname.changeState();
        if(qName==categoryparentid.getName())categoryparentid.changeState();
        if(qName==isexpired.getName())isexpired.changeState();
        if(qName==isintlautosfixed.getName())isintlautosfixed.changeState();
        if(qName==isvirtual.getName())isvirtual.changeState();
        if(qName==leafcategory.getName())leafcategory.changeState();
      }
      
      public void endElement(String URI, String localName, String qName)
    throws SAXException
      {
        if(qName==ebay.getName())ebay.changeState();
        if(qName==ebaytime.getName())ebaytime.changeState();
        if(qName==categories.getName())categories.changeState();
        if(qName==version.getName())version.changeState();
        if(qName==updategmttime.getName())updategmttime.changeState();
        if(qName==updatetime.getName())updatetime.changeState();
        if(qName==category.getName())
        {
          //here is where it calls the method on the bean to insert the Category
          updaterRef.addEbayCategory(ebayCategory);
          category.changeState();
          ebayCategory=null;
        }
        if(qName==categoryid.getName())categoryid.changeState();
        if(qName==categorylevel.getName())categorylevel.changeState();
        if(qName==categoryname.getName())categoryname.changeState();
        if(qName==categoryparentid.getName())categoryparentid.changeState();
        if(qName==isexpired.getName())isexpired.changeState();
        if(qName==isintlautosfixed.getName())isintlautosfixed.changeState();
        if(qName==isvirtual.getName())isvirtual.changeState();
        if(qName==leafcategory.getName())leafcategory.changeState();
      }
      
      public void characters(char [] ch, int start, int length)
    throws SAXException
      {
        String chars=new String(ch,start,length);
        
        if(ebay.in())
        {
          if(categories.in())
          {
            if(category.in())
            {
              if(categoryid.in())
              {
                ebayCategory=new EbayCategory();
                ebayCategory.setCategoryId(chars);
              }
              
              if(categorylevel.in())
              {
                ebayCategory.setCategoryLevel(chars);
              }
              
              if(categoryname.in())
              {
                ebayCategory.setCategoryName(chars);
              }
              
              if(categoryparentid.in())
              {
                ebayCategory.setCategoryParentId(chars);
              }
              
              if(isexpired.in())
              {
                if(Integer.parseInt(chars)==0)
                  ebayCategory.setIsExpired(false);
                else
                  ebayCategory.setIsExpired(true);
              }
              
              if(isintlautosfixed.in())
              {
                if(Integer.parseInt(chars)==0)
                  ebayCategory.setIsIntlAutosFixedCat(false);
                else
                  ebayCategory.setIsIntlAutosFixedCat(true);
              }
              
              if(isvirtual.in())
              {
                if(Integer.parseInt(chars)==0)
                  ebayCategory.setIsVirtual(false);
                else
                  ebayCategory.setIsVirtual(true);
              }
              
              if(leafcategory.in())
              {
                if(Integer.parseInt(chars)==0)
                  ebayCategory.setLeafCategory(false);
                else
                  ebayCategory.setLeafCategory(true);
              }
            }
          }
        }
      }
    }

    class CategoryElement
    {
      private String name;
      private boolean flag;
      
      public CategoryElement(String name)
      {
        this.name=name;
        flag=false;
      }
      
      public String getName()
      {
        return name;
      }
      
      public boolean in()
      {
        return flag;
      }
      
      public void changeState()
      {
        flag=!flag;
      }
    }


    *****************************************
    The session bean
    *****************************************
    package ebaycategories;

    import javax.ejb.SessionBean;
    import javax.ejb.SessionContext;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import javax.net.ssl.HttpsURLConnection;
    import java.net.*;
    import java.io.*;

    public class EbayCategoryUpdaterBean implements SessionBean
    {
      private EbayCategoryLocalHome ebayCategoryLocalHome;
      
      //here is the parser
      private EbayCategoryParser ebayCategoryParser;
      
      private URL sandbox;
      private HttpsURLConnection sandboxConn;
      
      public void updateEbayCategories()
      {
        try
        {
          sandbox=new URL(sandboxURL);
          sandboxConn=(HttpsURLConnection)sandbox.openConnection();
          
          sandboxConn.setDoInput(true);
    sandboxConn.setDoOutput(true);

    sandboxConn.setRequestMethod("POST");

    sandboxConn.addRequestProperty("X-EBAY-API-COMPATIBILITY-LEVEL",compatibilityLevel);
    sandboxConn.addRequestProperty("X-EBAY-API-SESSION-CERTIFICATE",sessionCertificate);
    sandboxConn.addRequestProperty("X-EBAY-API-DEV-NAME",devName);
    sandboxConn.addRequestProperty("X-EBAY-API-APP-NAME",appName);
    sandboxConn.addRequestProperty("X-EBAY-API-CERT-NAME",certName);
    sandboxConn.addRequestProperty("X-EBAY-API-CALL-NAME",callName);
    sandboxConn.addRequestProperty("X-EBAY-API-DETAIL-LEVEL",detailLevel);
    sandboxConn.addRequestProperty("X-EBAY-API-SITEID",siteID);
    sandboxConn.addRequestProperty("Content-Type",contentType);
          
          OutputStream output = sandboxConn.getOutputStream();
    PrintStream sendToSandbox = new PrintStream(output);

    sendToSandbox.print(xmlFunctionCall);
    sendToSandbox.close();

    InputStream input = sandboxConn.getInputStream();
          
          ebayCategoryParser.parseCategories(input);
    //BufferedInputStream fromSandbox = new BufferedInputStream(input);
        }
        catch(Exception EX)
        {
        }
      }
      
      public void addEbayCategory(EbayCategory ebayCategory)
      {
        EbayCategoryLocal ebayCategoryLocal=null;
        try
        {
          ebayCategoryLocal=ebayCategoryLocalHome.create(ebayCategory.getCategoryId(),
            ebayCategory.getCategoryLevel(),ebayCategory.getCategoryName(),
            ebayCategory.getCategoryParentId(),""+ebayCategory.isIsExpired(),
            ""+ebayCategory.isIsIntlAutosFixedCat(),""+ebayCategory.isIsVirtual(),
            ""+ebayCategory.isLeafCategory());
        }
        catch(javax.ejb.CreateException CEX)
        {
        }
      }
      
      public void ejbCreate()
      {
        try
        {
          ebayCategoryLocalHome=getEbayCategoryLocalHome();
        }
        catch(NamingException NEX)
        {
        }
        //construct the parser with a reference to this bean class
        ebayCategoryParser=new EbayCategoryParser(this);
      }
      
      public void ejbActivate()
      {
      }

      public void ejbPassivate()
      {
      }

      public void ejbRemove()
      {
      }

      public void setSessionContext(SessionContext ctx)
      {
      }

      private EbayCategoryLocalHome getEbayCategoryLocalHome() throws NamingException
      {
        final InitialContext context = new InitialContext();
        return (EbayCategoryLocalHome)context.lookup("java:comp/env/ejb/local/EbayCategory");
      }
      
      
      
      //for connecting to ebay
      static final String sandboxURL = "https://api.sandbox.ebay.com/ws/api.dll";

    static final String DevID = "devid";
    static final String AppID = "appid";
    static final String CertID = "certid";
    static final String compatibilityLevel = "305";
    static final String sessionCertificate = DevID + ";" + AppID + ";" + CertID;
    static final String devName = DevID;
    static final String appName = AppID;
    static final String certName = CertID;
    static final String callName = "GetCategories";
    static final String siteID = "0";
    static final String detailLevel = "1";
    static final String contentType = "text/xml";

    static final String authToken = "authtoken";

    static final String xmlFunctionCall =
    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
    "<request>" +
    "<RequestToken>"+authToken+"</RequestToken>" +
    "<ErrorLevel>1</ErrorLevel>" +
    "<DetailLevel>1</DetailLevel>" +
    "<SiteId>0</SiteId>" +
    "<verb>GetCategories</verb>" +
    "<ViewAllNodes>1</ViewAllNodes>" +
    "<CategorySiteId>0</CategorySiteId>" +
    "</request>";
    }


    If anyone has an opinion on this or knows a better design I would greatly
    appreciate it.
  2. Passing the reference of a bean to another class is not a good idea. I think, you can use this EbayCategoryParser class as a helper to EJB, to return values in a kind of object to your bean and invoke the another bean method from your bean.

    Hope this helps,
    Senthil.
  3. Hi,
    Id really think they should be kept separate. Passing the reference of the session object is like passing control of the business logic to what is ideally a helper class. In case there is a change in the business logic wherein you need to apply further business logic prior to persisting to the database, you would be changing your helper class instead of your controller!!
  4. You should actually look up the bean and pass the required arguments to it for doing the computation. Referrence of a bean should never be passed to another object.
  5. Thanks[ Go to top ]

    Thanks for the info. The only question I have though is since the Parser
    is packaged in the same JAR as the bean and is only intended to be used
    with this bean, isnt the extra overhead of looking up the bean and then
    calling it through the local interface unnecessary?
  6. Thanks[ Go to top ]

    Thanks for the info. The only question I have though is since the Parseris packaged in the same JAR as the bean and is only intended to be usedwith this bean, isnt the extra overhead of looking up the bean and thencalling it through the local interface unnecessary?
    You can pass the reference to your EJB Object to your parser class and invoke the method rather than passing the bean reference.

    context.getEJBLocalObject()
    context.getEJBObject()

    Hope this helps,
    Senthil.
  7. Thanks[ Go to top ]

    That sounds like a good idea, ill give that a try.