SOAP

SOAP - Simple Object ACCESS PROTOCOL
  1. SOAP – это целое семейство протоколов и стандартов, откуда напрямую вытекает, что это более тяжеловесный и сложный вариант с точки зрения машинной обработки. Поэтому REST работает быстрее.
  2. SOAP используют HTTP как транспортный протокол, в то время как REST базируется на нем. Это означает, что все существующие наработки на базе протокола HTTP, такие как кеширование на уровне сервера, масштабирование, продолжают так же работать в REST архитектуре, а для SOAP необходимо искать другие средства. 
  3. Есть мнение, что разработка RESTful сервисов намного проще. Наверное, это правда, если использовать Notepad в качестве основной среды разработки, но вот с использованием наших чудесных средств разработки, я позволю себе усомниться в верности этого утверждения.
  4. В первом гугловском результате по запросу «REST vs SOAP» акцентируется внимание на том, что ответ REST может быть представлен в различных форматах, а SOAP привязан к XML. Это действительно важный фактор, достаточно представить себе вызов сервиса из javascript, ответ на который мы определенно хотим получать в JSON.
  5. «REST vs SOAP» можно перефразировать в «Простота vs Стандарты», что проявляется в том, что для SOAP мы имеем протокол WSDL для исчерпывающего описания веб-сервиса, который с использованием все тех же чудесных средств разработки прото-таки волшебным образом делает почти всю работу за нас. Со стороны REST мы имеем загадочный и неиспользуемый протокол WADL, который, в принципе, и не нужен – он мешает простоте.
  6. Второй аспект предыдущего пункта – обработка ошибок. В SOAP она полностью стандартизована, а REST может использовать давно известные коды ошибок HTTP (если здесь Вас посетила мысль, что это же очевидно и зачем я это пишу, то значит Вы внимательно читаете статью).
  7. То, с чего можно было бы начать, но я припас напоследок. Это одна из ключевых мыслей. SOAP работает с операциями, а REST – с ресурсами. Этот факт в совокупности с отсутствием клиентского состояния у RESTful сервисов приводит нас к тому, что такие вещи как транзакции или другая сложная логика должна реализовываться «SOAP-но».
Веб-сервис(endpoint) — содержит всю логику с которой вы будете работать, именно через него активируются запросы в базу данных, обработка данных и т.д.
Паблишер(publisher) — сервис который загружает веб-сервис в сеть для общего к нему доступа.
Клиент(client) — сервис который обращается к веб-сервису для получения того или иного результата.
Пишем наш веб-сервис.
Для начала нам надо сделать интерфейс который описывает скелет будущей функциональности веб-сервиса:
1
2
3
4
5
6
7
8
9
10
11
12
13
package dev.bay.ws;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
public interface SayHello {
    @WebMethod
    String hi();
}
Как вы можете видеть, это интерфейс похож на сотни других, веб-сервисом его делают аннотации, которые мы к нему дописали. Основной аннотацией является @WebService, именно указывает что интерфейс на который мы смотрим является веб-сервисом. Аннотация @SoapBinding служит для определения к какому стилю принадлежит веб-сервис и как он отображается в wsdl файл. Style=Document/Use=Literal является стандартными параметрами и когда вы будете писать свои собственные веб-сервисы и вас будут удовлетворять стандартные установки, вам не надо будет это прописывать. Аннотация @WebMethod служит для корректного отображения метода в wsdl(xml-подобные формат в в который отображаются веб-сервисы) файле. @WebMethod содержит такие аргументы: perationName — отвечает за имя операции, action — этот атрибут отвечает за значения поля soapAction (стандартным значением этого атрибута является пустая строка), exclude — определяет должен ли метод отображаться в wsdl файле или нет.
Теперь пилим реализацию нашего веб-сервиса.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package dev.bay.ws;
import javax.jws.WebService;
@WebService(endpointInterface = "dev.bay.ws.SayHello")
public class SayHelloImpl implements SayHello{
    @Override
    public String hi() {
        return "Hey there, sweety!";
    }
    @Override
    public void printOut() {
        System.out.println("Is that what you wanted to see?");
    }
}
Демон — он в деталях, обратите внимание на уже знакомую аннотацию @WebService, но смысл ее кардинально иной за счет атрибута endpointInterface = «dev.bay.ws.SayHello», этот атрибут говорит нам, что этой реализации отвечает имеет этот веб-сервис.
Согласно нашей небольшой диаграмме представленной в начале статьи, мы уже знаем, что после того как мы заполучили сервис, нам надо его запустить для общего доступа в сеть иначе смысла в нем немного. Для этого нам нужен паблишер.
1
2
3
4
5
6
7
8
9
10
11
12
13
package dev.bay.ws.publisher;
import dev.bay.ws.SayHelloImpl;
import dev.bay.ws.SayRPCImpl;
import javax.xml.ws.Endpoint;
public class Publisher {
    public static void main(String[] args) {
        Endpoint.publish("http://localhost:9999/ws/hello", new SayHelloImpl());       
    }
}
Вас может удивить простота приведенного выше кода, но не обольщайтесь, это самая примитивная реализация и обычно функцию паблишинга берет на себя сервлет контейнер. http://localhost:9999/ws/hello — это url на который будет запаблишен наш веб-сервис (мы его прописываем сами).
После того как вы запаблишили наш веб-сервис нам надо к нему как-то стучаться, для этого пишем клиент.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package dev.bay.ws.client;
import dev.bay.ws.SayHello;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import java.net.MalformedURLException;
import java.net.URL;
public class Client {
    public static void main(String[] args) throws MalformedURLException {
        URL url = new URL("http://localhost:9999/ws/hello?wsdl");
        QName name = new QName("http://ws.bay.dev/","SayHelloImplService");
        Service service = Service.create(url,name);
        SayHello sayHello = service.getPort(SayHello.class);
        System.out.println(sayHello.hi());
    }
}
Первостепенная задача клиента — это достучаться до веб-сервиса. Поскольку наш веб-сервис уже имеет адресс в сети(http://localhost:9999/ws/hello) мы его и прописываем. Первая непонятная деталь состоит в приписке к нашему url адресу: ?wsdl. Не поленитесь и зайдите по этому адресу, то что вы увидите и есть наш wsdl файл который является точным отображением нашего веб-сервиса в xml-формате. Дальше идет QName, откуда мы берем значение для него? Ответ мы найдем в wsdl файле который мы только что просматривали. Обратите внимание на атрибуты targetNamespace=»http://ws.bay.dev/»и на соседний с ним атрибут name=»SayHelloImplService».
И так, алгоритм запуска приложения:
1) Запускаем паблишер;
2) Запускаем клиент.
При удачном исходе, в консоле клиента мы должны получить следующее: «Hey there, sweety!».
Все, успех!;)

REST

 REST (representation state transfer):
  • Все является ресурсами с уникальным идентификатором (URL)
  • Все операции клиента с сервером stateless, т.е. сервер не должен хранить вообще никакой информации о клиенте – никакой сессии
  • Все запросы можно поделить на 4 типа в соответствии с CRUD, причем каждому типу сопоставляется HTTP метод – Post, Get, Put и Delete
  • Вся логика крутится вокруг ресурсов, а не операций
Важно понимать, что REST – это не протокол и не стандарт, а архитектурный стиль. У этого стиля есть свои принципы. Позволю себе скопировать их с понравившегося источника и прокомментировать:
  1. Give every “thing” an ID.
    Очччень желательно.
  2. Link things together.
    Например, в страницу (представление) о Mercedes C218 хорошо бы добавить ссылку на страницу конкретно о двигателе данной модели, чтобы желающие могли сразу туда перейти, а не тратить время на поиск этой самой страницы.
  3. Use standard methods.
    Имеется в виду, экономьте свои силы и деньги заказчика, используйте стандартные методы HTTP, например GET
    http://www.example.com/cars/00345
    для получения данных вместо определения собственных методов вроде getCar?id=00345.
  4. Resources can have multiple representations.
    Одни и те же данные можно вернуть в XML или JSON для программной обработки или обернутыми в красивый дизайн для просмотра человеком.
  5. Communicate statelessly.
    Да, RESTful сервис должен быть как идеальный суд – его не должно интересовать ни прошлое подсудимого (клиента), ни будущее – он просто выносит приговор (отвечает на запрос).

JSF

JSF построен в на паттерне MVC.
JSF Architecture
Жизненный цикл JSF
В жизненном цикле JSF выделяют следующие фазы:
• Restore View(восстановление Вида) — восстанавливает или создает дерево компонентов в памяти на стороне сервера, которое будет представлять пользовательский интерфейс клиента и информацию в нем;
• Apply Request Values (Применение значений запроса) — обновляет компоненты UIна стороне сервера, записывая в них свежие данные, пришедшие со стороны клиента;
• Process Validations (Выполнение проверок) — проводит проверки и преобразует данные и их типы к требуемым на стороне сервера;
• Update Model Values(Обновление значений Модели) — обновляет объекты Модели на стороне сервера, передавая им новые данные (проверенные и преобразованные);
• Invoke Application (Выполнение приложения) — выполняет логику приложения, необходимую для исполнения запроса и перехода на какую-нибудь страницу (если это необходимо, конечно);
• Render Response (Формирование ответа) — сохраняет состояние и формирует ответ клиенту, который послал запрос.
<dependencies>
  <dependency>
  <groupId>com.sun.faces</groupId>
  <artifactId>jsf-api</artifactId>
  <version>2.1.7</version>
  </dependency>
  <dependency>
  <groupId>com.sun.faces</groupId>
  <artifactId>jsf-impl</artifactId>
  <version>2.1.7</version>
  </dependency>
</dependencies>  <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee" 
   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   id="WebApp_ID" version="2.5">
   <welcome-file-list>
      <welcome-file>faces/home.xhtml</welcome-file>
   </welcome-file-list>
   <!-- 
      FacesServlet is main servlet responsible to handle all request. 
      It acts as central controller.
      This servlet initializes the JSF components before the JSP is displayed.
   -->
   <servlet>
      <servlet-name>Faces Servlet</servlet-name>
      <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
      <servlet-name>Faces Servlet</servlet-name>
      <url-pattern>/faces/*</url-pattern>
   </servlet-mapping>
   <servlet-mapping>
      <servlet-name>Faces Servlet</servlet-name>
      <url-pattern>*.jsf</url-pattern>
   </servlet-mapping>
   <servlet-mapping>
      <servlet-name>Faces Servlet</servlet-name>
      <url-pattern>*.faces</url-pattern>
   </servlet-mapping>
   <servlet-mapping>
      <servlet-name>Faces Servlet</servlet-name>
      <url-pattern>*.xhtml</url-pattern>
   </servlet-mapping>
</web-app>
Простой ПРИМЕР!
package com.tutorialspoint.test;

import javax.faces.bean.ManagedBean;

@ManagedBean(name = "helloWorld", eager = true)
public class HelloWorld {
   public HelloWorld() {
      System.out.println("HelloWorld started!");
   }
   public String getMessage() {
      return "Hello World!";
   }
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title>JSF Tutorial!</title>
</head>
<body>
   #{helloWorld.message}
</body>
</html>
ScopeDescription
@RequestScopedBean lives as long as the HTTP request-response lives. It get created upon a HTTP request and get destroyed when the HTTP response associated with the HTTP request is finished.
@NoneScopedBean lives as long as a single EL evaluation. It get created upon an EL evaluation and get destroyed immediately after the EL evaluation.
@ViewScopedBean lives as long as user is interacting with the same JSF view in the browser window/tab. It get created upon a HTTP request and get destroyed once user postback to a different view.
@SessionScopedBean lives as long as the HTTP session lives. It get created upon the first HTTP request involving this bean in the session and get destroyed when the HTTP session is invalidated.
@ApplicationScopedBean lives as long as the web application lives. It get created upon the first HTTP request involving this bean in the application (or when the web application starts up and the eager=true attribute is set in @ManagedBean) and get destroyed when the web application shuts down.
@CustomScopedBean lives as long as the bean's entry in the custom Map which is created for this scope lives.
@ManagedBean(name = "helloWorld", eager = true) - eager =true - не ленивая загрузка. Управляющией бин загружается еще до первого вызова.
@RequestScoped
public class HelloWorld {

   @ManagedProperty(value="#{message}")  // внедрение друго менеджд бина. (по принцыge как аннотация @EJB)
   private Message messageBean;
@ManagedBean(name = "navigationController", eager = true)
@RequestScoped
public class NavigationController implements Serializable {

   //this managed property will read value from request parameter pageId
   @ManagedProperty(value="#{param.pageId}")
   private String pageId;

   //condional navigation based on pageId
   //if pageId is 1 show page1.xhtml,
   //if pageId is 2 show page2.xhtml
   //else show home.xhtml
   public String showPage(){
      if(pageId == null){
         return "home";
      }
      if(pageId.equals("1")){
         return "page1";
      }else if(pageId.equals("2")){
         return "page2";
      }else{
         return "home";
      }
   }
}
<h:form>
   <h:commandLink action="#{navigationController.showPage}" value="Page1">
      <f:param name="pageId" value="1" />
   </h:commandLink>
   <h:commandLink action="#{navigationController.showPage}" value="Page2">
      <f:param name="pageId" value="2" />
   </h:commandLink>
   <h:commandLink action="#{navigationController.showPage}" value="Home">
      <f:param name="pageId" value="3" />
   </h:commandLink>
</h:form>
Look at following code in a managed bean.
public String processPage1(){
   return "page";
}
public String processPage2(){
   return "page";
}
To resolve views, define following navigation rule in faces-config.xml
<navigation-rule>
   <from-view-id>home.xhtml</from-view-id>
   <navigation-case>
      <from-action>#{navigationController.processPage1}</from-action>
      <from-outcome>page</from-outcome>
      <to-view-id>page1.jsf</to-view-id>
   </navigation-case>
   <navigation-case>
      <from-action>#{navigationController.processPage2}</from-action>
      <from-outcome>page</from-outcome>
      <to-view-id>page2.jsf</to-view-id>
   </navigation-case>
</navigation-rule>
<h:form>
   <h3>Forward</h3>
   <h:commandButton action="page1" value="Page1" />   url в браузер не изменяется.
   <h3>Redirect</h3>
   <h:commandButton action="page1?faces-redirect=true" value="Page1" /> url меняется
</h:form>
<html 
   xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:h="http://java.sun.com/jsf/html" 
> подключение тего JSF в XHTML файле.