вторник, 8 января 2013 г.

Code style and code conventions

     Code conventions is a must-have part for all developers projects. If you want to keep a high standard of quality in the code you should write with common convention. I guess all real open source projects follow some convention, and it's right way.
     It’s not a secret that long term-value of software is in direct proportion to the quality of the codebase. During the lifetime of the program, it probably will be modified many times. If application has a clearly understandable structure, it's less likely that it will be broken with changes. Also it can help in reducing the brittleness of programs.
     Each project should have its own code/style conventions or follow the already written and all know rules.        
     And if you asking yourself about conventions, you must understand that it makes it easier to follow by the people who inherit it after you. Sometimes happens when code is really difficult to understand, then you should try and clean up the code to make it more readable.
     Often happens that the code does not follow good conventions, so it's hard to follow the precedent, but one of the main goals of a code style is consistency. Of course if you spend many hours to understand what a method does because it uses poorly named variables or something else, you should refactor as appropriate for the situation. But you should remember, if you introduce a different style into the code that is already consistent you lose that consistency.
    This is an example in general form, a set of coding conventions and rules for use in Java and GWT programming. So, this document describes how developers should write code. The reasoning of these styles and conventions is mainly for consistency, readability and maintainability reasons. All working file should represent the following conventions.

пятница, 4 января 2013 г.

Logging in GWT

1) Client logging
     Логирование в GWT эмулирует пакет java.util.logging, по этому он использует тот же синтаксис и имеет такое же поведение как на серверной стороне. Это позволяет обмениваться данными логирования между клиентом и сервером. Конфигурирование происходит через основной файл <gwt_app>.gwt.xml. В нем можно настраивать уровень протоколирования, включать/отключать различные обработчики, добавлять динамическое включение/отключения ведение логов и т.д. 
     GWT предоставляет множество обработчиков по умолчанию, которые будут вести записи через регистрацию. 
- SystemLogHandler - сообщения видны только в режиме разработки в окне development mode 
- DevelopmentModeLogHandler - логи вызываются через метод GWT.log(), сообщения выводятся только в devmode режиме в окне devmode. 
- ConsoleLogHandler - запись ведется в javascript консоль 
- FirebugLogHandler - логи выводятся в firebug консоль 
- PopupLogHandler - информация о логировании записывается в полупрозрачное окно, которое по умолчанию появляется в левом верхнем углу приложения. Окно можно изменять в размерах и минимизировать. 
 - SimpleRemoteLogHandler - обработчик отправляет сообщения на сервер, где они будут обработаны через механизм логирования на серверной стороне. 
     Для ведения логов на клиентской стороне достаточно указать, что мы хотим использовать логирование, включить подходящий обработчик в главный файл приложения и можно вызывать различные методы класса Logger
     GWT логирование хорошо документировано, поэтому за дополнительной информацией следует обращаться к первоисточнику. 
2) Dynamic client-side logging
     Рассмотрим реализацию динамического логирования, который позволяет легко управлять процессом в рантайме.
     Добавим поддержку логирования и установим уровень в файл модуля приложения <gwt_app>.gwt.xml.
 <!-- Add logging support -->
 <inherits name="com.google.gwt.logging.Logging" />
 <set-property name="gwt.logging.logLevel" value="INFO" />

* This source code was highlighted with Source Code Highlighter.
   Новое свойство модуля dynamicLogging сделает возможным включать и отключать логирование в зависимости от входного параметра logging. Если в url-е будет присутствовать параметр ?logging=some_value, то логирование будет включено несмотря на значение.
 <!-- Logging output depends on input query string parameter [logging] -->
 <define-property name="dynamicLogging" values="TRUE, FALSE" />
 <property-provider name="dynamicLogging">
     <![CDATA[
         if (window.location.href.indexOf("logging") != -1) {
             return "TRUE";
         }

         return "FALSE";
     ]]>
 </property-provider>


* This source code was highlighted with Source Code Highlighter.
     Также можно написать переключатель таким образом, чтобы логирование зависело от значения параметра logging. Если true - включено, во всех остальных случаях вывод будет отключен.
 <!-- Logging output depends on input query string parameter [logging] -->
 <define-property name="dynamicLogging" values="TRUE, FALSE" />
 <property-provider name="dynamicLogging">
     <![CDATA[
         function equals(name) {
            name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
            var regexS = "[\\?&]" + name + "=([^&#]*)";
            var regex = new RegExp(regexS);
            var results = regex.exec(window.location.href);
            if (results == null)
                return "";
            else
                return results[1];
        }

         if (window.location.href.indexOf("logging") != -1) {
             if (equals("logging").toLowerCase() == "true") {
                 return "TRUE";
             }
         }

         return "FALSE";
     ]]>
 </property-provider>


* This source code was highlighted with Source Code Highlighter.
     Переопределенное свойство gwt.logging.enabled зависит от значения dynamicLogging.
 <set-property name="gwt.logging.enabled" value="FALSE">
     <!-- disable logging -->
     <when-property-is name="dynamicLogging" value="FALSE" />
 </set-property>


* This source code was highlighted with Source Code Highlighter.
     Теперь логированием можно управлять простым добавлением параметра в url http://127.0.0.1:8888/GwtLoggingApp.html?gwt.codesvr=127.0.0.1:9997?logging=true или ?logging=false.
...
private static final Logger logger = Logger.getLogger(GwtLoggingApp.class.getName());
logger.log(Level.INFO, e.getMessage());
...


* This source code was highlighted with Source Code Highlighter.
3) Remote logging
     Включения логирования на сервере осуществляется также просто. Добавим модуль logging в проект и обработчик, отвечающий за ведение логов на сервере.
 <inherits name="com.google.gwt.logging.Logging" />
 <set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED"/>


* This source code was highlighted with Source Code Highlighter.
В файле web.xml необходимо определить удаленный сервлет логирования.
 <servlet>
    <servlet-name>remoteLoggingServlet</servlet-name>
    <servlet-class>com.google.gwt.logging.server.RemoteLoggingServiceImpl</servlet-class>
 </servlet>

 <servlet-mapping>
    <servlet-name>remoteLoggingServlet</servlet-name>
    <url-pattern>/gwtloggingapp/remote_logging</url-pattern>
 </servlet-mapping>


* This source code was highlighted with Source Code Highlighter.
4) Stack traces logging exception 
     Знания о выброшенном исключении обычно не очень полезно, если вы не знаете точно, где оно произошло. При компилировании Java кода в Javascript, он уменьшается и обфусцируется. Безусловно, это очень полезно для производительности и безопасности, но с точки зрения поддержки приложения, определенные вещи тяжелее реализовать. Если взглянуть на обфусцированный код, то вместо привычных имен классов и методов можно увидеть приблизительно следующее: Unknown.Qs(Unknown source), что не очень полезно. 
    К счастью, существуют разные варианты того, как GWT компилируется в Javascript, который предоставляет различные объемы информации для отладки. Но придется заплатить безопасностью и производительностью. Для красивого и чистого Javascript кода, который будет напоминать Java код, и предоставлять понятный stack trace, можно установить флаг -style в PRETTY(код станет читабельным) или DETAILED(еще более читабельный код + подробные имена переменных). По умолчанию флаг style установлен в режим OBF(обфускация). Это сделано для защиты интеллектуальной собственности разработанного приложения, для уменьшения размеров Javascript файлов, что делает их быстрее для загрузки и обработки. 
     Но есть компромисс позволяющий сохранять имена файлов и номера строк в stack trace и одновременно обфусцировать весь код приложения. При этом величина Javascript кода будет увеличена. Необходимо добавить следующие строки в файл *.gwt.xml:
 <set-property name="compiler.stackMode" value="emulated" />
 <set-configuration-property name="compiler.emulatedStack.recordLineNumbers" value="true"/> 
 <set-configuration-property name="compiler.emulatedStack.recordFileNames" value="true"/>


* This source code was highlighted with Source Code Highlighter.

четверг, 3 января 2013 г.

Exception handling in GWT

1) Global exception handling
     При разработке GWT приложения временами происходят непонятные вещи, и вы понятия не мееете, почему такое происходит. Вы можете тратить часы напролет в дебаге пытаясь найти критическую область, что часто зависит от многих факторов. Наверное, многие сталкивались с такой ситуацией, когда в режиме разработки(development mode) работает все отлично, но не после того, как все скомпилируется, соберется и разверернется на сервере. И это почти неизбежно, но если вы вооружены несколькими простыми приемами, то можно сэкономить много времени.
     Хорошим местом для добавления глобального обработчика исключений будет EntryPoint класс. Он позволит на клиентской стороне перехватывать все выброшенные исключения. Давайте зарегистрируем UncaughtExceptionHandler.
public void onModuleLoad() {
  GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
    @Override
    public void onUncaughtException(Throwable e) {
      // some exception handling logic
    }
  });
  // module loading...
}


* This source code was highlighted with Source Code Highlighter.
     Что произойдет, если не добавить UncaughtExceptionHandler в приложение? В режиме отладки(hosted mode), по умолчанию обработчик будет логировать исключения и выводить на консоль. В веб-режиме(web mode) обработчик является null и исключения будут выводиться в браузер, что не очень дружественно к пользователю.
     Также не стоит забывать, что UncaughtExceptionHandler начнет работать только после того, как отработает onModuleLoad() метод. Другими словами, если произойдет исключение во время загрузки модуля, то пользовательский обработчки событий еще не успеет проинициализироваться и это исключение не будет обработано. Это известная проблема, у которой, пока что нет решения, но есть небольшой обходной путь. Если вы ожидаете, что при выполнении метода onModuleLoad() может быть выброшено исключение, то можно извлечь содержимое метода в другой метод onModuleLoad2() и вызвать его используя Scheduler.
public void onModuleLoad() {
  GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
    @Override
    public void onUncaughtException(Throwable e) {
      // some exception handling logic
    }
  });
  
  Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
    @Override
    public void execute() {
      onModuleLoad2();
    }
  });

  private void onModuleLoad2() {
    // module loading logic
  }
}


* This source code was highlighted with Source Code Highlighter.
2) UmbrellaException
     Иногда работая с GWT мы получаем UmbrellaException исключение:
com.google.gwt.event.shared.UmbrellaException: One or more exceptions caught, see full set in UmbrellaException#getCauses
  at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:129)
  at com.google.gwt.user.client.ui.Widget.fireEvent(Widget.java:129)
  at com.google.gwt.event.dom.client.DomEvent.fireNativeEvent(DomEvent.java:116)
  at com.google.gwt.user.client.ui.Widget.onBrowserEvent(Widget.java:177)
  at com.google.gwt.user.client.DOM.dispatchEventImpl(DOM.java:1351)
  at com.google.gwt.user.client.DOM.dispatchEvent(DOM.java:1307)
  at sun.reflect.GeneratedMethodAccessor57.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  …


* This source code was highlighted with Source Code Highlighter.
    Он появился в GWT 2.1.1, вот что про него написано в документации:
A RuntimeException that collects a Set of child Throwables together. Typically thrown after loop, with all of the exceptions thrown during that loop, but delayed so that the loop finishes executing.

* This source code was highlighted with Source Code Highlighter.
     Класс UmbrellaException наследует RuntimeException и является простым набором исключений(Throwable на самом деле). Название скорее всего происходит от слова “зонтик”, обозначающее объект, которые охватывает различные вещи. В текущем случае, это исключение, которое охватывает множество других исключений.
     Для упрощения отладки и более точной обработки ошибок бывает очень полезно развернуть выброшеные исключения.
GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
  @Override
  public void onUncaughtException(Throwable e) {
    verifyNotUmbrellaException(e);
  }
});

private void verifyNotUmbrellaException(Throwable e) {
  for (Throwable th : ((UmbrellaException) e).getCauses()) {
    if (th instanceof UmbrellaException) {
      verifyNotUmbrellaException(th);
    } else {
      th.printStackTrace();
    }
  }
}


* This source code was highlighted with Source Code Highlighter.