Expor ADF BC como RESTful Web Service

Expor um ADF BC como SOAP Web Service é muito simples. Tudo que você tem a fazer é permitir que o Application Module suporte Service Interface. Mas, como posso expor este Application Module como RESTful Web Service?

Neste post, você vai aprender a expor ADF BC como RESTful Web Service usando o 12c JDeveloper (12.1.3). Faça o download do aplicativo de amostra: ADFRESTApp.zip.

Crie um ADF Fusion Web Application, e o chame de ADFRESTApp.

expose-adf-bc-restful-web-service1

Crie o Business Components, usando a tabela Employees.

expose-adf-bc-restful-web-service2

Desta forma, você tem um aplicativo ADF simples com dois projetos, Model e ViewController.
Agora, nós temos que criar um projeto para organizar os códigos RESTful.
Crie um novo projeto ADF Model RESTful Web Service.

expose-adf-bc-restful-web-service3

Para usar o Application Module do projeto Model, você precisa adicionar o Projeto Model como uma dependência.
Clique duas vezes no projeto RESTWebService e adicione o Projeto Modelo como uma dependência.

expose-adf-bc-restful-web-service4

Crie as entidades Employee e Employees.
Na janela Applications, clique com o botão direito no projeto RESTWebService e selecione New > From Gallery..
Na caixa de diálogo New Gallery, escolha General > Java Class, e clique em OK.
Na caixa de diálogo Create Java Class, altere o nome para Employee e clique em OK.
Copie o seguinte código dentro da classe Employee:

@XmlRootElement
public class Employee {
  @XmlElement
  private Integer employeeId;
  @XmlElement
  private String firstName;
  @XmlElement
  private String lastName;
  @XmlElement
  private String email;
  @XmlElement
  private String phoneNumber;
  @XmlElement
  private Date hireDate;
  @XmlElement
  private String jobId;
  @XmlElement
  private BigDecimal salary;
  @XmlElement
  private BigDecimal commissionPct;
  @XmlElement
  private Integer managerId;
  @XmlElement
  private Integer departmentId;
    
  public Employee() {
    super();
  }
  public void setEmployeeId(Integer employeeId) {
    this.employeeId = employeeId;
  }
  public Integer getEmployeeId() {
    return employeeId;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public String getFirstName() {
    return firstName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public String getLastName() {
    return lastName;
  }
  public void setEmail(String email) {
    this.email = email;
  }
  public String getEmail() {
    return email;
  }
  public void setPhoneNumber(String phoneNumber) {
    this.phoneNumber = phoneNumber;
  }
  public String getPhoneNumber() {
    return phoneNumber;
  }
  public void setHireDate(Date hireDate) {
    this.hireDate = hireDate;
  }
  public Date getHireDate() {
    return hireDate;
  }
  public void setJobId(String jobId) {
    this.jobId = jobId;
  }
  public String getJobId() {
    return jobId;
  }
  public void setSalary(BigDecimal salary) {
    this.salary = salary;
  }
  public BigDecimal getSalary() {
    return salary;
  }
  public void setCommissionPct(BigDecimal commissionPct) {
    this.commissionPct = commissionPct;
  }
  public BigDecimal getCommissionPct() {
    return commissionPct;
  }
  public void setManagerId(Integer managerId) {
    this.managerId = managerId;
  }
  public Integer getManagerId() {
    return managerId;
  }
  public void setDepartmentId(Integer departmentId) {
    this.departmentId = departmentId;
  }
  public Integer getDepartmentId() {
    return departmentId;
  }
}

Repita o passo anterior e crie a classe Employees.
Copie o seguinte código dentro da classe Employees:

@XmlRootElement
public class Employees {
  @XmlElement(name = "employee")
  private List employees;

  public Employees() {
    super();
  }
  public void setEmployees(List employees) {
    this.employees = employees;
  }
  public List getEmployees() {
    return employees;
  }
  public void addEmployees(Employee employee) {
    if (employees == null) {
      employees = new ArrayList();
    }
    employees.add(employee);
  }
}

Crie o Employees RESTful Service.
Na janela Applications, clique com o botão direito no Projeto Rest e selecione New > From Gallery.
Na caixa de diálogo New Gallery, escolha General > Java Class e clique em OK.
Na caixa de diálogo Create Java Class, altere o nome para EmployeesResource e clique em OK.
Copie o seguinte código dentro da classe EmployeesResource:

public class EmployeesResource {
  private static final String amDef = "br.com.waslleysouza.model.AppModule";
  private static final String config = "AppModuleLocal";

  public EmployeesResource() {}

  public void update(Employee employee) {
    ApplicationModule am = Configuration.createRootApplicationModule(amDef, config);
    ViewObject vo = am.findViewObject("EmployeesView1");

    Key key = new Key(new Object[] { employee.getEmployeeId() });
    Row[] rowsFound = vo.findByKey(key, 1);
    if (rowsFound != null && rowsFound.length > 0) {
      Row row = rowsFound[0];
      if (employee.getEmail() != null && !employee.getEmail().isEmpty()) {
        row.setAttribute("Email", employee.getEmail());
      }
      if (employee.getHireDate() != null) {
        row.setAttribute("HireDate", employee.getHireDate());
      }
      if (employee.getJobId() != null && !employee.getJobId().isEmpty()) {
        row.setAttribute("JobId", employee.getJobId());
      }
      if (employee.getLastName() != null && !employee.getLastName().isEmpty()) {
        row.setAttribute("LastName", employee.getLastName());
      }
    }
    am.getTransaction().commit();
    Configuration.releaseRootApplicationModule(am, true);
  }

  public Employee getById(Integer id) {
    ApplicationModule am = Configuration.createRootApplicationModule(amDef, config);
    ViewObject vo = am.findViewObject("EmployeesView1");
    Employee employee = null;

    Key key = new Key(new Object[] { id });
    Row[] rowsFound = vo.findByKey(key, 1);
    if (rowsFound != null && rowsFound.length > 0) {
      Row row = rowsFound[0];
      employee = new Employee();
      employee.setEmployeeId((Integer) row.getAttribute("EmployeeId"));
      employee.setEmail((String) row.getAttribute("Email"));
      employee.setHireDate((Timestamp) row.getAttribute("HireDate"));
      employee.setJobId((String) row.getAttribute("JobId"));
      employee.setLastName((String) row.getAttribute("LastName"));
    }
    Configuration.releaseRootApplicationModule(am, true);
    return employee;
  }

  public void deleteById(Integer id) {
    ApplicationModule am = Configuration.createRootApplicationModule(amDef, config);
    ViewObject vo = am.findViewObject("EmployeesView1");

    Key key = new Key(new Object[] { id });
    Row[] rowsFound = vo.findByKey(key, 1);
    if (rowsFound != null && rowsFound.length > 0) {
      Row row = rowsFound[0];
      row.remove();
    }
    am.getTransaction().commit();
    Configuration.releaseRootApplicationModule(am, true);
  }

  public void add(Employee employee) {
    ApplicationModule am = Configuration.createRootApplicationModule(amDef, config);
    ViewObject vo = am.findViewObject("EmployeesView1");

    Row row = vo.createRow();
    vo.insertRow(row);
    row.setAttribute("EmployeeId", employee.getEmployeeId());
    row.setAttribute("LastName", employee.getLastName());
    row.setAttribute("Email", employee.getEmail());
    row.setAttribute("HireDate", new Timestamp(employee.getHireDate().getTime()));
    row.setAttribute("JobId", employee.getJobId());
    am.getTransaction().commit();
    Configuration.releaseRootApplicationModule(am, true);
  }

  public Employees findAll() {
    ApplicationModule am = Configuration.createRootApplicationModule(amDef, config);
    ViewObject vo = am.findViewObject("EmployeesView1");
    vo.executeQuery();
    Employees employees = new Employees();

    while (vo.hasNext()) {
      Row row = vo.next();
      Employee employee = new Employee();
      employee.setEmployeeId((Integer) row.getAttribute("EmployeeId"));
      employee.setEmail((String) row.getAttribute("Email"));
      employee.setHireDate((Timestamp) row.getAttribute("HireDate"));
      employee.setJobId((String) row.getAttribute("JobId"));
      employee.setLastName((String) row.getAttribute("LastName"));
      employees.addEmployees(employee);
    }
    Configuration.releaseRootApplicationModule(am, true);
    return employees;
  }
}

Na janela Applications, clique com o botão direito na classe EmployeesResource e escolha Create RESTful Service.
Escolha JAX-RS 2.0 Style e clique em Next.
Configure o RESTful Service e clique em Finish.

expose-adf-bc-restful-web-service5

Na caixa de diálogo Return Type Warning, clique em OK.

expose-adf-bc-restful-web-service6

Feito!
Para testar o RESTful Service, clique com o botão direito na classe EmployeesResource e escolha Test Web Service.
Você pode testar cada operação de serviço utilizando o HTTP Analyzer.
Selecione a operação findAll e clique no botão Send Request.

expose-adf-bc-restful-web-service7

Quando você tenta executar uma operação PUT ou POST, como a operação add, você recebe o seguinte erro:

Root cause of ServletException.
A MultiException has 1 exceptions.  They are:
1. java.lang.RuntimeException: Security features for the SAX parser could not be enabled.
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2494)
at org.jvnet.hk2.internal.ServiceHandleImpl.getService(ServiceHandleImpl.java:98)
at org.jvnet.hk2.internal.ServiceHandleImpl.getService(ServiceHandleImpl.java:87)
at org.glassfish.jersey.internal.inject.ContextInjectionResolver$1.provide(ContextInjectionResolver.java:114)
at org.glassfish.jersey.message.internal.XmlRootElementJaxbProvider.readFrom(XmlRootElementJaxbProvider.java:138)
Truncated. see log file for complete stacktrace
Caused By: java.lang.RuntimeException: Security features for the SAX parser could not be enabled.
at org.glassfish.jersey.message.internal.SecureSaxParserFactory.(SecureSaxParserFactory.java:103)
at org.glassfish.jersey.message.internal.SaxParserFactoryInjectionProvider.provide(SaxParserFactoryInjectionProvider.java:78)
at org.glassfish.jersey.message.internal.SaxParserFactoryInjectionProvider.provide(SaxParserFactoryInjectionProvider.java:57)
at org.jvnet.hk2.internal.FactoryCreator.create(FactoryCreator.java:96)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:456)
Truncated. see log file for complete stacktrace
Caused By: javax.xml.parsers.ParserConfigurationException: SAX feature 'http://xml.org/sax/features/external-general-entities' not supported.
at oracle.xml.jaxp.JXSAXParserFactory.setFeature(JXSAXParserFactory.java:272)
at weblogic.xml.jaxp.RegistrySAXParserFactory.setFeature(RegistrySAXParserFactory.java:134)
at org.glassfish.jersey.message.internal.SecureSaxParserFactory.(SecureSaxParserFactory.java:100)
at org.glassfish.jersey.message.internal.SaxParserFactoryInjectionProvider.provide(SaxParserFactoryInjectionProvider.java:78)
at org.glassfish.jersey.message.internal.SaxParserFactoryInjectionProvider.provide(SaxParserFactoryInjectionProvider.java:57)
Truncated. see log file for complete stacktrace

expose-adf-bc-restful-web-service8

Este é um problema conhecido do JDeveloper e ADF 11g Release 2, mas eu não encontrei nada sobre isso no Release Notes do JDeveloper e ADF 12c.
Provavelmente este problema continua no JDeveloper e ADF 12c, então vamos usar a solução para o 11g.

Crie uma classe Java que estende org.glassfish.jersey.server.ResourceConfig e defina a propriedade MessageProperties.XML_SECURITY_DISABLE para TRUE.

@ApplicationPath("/resources/")
public class MyResourceConfig extends ResourceConfig {

  public MyResourceConfig() {
    super();
    property(MessageProperties.XML_SECURITY_DISABLE, Boolean.TRUE);
  }
}

Feito!
Teste o seu RESTful Web Service novamente e execute as operações PUT e POST com sucesso!

expose-adf-bc-restful-web-service9

Waslley Souza

Autor: Waslley Souza

Consultor Oracle com foco em tecnologias Oracle Fusion Middleware e SOA. Certificado Oracle WebCenter Portal, Oracle ADF e Java.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *