Thursday, July 12, 2012

Java Практика - Занятие 5

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

На этом занятии мы рассмотрели не все интерфейсы коллекций и возможные варианты их использования. Это еще предстоит в будущем. Пока что мы остановились только на интерфейсах Collection, List, Map. Также рассмотрели использование итератора для прохождения коллекции и возможного удаления элементов.

Домашнее задание для этого занятия:
  1. Добавить Map продуктов в класс Deal 
  2. Изменить методы getCost() и getSum(), чтобы они работали, используя Map продуктов. 
  3. Добавить Map свойств в Party вместо массивов keys и value. 
  4. Исправить методы ввода/вывода для работы с Map 
  5. Добавить возможность выбирать ранее введенный продукт при добавлении его в сделку.
Дополнительная задача для развития навыков программирования:
Написать программу, которая заполняет матрицу (двумерный массив) нулями и единицами так, чтобы получился рисунок песочных часов. Матрица обязательно квадратная. Размер матрицы пользователь вводит с консоли.
Например, для матрицы, размером 5х5, должен получиться такой рисунок:
1 1 1 1 1
0 1 1 1 0
0 0 1 0 0
0 1 1 1 0
1 1 1 1 1
Я также написал возможное решение этой задачи, если вдруг кому-то будет очень сложно. Скачать исходные файлы можно тут: JavaPractice05.zip (5,9 KB)

Чтобы откомпилировать и запустить этот пример, выполните следующие команды:
cd <каталог_куда_распаковали_архив>
cd src
javac *.java
java Program5 - это для запуска программы о сделках
java Program5Additional - это для запуска песочных часов 
Также, если Вы уже умеете работать со средой разработки Eclipse, то можете импортировать этот проект в нее и запустить. 


Ну и, собственно, видео занятия:

Read More...

Wednesday, July 4, 2012

Java Практика - Занятие 4

На четвертом занятии мы продолжили разбирать пример из предыдущего урока, немного усложнив его. Основное внимание в этот раз было уделено наследованию: класс Product мы сделали абстрактным и создали два его потомка. Также я показал, как можно использовать переопределение метода для уточнения логики в классе FotoProduct. Также немного поговорили об использовании констант в Java.

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

  • Написать классы FotoProduct и BotinkiProduct
  • Написать методы для расчета скидки
  • Написать метод для расчета стоимости продукта с учетом скидки
  • Добавить поля в классы Product и Party
Также, заданием является сделать программу рабочей после вышеуказанных изменений, а именно:
  • Добавить ввод отдельных продуктов
  • Добавить ввод информации о Party
  • Добавить вывод информации о Party
В качестве дополнительного задания можно сделать следующее:
  • Добавить вывод полей отдельных продуктов
  • Усовершенствовать ввод и вывод, чтобы был более приятным для глаз :)
Обновление: Я в очередной раз написал возможное решение этой задачи. Скачать исходные файлы можно тут: JavaPractice04.zip (4,8 KB). Запуск программы описан в предыдущем посте.

 Ну и собственно видео:


Read More...

Sunday, July 1, 2012

Java Практика - Занятие 3

На третьем занятии мы уже подошли к объектам и проектированию. Я рассмотрел создание программы с позиции объектно-ориентированного дизайна. Бегло прошелся по теме третьего урока из курса Java для тестировщиков, чтобы вспомнить, что такое объект и как с ним работать. Далее мы решали задачу, немного похожую на реальный пример: выделяли объекты, рисовали диаграммы и реализовывали методы. 

На этом занятии я также впервые упомянул про одну из очень полезных книг, а именно книгу по шаблонам проектирования: Приемы объектно-ориентированного проектирования. Паттерны проектирования ("Банда четырёх": Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидс). Я считаю, что каждый программист просто обязан изучить эту книгу и по возможности использовать шаблоны в своих программах. Конечно, это не легко будет делать сразу - понимание, где и какой шаблон лучше применять, приходит с опытом. Также, не расстраивайтесь, если Вы сразу не поймете эту книгу. Продолжайте изучать программирование и больше практикуйтесь писать программы - со временем Вы поймете, насколько мощный инструмент у Вас в руках. Однако, есть небольшое предостережение по поводу шаблонов проектирования: фокусируйтесь на простых решениях проблем, прежде чем сразу браться за применение сложных "рецептов" шаблонов. Так что не забывайте: Keep It Simple :)

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

На видео я вспоминаю про метод keyboard, который позволяет вводить данные с консоли, и который я обещал выслать слушателям. Итак, вот он: 
private String keyboard(String message) {
     System.out.print(message + ": ");
     Scanner scan = new Scanner(System.in);
     String rez = scan.next();
     scan.close();
     return rez;
}
Я также написал возможное решение этой задачи, если вдруг кому-то будет очень сложно. Скачать исходные файлы можно тут: JavaPractice03.zip (3,4 KB)
Чтобы откомпилировать и запустить этот пример, выполните следующие команды: 
cd <каталог_куда_распаковали_архив>
cd src 
javac *.java
java Program
Также, если Вы уже умеете работать со средой разработки Eclipse, то можете импортировать этот проект в нее и запустить. 

В качестве дополнительного задания, можно написать отдельные класс Keyboard, который будет содержать статические методы для ввода строки (String), целого числа (Integer) и дробного числа (Double). Методы по вводу чисел будет проверять, а число ли введено вообще, и выдавать сообщение об ошибке или требовать правильный ввод.

Ну и собственно видео:


Read More...

Saturday, June 16, 2012

Java Практика - Занятие 2

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

Перед просмотром этого занятия можно посмотреть Урок 4 из курса Java для тестировщиков, где я как раз рассказываю про объявление функций (методов класса), аргументы функций и возврат значений из них. Там, конечно, еще и много чего другого, так что Урок 3 тоже посмотрите, если не совсем понятно, что такое объекты и "с чем их едят".

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

Итак, задания для самостоятельной работы:
  • реализовать еще один алгоритм сортировки массива (отличный от того, что был реализован для предыдущего занятия)
  • реализовать алгоритм бинарного поиска элемента в отсортированном массиве.

Ну и собственно видео второго занятия, которое, кстати, было записано в FullHD :)

Read More...

Saturday, June 9, 2012

Занятия по Java

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

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

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

Итак, первое занятие из курса Java практика можно посмотреть ниже. Перед просмотром этого видео, рекомендуется ознакомиться с уроком 1 и уроком 2 из курса Java для тестировщиков. Обратите также внимание на комментарии ко второму уроку, где многие поправляли ошибки, которые я допускал. Вообще, некоторые комментарии очень даже хорошие и полезные, особенно от пользователя hazartilirot .

Задания для самостоятельной работы после первого занятия:
  1. Написать программу, которая выдает заданное число из последовательности Фибоначчи
  2. Написать программу, которая сортирует массив чисел.
Естественно, при написании программ не желательно использовать встроенные механизмы Java для сортировки или поиска числа Фибоначчи :)

Read More...

Tuesday, November 15, 2011

CDMA модем Huawei и Ubuntu Linux

В связи с жизненной необходимостью подключил себе услугу мобильного высокоскоростного доступа в интернет от провайдера, которым уже давно пользуюсь. Данный провайдер использует технологию CDMA, и для пользования высокоскоростным интернетом пришлось приобрести новый модем. Имя ему Huawei EC 306. Интересно это устройство тем, что при подключении к компьютеру оно распознается как флеш-накопитель, на котором находятся Windows-драйвера. Однако внутри устройства также находится SIM-карта оператора, и оно может работать как модем. Драйверов для Linux, естественно, нету, да они и не нужны. Необходимо всего лишь переключить режим работы устройства...


На Windows-системе все оказывается очень просто. На флеш-карте находятся драйвера. Установка запускается автоматически, когда подключается устройство. После установки будет доступно приложение, запустив которое можно подключаться к интернету. Приложение называется Mobile Partner, написанное все той же компанией Huawei, и видимо, распространяется с ее модемами, а разные операторы уже изменяют текст интерфейса и картиночки на свои.

На Linux-системе драйвера для модема не нужны вообще. Это универсальное последовательное устройство, с которым Linux умеет работать — все, что нужно, это настроить модем. В операционной системе Ubuntu такие настройки хорошо автоматизированы, а менеджер сетевых подключений даже умеет подключаться к моему оператору через выбранное устройство. Выходит, что нужно только заставить систему распознавать устройство как модем, а не как флеш-накопитель.


Можно установить программу Mobile Partner на Ubuntu. Вот здесь я, даже, нашел ссылку на скрипт установки (я скрипт не проверял, так что запускайте его на свой страх и риск!). А потом вот тут на ubuntuforums.org и еще вот тут на habrahabr.ru в комментариях я нашел, что устанавливать программу нет смысла. Достаточно указать системе, чтобы она переключала режим работы устройства. Необходимо выполнить следующие шаги:


  1. Открываем терминал и выполняем команду lsusb
    В результате получим список USB устройств, подключенных к компьютеру.
    ~$ lsusb
    Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

    Bus 004 Device 002: ID 046d:c018 Logitech, Inc. Optical Wheel Mouse
    Bus 003 Device 001: ID 12d1:1505 Huawei Technologies Co., Ltd.
    Bus 003 Device 002: ID 1d6b:0001 Linux Foundation 1.1 root hub

  2. В полученном списке находим модем и обращаем вниманием на его ID. Первые четыре символа (в моем случае это 12d1) — это идентификатор производителя. Вторые четыре (в моем случае это 1505) — это идентификатор устройства.

  3. Теперь выполняем в терминале следующую команду (все одной строчкой), заменив идентификаторы производителя и устройства на свои:


    echo 'SUBSYSTEM=="usb", SYSFS{idProduct}=="1505", SYSFS{idVendor}=="12d1", RUN+="/lib/udev/modem-modeswitch --vendor 0x12d1 --product 0x1505 --type option-zerocd"' | sudo tee /etc/udev/rules.d/45-huawei1550.rules

    После выполнения этой команды в каталоге /etc/udev/rules.d/ появится файл 45-huawei1550.rules, команды из которого будут прочитаны, при подключении устройства к компьютеру.

  4. Вынимаем устройство, вставляем его снова — и у вас уже не флешка, а модем, подключенный к компьютеру. Дальше все просто — правой кнопкой на значке сети, Редактировать подключения, закладка Мобильные подключения, Кнопка Добавить — выбираем свою страну, провайдера и все! :)


P.S. Немного о скорости для тех, кому интересно. Заявленная оператором скорость передачи данных в сети EVDO Rev.B+: загрузка до 14,7 Мбит/с, передача до 5,4 Мбит/с. В реальности, конечно, все зависит от загруженности сети, удаленности от базовой станции, и количества осадков в амазонской равнине. Тестируя связь в центре Киева в полдень, загружая ролики с youtube, файлы с ex.ua и т.д. скорость у меня прыгала от 1 до 6 Мбит/с, что очень даже недурно, как для мобильного интернета.


Read More...

Monday, October 24, 2011

javax.net.ssl.SSLException: bad_record_mac

While writing a java net application I've encountered an interesting problem, which solution was not very trivial. The task was to connect to one website, parse the output, and write extracted information to a file. At first glance the task is "a piece of cake", but the problem appeared at the stage of connecting to the web site. The site uses the https protocol, and I had to use something more complex than basic java's HttpURLConnection. I've tried to use java's HttpsURLConnection, but while connecting to the site I received the following exception, which got me stuck me for a while: javax.net.ssl.SSLException: bad_record_mac. Eventually the problem was solved and the solution is described below.

Firstly, I will describe classes that were used to perform the connection. I've decided not to use internal java api directly and to look for some 3-rd party library, because besides connecting to the site, I had to execute some post and get queries to get required information and I wanted to do that with less pain. I chose to use the HttpClient library from Apache commons project. Here is the basic connection example that uses that library:

HttpClient httpclient = new DefaultHttpClient();
try {
    HttpGet httpget = new HttpGet("http://www.google.com/");
    ResponseHandler<String> responseHandler = new BasicResponseHandler();
    String responseBody = httpclient.execute(httpget, responseHandler);
} finally {
    httpclient.getConnectionManager().shutdown();
}

However, it won't work with some https websites. It does work with many of them, but some of them fail with different ssl exceptions. The site I was connecting to firstly failed with the following exception:

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

That means that the certificates were not verified correctly. Therefore, I had to implement more complex solution to handle different SSL cases. Here you might look for some other 3-rd party library that will handle secure socket connections by itself, however you might not get the full control. You can use this advice from the HttpClient manual and implement everything on your own. Eventually, everything can work fine OR you might get the exception mentioned at the beginning. If you're lucky one - my congratulations. If not - keep reading :)

In order to get the better understanding I decided to implement everything based on HttpClient and then debug it to see where it fails. I didn't care about checking the certificates and trusting the connection and just wanted to get the page contents. I've used examples from this blog post that I found pretty interesting. Therefore, I've created MyConnectionFactory that extends SSLSocketFactory. It initialized the SSL context with my own TrustManager and then uses it to create secure sockets.

public static class MySSLSocketFactory extends SSLSocketFactory {
    private SSLContext sslContext = SSLContext.getInstance("SSLv3");
    public MySSLSocketFactory() throws Exception {
        super((TrustStrategy) null, new AllowAllHostnameVerifier());
        sslContext.init(null, new TrustManager[] { myTrustManager }, null);
    }
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) 
            throws IOException, UnknownHostException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

I created the implementation of TrustManager that basically does nothing in its methods - so it skipped any security check. In other circumstances its probably not a wise thing to do, but for my task that was enough, so I didn't want to complicate things.

TrustManager myTrustManager = new X509TrustManager() {
    public void checkClientTrusted(X509Certificate[] chain, String authType) 
        throws CertificateException {    }
    public void checkServerTrusted(X509Certificate[] chain, String authType) 
        throws CertificateException {    }
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
}

Then I put everything together by registering my socket factory for the port 443 connections and then creating the HttpClient with my connection manager. The code to setup HttpClient looks like this:

private static HttpClient setupHttpClient() throws Exception {
    SSLSocketFactory sf = new MySSLSocketFactory();
    SchemeRegistry registry = new SchemeRegistry();
    registry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
    registry.register(new Scheme("https", sf, 443));
    ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry);
    return new DefaultHttpClient(ccm);
}

With this code I was able to connect to my https website, but I started to get the exception javax.net.ssl.SSLException: bad_record_mac. And that's where all the fun started - looking into Internet and debugging to get the solution.

First of all, I've downloaded source code for HttpClient and started to debug to see where exactly the problem occurs. It was interesting to find out that the problem occurs when the getSession() method is called on SSLSocket. Java performs the SSL handshake and it fails. So, I went to the Internet to find the solution, because very likely the problem was solved before.

Quite interesting looks the following stackoverflow answer to similar question, which says that the problem could be due to the load balancing, when the MAC address changes during negotiation. It could be the reason that the problem occurs sometimes. However, in my case the exception appeared every time, so I continued to search.

Eventually, I found two different sources that pointed out for the reason and how to overcome it: one is the knowledge base article for JIRA client connecting to server, and another is last coderanch answer. The problem appears because Java tries all kinds of secure socket protocols (TLS, SSLv2, SSLv3, etc.) even if only one is supported by the server. This results in the aborted connection. Trapping this error can be hard if you don't have access to the server. But if not the load balancing, then the reason could be either unsupported protocol, or unsupported cipher algorithm.

The solution is to configure Java in such a way that it will use only one secure socket protocol for communication. Therefore, in both createSocket methods of MySSLSocketFactory I've added the following code after creating sockets:

((SSLSocket) socket).setEnabledProtocols(new String[] { "SSLv3" });
((SSLSocket) socket).setUseClientMode(true);

And it worked! That solved my problem. The handshake went fine, the connection went fine, and I was able to do my task. In conclusion, I can say, that while writing this blog post, I could not reproduce the problem. :) So, maybe, it really has something to do with load balancing - I didn't dig into it. In any case, debugging of SSL problems can be tough, so enabling Java net log by calling System.setProperty("javax.net.debug", "all"); can be very helpful.

The testing program with working example with SSL connection can be downloaded here: http://goo.gl/JFdw5

Read More...