Info Redakcija

Info Redakcija

ponedjeljak, 21 Avgust 2017 08:14

Osnove Springa

Na samom početku jedna mala napomena: izvorni kod za primjere opisane u ovom tekstu se može pregledati i preuzeti sa ove lokacije. U ovom članku će biti prikazani i analizirani samo oni fragmenti koda koji su neophodni za opisivanje i razumjevanje specifičnih Spring koncepata.

Primjer kojeg ćemo koristiti opisuje jedan jednostavan domen koji se sastoji od čuvanja detalja o filmovima i glumcima. Aplikacija se sastoji od tri sloja: domenski sloj, sloj repozitorija i servisni sloj.

 

 

Domenski objekti Movie i Actor predstavljaju apstrakcije filmova i glumaca. Interfejsi MovieRepository i ActorRepository definišu CRUD operacije nad domenskim objektima, a njihove InMemory implementacije omogućavaju spašavanje i čitanje domenskih objekata iz memorije. CinemaService interfejs i njegova implementacija omogućavaju izvršavanje aplikacione logike, korištenjem navedenih repozitorija. Tipična java aplikacija treba da, u okviru setup koda, instancira navedene klase i izvrši njihovo povezivanje prije izvršavanja bilo kakve poslovne logike. Npr. slijedeći primjer pokazuje jedan od mogućih načina za definisanje aplikacione logike koja popunjava i ispisuje bazu filmova i glumaca:

public class App {
    public static void main(String[] args) {
        ActorRepository actorRepository = new InMemoryActorRepository();
        MovieRepository movieRepository = new InMemoryMovieRepository();
        CinemaService cinemaService = new CinemaServiceImpl(movieRepository, actorRepository);
        populateDatabase(cinemaService);
        printDatabase(cinemaService);
    }
    private static void populateDatabase(CinemaService cinemaService) {
        Actor actor1 = new Actor(1, "Brad", "Pit");
        Actor actor2 = new Actor(2, "Edward", "Norton");
        Movie movie1 = new Movie(1, "Zodiac", 157, new HashSet>());
        Movie movie2 = new Movie(2, "Fight Club", 139,  new HashSet>());
        movie1.getActors().add(actor1);
        movie2.getActors().add(actor1);
        movie2.getActors().add(actor2);
        cinemaService.saveMovie(movie1);
        cinemaService.saveMovie(movie2);
        cinemaService.saveActor(actor1);
        cinemaService.saveActor(actor2);
    }
    private static void printDatabase(CinemaService cinemaService) {
        cinemaService.findAllMovies().forEach(System.out::println);
    }
}


Spring Framework se, sa druge strane, oslanja na izuzetno moćan koncept koji se naziva inverzija kontrole ili Dependency Injection (DI). U ovom pristupu developer ne mora pisati kod za instanciranje i povezivanje jer je to zadatak Spring kontejnera. Ono što developer mora obezbjediti jeste postojanje "recepta" po kojem će kontejner kreirati navedene objekte. Tradicionalni način za definirianje ovog recepta je bila odgovarajuća xml struktura. Npr. te recepte možemo kreirati unutar application-config.xml datoteke:

Svaki recept za kreiranje java objekta mora biti sadržan unutar taga bean. Npr:

Ova definicija znači da će Spring kontejner kreirati actorRepository bean instanciranjem klase InMemoryActorRepository. Po defaultu, navedeni bean je singleton što znači da će kontejner svim svojim klijentima vraćati uvijek jedan te isti objekat. Ukoliko želimo da kontejner uvijek kreira novi objekat, trebamo promijeniti recept tako da scope beana definišemo kao prototype:

Ukoliko bean treba da bude kreiran uz pomoć drugih beana, recept treba da sadrži reference tih objekata:

Prikazani primjer predstavlja instrukciju kontejneru da kreira cinemaService objekat koristeći konstruktor u kojeg će biti ubačene dvije reference, pri čemu če kontejner preuzeti brigu o redoslijedu kreiranja objekata.

Recept za kreiranje objekta može definisati i korake koji se dešavaju nakon kreiranja instance. Tako npr. možemo kreirati instrukciju kojom će kontejner nakon kreiranja instance postaviti atribute objekta: 

Kontejner će kreirati objekat actor1 instanciranjem klase Actor (pozivom default konstruktora), nakon čega će postavljati atribute objekta pozivom odgovarajućih set metoda (npr. setFirstName). Treba napomenuti da recept može definisati upotrebu konstruktora i postavku atributa zajedno.

Dakle, xml datoteka definiše objekte koje će kontejner kreirati, odnosno kontejnersku konfiguraciju. Kreiranje samog kontejnera se oslanja na instanciranje neke od implementacija ApplicationContext interfejsa. Ukoliko se naša xml datoteka nalazi na classpath-u aplikacije, možemo koristiti ClassPathXmlApplicationContext klasu:

ApplicationContext ctx = new ClassPathXmlApplicationContext("application-config.xml");

 

Ovim iskazom se kreira kontejner a istovremeno i svi singleton objekti u kontejneru. Nakon ovoga moguće je dohvatiti kreirane objekte, ili preko njihovog tipa ili preko njihovog imena:

CinemaService cinemaService = ctx.getBean(CinemaService.class);

 

Metod getBean() će potražiti objekat tipa CinemaService u kontejneru i vratiti ga pozivaocu. U slučaju da navedeni bean nije singleton (prototype), u ovom koraku će taj objekat biti kreiran.

Da bi sve ovo radilo, aplikacija mora importovati odgovarajuće Spring biblioteke, u ovom slučaju spring-context biblioteku. Navedenu biblioteku možemo ručno ubaciti u projekat, ali preporučeni pristup je korištenje nekog od build alata koji omogućavaju dependency management, npr. maven čija konfiguracija (pom.xml) treba da definiše odgovarajući dependency: 

 

Struktura upravo opisanog projekta izgleda ovako:

 

Naravno, konfiguracija kontejnera ne mora biti zapisana u xml dokumentu. Veliki broj developera ne želi da oslanja na nezgrapnu xml strukturu te konfiguriše Spring kontejner unutar java klase. Pretpostavimo da se ta klasa naziva Config. Za kreiranje kontejnera sada moramo koristiti drugačiju ApplicationContext implementaciju:

ApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);

 

Klasa Config predstavlja običnu java klasu obogaćenu određenim anotacijama:

@Configuration

public class Config {

   ...

}

 

Anotacija @Configuration znači da se ova klasa koristi za konfiguraciju kontejnera. Ova klasa će biti instancirana odmah nakon kreiranja ApplicationContext instance. Unutar Config klase možemo definisati bean objekat na slijedeći način: 

@Bean
public Actor actor1(){
    return new Actor(1, "Brad", "Pitt");
}


@Bean(name="actor2")
public Actor actor2(){
    return new Actor(1, "Edward", "Norton");
}

 

Kao što vidimo, kreirali smo metode koje kreiraju Actor instance i koje su označene @Bean anotacijom. Spring će automatski izvršiti ove metode i njihove rezultate spremiti u kontejner, kao bean objekte sa nazivima actor1 i actor2. Ukoliko ove beane želimo koristiti za konstrukciju drugih objekta, možemo npr. napisati slijedeći kod:

@Bean
public Movie movie1(){
    Set actors = new HashSet>();
    actors.add(actor1());
    return new Movie(1, "Zodiac", 157, actors);
}

@Bean
public Movie movie2(Set actors){
    return new Movie(2, "Fight Club", 139, actors);
}

Bean movie1 će biti kreiran korištenjem beana actor1, a bean movie2 će biti kreiran uz pomoć referenci na oba Actor objekta. Obratite pažnju da metod movie2() ima argument kolekcije Actor objekata. Kontejner će u ovu kolekciju ubaciti sve bean objekte tipa Actor, a to su upravo actor1 i actor2. Dakle, kontejner automatski poziva @Bean metode i ubacuje druge bean objekte kao argumente tih metoda. Navedeni proces se naziva autowiring.

Postoje i drugi načini da kontejner kreira bean objekte. Npr. naša konfiguracijska klasa može imati slijedeću anotaciju: 

@Configuration
@ComponentScan(basePackages = "org.infobip.spring.ann")
public class Config {
   ...
}


@ComponentScan anotacija predstavlja instrukciju kontejneru da skenira odgovarajući java paket (i njegove podpakete) te da kreira bean objekte instanciranjem kandidatskih klasa. Kandidatska klasa je svaka klasa koja je označena nekom od slijedećih anotacija: @Service, @Component, @Repository i @Controller. Razlika između svih ovih anotacija je čisto semantičke prirode, a svaka će rezultirati instanciranjem klase i registracijom objekta unutar kontejnera. Npr.

@Service
public class CinemaServiceImpl implements CinemaService{
    private MovieRepository movieRepository;
    private ActorRepository actorRepository;

    @Autowired
    public CinemaServiceImpl(MovieRepository movieRepository, ActorRepository actorRepository) {
       this.movieRepository = movieRepository;
       this.actorRepository = actorRepository;
    }
   ...
 }
 

Ukoliko kontejner skeniranjem naleti na ovu klasu, pokušat će je instancirati. Obratite pažnju na @Autowired anotaciju; ona predstavlja instrukciju kontejneru da potraži bean objekte i ubaci ih u konstruktor navedene klase. To znači da i navedene klase trebaju biti instancirane uz pomoć kontejnera, uz pomoć @Bean metoda ili skeniranja komponenti. Klasa CinemaServiceImpl može izgledati i ovako:

@Service
public class CinemaServiceImpl implements CinemaService{
    @Autowired
    private MovieRepository movieRepository;
    @Autowired
    private ActorRepository actorRepository;
     
    public CinemaServiceImpl() {}
   ...
 }


I u ovom slučaju @Autowired anotacija omogućava automatsko ubacivanje objekata iz kontejnera u instancu posmatrane klase, baš kao što bi bio slučaj i da smo istu anotaciju postavili za odgovarajuće setter metode. Naravno, u ovom slučaju nećemo koristiti kontstruktor jer je kontejner obezbjedio postojanje povezanih objekata!

Naravno, ovo nije sve što se tiče bean objekata. Spring nam omogućava da definišemo metode koje će automatski biti pozvane nakon konstrukcije objekta, ili metode koje će biti pozvane prije njegovog uništavanja. Također, bean objekte je moguće kreirati uz pomoć factory objekata umjesto instanciranja klase. Kontejner (ApplicationContext) nije zadužen samo za konstrukciju objekata već i za dohvatanje informacija o okruženju u kojem se aplikacija izvršava, registraciju i slušanje aplikacionih događaja itd. Ove mogućnosti ostavljamo čitaocu za istraživanje uz još jednu napomenu da se izvorni kod primjera navedenih u ovom članku može preuzeti sa linka na početku teksta. Do narednog čitanja!

 

Almir Pehratović, Infobip BH d.o.o.

 

petak, 14 Juli 2017 12:18

Uvod u Spring Framework

Razvoj Java enterprise aplikacija uobičajeno zahtijeva upotrebu velikog broja različitih proizvoda, biblioteka i frameworka. Gotovo svaka oblast koju developer želi obuhvatiti svojom aplikacijom nudi alternative u vidu sličnih tehnologija, dovoljno različitih tek toliko da zadaju glavobolju prilikom izbora one prave, i da doprinesu vječitom samopropitivanju u smislu pravilnosti donesenog izbora. Spring framework je izuzetno opsežan aplikacioni framework koji znatno olakšava spomenutu dilemu, integrirajući razne open-source tehnologije u kohezivnu cjelinu obogaćenu različitim Spring unapređenjima.

Spring je dakle, prije svega ostalog, open-source Java platforma sa izuzetno kvalitetnom podrškom za razvoj aplikacija. Gotovo da ne postoji oblast koju ovaj framework nije obuhvatio svojim bogatim skupom modula i podprojekata. Želite napraviti web aplikaciju povezanu sa relacionom bazom podataka? Integrirati embedded web server i bazu podataka u izvršni fajl aplikacije? Kreirati SOAP ili REST servise? Umjesto relacione baze koristiti neku NoSQL varijantu? Povezati se na neku društvenu mrežu, npr. pisati po zidovima Facebook prijatelja? Spašavati datoteke na Dropbox account? Komunicirati sa drugim aplikacijama koristeći messaging servere tipa ActiveMQ ili RabbitMQ? Spring nudi sve ovo, i mnogo više.

Programiranje u Springu je vezano za koncept inverzije kontrole, poznatim i pod nazivom Dependency Injection. Ovaj koncept je praktično obezbijedio kreiranje loosely-coupled objekata i njihovo automatsko povezivanje u smislenu aplikacionu cjelinu od strane frameworka. Npr. posmatrajmo sljedeće dvije java klase:

package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

 @Configuration
public class AppConfig {
@Bean
public DateFormat defaultDateFormat() {
return new SimpleDateFormat("dd.MM.yyyy hh:mm:ss");
 }
}

package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.DateFormat;
import java.util.Date; 

@RestController
public class HomeController {
 private DateFormat dateFormat;
 

 public HomeController(DateFormat dateFormat) {
 this.dateFormat = dateFormat;
 }
 @GetMapping("/")
 public String home() {
 return dateFormat.format(new Date());
 }
}

Klasa označena @Configuration anotacijom će biti instancirana veoma rano u životnom ciklusu aplikacije, prilikom njenog startupa. Tom prilikom, Spring će izvršiti svaku metodu označenu @Bean anotacijom i rezultat metode spasiti u registry objekata koji se naziva aplikacionim kontekstom. U ovom slučaju, aplikacioni kontekst sadrži singleton objekat pod nazivom defaultDateFormat. Klasa HomeController predstavlja REST kontrolera, odnosno još jednu klasu koju Spring automatski instancira za nas. Treba primijetiti da konstrukcija homeController objekta zahtijeva prisustvo objekta tipa DateFormat. Spring će u ovom slučaju pretražiti aplikacioni kontekst, pronaći defaultDateFormat objekat i iskoristiti ga za instanciranje HomeController klase. Kao što vidimo, Spring je izvršio instanciranje pojedinačnih klasa, te riješio njihove međusobne ovisnosti. Programer se može brinuti o pisanju aplikacione logike, a sve detalje instanciranja, redoslijeda, povezivanja i uništavanja objekata prepustiti frameworku.

Još jedna stvar koju Spring radi izuzetno dobro jeste apstrahiranje programskih koncepata. Pretpostavimo npr. da želimo implementirati logiku keširanja podataka koje čitamo iz baze podataka. U tu svrhu možemo iskoristiti Guava biblioteku. Ukoliko nakon nekog vremena, iz bilo kojeg razloga, poželimo koristiti neko drugo rješenje, recimo EhCache, morat ćemo mijenjati kôd i koristiti sasvim novi programski API. Spring sa druge strane obezbjeđuje generički API za keširanje, koji u pozadini može koristiti Guavu, EhCache, Caffeine, Gemfire ili neku sličnu tehnologiju. Zapravo, odabir konkretne tehnologije je u ovom slučaju stvar konfiguracije. Navedeni pristup osigurava ne samo jednostavnu zamjenu kešing rješenja, nego isto tako čini cijeli pristup pisanja keširanja znatno bržim i jednostavnijim - umjesto više API-ja mi trebamo poznavati samo jedan.

Možda i najočiglednija prednost Spring frameworka, iz ugla programera, se ogleda u njegovom ekosistemu odnosno velikom broju modula i projekata koji daju zaista velike mogućnosti u razvoju enterprise aplikacija. Ova modularnost osigurava da aplikacija, ručno ili upotrebom dependency management alata kao što je Maven, importira samo one module koji joj zaista trebaju. Tako, ako želimo razvijati web aplikaciju treba nam spring-mvc, za razvoj messaging funkcionalnosti možemo koristiti spring-integration, za baze podataka koristiti spring-data-jpa, itd. Pored ovih "funkcionalnih" modula, Spring sadrži i module koji predstavljaju totalne nove paradigme programiranja Spring aplikacija, kao što su Spring Boot, Spring Groovy ili Spring Roo. Ovdje ćemo posebno naglasiti Spring Boot kao najefikasniji i najbrži način ulaska u svijet Springa, i u narednim postovima ćemo koristiti upravo ovaj projekat za objašnjavanje koncepata i pisanje aplikacija u Springu.

Naravno, Spring framework je nemoguće opisati u jednom članku i zbog toga vam savjetujemo da posjetite https://spring.io radi dodatnih detalja. Na linku https://spring.io/guides može se naći veliki broj početnih primjera, dok https://spring.io/projects nudi pregled svih Springovih projekata i njihovih mogućnosti. U narednom članku ćemo početi pisati prve primjere, predstavljajući ključne koncepte frameworka. Do narednog čitanja....

Almir Pehratović, Infobip BH d.o.o. https://www.infobip.com/en/about

Igre su se razvijale stoljećima, a nakon pojave katodne cijevi otvorile su se mogućnosti za novu vrstu igara koju čovjek još nije vidio. Ralph Baer je u to vrijeme razmišljao o igranju igara u kući i to na malim ekranima. Tako je davne 1951. godine začeta ideja o video-igrama da bi 1967. gospodin Baer istu i realizirao, kreirajući Brown Box, prvu kućnu konzolu za video-igre. Od tog momenta video-igre su krenule na svoj put ka osvajanju svijeta zabave.

Dokumentarista Muzeja grada Zenice Alen Karamehić, pasionirani zaljubljenik u video-igre, odlučio se da svoj hobi poveže s onim što radi, pa je u muzeju organizirao izložbu pod naslovom Power Up. Izložba je otvorena 17. februara u Muzeju grada Zenice. Izložba je posvećena kratkoj historiji videoigara i predstavlja svojevrsni vremeplov kroz njihovu evoluciju. Počev od Atarija 2600 iz 1978. godine na čijem se portabl crno-bijelom televizoru vrtio popularni Frogger, preko ZX Spectruma, Commodorea 64, Nintendo konzola, Amige 1200 pa sve do Sega Saturna iz 1999.  gdje se zaista vidi koliko su se video-igre modernizirale tijekom 35 godina evolucije koje ova izložba pokriva.

Posjetioci izložbe imaju priliku čak i da isprobaju nekadašnje hit naslove kao što su: Pac-Man, Commando, Arkanoid, Giana Sisters, Super Mario Bros, Sonic the Hedgehog, Street Fighter 2 Turbo, Doom, Alien Breed, itd., a sve na originalnim konzolama i računalima iz tog doba. Također su izložene i ručne igraće konzole počev od Gameboya, preko Sega Game Geara, sve do Playstation Vite.

Izložbu, pored još uvijek funkcionalnih uređaja za igranje, prate i informativni panoi, posteri videoigara, te časopisi o video-igrama iz osamdesetih i devedesetih godina prošlog, a i oni s početka ovog stoljeća, koji su odlično upotpunili čitav doživljaj ove jako zanimljive postavke.

Planirano je da ova muzejska postavka bude otvorena za posjete (uz besplatan ulaz) do kraja marta, tako da svi ljubitelji videoigara, a i oni koji to nisu, mogu pogledati izložbu, pustiti da ih nostalgija vrati u neka prošla vremena, a ukoliko su roditelji, da pokažu svojoj djeci kako su video-igre izgledale nekad i da im priušte priliku da osjete kako se nekad igralo. Bilo bi zanimljivo da ova izložba, inače prva takve vrste u jugoistočnoj Europi, napravi turneju po drugim gradovima ali i susjednim zemljama, kako bi i oni koji nisu uspjeli da je pogledaju, imali priliku osjetiti digitalnu nostalgiju.

Autor: Samir Lemeš 

petak, 15 Januar 2016 21:00

Najočekivanije igre u 2016. godini

Ahem. Brzinski osvrt na našu listu najočekivanijih naslova u 2015. je i više nego dovoljan da shvatite kako smo se u januaru prošle godine malčice preračunali - od 19 naslova sa liste, njih čak 8 nije ugledalo svjetlo dana u proteklih dvanaest mjeseci. Neki od njih su odgođeni za ovu godinu, neki na neodređeno, a o nekima se njihovi developeri uopšte nisu ni izjašnjavali. Stoga smo ovaj put odlučili biti pažljiviji - na svojim Top 10 listama najočekivanijih naslova, naši recenzenti su uvrstili samo one igre za koje smo 99% sigurni da ćemo ih igrati ove godine.

Drugim riječima, koliko god ih mi željno iščekivali, igre kao što su Mass Effect Andromeda, Dishonored 2 i NieR: Automata su potisnute u drugi plan i naći ćete ih tek na našoj ‘I još malo igara na koje treba obratiti pažnju u 2016. godini’ listi.

petak, 08 Januar 2016 19:30

Najbolje igre 2015. godine

Jednom davno, tamo negdje početkom januara dvije i petnaeste, pitali smo se da li je pred nama najbolja godina u historiji igara. Nekoliko mjeseci, odgoda i razočarenja kasnije, postalo nam je jasno da smo od 2015. možda i očekivali previše. U drugu ruku, bilo je tu i nekih zaista fantastičnih igara i jako ugodnih iznenađenja, tako da se na kraju ispostavilo da sa našim odvažnim predviđanjima nismo bili daleko od istine.

Posebno su nas oduševili monumentalni RPG-ovi svih vrsta i oblika, kao i raznolikost igara sa kojima su nas developeri - veliki i mali - počastili tokom proteklih dvanaest mjeseci. Isto tako smo ostali iznenađeni gomilom odličnih ekspanzija za neke nama vrlo drage naslove, ali i ponekom koja bi nas natjerala da ljudima počnemo preporučivati igre u kojima ranije i nismo toliko uživali.

četvrtak, 31 Decembar 2015 18:00

Sretna Nova godina!

Znamo da ste u frci sa pripremama za proslavu Nove godine i ne sumnjamo da neki od vas tek trebaju okititi svoje jelke i pripremiti klopu i piće za večeras, pa vas nećemo puno gnjaviti - iza nas je još jedna godina, u kojoj smo dočekali nove Windowse, koji su ispravili skoro sve grijehe Osmice, ali i Appleov dugo očekivani izlet u vode pametnih satova. Bilo je tu i drugog zanimljivog hardvera, od Pro verzije iPada, pa do bezbroj novih telefona i nekoliko novih modela minijaturnih Raspberry Pi računara. A da i ne spominjemo sve one fantastične igre, od poslastica za ljubitelje RPG-a u vidu BloodborneaWitchera 3 i Obisidianovih Pillarsa, pa do ultimativne verzije fudbala u kojoj smo uživali - i još uvijek uživamo - u Rocket Leagueu.

Tu i tamo smo se znali vratiti i našoj staroj rubrici SF Corner, pa smo tako pisali o novijim SF filmovima vrijednim vaše pažnje, ali i o odličnom novom nastavku kultne Star Wars sage, dok su kroz naše druge rubrike prošli brojni novi online servisi i tehnologije.

No, dosta priče o 2015. - vrijeme je da pogled bacimo u budućnost i na sve ono što nas čeka u 2016. godini, a o čemu ćemo pisati idućih 12 mjeseci (u biti, nadamo se jeftinim VR headsetovima, iako već uveliko štedimo za njih, jer znate već šta kažu za nadu).

Bilo kako bilo, ekipe portala Info Online i TV emisije Terminal vam žele sretnu i uspješnu novu 2016. godinu! Čitamo se - i gledamo - u januaru!

Stranica 8 od 9