Поиск по этому блогу

воскресенье, 19 октября 2014 г.

Вопросы на собеседовании Java программиста. Java Runnable vs Callable

Очень интересный и популярный вопрос на собеседованиях. Чем отличаются два интерфейса для реализации задач Runnable и Callable.

Основные различия



  1. Интерфейс Runnable появиля в Java 1.0, а интерфейс Callable был введен в Java 5.0 в составе библиотеки java.util.concurrent.
  2. Классы, реализующие  интерфейс Runnable должны реализовывать метод run() для выполнения задачи. Классы, реализующие интерфейс Callable должны реализовывать метод call() для выполнения задачи.
  3. Метод Runnable.run() не возвращает никакого значения, его тип void, а метод Callable.call() может возвращать значение типа T. Интерфейс Callable является параметризированным  Callable<T> и тип значения, которое будет возвращаться в методе call() задается этим параметром T. 
  4. Метод run() не может бросить проверяемое исключение, в то время как метод call() может бросить проверяемое исключение.


Пример реализации интерфейсов Runnable и Callable


import java.util.concurrent.Callable;
 
public class RunVsCalEx {
 
 public static void main(String[] args) throws Exception {
  Runnable callback1 = new Runnable() {
 
   @Override
   public void run() {
   }
  }; 
  process(callback1);
 
  Callable<String> callback2 = new Callable<String>() {
 
   @Override
   public String call() throws Exception {
    String str = "String from callback";
    return str;
   }
  };  
  processString(callback2);
 }
 
 private static void process(Runnable callback) {
  for (int i = 0; i <= 100; i++) {
   if (i == 100) {
    callback.run();
   }
  }
 }
 
 private static void processString(Callable<String> callback) 
   throws Exception {
  for (int i = 0; i <= 100; i++) {
   if (i == 100) {
    callback.call();
   }
  }
 }
 
}

Источники


http://java67.blogspot.ru/2013/01/difference-between-callable-and-runnable-java.html
http://stackoverflow.com/questions/141284/the-difference-between-the-runnable-and-callable-interfaces-in-java
http://pro-java.ru/java-dlya-opytnyx/interfejsy-callable-i-future-v-java/

вторник, 14 октября 2014 г.

How To Configure The Session Timeout (Java web.xml )

Для того, чтобы настроить время сессии необходимо в файл web.xml добавить следующие строки.
<web-app ...>
 <session-config>
  <session-timeout>10</session-timeout>
 </session-config>
</web-app>

Значение указывается в минутах!!!

суббота, 11 октября 2014 г.

GWT TextBox Placeholder

В GWT у виджета TextBox нету поля placeholder. Поэтому чтобы его добавить необходимо выполнить следующие действия.

Допустим у нас имеется виджет TextBox описанный в uiBinder
<g:TextBox ui:field="emailField"></g:TextBox>

Соответствующее ему поле в Java классе
@UiField
TextBox emailField;

Для того чтобы задать placeholder этому виджету, получаем у него элемент и ему задаем атрибут placeholder.
emailField.getElement()
  .setAttribute("placeholder", "Gmail or Google-based email only");

GWT + Bootstrap Tooltips and Popovers. How to hide popover

Tooltip - всплывающая подсказка при наведении курсора мыши на элемент.
Popover - всплывающее окно, появляющееся при клике на элементе.

Официальная документация Bootstrap


Как работают Tooltips в Bootstrap

Как работают Popovers в Bootstrap

Пример работы с Tooltip и Popover


Для того, чтобы у элемента показывался tooltip достаточно написать ему атрибуты
<button type="button" 
  class="btn btn-default" 
  data-toggle="tooltip" 
  data-placement="left" 
  title="Tooltip on left">
  Tooltip on left
</button>

Эти атрибуты определяют следующее

  1. data-toogle = "tooltip" свойство задает что у элемента будет tooltip
  2. data-placement = "left" позиция, в которой будет показываться tooltip
  3. title = "Help text" текст, который будет показываться в tooltip

Теперь для того чтобы по наведению на элемент показывался tooltip необходимо написать код 
$('.btn').tooltip();

Теперь у всех элементов у которых прописан class="btn" и заданы атрибуты title, data-toogle, data-placement будет показываться tooltip при наведении курсора.

Для того, чтобы у элемента по клику показывался popover достаточно написать ему атрибуты
<button type="button" 
  class="btn btn-default" 
  data-container="body" 
  data-toggle="popover" 
  data-placement="top" 
  data-content="Lorem ipsum dolor sit amet, consectetur adipisicing elit.">
  Popover on top
</button>

Тут атрибуты немного поменялись
  1. data-toogle = "popover" теперь у элемента будет pover
  2. data-placement = "top" позиция для popver теперь будет top
  3. data-content = "Popover text" тут задается текст, который будет показываться в Popover

Точно также как и с tooltip для того чтобы popover показывался по клику необходимо написать код 
$('.btn').popover();

Теперь у всех элементов у которых прописан class="btn" и заданы атрибуты data-toogle, data-placement и data-content будет показываться popover при клике.

Как убрать Popover по клику в другом месте


Если с появлением и исчезанием tooltip все просто, он появляется и исчезает при наведении и убирании курсора соответственно. То с Popover ситуации поинтереснее, он появляется по клику на элементе и исчезает тоже по клику на элементе, но нам необходимо чтобы он убирался когда пользователь просто кликает в любое место на экране. Вот демонстрация как это сделать.

Демонстрация как убирать Popover

Вот код который убирает Popover при клике на любое место на экране. Здесь мы слушаем события клика по элементу body, в котором лежат все элементы интерфейса. Далее для всех элементов, у которых есть атрибут data-toggle="popover" мы проверяем условие и если условие выполняется, то убираем Popover.

$('body').on('click', function (e) {
    $('[data-toggle="popover"]').each(function () {
        if (!$(this).is(e.target) 
            && $(this).has(e.target).length === 0 
            && $('.popover').has(e.target).length === 0) {
               $(this).popover('hide');
        }
    });
});

GWT + Bootstrap Tooltips and Popovers


Теперь самое интересное - как соединить Bootstrap и GWT. Будем считать что библиотека Bootstrap.js уже подключена к нашему gwt проекту и поэтому мы можем писать нативный JavaScript код и вызывать методы для работы с Tooltip и Popover.  Допустим у нас есть элемент интерфейса, для которого мы хотим показывать tooltip или по клику на него показывать Popover.
Он может быть описан в uiBinder так
<span class="help-text" ui:field="learnMoreButton">Learn More</span>

или так (это для показа Tooltip)
<span ui:field="learnMoreButton"
      class=="has-tooltip-users" 
      title="learn Much More" 
      tooltipPlace="left">Learn More
</span>

В Java классе для него создано соответствующее поле.
@UiField
Element learnMoreButton;

Создадим специальный класс для работы с Tooltip и Popover. В нем мы напишем нативные методы для вызова Bootstrap методов.

Класс BootstrapUtilities  для работы с нативным JavaScript кодом


public class BootstrapUtilities {
 
 public static native void initializeTooltips(String className)/*-{
  $wnd.$('.' + className).tooltip('destroy');
  $wnd.$('.' + className).tooltip();
 }-*/;
 
 public static void initializeTooltip(Element element, 
            String position, String title) {
  element.setAttribute("data-toggle", "tooltip");
  element.setAttribute("data-placement", position);
  element.setAttribute("title", title);
  initializeTooltip(element);
 }
 
 public static native void initializeTooltip(Element element)/*-{
  $wnd.$(element).tooltip();
 }-*/;
 
 public static native void initializePopover(Element element)/*-{
  $wnd.$(element).popover();
 }-*/;
 
 public static void initializePopover(Element element, String position, 
   String content) {
  element.setAttribute("data-toggle", "popover");
  element.setAttribute("data-placement", position);
  element.setAttribute("data-content", content);
  initializePopover(element);
 };
 
 public static native void hidePopover(Element element)/*-{
  $wnd.$(element).popover('hide');
 }-*/;
 
}
 

Все что нам теперь осталось - это просто обратится к методам из класса BootstrapUtilities для того, чтобы показывать Tooltip или Popover.

Теперь для всех элементов у которых прописан class="has-tooltip-users" будет показываться tooltip.
BootstrapUtilities.initializeTooltips("has-tooltip-users");

Теперь по клику на элемент learnMoreButton будет показываться Popover.
BootstrapUtilities.initializePopover(learnMoreButton, "top", message);


Как в GWT убрать появившийся Popover


Для этого нам понадобится специальное поле типа Long, в котором мы будем хранить время, когда был произведен клик по элементу. 
private Long learnMoreClicked;

В момент клика по элементу мы будем запоминать время
learnMoreClicked = System.currentTimeMillis();

Далее при нажатии по свободному месту на экране мы будем отслеживать, что с момента клика по элементу, к которому привязан Popover прошло более 250 миллисекунд.
System.currentTimeMillis() - learnMoreClicked > 250

RootPanel - корневая панель, в которой содержаться все элементы интерфейса. Поэтому нужно слушать клики пользователя по этой панели, чтобы убирать Popover.

Вешаем слушателя событий на кнопку и тут же подписываем RootPanel на событие Click. Также запоминаем время клика.
Event.sinkEvents(learnMoreButton, Event.ONCLICK);
Event.setEventListener(learnMoreButton, new EventListener() {
 
    @Override
    public void onBrowserEvent(Event event) {
      RootPanel.get().sinkEvents(Event.ONCLICK);
      learnMoreClicked = System.currentTimeMillis();
    }
 
});

Вешаем слушателя событий на RootPanel и при выполнении условия, что с момента клика по элементу до момента клика по RootPanel прошло более 250 миллисекунд
убираем Popover и отписываем панель от слушания событий
RootPanel.get().addHandler(new ClickHandler() {
 
    @Override
    public void onClick(ClickEvent event) {
 if (learnMoreClicked != null 
          && System.currentTimeMillis() - learnMoreClicked > 250) {
         BootstrapUtilities.hidePopover(learnMoreButton);
  RootPanel.get().unsinkEvents(Event.ONCLICK);
 }
    }
}, ClickEvent.getType());

Убирается Popover c помощью метода hidePopover() из класса BootstrapUtilities
BootstrapUtilities.hidePopover(learnMoreButton);

public static native void hidePopover(Element element)/*-{
  $wnd.$(element).popover('hide');
 }-*/;

пятница, 10 октября 2014 г.

CSS hand cursor on hover

Для того чтобы при наведении на элемент курсор мышки превращался в указатель необходимо добавить для этого элемента следующий стиль.

li { cursor: pointer; }

Чтобы это гарантированно работало во всех браузерах можно написать так.

li { cursor: pointer; cursor: hand; }

CSS text-decoration Property

Свойство стиля text-decoration позволяет добавить к тексту выделения. Следующее выделение используется наиболее часто.

  1. text-decoration: overline; Линия над  текстом
  2. text-decoration: line-through; Текст перечеркивается
  3. text-decoration: underline; Текст подчеркивается

HTML + CSS

<!DOCTYPE html>
<html>
<head>
<style>
h1 {
    text-decoration: overline;
}
 
h2 {
    text-decoration: line-through;
}
 
h3 {
    text-decoration: underline;
}
</style>
</head>
<body>
 
<h1>This is heading 1</h1>
<h2>This is heading 2</h2>
<h3>This is heading 3</h3>
 
</body>
</html>

Результат



вторник, 9 сентября 2014 г.

Принципы разработки программного обеспечения


  1. Принцип минимального API. Заключается в том, чтобы не создавать новых сущностей, если можно обойтись существующими.
  2. Принцип разделения обязанностей (На примере шаблона Model View Presenter). Вся бизнес-логика приложения должна быть расположена в сервисах, а за отображение должны отвечать презентеры и виды (presenters and views). У отображения тоже есть логика, она должна находиться в перезентере, а в виде должен быть только код, который отвечает за внешний вид интерфейса.
Статья будет дополнятся!

понедельник, 14 июля 2014 г.

Guava. Filter Collections and Iterables

Guava - это библиотека, предоставляющая возможности функционального программирования.

Guava на Google Code

Guava на Wikipedia

Зависимость в POM.XML файле проекта (Если используем Maven для проекта)
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>${guavaVersion}</version>
</dependency>


Фильтруем List

Для фильтрации List'a следующие классы необходимо импортировать.
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;

Объявляем объект, реализующий интерфейс List.
private List<Document> displayList;

Фильтруем наш displayList. Создаем новый лист на основе исходного, но при этом в новый лист попадут только те элементы которые будут соответствовать условию, указанному в предикате. Например, тут в листе будут содержаться только не архивные документы.
displayList = Lists.newArrayList(
    Collections2.filter(displayList, new Predicate<Document>() { 
 
      @Override
      public boolean apply(Document document) {
        return !document.isArchived();
      }
    })
);
 
setupView(displayList);

Фильтруем Iterables

Для фильтрации Iterables следующие классы необходимо импортировать.
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

Создаем список реализующий интерфейс List, он будет содержать объекты класса SchemaItem.
private List<SchemaItem> attributeList;

Допустим у нас есть объект класса Schema, который содержит в себе объекты SchemaItem и реализует интерфейс Iterable.
public class Schema implements Iterable<SchemaItem>

Фильтрованный лист будет создан на основе объекта реализующего интерфейс Iterable и содержащего объекты класса SchemaItem. В него попадут только те элементы, которые будут соответствовать условию в предикате.
attributeList = Lists.newArrayList(
  Iterables.filter(result, new Predicate<SchemaItem>() { 
 
    @Override
    public boolean apply(SchemaItem si) {
      return (si.getSearchable());
    }
  ));
setupView(attributeList);

пятница, 11 июля 2014 г.

Становимся экспертами в GWT или GWT in Action

Очень познавательная книжка по технологии GWT. Подойдет для всех категорий читателей, как для тех, кто уже знаком с GWT и хочет разобраться поглубже, так и для тех, кто будет изучать GWT с нуля.

GWT in Action, Second Edition




GWT. Maven GWT Plugin commands


1. GWT Maven Plugin 

    http://mojo.codehaus.org/gwt-maven-plugin/

Этот плагин предназначен для запуска gwt проектов с помощью Maven.

<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>${gwtVersion}</version>

1. mvn gwt:eclipse создаст Launch файл для запуска проект из Eclipse

2. mvn gwt:run запустит проект на AppEngine

3. mvn gwt:debug запустит проект на AppEngine в debug mode



2. Appengine Maven Plugin 



Этот плагин предназначен для запуска с помощью Maven сервера AppEngine
   
<groupId>com.google.appengine</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>${appengine.target.version}</version>

1. mvn appengine:devserver эта команда запустит локальный dev сервер AppEngine 

2. mvn appengine:devserver -Plocal эта команда запустит локальный dev сервер AppEngine с профилем local, профиль local описывается в POM файле проекта.
<profiles>
  <profile>
    <id>local</id>
      <properties>
        <root.url>http:\/\/localhost:8888</root.url>
      </properties>
  </profile>
</profiles>

3. Профили и параметры Maven


1. mvn clean install -DskipTests  эта команда очистит папку target проекта, после чего скомпилирует файлы проекта и при этом пропустит выполнение тестов.

2. mvn clean install -DskipTests -Pdebugging -DgwtLogLevel=INFO для того, чтобы выполнилась такая команда необходимо добавить профиль в POM файл проекта для параметра Pdebugging, другие два параметра являются параметрами встроенными в Maven.
<profiles>
<profile>
  <id>debugging</id>
    <properties>
      // уровень логгирования
      <gwtLogLevel>TRACE</gwtLogLevel>
      // количество выделяемой памяти
      <gwtDebugJvm>-Xmx2048m -XX:MaxPermSize=2048m</gwtDebugJvm>
      // пропустить тесты
      <skipTests>true</skipTests>
    </properties>
  </profile>
<profile>
</profiles>

CSS. How to center div inside div

Для div элемента, который будет выравниваться по центру другого div элемента, необходимо прописать следующий стиль

margin: 0 auto;

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<body>
    <div style="width: 100%;">
     <div style="margin: 0 auto;">
      Test
     </div>
    </div>
</body>
</html>

Mac OS X Как открыть Android SDK manager

Для того, чтобы в Eclipse добавить в панель инструментов кнопки Android SDK и AVD необходимо нажать в меню Window > Customize perspective, после чего выбрать вкладку Command Groups Availability. Здесь необходимо поставить галочку  Android SDK and AVD Manager и нажать кнопку ОК

вторник, 1 июля 2014 г.

GWT. Programatically selecting text in a TextBox

Для того, чтобы по нажатию на компонент выделить текст, который в нем находится, необходимо написать следующий нативный метод. В качестве параметра передаем в метод тот элемент, в котором будем выделять текст.
private native void selectAll(Element element) /*-{
     element.setSelectionRange(0, element.value.length);
}-*/;

И использовать этот метод в обработчике события получения фокуса компонентом.
Event.sinkEvents(selector.getInputElement(), Event.ONFOCUS);
Event.setEventListener(selector.getInputElement(), 
  new EventListener() {
 
    @Override
    public void onBrowserEvent(Event event) {
      selectAll(selector.getInputElement());
    }
});

Но часто может происходить следующая ситуация - текст в компоненте будет выделяться после того как пользователь поставит курсор внутри компонента, однако после этого выделение будет слетать. Это происходит потому что выделение может быть установлено еще до того как выполнятся все события связанные с отрисовкой интерфейса. Поэтому необходимо использовать очередь событий и вызывать метод, который будет выделять текст только после того как все события интерфейса будут выполнены. Для этого нам понадобится метод
Scheduler.get().scheduleDeferred() 

Добавим в очередь событий вызов метода выделения текста в компоненте.
Scheduler.get().scheduleDeferred(
  new Scheduler.ScheduledCommand() {
    public void execute() {
      selectAll(selector.getInputElement());
    }
});

Полностью код будет выглядеть так
Event.sinkEvents(selector.getInputElement(), Event.ONFOCUS);
Event.setEventListener(selector.getInputElement(), 
  new EventListener() {
    @Override
    public void onBrowserEvent(Event event) {
      openDropdown(true);
      currentValue = selector.getText();
      Scheduler.get().scheduleDeferred(
        new Scheduler.ScheduledCommand() {
          public void execute() {
            selectAll(selector.getInputElement());
          }
        });
      }
  });

понедельник, 30 июня 2014 г.

jQuery. How to lock screen while loading

Для того, чтобы в jQuery заблокировать экран, например, пока выполняется какая-то логика или загружаются данные с сервера, можно использовать специальный плагин

jQuery Block UI

Заблокировать страницу
$.blockUI();

Разблокировать страницу
$.unblockUI();

Помимо это есть варианты блокировки с опциями (затенение экрана и добавление текста)

Если этот плагин используется в связке с библиотекой require.js, тогда его подключать нужно так

requirejs.config({
    "baseUrl": "js/lib",
    paths: {
        'jquery': ['jquery-1.9.1.min'],
        'jquery-mobile': ['jquery.mobile-1.3.2.min'],
        'iscroll': ['iscroll'],
        'iscroll-lite': ['iscroll-lite'],
        'jquery-form': ["jquery.form"],
        'jquery-validity': ["jquery.validity.min"],
        'jquery-blockui':["jquery.blockUI"],
 
 ...
 
        'facebook-helper': ['../helper/facebook-helper'],
        "components": ["../components"]
    },
    shim: {
        'jquery-mobile': ['jquery'],
        'jquery-form': ["jquery"],
        'jquery-validity': ["jquery"],
        'jquery-blockui':["jquery"]
    }
 
});

Теперь пример, тут вызывается серверный POST-метод и пока мы ждем ответа от сервера, мы блокируем экран, а когда получаем ответ разблокируем его.
define(["jquery", "jquery-blockui"], function ($, settings) {
    var apiClient = {
 
        callPost: function (methodName, requestData, callback) {
            require(['utils'], function (utils) {
                console.info("Call server method: name='" + 
                methodName + "' requestData='" + 
                requestData + "' apiUrl='" + settings.apiUrl + "'");
                $.blockUI({ css: {
                    border: 'none',
                    padding: '15px',
                    backgroundColor: '#000',
                    '-webkit-border-radius': '10px',
                    '-moz-border-radius': '10px',
                    opacity: .5,
                    color: '#fff'
                } });
                $.ajax({url: settings.apiUrl + methodName, type: "post", 
                  data: requestData, success: function (data) {
 
                        if (data.serviceData && data.serviceData.error) {
                            $(document).ajaxStop($.unblockUI);
                            console.warn(data.serviceData.message);
                            utils.popup(data.serviceData.message)
                            // some logic invoke
                        } else {
                            callback(data);
                            utils.hideLoading();
                            $(document).ajaxStop($.unblockUI);
                        }
                    }, error: function (jqXHR, textStatus, errorThrown) {
                        $(document).ajaxStop($.unblockUI);
                        utils.popup("Oops...an error occurred. 
                          Please try again in a few seconds.");
                        console.info("Error:" + textStatus);
                        console.info("Error:" + errorThrown);
                    },
                        contentType: "application/json"
                    }
                )
            });
        }
 
...
 
});

Блокируем экран с затемнением
$.blockUI({ 
  css: {
    border: 'none',
    padding: '15px',
    backgroundColor: '#000',
    '-webkit-border-radius': '10px',
    '-moz-border-radius': '10px',
    opacity: .5,
    color: '#fff'
  } 
});

Разблокируем экран
$(document).ajaxStop($.unblockUI);

jQuery. How to handle page refresh

Для того, чтобы в jQuery обработать событие обновления страницы необходимо сделать следующее.

$(window).bind('beforeunload',function(){
 
  //Your logic here
 
  return 'Are you sure you want to leave?';
 
});

Работающий пример

воскресенье, 29 июня 2014 г.

NYRBY - будь в курсе!

На днях поставил себе новое приложение – NYRBY. Ребята разработчики на странице приложения (ссылка - https://play.google.com/store/apps/details?id=com.nyrby&hl=ru) пишут, что оно умное. Решил проверить, кто умнее )

Завел себе аккаунт, добавил пару друзей.

 



Так вот, нирби за один день узнало, где я живу, и начала мне показывать новости от моих соседей!



Магия одним словом )
Посмотрим, что будет дальше. 

Google Guava Splitter Example

Разобрать строку в GWT можно с помощью библиотеки Guava. Вот пример как это сделать.

Описание библиотеки на Wikipedia

Скачать библиотеку Guava

Пример использования Guava
String str = "This;is test;string with;semicolons";
Iterable<String> result = Splitter.on(";").trimResults() 
    .omitEmptyStrings() 
    .split(str); 
StringBuilder sb = new StringBuilder(); 
for (String s : result) { 
  sb.append(s + "\n"); 
} 
System.out.print(sb.toString()); 

Результат работы