Метка: Java

  • Apples and oranges. Сравнение веб-фреймворков.

    Этим летом ко мне обратился старый знакомый, который хотел начать разработку нового веб-проекта. Он хотел пообщаться/посоветоваться на тему современных инструментов (фреймворков) для разработки веб-приложений. Дело в том, что у него скорее планировалась не разработка нового, а переделка старого проекта, сделанного на JSP и сервлетах, базовая архитектура которого ваялась еще в начале 2000-ных. В прошлом я немного участвовал в жизни этого программного продукта (доработки по Hibernate, прикручивал apache fop и т.д.), поэтому был немного в курсе внутренних особенностей системы.

    В целом это было добротное веб-приложение на Spring-e и оракловой СУБД. Думаю многие из нас в былые времена делали подобные вещи. С тех пор многое поменялось, одни инструменты сильно развились, появились абсолютно новые, а некоторые безнадежно устарели и канули в Лету. В итоге мы решили встретиться, пообщаться, попить кофе и обсудить, кто с чем столкнулся на профессиональном поприще за последние несколько лет, а также поделиться впечатлениями об использовании тех или иных инструментов.
    На мой взгляд к 2013 году человечество создало такое огромное количество библиотек, утилит, платформ и других полезных и бесполезных вещей для создания веб-приложения, что разобраться в них становится все сложнее и сложнее. Суть проблемы заключается в том, что обилие различных модных слов создают кашу в голове программистов.

    Чтобы хоть в чем-то упростить себе (и другим программистам) жизнь, я решил после нашей беседы написать этот небольшой обзор различных веб инструментов (в контексте Java и JavaScript). Возможно многие вещи покажутся слишком простыми и очевидными, рассчитанные на совсем юных программистов, тем не менее думаю ошибочно считать, что “каша” возникает только у новичка. Наоборот, умудренные опытом программисты, опираясь на сформировавшиеся у себя в мозгу концепции, проецируют свои старые понятия на новые фреймворки, в итоге сложнее впитывают суть, смысл и назначение новых.

    Ведь на самом деле, многие инструменты качественно отличаются друг от друга и сравнивать их порой не представляется возможным. Apple_and_Orange_-_they_do_not_compareВ английском языке существует выражение “сравнивать яблоки и апельсины“, в русском языке ближайшим аналогом этого высказывания “путать теплое с мягким“. Сравнивать разные по сути вещи. Например, все равно что сравнивать JSF и jQuery.

    Поэтому, чтобы внести ясность, я решил раскидать “яблоки к яблокам, а апельсины к апельсинам”. В итоге получился следующий текст.
    (далее…)

  • Про ASM и манипуляции с байт-кодом.

    asm2Больше месяца назад автор статьи Decrypting Java Malware using ASM прислал мне оригинальный текст на русском языке для публикации в блоге, с целью донести широкому кругу лиц определенные аспекты защиты программ написанных на java от действий недоброжелателей. Автор статьи — разработчик, который долгое время занимается разработкой средств для противодействия реверс-инжирингу и взлому ПО, специалист в области информационной безопасности.
    К сожалению, в связи с большой загруженностью (казалось бы лето, все должны быть в отпусках, а нет — работы только привалило), никак не мог заняться блогом и выложить эту статью.

    Исправляюсь, надеюсь статья всё еще актуальна.

    В настоящее время очень популярны Java Malware, использующие уязвимости в Java. Многие из них для скрытия своих действий используют шифрование строк. Как правило в них могут храниться ключи реестра, команды для запуска различных программ и т.д.

    В этой статье мы рассмотрим самый распространенный метод шифрования строк в Java Malware и напишем утилиту для снятия такой защиты.

    1) Небольшое введение в формат байткода class-файлов.

    Для дальнейшего понимания, необходимо знать следующие вещи – все константы (строки/примитивные типы) хранятся в специальной структуре внути class-файла, которая называется Constant Pool и для получения элемента из Constant Pool используется инструкция ldc.

    Посмотрим как выглядит байт код вызова метода System.out.println(“HelloWorld”);

    Пишем простой класс

    public class Hello {
      public static void main(String[] args) throws Exception {
        System.out.println("HelloWorld");
      }
    }

    Компилируем
    javac Hello.java

    Декомпилируем с помощью javap

    javap -c -v Hello

    ConstanPool:

      ... 
        const #3 = String	#20;	//  HelloWorld
        const #20 = Asciz	HelloWorld;
    
       3:	ldc	#3; //String HelloWorld
       5:	invokevirtual	#4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

    (далее…)

  • Про старый добрый RMI


    Не так давно, после многолетнего перерыва, в одном небольшом проекте использовал такую древнюю технологию как RMI. В итоге хотел поделиться общими впечатлениями и сделать небольшие заметки “для себя” на будущее.
    Задача была типовой — перебросить выполнение некоторых функций с одного сервера на другой, на котором установлено специальным образом настроенное оборудование и программное обеспечение. В результате нескольких раундов переговоров с клиентом были получены следующие нефункциональные требования:

    1. Между серверами гигабитная сеть в доверенной зоне, без доступа в интернет.
    2. Физически сервера расположены рядом (в одной стойке).
    3. Размер передаваемых в функцию данных около нескольких сотен килобайт, максимум нескольких мегабайт.
    4. Количество запросов небольшое, но возможны пиковые нагрузки.
    5. Операционная системы и оборудование позволяет установить последнюю стабильную версию Java, но по возможности следует избегать большого количества сторонних библиотек и фреймворков.
    6. Клиентская и серверная часть должны работать не столько в рамках сервера приложения/веб-сервера, а скорее как обычное приложение.

    Если обобщить функциональные требования — обработка и выполнение специальных запросов содержащих данные в закрытом формате, идентификаторы и различную служебную информацию.

    Кончено RMI давно уже не в тренде, но в данном случае он очень органично подходил для решения этой задачи. Другое дело, что явно пользовался им очень давно, во времена предшествующие Java 5. С тех пор для ремоутинга чего-только не приходилось применять. В зависимости от контекста: .NET Remoting, Hessian/Burlap, GWT-RPC, SOAP, ну и конечно различные самодельные реализации.
    Сейчас большинство моих заказчиков хотят веб-службы. Бизнесу нужен SOAP и WSDL, по крайней мере сейчас.

    Еще раз повторюсь, я не смотрел на RMI много лет, с тех пор многое изменилось (для меня). В первую очередь радует то, что уже давно можно не запускать rmic и колдовать со скелетонами как нас до сих пор учит википедия.
    С другой стороны классы Remote и RemoteException остались, т.е. преемственность базовых классов естественно остается. И это хорошо!

    Официальный Java-учебник как обычно в хорошем состоянии. Пересказывать его не вижу смысла, поэтому далее хочу ограничиться небольшим количество “хинтов”, которые возможно пригодятся мне в будущем.

    • Системное свойство java.rmi.server.logCalls = true/false полезно для отладки.
    • Если две сетевые карты, то может будет полезно посмотреть на свойство java.rmi.server.hostname.
    • Если вдруг понадобится, то можно прочитать руководство по работе RMI и SSL.
    • Подробный список свойств находится на страницах javarmiproperties и sunrmiproperties.

    Резюмируя — мне понравилось, вернулись воспоминания моей java-молодости, во времена когда клепал Applet-ы, раскладывал GridBag-ом и писал сервера на голых ServerSocket-ах. В целом, не смотря на то, что RMI уже очень много лет, оказалось, что на нем до сих пор можно быстро делать простые связки Java-to-Java фактически “из коробки”.

  • Java и лямбда-выражения.

    Lambda

    Ни для кого не секрет, что во второй половине 2013 года планируется выпуск Java 8 (UPD: на JavaOne 2013 в Москве сообщили, что выход восьмерки перенесут на 2014). Мне наконец-то надоело быть пассивным читателем всех этих многочисленных восторженных отзывов о нововведениях языка и я решил скачать предварительную версию JDK (благо она уже давно выложена) и начать свои экзерсисы.

    Как правило я стараюсь ждать релиза, но сейчас в новостях столько разговоров о лямбда-выражениях в новой Java, что мне, старому Scala-фанатику и функционального программирования, уж очень сильно захотелось поиграться с новыми возможностями языка. Если смотреть на все новшества восьмой Java со стороны Scala программиста, то в целом лично я отношусь к ним положительно, поскольку такой расклад возможно приведет к уменьшению разрыва между мощью синтаксиса Scala и текущей (седьмой) версией Java как языка программирования. Хотя конечно, даже со всеми новшествами восьмерки Java будет сильно отставать от Scala.

    JDK с “Lambda Project” можно скачать c официальной страницы.
    Также в текущей сборке JDK 8 (на момент написания статьи) лямбды уже тоже есть, но API с коллекциями еще не полностью завершены.

    Целью данной статьи не написание учебного пособия по новым функциям Java, думаю этой работой должны заниматься ребята из Oracle. Здесь я хотел сделать небольшие заметки для себя на будущее вместе с небольшими примерами кода, к которым хотелось бы вернуться после официального выпуска JDK 8.

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

    Мои опыты

    Один из самых часто встречаемых примеров в интернете, демонстрирующих пользу от использования лямбды — замена старых добрых анонимных классов.
    Сравните. Это новый вариант:

       // Вот она, анонимная функция!
       Runnable r = () -> System.out.println("hello");
       Thread th = new Thread(r);
       th.start();
    

    Вот так по-старинке:

       
       Runnable r = new Runnable() {
            public void run() {
                System.out.println("hello");
            }
       };
       Thread th = new Thread(r);
       th.start();
    

    Естественно и логично применить такой подход для слушателей.
    Вот небольшой сниппет с формочкой и кнопкой.

    public class Main {
        public static void foo(ActionEvent e) {
            System.out.println("hello:" + e);        
        }
    
        public static void main(String arg[]) throws Exception {
            JFrame frame = new JFrame("Demo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JButton button = new JButton("Hello");
            // магия происходит здесь
            button.addActionListener((ActionEvent e)-> { foo(e); });
    
            frame.getContentPane().add(button, BorderLayout.CENTER);
            frame.pack();
            frame.setVisible(true);
        }
    }

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

        // Можно присвоить listener-у
        ActionListener listener = (ActionEvent e)->{ foo(e); };
        // а вот так не скомпилируется ;)
        //Object o = (ActionEvent e) -> { foo(e); };
        button.addActionListener(listener);
    

    Или даже можно сделать так:

            
       button.addActionListener(Main::foo);
    

    Главное никаких отражений, используется invokedynamic.

    Естественно возникает желание посмотреть на API коллекций.

    Можно использовать в качестве Comparator-а функцию сортировщик:

      
       String arr[] = {"a","b","c"};
       Arrays.sort(arr, (x, y) -> x.compareToIgnoreCase(y));
    

    Также в Java 8 будет реализация многопоточной сортировки:

      
      String arr[] = {"a","b","c"};
      Arrays.parallelSort(arr, (x, y) -> x.compareToIgnoreCase(y));
    

    Функциональщики как раз любят такие многопоточные методы. К сожалению, на моих тестах в используемой версии JDK 8 от использования parallelSort польза была только на примитивных данных (например при сортировки массивов int-ов). На массивах с объектами никакой пользы не было, но ведь и релиз только через несколько месяцев, так что сейчас никаких серьезных тестов скорости проводить некорректно.

    Итог

    Думаю многие согласятся, что восьмерка не скоро будет тотально доминировать на серверах и использоваться в промышленной эксплуатации, поскольку существует довольно большая прослойки особо консервативных Java-программистов. Тем не менее функциональщина сейчас в мировом программистком тренде, поэтому Java 8 это безусловно интересно и имеет смысл потратить в дальнейшем дополнительное время на её изучение.

  • Java. Примеры копирования файлов. Эволюция и революция.

    Задачка копирование файлов в свое время была хорошим тестом для программистов.

    1. Streams.

    До появления пакета NIO (New I/O, версия Java 1.4) многие использовали обычные потоки.

        public static void copy(File source, File dest) throws IOException {
            FileInputStream is = new FileInputStream(source);
            try {
                FileOutputStream os = new FileOutputStream(dest);
                try {
                    byte[] buffer = new byte[4096];
                    int length;
                    while ((length = is.read(buffer)) > 0) {
                        os.write(buffer, 0, length);
                    }
                } finally {
                    os.close();
                }
            } finally {
                is.close();
            }
        }
    

    2. New I/O

    В 2000-ном году появился пакет java.nio. Акроним NIO означает New I/O (новый ввод/ввывод). Отчасти я согласен с мнением, что название было выбрано не очень удачным, т.к. не сложно было предположить, что пройдет время и будет нелепо называть новым пакет 12-летней давности.

    С помощью NIO копирование файлов смотрелось более изящно, решение эволюционировало следующим образом:

        public static void copy(File source, File dest) throws IOException {
            FileChannel sourceChannel = new FileInputStream(source).getChannel();
            try {
                FileChannel destChannel = new FileOutputStream(dest).getChannel();
                try {
                    destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
                } finally {
                    destChannel.close();
                }
            } finally {
                sourceChannel.close();
            }
        }
    

    Легко видеть, что здесь мы избавились от цикла, используем “новое” API и сократилось количество кода.

    3. Apache Commons IO.

    Тем не менее, многих ленивых программистов такое развитие не особо впечатлило и те кто знал, продолжил использовать Apache Commons IO.

        public static void copy(File source, File dest) throws IOException {
            FileUtils.copyFile(source, dest);
        }
    

    Единственным неудобством была необходимость в дополнительной сторонней библиотеке. Тем не менее, поскольку библиотека предоставляла программистам еще много другого удобного API для работы с I/O, по моим наблюдениям файл commons-io-*.jar стал присутствовать во многих крупных проектов того времени.

    4. Java 7.

    Революция произошла с выходом Java 7, релиз который был сделан уже Oracle, а не Sun Microsystems.
    Появился класс Files, с помощью которого копирование файлов стало не намного сложнее чем commons-io:

        public static void copy(File source, File dest) throws IOException {
            Files.copy(source.toPath(), dest.toPath());
        }
    

    При этом не нужно прописывать в мавене дополнительную зависимость.

    Понятно, что это доступно только для Java 7 и предыдущие ее версии во всю используются многими компаниями. Тем не менее, в связи с недавней новостью о том, что Oracle выпустил недавно свое последнее публичное обновление для Java 6, возможно многие все-таки будут постепенно переползать на семерку.

  • Java Security Update (Java 7u13)

    Вышло долгожданное обновление Java!

    Java
    Oracle выпустил релиз даже раньше запланированного срока (изначально должен был выйти 19 февраля 2013г).
    В анонсе сказано, что обновление содержит 50 исправлений безопасности:

    Due to the threat posed by a successful attack, Oracle strongly recommends that customers apply CPU fixes as soon as possible. This Critical Patch Update contains 50 new security fixes across Java SE products.

    Как обычно, обновление можно скачать с сайта java.com (JRE) или с сайта oracle.com (JDK, JRE и все остальное).

  • Липкий запуск сервисов в Android-e.

    В Android API есть такой абстрактный класс как Service. Он является наследником ContextWrapper-а, который в свою очередь является наследником Context-a. При некоторых допущениях можно относиться к сервисам как к “активити без UI” (хотя это не совсем правильно в деталях). Использовать сервис рекомендуется для задач не требующих прямого вмешательства пользователя.

    В документации особо акцентируется внимание на том, что Service не является ни процессом, ни ниткой. Если сервис должен делать какую-то “тяжелую” работу, то нужно самому выносить ее в отдельный thread, чтобы не получить ANR (Application Not Responding).

    Если делать свой thread лениво, то можно использовать готовый класс для асинхронной работы IntentService.

    Про него нужно знать следующее:

    • IntentService наследуется от Service.
    • Является абстрактным классом.
    • Нужно реализовать в нём метод onHandleIntent(Intent).
    • Обработка intent-ов идёт поочередно, но не в главном, а в своем выделенном thread-e.

    Диаграмма классов сервисов выглядит следующим образом: (далее…)

  • Андроидная венгерско-верблюжья нотация

    Для разработчиков OC Android, как и для других серьёзных программистов, существует соглашение по оформлению кода.
    В целом оно совпадает с соглашением в обычной Java. Как именно нужно оформлять, можно прочитать на официальной странице для Android разработчиков.

    Привожу краткую справку по наименованию полей класса:

    • НЕ паблики и НЕ статики должны начинаться с “m” (анг: Non-public, non-static field names start with m).
    • Статики с “s” (Static field names start with s).
    • Все остальные – со строчной буквы (Other fields start with a lower case letter).
    • Константы – БОЛЬШИМИ_БУКВАМИ (Public static final fields (constants) are ALL_CAPS_WITH_UNDERSCORES).

    Активно используется верблюжий регистр (Camel Case).

    Пример с официального сайта:

    public class MyClass {
        public static final int SOME_CONSTANT = 42;
        public int publicField;
        private static MyClass sSingleton;
        int mPackagePrivate;
        private int mPrivate;
        protected int mProtected;
    }

    Наверное, гугл не был бы гуглом, если бы не внёс изменения в стандартные соглашения Java. Очень активно используются префиксы.
    Для обычных полей “m” (возможно от англ. member), а для статических полей – “s” (static).
    Это очень похоже на венгерскую нотацию.

    Занятный факт, если пройтись grep-ом по исходникам Android-a, можно найти места, где эти конвенции не соблюдаются. Например статические поля имеют префикс “m”:


    sources/adndroid-16

    ./android/app/ActivityThread.java: static ContextImpl mSystemContext = null;
    ./android/app/SearchManager.java: private static ISearchManager mService;
    ./android/bluetooth/BluetoothTetheringDataTracker.java: private static String mIface;
    ./android/content/res/Resources.java: /*package*/ static Resources mSystem = null;
    ./android/content/res/Resources.java: private static boolean mPreloaded;
    ./android/database/DatabaseUtils.java: private static Collator mColl = null;
    и т.д.

    Непонятно, почему так получилось. Обычно проверка правильности оформления исходного кода в крупных организациях автоматизирована.
    Тем не менее, хотя принцип догфудинга по оформлению исходников гуглом соблюден не в полной мере, думаю, это не оправдание для других Android-программистов нарушать правила.

    UPD! Нужно уточнить, правила действительны для контрибуторов AOSP. То есть тех, кто пишет исходники Андроида.

  • Тренды программистских вакансий на indeed.com

    Пару дней назад прочитал интересную статью на dzone.com с занятными графиками, которые показывали количество вакансий для программистов.

    В статье были опубликованы данные с сайтов: indeed.com и simplyhired.com

    Оба сайта имеют русскоязычный интерфейс, поэтому надеюсь, что приведенные графики отображали не только данные по США (как часто бывает), а мировые тренды.
    Хотя может быть это и не так. К сожалению, не нашел способа получить картинки локализованные под Россию (или Москву).

    Меня в первую очередь конечно интересовала java, а также близкие или “конкурирующие” языки программирования.
    Поэтому в отличие от оригинальной статье на dzone я оставил в графике от indeed.com только такие языки как: java, C++, C#, objective c (убрал Perl и Visual Basic).

    Получилась такая картинка: (далее…)

  • Примеры работы с JMeter в картинках

    Приблизительно раз в год у меня возникает необходимость проводить пробное нагрузочное тестирование очередного проекта. Раньше приходилось сталкиваться с этой задачей чаще, но сейчас больше времени уходит на разработку под мобильные платформы (Android и т.д.) или создание программного обеспечения для решения внутренних инфраструктурных задач клиентов.


    В итоге каждый раз я судорожно вспоминаю как работать с jmeter-ом. Скачиваю, запускаю и полдня вспоминаю как его настраивать.

    Сразу оговорюсь, я не профессиональный тестировщик и проверка работы веб-приложений под нагрузкой не входит в мои прямые обязанности.
    Поэтому фраза “возникает необходимость” скорее нужно понимать не как приказ начальника, а “мне очень любопытно посмотреть, что случиться если…” (особенно если учесть, что начальника у меня нет, но про это в другой раз).

    Лет 10-15 назад на одной из своих первых работ для задач нагрузочного тестирования мы использовали утилиту, которая кажется так и называлась стресс-тул (вроде даже микрософтовская). Она была простая и интуитивно понятная. Только я ее уже 10 лет не видел и не знаю, использует ее кто-нибудь еще сейчас.

    Последние несколько лет пользуюсь JMeter-ом (или облачными сервисами). Пользовательский интерфейс JMeter-а (если с ним не работать регулярно) совсем не интуитивно понятный. Без прочтения документации или просмотра обучающего фильма очень сложно сделать даже самый простой тест (скажем 1000 запросов к одному URL-у).

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

    Итак. (далее…)