GWT: How to use new fancy LocalStorage

LocalStorage is definitely not a very new HTML5 feature. It is well known and used for several years. GWT provides special API for localStorage.

The way it can be used is the same as in JavaScript.

First of all we import:

import com.google.gwt.storage.client.Storage;

then we can take storage object:

Storage storage = Storage.getLocalStorageIfSupported();

if localStorage does not supported, then storage will be null.

To save value or read it by key we can use:

storage.setItem("message", "text");
storage.getItem("message");

There is a nice way to subscribe to changes in localStorage:

HandlerRegistration handlerRegistration = storage.addStorageEventHandler(new StorageEvent.Handler() {
  @Override
  public void onStorageChange(StorageEvent event) {
    Window.alert(event.getKey() + " " + event.getNewValue() + " " + event.getOldValue());
  }
});

it will show any changes on the storage item. If item will be removed, the event.getNewValue() will return null.

Tags:

GWT: How to use plain old Cookies?

Cookies is a quite old and limited technology to save some data between sessions in browsers. There are much more capable technologies like HTML5 localStorage. There is a nice topic on how to compare and choose which one is better.

To check if Cookies are enabled set Cookie we can use the following code:

import com.google.gwt.user.client.Cookies;
...
if (Cookies.isCookieEnabled() {
  setText("Cookie enabled");
}

To set and read Cookie we can use:

Cookies.setCookie("message", "Hi!", new Date(2015, 12, 30));
setText(Cookies.getCookie("message"));

To remove Cookie we can use:

Cookies.removeCookie("message");

Documentation on GWT Cookies

Tags:

Some common use-cases of Gin

There are several useful cases for Gin injections.

EventBus

One of the most popular way to make application loosely coupled is to use EventBus. We can create injection without taking care of how it was instantiated. In MyWidgetClientModule we add line:

bind(EventBus.class).to(SimpleEventBus.class).in(Singleton.class);

It declares that injected EventBus interface should be implemented by SimpleEventBus and be Singleton.
In all classes it will provide the same instance.

Now it can be used in the following way:

private EventBus eventBus;

@Inject
public MyWidgetMainPanel(EventBus bus) {
  this.eventBus = bus;
}

Geolocation

Another interesting option for GWT injection is Geolocation.

bind(Geolocation.class).in(Singleton.class);

In this case we declare implementation without interface as a Singleton.
Now we can inject it:

@Inject
public MyWidgetMainPanel(Geolocation geolocation) {
  geolocation.getCurrentPosition(new Callback() {
    @Override
    public void onFailure(PositionError reason) {
      setText("onFailure");
    }

    @Override
    public void onSuccess(Position result) {
      setText("accuracy:" + result.getCoordinates().getAccuracy());
    }
  });
}

Tags: ,

How to use Constants in Gin

Here is a nice way to inject some properties to GWT application.

First of all declare Constants interface.

public interface MyConstants extends Constants {
  @DefaultStringValue("hello")
  String myWords();
}

Then bind MyConstants:

bind(MyConstants.class).in(Singleton.class);

Next we can use constants:

public class MyWidgetMainPanel extends Label {
  @Inject
  public MyWidgetMainPanel(MyConstants myConstants) {
    this.setText(myConstants.myWords());
  }
}

by default it will show message: hello

If we will create MyConstants.properties and write

myWords=Hello World!

then it will show: Hello World!

Tags:

How to use Gin for GWT

There is quite good tutorial on Gin that I’ve used to try it.

First of all there is need to declare it in *.gwt.xml file.

<inherits name="com.google.gwt.inject.Inject"/>

Next step is to create Injector:

import com.google.gwt.inject.client.GinModules;
import com.google.gwt.inject.client.Ginjector;

@GinModules(MyWidgetClientModule.class)
public interface MyWidgetGinjector  extends Ginjector {
  MyWidgetMainPanel getMainPanel();
}

and create «binder»:

import com.google.gwt.inject.client.AbstractGinModule;
import com.google.inject.Singleton;

public class MyWidgetClientModule extends AbstractGinModule {
  protected void configure() {
    bind(MyWidgetMainPanel.class).in(Singleton.class);
  }
}

finally in EntryPoint we can declare:

private final MyWidgetGinjector injector = GWT.create(MyWidgetGinjector.class);

and take any widget like MyWidgetMainPanel that we’ve declared in MyWidgetGinjector and MyWidgetClientModule.

Tags:

Первые дни в Калифорнии

На следующее утро после заселения мы решили воспользоваться бесплатным завтраком, который предоставляется в отеле Extended Stay America. В него входили овсянка фасованная в пакетики, кипяток, дешевый чай в пакетиках, приличный кофе, кексы, яблоки, апельсины и батончики мюсли. На самом деле, кофе только временами был хороший, а иногда оказывался разбавлен водой. Овсянка тоже на несколько дней пропадала, а потом снова появлялась. В номере у нас оказалась электрическая плита, холодильник и даже микроволновка.

Стоит отметить, что этот отель имеет всего две звезды, а одна ночь в этом отеле стоит $130! При этом большая часть номеров оказалась заполнена. Для чистюль там есть прачечная самообслуживания, где стоят в несколько рядов стиральные и сушильные машины. Каждая стирка или сушка стоят по $2, а средста для стирки нужно иметь свои. Оплачивать их нужно четвертаками – монетками по 25 центов.

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

Кроме Walgreens рядом оказались обычный продуктовый магазин Smart & Final, магазин с особенно хорошим ассортиментом Nob Hill Foods и магазин японских продуктов Nijiya Market. Использование купюр по $100 никого не смутило, вообще есть много любителей платить наличными.

Самое первое дело — подключение номера мобильного телефона. В пешеходной дистанции оказался только AT&T, его стандартный пакет за $45 в месяц включает в себя интернет 1,6 Гб, безлимитные звонки и SMS. При своевременной оплате через интернет стоимость снижается до $40.

Мой телефон имеет два слота для сим-карт, но ни один из них не стал работать с такой странной сим-картой. В результате пришлось купить телефон за $20. У жены телефон заработал с новой сим-картой без проблем.

Вторым важным делом является получение банковского счета. Проще всего это сделать в Bank of America, он требует только паспорт и предложение работы с указанием зарплаты. Процедура открытия счета оказалось быстрой и безболезненной. Мне выдали временную карточку и несколько бланков для выписки чеков. С их помощью можно безналично оплачивать некоторые услуги.

Представительница банка, среди прочего, спросила номер телефона и предложила настроить приложение для управления банком. Нужно было видеть с каким презрением она смотрела на новый телефон за $20. Она тыкала пальцем в него словно он был в чем-то перемазан. После того, как у нее ничего не получилось она сказала, что я сам поставлю приложение после того как куплю с первой зарплаты себе телефон по приличнее.

Третье важное дело — получение SSN. В офисе Social Security можно заполнить несложную анкету. После ожидания в небольшой электронной очереди меня вызвали и дяденька стал переписывать данные с моей анкеты в компьютер. Еще ему потребовалась специльная петиция H1B, которую также спрашивали в консульстве для получения визы. Когда я уже расслабился, дяденька вдруг попросил форму I-94. Мурашки побежали у меня по спине — этой формы у меня не было. Я стал спрашивать, на что она похожа и что там должно быть. Оказалось, это выписка с сайта о том когда я вьехал в США. Эту форму я нашел в телефоне и показал дяденьке. Он перепечатал информацию без тени презрения к дешевому телефону. Может быть потому, что тыкать в него ему было не нужно.

SSN должен был придти через 10 дней, однако и через 15 дней он не пришел. Возможности выяснить где и почему он застрял не оказалось — все отказывались говорить что-либо конкретное. В результате пришлось заказать замену номера, которая пришла довольно быстро уже в арендованные апартаменты. SSN представляет собой документ в одну треть листа A4 на очень дешевой и тонкой бумаге. Ламинировать его нельзя и нужно хранить всю жизнь. Этот секретный документ следует показывать только в особых случаях, например в банке или работодателю.

Tags: ,

Релокация в Калифорнию

К сожалению, в Румынии я пробыл не долго — всего три месяца. Судьба решила забросить простого программиста в солнечную Калифорнию. Не скажу что сильно из-за этого расстроился, даже обрадовался… Очень обрадовался! Все произошло быстро — доработал месяц в Румынии, заехал в Петербург, сделал визу и собрался лететь с семьей.

Вещей набралось аж на 9(девять) чемоданов с максимальным весом. В аэропорту Пулково были явно обескуражены таким количеством багажа, однако виду не подали. После сдачи скромных пожитков полоса препятствий не закончилась — меня не хотели пропускать к пограничникам. Автоматическая система отмечала билет красным и меня просили подождать. Я уже начал беспокоиться, не нашли ли чего-нибудь запрещенного в моих вещичках, однако придумать к чему могли быть вопросы не получилось. Позже оказалось еще несколько таких «счастливчиков».

Пограничники спросили чего это такой крендель как я вдруг собрался в США. А когда узнали, что еду работать — задумались. Чтобы сгладить неловкий момент, пришлось сказать, что виза у меня только на год и уже есть обратные билеты. После этого атмосфера явно разрядилась. Похоже такие «умники» выезжают не первый раз и на это обращают внимание.

Дальше пошло легче — самолет до Франкфурта отправился точно по расписанию. Во Франкфурт он не только опоздал, но даже прилетел не в тот терминал. После этого пришлось бежать со всех ног чтобы успеть пересесть на рейс в Сан-Франциско.

Самолет оказался не обычным, а двухэтажным — на таких «птичках» мне еще не приходилось летать. Впрочем, двухэтажность сама по себе ничего не прибавила, полет прошел без вечеринки и коктейлей. Возможно на втором этаже было джакузи, но нищебродов вроде меня туда не звали.

В Сан-Франциско пограничный контроль оказался проще. Суровый пограничник совсем не удивился, видимо тут и покруче программисты очередями стоят. Потом я пошел получать чемоданы — все 9 чемоданов добрались без проблем. Нужно было видеть как я перебежками тащил две тележки нагруженные чемоданами и еще ручную кладь. Таксист, который нас встречал, был явно удивлен. В его шикарный вместительный автомобиль представительского класса могло поместиться много чемоданов, но не столько. Он позвонил своему товарищу и через 40 минут приехало второе такси, они распределили багаж по машинам и минут через 30 мы доехали до отеля.

Казалось, в отеле приключения должны закончиться, но в приемной нас ждала тетенька-колобок. Она попросила кредитную карточку, но я закрыл все банковские карточки в России и были только наличные. После некоторых обсуждений и телефонных звонков она выдала ключи от номера. Когда мы пришли к номеру и попытались его открыть — он не открылся. Тогда тетенька выдала новые ключи и когда мы открыли номер… оказалось, что кто-то опредил нас и занял этот номер раньше. Тетенька сильно удивилась и даже сходила посмотреть, уж не фантазия ли это все. В результате мы таки получили ключи от действительно свободного номера.

Приключения стали заканчиваться и после долгого перелета очень хотелось кушать. Продуктовые магазины были уже закрыты, работала только круглосуточная аптека Walgreens. Там нашлось вяленое мясо, мыло, туалетная бумага — не слишком хорошая перспектива для голодных человеков. Остался вариант с Burger King. Там работало только одно окно, к которому подъезжают автомобили и заказывают гамбургеры. Я занял очередь и когда подошел — у продавца был шок. Пешеходы не слишком частые клиенты ночного окна для автомобилистов.

Из-за того, что EPAM взял хорошие авиабилеты, с одной короткой пересадкой, адаптация к смене дня на ночь прошла легко и быстро. Время в Калифорнии отличается от Петербурга и Бухареста практически наоборот: когда в Маунтин Вью 11 вечера, в Петербурге 9 утра.

Спонсор визы и поездки — EPAM Systems. Если будете отправлять резюме, то можете сослаться на меня.

Tags: ,

GWT: How to use JavaScript Native Interface

GWT classes are able to implement JSNI methods. As an example, we can create the following simple method to check filter message. It receives Java String, boolean and int as a parameters and converts them to JavaScript String, boolean and int. Then JavaScript makes some logic and returns String. In the same way it can return boolean and int.

public static native String doMagic(String msg, boolean isSecret, int level) /*-{
  if (isSecret && level > 5) {
    return "message is not available";
  }
  return msg;
}-*/;

We can pass parameters and return values only the following types: int, String, boolean.

JavaScriptObject

If we wish to use complex data structures we can extend JavaScriptObject.

public class Pet extends JavaScriptObject {
  protected Pet() {}

  public final native String getName()/*-{
    return this.name;
  }-*/;
}

Then we can receive it as a normal Java DTO.

public static native Pet giveMeMyPet() /*-{
  return { name: "Jim" };
}-*/;

Special objects

The JavaScript objects like Window and Document can be used as a $wnd and $doc.
For example:

$wnd.alert("Hello");
$doc.getElementById("head");

Tags:

Usage of ComparatorPredicate

ComparatorPredicate is a very useful instrument for object validation. It uses plain old Comparator to check provided value. You can easily find some examples of Comparators and their usage for sorting Java objects.

Here is a simple Comparator for Strings. It compares to String’s by their length.

Comparator<String> LENGTH = new Comparator<String>() {
  public int compare(String first, String second) {
    return second.length() - first.length();
  }
};

This Compatator will return 0 if length of both strings is equal, negative value if first string is longer and positive value if second string longer.

We can create new ComparatorPredicate to print Strings with length of 5 symbols.

Predicate<String> LENGTH_5 = ComparatorPredicate.comparatorPredicate("12345", comparator);

and iterate over the set of lines:

for( String line : lines ) {
  if (EQUAL_LENGTH.evaluate(line)) {
    System.out.print(line);
  }
}

If we wish to see lines longer then 5 symbols we can use special criteria. Here is an example:

Predicate<String> LENGTH_5 = ComparatorPredicate.comparatorPredicate(
  "12345",
  comparator,
  ComparatorPredicate.Criterion.GREATER);

also it is possible to use several other criterias:

ComparatorPredicate.Criterion.LESS
ComparatorPredicate.Criterion.GREATER_OR_EQUAL
ComparatorPredicate.Criterion.LESS_OR_EQUAL

The benefits of Predicates are not obvious. Why simple If statement isn’t better? We can declare well-named predicates and then provide as an arguments to the loops. This will make our code self-documented and easy to read.

Documentation for ComparatorPredicate

Grouping of Predicates using AndPredicate

There is a nice way to group predicates: AndPredicate. It is good idea to use more general interface Predicate because it can be used in many more cases. To instantiate AndPredicate we can use constructor:

Predicate merged = new AndPredicate(firstPredicate, secondPredicate);

or we can use factory:

Predicate merged = AndPredicate.andPredicate(firstPredicate, secondPredicate);

In order to pass Predicate evaluation element must be successfully verified by both predicates: first and second.

A simple usage of AndPredicate could be the following:

for( Integer number : numbers ) {
  if (merged.evaluate(number)) {
    System.out.print(number + " ");
  }
}

In order to save specific features of AndPredicate we can use:

AndPredicate merged = new AndPredicate(firstPredicate, secondPredicate);

in this case we will be able to use one more method: getPredicates() it returns Array with two provided predicates. Usage could be the following:

for( Integer number : numbers ) {
  if (merged.getPredicates()[1].evaluate(number)) {
    System.out.print(number + " ");
  }
}

Tags: ,