Wednesday, December 16, 2020

AWS Beanstalk Sensitive Info Exposed

The best way to learn something is to create projects from scratch.  Once I have free time I always try to create different types of projects.  Right now I decided to create an event-driven process to make data transformation/processing/real-time searching (Talking about the Big Data). I have standard ETL architecture using AWS S3, AWS SQS, AWS Lambdas. I also use AWS Lambdas to create data partitions on S3 and  Elastic beanstalk for data processing.  

I've just found that some sensitive information was exposed. I found the following header in the HTTP response:

Server: Apache/2/4/39 (Amazon) OpenSSL 1.0.2l-fips

The solution is pretty straightforward. We need to open the Apache documentation and read it. Note that if you need to completely remove the header you have to install the mod_security module. On the AWS EBS side, everything is simple. We need to create a new config for the beanstalk cluster. 

Location: Amazon S3/$bucket name/build/$app/.ebextensions/httpd/conf.d/

Next time I may share the entire project architecture - how I created real-time processing/searching on AWS env, why I use AWS Lambdas, why I create parquet files for the metadata, how I run distributed processing at AWS Beanstalk with Apache Ignite etc.


Have a good holiday!

Saturday, March 7, 2020

Fork Join pool - sometimes the solution is really simple


Let's discuss how people try to use the Fork Join pool in Java 7. Imagine that you have a class that extends RecursiveTask.


@Override
protected BigInteger compute() {
    if ((n - start) >= THRESHOLD) {
        Collection<FactorialTask> tasks = ForkJoinTask
                             .invokeAll(getSubTasks());
        BigInteger result = BigInteger.ONE;
        for (FactorialTask t : tasks) {
            result =  t.join().multiply(result);
        }
        return result;
    } else {
        return calculate(start, n);
    }

}


Ok, and do you know how some people try to transfer this code into the java 8 style? Yep, that's the code that you may find when you surf the web:

  @Override
   protected BigInteger compute() {
       if ((n - start) >= THRESHOLD) {
           return ForkJoinTask
             .invokeAll(createSubtasks())
             .stream()
             .map(ForkJoinTask::join)
             .reduce(BigInteger.ONE, BigInteger::multiply);
       } else {
           return calculate(start, n);
       }
   }


Off-course they still have additional methods:

    private BigInteger calculate(int start, int finish) {
        return IntStream.rangeClosed(start, finish)
                .mapToObj(BigInteger::valueOf)
                .reduce(BigInteger.ONE, BigInteger::multiply);

    }
    private Collection<FactorialTask> getSubTasks() {
        List<FactorialTask> tasks = new ArrayList<>();
        int mid = (start + n) / 2;
        tasks.add(new FactorialTask(start, mid));
        tasks.add(new FactorialTask(mid + 1, n));
        return tasks;
    }


In order to invoke:

public BigInteger factorial(Integer number){
    ForkJoinPool pool = ForkJoinPool.commonPool();
    return pool.invoke(new FactorialTask(number));
}

BUT wait! In Java 8+ we have a parallel stream, why don't rewrite this code in one line? Everything is  just simple:

IntStream.rangeClosed(1, number)
         .parallel()
         .mapToObj(BigInteger::valueOf)         
         .reduce(BigInteger::multiply);



Sometimes the solution is quite simple.

Tuesday, October 2, 2018

RDP linux to windows

In order to connect from Linux to windows via the RDP protocol please do the following steps.

  • install rdesktop
You can build source code from github or you can just find the built one in your OS repository.Source code:
For OpenSuse:

  • Connection:

Thursday, September 27, 2018

HikariCP pooling

If you are going to crate connections pools you have many options:


Why shoud I HikariCP? It's just very fast and stable!














Let's create configuration with Spring boot:

And our database configuration property

Our Persisntence Configuration

Ah I know  packagesToScan is ugly. We have Lambdas in Java. Generally this method is craeted to scan components in different modules.

public List <String> packagesToScan() { 
   return scanPackages.stream()
            .map(ScanPersistencePackage::asStrings)
            .flatMap(Collection::stream)
            .collect(Collectors.toList());
}
And concrete persistence configuration for our module:

JPA + Oracle procedures


Due the Oracle's license agreement there is no public repository with the Oracle Driver JAR. So first off all download  oracle  jdbc driver and install to local maven repository (or publish to your artifactory server).


Let's create simple procedures:


Create repository and call procedure using entity manager:


Friday, September 7, 2018

How to make your servers properly secure - Why agent forwarding is dangerous

In this article, I'll show you how to hack server if is bastion host is compromised.  let's talk for about bastion host...

What is the bastion host?

On Wikipedia, you may read that  "bastion host is a special purpose computer on a network specifically designed and configured to withstand attacks."  but it's more important to make correct server configuration otherwise bastion host can be a weapon for an attacker.



How to configure bastion server?
Let's configure Linux servers and then we can start hacking.  Imagine that we have N number of Linux instances and one bastion server. We will use private key ssh authentification for our Linux instances. For testing purpose, we will use user/password authentification for the bastion server. Let's start the configuration.
  • Create a user for the server
adduser bastion
passwd bastion
  •  open sshd_config and edit configuration. Change PermitRootLogin yes to PermitRootLogin no
vim /etc/ssh/sshd_config
  • Restart sshd and check the status
systemctl restart ssh
systemctl status sshd

You should see something like that:
[vq@localhost~]# systemctl status sshd
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; 

 enabled; vendor preset: enabled)
   Active: active (running) 
 
since Wed 2018-07-04 10:02:06 UTC; 32s ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 11595 (sshd)
   CGroup: /system.slice/sshd.service
           └─11595 /usr/sbin/sshd -D
Jul 04 10:02:06 systemd[1]:Starting OpenSSH server daemon...
Jul 04 10:02:06 sshd[11595]: Server listening on 0.0.0.0 port 22
Jul 04 10:02:06 sshd[11595]: Server listening on :: port 22
Jul 04 10:02:06 *** systemd[1]: 
  Started OpenSSH server daemon.
Now you can't log in via the root user. You can see if this configuration checks out.
vq@localhost:~> ssh root@X.X.X.X
root@X.X.X.X's password:
Permission denied, please try again.
  •  Let's block user if he/she tries to log in with incorrect user/password. For example we can give him/her three chances to log in - otherwise, we can block permanently or temporarily. So we can use  fail2ban.
sudo yum install epel-release
sudo yum install fail2ban
  • Duplicate fail2ban configure to create override config file:
cp /etc/fail2ban/fail2ban.conf /etc/fail2ban/fail2ban.local
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
vim jail.local
  •  If you use CentOS you need to change backend variable in the configuration. Just open  jail.local file and change auto to systemd.
 [DEFAULT] 
 backend = systemd  
  • Now enable SSH daemon jail in the jail.local file (anyway it's necessary for CentOS 7)
[sshd]
enabled = true
  • Set bantime, findtime, and maxretry values. For example:
bantime  = 1000
findtime = 1000
maxretry = 3
  • Enable fail2ban and restart service
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Now if you try authentification with incorrect user/password you will be blocked.
 



How to configure ssh private key authentification on Linux?
  • Crate user in the server
adduser usr
passwd usr
  • Generate ssh keys
     ssh-keygen
  • Copy public key to the server
    ssh-copy-id -i ~/.ssh/name.pub usr@IP
  • Login using private key:
 
    ssh -i name usr@IP
  • Disable root login and password authentification to the following file:
 
    vim /etc/ssh/sshd_config
    PasswordAuthentication no
    PermitRootLogin no
  • hmm... why not to change SSH port? Let's tell SELinux that we need to change it. Let's use just random number 2597
   
    yum -y install policycoreutils-python
    semanage port -a -t ssh_port_t -p tcp 2597
  • Now change port in sshd_config.  
vim /etc/ssh/sshd_config
    Check configuration file
    sshd -t
  • Restart services
 
    sudo systemctl restart sshd
  • Check what port is LITESENING
 
    sudo netstat -lntp | grep ssh
  • Allow ssh login only from bastion. So open 2597 port only for bastion. If you use firewalld run the following command:
 
 firewall-cmd  
 --permanent   
 --zone=public  
 --add-rich-rule='rule family="ipv4" 
 source address="BASTION_IP/32"   
 port protocol="tcp" 
 port="2597" accept'

If this is not your server just check your default zone.
 
firewall-cmd --get-default-zone
 

And check your rules:
  
firewall-cmd --list-all

But maybe you prefer to use iptables instead of firewald:
iptables -I INPUT -p tcp -s BASTION_IP  --dport 2597 -j ACCEPT
iptables -I INPUT -p tcp -s 0.0.0.0/0 --dport 2597 -j DROP

if this is not your own server just check iptable rules and remove some of them if necessary:

iptables -L --line-numbers
sudo iptables -D INPUT {line}

How to access my server via the Bastion? Generally, there are many ways but some of them are not secure. Let's talk for about them.

 
How to use AgentForwarding
  • Create config in ~/.ssh/config
    Host bast
        Hostname BASTION_IP
        ForwardAgent yes
        User bastion

  • Add your authentification key to ssh agent
ssh-add ~/.ssh/name_rsa
  • Connect to bastion host using username/password
    ssh bast
  • Connect application server
    ssh app@IP -p PORT

As you see you should connect your remote servers via the bastion server.  The same scenario is if you want to upload/download files:
  • Download file from remote server to BASTION. Run the command in Bastion server
    scp -P PORT app@IP:/src_path  /dest_path
  • Download file from BASTION to LOCA machine. Run the command in LOCAL machine:
    scp  -P PORT bastion@ip:/src_path /dest_path 
or
   scp  -P PORT bast:/src_path /dest_path
  • Upload file to BASTION
scp   /src_path bastion:/dest_path 

You may, well, ask me the question: Is my server secure?  And the answer is quite simple:
- Le't me tell you: NO!
 - Why?
 - Because you are using SSH Agent forwarding?
 - And where is the problem?
 - Because Agent forwarding is dangerous and it's consider considered harmful.

Let's explain everything inside out:  When you connect bastion host your glorious ssh agent is forwarded. It means that the socket will be set up so that someone may use this socket data to access your servers. Imagine that your bastion server is compromised, If someone has sufficient permissions on your Linux server he/she will just use your socket info. As a result, all your server can be accessed. I know window of compromise is very small because it depends on how much time you are connected to the bastion host. But do you really want to the risk when you have other options like ProxyCommand? Hence, just use ProxyCommand!

How to hack servers if you compromised bastion host?

In /tmp directory you may see something like that:
[root@localhost tmp]# ll
total 12
drwx------  2 bastion bastion 4096 Sep  7 17:35 ssh-mKX88v0Vlo
let's open the temporary file
[root@localhost tmp]# cd ssh-mKX88v0Vlo/
[root@localhost ssh-mKX88v0Vlo]# ll
total 0
srwxr-xr-x 1 bastion bastion 0 Sep  7 17:35 agent.10507
Let's see connections to this process id.
netstat -nxp | grep  10507
result:
unix  [ ]   STREAM     CONNECTED     501384   10507/sshd: bastion
and who is connected?
lsof -i -a -p 10507
result:
COMMAND  PID   USER  FD  TYPE DEVICE SIZE/OFF NODE NAME
sshd    10507 bastion  3u  IPv4 501301  0t0  TCP *IP*:ssh->*IP*:8279 (ESTABLISHED)
We can also see socket files:
cd /proc/10507/fd/
ls
result:
lrwx------ 1 root root 64 Sep  7 17:46 0 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 1 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 10 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:46 14 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:46 15 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:46 2 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 3 -> socket:[501994]
lrwx------ 1 root root 64 Sep  7 17:46 4 -> socket:[502069]
lrwx------ 1 root root 64 Sep  7 17:46 5 -> socket:[502072]
l-wx------ 1 root root 64 Sep  7 17:46 6 -> /run/systemd/sessions/1836.ref
lr-x------ 1 root root 64 Sep  7 17:46 7 -> pipe:[502079]
l-wx------ 1 root root 64 Sep  7 17:46 8 -> pipe:[502079]
lrwx------ 1 root root 64 Sep  7 17:46 9 -> socket:[502080]
And what happens when client will be connected to remote server? let's see:
lrwx------ 1 root root 64 Sep  7 17:46 0 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 1 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 10 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:48 11 -> socket:[502267]
lrwx------ 1 root root 64 Sep  7 17:46 14 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:46 15 -> /dev/ptmx
lrwx------ 1 root root 64 Sep  7 17:46 2 -> /dev/null
lrwx------ 1 root root 64 Sep  7 17:46 3 -> socket:[501994]
lrwx------ 1 root root 64 Sep  7 17:46 4 -> socket:[502069]
lrwx------ 1 root root 64 Sep  7 17:46 5 -> socket:[502072]
l-wx------ 1 root root 64 Sep  7 17:46 6 -> /run/systemd/sessions/1836.ref
lr-x------ 1 root root 64 Sep  7 17:46 7 -> pipe:[502079]
l-wx------ 1 root root 64 Sep  7 17:46 8 -> pipe:[502079]
lrwx------ 1 root root 64 Sep  7 17:46 9 -> socket:[502080]
We can even see if socket file is used using netstat:
unix  3 [ ]  STREAM  CONNECTED  502267  10561/sshd: 
                     bastion  /tmp/ssh-oVoMXC6vb8/agent.10561
unix  3  [ ] STREAM     CONNECTED     502072   10561/sshd:  bastion 
but wait we need to steal the socket information while the session of bastion host is open. Oh, we also need destination server IP, so just use netstat It's funny but you might find something like that on the internet.:
netstat -tn 2>/dev/null 
grep :22  | awk '{print $5}' | cut -d: -f1 | 
sort | uniq -c | sort -nr | head
Sometimes people try to demonstrate their knowledge  but just make everything simple.
netstat -tn
The final step to use the forwarded socket file
eval "$(ssh-agent -s)"
SSH_AUTH_SOCK=/tmp/ssh-EAKxOdL4fl/agent.10507
Check if the key is loaded.
ssh-add -l
result should be something like that:
2048 SHA256:2Psdl..B5KQ /home/usr/.ssh/name_rsa (RSA)
Ok. We have seen that Agent Forwarding is a problem. But where is the solution? Fortunately, we can just use a proxy command. So let's rewrite our configuration:
Host app
    Hostname *.*.*.*
    IdentityFile ~/.ssh/your_rsa
    User *******
    Port ****
    ProxyCommand ssh -W %h:%p bast

Host bast
     Hostname *.*.*.*
     ForwardAgent no
     User ******
Now  it's very simple to connect your server
ssh app
Do you want to download something from bastion?
scp bast:/home/bastion/sh ~/
Maybe you want to download something from the remote server via the bastion tunnel:
scp -P **** app:/src_path  /dest_path
Maybe you want to ypload something to remote server via the bastion tunel:
scp -P **** app:/src_path  /dest_path

Conclusion
  • If you use bastion host, don't use AgentForwarding but use ProxyCommand
  • Always use non root user for authentification
  • Use firewall and block all unnecessary connections.
  • Use SELinux
  • Block the IP address who  tries to login  several time with incorrect credentials
  • If it's not necessery don't give sudo permission to the user
  • Monitor your server
  • Update your server for security patches

Tuesday, August 14, 2018

How to create your own system.d service


If you explore latest Red Hat linux, you will see that the  traditional init scripts are gone. It's much easier to use rather then SysVinit, it reduces system startup time because the processes are running in parallel. It has also very nice logging mechanism. Let's write simple examples for CentOS7

Create a bash file:
 touch /usr/local/sbin/{launcher_name}.sh

It's a simple bash file that launches java application.
#!/bin/bash
java -jar /root/{name}.jar

Add execution permission
chmod +x {launcher_name}.sh

Create service:
touch /etc/systemd/system/{service_name}.service

Configuration:
[Unit]
Description=Application launcher service

[Service]
Type=simple
ExecStart=/usr/local/sbin/{launcher_name}.sh
TimeoutStartSec=0

[Install]
WantedBy=default.target

Set permissions:
chmod 664  {service_name}.service

Reload daemon
 systemctl daemon-reload 

Usage:
systemctl enable {service_name}
systemctl start {service_name}

We can create the same using init instead of sytstem.d. We shiuld just create configuration to the following locataion: /etc/init.d


#! /bin/sh
# /etc/init.d/{service_name}
### BEGIN INIT INFO
# Provides:           {service_name}
# Default-Start:      2 3 4 5
# Default-Stop:       0 1 6
# Short-Description:  Example of init service.
### END INIT INFO
# Actions provided to make it LSB-compliant
case "$1" in
  start)
    export DISPLAY=:0
    sh {launcher_name}.sh
    ;;
  stop)
    echo "Stopping"
    ...
    ;;
  restart)
    echo "Restarting"
    ;;
  force-reload)
    echo "Reloading"
    ...
    ;;
  status)
    echo "Status"
    ...
    ;;
  *)
    echo "Usage: /etc/init.d/{service_name} 
        {start|stop|restart|force-reload|status}"
    exit 1
    ;;
esac
exit 0 



How to allow non-root users to control system.d services/utilities that needs root permissions.

How to allow non-root users to control system.d services/utilities that needs root permissions.

By default sudo is not installed on debian. So, install sudo
apt-get install sudo -y

Add current user to sodoers list
usermod -a -G sudo vq

Change editor for visudo (I love vim).
update-alternatives --config editor

Let's give user perrmision to reboot without password. First off all we should change configuration in /etc/sudoers file. In order to edit the fiole  use visudo:
vq ALL=NOPASSWD:/sbin/reboot

Usage (password is not required)
sudo reboot

Now let's allow user to access concrete system.d service without password. For example let's do it for firewalld service.

Create file
cd /etc/sudoers.d
touch vq
vim vq

Add the following configuration
%vq ALL= NOPASSWD: /bin/systemctl start firewalld
%vq ALL= NOPASSWD: /bin/systemctl stop firewalld
%vq ALL= NOPASSWD: /bin/systemctl status firewalld

Usage (password is not required)
sudo systemctl start firewalld
sudo systemctl stop firewalld
sudo systemctl status firewalld

Note that my user and group is called vq

.

Friday, July 27, 2018

synchronise time using ntpd and timesyncd

Imagine that you have many servers. It's important to have synchronized time between our servers - at least the log files should have same time in order to find out the correct sequence of the processes. We can use the following tools for time synchronization
  • ntpd - powerfull Network Time Protocol Daemon. Full implementation of  NTP protocol
  • systemd-timesyncd - it is lightweight daemon for synchronizing the system clock. This client implements an SNTP.  if we  have ntpd daemon we can use ntpdc - utility program used to monitor NTP daemo (now it's deprecated and we use ntpq).  If we have systemd-timesyncd we can use  timedatectl - it has very beautiful configurations and controls the system time/date very well.
  • chrony is also full implementation of NTP. it has really great performance because It quickly detects sudden time changes like ntpd.   
  • OpenNTPD - It's part of the Open BSD project that also implements NTP protocol.
There are another implementations too but know let's talk for about ntpd and timedatectl.

 How to Configure ntpd

  • Install and enable ntpd for CentOS:
yum install ntpd
systemctl enable ntpd
firewall-cmd --add-service=ntp --permanent
  • Install and enable ntpd for Debian:
apt-get install ntpd
apt-get install ntpdate
  • Add pools in  /etc/ntp.conf  server configuration
server 0.[YOUR_POOLl]
server 1.[YOUR_POOLl]
  • Add local clock in  /etc/ntp.conf  server configuration.  For example, we can add local clock as a stratum 10  server or we  can set up to stratum 15 - so that it will never be used unless internet access is lost.
server  127.127.1.0 
fudge   127.127.1.0 stratum 10
  • Add pool adress in /etc/ntp.conf client configuration
server  X.X.X.X
  • Force update time, we can create crontab too (optional)
ntpdate -u X.X.X.X
  • Start ntpd service for CentOS:
systemctl start ntpd
  • Start ntpd service for Debian:
service ntp start  or systemctl start ntp

Let's check if everything works well and print all the peers of the servers
[vq@centos etc]# ntpq -p
 remote   refid  st t when poll reach delay  offset jitter
===========================================================
*LOCAL(0) .LOCL. 10 l 40  64   17     0.000  0.000  0.000

 How to Configure timesyncd

Because of we have installed ntpd we can't use systemd-timesyncd. Even if you try to use systemd-timesyncd service you will have the follolwing error:

vq@debian:/var/log# systemctl status 
systemd-timesyncd.service
● systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded 
(/lib/systemd/system/systemd-timesyncd.service;
 enabled; vendor preset: enabled)
  Drop-In: /lib/systemd/system/systemd-timesyncd.service.d
           └─disable-with-time-daemon.conf
   Active: inactive (dead)
Condition: start condition failed at 
Fri 2018-07-27 13:31:23 +04; 35s ago
           └─ ConditionFileIsExecutable=
!/usr/sbin/ntpd was not met
     Docs: man:systemd-timesyncd.service(8)


So we should remove ntpd if we want to use  timesyncd and timedatectl. You can find  timesyncd configuration to the following URL:

/etc/systemd/timesyncd.conf

[Time]
NTP= ${URLS}
FallbackNTP=${URLS}
#RootDistanceMaxSec=5
#PollIntervalMinSec=32
#PollIntervalMaxSec=2048
  • check if NTP synchronization is enabled 
 
vq@debian:/etc# timedatectl
      Local time: Fri 2018-07-27 13:27:36 +04
  Universal time: Fri 2018-07-27 09:27:36 UTC
        RTC time: Fri 2018-07-27 09:46:02
       Time zone: Asia/Tbilisi (+04, +0400)
 Network time on: YES
NTP synchronized: YES
 RTC in local TZ: YES

Friday, July 13, 2018

How to install JDK on linux and how it really works?

How to install JDK on linux and how it really works?

You may , well, ask me the question - which installation file should you download for your Linux. You know, you have many options: prm or deb or tar.gz


What is difference between rpm and deb file formats?

  • RPM and DEB files files provide an easy way for software to be distributed, installed, upgraded, and removed 
  • tag.gz is g-zipped tar file. You should download it if you are going to install JDK manually.

What is difference between deb and rpm file formats?

To be honest, therey are both archive files, with some metadata. In order to install deb file you need dpkg - this is package manager for Debian-based systems like Ubuntu, Debian etc. For rpm file format we use RPM Package Manager.

What about dependency problem?

Everything seems great but sometimes we have dependency problems.  In the other words, we had better install all dependencies for our program to work correctly.  Therefor RPM and dpkg  is unable to automatically do it.   Fortunately we have many tools in order to sole the problem:

  • APT (the Advanced Packaging Tool) to install, update and remove software  on Debian-based systems. 
  • YUM  package-management utility that uses the RPM Package Manager.
  • Zypper this is my favorite  package manager for installing, updating and removing packages as well as for managing repositories.  

How To install RPM format JDK on linux?


This method is suitable for SUSE/Arch/Fedora/CentOS/RedHat etc. You should just have RPM package manager.
 

  •  Download oracle jdk RPM package
  • To install using terminal type: `rpm -ivh {jdk-name-version}.rpm`
  • Run the following commands
update-alternatives --install /usr/bin/java java /usr/java/latest/bin/java 100
update-alternatives --install /usr/bin/javac javac /usr/java/latest/bin/javac 100
view raw update_java_path.sh hosted with ❤ by GitHub
  • Set default Java for in system

update-alternatives --config java
update-alternatives --config javac
view raw default_java.sh hosted with ❤ by GitHub



  

How to install  tar.gz format zypped JDK on linux?


  •  Download oracle jdk tar.gz
  •  mkdir /opt/jdk
  •  tar -zxf {jdk-name-version}.tar.gz -C /opt/jdk
  • update-alternatives --install /usr/bin/java java /opt/jdk/{jdk-name-version}/bin/java 100
  • update-alternatives --install /usr/bin/javac javac /opt/jdk/{jdk-name-version}/bin/javac 100
Check if java is installed

  •  update-alternatives --display java
  •  update-alternatives --display javac
 Set default Java for in System
  •  update-alternatives --config java
  •  update-alternatives --config javac


how to change shceduler times in spring

How to change scheduler times in Spring

 

Imagine that you have scheduler but you want to change time at runtime. What Can you do? Off-course there are ways do solve the problem. So In this article I will write how to implement Trigger interface that is located to the following package: org.springframework.scheduling in the spring-context project.

1. First off all, let's create interface for our logic:

























2. In Spring we have org.springframework.scheduling.Trigger interface:
























So we can write our own implementation. It's very simple. We should just overwrite nextExecutionTime(_) method.  Something like that:



3. Now we can write configuration.





In this example we just choose ThreadPoolTaskScheduler that is child ofTaskScheduler interface.


4. So what is the next? Let's see how to use our scheduler. Everything is simple:



That's it!

Goodbye!
Have good day!

Tuesday, January 16, 2018

Running rsync as a daemon



rsync is a very flexible utility for  transferring and synchronizing files across computer systems. For example, when we want to run updates to the remote devices, we can just update some files in the rsync server and another remote devices will receive the updated files automatically.







Rsync has three ways to decide if a file is outdated:
  1. Compare size of files
  2. Compare timestamps
  3. Compare static checksums

So we can choose   --size-only, --ignore-times or ---checksum option in order to decide how to compare files.


Let's write little example

  • Let's create some directory and write some files in it. The idea is the following: if we add any files in the directory , remote devices will revieve that files (any devices who have rsync client)

mkdir /opt/{my_app_settings}/dev/
  •  Edit rsyncd.conf file and write configurations. I have created 2 configuration. But before editing the file imagine that some remote devices mught need to revieve files from different directory. We have already created directory named "dev" but we can also can create another directory. For example let's create another directory named "prod". So rsync client will decide which directory to use  - in the other words where to get files. So our configuration looks like that:

[dev] 
path = /opt/{my_app_settings}/dev 
read only = true
uid = root
gid = root


[prod]
path = /opt/{my_app_settings}/prod 
read only = true 
uid = root 
gid = root 

  • Run rsync daemon

 rsync --daemon 

  • Run rsync client in order to retrieve new files:

  rsync -rtv root@IP::dev {destionation_directory} 


Also we can create sheduler in order to execute auto synchronization.

 crontab -e 

If you want to run cron job every 1 minute, write the following  cron config




  • Cron examples


Every 1 minute     * * * * * 
Every 15 minutea   */15 * * * * 
Every 30 minutes   */30 * * * * 
Every 1 hour       0 * * * * 
Every 6 hours      0 */6 * * * 
Every 12 hours     0 */12 * * * 
Once a day         4 0 * * *
Once a week        4 0 * * 0 
Once a month       4 0 1 * * 


Now just verify your cron job

 crontab -l 
Results should be something like that:

Tuesday, October 3, 2017

Debian 9 touch screen calibration (ENG)


Touchscreen mouse calibration is tested for the following OS:


  • Description: Debian GNU/Linux 9.1 (stretch)
  • Release: 9.1
  • ernel: Linux 4.9.0-3-686-pae
  • Architecture: x86


For touch screen we can use libinput or evdev driver. Libinput replaces the evdev driver. The configuration below is created for evdev. In the other words We use evdev.


  • Get information about xserver-xorg-input.


dpkg -l | grep xserver-xorg-input


Result:




As we see there is no evdev driver.


  • Let's install evdev driver.

apt-get install xserver-xorg-input-evdev


  • Check if evdev driver is installed


dpkg -l | grep xserver-xorg-input


Result:







  • Check if configuration files are in /usr/share/X11/xorg.conf.d directory.


cd /usr/share/X11/xorg.conf.d ls

result:

 
10-amdgpu.conf 10-evdev.conf 10-quirks.conf 40-libinput.conf 70-wacom.conf


  • now remove libinput driver or we can just remove touch screen section from libinput driver configuration file.


in order to remove libinput driver with dependent packages:


 
apt-get remove --auto-remove xserver-xorg-input-libinput


in order to disable libinput touch scree:

open 40-libinput.conf and remove a touchscreen InputClass Section that is shown in image below.




  • now install xinput-calibrator



sudo apt-get install xinput-calibrator


  • Check if you need to swap axes. if you need to swap just run:


xinit set-int-prop "eGalax Inc." "Evdev Axes Swap" 8 1


  • Run calibrator to get correct x,y positions.

 
xinput_calibrator --output-type xinput

The result will be like this:





Now everything should be fine, but if we want to make calibration permanent (after system restart),  open 10-evdev.conf config, find touch screen section and add "Calibration" and "SwapAxes" entries.





If we don't want to touch evdev configuration we can run the folloing command after X11 load:


xinput set-prop "eGalax Inc." "Evdev Axis Calibration" 1543, 222, 409, 1582 xinput set-prop "eGalax Inc." "Evdev Axes Swap" 1
if you want to configure libinput instead of evdev, remove evdev driver and install lib input if the last one is removed:
dpkg -P xserver-xorg-input-evdev apt-get install xserver-xorg-input-libinput

Wednesday, May 24, 2017

dnsmasq in Gnu/Linux



dnsmasq არის DNS forwarder და ასევე შეგვიძლია გამოვიყენოთ როგორც DCHP სერვერად. სხვა სიტყვებით რომ ვთქვათ dnsmasq საშუალებით ჩვენ შეგვიძლია DNS ის ქეშირება/ჩვენ გემოზე კონფიგურაცია სიჩქარის გასაზრდელად,  ასევე  როუტების,  internal IP გასაწერად.

მიუხედავად იმისა, რომ პირადად Open Suse Leap ზე ვმუშაობ, უნდა ვაღიარო,   ერთერთი ყველაზე კარგი დოკუმენტაცია  archlinux აქვს.  შესაბამისად,  ზოგჯერ, arch ის დოკუმენტაციაშიც ვიხედები. ხშირად ბევრი რამე პირდაპირ ემთხვევა.  მოკლედ, დეტალებში თუ დაგაინტერებთ იხილეთ შემდეგი ლინკი.




პატარა მაგალითი მოვიყვანოთ:

წარმოიდგინეთ მუშაობთ კომპანიაში სადაც გაქვთ შიდა DNS სერვერი.  როგორც Google-ს მოყვარული ჩემთვის პრიორიტეტი ყოველთვის 8.8.8.8 არის, გამომდინარე იქიდან, რომ ხშირად ვაწყდები ისეთ სიტუაციას, როდესაც შიდა DNS სერვერი ცუდად მუშაობს.

გამოსავალი:

1. მოვახდინო ქეშირება.
2. თუ შიდა სერვერი არაა, გავიდე გუგლის DNS მეშვეობით.


 პირველ რიგში ვნახოთ, dnsmasq თუ გვიყენია.  დაყენების ინსტრუქცია just google (გააჩნია დისტროს  zypper, apt-get, yast, etc...)

 სტატუსი:

vq@local:/etc/NetworkManager> sudo systemctl status dnsmasq.service 
root's password:
dnsmasq.service - DNS caching server.
   Loaded: loaded (/usr/lib/systemd/system/dnsmasq.service; enabled; 
 vendor preset: disabled)
  Drop-In: /run/systemd/generator/dnsmasq.service.d
           └─50-insserv.conf-$named.conf
   Active: active (running) since Wed 2017-05-24 11:22:19 +04;  
 34min ago
  Process: 5341 ExecStartPre=/usr/sbin/dnsmasq --test 
 (code=exited, status=0/SUCCESS)
 Main PID: 5344 (dnsmasq)
    Tasks: 1 (limit: 512)
   Memory: 464.0K
      CPU: 244ms
   CGroup: /system.slice/dnsmasq.service
           └─5344 /usr/sbin/dnsmasq --log-async 
 --enable-dbus --keep-in-foreground


შემდეგი ნაბიჯი (საჭიროა კომენტარების მოხსნა კონფიგურაციის ფაილში და გადაკეთება თქვენს გემოზე):

vim /etc/dnsmasq.conf 
resolv-file=/etc/resolv.dnsmasq.conf
strict-order
server=/დომეინი /DNS მისამართი
listen-address=127.0.0.1
bind-interfaces
vim /etc/resolv.dnsmasq.conf
nameserver 8.8.4.4
nameserver 8.8.8.8
იმის შემდეგ, რაც NetworkManager - ს ვეტყვით რომ 127.0.0.1-ს მოუსმინოს, შევამოწმოთ, რომ მართლაც 127.0.0.1 -ს უსმენს:

vim /etc/resolv.conf  nameserver 127.0.0.1 
vq@local:/etc> nmcli dev show | grep DNS
IP4.DNS[1]:                             127.0.0.1 

vq@local:/etc> nslookup domain
Server:        127.0.0.1



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 
...
...
...