Friday, September 6, 2013

Jdeveloper 12c - EJB with Rest WebService and Filtering Data Collection

In Jdeveloper 12c there is a support for Rest WebService based on EJB and its only for Java Service Facade not for Session Facade. You can create Rest WebService just right click on the Java Service Facade and in context menu click on Create RESTful Service.

In this blog entry I'm interested in constructing dynamic data collection based on the URI, query-string parameters and send Rest WebService response. Having sensible resource names or paths (e.g., /departments/10 instead of /api?type=departments&id=10) improves the clarity of what a given request does. Using URL query-string parameters is fantastic for filtering, sorting, limit, pagination or dynamic fields. Here HTTP GET method is used to retrieve (or read) a representation of a resource. Read more on Rest Webservice.

The resources are based on EJB Java Service Facade. I tried adding GET parameters (PathParam/QueryParam) to a collection in order to add functionality such as filtering, sorting, filetering fields, limit. I have written logic in Java Service Facade for few resources that looks as below:

HTTP Verb Resource Naming (URI) Entire Collection (e.g. departments)
GET RestApplication/resources/model/departments Return list of departments.
GET RestApplication/resources/model/departments?offset=1 Return individual department object.
GET RestApplication/resources/model/departments?limit=4&childValue=false Return list of departments based on limit, if childValue passed as false response will not contains employeeList object.
GET RestApplication/resources/model/departments?limit=4&childValue=false&orderBy=departmentId
&orderType=DESC
Return list of departments based on ascending/descending order.
GET RestApplication/resources/model/departments?limit=4&childValue=false
&fields=departmentId,departmentName
Return list of departments with selected departments fields dynamically.
GET RestApplication/resources/model/departments/20 Return department object by departementId.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 12.1.2.0.0]

JDeveloper provides WADL supports to run the REST WebService, below are the examples.
  • GET http://127.0.0.1:7101/RestApplication/resources/model/departments - Return list of departments
  • GET http://127.0.0.1:7101/RestApplication/resources/model/departments?offset=1 - Return department object.
  • GET http://127.0.0.1:7101/RestApplication/resources/model/departments?limit=4&childValue=false - Return list of departments based on limit, if childValue passed as false response will not contains employeeList object.
  • GET http://127.0.0.1:7101/RestApplication/resources/model/departments?limit=4&childValue=false&orderBy=departmentId&orderType=DESC - Return list of departments based on ascending/descending order.
  • GET http://127.0.0.1:7101/RestApplication/resources/model/departments?limit=4&childValue=false&fields=departmentId,departmentName - Return list of departments with dynamic departments fields.
  • GET http://127.0.0.1:7101/RestApplication/resources/model/departments/20 - Return department object by departementId.

Below Java Service Facade code explains how to create resources and filter the data collection for above scenarios.
@Path("model")
public class JavaServiceFacade {
    private final EntityManager em;
    private String XMLResponse;
    private String fields = null;
    private boolean childValue;

    public JavaServiceFacade() {
        final EntityManagerFactory emf = Persistence.createEntityManagerFactory("Model-1");
        em = emf.createEntityManager();
    }

    /**
     * @param childValue
     * @param offset
     * @param limit
     * @param fields
     * @param orderBy
     * @param orderType
     * @return
     */
    @GET
    @Produces("application/xml")
    @Path("/departments")
    public String getDepartmentsFindAll(@DefaultValue("true") @QueryParam("childValue") boolean childValue,
                                        @DefaultValue("0") @QueryParam("offset") int offset,
                                        @DefaultValue("0") @QueryParam("limit") int limit,
                                        @QueryParam("fields") String fields, @QueryParam("orderBy") String orderBy,
                                        @QueryParam("orderType") String orderType) {
        this.childValue = childValue;
        this.fields = fields;

        Query query = null;
        if (offset > 0) {
            query =
                em.createNamedQuery("Departments.findAll", Departments.class).setFirstResult(offset).setMaxResults(1);
            this.generateXMlResponse(query, false);
        } else if (orderBy != null) {
            String qlString = "select o from Departments o order by o." + orderBy;
            if (orderType != null)
                qlString += " " + orderType;
            query = em.createQuery(qlString, Departments.class).setMaxResults(limit);
            this.generateXMlResponse(query, false);
        } else {
            query = em.createNamedQuery("Departments.findAll", Departments.class).setMaxResults(limit);
            this.generateXMlResponse(query, false);
        }
        return this.XMLResponse;
    }

    /**
     * @param departmentId
     * @param fields
     * @param childValue
     * @return
     */
    @GET
    @Produces("application/xml")
    @Path("/departments/{departmentId}")
    public String getDepartmentById(@PathParam("departmentId") int departmentId, @QueryParam("fields") String fields,
                                    @DefaultValue("true") @QueryParam("childValue") boolean childValue) {
        this.childValue = childValue;
        this.fields = fields;
        Query query =
            em.createNamedQuery("Departments.ByDeptId", Departments.class).setParameter("bind_departmentId",
                                                                                        departmentId);
        this.generateXMlResponse(query, true);
        return this.XMLResponse;
    }

    /**
     * @param query
     * @param singleResult
     */
    public void generateXMlResponse(Query query, boolean singleResult) {
        if (singleResult == true) {
            List deptResultList = query.getResultList();
            if (deptResultList.size() > 0) {
                this.XMLResponse = "";
                Iterator deptListIterator = deptResultList.iterator();
                while (deptListIterator.hasNext()) {
                    this.XMLResponse += "";
                    Departments dept = (Departments) deptListIterator.next();
                    this.constructXML(dept.getClass(), dept, false);
                    if (this.childValue == true) {
                        List empList = dept.getEmployeesList1();
                        for (int j = 0; j < empList.size(); j++) {
                            Employees emp = empList.get(j);
                            this.XMLResponse += "";
                            this.constructXML(emp.getClass(), emp, true);
                            this.XMLResponse += "";
                        }
                    }
                    this.XMLResponse += "";
                }
                this.XMLResponse += "";
            }
        } else {
            Vector resultList = (Vector) query.getResultList();
            int deptSize = resultList.size();
            if (deptSize > 0) {
                this.XMLResponse = "";
                for (int i = 0; i < deptSize; i++) {
                    //  Object obj = resultList.elementAt(i);
                    this.XMLResponse += "";
                    Departments dept = (Departments) resultList.elementAt(i);
                    this.constructXML(dept.getClass(), dept, false);
                    if (this.childValue == true) {
                        List empList = dept.getEmployeesList1();
                        for (int j = 0; j < empList.size(); j++) {
                            Employees emp = empList.get(j);
                            this.XMLResponse += "";
                            this.constructXML(emp.getClass(), emp, true);
                            this.XMLResponse += "";
                        }
                    }
                    this.XMLResponse += "";
                }
                this.XMLResponse += "";
            }
        }
    }

    /**
     * @param clazz
     * @param obj
     * @param childValue
     */
    public void constructXML(Class clazz, Object obj, boolean childValue) {
        Class noparams[] = { };
        try {
            Field[] field = clazz.getDeclaredFields();
            for (int i = 0; i < field.length; i++) {
                String fieldName = field[i].getName();
                if (field[i].isAnnotationPresent(Column.class)) {
                    String methodName =
                        "get" + field[i].getName().toString().substring(0, 1).toUpperCase() +
                        field[i].getName().toString().substring(1);
                    Method method = clazz.getDeclaredMethod(methodName, noparams);
                    Object fieldValue = method.invoke(obj, null);

                    if (this.fields == null || childValue == true) {
                        this.XMLResponse += "<" + fieldName + ">" + fieldValue + "</" + fieldName + ">";
                    } else {
                        String columnNames[] = this.fields.split(",");
                        for (int j = 0; j < columnNames.length; j++) {
                            if (columnNames[j] != null) {
                                boolean colNamesExist = this.findFieldExists(Departments.class, columnNames[j]);
                                if (colNamesExist == true && columnNames[j].equals(fieldName))
                                    this.XMLResponse += "<" + fieldName + ">" + fieldValue + "</" + fieldName + ">";
                            }
                        }
                    }
                }
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param clazz
     * @param fieldName
     * @return boolean
     */
    public boolean findFieldExists(Class clazz, String fieldName) {
        try {
            Field field = clazz.getDeclaredField(fieldName);
            if (field != null)
                return true;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return false;
    }
 
  /**
     * All changes that have been made to the managed entities in the
     * persistence context are applied to the database and committed.
     */
    private void commitTransaction() {
        final EntityTransaction entityTransaction = em.getTransaction();
        if (!entityTransaction.isActive()) {
            entityTransaction.begin();
        }
        entityTransaction.commit();
    }

    public Object queryByRange(String jpqlStmt, int firstResult, int maxResults) {
        Query query = em.createQuery(jpqlStmt);
        if (firstResult > 0) {
            query = query.setFirstResult(firstResult);
        }
        if (maxResults > 0) {
            query = query.setMaxResults(maxResults);
        }
        return query.getResultList();
    }

    public  T persistEntity(T entity) {
        em.persist(entity);
        commitTransaction();
        return entity;
    }

    public  T mergeEntity(T entity) {
        entity = em.merge(entity);
        commitTransaction();
        return entity;
    }
}

No comments:

Post a Comment