Junos Space SDK > Developer Guides > Junos Space Application Developer Guide > Programming with the Junos Space SDK > Developing Junos Space Applications > Creating EJBs

Creating EJBs for the Junos Space Platform

Introduction

This topic provides an overview of Enterprise Java Beans (EJBs) and describes how to create and use them in Junos Space platform applications.

What is an EJB?

Enterprise Java Bean (EJB) technology is the server-side component architecture for the Java Platform, Enterprise Edition (Java EE). EJB technology enables rapid and simplified development and deployment of robust and highly scalable component-based business applications. Such applications are distributed, scalable, transactional, multi-user, secure, and portable.

EJBs simplify development of small and large enterprise applications. With an EJB container providing system-level services to enterprise beans, the bean developer can focus on developing logic to solve business problems.

Types of EJBs

There are three types of EJBs:

The three types of EJBs are described in the next sections.

Stateless Session Bean

Session beans model business processes. A session bean is not persistent and it is destroyed once the session terminates.

A stateless session bean does not maintain a conversational state for the client. When a client invokes a method on a stateless bean, the bean's instance variables might maintain state information, but only for the duration of the invocation.

Because stateless session beans can support multiple clients, they offer better scalability for applications that require large numbers of clients.

A stateless session bean written the EJB 3.0 way is just a plain Java class with a class-level annotation of @Stateless.

Example:

import javax.ejb.*;
/**
 * A stateless session bean
 */
@Stateless
@Remote
public class HelloWorldBean {
    public String sayHello() {
        return "Hello World!!!";
    }
}

Entity Bean

Entity beans model business data. They are persistent Java objects whose state can be saved to a database and later restored from the database. An Entity bean represents a row of a database table.

Entity beans are marked with the @Entity annotation, and all properties or fields in the entity bean class not marked with the @Transient annotation are considered persistent. Entity bean persistent fields are exposed through Java Bean-style properties or as public or protected Java class fields.

Example:

public class CountryEntity  {	

 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 private int id;

 private String country;

 private String name;

// For brevity setter and getter methods for these properties are omitted

}

Message Driven Bean

Message-driven beans (MDBs) are light-weight components used for communication. In MDBs, the messaging service is in asynchronous mode because an instant result cannot be guaranteed to the user. MDBs act as message consumers receiving Java Message Service (JMS) messages.

Message-driven beans are the only kind of bean that must implement a business interface. This interface's type indicates the type of messaging system that the bean supports. For JMS-based MDBs, this interface is javax.jms.MessageListener. Note that the MDB business interface is not truly a business interface; it is simply a messaging interface.

For more information about EJB 3.0, see the EJB specifications at http://jcp.org/aboutJava/communityprocess/final/jsr220/index.html.

Guidelines for Writing Session Beans with the Eclipse SDK Plug-in

This section provides information and techniques for exposing session beans as REST interfaces using the Junos Space SDK Eclipse IDE, including guidelines for creating session bean methods.

Parameter Order

The order of path and query parameters in an EJB method is critical, as they are mapped to the path and query parameters of the REST interface or interfaces, respectively.

The ordering is from left to right corresponding to path parameters, query parameters, and the REST data objects, respectively. This is shown in the following example:

EJB Method:

public void storeEmployeeData(int empId, String empName, Department dept);

Corresponding REST Method:

@Path("/employees/{empId}")
@POST
@Consumes({"application/xml","application/json"})
public void saveEmployee(@PathParam("empId") int empId, @QueryParam("empName") String empName, DepartmentRest dept);

where:

Supporting Paging, Sorting, and Filtering on EJBs

To support paging at the EJB end, you need to use annotations. Annotate the EJB method with the @Cursor annotation, which takes the name of the JPA entity and the corresponding named query for paging.

@Entity
@NamedQueries(value = 
{
  @NamedQuery(
    name=CountryEntity.GET_ALL_COUNTRIES,
    query="select c from CountryEntity c"
  ),
  @NamedQuery(
    name=CountryEntity.GET_COUNTRY,
    query="select c from CountryEntity c where c.country = :countryName"
  ),	 
  @NamedQuery(
    name=CountryEntity.GET_COUNTRY_BY_ID,
    query="select c from CountryEntity c where c.id = :id"
  ),
  @NamedQuery(
    name=CountryEntity.GET_NUM_COUNTRIES,
    query="select count(id) from CountryEntity"
  ),
  @NamedQuery(
    name=CountryEntity.GET_A_STATE_BY_A_COUNTRY,
    query="select c from CountryEntity c where c.id = :cid and c.state = :sid "
  )
}	
)

@Table(name = "CountryEntity", uniqueConstraints = {
  @UniqueConstraint(columnNames = "country") })
  @ManagedObject({"vnd.jssdk.helloworld.Country"})

public class CountryEntity extends AbstractEntity {	

    private static final long serialVersionUID = -4777494269104907844L;
    public final static String CLASSNAME = "vnd.jssdk.helloworld.jpa.CountryEntity";
    public final static String GET_ALL_COUNTRIES = CLASSNAME + ".AllCountries";
    public final static String GET_COUNTRY = CLASSNAME + ".Country";
    public final static String GET_COUNTRY_BY_ID = CLASSNAME + ".Countryid";
    public final static String GET_NUM_COUNTRIES = CLASSNAME + ".NumCountries";

    public final static String GET_A_STATE_BY_A_COUNTRY = CLASSNAME + ".Country_State";

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;

    private String country;
    private String name;
    private int population = 0;

    @OneToMany(mappedBy="country")
    private Collection state;

    public int getId() {
     return id;
    }

    public void setId(int id) {
     this.id = id;
    }

    public String getName() {
     return name;
    }

    public Collection getState() {
     return state;
    }

    public void setState(Collection state) {
     this.state = state;
    }

    public void setName(String name) {
     this.name = name;
    }

    @Basic
    public String getCountry() {
     return country;
    }

    public void setCountry(String country) {
     this.country = country;
    }

    @Basic
    public int getPopulation() {
     return population;
    }

    public void setPopulation(int population) {
     this.population = population;
    }

    @Override
    protected StringBuffer getDedupQueryStr() {
     //Can be overridden to expose AbstractEntity capability
     return null;
    }

    @Override
    public Object syncWithDbObject(EntityManager arg0) throws Exception {
     //Can be overridden to expose AbstractEntity capability
     return null;
    }
}

The JPA entity class CountryEntity.java provided in the example above, has a named query CountryEntity. GET_ALL_COUNTRIES, which is used in the @Cursor annotation on the EJB method getCountries(PagingContext ctxt) shown below. Ensure your EJB method takes a PagingContext object as one of the parameters and returns a PagingResult collection. Use EntityManagerWrapper for executing queries. For an example, see the following code:

@Cursor( entityClass = CountryEntity.CLASSNAME, queryName = CountryEntity.GET_ALL_COUNTRIES )
public PagingResult getCountries(PagingContext ctx) throws Exception
{
    EntityManagerWrapper qm = new EntityManagerWrapper( manager );
    List countryEntities = qm.executeNamedQuery( CountryEntity.GET_ALL_COUNTRIES, ctx );
    if ( countryEntities == null )
      return null;
    PagingResult countries = new PagingResult();
    for ( CountryEntity countryEntity : countryEntities ) 
    {
      countries.add( fromCountryEntity2Country( countryEntity ) );
    }
    return countries;
}

Enabling Sorting and Filtering (on a managed object where names of attributes differ from the JPA entity)

To support filtering and sorting on an EJB when the names of attributes in managed objects are different from the names of attributes in the corresponding JPA, you need to use annotations. You should annotate the getter or setter of those attributes in the managed object with @Sortable/@Filterable annotations.

public class Country extends AbstractManagedObject implements Serializable {

   private static final long serialVersionUID = -7193689193493067352L;

   @XmlElement
   private int id = 0;
   @XmlElement
   private String name;
   @XmlElement
   private Integer population;
   @XmlElement
   private String text;
   @XmlElement
   private boolean leaf;
   @XmlElement
   private Collection states;

   public Country() { }

   public String getText() {
     return text;
   }

   public void setText(String text) {
     this.text = text;
   }

   public boolean getLeaf() {
     return leaf;
   }

   public void setLeaf(boolean leaf) {
     this.leaf = leaf;
   }

   public Country(String name) {
     this.name = name;
   }

   @Sortable(entityAttrName = "id")
   public int getId() {
     return id;
   }

   public void setId(int id) {
     this.id = id;
   }

   @Filterable(entityAttrName = "country")
   @Sortable(entityAttrName = "country")
   public String getName() {
     return name;
   }

   public void setName(String name) {
     this.name = name;
   }

   @Sortable(entityAttrName = "population")
   public Integer getPopulation() {
     return population;
   }

   public void setPopulation(Integer population) {
     this.population = population;
   }

   @XmlTransient
   private String moid = null;

   @Override
   public String getMOID() {
     return moid;
   }

   @Override
   public void setMOID(String arg0) {
     this.moid = arg0;
   }

   public Collection getStates() {
     return states;
   }

   public void setStates(Collection states) {
     this.states = states;
   }

}

Enabling Long Running Request (LRR) on EJB

To enable scheduling on a long running request (LRR) for asynchronous notifications, see Asynchronous Notifications with Long Running Request.