Sunday, April 17, 2016

English to Georgian Dictionary for Kindle FREE




ქინდლისვის გავაკეთე ლექსიკონი. წიგნის კითხვის დროს მონიშნავთ სიტყვას და ავტომატურად გაიხსნება ფანჯარა, სადაც მონიშნული სიტყვის განმარტებას ნახავთ.


Google drive დან ფაილის გადმოსაწერი ლინკი

ესეც ლინკი ამაზონზე

იმედია მოგეწონებათ :) 






Friday, January 15, 2016

JNA & JNI Intro

JNA & JNI


ასე 1 წელიწადი იქნება რაც არაფერი დამიწერია ბლოგზე. მეგობრის თხოვნით პატარა სტატია მივუძღვენი JNA-ს.

Java Native Access  და Java Native Interface ბიბლიოთეკები გამოიყენება C , C++, assembly ზე დაწერილი კოდების გამოსაძახებლად (C++ ვრაფერი JNA არ აქვს, ხელით უნდა დაწეროთ ან შეგიძლიათ გამოიყენოთ JNA-ს შვილობილი პროექტები, როგორიცაა მაგალითად BridJ და სხვა მრავალი).  C/C++ ენაზე მიჩვეული დეველოპერი JNI-ს აირჩევს, რადგან კონვერტაციები Native მხარეს არის იმლემენტირებული, ვისთვისაც Java ენაა უფრო ახლოს, ის JNA აირჩევს, რადგანაც კონვერტაციები Java მხარეს ხდება. გამოყენების არეალი ორივეს დიდი აქვს, მაგალითად JNA-ს იყენებს Apache Cassandra რომელიც არის ერთერთი საუკეთესო NoSQL მონაცემთა ბაზა , რომელიც CAP  Theorem ის მიხედვით Availability სა და Partition Tolerance -ს შორის ზის. ასევე JetBrains ის მიერ შექმნილი ცნობილი InteliJ IDEA, Netbeans IDE და ასე შემდეგ.

JNA ზე მაგალითები , ბიბლიოთეკასთან ერთად, შეგიძლიათ ნახოთ შემდეგ ლინკზე:
https://github.com/java-native-access/jna.git


თვალსაჩინოებისთვის დავწეროთ მარტივი მაგალითი.

header.h
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED 

int  buildRequest(char * input, char * answer, int inputLenth);  

typedef void(*NotificationListener)(char *, int);
void callbackTriger(const NotificationListener l); 
void getDeviceRandomStatus(char *answer, int sizeOfChars); 
int randNum( int min,  int max); 

#endif // HEADER_H_INCLUDED



header.c
#include<stdio.h>
#include "header.h"
#include <stdlib.h>
#include <time.h>


int buildRequest(char * input, char * answer, int inputLenth) {
  printf("C: log passed params from java to C: ");
  int i = 0;
  for (; *input; ++input) {
    i++;
    if (i > inputLenth) {
          break;
    }
    char c = *input;
    int i = (int) c;
    printf("%d ", i);
  }
  printf("\n");
  answer[0] = 0xFE;
  answer[1] = 0x81;
  return i - 1;
}

void callbackTriger(const NotificationListener l) {
  int size = randNum(1, 20);
  char answer[size];
  getDeviceRandomStatus(answer, size);
  (*l)(answer, sizeof(answer));
}

void getDeviceRandomStatus(char *answer, int sizeOfChars) {
  int i;
  for (i = 0; i < sizeOfChars; i++) {
        int i = randNum(0, 255);
        answer[i] = i + '0';
  }
}

int randNum(int min, int max) {
  srand(time(NULL));
  double scaled = (double) rand() / RAND_MAX;
  int val = (max - min + 1) * scaled + min;
  return val;
} 




mainc.c    გამოვიყენებთ ბიბლიოთეკის გასატესტად (ის Shared Library რომელიც შემდგომ უნდა ჩაბამათ Java კოდში ში JNA დახმარებით)
#include<stdio.h>
#include <limits.h>
#include <stdlib.h>

int main(void)
{
     char ch [] = {0x01, 0x07, 0x09 ,0xA, 0xB,0xC, 0xD,0xE ,0xF };
     char answer[2];
     int r=buildRequest(ch, answer, 5);
     printf("Returned params: ");

     int i;
     for (i = 0; i < sizeof(answer); ++i){
           printf("%d ", answer[i]);
     }

    return 0; 


}


შევქმნათ Shared ბიბლიოთეკა და გავტესტოთ. ამ სკრიპტებით შექიმნება header.o და libHeader.so, შემდეგ main ს მივაბამთ და გავტესტავთ:
gcc -c -Wall -Werror -fpic header.c 
gcc -shared -o libHeader.so header.o
gcc main.c -o main -lHeader -L/home/vq/Desktop -Wl,-rpath=/home/vq/Desktop
./main



ახლა დავწეროთ რამდენიმე მაგალითი, ერთი უბრალოდ Java დან C კოდის გამოძახება, მეორე კი პირიქით ანუ callback. განვიხილოთ buildRequest ფუნქციის გამოძახების მაგალითი -  ბაიტების მასივი წარმოდგენილი გვაქვს როგორც char *, როგორც input ისე output რაც უნდა დაბრუნდეს, ასევე აქ გვჭირდება ერთი დამხარე პრიმიტივი ბაიტების მასივის ზომის განსასაზღვრად. callbackTriger -ის შემთხვევაში პოინტერი გვაქვს პარამეტრად NotificationListener ის რომელიც ჰედერშია გამოცხადებული, pointer-to-function ტიპი. რაც შეეხება randNum და getDeviceRundomStatus, ესენი უბრალო მეთდებია შემთხვევითი ზომის და მნიშვნელობების ბაიტების მასივის დასაბრუნებლად.



import java.util.Arrays;
import java.util.logging.Logger;

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;

/**
 * 
 * @author vakhtang Koroghlishvili
 * 
 */
public class BuildRequestMaker {

public static Logger log = Logger.getLogger(CallBack.class
  .getSimpleName());

public interface CLibrary extends Library {

 public int buildRequest(Pointer input, Pointer output,
   int inputLenth);
}

public interface CLibraryCallBack extends Library {

 public interface NotificationListener extends Callback {
  void invoke(Pointer val, int lenth);
 }

 public static class NotificationListenerImpl implements
   NotificationListener {
  @Override
  public void invoke(Pointer val, int lenth) {
   log.info("java mehtod, callback: "
     + Arrays.toString(val.getByteArray(0, lenth)));
  }
 }

 public void callbackTriger(NotificationListener callback);
}

public byte[] buildRequest(byte[] inputArr) {

 CLibrary clib = (CLibrary) Native.loadLibrary(
   "/home/vq/Desktop/libHeader.so", CLibrary.class);

 Pointer input = new Memory(inputArr.length
   * Native.getNativeSize(Byte.TYPE));
 Pointer answer = new Memory(inputArr.length
   * Native.getNativeSize(Byte.TYPE));

 for (int i = 0; i < inputArr.length; i++) {
  input.setByte(i * Native.getNativeSize(Byte.TYPE),
    inputArr[i]);
 }

 int resultSize = clib.buildRequest(input, answer,
   inputArr.length);

 log.info("returned value from c lib is: " + resultSize);
 byte[] resultByte = answer.getByteArray(0, resultSize);

 log.info("returned value array from c lib is: "
   + Arrays.toString(resultByte));

 return resultByte;

}

public void callBackListener() {

 CLibraryCallBack clib = (CLibraryCallBack) Native
   .loadLibrary("/home/vq/Desktop/libHeader.so",
     CLibraryCallBack.class);

 // instantiate a callback wrapper instance
 CLibraryCallBack.NotificationListenerImpl callbackImpl = new CLibraryCallBack.NotificationListenerImpl();

 // pass the callback wrapper to the C library
 clib.callbackTriger(callbackImpl);

 }

}


და ტესტები:


import org.junit.Assert;
import org.junit.Test;

public class JNATests {

 @Test
 public void buildRequestTest() {
  BuildRequestMaker m = new BuildRequestMaker();
  byte[] input = { (byte) 0x81, (byte) 0xFE };
  byte[] expect = { (byte) 0xFE, (byte) 0x81 };
  Assert.assertArrayEquals(expect, m.buildRequest(input));
 }

 @Test
 public void callBacklTest() {
  BuildRequestMaker m = new BuildRequestMaker();
  Exception ex = null;
  try {
   m.callBackListener();
  } catch (Exception e) {
   ex = e;
  }
  Assert.assertEquals(null, ex);
 }
შედეგები:
INFO: started call back listener
INFO: java mehtod, callback: [-64, -28, 119, 124, 84, 127, 0, 0]
...
INFO: started building request
INFO: returned value from c lib is: 2
INFO: returned value array from c lib is: [-2, -127]
C: log passed params from java to C: -127 -2 


ეს მაგალითი, ისე, დამატებითი დეტალებისთვის Just Google 

Wednesday, November 5, 2014

Spring, Pooling - tomcat, ORA

Connection Pool

ქონექშენ ფული აუცილებლად გვჭირდება მაშინ, როდესაც საქმე გვაქვს ისეთ აპლიკაციასთან, რომელსაც ბევრი მომხმარებელი იყენებს - წინასწარ ვამყარებთ კომნიკაციას ბაზასთან, წინასწარ გამოვყოფთ ამ უკანასკნელისთვის რესურსებს და ასე შემდეგ.

ალტერნატივები ბევრი გვაქვს, მაგალითად Apache commons DBCP, Tomcat DBCP, C3PO  და ასე შემდეგ. ამ სტატიაში კი tomcat ის DBCP ზე მინდა ვისაუბრო - ეს tomcat სერვერიც ძალიან მომწონს და მისი ფულინგის სისტემაც. ტომკატში dbcp ისტორია იწყება იმით რომ, მათ გააგრძელეს  commons DBCP ის დეველოპმენტი.. ამის მიზეზი კი ის იყო რომ commons -ს  საშინელი thread-safety პრობლემები ქონდა (ეს იხება 1.0, 1.2 ვერსიებს მაგალთად).. შესაბამისად ტომკატმა თავისი დეველოპმენტი დაიწყო, გადააკეთე ყველაფერი თავის გემოზე, common ის პრობლემებიც გაასწორა.. დღე დღეს მისდევდა, დრო კი არ ჩერდებოდა  - ტომკატი ყველანაირად ცდილობდა მაქსიმალურად ჩქარი ფულინგი გაეკეთებინა და ამასაც მიაღწია, ამასობაში Commons მაც გაასწორა თავისი პრობლემები და დააფაბლიშა ახალი ვერსია...  საბოლოოდ ასე მივიღეთ tomcat ის ალტერნატიული ფულინგ სისტემა, რომელის წინა პირობა რათქმაუნდა common ის dbcp იყო... ახალი და განსხვავებული, მორგებული ყველანაერად სერვერ...


Spring ში რამდენიმე ტიპის data source შეგვიძლია ავღწეროთ, ყველა org.springframework.jdbc.datasource პაკეტშია.

1. DriverManagerDataSource - ყოველ ჯერზე, როდესაც ქონექშენის მოთხოვნა მოუვა, აბრუნებს ახალ ქონექშენს. სამწუხაროდ, pool ინგი არ აქვს გაკეთებული.

2. SingleConnectionDataSource  - ყოველ ჯერზე ერთდაიგივე ქონექშენს აბრუნებს.

ორივე, ზემოთ აღწერილი, პატარა აპლიკაციებისთვის არის გათვლილი.

მოვიყვანოთ  კონფიგურაციის მაგალითი:

 
     <bean id="dataSource"  class=
      "org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value=
      "oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="${database.url}" /> 
        <property name="username" value="${database.username}" />
        <property name="password" value="${database.password}" />
    </bean> 


 
ახლა კი ტომკატის ფულინგ მექანიზმზე გადავიდეთ, რომელზეც ზემოთ ვსაუბრობდით. მე კონკრეტულად Oracle-ს ვუკავშირდები, და კონკრეტული კონფიგურაციების მნიშვნელობები .properties ფაილში მაქვს გაწერილი.

     <bean id="dataSource" class=
      "org.apache.tomcat.jdbc.pool.DataSource" 
      destroy-method="close">
        <property name="initialSize" value="${database.initialSize}" />
        <property name="maxActive" value="${database.maxActive}" />
        <property name="maxIdle" value="${database.maxIdle}" />
        <property name="minIdle" value="${database.minIdlel}" />
         <property name="driverClassName" 
      value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="${database.url}" /> 
        <property name="username" value="${database.username}" />
        <property name="password" value="${database.password}" />
     </bean>





ყველაეფრი ძალიან კარგადაა, თუმცა არ დაგავიწყდეთ ბაზის ის კონფიგურაცია. Pool ის გაკეთება კარგია მაგრამ ბაზასაც უნდა შეეძლოს რექუესთების მიღება.

პრიმიტიულ მაგალითს მოვიყვან, Oracle-ს შემთხვევაში.  შეამოწმეთ ბაზას რამდენი პროცესის დამუშავება შეუძლია ან job_queue_processes რამდენი გაქვთ მითითებული.

show parameter processes;

NAME                       TYPE        VALUE      
------------------------------------------- 
aq_tm_processes            integer     0          
db_writer_processes        integer     1          
gcs_server_processes       integer     0          
global_txn_processes       integer     1          
job_queue_processes        integer     5       
log_archive_max_processes  integer     4          
processes                  integer     10       



შეგიძლიათ შეცვალოთ მნიშვნელობები (ეს დამოკიდებულია თქვენი აპლიკაციის ტიპზე, თუ როგორი დატვირტვა ექნება ბაზასთან მიმართებაში):
ALTER SYSTEM SET processes=2000 SCOPE=SPFILE;

ALTER SYSTEM SET job_queue_processes=1000 scope=both;

პ.ს ბოლო ორი ALTER ის შემდეგ სერვერის რესტარტი არ დაგავიწყდეთ :)

Monday, October 27, 2014

JIT -server || -client

უკვე ღამის ოთხი საათა და ობიექტური მიზეზების გამო ჯერაც არ მძინავს. სანამ ჩემ ფუმფულა ბალიშზე თავს დავდებდი,  გადავწყვიტე, არც მეტი არც ნაკლები 2-3 წუთი დამეთმო ამ სტატიისთვის. უძინარის კვალობაზე, გრამატიკულ შეცდომებს თუ შეამჩნევთ, არ გაიკვირვოთ. :)

ალბათ გექნებათ ნანახი აპლიკაციები, რომლებიც გაშვებული არიან JVM ის შემდეგი პარამეტრით: "-server" ან "-client".



ორივე შემთხვევაში, ვიყენებთ ჩვენ -server  თუ client პარამეტრს,  JVM იქცევა სხვადასხვანაგვარად. -server ის დროს JVM მეტ ოპტიმიზაციას ანხორციელებს (JIT ზე ვსაუბრობ აქ), აპლიკაციის დასტარტვის დრო ცოტა ნელია თუმცა საბოლოო ჯამში მეტად ოპტიმიზირებული შედეგი მიიღება. -client შემთხვევაში კი მსუბუქად უკეთებს ოპტიმიზაციას კოდის ისეთ ნაწილებს სადაც JVM-ს მეტად  მძიმე, დატვურთული, მუშაობა ჭირდება.

ორივეს ფლაგს თავისი ადგილი და მიზანი აქვს. მაგალითად, როდესაც რაიმე სერვერს ვსტარტავთ, აუცილებლად -server პარამეტრი უნდა გამოვიყენოთ. ამას ბევრი მიზეზი აქვს. ერთერთო ის, რომ სერვერის დასტარტვის დროზე მეტად, ჩვენთვის მნიშვნელოვანია სერვერის საბოლოო ჩქარი მუშაობა. რაც შეეხება -client-ს ის შეილება გამოვიყენოთ, მაგალითად GUI აპლიკაციის გასაშვებად - ეშვება სწრაფად და სამუდამოდაც არ იქნება დასტარტული.

შენიშვნა Thread Visibility -ზე  წინა ერთერთ სტატიაში (შეგიძლიათ გახსათ lazy init, dc locking, volatile) დავწერე Volatile-ცვლადების სპეციფიურ ქცევაზე.  მაგალითი იყო შემდეგი: გვაქვს 2 სრედი, პირველი ნაკადი უყურებს whilte(flag){}-ს მეორე კი flag ზე ახდენს მოდიფიცირებას -მნიშვნელობას უცვლის ისე რომ ციკლი გააჩეროს.  ერთ შემთხვევაში flag არის volatile მეორეში კი უბრალოდ მარტივი, კოტხტა, ლამაზი და მშვენიერი boolean - რომელიც თავისთვის არის და არის, ცხოვრობს თავის თბილ სახლში, heap ად წოდებულში.

წარმოვიდგინოთ,  ზემოთ აღნიშნული კოდი წერია ერთერთ აპლიკაციაში რომელიც გაშვებულია სერვერზე - Tomcat მაგალითად, ან Jetty (ეს უკანასკნელი ძალიან კარგი ბიჭია asynchronous რექუესთების დამუშავებაში). ჩვენ უკვე ვიცით რომ, რომ სერვერ აპლიკაციები ყოველთვის უნდა იყვნენ დასტარტულები  -server ბრძანებით. მაგრამ Oops! -server  ის წყალობით , უფრო კი მისი ოპტიმიზაცთ, JVM მა შესაძლოა ციკლში არსებული არამოდიფიცირებადი ცვლადებისადმი ხედვის არიალი გადაიტანოს ციკლის გარეთ - უფრო გასაგები რომ იყოს, ციკლის შიგნით არ ხდება flag მნიშვნელობის შეცვლა, ამან კი შესაძლოა JVM დაარწმუნის, რომ ოპტიმიზაციისთვის ხედვის არეალი შეცვალოს. გილოცავთ, ეს არის უსასრულო ციკლი!  შედეგად,   შესაძლოა კოდმა იმუშაოს -client გარემოში, და არ იმუშაოს -server ში. დებაგირების დროსაც თუ  -server-ს გამოვიყენებთ, პროდაქშენზე დადებამდე, ამით შემდეგი ტიპის გაჟონვებს თავიდან ავიცილებთ - ტესტირების დროსვე დავიჭერთ შეცდომას.


ოპტიმიზაცია ამასთან გულისხმობს არამარტო სხვადასხვა ალგორითმის თვალით დამუშავებულ კოდის ნაწილებს, არამედ მეხსიარების გამოყოფის სხვადასხვა მექანიზმებსაც, JVM ის მიერ განსხვავებულ დამოკიდებულებას gc-ს მიმართ, და ასე შემდეგ.


Friday, October 10, 2014

NoSQL 'n CAP


 NoSQL მოიცავს ისეთ ბაზებს როგორებიცაა: Mongo, Neoj4, Cassandra, Riak, Hadoop (HDFS ხოლო რეალ თაიმ ბაზა HBase) და ასე შემდეგ, ისინი ერთმანეთისგან სტრუქტურულად განსხვავდებიან (ჰადუპის ეკო სისტემაზე სხვა დროს დეტალურად ვისაუბრებ). მაგალითად არსებობს, გრაფებზე აგებული ბაზები (Neo4j), Key Value სტრუქტურის მქონენი (Cassandra, Redis), Mongo სა და CouchDB– ში დოკუმენტების შენახვა JSON ობიექტებით ხდება

საბოლოოდ, მათში ინახება უსქემო მონაცემები*, ადვილია მათი დაკლასტერება, ეს სისტემები გამოირჩევიან დიდი სისწრაფით და ამარტივებენ ამოცანის გადაჭრას. NoSQL მონაცემთა ბაზა არ იყენებს SQL–ს, თუმცა ზოგი მათგანი query ენას გვაძლევს – მაგალითად Cassandra CQL.

*სიტყვა „უსქემო“ ხშირად დამაბნეველია, მაგალითად, როდესაც იგებენ, რომ მონგოს აქვს დიამიური სქემა- მასში შეგვიძლია შევქმნათ ქოლექშენები ისე რომ წინასწარ სტრუქტურა არ გვქონდეს აღწერლი.



ბაზებთან მუშაობისას შესაძლოა გვქონდეს“ network partition”–ები, რომლებიც გულსიხმობენ კლასტერში ნოუდებს შორის კომუნიკაციის დაკარგვას და შესაბამისად ინფორმაციის არასინქრონულობას.




შესაბამისად ბაზას ყოფენ შემდეგი ტიპებად, რომელთაგან მხოლოდ 2 შეგვიძლია შევინარჩუნოთ.



Consistency (მუდმივობა) - ჩანაწერები იგივეა კლასტერის ყველა node ში.
Availability – თუ რომელიმე Node არის ჩავარდნილი, მაინც შესაძლებელია კლასტერთან წვდომა.
Partition Tolerance – კლასტერი განაგრძობს ფუნქციონალობას მაშინაც კი როდესაც node ებს შორის არის კომუნიკაციის პრობლემა.

ამ სამზე (CAP) დეტალურ მაგალითებს, ქვემოთ მოვიყვან.




როდესაც კომუნიკაციის პრობლემაა, არჩევანი გვაქვს:

1. ან დავუშვათ რომ არასინქრონირებული მნაცემები იყვნენ ბაზაში (დავივიწყოთ Consistency)
2. ჩავთვალოთ რომ კლასტერი დაზიანდა, ანუ დავივიწყოთ Availability

ყველა კომბინაცია ასე გამოიყურება:
CA ერთიდაიგივე მონაცემებია ყველა node ში. თუ რაიმე კომუნიკაციის პრობლემა დაფიქსირდა node ებს შორის (partition ), მონაცემები იქნება არასინქრონირებული სანამ პრობლემა არ გადაიჭრება. ანუ node ებს შორის სხვადასხვა მონაცემები იქნება.

CP აქაც მონაცემები მუდმივია ყველა node ში. მაგალითად, დაფიქსირდა დაფიქსირდა კომუნიკაციის პრობლემა. ამ დროს არასინქრონული რომ არ იყოს მონაცემები შესაბამისი node გახდება გაუქმებული ანუ წაკითხვა/ჩაწერა იქნება გაჩერებული შესაბამის node ში. აქ თავი გვაქ დაცული იმისგან რომ სხვადასხვა მონაცემები არ გვეწეროს ბაზაში.

AP იგივე მაგალითი – დაფისქირდა პრობლემა node ებს შორის. აქ დაზიანებული node ები არ არიან გაუქმებულები. ისინი დამოუკიდებლად განაგრძობენ მუშაობას. როდესაც კომუნიკაციის პრობლემა აღდგება დაიწყება სინქრონიზაცია მონაცემების, თუმცა გარანტია არ გვაქვს რომ ყველა მონაცემი იგივე იქნება ნოუდებს შორის.

Wednesday, May 14, 2014

RBS Drools (PART I, BASICS)

Rule-based systems - წესებზე/ბრძანებებზე დაფუძნებული სისტემა–  ძირითადად ისეთი ამოცანების გადაჭრაში გამოიყენება სადაც  ხელოვნური ინტელექტია საჭირო ან მძლავრი გამოთვლებია განსახორციელებელი. მაგალითად:  მგზავრობა მაქსიმალურად ბევრ ქალაქში ისე რომ მაქსიმალურად ცოტა თანხა დავხარჯოთ, ჭადრაკი ან თუნდაც სუდოკუ...

RBS–სათვის ბევრი პროექტები არის შექმნილი, ერთერთი არის Jboss Drools. ეს გახლავთ openSource პროექტი, რომელსაც სხვადასხვა შვილობილი (sub) პროექტები გააჩნია – Drools Expert, Drools Fusion, Drools Guvnor, Drools Planner და ასე შემდეგ.

გამახსენდა კიდევ Scala, ან IBM –ს აქვს Jrules პროექტი. Jrules ფასიანია, თუ ფული არ გვაქვს, უბრალოდ უნდა დავკმაყოფილდეთ იმით რაც გვაქვს. ამჯერად ამ სტატიაში Drools ზე ვისაუბრებთ.

სინტაქსი


 
rule "HelloPersons" 
  when 
       Person( firstName == "mariam" ) 
  then 
     // შესრულება
end  

მარტივი სინტაქსია. თუ სახელი ექვივალენტურია მარიამის, მაშინ
then ში გადავდივართ. კომპილერი ჭკვიანია და იცის რომ == იგივეა რაც String.equals

Person კლასის სხვა ველების შემოწმებაც შეგვიძლია და ასეთი სინტაქსი გვექნება:

 
rule "CheckPerson" 
when
    p: Person(age >= 18, country == "Georgia", nick: nickName)
then
    System.out.println( "Hello Mariam" );
end


ამ შემთხვევში p  არის reference variable.  აქვე პერსონის ობიექტიდან nickName ველი ამოვიღე და nick ცვლადში ჩავწერე (რათქმაუნდა  სქოუფი შეზღუდული აქ ამ ცვლადს).


პროგრამის გასაშვებად 2 გზა გვაქვს. პირველი ესაა ფლაგინის დაყენება IDE ში.

ვერსიები შეგიძლიათ აქედან ამოირჩიოთ:
 
http://download.jboss.org/drools/release/

თუმცა მე ყოველთვის ბოლო განახლებულს ვიღებ, ანუ შეგიძლიათ დააინსტალიროთ ეკლიფსში შემდეგი ლინკიდან :
 
http://download.jboss.org/drools/release/latest/org.drools.updatesite/ 


მეორე გზაა მავენის (ანუ იგივე მავნე) დეფენდენსებში დავამატოთ:

 
<dependency> 
        <groupId>org.drools</groupId> 
            <artifactId>drools-compiler</artifactId>
            <version> [ვერსია]</version> 
        </dependency> 
<dependency> 



rule ბის დასაწერად შექმენით სახელი.drl ფაილი რესურსებში. გასაშვებად კი Drools და jBPM ის მიერ შემოთავაზებული KIE API გამოგვადგება.


KieServices ks = KieServices.Factory.get(); 
KieContainer kContainer = ks.getKieClasspathContainer();
KieSession kSession = kContainer.newKieSession("ksession-rules"); 
 
Person p= new Person();

...     

kSession.insert(p); 
kSession.fireAllRules(); 


განვიხილოთ  ცოტა დახვეწილი მაგალითი. მაგალითად, ფიბანაჩის მიმდევრობაზე:

ჩვენ ვიცით რომ
 F(n)=F(n-1) + F(n+2)
ამასთან
 F(1) =1, და F(2)=1;



 public static class Fibonacci {

  private int sequence;
  private long value;

  public Fibonacci(int sequence) {
   this.setSequence(sequence);
   this.setValue(-1);
  }
   //... 
 } 


თავიდან  -1 მნიშვნელობები მივანიჭოთ  (–1 ით ავღნიშნოთ   ჯერ გამოუთვლელი მნიშვნელობები  )

rule "ფიბანაჩის ობიექტების შექმნა"
    when
        f : Fibonacci ( value == -1 )
        not ( Fibonacci ( sequence == 1 ) )   
    then
        insert( new Fibonacci( f.sequence - 1 ) );
        System.out.println( "recurse for " + f.sequence );
end



when –> თუ  Fibonacci ობიექტში მნიშვნელობა არის -1 (ჩვენ შექმნისას –1 მივანიჭეთ, შესაბამისად არის), მაშინ –> შევქმნათ ახალი ობიექტი , ერთით ნაკლები მიმდევრობის ნომრით.  


 rule "F(1) , F(2) ის ინიციალიზება"
    when
        f : Fibonacci(  sequence==1 || ==2, value == -1  ) 
    then
            modify ( f ){
         value = 1
     };
        System.out.println( f.sequence + " და " + f.value ); 
end



ყველა შემთხვევაში ვიცით რომ 1 –ს უდრის F(1) , F(2). ამიტომ: როცა  sequence==1 ან  sequence==2 , მაშინ გადავაკეთოთ მნიშვნელობები 1 ით. ამასთან value == -1 პირობაც დავამატოთ, თორემ ჩავიციკლებით.


და ბოლოს გამოვთვალოთ:

rule "გამოთვლა"
    when
        f1 : Fibonacci( s1 : sequence, value != -1) 
        f2 : Fibonacci( s2: sequence == (s1+1), value != -1 )
        f3 : Fibonacci( s3 : sequence == (f1.sequence+2 ), value == -1 )             
    then   
        modify ( f3 ) {
          value = f1.value + f2.value
         };
        System.out.println( s3 + " == " + f3.value ); 
end 



შედეგი
1 = 1
2 = 1
3 == 2
4 == 3
5 == 5
6 == 8
7 == 13
8 == 21
9 == 34
10 == 55
11 == 89
12 == 144
13 == 233
14 == 377
15 == 610
16 == 987
17 == 1597
18 == 2584
19 == 4181
20 == 6765
21 == 10946
22 == 17711
23 == 28657
24 == 46368
25 == 75025
26 == 121393
27 == 196418
28 == 317811
29 == 514229
30 == 832040
31 == 1346269
32 == 2178309
33 == 3524578
34 == 5702887
35 == 9227465
36 == 14930352
37 == 24157817
38 == 39088169
39 == 63245986
40 == 102334155
41 == 165580141
42 == 267914296
43 == 433494437
44 == 701408733
45 == 1134903170
46 == 1836311903
47 == 2971215073
48 == 4807526976
49 == 7778742049
50 == 12586269025
51 == 20365011074
52 == 32951280099
53 == 53316291173
54 == 86267571272
55 == 139583862445
56 == 225851433717
57 == 365435296162
58 == 591286729879
59 == 956722026041
60 == 1548008755920
61 == 2504730781961
62 == 4052739537881
63 == 6557470319842
64 == 10610209857723
65 == 17167680177565
66 == 27777890035288
67 == 44945570212853
68 == 72723460248141
69 == 117669030460994
70 == 190392490709135
71 == 308061521170129
72 == 498454011879264
73 == 806515533049393
74 == 1304969544928657
75 == 2111485077978050
76 == 3416454622906707
77 == 5527939700884757
78 == 8944394323791464
79 == 14472334024676221
80 == 23416728348467685
81 == 37889062373143906
82 == 61305790721611591
83 == 99194853094755497
84 == 160500643816367088
85 == 259695496911122585
86 == 420196140727489673
87 == 679891637638612258
88 == 1100087778366101931
89 == 1779979416004714189
90 == 2880067194370816120
91 == 4660046610375530309
92 == 7540113804746346429 
...
...
...

Saturday, December 21, 2013

ProtoBuf & Thrift



Protocol Buffer არის გუგლის ენა  - მექანიზმი დასასერიალიზირებადი მონაემებისათვის. სხვა სიტყვებით რომ ვთქვათ, საშუალებას გვაძლევს მარტივად და სწრაფად ვიმუშაოთ სტრუქტურიზირებულ მონაცემებთან.  წარმოიდგინეთ XML დოკუმენტი. XML ზე უფრო პატარა გვაქვს  JSON. უფრო პატარას, უფრო სწრაფს და უფრო მარტივს კი გუგლის გვთავაზობს(binary არის ოღონდ).  ერთხელ ვწერთ, თუ როგორი სტრუქტურა გვინდა, შემდეგ კი შესაძლებლობა გვაქვს მონაცემები ჩავწეროთ ან წავიკითხოთ.  ამასთან გვაქვს საშუალება,  სხვადასხვა ენებში მუშაობისა - Java, C++,  Python.

ტესტირებისთვის ჯავას ობიექტი დავასერიალიზე, დაახლოებით 500 byte ზომის გამომივიდა, ProtoBuf ით კი ბაინარი დატა 50 byte.

ამ მექანიზმს, ვისაც ნანახი გაქვთ, Google App Engineც იყენებს, და სხვა გუგლის სერვისები. საკმაოდ ფართოდ გამოყენებადია.

ალტერნატივებიც არსებობს, მაგალითად  Apache Thrift, რომელიც FB-მ შექმნა. ორივე რაღაცით არის კარგი. მაგალითად Thrift ისგან განსხვავებით, პროტოკოლ ბუფერით დასერიალიზირებული მონაცემები 30% ით უფრო მცირე არის. სამაგიეროდ, Thrift-ს სტრუქტურა მეტად დახვეწილი აქვს, მაგალითად შესაძლებელია Map ის აღწერა. კიდე ერთი განსხვავება ის არის რომ Thrift ში პირდაპირ არის ინტეგრირებული RPC , პროტოკოლ ბუფერში კი ცალკე არის გატანილი. ენების მხრიბ Thrift-ს შემდეგ ენებთან აქვს მუშაობის შესაძლებლოვა: Thrift: Java, C++, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk, OCaml, ხოლო რაც შეეხება protobuf-ს მხოლოდ Java, C++, Python. და ბოლოს, რაც მთავარია Protobuf ვრცელდება BSD ლიცენზიით, Thrift-ს კი Apache License ადევს.