четверг, 23 марта 2017 г.

English Intermediate в skyeng (done)

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


    Кстати, мне недавно попался отличный сервис в сети https://www.italki.com/i/AcAbaB (это инвайт - по нему каждый получит плюс 10$ в копилку), где можно беседовать и учиться (за денежку) с носителями языка. По скайпу, разумеется. Но в отличие от школы, во-первых, там можно очень динамично формировать график занятий, во-вторых, общаться с разными людьми, а вот в-третьих (что не очень хорошо с точки зрения учёбы) у каждого преподавателя своя программа, так что иногда сложно ориентироваться. Но как возможность поработать над speaking - великолепно.

   НО! Для реальной работы мой текущий уровень мал. И надо отдать должное, я это прекрасно понимаю сам. Поэтому изучение продолжается. Впереди upper.


среда, 22 февраля 2017 г.

Java 8 example: two String arrays to one Set with Streams


Just an example


@Test
public void testArraysToStream() {
    String[] s1 = null;
    String[] s2 = null;
    Set<String> res = Stream.of(s1, s2)
                .filter(Objects::nonNull)  // <-- Filter out null values
                .flatMap(Stream::of)
                .collect(Collectors.toSet());
    Assert.assertNotNull(res);
    Assert.assertEquals(0,res.size());


    s1 = new String[]{"1","2"};
    Set<String> res2 = Stream.of(s1, s2)
                .filter(Objects::nonNull)  // <-- Filter out null values
                .flatMap(Stream::of)       // two arrays to one stream
                .collect(Collectors.toSet());
    Assert.assertNotNull(res2);
    Assert.assertEquals(2,res2.size());
    s2 = new String[]{"3","4"};
    Set<String> res3 = Stream.of(s1, s2)
                .filter(Objects::nonNull)  // <-- Filter out null values
                .flatMap(Stream::of)       // two arrays to one stream
                .collect(Collectors.toSet());
    Assert.assertNotNull(res3);
    Assert.assertEquals(4,res3.size());
    Assert.assertNotNull(res3.iterator().next());
}

вторник, 7 февраля 2017 г.

Что такое стратегия использования SVN

    На днях коллега поинтересовался - какая стратегия SVN используется у нас при работе с хранилищем. Ответить было нечего, так как это понятие начисто стёрлось у меня из памяти. Хотя как выяснилось при дальнейшем поиске информации, я об этом когда-то читал.
    Смысл термина "стратегия использования SVN" в том, как именно в хранилище sVN именуются каталоги(branches и tags) проекта, а также когда и куда сливаются(merge) ветки.

    Описание типового шаблона из руководства svn: SVN.Ветвление и слияние.Типовые примеры
    Хорошее простое изложение с примерами можно посмотреть тут: Стратегии использования SVN

    Я для себя сформулировал смысл так:

    Простой случай (то, что используется у нас):
- для ошибок и фич создаётся branch, и потом эта ветка сливается в trunk;
- при фиксации, создаётся tag.

    Более сложный случай (как-раз описан в руководстве svn):
- для релиза создаётся branch (1.x-stable);
   -- здесь правятся ошибки этого релиза
   -- для каждой передачи всё фиксируется в tags (1.x.1, 1.x.2)
   -- всё сливается в trunk
- для новых фич создаётся новая ветка (1.(x+1))
   -- здесь ведётся разработка новой функциональности
   -- сюда сливается всё из trunk (чтобы попали исправления ошибок из релизов)
   -- в конце эта ветка сливается в trunk
   -- на основе trunk после этого создаётся новый tags/1.(x+1)
 
Для себя сделал ещё напоминающую табличку:


вторник, 10 января 2017 г.

Free books from O’Reilly. 2016

Отличная подборка бесплатных книг от издательства O’Reilly за 2016 год

https://lifehacker.ru/2017/01/09/free-oreilly-ebooks/  (ссылки на тематические подборки)

Прямая ссылка на раздел с книгами о разработке ПО

http://www.oreilly.com/programming/free/

Архив бесплатных книг за предыдущие годы

http://www.oreilly.com/data/free/archive.html

вторник, 25 октября 2016 г.

Формат даты-времени в параметрах функции, в mvc-контроллере spring

При получении параметра из query-строки в http-запросе, можно задать шаблон для даты-времени (по умолчанию это ISO).
Задаётся аннотацией org.springframework.format.annotation.DateTimeFormat с указанием шаблона.

Пример


@RequestMapping(path = "/test", method = RequestMethod.GET)
public List<MyObject> getTest(
  @RequestParam(name="in_baseDateTime") @DateTimeFormat(pattern="dd.MM.yyyy HH:mm:ss") LocalDateTime baseDateTime){...}

вторник, 18 октября 2016 г.

Тест junit с hamcrest с проверкой коллекции на содержание чего-либо

Часто, я первой проверкой на коллекции в unit-тесте, ставлю простое определение есть ли что-то там или нет.

Обычно (по ленивой привычке) я делал это примерно так:


@Test
public void testNotEmptyList(){
    List<String> list = Arrays.asList("item_1","item_2");
    Assert.assertNotNull(list);
    Assert.assertTrue(list.size() > 0);
}

Но тут решил попробовать Hamcrest matchers и почему-то не сразу понял как там сделать такого рода проверку с коллекциями. Без коллекций всё достаточно понятно, а вот именно с коллекциями как-то не сразу въехал. Но в результате получилось вот так:

...
import org.hamcrest.collection.IsEmptyCollection;
import static org.hamcrest.CoreMatchers.*;
...
@Test
public void testNotEmptyList(){
    List<String> list = Arrays.asList("item_1","item_2");
    Assert.assertThat(list, notNullValue());
    Assert.assertThat(list, not(IsEmptyCollection.emptyCollectionOf(String.class)));
}

Версия Hamcrest должна быть не меньше 1.3

пятница, 30 сентября 2016 г.

Сертификация OCA Java SE 8 Programmer (1Z0-808). Complete

Сегодня сдал Oracle Certified Associate, Java SE 8 Programmer I (1Z0-808) 
(Результат 90%)
С одной стороны хорошо, а с другой - это только часть экзамена :)
В любом случае, полезно.  Но в нём только базовые знания, более глубоко в части II. Посмотрим, может и до неё доберусь.

Готовился со средней интенсивностью около 3-х месяцев. Пользовался следующими вещами:
Книга: 
Тесты:
  - всё, что бесплатно нашёл в интернете
  - книжка "OCA: Oracle Certified Associate Java SE 8 Programmer I Study Guide: Exam 1Z0-808" ( в ней, кстати, указано где тесты можно взять)
  - набор тестов http://enthuware.com/ (10$)

Этого, на мой взгляд вполне достаточно для успешной сдачи.


четверг, 25 августа 2016 г.

Смешная и грустная цитата из Кобьелла

Просто цитата:

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

Клаусс Кобьел (это тот, что написал "Мотивация в стиле экшн")

понедельник, 18 июля 2016 г.

Русские буквы в имени файла, отдаваемого сервлетом

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

Решение
Имя файла должно быть закодировано  javax.mail.internet.MimeUtility.encodeText()

Т.е. пример должен выглядеть как-то так:

response.setHeader("Content-Type", "application/file; charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename="+ MimeUtility.encodeText(dataFilePath.getFileName().toString()));

response.getOutputStream().write(FileUtils.readFileToByteArray(dataFilePath.toFile()));



понедельник, 30 мая 2016 г.

Напоминалка: ссылка на статическое поле в jаvadoc

Чтобы каждый раз заново не вспоминать, как ссылаться на статическое поле(константу) в javadoc-е:

/**
*  Ссылка на описание внешней константы {@link ru.pevgen.test.Consts#MY_CONST} в документации
**/

четверг, 5 мая 2016 г.

GreenMail - простая библиотека для unit-тестирования получения/приёма email в java (spring)

Собственно по теме, чтобы не забыть :  http://www.icegreen.com/greenmail/

Представляет из себя простой почтовый сервер (с разными протоколами  - pop,smtp,imap), который может быть внедрён в код и использован для простого тестирования кода, связанного с посылкой/приёмом email-ов.

Пример конфигурации и работы в тестовой spring-конфигурации

Фактически тут просто в тестовой конфигурации подменяется mail-сервер, на greenmail. А у самого greenmail-объекта есть методы для проверки того, что на него посылалось.
 
https://stackoverflow.com/questions/9661907/testing-greenmail-without-installing-a-smtp-server/9663399#9663399


import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.GreenMailUtil;
import com.icegreen.greenmail.util.ServerSetupTest; ...

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("ApplicationContext-Greenmail.xml")
public class EmailServiceIntegrationTest {

    /** Class under test */
    @Resource
    private EmailService emailService;

    private GreenMail greenMail;

    @Before
    public void startMailServer() {
        greenMail = new GreenMail(ServerSetupTest.SMTP);
        greenMail.start();
    }

    @After
    public void stopMailServer() {
        greenMail.stop();
    }

    @Test
    public void testPledgeReminder()
                throws InterruptedException, MessagingException {

        String mailText = "Hallo World";
        String mailSubject = "Hallo";
        String mailTo = "test@excaple.com";

        /** when: sending a mail */
        emailService.send(mailSubject, mailTo, mailText);

        assertTrue(greenMail.waitForIncomingEmail(5000, 1));
        Message[] messages = greenMail.getReceivedMessages();
        assertEquals(1, messages.length);
        assertEquals(mailText, messages[0].getSubject());       
        String body = GreenMailUtil.getBody(messages[0]).replaceAll("=\r?\n", "");
        assertEquals(mailText, body);       
    }

}
important: use port 3025
<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    <property name="javaMailProperties">
        <util:properties>
            <prop key="mail.debug">false</prop>
            <prop key="mail.transport.protocol">smtp</prop>
            <prop key="mail.smtp.port">3025</prop>
            <prop key="mail.smtp.auth">true</prop>
            <prop key="mail.smtp.user">test@mail.extern</prop>
            <prop key="mail.smtp.host">localhost</prop>
            <prop key="mail.smtp.from">test@mail.extern</prop>
        </util:properties>
    </property>
    <property name="username" value="test"/>
    <property name="password" value="xxx"/>
    <property name="defaultEncoding" value="utf8" />
</bean>
Then this configuration will configure a Spring JavaMailSender to send its mails to the GreenMail-Server started and finished by the test code.

четверг, 21 апреля 2016 г.

Создание среды для Unit-тестирования JavaScript с помощью Jasmine и Karma (в IntelliJ IDEA). Пошаговое руководство.


Технические средства


  • Node.js (https://nodejs.org) - программная платформа, основанная на движке браузера Chrome V8; позволяет выполнять JavaScript код
  • Karma (https://karma-runner.github.io) - настраиваемый движок, который позволяет запускать тесты (TestRunner)
  • Jasmine(http://jasmine.github.io/) - js-библиотека для unit-тестирования JavaScript
  • PhantomJS(http://phantomjs.org/)  - полноценный браузер на основе WebKit из консоли
  • IntelliJ IDEA(https://www.jetbrains.com/idea/) - IDE-среда для разработки (к сожалению, до сих пор в компании используется уже сильно устаревшая версия 13)
  • Плагины IntelliJ IDEA для Node.js и Karma - дополнительные модули(plugins) для возможности запуска тестов Karma-Jasmine в IDE

Установка в системе


1. Скачать установочный файл Node.js и установить всё по умолчанию (https://nodejs.org/en/ (Версия 5.x) )

2.  Проверить в Windows PowerShell (Все программы/Стандартные/Windows PowerShell/Windows PowerShell)

Команда: node -v

3. Установить библиотеки karma,jasmine,phantomjs в nodejs npm, для чего выполнить команды из под WindowsShell

    npm install -g karma
    npm install -g jasmine
    npm install -g jasmine-core
    npm install -g karma-cli
    npm install -g karma-jasmine
    npm install -g phantomjs-prebuilt
    npm install -g karma-phantomjs-launcher

Установка в IntellijIDEA(13)

В среде

1.Установить плагин Node.js

2. Установить плагин Karma

В проекте

1. Создать в проекте файл конфигурации запуска тестов для Karma, karma.conf.js  

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

Пример karma.config.js
module.exports = function(config) {
    config.set({
        basePath: '',
       // файлы, в которых находится исходный код, необходимые библиотеки, сами тесты
        files: [
            "./base/js/ext-4.2/ext-all.js",
            "./base/js/FormStik.js",
            "./base/js/isuprTrains.js",
            "./test/js/isuprTrains.Test.js"
        ],
        // указать конкретную библиотеку для тестирования
        frameworks: ['jasmine'],
        // если тестировать в phantomjs, т.е. без явного запуска браузера
        browsers: ["PhantomJS"]
    });
};

2. Создать тестовый класс с использованием jasmine, c именем <имя js файла>.Test.js (имя на самом деле не принципиально - оно настраивается в конфиге karma.config.js)

Пример jasmine- unit-теста
describe("First Test", function() {
    it("makes testing JavaScript awesome!", function() {
        expect(true).toBe(true);
    });
});

3. Создать запускающую конфигурацию в проекте


4.Выполнить конфигурацию (Run)

Результат выглядит приблизительно так:


среда, 13 апреля 2016 г.

Про то, как надо делать API

Попалась отличная статья(перевод) на хабре, о том, как надо делать REST API: Разработка web API (перевод)
Жаль, что я не прочитал её на несколько месяцев раньше, когда я переделывал некоторую функциональность на одном из проектов. Хотя приятно, что до некоторых идей получилось додуматься самостоятельно :)

Из интро выяснилось откуда ноги растут: "Это краткий перевод основных тезисов из брошюры «Web API Design. Crafting Interfaces that Developers Love» Брайана Маллоя из компании Apigee Labs"

В общем, читать и перечитывать, пока в голове не застрянет накрепко :)

четверг, 11 февраля 2016 г.

Мои последние достижения на coursera (Build Complete Web Solutions.The Hong Kong University of Science and Technology)

Решил поучиться новым технологиям в области frontend-a. А то что всё сервер да сервер. Хочется иногда чего-то "творческого" :)
На coursera пару месяцев назад началась специализация  Build Complete Web Solutions Гонконгского университета (якобы, номер 1 в Азии). Пока решил всю специализацию не проходить - да и не очень понятно зачем мне это - зато поучиться на отдельных курсах. К моменту начала coursera ещё не стала сильно жадной, и на ряде курсов можно было получить оценку, не покупая сертификат (последний курс прошёл уже без оценок).
В двух словах - интересно и познавательно. Буду пробовать дальше саморазвиваться в эту сторону.
А результат самих курсов, на данный момент, на картинке :


вторник, 9 февраля 2016 г.

Google Sheets. Копирование данных листа google sheet из одного документа в другой.

Дано

1. Документ-источник (google sheet), в котором ведутся некоторые данные.
2. Документ-приёмник (google sheet), в котром на одном из листов надо использовать данные из документа-источника.

Описание решения

В документе-приёмнике в скриптах, пишется код, который запускается регулярно триггером (в моём случае каждый час), и копирует полностью (т.е. накрывает/перезаписывает диапазон ячеек целиком) данные. А также и цветовые схемы (font,background colors) и примечания ячеек, входящих в диапазон.

Код скрипта

function readFomVolonteersQuestionnaire() {
  var RANGE_NAME = "A1:AT202";
  var DEST_SHEET_NAME = "Диапазон";
  
  // Документ - источник
  var spreadsheet = SpreadsheetApp.openById('13d...'); 
  
  var sheet = spreadsheet.getSheets()[0];     // лист с данными (первый в источнике)
  
  var range = sheet.getRange(RANGE_NAME);
  var values = range.getValues();
  var backgroundColors = range.getBackgrounds();// цвет фона
  var fontColors = range.getFontColors();// цвет текста
  var notes = range.getNotes();  // примечания

  
  // Текущий документ (приёмник данных)
  var ss = SpreadsheetApp.getActiveSpreadsheet();  // активный документ (из которого запускается скрипт)
  var SSsheet = ss.getSheetByName(DEST_SHEET_NAME);
  var ssRange = SSsheet.getRange(RANGE_NAME);
  ssRange.setValues(values);
  ssRange.setBackgrounds(backgroundColors);
  ssRange.setFontColors(fontColors);
  ssRange.setNotes(notes);  // примечания 
}

пятница, 4 декабря 2015 г.

Как сделать простую плановую рассылку, используя google sheets

1.Создать таблицу в google sheets
2.Заполнить столбцы : электронная почта(B) и текст(C)
3.Войти в редактор скриптов: Инструменты\Редактор скриптов
4.Код наподобие этого:
function sendEmails() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var startRow = 2;  // First row of data to process
  var numRows = 10;   // Number of rows to process
  // Fetch the range of cells A2:B3
  var dataRange = sheet.getRange(startRow, 1, numRows, 4)
  // Fetch values for each row in the Range.
  var data = dataRange.getValues();
  for (i in data) {
    var row = data[i];
    var name = row[0];  // First column
    var emailAddress = row[1];  // Second column
    if (emailAddress != '') {
      var message = 'Сообщение на русском языке: ' + row[1] + ' ::: ' + row[2] + ' ::: ' + row[3] ;//row[2];       // Третий столбец
      var subject = "Sending emails from a Spreadsheet";
      MailApp.sendEmail(emailAddress, subject, message);    
    };
  }
}
5.Настроить планировщик(триггер) регулярного запуска скрипта рассылки
  5.1.Инструменты\Редактор скриптов\Триггеры текущего проекта (кнопка с часами)
  5.2.Добавить триггер ("Триггеры не настроены.Нажмите здесь, чтобы добавить триггер")
    5.2.1 Выбрать нужную функцию (в нашем случае sendEmails), "динамичный", нужный таймер, регулярность
    5.2.2 Сохранить
    5.2.3 Дать разрешение(авторизацию) скрипту, которую он попросит при сохранении.

Это всё.

Примечания
Разумеется столбцы могут быть любые, а не только A и B - это отразится в индексах, в скрипте 

четверг, 5 ноября 2015 г.

Форматирование кода в блоге

Так как я не нашёл в "родных" средствах blogger, хоть какого-то форматирование кода, а некрасивый код вставлять надоело, то теперь использую простой до невозможности проект http://hilite.me/
Выбрал язык, вставил в левое окошко, нажал на кнопку, скопировал результат из окна. Короче, здесь копипаст рулит :)

Решение для "Unable to locate Spring NamespaceHandler for XML schema namespace"

Дано

Jar-файл, собранный с зависимыми библиотеками прямо внутри (это когда просят сделать весь проект в одном файле, и тогда сторонние библиотеки разжимаются и копируются в целевой jar в виде классов);
Конфигурация spring в xml-файлах, также внутри jar-а
Внешний проект запускает метод, в котором создаётся ApplicationContext spring-а.
Для сборки используется ant

Проблема

При попытке загрузить конфиг во внешнем проекта получаеv ошибку при создании ApplicationContext : "Unable to locate Spring NamespaceHandler for XML schema namespace"

Что дали поиски проблемы 
В двух словах, при сборке нескольких spring-библиотек в один файл, перекрываются схемы и другие настройки, которые хранятся в META-INF/spring.* файлах, которые для каждой библиотеки спринга свои. Т.е. остаются в итоге те, что собирались последними - они просто накрывают предыдущие.

Источники

http://stackoverflow.com/questions/8523997/unable-to-locate-spring-namespacehandler-for-xml-schema-namespace-http-www-sp/8574629#8574629
http://stackoverflow.com/questions/23574979/creating-an-uber-jar-with-spring-dependencies (это уже почти решение)

Решение (быстрое)

По мотивам описанного на stackoverflow был сделан отдельный ant-скрипт, который создаёт общие META-INF/spring.* схемы и настройки. Затем эти файлы были добавлены в папку с META-INF, которая подкладывается в финальный jar при сборке.
А в процессе сборки jar-а, исключаются те spring-настройки, которые разжимаются из spring-библиотек.

Скрипт ant, который собирает из отдельных spring-настроек, всё в общие настройки для всех библиотек spring-а, которые используются в проекте.

<?xml version="1.0" encoding="UTF-8"?>
<project name="springschemamake" default="create.spring.schema.full">

    <taskdef resource="net/sf/antcontrib/antlib.xml" classpath="lib/ant-contrib-1.0b3.jar"/>

    <property name="lib.dir" value="${basedir}/lib"/>
    <property name="dist.dir" value="${basedir}/templib"/>
    <target name="create.spring.schema.full">

        <!-- iterate over the dependencies -->
        <for param="file">
            <path>
                <fileset dir="${lib.dir}">
                    <include name="**/*spring*.jar"/>
                </fileset>
            </path>
            <sequential>

                <local name="jar.name"/>
                <basename  property="jar.name" file="@{file}"/>
                <!-- put the spring.* jars into special sub-directories -->
                <mkdir dir="${dist.dir}/${jar.name}"/>
                <unzip dest="${dist.dir}/${jar.name}" src="@{file}">
                    <patternset>
                        <include name="**/META-INF/spring.*"/>
                    </patternset>
                </unzip>

            </sequential>
        </for>

        <mkdir dir="${dist.dir}/META-INF"/>
        <!-- build the concatenated spring.* files -->
        <mkdir dir="${dist.dir}/META-INF"/>
        <concat destfile="${dist.dir}/META-INF/spring.handlers" fixlastline="true">
            <fileset dir="${dist.dir}/" includes="*/*/spring.handlers"/>
        </concat>
        <concat destfile="${dist.dir}/META-INF/spring.schemas" fixlastline="true">
            <fileset dir="${dist.dir}/" includes="*/*/spring.schemas"/>
        </concat>
        <concat destfile="${dist.dir}/META-INF/spring.tooling" fixlastline="true">
            <fileset dir="${dist.dir}/" includes="*/*/spring.tooling"/>
        </concat>
        <concat destfile="${dist.dir}/META-INF/spring.factories" fixlastline="true">
            <fileset dir="${dist.dir}/" includes="*/*/spring.factories"/>
        </concat>

        <delete includeemptydirs="true">
            <fileset dir="${dist.dir}" includes = "**/*spring*/**" excludes="/META-INF/**"/>
        </delete>
    </target>
</project>

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