Tuesday, October 14, 2014

Convert csv to xls/xlsx (using Apache POI, openCSV).

I had a task to make "csv to xlsx" converter for reason nonfunctional M$ Excel import tool. M$ Excel couldn't convert huge sentence containing commas and newlines surrounded with quotes as text. This brainless M$ Excel tool interpreted commas and newlines characters inside quotes as new separator. LibreOffice imported CSV file correctly (of course), but ... you know, LibreOffice is not approved tool for corporation.

I decided to make the java tool for this purpose. This tools is consisting of two steps and is using two libraries (openCSV, Apache POI).

openCSV: serves to convert CSV file to String (CSVReader obj.)
CSVReader reader = null;
...
reader = new CSVReader(new FileReader(input_file),',');


Apache POI: serves to convert String do XLS file
XSSFWorkbook workBook = new XSSFWorkbook();
XSSFSheet sheet = workBook.createSheet("sheet1");

int RowNum=0;
while ((nextLine = reader.readNext()) != null)
{
  XSSFRow currentRow=sheet.createRow(RowNum++);
  for(int i=0;i<nextLine.length;i++)
  {
    currentRow.createCell(i).setCellValue(nextLine[i]);
  }
}

Entire example:
import au.com.bytecode.opencsv.CSVReader;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

public class Main {
  public static void main(String[] args) {

    CSVReader reader = null;
    FileOutputStream fileOutputStream = null;

    System.out.println("Type name of CSV file for conversion." +
      "\nFile must be in same folder as \"CSV_to_XLSX.exe\":\n");
  
    //csv file name
    Scanner sc = new Scanner(System.in);
    String input_file = sc.next();

    //xls file name
    String xlsxFileAddress = null;
    if(input_file.length() < 5){
      System.out.println("Incorrect file name!");
      System.exit(0);
    } else {
      xlsxFileAddress = input_file.substring(0, input_file.length() - 4)+".xlsx";
    }
  
    try {
      //Get the CSVReader instance with specifying the delimiter to be used
      String[] nextLine;
      reader = new CSVReader(new FileReader(input_file),',');

      XSSFWorkbook workBook = new XSSFWorkbook();
      XSSFSheet sheet = workBook.createSheet("sheet1");

      int RowNum=0;
      while ((nextLine = reader.readNext()) != null)
      {
        XSSFRow currentRow=sheet.createRow(RowNum++);
        for(int i=0;i<nextLine.length;i++){
          currentRow.createCell(i).setCellValue(nextLine[i]);
        }
      }

      fileOutputStream = new FileOutputStream(xlsxFileAddress);
      workBook.write(fileOutputStream);
    }
    catch (Exception e1) {
      //e.printStackTrace();
      System.out.println("\nFile \"" + input_file + "\" does not exist!");
    }
    finally {
      if (reader != null) {
        try {
          reader.close();
          fileOutputStream.close();
          System.out.println("Done");
        } catch (IOException e2) {
          //e2.printStackTrace();
          System.out.println("\nFile \"" + input_file + "\" can not be closed correctly!");
        }
      }
    }
  
    try {
      System.out.print("\n...press [Enter] key to exit.");
      System.in.read();
    } catch (IOException e3) {
      // TODO Auto-generated catch block
      //e3.printStackTrace();
      System.out.println("Application is not close correctly!");
    }
  }
}

All required libraries:




Wednesday, August 27, 2014

Debian (wheezy) Eclipse error: GLib-GObject-WARNING libgdk-x11-2.0.so

Do you have a problem to run Eclipse or STS (Spring Tool Suite) on Debian Wheezy? Is your error message when you start Eclipse, like this:


user@comp:~$ eclipse/eclipse
GLib-GObject-WARNING **: crashing aplications
...
Problematic frame: C [libgdk-x11-2.0.so.0+0x5173f]
...


The problem is that glibc library is older than Eclipse needs. The default version of the library is glibc-2.13-1 and Eclipse need version glibc-2.14 or higher, but these versions glibc libraries are missing in Debian stable repository.
My solution is to add the official unstable/testing repository to APT, and then install the newer version glibc library.

Add the official unstable/testing repository in the "/etc/apt/sources.list":

deb http://http.us.debian.org/debian/ testing non-free contrib main
deb http://http.us.debian.org/debian/ unstable non-free contrib main
deb http://http.us.debian.org/debian/ wheezy non-free contrib main

Search for a newer version glibc Library in the repository:


user@comp:~$ sudo aptitude search glibc
...
v   glibc-2.13-1
v   glibc-2.19-1  
...


Install a newer version glibc library:


user@comp:~$ sudo aptitude install glibc-2.19-1


You can now successfully run Eclipse.

Wednesday, June 19, 2013

Android NDK / JNI (Java Native Interface)


NDK - Native Development Kit NDK je sada nástrojov, ktorá umožňuje implementovať natívny kód v iných jazykoch (C, C + +).  NDK využíva štandardný java framework k tomu určený – JNI.
JNI – Java Native Interface je framework umožňujúci volať natívne programy a knižnice napísané v iných jazykoch (C, C++, ..) priamo v kóde, bežiacom v Java Virtual Machine (JVM).
Uplatnenie:
  • využitie staršieho kódu napísaného v inom jazyku (nie Java) bez nutnosti ho prepisovať do javy
  • využitie API iných jazykov (nie Java)
  • komunikácia s HW

Obmedzenia (nevýhody):
  • strata platformovej nezávislosti javy (natívny kód je potrebne prepísať pre každú platformu)
  • vlastnosti javy ako typová bezpečnosť, garbage collector sa nevzťahujú na natívny kód

Implementácia:
  1.  triede v ktorej chceme volať metódu, implementovanú v natívnom jazyku, vytvoríme deklaráciu natívnej metódy. Natívna metóda musí obsahovať modifikátor „native“,

    public native int callJni(int i);
    


  2. Signatúru natívnej metódy môžeme vytvoriť pomocou nástroja „javah“ (javah -jni ClassName), alebo ju vytvoríme ručne, teda vytvoríme samostatný súbor pre požadovanú metódu (napr.: „jni_part.cpp“) v adresári „jni“ (napr.: project_folder/jni/jni_part.cpp),


    #include <jni.h>
    extern "C" {
        JNIEXPORT jint JNICALL Java_com_example_test04jni_MainActivity_callJni(JNIEnv*, jclass, jint);
        JNIEXPORT jint JNICALL Java_com_example_test04jni_MainActivity_callJni(JNIEnv* je, jclass jc, jint i)
        {
            return (i * i);
        }
    }
    


  3. V mieste umiestnenia natívnej funkcie vytvoríme „makefile“ s názvom „Android.mk“ pre android build,

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE    := jni_example  
    LOCAL_SRC_FILES := jni_part.cpp
    include $(BUILD_SHARED_LIBRARY)
    


  4. Zbuildujeme natívnu metódu pomocou „android-ndk“,

    LINUX shell:
    "project dir"$ ~/.android-ndk-r8c/ndk-build
    

  5. Nakoniec v android aplikácii v mieste volania natívnej metódy, najskôr načítame knižnicu, ktorá bude kompilovať natívnu metódu a zavoláme samotnú metódu.

    // Load native library
    System.loadLibrary("jni_example");
    ...
    // call native method: "callJni(i)"
    textView_result.setText(Integer.toString(callJni(i)));
    


    Zdroj android triedy, v ktorej bola volaná natívna metóda:


    package com.example.test04jni;
     
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.Menu;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    public class MainActivity extends Activity {
     
        private TextView textView_result;
         
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
             
            // Load native library
            System.loadLibrary("jni_example");
             
            textView_result = (TextView) findViewById(R.id.textView_result);
             
            final Button btn_start = (Button) findViewById(R.id.button1);
            btn_start.setOnClickListener(new View.OnClickListener() {
                 public void onClick(View v) {
                    Integer i = 10;                   
                    // call native method: "callJni(i)"                       
                    textView_result.setText(Integer.toString(callJni(i)));           }            
            });
             
        }
     
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
     
        // Declaration of native methods.
        public native int callJni(int i);
    }
    

Zdroj príkladu: Android-NDK-JNI-example

Wednesday, March 6, 2013

Oracle XE on Debian

This is short introduction how to install and use Oracle XE database on Debian. Oracle web page offer only two version of XE database for download (for Windows x32 and Linux x64), but on "Oracle Open Source Software" is available i386 version of Debian package: https://oss.oracle.com/debian/dists/unstable/non-free/binary-i386/

Installation:


After download package, we can start install package:
  • $ sudo dpkg -i oracle-xe-universal_10.2.0.1-1.1_i386.deb
Next we execute "after installation" configuration. We can keep parameters that are as default in configuration process, except "user password" and maybe number of port for web manager (8080 replace by for example 8180):
  • $ sudo /etc/init.d/oracle-xe configure

Default username is: 
  • system

Oracle web manager:

Oracle web manager is running on "localhost" address:


Oracle SQL Developer:

Quote: "Oracle SQL Developer is a free integrated development environment that simplifies the development and management of Oracle Database." This tool is available on Oracle home page, but if you want to download, you must register (horror). Another solution is to find this package on "One-click hosting" (for example: sqldeveloper-3.2.20.09.87-no-jre.zip).

After download and unpack, we must change file mode:
  • chmod 755 /sqldeveloper/sqldeveloper.sh 

And then we can run tool. For first start we must setting path to JVM (in my case: JAVA_HOME=/usr/lib/jvm/java-6-sun):
  • $ /sqldeveloper/sqldeveloper.sh


SQLplus:

Oracle command-line interface "sqlplus" is good hiding. The file path is following in my installation:
  • /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/config/scripts/runsqlplus.sh


SQL commands:

And finally, several examples of SQL commands (sqlplus):

login:
  • SQL> connect  system/oracle
view all users:
  • SQL> select * from all_users;
view all tables:
  • SQL> select * from dict;
execute an SQL script from file:
  • SQL > @/oracle/scripts/script.sql


Monday, February 25, 2013

REST-ovaný Android s Djangom.

Krátka prezentácia komunikácie Android aplikácie s webovým portálom. Komunikácia spočíva v zobrazovaní obsahu z webového portálu v Android aplikácii, pomocou REST rozhrania reprezentovaného JSON formátom.

Vzorová aplikácia reprezentuje webový portál fiktívneho IT bazáru a k nemu prislúchajúcu Android aplikáciu pre zobrazovanie obsahu web portálu.

Technológie:
  • Django (python web framework)
  • Android (OS pre mob.)
  • REST (súbor architektonických princípov, umožňujúce návrh webových služieb)
  • JSON (dátový formát, určený pre prenos dát)

Web portál – Django
V tejto prezentácii sa nerieši UI webového portálu a teda URL web portálu vracia len JSON bez „template“).

Poznámka na úvod:
Štandardný MVC model je v Django frameworku prezentovaný ako MTV model. (Model View Controller = Model Template View)

Riešenie:
Web portál pozostáva z jednoduchého modelu (models.py), view (views.py) a admin rozhrania (admin.py) pre naplnenie dát, ktoré sú JSON výstupom pre Android aplikáciu.

[views.py]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# coding: UTF-8

from django.http import HttpResponse
from django.utils import simplejson
from django.core import serializers

from json01App.models import Category, Product

def index(request):
    '''
    index.html 
    '''
    cat_type = 0
    if 'cat_type' in request.GET and request.GET['cat_type']:
        cat_type = request.GET['cat_type']

    category = Category.objects.all()
    json_category = serializers.serialize("json",category)

    products = Product.objects.filter(category_id = cat_type)
    json_products = serializers.serialize('json', products, ensure_ascii=False)
    json_products_encode = json_products.encode('ascii', 'ignore')
    json_string = "{\"product\":" + str(json_products_encode) + "}"

    return HttpResponse(json_string, content_type='application/javascript; charset=utf-8')

URL je volaná s parametrom „cat_type“, definujúcim kategóriu, ktorej obsah sa má vrátiť (hodnota parametra predstavuje primárny kľúč entity „Category“ v DB, viď. „models.py“).

Príklad URL: http://192.168.1.1:8000/?cat_type=1

Dôležité:
Ak je web portál spúšťaný na localhost-e, je potrebné ho spustiť pod IP adresou samotného PC, predstavujúceho web server a nie ako „localhost“, alebo „loopback“ (127.0.0.1), nakoľko za týmto istým účelom používa OS Android tieto adresy. To znamená že po nastavení URL v Android aplikácii (viď nasledovný odstavec) a jej následnom spustení by sa volal „localhost“ OS Androidu a nie požadovaný web portál.

[models.py]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=30)

    def __unicode__(self):
        return self.name

class Product(models.Model):
    '''
    product id = implicit primary key 
    '''
    category_id = models.ForeignKey(Category)
    product_type = models.CharField(max_length=30)
    product_mob = models.CharField(max_length=30)
    product_mail = models.CharField(max_length=30)
    product_desc = models.CharField(max_length=160)
    product_price = models.CharField(max_length=30)

    def __unicode__(self):
        return self.product_type

[admin.py]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# Coding: UTF-8

from json01App.models import Category, Product
#from heatmap.models import *
from django.contrib import admin

class CategoryAdmin(admin.ModelAdmin):
    list_display = ('id','name',)
    fields = ('name',)
    ordering = ('id',)

class ProductAdmin(admin.ModelAdmin):
    list_display = ('id','category_id','product_type','product_mob','product_mail','product_price','product_desc',)
    fields = ('category_id','product_type','product_mob','product_mail','product_price','product_desc',)
    ordering = ('id',)

admin.site.register(Category, CategoryAdmin)
admin.site.register(Product, ProductAdmin)

Admin UI - Category:

Admin UI - Product:



Návratová hodnota URL je JSON:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
    "product": [
        {
            "pk": 3,
            "model": "json01App.product",
            "fields": {
                "product_mail": "PC01@pc.sk",
                "product_mob": "0948 620 720",
                "product_type": "Dell OptiPlex 755",
                "product_desc": "Parametre: OptiPlex 755 DT: Intel Core 2 Duo E7200 (2.53GHz, 1066MHz, 3MB) Desktop Chassis Resource DVD: OptiPlex 755 Diagnostics & Drivers Vista/XP Documentati",
                "product_price": "130 ",
                "category_id": 1
            }
        }
    ]
}

Android aplikácia

Aplikácia obsahuje na úvodnej obrazovke tri tlačítka a každé z nich reprezentuje vstup do inzertného obsahu danej kategórie. Po stlačení tlačítka sa zobrazia položky (inzeráty) danej kategórie a po následnom kliknutí na konkrétny inzerát sa zobrazí jeho podrobný obsah.

Poznámka na úvod:
Minimálne požiadavky na verziu OS je Android 3.0.x HONEYCOMB (API 11) z dôvodu použitia dialógového okna „DialogFragment“, namiesto zavrhovaného „AlertDialog“.

Riešenie:
  1. MainActivity.java - po spustení aplikácie sa na pozadí volá URL pre každú kategóriu zvlášť (inštancia „inner“ triedy [ReadJSONFeedTask]). Vrátená hodnota sa uloží ako JSONObject a rozparsovaný výsledok sa ukladá do HashMap premennej (ArrayList), pripravenej pre zobrazenie JSON obsahu, prezentovaného v UI ako zoznam položiek (ListActivity). Ak je návratová hodnota JSON prázdna, prípadne je URL neplatné, vyvolá sa dialógové okno (DialogFragmet) s informáciou o probléme.
  2. DisplayMessageActivity.java – kliknutím na ľubovoľné tlačítko predstavujúce jednu z kategórii sa volá aktivita, ktorá zostaví a zobrazí spomenutý zoznam položiek.
  3. SingleMenuItemActivity.java - následným kliknutím na niektorú z položiek zoznamu sa jej obsah zobrazí opäť ako nový zoznam položiek.


Dôležité:
Pred spustením (kompiláciou) Android aplikácie je potrebné upraviť nasledovné konštanty v hlavnej triede "MainActivity":

  • JSON_URL = URL webového portálu, volaný pre získanie JSON dát,
  • CATEGORY_TYPE_PC (NB,MOB) = číselný parameter definujúci kategóriu (hodnota parametra predstavuje primárny kľúč entity „Category“ v DB, viď. „models.py“).


Screenshot:



Sources:
Bazar_example.zip


Záver:
Ukážková aplikácia slúži ako priblíženie a nie ako komplexné riešenie danej problematiky, preto je potrebné brať v úvahu absenciu štandardných funkcionalít pri podobných riešeniach v praxi, ako napríklad ukladanie získaných dát v mobile pre neskoršiu prezentáciu – offline a podobne.


Monday, January 14, 2013

Kivy, (že by) skutočný multiplatformový framework?


Kivy je open source knižnica nástrojov pre platformne nezávislé (MacOSX, Linux, Windows, Android, iOS), „multy-touch“, GUI aplikácie.

Programovací jazyk – python

GUI interface – OpenGL

zdroj: http://kivy.org/


Ukážka jednoduchej aplikácie (okno s jedným tlačítkom):

(main.py)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import kivy
kivy.require('1.0.6')
 
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.uix.button import Button
 
class Controller2(BoxLayout):
 
    def __init__(self, **kwargs):
        super(Controller2, self).__init__(**kwargs)
 
        self.padding = 20
 
        button = Button(text='button')
        self.add_widget(button)
 
class Controller2App(App):
    def build(self):
        return Controller2()
 
if __name__ == '__main__':
    Controller2App().run()


Ten istý príklad s použitím "kivy language". Konfiguračný súbor (*.kv), popisujúci užívateľské rozhranie a interakcie umožňuje oddeliť zdrojový kód od kódu určujúceho vzhľad UI.

(main.py)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import kivy
kivy.require('1.0.6')
 
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
 
class Controller(BoxLayout):
    pass
 
class ControllerApp(App):
    def build(self):
        return Controller()
 
if __name__ == '__main__':
    ControllerApp().run()

(controller.kv)
1
2
3
4
5
6
7
8
9
#:kivy 1.0
 
<Controller>:
 
    BoxLayout:
        padding: 20
 
        Button:
            text: 'button'


Print screen jednoduchej app. na rôznych platformách t.j. jeden zdrojový kód (viď. nižšie) interpretovaný pod troma platformami (OS X nebol k dispozícii :-)

Linux Debian - GNOME 3:

Windows 7:

 Android 4.0:

Jednotný zdrojový kód ukážkovej aplikácie interpretovaný vo všetkých platfomách:

(main.py)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import kivy
kivy.require('1.0.5')
from kivy.uix.gridlayout import GridLayout
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.image import Image
class MyClass(GridLayout):
    def __init__(self):
        super(MyClass, self).__init__()
        def my_callback(self, obj):
            print 'My button <%s> state is <%s>' % (self, obj)
            textOutput.text = textInput.text
        self.cols = 2
        self.padding = 200
        self.spacing = 10
  
        self.row_force_default = True
        self.row_default_height = 40
        wimg = Image(
            source='Logo.png',
            size_hint_x=None,
            width=200
            )
        textOutput1 = Label(
            size_hint_x=None,
            width=100
            )      
        textInput = TextInput(
            multiline=False,
            size_hint_x=None,
            width=200
            )
        button = Button(
            text='Push',
            size_hint_x=None,
            width=100
            )
        textOutput = Label(
            size_hint_x=None,
            width=200
            )      
        button.bind(state = my_callback)
        self.add_widget(wimg)
        self.add_widget(textOutput1)
        self.add_widget(textInput)
        self.add_widget(button)
        self.add_widget(textOutput)
 
class MyClassApp(App):
    def build(self):
        return MyClass()
if __name__ == '__main__':
    MyClassApp().run()

Výhody:
  • open source
  • skutočne jednotný kód pre všetky podporované platformy
  • jednoduchá tvorba GUI rozhrania
  • jednotný vzhľad GUI na všetkých platformách (dá sa považovať aj za nevýhodu, tak ako u JAVA app.)
  • podpora periférií mob. zariadení (multy-touch, kamera, telefón,... )
  • dobra dokumentácia (400 stranové pdf) a aktívna komunita

Nevýhody:
  • vyžaduje OpenGL od verzie 2.0 napriek tomu že táto verzia je vonku už od 2004, mnohé PC s OS Win XP majú GPU, ktorých ovládače ešte stále nepodporujú OpenGL 2.0 a už s najväčšou pravdepodobnosťou ani nebudú podporovať
  • jednotný vzhľad GUI, ktorý je silne orientovaný na mob. aplikácie (čierno – čierny šat aplikácie)
  • minimálna veľkosť aplikácie po nainštalovaní na OS Android mala 20MB (predpokladám že veľkosť app. lineárne nenarastá so zložitosťou samotnej app., ale aj tak je to dosť).

Záver:
Zaujímavý nástroj pre rýchlu a jednoduchú tvorbu GUI multiplatformových aplikácii, ktorý ale asi potrebuje ešte trošku vyzrieť a to nie len po komunitnej stránke.

Django-cms navigation / menu example


1. project structure:

django-cms_project_dir/
    .
    |-- templates (dir)
    |    `-- example.html
    |-- __init__.py
    |-- manage.py
    |-- settings.py
    |-- urls.py
    |-- ..

2. create file:
./templates/example.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{% load cms_tags menu_tags sekizai_tags %}
<!doctype html>
<head>
  <title>{{ request.current_page.get_title }}</title>
  {% render_block "css" %}
</head>

<body>
<p>
    {% show_menu 0 100 100 100 %}
</p>
{% cms_toolbar %}
    {% placeholder "main" %}
{% render_block "js" %}
</body>
</html>

2. add to file:
./settings.py

1
2
3
CMS_TEMPLATES = (
    ('example.html', 'Example Template'),
)




3. create several pages through django-cms "admin" page:
("Add page" and "Save and continue editing")

4. drag and drop subpages into "home" page:

5. view "home" page:

...that's all