Category Archives: Programming

Comet на Embedded Jetty. Первый блин)

комом. Мой первый эксперимент с COMET и с Embedded Jetty. “Пощупать” COMET хотелось уже давно. Во-первых сама по себе технология достаточно интересная, а во-вторых — хотелось попробовать что-то новенькое. Jetty был выбран в качестве сервера для экспериментов как наиболее легковесный (особенно в embedded-варианте) из известных мне Java-серверов.

В качестве примера напишем простенький чат. Будем использовать технику long polling. Допустим у нас запущен Jetty-сервер с приложением-чатом, к которому подключились два клиента Саша и Маша. На диаграмме все их мучения будут выглядеть так:

comet

Теперь попробуем объяснить увиденное с небольшими вставками кода (полный исходный код можно скачать в конце статьи).

Continue reading

Визуализируем репозиторий #2

Продолжаем эксперименты с Code Swarm. В связи со сменой работы решил натравить визуализацию на текущий проект) Вот что получилось:

P.S.: хорошая пошаговая инструкция по этой утилите.

Reorder JQuery event handlers

I was little bit suprised when I didn’t find in JQuery an ability to bind event’s handler before than already binded event’s handlers list. Yes, it is possible to first attach our handler rather than others, but this may be very difficult sometimes. So I spent some time looking through JQuery sources and found what I need:

/*
 * A number of helper functions used for managing events.
 * Many of the ideas behind this code originated from
 * Dean Edwards' addEvent library.
 */
jQuery.event = {
 
    // Bind an event to an element
    // Original by Dean Edwards
    add: function( elem, types, handler, data ) {
        ...
 
        // Init the element's event structure
        var elemData = jQuery.data( elem );
 
        // If no elemData is found then we must be trying to bind to one of the
        // banned noData elements
        if ( !elemData ) {
            return;
        }
 
        // Use a key less likely to result in collisions for plain JS objects.
        // Fixes bug #7150.
        var eventKey = elem.nodeType ? "events" : "__events__",
            events = elemData[ eventKey ],
            eventHandle = elemData.handle;
 
        ...
 
        while ( (type = types[ i++ ]) ) {
            ...
 
            // Get the current list of functions bound to this event
            var handlers = events[ type ],
                special = jQuery.event.special[ type ] || {};
 
            ...
 
            // Add the function to the element's handler list
            handlers.push( handleObj );
 
            ...
        }
 
        // Nullify elem to prevent memory leaks in IE
        elem = null;
    }
 
    ...
}

As we can see from this code all we need to do is get “handlers” array (for “click” event in this example) from target element. Then we can do anything we need with event’s handlers. Code to do this is quite simple:

var
elementData = jQuery.data(targetElementDom),
events = (elementData.events ? elementData.events : elementData.__events__),
handlers = events['click'];
 
// Only one handler. Nothing to change.
if (handlers.length == 1) {
    return;
}
 
// Insert last handler at first index.
handlers.splice(0, 0, handlers.pop());

I used previous code to attach confirm window to elements which already have (or not) “click” event handlers.

Little demo.

Jersey: how to get temporary file

I use Jersey with flash uploader and the problem I met is that I need to determine “file partialy uploaded” situation ’cause user has an opportunity to cancel it at any time. All solutions that I found for this problem were on PHP (look for The uploaded file was only partially uploaded text). I didn’t find any standart technics how to get size of uploaded file (uploaded file’s input stream doesn’t has such information) to compare it with actual file size. So I used a “little reflection magic” to get it. ’cause classes that we’ll use to get information is private for org.jvnet.mimepull package we need to create out util class in exactly the same package. Then we can use reflection to get any infomation that we need.

Continue reading

Fix for Jersey’s russian files names bug

In our project we use Sun/Oracle implementation of JAX-RS — Jersey ’cause it’s greate framework for build REST-services. But there are some troubles with uploading files feature. When you uploading file with latin chars in file name everything is fine, you read this file name on server and it’s exactly the same as on client computer. But when you trying to upload file with russian chars in file name you get “abracadabra” instead of them. For example:

Original file name Received file name
Test123.txt Test123.txt
Тест123.txt Тест123.txt

Continue reading

JRebel: хватит тратить своё время

Небольшой обзор по установке и использованию JRebel. Штука действительно очень клёвая. Предназначена для java-разработчиков. В основном для тех, которые занимаются enterprise-решениями, так как они достаточно громоздкие и пересборка/перезапуск всего проекта занимает значительное время (несколько минут), что сказывается как на скорости, так и на желании работать) JRebel позволяет увидеть результат от внесённых изменений практически мгновенно. Обзор проводился в следующем окружении:

  • Maven 2
  • JBoss 4.3.2
  • Seam 2.2.0.GA
  • IntelliJ IDEA 9

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

Continue reading

Sharing JSESSIONID cookie across subdomains on JBoss

The problem with sharing cookie with JSESSIONID value arises when we start use subdomains system in our application. For example: images.portal.com, security.portal.com, etc.

Respectively a cookie with unique JSESSIONID value will be created for each domain address and you can get some problems. For example, with autorization if it stores credentials in session. So for our example we will have three diffrent cookies with three different session ids.

# Domain Value
1 portal.com JSESSIONID1
2 images.portal.com JSESSIONID2
3 security.portal.com JSESSIONID3

Not very good, really?) Our cookie must have “.portal.com” domain to starts sharing across all subdomains (and there also will be only one session cookie instead of three). I didn’t find any standart solution for this problem. Possible solutions are:

  1. hardcode domain name in TomCat source files and recompile them (heh, I think this is the most popular solution for this problem over the Internet, but it isn’t our way);
  2. use custom valve to set domain name (very flexible solution, so we will used it);
  3. write cookie with true domain from application. But this will make your application logic more complicated and you will have two cookie with identical JSESSIONID value and different domains. “.portal.com” — from your application, “portal.com” — from TomCat.

Valve is the great software development company and it is also a filter that can do some transformation with request. In our case the valve must takes session cookie from request and rewrites its’ domain to some that we setup in config file. It’s very easy, ’cause problem is already solved. From previous link we saw how to work with valve and now we can go here.

Step-by-step guide (for JBoss 4.2.3):

  1. download customvalve2.zip file;
  2. put customvalve.jar file from archive to “JBOSS_HOME/server/YOUR_CONFIGURATION/lib” folder;
  3. add string “<Valve className=”com.redhat.jboss.support.ConfigureSessionCookieValve” cookieDomain=”.portal.com” />” to your host in “JBOSS_HOME/server/YOUR_CONFIGURATION/jboss-web.deployer/server.xml” file. Looks like:
    <Host name="localhost"
        autoDeploy="false" deployOnStartup="false" deployXML="false"
        configClass="org.jboss.web.tomcat.security.config.JBossContextConfig"
        >
        ...
        <Valve className="com.redhat.jboss.support.ConfigureSessionCookieValve"
            cookieDomain=".portal.com" />
        ...
    </Host>

And at last let us see the method that does all work (located in ResponseWrapper.java):

// Called from addCookie() and addCookieInternal() methods.
protected void configureSessionCookie(Cookie cookie) {
    if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) {
        if (cookiePath != null) {
            cookie.setPath(cookiePath);
        }
        if (cookieDomain != null) {
            cookie.setDomain(cookieDomain);
        }
        if (cookieSecure != null) {
            if (cookieSecure.equalsIgnoreCase("true")) {
                cookie.setSecure(true);
            } else if (cookieSecure.equalsIgnoreCase("false")) {
                cookie.setSecure(false);
            }
        }
    }
}

That’s all!) Valve sources lie in downloaded archive so they can be easily modificated for your purposes.

Карты со вкусом Яндекса

Во время работы над очередным проектом столкнулся с непреодолимым желанием заменить имеющуюся карту (надо сказать не лучшего качества) на странице “Контакты” на что-то более интересное и интерактивное) На ум пришли Google.Maps и Яндекс.Карты. Выбор в пользу последних был сделан в силу того, что нужный участок нашей планетки был отрисован там гораздо подробней, чем у Google:

Череповец с точки зрения Google Maps

cherepovets_google_maps
Череповец с точки зрения Яндекс.Карт

cherepovets_yandex_maps
Гы) Как говорится, почувствуйте разницу)

Итак, выбор сделан. Что дальше? Идём вот сюда. Нужен ключ? Ок) Заполняем простенькую форму, где только и требуется, что указать адрес сайта. Причём сделать это надо правильно. Вместе с ключом выводится также несложный примерчик с подробными комментариями, аля “Hello world”:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Примеры. Простой вызов карты.</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script src="http://api-maps.yandex.ru/1.1/index.xml?key=XXXYYYZZZ" type="text/javascript"></script>
        <script type="text/javascript">
            // Создание обработчика для события window.onLoad
            YMaps.jQuery(function () {
                // Создание экземпляра карты и его привязка к созданному контейнеру
                var map = new YMaps.Map(YMaps.jQuery("#YMapsID")[0]);
 
                // Установка для карты ее центра и масштаба
                map.setCenter(new YMaps.GeoPoint(37.64, 55.76), 10);
            })
        </script>
    </head>
 
    <body>
        <div id="YMapsID" style="width:600px;height:400px"></div>
    </body>
</html>

Так как меня интересовала именно интерактивная карта, то мне подошёл JavaScript API. Лезем в примеры, где сразу находим всё, что нужно) Также порадовал подробный “Справочник по программному интерфейсу“, где расписано, что куда и как надо передавать. Пришлось немного помучатся с масштабом и размером всплывающего balloon’а, но в итоге всё стало выглядеть так как надо. Ура! Получилась вот такая загагулина:

my_yandex_maps

<div id="YandexMap" style="width : 420px; height : 350px; float: right; border: 1px solid gray;"></div>
 
<script src="http://api-maps.yandex.ru/1.1/index.xml?key=XXXYYYZZZ" type="text/javascript"></script>
 
<script type="text/javascript" charset="utf-8">
    YMaps.jQuery(function () {
        var
        map = new YMaps.Map(YMaps.jQuery("#YandexMap").get(0)),
        geoPoint = new YMaps.GeoPoint(37.928155, 59.122003);
 
        map.setCenter(geoPoint, 16);
        map.openBalloon(
            geoPoint,
            'XXXYYYZZZ',
            { hasCloseButton : false, maxWidth : 180 }
        );
        map.addControl(new YMaps.Zoom());
    });
</script>

Вообщем, я доволен)

Redirect to “No IE6 page”

Many online services have stopped supporting Internet Explorer 6 and when a user tries to access them with the browser sent him to the information page, where the offer to upgrade IE to latest version or choose another browser. Here is my easiest solution for this:

<html>
    <head>
        <!--[if lt IE 7]>
            <script type="text/javascript" charset="utf-8">
                window.location = 'location_of_your_no_ie6_page';
            </script>
        <![endif]-->
        ...
    </head>
    ...
</html>

It used nothing, but IE conditional comments, so it’s very compact and fast ’cause every browser except IE6 and lower just ignores this code.

Багаж знаний

В последнее время практически полностью перешёл на техническую литературу в электронном виде, т.к. её гораздо легче достать, она не занимает много места и не надо лихорадочно листать страницы, когда нужно что-то найти:) Но иногда бывает приятно полистать какую-нить книженцию) Вот багаж, который был накоплен за долгие годы:

my_books_small

Особо стоит отметить трёхтомник Кнута и книгу по C++ Страуструпа)