суббота, 22 сентября 2012 г.

Установка приложений на Tomcat с помощью ant.

При разработке приложения для работы на Tomcat очень удобной возможностью является установка приложения на Tomcat с помошью скрипта ant.
Удобство заключается в небольшом количестве действий, которое необходимо для установки приложения.
Установку можно выполнить на любой сервер, локальный или удалённый.

Почитать об этом можно в руководстве на Tomcat, но для удобства опишу основные моменты здесь:

1) Необходимо скопировать файл server/lib/catalina-ant.jar из Tomcat в каталог с библиотеками ant ($ANT_HOME/lib).
2) В Tomcat прописать учётную запись для пользователя manager-script.
3) В ant скрипте необходимо объявить задачи tomcat и параметры установки приложения:
<!-- Configure the directory into which the web application is built -->
    <property name="build"    value="dist"/>
    <!-- Configure the context path for this application -->
      <property name="path"     value="/test"/>

      <!-- Configure properties to access the Manager application -->
      <property name="url"      value="http://localhost:8080/manager"/>
      <property name="username" value="duglas"/>
      <property name="password" value="password"/>

      <!-- Configure the custom Ant tasks for the Manager application -->
      <taskdef name="deploy"    classname="org.apache.catalina.ant.DeployTask" />
      <taskdef name="undeploy"  classname="org.apache.catalina.ant.UndeployTask"/>

   
<target name="deploy" description="Install web application"
              depends="war">
        <deploy url="${url}" username="${username}" password="${password}"
                path="${path}" war="file:${build}/springwstest.war"/>
      </target>

  <target name="undeploy" description="Remove web application">
        <undeploy url="${url}" username="${username}" password="${password}"
                path="${path}"/>
      </target>

4) После этого можно вызывать нужную цель, и приложение будет установлено на сервере. Вызов цели undeploy влечёт за собой удаление приложение на сервере.

Spring Web Services. Тестирование клиента к веб-сервису.

Автономное тестирование клиента к веб-сервису без самого сервиса позволяет получить уверенность в том, что клиент работает как в стандартных ситуациях, так и не очень.
К стандартным ситуациям следует отнести ситуацию, когда сервис выдаёт ожидаемый ответ.
К нестандартным ситуациям следуюет отнести ситацию, когда сервис выдает исключение.

В нашем распоряжении есть следующее ПО:
  1. jUnit 4.10
  2. Spring WS 2.1.0 
  3. Eclipse
Рассмотрим следующий пример сервиса. На вход принимается две строки, на выходе выдаётся их склейка. Для тестирования клиента используется класс MockWebServiceServer. Перед вызовом клиента нам необходимо установить последовательность пар вызовов и ответов веб-сервиса.

Это осуществляется в строке: mockServer.expect(RequestMatchers.payload(expectedRequestPayload)).andRespond(ResponseCreators.withPayload(responsePayload)); 

Далее мы осуществляем вызов нашего клиента к веб-сервису, и в конце теста
вызываем метод mockServer.verify(). Этот метод проверяет, что веб-сервис получил все ожидаемые запросы от клиента. Если какие-то запросы не пришли, то unit тест не пройдёт.

За более подробным описанием предлагаю обратиться к описанию класса MockWebServiceServer.
Также можно прогнать пример ниже.

 @RunWith(SpringJUnit4ClassRunner.class)  
 @ContextConfiguration("/context.xml")  
 public class MyWebServiceClientIntegrationTest {  
   @Resource(name="webServiceTemplate")  
   org.springframework.ws.client.core.WebServiceTemplate webServiceTemplate;  
   private MockWebServiceServer mockServer;  
   @Before  
   public void createServer() throws Exception {  
     mockServer = MockWebServiceServer.createServer(webServiceTemplate);  
   }  
   @Test  
   public void testExpected() throws Exception {  
     String request = "<ConcatRequest xmlns=\"http://www.chernykh.ru/myfirst\">"+  
         "<p1>1</p1>"+  
         "<p2>2</p2>"+  
         "</ConcatRequest>";  
     String request2 = "<ConcatRequest xmlns=\"http://www.chernykh.ru/myfirst\">"+  
         "<p1>1</p1>"+  
         "<p2>2</p2>"+  
         "</ConcatRequest>";  
     String response = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ConcatResponse xmlns=\"http://www.chernykh.ru/myfirst\"><out>12</out></ConcatResponse>";  
     Source expectedRequestPayload =  
         new StringSource(request);  
     Source responsePayload = new StringSource(response);  
     mockServer.expect(RequestMatchers.payload(expectedRequestPayload)).andRespond(ResponseCreators.withPayload(responsePayload));  
     ByteArrayOutputStream output = new ByteArrayOutputStream();   
     StreamResult result = new StreamResult(output);  
     String uri = "http://localhost:8080/test/service";  
     webServiceTemplate.sendSourceAndReceiveToResult(uri,new StringSource(request2), result);  
     String resultStr = "";   
     resultStr = new String(output.toByteArray(), UTF_8.utf8);  
     mockServer.verify();  
     System.out.println("Finished:"+resultStr);  
   }  
 }  

вторник, 18 сентября 2012 г.

Spring + MongoDB + Eclipse. Проблема с spring-mongo-1.0.xsd.


При использовани Spring + Mongo в Eclipse последний ругается на файл с бинами Spring.

<beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context"
          xmlns:mongo="http://www.springframework.org/schema/data/mongo"
          xsi:schemaLocation=
          "http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context-3.0.xsd
          http://www.springframework.org/schema/data/mongo
          http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

Детальная ошибка говорит: "Cannot resolve the name 'repository:repository' to a(n) 'type definition' component" вspring-mongo-1.0.xsd.

Решение нашёл в замечательной заметке: http://stackoverflow.com/questions/11684673/spring-mongo-1-0-xsd-error.

Нужно изменить   http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd на
  http://www.springframework.org/schema/data/mongo/spring-mongo-1.1.xsd. После этого eclipse перестанет ругаться на проект.

воскресенье, 9 сентября 2012 г.

Spring + MongoDb. Первое знакомство.

В одном из моих проектов мне понадобилось использовать mongodb в качестве хранилища данных сессии пользователя.

Для работы на java с mongodb можно использовать java драйвер. Это довольно утомительное занятие. Поэтому я нашёл интересный проект spring-data-mongodb, который позволяет упростить работу с mongodb.

суббота, 8 сентября 2012 г.

Spring ws 2.1.0 и Http components 4.2.1. Обработка исключений.

При создании клиентов к веб-сервисам с помощью Spring Web Services и Http components возникает вопрос - как обрабатывать исключения?

Речь идёт об исключениях, которые возникают при установке socket timeout или connection timeout в классе org.apache.http.params.SyncBasicHttpParams. 

При исполнении метода     template.sendSourceAndReceiveToResult(uri, source,result ); может возникнуть исключение, однако сигнатура данного метода не содержит исключений.

Поэтому для корректной работы приложения можно просто обернуть этот метод в try catch конструкцию, таким образом вызов клиента будет выглядить следующим образом:

try{
       template.sendSourceAndReceiveToResult(uri, source,result );
}catch (IOException ex){
     //делаем необходимую обработку исключения
}

Второй вариант, это добавить throws IOException в объявление метода, который использует вызов клиента к веб-сервису.


Кодировки и класс Charset

Иногда приходится работать с кодировками, в частности, преобразовывать бинарные данные в строковые. Для этого можно использовать класс Charset.

Можно было подумать, что в JVM есть удобные константы для кодировки UTF-8, но вместо этого предлагается использовать Charset.forName(). Плохо, что этот метод выкидывает 3 исключения. В java версии 7 нам дают в распоряжение новый класс StandardCharsets. Данный класс предлагает ряд кодировок, которые ГАРАНТИРОВАННО поддерживаются на каждой реализации JVM. Данный класс имеет static Charset UTF_8.  

В принципе никто не мешает написать такой класс самому.
Расстраивает одно, почему такой вспомогательный класс появился только в 7 версии машины? 

воскресенье, 2 сентября 2012 г.

Сравнение Apache CXF и Spring WS

-->
Попробуем сравнить 2 известных фреймворка для написания веб-сервисов и клиентов к ним.
К этим фреймворкам относятся: Spring Web Services, Apache CXF.

Проект Apache CXF активно развивается, в то время как Spring WS представляет собой законченное решение. Архитектура Spring WS довольно простая, что при желании позволит разобраться в её исходном коде и поправить замеченные ошибки.
Я знаком с обоими фреймворками, но испробовал не все их возможности. Сравнение представлено в таблице ниже и представляет собой попытку свести информацию в табличный вид.
По итогам сравнения можно сказать следующее:
  1. Apache CXF обладает большим количеством возможностей по сравнению с Spring WS.
  2. В проекте, когда интерфейс WSDL довольно часто меняется, то проще использовать Spring WS.
  3. Обе библиотеки довольно просты в освоении, однако с CXF много времени можно потратить на настройке.
  4. Следует отметить, что с обоими библиотеками поставляется набор примеров.
  5. Выбор в пользу той или иной библиотеки необходимо делать исходя из требований к проекту, а также исходя из приверженности работы по стандарту JAX-WS.



Spring WS
Apache CXF
Поддержка разработки типов сервисов
сверху-вниз
сверху-вниз, снизу-вверх.
Обработка входящих сообщений
DOM, SAX, StAX, JDOMs, dom4j, XOM, JAXB, Castor, Apache XMLBeans, XStream. Определение обработчика входящего XML запроса на основе запроса, заголовка SOAP Action или Xpath выражения.
DOM, SAX, StAX, InputStream, JAXB 2.x, Aegis, Apache XMLBeans, Service Data Objects (SDO), JiBX.
Поддержка спецификаций
WS-Security, WS-Addressing.
Интеграция с Acegi Security.
JAX-WS, JAX-RS, WS-Basic Profile, WS-Addressing, WS-Policy, WS-Reliable Messaging, WS-Security, WS-SecurityPolicy, WS-SecureConversation, WS-Trust (partial support).
Поддержка транспорта
JMS, Email, XMPP, HTTP, Embedded HTTP.
HTTP, Servlet, JMS, In-VM and many others via the Camel transport for CXF such as SMTP/POP3, TCP and Jabber.
Документация
Неплохая, есть tutorial.
Простота в использовании.
Крайне разрозненная. Трудно понять с чего стоит начинать, и где найти нужную информацию.
Наличие инструментов
Отсутствует.
  • генераторы кода WSDL to Java, WSDL to JavaScript, Java to JavaScript,
  • генераторы WSDL Java to WSDL, XSD to WSDL, IDL to WSDL, WSDL to XML
  • проверка WSDL.
Версионность сервисов
Через XSLT преобразование запроса. Возможность быстрого внесения изменений в интерфейс сервиса, что полезно при изменяющемся контракте.
Написание собственного перехватчика (http://cxf.apache.org/docs/service-routing.html).
Клиенты
Простой синхронный клиент, интеграция с http client.
Возможность создания клиента на javascript, асинхронного клиента.
Отказоустойчивость
Необходимо придумывать самому.
Возможность создания клиентов, использующих возможность работы с другим сервисом в случае отказа сервера.
Управление
Отсутствует
Поддержка JMX.
Тестирование сервисов
Поддержка для тестирования клиентов и сервисов.
Необходимо писать самому. Можно использовать локальный или in-VM транспорт.
Интеграция с IDE
Отсутствует.
Интеграция с Eclipse.