суббота, 21 июля 2012 г.

Клиент Spring ws 2.1.0 + http components 4.2.1

В данном заметке я напишу о том, как мне удалось заставить работать связку из Spring ws 2.1.0 и http components 4.2.1.

Итак, начну с конфига:

    <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">  
   <property name="messageSenders"> 
      <list> 
       <ref bean="httpSender" /> 
      </list> 
     </property>
 </bean>

 <!-- http sender configuration -->
 <bean id="httpSender" class="org.springframework.ws.transport.http.HttpComponentsMessageSender"> 
    <constructor-arg> 
     <ref bean="httpClient"/> 
    </constructor-arg> 
   </bean>   
  <!-- http client definition -->
   <bean id="httpClient" class="ru.chernykh.MyDefaultHttpClient">
   <constructor-arg>
    <ref bean="connmanager"/>
   </constructor-arg> 
    <property name="params" ref="httpParams" />
   </bean>
 <!-- http params definition -->
   <bean id="httpParams" class="org.apache.http.params.SyncBasicHttpParams"/>

   <!-- setup thread-safe connection manager -->
   <bean id="connmanager" class="org.apache.http.impl.conn.PoolingClientConnectionManager" destroy-method="shutdown">
    <property name="maxTotal" value="100"></property>
    <property name="defaultMaxPerRoute" value="100"></property>
   </bean>  
   <!--  connection manager params  --> 
  <bean id="connParams" class="org.apache.http.params.HttpConnectionParamBean">
   <constructor-arg>
    <ref bean="httpParams"/>
   </constructor-arg>
    <property name="soTimeout" value="10000"></property>
  </bean>
  
Здесь всё стандартно за исключением бина httpClient. По умолчанию, если мы будем использовать DefaultHttpClient, то получим ошибку исполнения:
"Content-Length header already present".  Это означает, что httpclient пытается поставить заголовок в надежде что его нет, но это не так, поэтому получаем исключение.

Класс ru.chernykh.MyDefaultHttpClient выглядит так:
public class MyDefaultHttpClient extends DefaultHttpClient{

    protected BasicHttpProcessor createHttpProcessor() {
        BasicHttpProcessor processor = super.createHttpProcessor();
        processor.addInterceptor(new RemoveHttpHeadersInterceptor(), 0);
        return processor;
    }

    public MyDefaultHttpClient(org.apache.http.impl.conn.PoolingClientConnectionManager connManager){
        super(connManager);
    }
}
А класс RemoveHttpHeadersInterceptor следующим образом:
public class RemoveHttpHeadersInterceptor implements HttpRequestInterceptor{

    public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
        if (request instanceof HttpEntityEnclosingRequest) {
            if (request.containsHeader(HTTP.TRANSFER_ENCODING)) {
                request.removeHeaders(HTTP.TRANSFER_ENCODING);
            }
            if (request.containsHeader(HTTP.CONTENT_LEN)) {
                request.removeHeaders(HTTP.CONTENT_LEN);
            }
        }
    }
}
После этого, клиент заработал, и ошибок не было.

Хочу обратить внимание, что по умолчанию в классе
org.springframework.ws.transport.http.HttpComponentsMessageSender используется deprecated API http components(рекомендую взглянуть в исходниках). Поэтому лучше потратить время на ручную установку параметров httpClient, как это сделал я.

понедельник, 16 июля 2012 г.

Linux mint 13 & медленный wi-fi

Итак, после непродолжительной работы по wi-fi скорость соединения резко падает, хотя очевидных причин к этому нет. В моём случае проблема оказалась решаема не на клиенте, а на маршрутизаторе: в настройках необходимо изменить скорость соединения wi-fi с auto на 54 мбит\с. После этого скорость соединения wi-fi возрасла к прежним значениям.

Клиент Spring WS 2.1.0 и HTTP components

В документации к Spring WS сказано: хотите использовать apache http client, тогда используйте класс CommonsHttpMessageSender и будет вам счастье. При этом вы ограничены использованием только Apache http client 3.1.

Теперь смотрим java doc и видим, что CommonsHttpMessageSender In favor of HttpComponentsMessageSender. При этом последний уже работает с http client 4.

Такое чувство, что меня надули...
С 4 версией я ещё не работал.

четверг, 12 июля 2012 г.

WRT54GL и IPTV

В этой заметке кратко опишу настройку IPTV для корректной работы на на маршрутизаторе LinkSys wrt54gl v1.1.

При написании статьи руководствовался источниками:
  • http://www.tradetelecom.ru/home-office/podrobnaya-nastroyka-routera-linksys-wrt54gl-s-dd-wrt-i-wi-fi.php
  • http://www.dd-wrt.com/wiki/index.php/Switched_Ports
Этот роутер долго стоял с родной прошивкой. Однако недавно мне захотелось поставить у себя IPTV. Для этого я заказал у провайдера телевизионную приставку, подключил её к телевизору и роутеру.
После этих нехитрых действий wi-fi лёг. Проблема оказалась в том, что IPTV вещает по мультикасту. В результате этот трафик вещается на все порты LAN  и WI-FI моего маршрутизатора, что приводит к забиванию WI-FI канала. Какой из этого есть выход?

Можно заставить работать один LAN порт в режиме switcha с WAN. Стандартная прошивка этой возможности не поддерживает. В результате раздумий и поисков в интернете было принято решение поставить прошивку DD-WRT.

Процесс установки этой прошивки описан на сайте http://www.dd-wrt.com. После установки этой прошивки субъективно стал быстрее работать административный интерфейс роутера, а также повысилась скорость работы сети. Это всё мои личные наблюдения.

Теперь начинается самое интересное. Как вывести один порт LAN в режим свитча с WAN?

Подключаемся по telnet роутеру. Далее выполняем команды:
nvram set vlan0ports="1 2 3 5*"

nvram set vlan1ports="0 4 5"

nvram commit

reboot

т.е мы вывели порт 4 в одну сеть с WAN.
Осталось воткнуть кабель приставки в порт 4, и наслаждаться интернетом и телевидением. 



пятница, 6 июля 2012 г.

Пример клиента на Spring Web Service

Итак, вызов веб-сервиса выглядит следующим образом:

 /**  
  * Вызов веб-сервиса       
  * @param request  
  * @return  
  */  
      public String invove(String request){  
            StreamSource source = new StreamSource(new StringReader(request));  
            ByteArrayOutputStream output = new ByteArrayOutputStream();  
            StreamResult result = new StreamResult(output);  
            webServiceTemplate.sendSourceAndReceiveToResult(url, source, result);  
            String resultStr = "";  
            try {  
                resultStr = new String(output.toByteArray(), "UTF-8");  
           } catch (UnsupportMultiThreadedHttpConnectionManageredEncodingException e) {  
                logger.error(e.getMessage(), e);  
           }  
            return resultStr;   
      }  

В данном случае я отсылаю запрос в виде строки и принимаю обратно строку.

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



Всё просто, не правда ли?

Правда, если мы хотим выставить таймаут на ожидание выполнения запроса, то необходимо в проект добавить библиотеку http commons 3.1.1 и изменить определение бина следующим образом:

 <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">    
   <property name="messageSenders">   
    <list>   
     <ref bean="httpSender" />   
    </list>   
    </property>   
  </bean>   
  <!-- add for thread safety -->   
  <bean id="connmanager" class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager">  
       <property name="params" ref="connmanagerParams"/>  
  </bean>  
  <!-- Total to 300 connections -->  
  <bean id="connmanagerParams" class="org.apache.commons.httpclient.params.HttpConnectionManagerParams">  
   <property name="maxTotalConnections" value="300"/>  
 </bean>  
   <bean id="httpParams" class="org.apache.commons.httpclient.params.HttpClientParams">   
   <!-- Timeout in milliseconds: in this case 10 seconds -->   
   <property name="soTimeout" value="10000" />    
   </bean>   
   <bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">   
   <property name="params" ref="httpParams" />  
   <property name="httpConnectionManager" ref="connmanager"/>   
   </bean>   
   <bean id="httpSender" class="org.springframework.ws.transport.http.CommonsHttpMessageSender">   
   <constructor-arg>   
    <ref bean="httpClient"/>   
   </constructor-arg>   
   </bean>    

Счастливой пятницы!

UPD 2012-07-14: Наткнулся на проблему, что по умолчанию
org.apache.commons.httpclient.HttpClient
не безопасен для использования в многопоточной среде. Чтобы это исправить, необходимо HttpClient передатьэкземпляр
MultiThreadedHttpConnectionManager
После этого Commons Http должен работать корректно в заданной конфигурации.

среда, 4 июля 2012 г.

Мысли о фреймворках java

Выдалось время подумать о том, как можно улучшить написание богатых приложений, работающих в браузере. Сразу приходит в голову множество разных фреймворков:
  • jsf/myfaces + facelets
  • struts
  • jsp+servlet+jstl, возможно tiles
  • gwt
  • apache click
  • apache wicket
  • spring mvc
От такого количества библиотек голова идёт кругом.
Первое с чего начинают разработчики это jsp + sertvlet + jstl. Это сравни ассемблеру. Идея хорошая. Реализация простая и надёжная. Однако богатые приложения на такой связке быстро не создашь.

Struts в этом плане лучше. Есть поддержка валидации, описание правил перехода по страницам. Богатые приложения на такой связке быстро не создашь.

JSF. Пожалуй, единственным плюсом данного каркаса является то, что он входит в J2EE с версии 5. Эта библиотека максимум для чего подходит - быстрое прототипирование приложений. Кроме того, если разработчику дали вёрстку и сказали использовать её в JSF приложении, то это будет геморрой. А если потом эту jsf страничку понадобится модифицировать верстальщику, то верстальщик в этих jsf компонентах ничего не поймёт.
Существует большое количество jsf библиотек. Каждая со своими глюками и компонентами. Поэтому, кроме головной боли, эта библиотека в продуктивных системах ничего более не принесёт.

Gwt. Приложения, которые создаются на этой библиотеке поистине богаты.

Apache click. Утверждается, что это отличная библиотека для богатых приложений, не занимающихся работой с хранением состояния.

Apache wicket. Это библиотека ориентирована на создание богатых приложений, которые часто и много имеют дело с хранением состояния приложения. Как утверждается на сайте библиотеки, в ней решена проблема кнопки Back в браузерах. Пожалуй, стоит уделить немного внимания данной библиотеке.

Spring mvc. Эта библиотека сделана разработчиками spring. Сам я дела с ней не имел и отзывов никаких не слышал. Поэтому упомянул её здесь для галочки.

Spring web services. Java doc.

Недавно я начал разбираться с новой для себя библиотекой - Spring Web Services. Скачал версию 2.1.0.

Оказалось, что эта версия не работает со Spring 2.5. Из недостатков дистрибутива можно отметить отсутствие javadoc. Однако после поисков мне удалось найти архив с javadoc по пути: http://repo1.maven.org/maven2/org/springframework/ws/spring-ws-core/2.1.0.RELEASE/spring-ws-core-2.1.0.RELEASE-javadoc.jar.

Также к недостатку можно отнести то, что при определённых условиях spring ws зависит от http client 3.1.1. Хотя http client уже давно имеет более свежую версию. Для меня было открытием, что spring ws не имеет встроенной возможности установить таймаут на ожидание обработки запроса в веб-сервис. Именно поэтому используется http client.

Что касается написания клиента, то здесь  Spring ws  предоставляет гибкие возможности. Например, можно посылать xml запросы в виде строк напрямую в сервис, а можно заставить spring ws самому заниматься преобразованием объектов в запросы и обратно. Мне, к сожалению, пришлось выбрать вариант работы с xml через строки, так как веб-сервис, с которым приходится работать, плохо документирован и определён. Поэтому часто приходится делать доработки клиента.

Подписывание xml также происходит довольно легко и быстро. Не надо тратить время на написание кода - всё можно сделать через файл конфигурации Spring. Пример постараюсь выложить позже.

Несмотря на то, что новичкам будет непросто сходу разобраться в этой библиотеке, я бы рекомендовал потратить время на её освоение.