четверг, 3 марта 2016 г.

Легкий web-фреймворк с малым потреблением памяти

(Light web framework with minimal memory usage)

    Привет! 
    Начну с описания возникшей у меня проблемы.
    У меня есть виртуальны сервер на https://www.digitalocean.com/pricing/ за 10$ в месяц с такими характеристиками: 1Gb RAM, 1 Core CPU, 30 Gb SSD. На нем крутится несколько сайтов написанных на разных инструментах, но в основном это https://playframework.com/. Данный фреймворк хорош для написания серьезных веб приложений Энтерпрайз уровня без JavaEE. Я его использовал для написания простеньких сайтов из-за того, что не нашел лучшего средства на Java.

    Прямо говоря сайт-визитка на данном фреймворке в холостую использует 130-150Mb оперативной памяти, а у меня их несколько и соответственно память сервера загружена под завязку и я не могу там разместить еще приложения. Написав еще один сайт мне пришлось докупить сервер, но это все влетает мне в копеечку и я призадумался. Мне финансово стало необходимо заменить существующий фреймворк на другой с меньшим потреблением ресурсов. Тут я начал гуглить, и моя история началась!

    Первое на что я набрел - это Легкий web-фреймворк с малым потреблением памяти (специфическое железо), что и послужило названием данной статьи. Из данного ресурса вытекало, что веб-фреймворк с минимальным потреблением написан на python, но с ним мне работать не хотелось и поэтому я обратил внимание на один из комментариев в котором упомянули nodejs, что для меня послужило призывом к действию(javascript я знаю достаточно хорошо). Но Nodejs не является веб-фреймворком сам по себе и я начал гуглить дальше и набрел на http://nodeframework.com/ и https://github.com/showcases/web-application-frameworks из чего я вдруг решил, что Meteor это именно то, что нужно.

    Я начал переносить сайт на метеоровскую платформу, не совсем осознавая, что я переписываю все. Метеор все-таки отличается от обычного MVC web-фреймворка и он скорее подходит для написания одностраничных приложений со специфичным разделением клиентского и серверного кода. Т. е. если вы хотите написать одностраничник или несложное приложение под iOS и Android при этом используя один JavaScript, то это то, что нужно.

    Однако у меня было четкое разделение сервера и UI, причем UI делится на пользовательскую и административную части, что в метеоре потребовало бы гораздо больше времени на разделение, так как к примеру все стили компилились в один файл и возникли еще кое-какие трудности. Но это полбеды, так как я больше гнался за минимальным использованием ресурсов, я обнаружил, что у Nodejs с этим не все в порядке и легко можно получить утечку памяти(Understanding Node.js Memory Leaks), что могло бы вообще парализовать мой сервер, но я к этому не был готов.

    Вот одна из статей про использование памяти Nodejs https://strongloop.com/strongblog/node-js-performance-heap-profiling-tip/, т. е. там она достаточно сложно устроена, а мне бы с JVM разобраться получше. В общем, я отказался от этой затеи с Nodejs и соответственно Meteor пока отложил в сторонку. 

    Здесь я опять вернулся к первоначальной мысли, что веб-фреймворк с минимальным потреблением написан на python и решил, что делать нечего и как бы я не сопротивлялся нужно решать проблему! Здесь я загуглил https://wiki.python.org/moin/WebFrameworks/Немного тестов производительности сетевых фреймворковBenchmark of Python WSGI ServersComparison of Web Servers for Python Based Web Applications. Из всех моих поисков я выявил, что самый минималистичный не до веб-фреймворк это http://www.gevent.org/, который мало кто использует вообще. Из того, что используют можно сравнить Django c Flask как описано здесь Что выбрать или Django vs Flask? и здесь Python web framework.

    Опять-таки Django - это настоящий, полноценный веб-фреймворк со всем необходимым для написания сайтов разного уровня, но когда встанет вопрос производительности, то видимо придется в добавок использовать Flask, и да Django потребует памяти в разы больше чем Flask, точно не меньше, так что решать вам. С точки зрения поиска работы, то знание Django просто обязательно (я бы сравнил это как JavaScript программисту обязательно знание jQuery). 

    Для себя же я решил поискать, а нет ли java web-micro-фреймворка для создания простеньких приложений с минимальным функционалом. И да я все-таки кое-что накопал Java Micro Frameworks: The New Trend You Can't Ignore из которого был выбран для ознакомления http://sparkjava.com/. К сожалению, информации по минимальному потреблению памяти данным фреймворком я не нашел поэтому, когда проверю его в бою напишу сам!

    Всем спасибо, надеюсь, статья была полезной!

среда, 1 апреля 2015 г.

Валютно-фондовый виджет для Андроид. Курсы валют, акций.

Валютно-фондовый виджет для Андроид

    Привет! 
    Сегодня я расскажу о виджете для Андроид, который показывает курсы валют, биржевые котировки в реальном времени. Если вы следите за биржевыми показателями или просто интересуетесь финансами, то вам он точно будет полезен!

Снимок экрана с виджетом в центре
    
    Чтобы скачать виджет перейдите в Гугл Плей Маркет по ссылке: Google Play Market [currency-and-stock-widget]

    С помощью виджета, вы сможете отслеживать изменение: курса валют, цен на нефть и золото, акций, индексов. А также получать своевременно данные о котировках, которые вам интересны.

    Доступные функции:
    - Выбор и отслеживание множества котировок доступных на сайте http://finance.yahoo.com;    
    - Отслеживание курсов валют;    
    - Получайте обновления ваших финансовых котировок каждую минуту; 
    - Разнообразная цветовая гамма виджета;
    - Динамика изменений финансовых котировок в режиме реального времени. 


Снимок экрана с графиком изменения котировки на нефть марки Брент 

    Чтобы увидеть динамику изменений валют и финансовых котировок просто нажмите на нужную котировку на экране виджета.
    Вы видели как быстро изменился курс доллара с 30 рублей до 60 рублей! А если бы вы вовремя заметили динамики повышения курса доллара, обменяли рубли на доллары, а потом продали, то получили бы прибыль, а ваш деньги увеличились в 2 раза. Именно для этого и был написан этот виджет, поэтому не тратьте время и деньги, а скачивайте Валютно-фондовый виджет, чтобы всегда быть в курсе событий!
    Чтобы скачать виджет перейдите в Гугл Плей Маркет по ссылке: Google Play Market [currency-and-stock-widget]

    Если вам понравился виджет или вы хотите, чтобы добавили еще функций в данный виджет, то сообщите нам об этом, оставив отзыв.
    Чтобы оставить отзыв перейдите по ссылке: 
Оценить [Currency and Stock Widget]

суббота, 17 января 2015 г.

Android Unit тестирование. Настройка Robolectric в Android Studio + Gradle.

Настройка Robolectric в Android Studio не простоя задача, но решаемая!
Что мы имеем в начале:
1 - Установленную Android SDK и последнюю версию Android Studio;
2 - Созданный по умолчанию проект и написано немного код, который нужно тестировать.

    В коде приложения, есть функционал, который зависит от стандартных библиотек Java и может выполняться в JVM(Java Virtual Machine). Значит написанные для него Unit-тесты можно выполнить в самой JVM, без подключения Android устройства или эмулятора. Это ускоряет процесс разработки особенно, если вы используете методологию TDD(Test Driving Development). Для этого я выбрал фреймворк для Unit-тестирования - Robolectric, который используется многими Android разработчиками.
    Robolectric, также позволяет тестировать классы зависящие от Android SDK, такие как: Activity, Fragments и т. д.. И все это без подключения устройства или эмулятора, в вашей JVM!
Это ускоряет процесс разработки, Unit-тесты запускаются без устройства, здорово, не правда ли!? Но есть одна проблемка, чтобы этого добиться, придется повозиться с настройками, да ладно поехали.
    Как только вы создали проект, вы увидите подобную структуру и файл сборки build.gradle, что на рис. 1.
Рисунок 1. Структура приложения в Android Studio
    Перед тем как продолжить, нужно установить Android Studio Unit Test Plugin: https://github.com/evant/android-studio-unit-test-plugin

    После долгих поисков в интернете и неудачных попыток настроить Robolectric для работы в Android Studio, я таки нашел способ все настроить так, чтобы работало.
    Отправной точкой для меня послужил шаблон Android проекта для разработки через тестирование: https://github.com/robolectric/deckard-gradle
    Общий файл сборки build.gradle стал выглядеть так:
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.0.0'

        classpath 'org.robolectric:robolectric-gradle-plugin:0.14.+'

    }
}

allprojects {
    repositories {
        jcenter()
    }
}  

    А файл сборки build.gradle самого Android приложения так:
apply plugin: 'com.android.application'
apply plugin: 'android'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "ru.besttuts.stockwidget"
        minSdkVersion 10
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    sourceSets {
        androidTest {
            setRoot('src/test')
        }
    }
}

apply plugin: 'robolectric'

robolectric {
    include '**/robolectric/**/*Test.class'
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.+'

    androidTestCompile 'org.hamcrest:hamcrest-core:1.3'
    androidTestCompile 'org.hamcrest:hamcrest-library:1.3'

    androidTestCompile('junit:junit:4.12') {
        exclude module: 'hamcrest-core'
    }
    androidTestCompile('org.robolectric:robolectric:2.4') {
        exclude module: 'classworlds'
        exclude module: 'commons-logging'
        exclude module: 'httpclient'
        exclude module: 'maven-artifact'
        exclude module: 'maven-artifact-manager'
        exclude module: 'maven-error-diagnostics'
        exclude module: 'maven-model'
        exclude module: 'maven-project'
        exclude module: 'maven-settings'
        exclude module: 'plexus-container-default'
        exclude module: 'plexus-interpolation'
        exclude module: 'plexus-utils'
        exclude module: 'wagon-file'
        exclude module: 'wagon-http-lightweight'
        exclude module: 'wagon-provider-api'
    }
}

apply plugin: 'idea'

idea {
    module {
        testOutputDir = file('build/test-classes/debug')
    }
}

    Обратите внимание на строки:
    sourceSets {
        androidTest {
            setRoot('src/test')
        }
    }
    По умолчанию Android Studio создает директорию для тестов под названием androidTest, которую понимает среда разработки и подсвечивает соответствующим образом. Чтобы придерживаться стандартов, я переименовал эту директорию в test и указал это среде разработки, как показано выше.
    
    Обратите внимание на строки:
    apply plugin: 'robolectric'

    robolectric {
        include '**/robolectric/**/*Test.class'
    }
    Я создал директорию robolectric (D:\ideaWorkspace\StockWidget\android\src\test\java\ru\besttuts\stockwidget\robolectric\EconomicWidgetConfigureActivityTest.java), в которой будут находиться тесты созданные на базе Robolectric. При выполнении тестов Robolectic будет тестировать откомпилированные классы оканчивающиеся на *Test.class и находящиеся в директории/субдиректориях robolectric, как показано выше.

   Не забываем нажать Sync Now для начала подгрузки зависимостей!

Далее напишем простенький тест (рис. 2), чтобы удостовериться в работоспособности нашей настройки.
Рисунок 2. Простенький Unit-тест для проверки
    Теперь все готово и можно приступить к тестированию; открываем Terminal в Android Studio и вводим:
    gradlew clean test
 
    Результат теста можно посмотреть по адресу: file:///D:/ideaWorkspace/StockWidget/android/build/test-report/debug/index.html, пример которого на рис. 3.
Рисунок 3. Пример результата теста
    Если при выполнение теста из консоли, обычно, проблем не возникает, то из Android Studio возникают ошибки, упоминания о которых полно в интернете.
    Сейчас я опишу путь решения. Поехали.

    Кликаете правой кнопкой по файлу теста -> в раскрывшемся контекстном меню кликаете по Run и выбираете обычный JUnit тест(не Android Test).
    С 99,99% вероятностью Вы получите ошибку:
!!! JUnit version 3.8 or later expected:

java.lang.RuntimeException: Stub!
at junit.runner.BaseTestRunner.<init>(BaseTestRunner.java:5)
at junit.textui.TestRunner.<init>(TestRunner.java:54)
at junit.textui.TestRunner.<init>(TestRunner.java:48)
at junit.textui.TestRunner.<init>(TestRunner.java:41)
    Копируем -classpath "...", рис. 4.
Рисунок 4. Копируем -classpath "..."
    Теперь отредактируем наш -classpath.

-classpath "C:\Program Files\Android\Android Studio\lib\idea_rt.jar;C:\Program Files\Android\Android Studio\plugins\junit\lib\junit-rt.jar;D:\ideaWorkspace\StockWidget\android\build\intermediates\classes\debug;C:\Android\android-sdk\platforms\android-21\android.jar;C:\Android\android-sdk\platforms\android-21\data\res;C:\Users\roman\.gradle\caches\modules-2\files-2.1\org.robolectric\robolectric-annotations\2.4\936c649cb0958d7fb5d3c09b31c56b3997f80650\robolectric-annotations-2.4.jar;...;C:\Users\roman\.gradle\caches\modules-2\files-2.1\com.almworks.sqlite4java\sqlite4java\0.282\745a7e2f35fdbe6336922e0d492c979dbbfa74fb\sqlite4java-0.282.jar"

    Строчку выделенную жирным шрифтом: C:\Android\android-sdk\platforms\android-<21>\android.jar;C:\Android\android-sdk\platforms\android-<21>\data\res; необходимо вырезать и вставить в конец нашего -classpath, и не забывайте ставить разделители ';'.
Вместо <21> может быть другая версия Android SDK, которую вы используете!
 
    После этого, также в конец нужно вставить: ;<D:\ideaWorkspace\StockWidget\>android\build\test-classes; - это путь до ваших откомпилированных тестовых классов вида *Test.class.
<D:\ideaWorkspace\StockWidget\> - вместо этого, вы должны вставить корневой путь до вашего проекта!

   В конце мы получаем наш отредактированный -classpath:
-classpath "C:\Program Files\Android\Android Studio\lib\idea_rt.jar;C:\Program Files\Android\Android Studio\plugins\junit\lib\junit-rt.jar;D:\ideaWorkspace\StockWidget\android\build\intermediates\classes\debug;C:\Users\roman\.gradle\caches\modules-2\files-2.1\org.robolectric\robolectric-annotations\2.4\936c649cb0958d7fb5d3c09b31c56b3997f80650\robolectric-annotations-2.4.jar;...;C:\Users\roman\.gradle\caches\modules-2\files-2.1\com.almworks.sqlite4java\sqlite4java\0.282\745a7e2f35fdbe6336922e0d492c979dbbfa74fb\sqlite4java-0.282.jar;C:\Android\android-sdk\platforms\android-21\android.jar;C:\Android\android-sdk\platforms\android-21\data\res;D:\ideaWorkspace\StockWidget\android\build\test-classes"

    Открываем Edit Configurations... -> находим Run/Debug Configurations настройки для запуска нашего Unit-теста и в VM options копируем наш измененный -classpath, рис. 5.
Рисунок 5. Вставка -classpath в VM options
    Также нужно создать Gradle конфигурацию, которая будет компилировать тестовые классы. Для этого откройте Gradle Tasks находящийся в правой части Android Studio. Среди All Tasks найдите test и запустите ее. Она выполнит тесты, при этом в Run/Debug Configurations появится новая Gradle конфигурация, которая будет запускать команду test, рис. 6.
Рисунок 6. Gradle конфигурация для запуска команды тест
  Перед выполнением нашего теста, нужно выполнить команду test из созданной нами Gradle конфигурации, путем добавления ее в Before Launch: Another Configuration, как показано на рис. 7.
Рисунок 7. Добавления Gradle конфигурации в Before Launch наше Unit-теста

   Нажимаем Apply -> Ok, сохраняем настройки запуска теста.

   Далее запускаем наш тест, и все должно заработать, рис. 8!
Рисунок 8. Наш тест прошел без ошибок
    Если вы добавляете новые зависимости в файл сборки build.gradle, то необходимо их также добавить в -classpath для запуска нашего теста, иначе тест может выбросить ошибку, так как добавленный зависимости на в -classpath(в VM options)!

    Все описал как сам настроил, ничего не забыл надеюсь. Если возникли вопросы пишите, постараюсь ответить. Лучше бы это все в видео формате выложить, чтобы было более понятно, как считаете?

    Спасибо за внимание!

вторник, 23 сентября 2014 г.

Создание Excel файла на java с библиотекой jxl


Привет читатель! 
    Сегодня я расскажу как создать Excel файл на java при помощи бесплатной библиотеки jxl. Когда-то давно, года два назад я использовал ее для создания приложения под windows/linux, для исправления ошибок в расписании университета(КНИТУ/КАИ). Программ называлась Schedule Assist и была написана на java с использованием Eclipse RCP/SWT/JFace/Osgi. Если кому интересно, то вот ссылка на код программы: https://code.google.com/p/assist-schedule/ .
    Теперь по подробнее о библиотеке jxl. 
    jxl - это простое и удобное средство для создания, генерирования Excel файлов на языке программирования java. Эта библиотека была написана очень давно, но обладает всеми необходимыми методами для работы Excel файлами.
    Вот простейший пример ее использования, мне необходимо создать Excel файл и заполнить его данными Ebean(http://www.avaje.org/) сущности User(табличка users в БД), реальный метод контроллера в PlayFramework2(https://playframework.com/):

public static Result generateUsersExcel() {

        User u = Application.getUser(session().get("login"));
        if (!Secured.isAdmin(u, request())) {
            return badRequest("Permission denied");
        }

        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat("hh-mm_dd-MM-yyyy");
            String date = dateFormat.format(System.currentTimeMillis());
            String fileName = date + "-users.xls";
            File file = new File(fileName);
            WritableWorkbook workbook = Workbook.createWorkbook(file);
            workbook.createSheet("users-" + date, 0);
//            workbook.createSheet("Sheet2", 1);
//            workbook.createSheet("Sheet3", 2);
            WritableSheet writableSheet = workbook.getSheet(0);

            List<User> users = User.find.order("id asc").findList();

            writableSheet.addCell(new Label(0, 0, "ID"));
            writableSheet.addCell(new Label(1, 0, "fullName"));
            writableSheet.addCell(new Label(2, 0, "login"));
            writableSheet.addCell(new Label(3, 0, "inviter"));
            writableSheet.addCell(new Label(4, 0, "phone"));
            writableSheet.addCell(new Label(5, 0, "email"));
            writableSheet.addCell(new Label(6, 0, "createDate"));
            int offset = 1;
            for(int i = 0; i < users.size(); i++) {
                User user = users.get(i);
                writableSheet.addCell(new Label(0, i + offset, String.valueOf(user.id)));
                writableSheet.addCell(new Label(1, i + offset, user.fullName));
                writableSheet.addCell(new Label(2, i + offset, user.login));
                if(null != user.inviter) {
                    writableSheet.addCell(new Label(3, i + offset, user.inviter.login));
                }
                writableSheet.addCell(new Label(4, i + offset, String.valueOf(user.phone)));
                writableSheet.addCell(new Label(5, i + offset, user.email));
                if(null != user.createDate) {
                    writableSheet.addCell(new Label(6, i + offset, dateFormat.format(user.createDate)));
                }
            }

            workbook.write();
            workbook.close();

            return ok(file);
        } catch (WriteException e) {
            Logger.error(e.getMessage());
            return badRequest(e.getMessage());
        } catch (IOException e) {
            Logger.error(e.getMessage());
            return badRequest(e.getMessage());
        }
    }

    Больше информации по jxl и пример ее использования можно найти по адресу: http://jexcelapi.sourceforge.net/

    Скачать саму библиотеку можно из maven репозитория: http://mvnrepository.com/artifact/net.sourceforge.jexcelapi/jxl 

Спасибо! Надеюсь моя статья вам оказалась полезной!

PS:// Не тот счастлив у кого много добра, а тот у кого жена верна!:)