• Anasayfa
  • Eğitimler
    • JavaScript Eğitimi
    • Angular 2 Eğitimi
    • React.js Eğitimi
    • Java 8 Eğitimi
    • Java EE 7 Eğitimi
    • Spring Framework Eğitimi
    • Git Eğitimi
  • Online Eğitimler
    • Online React.js Eğitimi
    • Online Angular 2 Eğitimi
    • Online Spring Boot Eğitimi
  • Referanslar
  • Hakkında
  • İletişim
KodEdu
  • Anasayfa
  • Eğitimler
    • JavaScript Eğitimi
    • Angular 2 Eğitimi
    • React.js Eğitimi
    • Java 8 Eğitimi
    • Java EE 7 Eğitimi
    • Spring Framework Eğitimi
    • Git Eğitimi
  • Online Eğitimler
    • Online React.js Eğitimi
    • Online Angular 2 Eğitimi
    • Online Spring Boot Eğitimi
  • Referanslar
  • Hakkında
  • İletişim

JaxRS 2 – HTML 5 SSE (Server Sent Events)

  • Posted by Kodedu
  • Categories backend, Genel, Tutorial, Uncategorized, Yazılar, Yazılım
  • Date 4 Temmuz 2013

SSE (Server Sent Events), HTML5 teknolojisi içinde geliştirilen bir Web Pushing teknolojisidir. Peki Pushing nedir?

Pushing

Sunucu uygulama üzerinden belirli aralıklarla güncellenen veri kümelerinin, web tarayıcının talebi olmadan, sunucu – – – > tarayıcı yönünde iletilmesidir. Twitter güncellemelerinin web sayfasında belirli aralıklarla güncel olarak sunulması, Facebook paylaşımlarının yeni paylaşım oldukça ekranda belirmesi, anlık finansal verilerin (dolar kuru, parite vs..) anlık olarak kullanıcı ekranlarına sunulması, pushing uygulamalarına örnek verilebilir.

Server Sent Events, pushing için kullanılan tek teknik değildir elbette, bundan önceki şuradaki yazıda, LongPolling tekniğiyle nasıl web tarayıcıya veri yayılımı sağlancağından bahsetmiştik. Push teknolojilerini sıralama ile gösterirsek, sanırım şu sıralama yanlış olmaz;

Polling –> LongPolling –> ServerSent Events –> WebSocket

ServerSent Events, halihazırda geliştirimi devam edilen bir teknoloji, WebSocket teknolojisinde olduğu gibi. Bu sebeple her web tarayıcıda kullanılamayabileceğini ve elbette yeni nesil web tarayıcıları tarafından desteklendiğini belirtmek isterim.

SSE teknolojisinin diğerlerinden farklı olarak birkaç ek özelliği bulunuyor. Bağlantı koptuğunda otomatik bağlanma, olay dağıtımlarında mesajın özgün bir fonksiyona yönlendirilmesi gibi. Örneğin SSE vs WebSocket karşılaştırmasına dair tartışmayı StackOverFlow adresindeki girdiden inceleyebilirsiniz.

Çalışma mantığı

SSE teknolojisinin çalışma mantığı aşağıdaki resimde görüldüğü gibi olmaktadır. Web tarayıcı tarafından, SSE desteklenen sunucuya bir el sıkışma isteği (handshake request) iletilir, sunucu sistem ise “text/event-stream” veri türünde bir el sıkışma yanıtı (handshake response) döndürür. Web tarayıcı ve SSE servisi tarafından el sıkışılan SSE söyleşmesiyle artık, sunucu istediği miktarda ve istediği anda veri kaynaklarını tarayıcı yönünde iletebilir.

jaxrs-sse

Java EE 7 standart teknoloji şemsiyesi altında bulunan JaxRS 2 standardı, 2. versiyonuyla birlikte SSE (Server Sent Events) teknolojisine destek sunmaktadır. Şimdi ise Twitter REST Api kullanarak bir kelimeyi arama yapan ve elde ettiği sonuçları tüm istemcilere sunan bir Jax-RS 2 uygulamasını birlikte gerçekleştirelim.

Bağımlılıklar

Jax-RS 2, Java EE 7 standart kümesi altında bulunur ve referans uygulayıcı kütüphanesi Jersey 2‘ dir. Bu maksatla eğer uygulama Glassfish 4 uygulama sunucusunda koşturulmak isteniyorsa, bir Maven bağımlılığı olarak pom.xml konfigürasyon dosyasına eklenmelidir.


<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>

SSE teknolojisi, Jersey 2 kütüphanesinin harici bir özelliği olarak uygulamalara eklenebilmektedir. Yani Jersey 2 core kütüphanesinde SSE özelliği bulunmaz, bir eklenti/özellik biçiminde bir bağımlılık olarak eklenmelidir.


<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>2.0</version>
</dependency>

Uygulama içerisinde JSON nesne ve dizilerini kolaylıkla yönetmek adına yine Java EE 7 dahilindeki bir standart olan Json-P’ yi kullanacağız. Bu maksatla “javax.json” bağımlılığı pom.xml içerisinde eklenmelidir.


<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.0</version>
</dependency>

Uygulama bir Twitter araması gerçekleştireceği için, Twitter REST Api versiyon 1.1 kullanmak durumundadır. Bu maksatla, Twitter REST Api kullanımını esnekleştiren Twitter4j kütüphanesinden faydalanılabilir.


<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>3.0.3</version>
</dependency>

Eğer uygulama bir uygulama sunucusu haricinde Jetty veya Tomcat gibi tüğ siklet Servlet Konteyner ortamlarında çalıştırılması da isteniyorsa, pom.xml içerisinde “jersey-container-servlet” bağımlılığı da eklenebilir.


<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.0</version>
</dependency>

Konfigürasyon

Bir Jax-RS sunucusuna giriş noktası için, uygulama içerisinde bir REST Endpoint sınıfı eklenmelidir.


@ApplicationPath("/search")
public class SearchEndpoint extends Application {

@Override
public Set<Class<?>> getClasses() {

   Set<Class<?>> classes=new HashSet<>();
   classes.add(SearchResource.class);
   return classes;
}

@Override
   public Set<Object> getSingletons() {
   Set<Object> singletons=new HashSet<>();
   singletons.add(new SseFeature());
   return singletons;
}
}

Application#getClasses() metoduna dikka kesildiğinde SearchResource isimli Java sınıfının bir RESTful kaynağı olarak yapılandırıldığı ve Application#getSingletons() metodunda ise SseFeature sınıfı üzerinden SSE özelliğinin RESTful uygulamasına tanıtıldığı görülmektedir.

SearchResource RESTful kaynağı

SearchResource isimli Java sınıfı, web tarayıcı-sunucu arasında SSE el sıkışmasını sağlayan ve sunucu üzerinde yapılan Twitter aramalarını kullanıcılara dağıtan (broadcast) bir REST kaynağıdır.


@Path("/")
public class SearchResource {

private static final SseBroadcaster BROADCASTER = new SseBroadcaster();
private static final ScheduledExecutorService sch = Executors.newSingleThreadScheduledExecutor();

static {

 sch.scheduleWithFixedDelay(
      new SearchTwitTask(BROADCASTER)
      ,0 // Twitter aramasına hemen başla (0 sn)
      ,30 // 30 saniyede bir SearchTwitTask'in run() metodunu koştur.
      ,TimeUnit.SECONDS);

}

@GET
@Produces("text/event-stream")
@Path("/hang")
public EventOutput getMessages() {

	EventOutput eventOutput = new EventOutput();
	BROADCASTER.add(eventOutput); // Dağıtım listesine ekleniyor
	return eventOutput;
}

 }

Jax-RS ile SSE teknolojisi üzerinden veri dağıtımı gerçekleştirilmek isteniyorsa bir SseBroadcaster nesnesi oluşturulmalıdır. Sunucuya istek yapan her bir client, bu SseBroadcaster nesnesine eklenirse, SseBroadcaster#broadcast(..) metodu üzerinden tüm kullanıcılara veri dağıtımı yapılabilir.

SseBroadcaster sınıfı her bir tekil kullanıcıyı EventOutput sınıfı türünden bir nesneyle içerisinde barındırır. Örneğin bir kullanıcı SearchResource#getMessages metoduna bir RESTful isteği yaptığında, yeni bir EventOutput nesnesi oluşturulmaktadır. Oluşturulan EventOutput nesnesi, o anki kullanıcıyı temsil eden bir dağıtım nesnesi durumundadır. getMessages() metodu üzerinde oluşturulan EventOutput nesnesi, dağıtıcı özellikli SseBroadcaster eklenir ve “text/event-stream” veri biçiminde kullanıcıya geri gönderilir. “text/event-stream” türünden Handshake verisini alan Web tarayıcı ise, sunucu tarafından verileri alabilir hale gelir.

30 saniyede bir arama yapılması ve kullanıcılara dağıtılması


public class SearchTwitTask implements Runnable {

private SseBroadcaster broadcaster;

public SearchTwitTask(SseBroadcaster broadcaster) {
this.broadcaster = broadcaster;
}

@Override
public void run() {

// JsonArray oluşturucu
JsonArrayBuilder jsonArray = Json.createArrayBuilder();
// JsonObject oluşturucu
JsonObjectBuilder jsonObject = Json.createObjectBuilder(); 
/* Twitter4J konfigürasyon ve arama */
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
    .setOAuthConsumerKey("kkkkkkkkkkkkk")
    .setOAuthConsumerSecret("sssssssssssssss")
    .setOAuthAccessToken("ttttttttttttttttttttt")
    .setOAuthAccessTokenSecret("tttttttttttttttttttsssssssssssss");

Twitter twitter = new TwitterFactory(cb.build()).getInstance();

QueryResult result = null;
try {
// Java EE ile ilgili twit'ler aranıyor.
result = twitter.search(new Query("Java EE")); 

// Dönen kayıtların çeşitli bilgileri birer birer JsonObject nesnesine ekleniyor.
for (Status status : result.getTweets()) { 
	jsonObject.add("created_at", 
	       status.getCreatedAt().toString());
	jsonObject.add("from_user_name",
	       status.getUser().getScreenName());
	jsonObject.add("profile_image_url",
	       status.getUser().getProfileImageURL());
// JsonObject nesnesi son olarak bir JsonArray nesnesine ekleniyor.
	jsonArray.add(jsonObject.add("text",   
	       status.getText()));
}
} catch (TwitterException e) {
e.printStackTrace(); 
} /* Twitter4J konfigürasyon ve arama */


// Dönen bilgiler Json dizisi olarak elde ediliyor
String twitJsonArray= jsonArray.build().toString(); 

// Kullanıcılara dağıtılacak bir olay bildirim nesnesi oluşturuluyor
OutboundEvent.Builder b = new OutboundEvent.Builder();
// Veri "application/json" olarak gönderilecek
b.mediaType(MediaType.APPLICATION_JSON_TYPE);

// Veri dağıtıcıya eklenmiş tüm kullanıcılara dağıtılıyor.
broadcaster.broadcast(b.data(String.class,twitJsonArray).build());

}
}

SearchTwitTask sınıfı Runnable arayüzü türünden, 30 saniye aralıklarla SchedulerExecutorService nesnesi ile koşturulan bir Görev sınıfıdır. @Override edilen Runnable#run metodunda sırasıyla önce “Java EE” ifadesi geçen Twitter kayıtları aranmakta ve elde edilen kayıtlar Json-P kütüphanesiyle JsonArray nesnesi olarak elde edilmektedir.

Jax-RS 2 ile yapılacak broadcast işlemleri geliştirici tarafından oluşturulacak OutboundEvent nesnesi olarak kullanıcılara iletilebilmektedir. SearchTwitTask sınıfında, MIME biçimi “application/json” olarak tanımlanan String türünden twitJsonArray verisi, SseBroadcaster sınıfının broadcast metodu üzerinden tüm uygulama tüketicilerine dağıtılmaktadır.

SSE HTML tarafı


<!DOCTYPE html>
<html class=" js no-touch svg inlinesvg svgclippaths no-ie8compat js no-touch svg inlinesvg svgclippaths no-ie8compat">
<head>
<title></title>
<meta charset="UTF-8">
<link type="text/css" rel="stylesheet" href="http://cdn.jsdelivr.net/foundation/4.0.4/css/foundation.min.css">
<link type="text/css" rel="stylesheet" href="http://cdn.jsdelivr.net/foundation/4.0.4/css/normalize.css">
</head>
<body>

<!-- Header and Nav -->
<div class="row">
<div class="large-12 columns">
<div class="panel">
<div class="row">
<div class="large-6 columns">
	<h1>Twitter Search Broadcaster</h1>
</div>
<div class="large-6 columns" >
	Pushes new data searhed for Java EE in every 30 seconds.
</div>
</div>
</div>
</div>
</div>

<!-- End Header and Nav -->
<div class="row" id="alertbox" style="display: none;">
<div class="large-12 columns">
<span class="alert-box alert">Your browser doesn not support HTML 5 SSE :(</span>
</div>
</div>

<div class="row">
<!-- Feed Placeholder -->
<div id="feeds" class="large-12 columns"></div>

</div>

<!-- Footer -->
<footer class="row">
<div class="large-12 columns">
<hr>
<div class="row">
<div class="large-12 columns">
<p>© Twitter Search Broadcaster | kodedu.com</p>
</div>
</div>
</div>
</footer>

<script type="text/x-mustache-template" id="feedTemplate">
{{#.}}
<!-- Feed Entry -->
<div class="row">
<div class="large-1 columns small-3"><img style="min-height: 60px;min-width: 60px;" src="{{profile_image_url}}">
</div>
<div class="large-11 columns">
<div class="row">
<div class="large-12 columns">
	<p><strong>{{from_user_name}} said:</strong> {{text}}</p>
</div>
<div class="large-12 columns">
	<p><strong>Created date:</strong> {{created_at}}</p>
</div>
</div>

</div>
</div>
<!-- End Feed Entry -->

<hr>
{{/.}}
</script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.7.2/mustache.min.js"></script>
<script type="text/javascript" src="resources/jaxrs-sse.js"></script>
</body>
</html>

Twitter araması yapılan uygulamanın, HTML tarafında aşağıdaki teknolojiler kullanılmaktadır.

  • Foundation Zurb: Twitter Bootstrap alternatifi
  • Jquery: Herkesin bildiği şey 🙂
  • Mustache.js: Basit bir Template çözümü

SSE Javascript tarafı


(function () {

if((typeof EventSource)==="undefined")
{
   // SSE desteklenmiyorsa
   $("#alertbox").css("display","");
   return;
}

// SSE servisine bağlan
var eventSource = new EventSource("search/hang");

// SSE Handshake sağlandığında
eventSource.onopen = function (e) {
 console.log("Waiting message..");
};

// Hata olduğunda
eventSource.onerror = function (e) {
 console.log("Error");
 console.log(e);
};

// Mesaj geldiğinde
eventSource.onmessage=function (e) {
   console.log(e);
   var feedTemplate = $("#feedTemplate").html();
   var feeds = Mustache.render(feedTemplate, $.parseJSON(e.data));
   // Gelen Json veri template ile render edilir ve ekrana basılır
   $("#feeds").html(feeds);
};

})();

HTML 5 SSE teknolojisinin Javascript taraflı ana nesnesi EventSource’ dir. EventSource nesnesi oluşturulur oluşturulmaz, SSE servisine bir URL ile istekte bulunmakta ve bağlanma durumuna, hata durumuna ve mesaj gelme durumlarını yönetmek için bulunan onopen, onerror, onmessage alanlarına bağlı Callback fonsiyonlarını işletmektedir.

Uygulamanın çalıştırılması

Twitter araması uygulaması, iki yollar çalıştırılabilir.

1. Yol (Gömülü jetty eklentisi ile)

> mvn clean package jetty:run-war

2. yol (Glassfish 4 uygulama sunucusu ile)

> mvn clean package > asadmin start-domain > asadmin deploy JaxRS-SSE-1.0.war

İki yöntemin biriyle çalıştırılan uygulamlara http://localhost:8080/JaxRS-SSE adresinden erişebilirsiniz.

Canlı Örnek: http://discoverjavaee.com/JaxRS-SSE/

Uygulama kodlarına: https://github.com/rahmanusta/JaxRS-SSE adresinden erişebilirsiniz.

Tekrar görüşmek dileğiyle.

Tag:backend, HTML 5, javaee7, jax-rs 2, server sent events

  • Share:
author avatar
Kodedu

Previous post

Jax-RS 2 and LongPolling based Chat Application
4 Temmuz 2013

Next post

CDI - @Produces, @New ve @PostConstruct Notasyonları
22 Temmuz 2013

You may also like

api-logo
Swagger Nedir? Neden kullanılır?
10 Ekim, 2018
spring-cli-logo
Spring CLI ile Spring Boot Projeleri Hazırlamak
21 Ağustos, 2017
eureka_architecture
Spring Cloud Netflix ve Eureka Service Discovery
3 Temmuz, 2017

Leave A Reply Cevabı iptal et

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

E-posta listesine kayıt olun!






Gözde yazılar

Hafif bir Kod Editörü – Brackets
30Haz2012
Java’da Record’lar
27Oca2020
Reflection ile Dependency Injection nasıl gerçekleştirilir?
04Eyl2012
Integration of Spring MVC and Mustache
02Ağu2013

Son Yazılar

  • Java’da Record’lar 27 Ocak 2020
  • Swagger Nedir? Neden kullanılır? 10 Ekim 2018
  • Spring CLI ile Spring Boot Projeleri Hazırlamak 21 Ağustos 2017
  • Spring Cloud Netflix ve Eureka Service Discovery 3 Temmuz 2017
  • Online React.js Eğitimi ardından (15-25 Mayıs 2017) 31 Mayıs 2017

Son Yorumlar

  • Coupling ve Cohesion Kavramları Nedir? için Hilal
  • Naïve Bayes Sınıflandırma Algoritması için Rahman Usta
  • Naïve Bayes Sınıflandırma Algoritması için Mete
  • YAML Nedir? Neden YAML Kullanmalıyız? için kara
  • JWT (JSON Web Tokens) Nedir? Ne işe yarar? için Furkan

Get Java Software

Arşivler

Bizi takip edin

React.js Eğitimi Başlıyor
11-22 Eylül, 2017
Eğitmen
Rahman Usta
İletişim

merhaba@kodedu.com

  • Hakkında
  • Gizlilik Politikası
  • İletişim
  • Referanslar
Kodedu Bilişim Danışmanlık
Cemil Meriç mah. Çelebi sok.
No:16/3 Ümraniye/İSTANBUL
Tel: 0850 885 38 65
Alemdağ V.D.: 8960484815

KODEDU © Tüm hakları saklıdır.