Шаблонизатор mustache и Java.

mustache

В этом году решил изменить вековые традиции и в Java проектах начать использовать вместо велосити (анг. Apache Velocity) популярный хипстерский мусташ (анг. Mustache). Дело в том, что в обычной жизни я, как правило, обхожусь вообще без шаблонизаторов и в простых случаях использую регулярки (regexp-ы). Когда нужно использовать сложные шаблоны для генерации текстовых файлов, то подключаю велосити (просто потому, что "рука набита").

В этот раз нужно было что-то среднее. С одной стороны, не такое тяжеловесное, как велосити, а с другой стороны... не хотелось все делать руками. В итоге выбор пал на Mustache. В историческом обзоре на википедии написано, что изначально Mustache был сделан для рубистов. Тем не менее, позже он стал крайне популярен на фронтендэ у JavaScript-eров (и не только), и сейчас пользу от его использования сложно переоценить. Более того, если зайти на сайт Mustache, то можно узнать, что он реализован на 30+ языках программирования. Естественно Java также присутствует среди них. Если быть точным, то на сайте у них Java на десятом месте (между Objective-C и C#). Стоит отдать должное создателям java версии библиотеки. Хотя она занимает не первое место в списке, но находится, как и документация к ней, в весьма удовлетворительном состоянии. Установить библиотеку и начать с ней работу особого труда не составляет: jar-ик подключается через мавеновский репозиторий.

В качестве отличительных особенностей самого шаблонизатора можно указать следующие:

Во-первых, символами, обрамляющими метки-заполнители (placeholder-ы), являются фигурные скобки "{". Визуально они чем-то напоминают усы (анг. mustache), повернутые на 90 градусов.
Выглядит это так:

Hello {{name}}
You have just won {{value}} dollars!
{{#in_ca}}
Well, {{taxed_value}} dollars, after taxes.
{{/in_ca}}

Во-вторых, основная идея mustache состоит в logic-less подходе. Под этим авторы подразумевают отсутствие различных if-else конструкций, а также циклов. Другими словами, вот такие велоситивские штуки не пройдут:

## Пример для Veloctity
#if( $foo < 10 )
    Go North
#elseif( $foo == 10 )
    Go East
#elseif( $bar == 6 )
    Go South
#else
    Go West
#end

Процессинг шаблонов в таком случае становится очень простым.

1. Берем шаблон.
2. Передаем данные. В случае Java это обычный Map.
3. Смотрим на ключ. Проверяем значение.
3.1. Значение является строчкой? Показываем.
3.2. Значение является пустым списком, false или отсутствует? Не показываем.
3.3. Значение является список (точнее Iterable)? Проходим по каждому элементу списка и применяем для него правило.
3.4. Значение является Callable? Получаем функциональщину.

С таким подходом можно решить большинство прикладных задач. Как я уже писал ранее, документация на сайте находится в нормальном состоянии и дает ответы на основные вопросы.

В ней детально изложены различные практические аспекты.
Например:
- Что делать, если вы хотите эскейптить HTML символы? Или не эскейпить?
- Что делать, если вы хотите выводить что-то в случае отсутствия данных (Inverted section)?
- Что делать, если вы хотите делать какую-то "предварительную" обработку данных, перед показом?
и т.д.

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

Android Design Support Library

Наконец Google сделал эту библиотеку с материальными виджетами!

Важно!
Возможно в официальной документации developer.android.com ошибка.
Вместо:
'com.android.support:support-design:22.0.0'

нужно указывать:
'com.android.support:design:22.2.0'

Про Gradle для любопытных.

Предыстория.

Вот раньше был Ant. Простой и понятный инструмент для сборки проектов. Открываешь xml-ку и видишь: здесь мы хотим скомпилировать файлы, здесь скопировать всё в папку dist, а здесь сделать jar-ик.

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

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

Разобраться, как работает Maven; понять, что означают все эти тэги – было весьма затруднительно. Всё взаимодействие ограничивалось, как правило, запуском команды mvn clean install. Для многих это действие означало что-то похожее на взмах волшебной палочки с параллельным произнесением заклинаний: "Expelliarmus" или "Avada Kedavra".

Любая проблема, требующая каких-либо нестандартных исправлений в pom.xml, первым делом решалась поиском "нужного заклинания" в stackoverflow или Google. Главная причина недовольства, которое высказывали многие программисты, что не понятно как и в какой последовательности всё работает. Например, что нужно сделать, чтобы просто скопировать файлик и затем выложить его на ftp (или запустить обфускатор)?

Тем не менее, Maven постепенно занял свое место в умах людей. Кто-то из любопытствующих и упорных в итоге разобрался в его внутреннем устройстве. Кто-то просто свыкся. Но время идет, мода меняется. Находятся люди, для которых уже и Мaven - это неудобный и даже архаичный инструмент.

Время не щадит никого...
Читать далее...

Практикум по программированию. Beta.

Мы начинаем курс Java/Android в рамках программы Weekend Coding Lab.
Друзья из коворкинга убедили меня, что возможно это будет интересно и востребовано.

Во-первых Java сама по себе востребована, во-вторых разработка мобильных приложений/игрушек Android тоже много кому интересна.
Начинаем уже в ближайшую субботу. Группа небольшая, предварительно уже часть людей записалось, просто разместить объявление у себя в блоге забыл.
Исправляюсь...

ВНИМАНИЕ, АНОНС!
logo

Сейчас уже кажется закономерным, что являясь одним из старейших языков, Java ни на мгновение не теряет своих лидерских позиций на вершине наиболее востребованных технологий рынка разработки программного обеспечения.

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

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

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

Студент знай! 
      Java - это не только скучное корпоративное программное обеспечение для банков и заводов.
      Java - это язык программирования под Android!

Этим мы и займемся, освоив основные принципы и написав свое приложение под эту замечательную платформу.

Запись на курс по телефону: 8 925 508 59 48 (Ирина)
Занятия по субботам с 11:00 (4 ак. часа) в коворкинге.
Описание программы: http://goo.gl/iJbnAT

Про FOP, SVG, PDF и значение дизайна.

Коворкинг интересен тем, что в нем можно встретить интересных людей.
Следующая история произошла после краткой беседы с Димой Гарником, арт-директором небольшой дизайн-студии.
У Димы была идея создать простой сайт для автовизиток. Идея несложная, но интересная. Вы заходите на сайт, указываете номер телефона и сообщение (например: "Мешает машина? Звони!"). Затем вы получаете развертку, из которой можно собрать симпатичную машинку. Развертка - это PDF-файл, который можно распечатать на листе бумаги формата А4 и собрать. Самое главное: сборка идет как "оригами", т.е. без ножниц и клея, нужны только "прямые" руки и время.
В итоге получается такая штука:

car_2
Собственно, нужно было как-то реализовать генерацию этих разверток.

Так совпало, что Дима подошел и рассказал про свою идею именно в тот момент, когда мы с соседом пили кофе и вели досужие разговоры на тему: "что бы такого сделать интересного и не сложного". Димина идея показалась интересной и не очень трудоемкой.
Генерацией PDF-файлов мне уже приходилось заниматься в прошлом (хотя это и была, в основном, генерация документов и отчетов с использованием различных выборок из БД - принципиальной разницы я не видел).

В общем, я сделал эту штуку.

Про FOP, SVG, PDF

Приблизительный план, что и как нужно делать, в целом, был понятен сразу:

1. Берем рисунок в векторе.
2. Сохраняем его в SVG-формате.
3. Поскольку SVG - это обычный XML, то менять в нем содержимое (номер, сообщение, цвет и т.д.) несложно.
4. Прикручиваем преобразователь SVG → PDF.
5. Проверяем, что все это работает, и делаем к этому "обвес", который обрабатывает HTTP запросы и отдает пользователю PDF-файл.
6. Прикручиваем дизайн или интегрируем с текущим сайтом.

В целом, все прошло согласно плану. За исключением следующих моментов:

1. Проблемы со шрифтами.
Конечно, все зависит от SVG-файла, но, возможно, возникнут сложности с кириллическими шрифтами после развертывания на сервере (т.е. на Linux-е).
Решение: поставить недостающие (зависит от того, какие нужны) шрифты.
Например, как-то так:

apt-get install ttf-mscorefonts-installer

2. Еще раз проблемы со шрифтами.
У того, кто раньше работал с Apache FOP, могут возникнуть сложности в более тонкой настройке конфигурации.
Дело в том, что формат файла для настройки PDFTranscoder-а отличается от привычного fop.xconf!

Если кратко:

//Создает перекодировщик. Кроме PDF, если верить документации есть перевод в PostScript, EPS.
        Transcoder transcoder = new PDFTranscoder();
 
        // Если нужно "вшивать" свои шрифты, требуется дополнительная настройка
        try {
            DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
            Configuration cfg = cfgBuilder.buildFromFile(new File("pdf-renderer-cfg.xml"));
            ContainerUtil.configure(transcoder, cfg);
        } catch (Exception e) {
            throw new TranscoderException(e);
        }

Где "pdf-renderer-cfg.xml":

<?xml version="1.0" encoding="UTF-8"?>
<pdf-renderer>
  <fonts>
    <font metrics-url="file:C:/Dev/FOP/temp/fonts/FUTURAL.ttf.xml" kerning="no" embed-url="file:C:/Dev/FOP/Temp/fonts/FUTURAL.ttf">
      <font-triplet name="Futura Lt BT" style="normal" weight="normal"/>
    </font>
  </fonts>
</pdf-renderer>

Весь пример можно скачать с сайта Apache FOP.

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

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

Про дизайн.

Есть такая замечательная статья Learning to see (Учимся видеть)
В ней приводится следующая диаграмма:
chart

Как правило, чем более "программистская" контора, тем сильнее доминирует принцип - делаем "not pretty but functional", а затем дизайн (если остались деньги).
Все бы хорошо, но бывают заказчики, которым потом жалко тратить деньги на нормальный дизайн: им главное, чтобы работало. Как правило, это касается разработки внутренних систем. В целом, это нормальная бизнес-ситуация: лишних денег на "красивости" часто нет. Правда в том, что в итоге сотрудникам некоторых компаний приходится годами пользоваться унылым корпоративным ПО.

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

pod_steklom_bold

Без дизайна

Для сравнения, вот так он выглядит сейчас:

pod_steklom_beauty

С дизайном

С другой стороны, если поставить дизайн во главу угла, может получиться ситуация, когда дизайн есть, а функциональности нет.

Красиво выглядит? Да, бесспорно! Работает? К сожалению, нет. При этом могут пройти месяцы, пока из красивого получится работающее. Ситуация может усугубиться, если дизайнер "понапридумывает" разного, а это потом не будет работать или окажется невозможным реализовать.

Многие скажут: "К чему эти банальности? Это и так понятно!". Понятно, но хотел бы повторить: нормальный дизайн - это не опция, это неотъемлемая часть хорошего программного продукта. Такая же составляющая, как и его функциональность.

PS: Может кто-то знает нормальные курсы дизайна по UI/UX? Не про "сферического коня в вакууме", а про конкретные практики - как пользоваться инструментами. И не про общие принципы: что нужно выравнивать, что какие-то цвета плохо сочетаются и т.д., - про это многое уже известно.
Проблема в том, что иногда по мелочи нужно что-то сделать (например, у меня бывают вопросы, как в фотошопе кнопку перекрасить из серого в красный) и это вызывает определенные сложности. Спасибо соседям по коворкингу, что выручают (Николай, Надежда - это я про вас ;).
В общем, если кто-то из программистов, читающих мой блог, бывал на таких курсах - был бы рад услышать про них отзыв: стоит или нет.

PPS: Если, вдруг, какой-то дизайнер забредет на мой программистский блог - буду рад возможности сотрудничества. Пишите в комментариях ;).

Обновление времени в Java.

Заметка об обновлении времени, на которую у меня все никак не хватало времени. 1419292146_clock

Речь идёт о смене временных зон для Oracle JDK/JRE. Такие изменения могут быть вызваны например отменой летнего/зимнего времени, сокращением часовых поясов за счет их объединения и другими обстоятельствами.
Для этих целей можно использовать Timezone Updater Tool.

Чтобы выполнить обновление нужно выполнить следующие шаги:
1. Загрузить с сайта jar-ик (http://www.oracle.com/technetwork/java/javase/downloads/index.html).
tzupdater_download

2. Затем запустить из консоли как обычную java-программу с ключами -u -v:

java -jar tzupdater.jar -u -v
-u означает обновить (update)
-v для показа дополнительной детальной информации (verbose).

Естественно, если у вас несколько JVM, то сначала нужно разобраться, какую конкретно вы хотите пропатчить. Поэтому на всякий случай проверьте, что конкретно указано в bat- или sh-скриптах которыми вы запускаете сервер и какая именно java запускается.

PS: Перед запуском, еще раз прочтите внимательно инструкцию на официальном сайте, не забудьте проверить права доступа и наличие резервной копии (это общие правила, они касаются вообще любых сервисных работ проводимых на сервере).

Оборачиваясь назад.

Проекты бывают разные. Некоторые можно сделать за два дня, некоторые за месяц, некоторые длятся годами. Именно про последние хотел написать эту заметку.

Дело в том, что общаясь в среде различных программистов с завидной периодичность наблюдаю следующую сцену. Один разработчик рассказывает и показывает итоги своей работы другим программистам в надежде получить отзыв вроде: "Ну ты крууууут!", в ответ же он получает не возгласы восхищения и аплодисменты, а вопрос: "На что именно было потрачено столько времени? На ЭТО? Что тут такого делать, почему так долго?". После этой фразы начинаются жаркие споры, обиды, непонимание и обвинения в некомпетентности друг друга.

Хорошо когда такие беседы проходят в дружеской программисткой атмосфере. Гораздо сложнее, когда выяснение отношений происходит на другом уровне. Например, когда одна команда пытается подрезать заказ у другой, убеждая клиента в том, что если бы обратились к ним, то они дескать сделали бы все гораздо быстрее и без затягивания сроков. Что принятые решения изначально были нерациональными и т.д.

Более того, сами программисты спустя годы, оборачиваясь назад начинают думать: "Я потратил на это три/пять/семь лет своей жизни? Почему?! Как ЭТО заняло столько времени?"

Одной из причин, на мой взгляд, является не совсем точное представление о том, как оценивается сложность проекта. Для многих это прямая из точки А в точку B.
Пред глазами предстает следующая картинка.
ab

На самом деле, это идеальная картина. В жизни разработка сложного проекта сопровождается решением многих неучтенных проблем. Возникают "развилки" на которых нужно принимать решение куда двигаться дальше. Это могут быть решения высокого уровня, такие как выбор языка (java, c#, python или всё вместе) или способ хранения данных (mysql, oracle, berkley db, mongodb, hazelcast или все вместе), так и более низкого уровня - какой веб-фреймворк выбрать (ext или gwt, или может быть JSF 2 и т.д.), прикрутить velocity или обойтись стандартными средствами для работы со строками, начать использовать более популярный graddle или остаться на maven-е (или даже ant-e), использовать AnglularJS или не стоит.

Таких "точек бифуркации"  в большом проекте может быть несколько десятков или даже сотен. При этом важно понимать, что все могут ошибаться и иногда приходится возвращаться на исходную позицию, менять стратегию, платформу (или как говорят программисты "переписать половину кода"). Кроме этого цель из точки B может передвинуться в точку B' и в результате некоторые принятые решения уже могут оказаться неподходящими.
Другими словами лучше описывает ситуацию следующая картина.
ab_2

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

Конечно более сложный случай, когда нет хороших проторенных "дорог". Например, если это принципиально новая разработка. В таком случаях утверждение "Что он тут такого делает уже N-цатый год?", звучит аналогично претензии к Колумбу: "Что тут такого? Здесь и ежу понятно, что нужно просто плыть на запад и попадешь в Америку". Сегодня это кажется очевидным, а тогда найти средства на подобную авантюру было не так уж и просто.  Опять-таки в итоге Колумб все-таки ошибся где-то в три с половиной раза (почти на Пи), ведь изначально он хотел попасть в Индию, а она намного дальше...

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

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

P.S. В качестве иллюстрации нарисовал дерево, на развилках которого выбирается один вариант и подсвечивается красным цветом. При нажатии мышкой на дерево, оно случайным образом перестраивается.
Приятного просмотра!

P.P.S. Дерево прорисовывается с помощью языка программирования processing. Собственно экспериментами с ним, а также arduino и raspberry pi сейчас посвящены воркшопы, которые мы проводим вместо проводимых ранее Scala-тусовок.


HTTPS авторизация по сертификату

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

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

Более распространен такой способ авторизации не в клиент-серверных решениях, а скорее в межсерверном взаимодействии. Например при решения задач в сфере B2B, когда необходимо отправлять запросы к различным серверам контрагентов и внешним системам. Отчасти это связанно с тем, что одним из популярных способов создания таких коммуникаций является использование веб-служб, что в свою очередь означает программную отправку HTTP запросов. Поскольку внутренняя реализации JAX-WS, базируется на использовании стандартных классов (URL, HttpURLConnection и т.д.), решив задачу в общем виде (отправка https запросов с авторизацией по сертификату) автоматически решается задача для клиента веб-службы (речь идет о JAX-WS, в Axis2 задачу решать можно немного другим способом).

Самое простое что можно сделать для решения этой задачи — указать ключи и пароли в системных свойствах:

-Djavax.net.ssl.keyStore=privateKey.jks
-Djavax.net.ssl.keyStorePassword=myPrivateKeyPassword
-Djavax.net.ssl.trustStore=truststore.jks
-Djavax.net.ssl.trustStorePassword=myTrustStorePassword

В данном случае в файл privateKey.jks вы можете положить свой приватный (закрытый) ключ, с помощью которого будет проходить аутентификация на сервере и (при необходимости) в файл truststore.jks положить сертификат сервера, к которому идет обращение.

Хранилище ключей может иметь тип не только JKS (Java Key Store), но например быть в более распространенном формате PKCS12. В таком случае в настройках следует указать тип хранилища:

-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.keyStore=privateKey.p12                
-Djavax.net.ssl.keyStorePassword=myPrivateKeyPassword

Очень хорошо описаны отличия в использовании JKS и PKCS12 в статье Java 2-way TLS/SSL (Client Certificates) and PKCS12 vs JKS KeyStores.

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

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

Общая последовательность шагов будет выглядеть следующим образом.
1. Получить хранилище ключей.
2. Создать объект класса менеджера ключей.
3. Создать объект управляющий доверенными сертификатами.
4. Произвести инициализацию ssl-контекста.

Теперь нужно разобраться, кто это такой "менеджер ключей" и "управляющий доверенными сертификатами", а также с кем еще возможно придется столкнуться. Для этого приведу сильно упрощенную диаграмму классов:
sslcontext

Из диаграммы легко видеть как можно управлять поведением работы программы. Например, чтобы поменять логику выбора алиаса, можно сделать наследника класса менеджера ключей (KeyManager).
Для этого вначале нужно получить хранилище ключей (KeyStore), а дальше сделав своего наследника, который будет работать с ключами, передать его в метод для инициализации SSL контекста. Самый простой способ сделать такого наследника — получить менеджера ключей по-умолчанию, а затем обернуть его методы таким образом, чтобы основные методы "проксировались" и в то же время можно было перекрыть нужный метод со специфической логикой (выбор алиас, отслеживание какой ключ/принципал используется и тд).

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

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

 
/**
 *
 * @author Vit vit@programmisty.com
 */
public class Demo {
 
    public static void main(String[] args) throws Exception {
        SSLContext sc = SSLContext.getInstance("SSL");
 
        // Каким-то образом получили хранилище ключей. Это за рамками статьи.
        KeyStore keystore = ... ;
 
        String algorithm = KeyManagerFactory.getDefaultAlgorithm();
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm);
        // не забываем инициализировать менеджера ключей
        keyManagerFactory.init(keystore, password);
        // получаем список менеджером (при необходимости делаем наследника и/или оборачиваем keyManager)
        KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
        // если у нас свой список доверенных серверов
        TrustManager[] trustManagers = getTrustManagers("/trusted.jks", "trustedPassword".toCharArray());
        sc.init(keyManagers, trustManagers, null);
        // проставляем контекст
        SSLContext.setDefault(sc);
        // для проверки отправляем запрос
        String url = "https://my-secure-server.com";
        try (InputStream in = new URL(url).openStream()){
            System.out.println(IOUtils.toString(in));
        }
    }
 
    /**
     * если у нас какой-то свой файлик с доверенными сертификатами
     */
    private static TrustManager[] getTrustManagers(String path, char[] passwd) throws Exception {
        String algorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
        // Загружаем доверенных
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        // Из ресурсов, так проще. 
        InputStream keystoreStream = Demo.class.getResourceAsStream(path);
        keystore.load(keystoreStream, passwd);
        trustManagerFactory.init(keystore);
        // 
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        return trustManagers;
    }
}

Заметки по Derby DB

Нельзя сказать, что к Derby DB у меня особо теплые отношения. Первое знакомство с ней произошло много лет назад, когда на работе возникла идея прикрутить Derby вместо полноценной базы данных, чтобы проще было готовить демку программы к выставке. Идея была в том, что если взять легковесную встраиваемую базу, то тогда развертывание демонстрационного дистрибутива сильно упростится — скопировал файлики и ничего настраивать не нужно (в отличие от Оракла). В случае если нам нужен всего-лишь выставочный демонстрационный образец ПО такое решение было вполне оправдано. Почему выбор пал в тот момент именно на дерби думаю сейчас мало уже кто вспомнит.
В итоге конечно всё прикрутить получилось, но скорость работы базы на тот момент оставляла желать лучшего. Возможно где-то я был не прав (был молодым и неопытным), а возможно и сама база была "юной" и не достаточно расторопной. derby_db_logo

С тех пор прошло много времени, Derby уже давно поставляется вместе с JDK под именем Java DB, поэтому думаю в жизни многих Java-программистов также возникали случаи совместной работы с этой удивительной базой данных. Собственно поэтому решил описать некоторые её капризы и особенности. Сразу хочу заметить, что эту БД использую в жизни не так часто и возможно именно поэтому ее поведение меня иногда удивляет.

1.Кидается исключениями при отключении.

Чтобы отключить БД в embedded режиме, нужно в JDBC-URL прописать "jdbc:derby:;shutdown=true". Если всё нормально, в вас обязательно при отключении кинут исключением SQLException с кодом XJ015. К этому нужно привыкнуть и не пугаться.

2.Режим использования RAM (In-memory).

У Derby есть не плохой экспериментальный режим, когда она работает в памяти.
Удобно использовать для создания временного окружения (чтобы не удалять созданные файлы и директории) или в различных jUnit-тестах.
Опять таки все делается через URL, например для создания пишем: "jdbc:derby:memory:myDB;create=true".

При этом если вы сделаете shutdown, но не потушите JVM, то ваша БД не почистится. Чтобы удалить данные из памяти нужно сделать сделать drop (jdbc:derby:memory:myDB;drop=true), который сам сделает shutdown:
You can shut down an in-memory database using the shutdown=true attribute before you drop the database, but this is optional. Dropping the database also performs the shutdown.

3.JRE7u51

В JRE7u51 поменялись ограничение в настройках безопасности. Поэтому при запуске дерби в сетевом режиме могут валиться исключения AccessControlException.
На официальной странице oracle предлагается решение, в котором необходимо настроить собственный security.policy файл, чтобы в нем был доступ к порту (по-умолчанию 1527). Например так:

grant {
    permission java.net.SocketPermission "localhost:1527", "listen";
};

Хорошая пошаговая инструкция на странице администрирования.

Распараллеливание задач в Java через InvokeAll

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

Сразу хочу заметить, что мне не очень хочется углубляться в описание всей мощи java concurrent API, а просто расставить некоторые акценты при работе над небольшой простой задачей. Она может возникнуть в жизни каждого программиста, он замечает некоторые независимые операции и у него появляется нестерпимое желание их распределить по нескольким потокам. Грубо говоря, у вас есть какой-то метод, который можно было бы безболезненно запихнуть в Runnable-ы, стартануть и подождать когда все закончат свою работу.

Понятно, что для этого может подойти invokeAll т.к. в описании про него явно сказано: "Executes the given tasks, returning a list of Futures holding their status and results when all complete."

Так вот, некоторые программисты не дочитывают последние слова и думают, что нужно самому контролировать процесс, ждать и "жать на тормоз", проверять все ли потоки завершились, периодически дергать в цикле future.get(), join-ить или делать другие различные телодвижения. Конечно так поступают не все, но тем не менее такое бывает. Для того, чтобы разобраться в том, что происходит на самом деле, достаточно взглянуть в базовую реализацию этого метода (AbstractExecutorService.java). Надо же пользоваться тем, что src.zip в JDK все еще продолжают подкладывать: Читать далее...