29 Haziran 2013 Cumartesi

Man Of Steel

Çok fazla çizgi roman okumuşluğum falan yoktur aslında fakat Superman'i sanırım herkes bir şekilde bilir küçüklüğünden beri. Benim için çizgi filmleri, 78 yapımı filmi ve 'Superman Returns' ibaretti aslında. Uzun zamandır sinemaya gitmediğim için ve gerçekten bu tarz bir film izlemeyi özlediğim için büyük bir heyecanla gittim aslında filme.


Öncelikle belirteyim bu 3D film furyası başladığından beri, üç boyutsuz izlemek istediğim filmleri o şekilde izleyememek, güzel senaryosu vs. olan filmlerin de üç boyutlu yapılmak uğruna efektlere falan boğulması beni en sinir eden şeydi fakat bu film o konuda çok başarılı diyebilirim. Süper kahraman filmlerindeki klasik olan dünyayı kurtarma kısımları başlamadan önceki kahramanın geçmişinin anlatıldığı kısımlar genelde çok kısa olup hemen aksiyona geçilmek istenir. Man of Steel'de bu durum çok güzel aşılmış bence. Filmin yaklaşık %20lik bir bölümünde nam-ı değer Superman'in doğuşu, gezegeninin geçmişi, dünyamıza gelişi gibi konular işlenmiş. Bu kısımlara hatta apayrı bir film gözüyle bile bakılabilir bence ve çok başarılı olmuş. Kısa kesilmemiş, insanı sıkacak kadar uzatılmamış, konu hemen geçilmemiş, efektler, aksiyon ve senaryo ile izleyiciyi ekranda tutmuş bu bölümler. Superman'in dünyaya gelişi sonrası çocukluğu, büyümesi, özelliklerini insanlardan gizleme çabası da ilk bölümden apayrı bir şekilde işlenmiş, daha sakin geçen, insanları kurtardığı bölümlerle filmin ana düşüncesinden insanları koparmayan bir bölüm olmuş. Filmin son bölümleri ise malum zaten, aksiyon patlaması. Kal-El'in zamanla dünya şartlarına adapte olup kendi gezegeninin atmosferine, materyallerine karşı zayıf düşmesi, ileride muhtemelen kendisini zor durumda bırakacak olan kriptonitin de neden buna sebep olacağını izleyiciye göstermiş ve güzel olmuş. Bunu yaparken insanın gözüne gözüne yeşil bir madde sokmayıp bu şekilde bir senaryodan gidilmesi de oldukça mantıklı olmuş. Ayrıca artık bu tarz filmlerde oldukça sık rastlanılan ufak espriler ve komiklikler de güzel bir renk katmış diyebilirim. Dünya'yı yok etme senaryosuna gelirsek, bence oldukça orijinal olmuş iki taraftan yer çekimini kullanmak. Fakat dünyayı ele geçirme sebebi için aynısını söylemeyeceğim. Arkadaşım koskoca uzayda başka gezegen mi yok da illaki dünya ile uğraşıyorsun. Al gezegeninin çocuk tarlasına sahip gemiyi ve git :) Şaka bir yana o noktada ufak bir zayıflık var ama film Superman'i biraz tanıtan bir film olduğundan ötürü her şeyden çok konulmamış; aynı kriptonitin çok kullanılmaması gibi dünyayı ele geçirme senaryosunun da üzerinde, detay olarak çok düşünülmemiş. Bu durum filmi kötü bir film yapıyor mu? Bence kesinlikle hayır. Benim gözümde hatta eksik denilebilecek tek ufak nokta burası olmuş. Bu senaryonun daha derinleşmesi ve Superman'in dünyadaki halkın sevgisini kazanıp onlarla kader birliği yapması durumunda zaten film bir Dark Knight seviyesine gelir.

Oyunculara geleyim önce. Fragmanı izlediğim zaman kim bu adam demiştim açıkçası. Henry Cavill rolüne tam gitmiş, adam net bir Superman yahu (alnında saçının kıvrılmamış olmasını saymazsak :). Bence oyunculukla aynı seviyede olan şey varsa, o kıyafeti vücuduyla doldurmaktır kesinlikle. Adamda çok başarılı bir vücut var. İleri derecede oyunculuk gerektirecek filmler için belki erken fakat vücut isteyen ne bileyim süper kahraman, kötü adam rollerinde kendisini artık görebileceğiz gibi geliyor. Lois Lane'imiz ise, rolüme çok gitmiş olan Amy Adams. Zaten filmin devamının geleceği bariz. Detayları okumadım, bir kaç filmlik anlaşıldı mı falan ama bu ikilinin devam etmesi bence oldukça güzel olur.

Herkesin çok tartıştığı kıyafet kısmına gelirsek. Ben genel olarak süper kahramanların tayt giymesine karşıyım o ayrı :) ama bence kırmızı slipsiz daha bir iyi olmuş gibi kıyafet. Eski çocuksu kırmızı-mavi ikilisinden biraz daha ürkütücü, daha heybetli, daha cool duran bir kıyafet olmuş. Pelerindeki logunun olmayışını filmin sonlarına doğru fark ettim ki bu da kötü durmamış demek ki. Benim her şeyden çok logo hoşuma gitti. Yani tam bir Superman Ssi değil, biraz daha farklı formatta, daha güzel bir logo olmuş. Özetlersek kıyafetin bu hale gelmesi bence genel olarak güzel olmuş. Yani Batman serilerine de bakarsak, bugün çekilecek bir filmin, siyah üzerine sırıtan sarılarla dolu retro bir kıyafet olmasını artık kimse istemez sanırım, bu da öyle bir şey işte.

Üç boyutlu filmlerdeki, 'Aman üç boyutlu film yaptık, herşeyi derin yapalım, show yapalım' anlayışı sanırım biraz biraz yıkılıyor. Zira bu filmde de benzer bir durum vardır. Efektlerde üç boyut kararında kullanılmış. Zaten karanlık ve hızlı sahnelere sahip filmlerde tam bir işkenceye dönüşüyor bence üç boyut ki bu filmde aynı hataya düşülmemiş. IMAX ise zaten ayrı bir keyif. Binalar arasındaki dövüş sahneleri, sesler, her bir yere çarpınca kırılan, çöken betonlarda kriptondan gelenlerin gücünün yansıtılışı, gezegende filmin başında geçen sahneler, kripton gezegenini parçalanışı... Uzun bir aradan sonra, geç bir saatte gitmeme rağmen bir filmi, saatime hiç bakmadan bitirdim diyebilirim.

After Earth, World War Z ve bu film arasında kalmıştım. Biraz yorum okudum ve sanırım akıllı bir tercih yapmışım. Filmi çok beğendim. Dark Knight seviyesinde tabi ki olmasa da, çok da uzak demeyeceğim ama. Diğer filmini dört gözle bekliyor olacağım. Süper kahraman filmlerini sevenler için kaçırılmaması gereken bir film ki bazıları özellikle Superman hayranıdır, o zaman kesinlikle kaçırmayın derim. Paraya kıyıp IMAX'de izlenmesi gerekiyor. Blueray'ini de çıktığı gibi edinip bir parti de evdeki büyük ekran TV'de izlemeyi planlıyorum. Kaçırmayın derim...

( man of steel, superman, henry cavill, amy adams, kriptonit, imax )

14 Mayıs 2013 Salı

JSF Ajax Requestlerdeki Tarayıcı Geri Butonu Sorunu ve Dojo İle Çözümü

Yine JSF kodlama ve yeni bir sorun ile karşı karşıyayız :) Aslında problem tam olarak JSF ile ilgili değil. Bir web uygulaması içerisinde AJAX request gönderildiğinde, URL üzerinde herhangi bir değişiklik olmuyor ise, tarayıcılar, hash değeri değişmediği için, içinde bulunduğu sayfayı tarayıcının History stack'ine eklemiyor. Dolayısıyla siz aynı sayfanın üzerinde bir çok işlem yapsanız bile, tarayıcıdaki sayfa adresi değişmediği için geri ve ileri butonlarını kullanamıyoruz.

Bu probleme çözümler mevcut aslında. Çoğu kişi tarayıcı geri-ileri butonlarını kullanıcıya kullandırtmak yerine uygulama içerisinde kendisinin oluşturduğu geri-ileri butonlarını javascript metodları vasıtasıyla kullandırtıyor. Fakat yine de tarayıcının butonlarına bir çözüm bulunmalı ve mevcut sürece entegre edilmeli. Bu noktada, araştırıp, biraz modifiye ederek uygulamamda kullandığım bir yöntemden bahsedeceğim.

Primefaces 3.5 ve JSF 2.1 kullanarak geliştirdiğim bir uygulamada, Primefaces Datatable elemanı içerisinde yüklü bir listem var ve bir file system dizini gibi, her bir satıra tıklandığında, o satırdaki klasörün içerisine girilmesi gerekiyor. Geri ve ileri butonlarının da çalışması gerekiyor.

Bu noktada çözüm olarak dojo'nun back sınıfını kullandım. Bu kütüphane, her bir click eventi esnasında, history stack'ine bir veri kaydetmemizi sağlıyor. Bu veriyi de, geri ve ileri butonlarına tıklandığı zaman yapacağı işlemi tanımlayarak kaydediyoruz. Böylece kullanıcı geri butonuna bastığı zaman, kaydettiği parametrelerle işlem yapabiliyor.

Kodlarla özetlemek gerekirse:

myfiles.xhtml
<script>
     function HistoryState(fileid)
     {
           this.fileid = fileid;
           this.back = function() { 
                browserBck([{name: 'fileid', value: fileid}]);
           };
           this.forward = function() { 
               browserFrwrd([{name: 'fileid', value: fileid}]);
           };
           this.changeUrl = false;
       }
</script>

<script type="text/javascript"  src="js/dojo.js" djConfig="preventBackButtonFix: false"></script>
<script type="text/javascript">
     dojo.require("dojo.back");
     dojo.back.init();
     dojo.back.setInitialState(new HistoryState(null));
</script>

...<p:dataTable>... 
        <p:ajax event="rowSelect" listener="#{fileController.list()}"/> 
...</p:dataTable>

   <p:remoteCommand name="browserBck" action="{fileController.listBack()}"/> 

Yukarıdaki örnekte HistoryState adında bir nesne oluşturdum. Bu nesnede, dojo için gerekli olan back, forward ve changeUrl değişkenlerini set ettim. back değişkeni, geri butonuna tıklanınca yapılacakları, forward değişkeni ileri butonu için aynı işlemleri tanımlamamızı sağlıyor. changeUrl ise, her bir state kaydolurken dojo tarafından oluşturulan random rakamın adres satırına yazılıp yazılmamasını kontrol ediyor. HTML5 desteği olmayan tarayıcılar için bu değer true olmalı. Sayfa ilk defa render olurken ise setInitialState'i çalıştırıp işlemi başlatıyoruz. Yine aynı dosyada bulunan p:dataTable elemanının bir satırına tıklanınca server tarafında liste yenilemek için <p:ajax> kullandım:

FileController.java
public void list() {
        RequestContext rc = RequestContext.getCurrentInstance();
        rc.execute("dojo.back.addToHistory(new HistoryState('" + selectedFile.getId() + "'));");
        listByParentID(selectedFile.getId());
}

public void listBack() {
        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); 
        String fileID = ec.getRequestParameterMap().get("fileid");
        listByParentID(fileID);
} 

Yukarıdaki örnekte görüldüğü gibi, her bir listeleme işleminde, client tarafındaki addToHistory metoduna, HistoryState nesnemi ,içerisinde mevcut parent id bulunacak şekilde set ediyorum.

Bu örnek çok daha basitleştirilbilirdi fakat JSF ve server side'da detaylı bir örnek bulunsun istedim.

Süreci Özetlersek:
1 - xhtml dosyasında dojo'yu initialize ettik. History'ye kaydedeceğimiz nesneyi ve back-forwad metodlarımızı belirledik
2 - Bir linke tıklayıp server tarafına bir ajax request geçtik. Server tarafındaki metodda "RequestContext.getCurrentInstance().execute()" ile client tarafındaki dojo.back.addHistory metodunu çağırdık.
3 - Tarayıcının geri butonuna bastık. Bu işlem, 1. maddede belirlediğimiz back metodunu çağırdı (client-side).
4 - <p:remoteCommand> ile, 3. maddede çağrılan metodun, server tarafındaki başka bir metodu çağırmasını sağladık.
5 - Server tarafındaki metod ise istediğimiz listelemeyi yaptı ve geri butonumuz çalışmış oldu.

İleri butonu için de, forward nesnesine gerekli fonksiyonu tanımlayarak aynı işlemleri tekrarlamamız lazım.

Not: Bu şekilde çalışabilmesi için 'js' klasörünün içerisinde;
* dojo.js
* back.js
* resources/iframe_history.html

dosyalarının bulunması gerekiyor.

( jsf, primefaces, ajax, browser back button, forward, dojo, dojo.back, dojo.hash, request, xhtml, p:remoteCommand, p:dataTable )
Kaynak: http://blog.andreaskahler.com/2009/09/managing-browser-history-for-ajax-apps.html

7 Mayıs 2013 Salı

JSF ve HTML Escape Problemi, Çözümü

JSF teknolojisi, web uygulamaları geliştirirken standart olarak yazılımcının uygulaması gereken bir çok güvenlik açığını kendisi gidermektedir. Bunların en önemlilerinden birisi de XSS'i engellemek için render edilen HTML'de bulunan ve atak yapmaya müsait karakterleri escape etmesidir. Örneğin ">" şeklinde yazılan bir yazı, kaynak kodunda "&gt;" şeklinde gözükecektir. Bu özellik güvenlik açısından kolaylık sağlasa da bir takım kısıtlamalar da getirmektedir. Örneğin, yazılımcının kendisinin, xhtml içerisine yazacağı javascript ya da benzeri kod blokları, JSF'in bu özelliği sebebi ile ya compile olmaz, ya da ekranda sorunlu bir şekilde render edilir.

Bu problemin çözümü ise <h:outputText> kullanmaktır. Bu tag ile, JSF'in default davranışını bypass edebiliriz. Örneğin basit bir Javascript tagi kullanalım:
<script>alert('Test');</script>
Bu kod bloğunu direkt olarak xhtml içerisine yazarsak &lt;script&gt;alert('Test');&lt;/script&gt; gibi bir görüntü ile karşılaşırız ya da IDE'miz bu kodu derlemez, hata verir. Bu kodu önyüze taşımak için:
<h:outputText value="&lt;script&gt;alert('Test');&lt;/script&gt;" escape="false" />
şeklinde bir kullanımda bulunmalıyız. Burada, h:outputText içerisindeki değerin escape="false" ile escape edilmemesini sağlıyoruz. Burada value'yu bu şekilde vermek yerine normal bir şekilde yazarak bir String halinde tutup: <h:outputText value="#{fooController.myScript}" escape="false" /> şeklinde de kullanabilirsiniz.

Görüldüğü üzere yöntem oldukça basit. Fakat benim başıma gelen bir problem, bu şekilde bir çözüme gitmeyi engelledi ne yazık ki. Sorun şu şekilde; Internet Explorer versiyonlarına göre farklı CSS dosyaları kullanmak için html taginin başına:
"<!--[if lt IE 7]> <html lang=\"en-us\" class=\"no-js ie6\" xmlns:h="http://java.sun.com/jsf/html"> <![endif]-->..." 
tarzı kodlar yazarız. Bu kodları, yukarıda bahsettiğim şekilde escape etmek ne yazık ki mümkün değil çünkü kullandığımız <h:outputText>'in dahil olduğu "http://java.sun.com/jsf/html" namespace'ini, henüz tanımlamadan bu tagi kullanmak istiyoruz ki bu da mümkün değil. Burada da imdadımıza <f:view> tagi geliyor. <f:view> taginin içerisine namespace'lerimizi tanımladıktan sonra bütün içeriğimizi (<html> tagi vs. de dahil), <f:view> içerisine koyuyoruz. Böylece içeride <h:outputText>'i kullanabilir duruma geliyoruz ve sorunumuz çözülmüş oluyor. Daha anlaşılır olması için:

Sorun: Aşağıdaki kod bloğunu escape etmeden ön tarafa taşımak
<!--[if lt IE 7]>          <html lang="en-us" class="no-js ie6"> <![endif]-->
<!--[if IE 7]>             <html lang="en-us" class="no-js ie7"> <![endif]-->
<!--[if IE 8]>             <html lang="en-us" class="no-js ie8"> <![endif]-->
<!--[if gt IE 8]><!--> <html lang="en-us" class="no-js" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <!--<![endif]-->
Çözüm: Kod bloğunu <f:view> içerisine alıp namespace'leri buraya taşımak
@Controller("fooController")
FooController{
   public String myUnescapedString =
 
                    "<!--[if lt IE 7]><html lang=\"en-us\" class=\"no-js ie6\"> <![endif]-->\n" +
                    "<!--[if IE 7]><html lang=\"en-us\" class=\"no-js ie7\"> <![endif]-->\n" +
                    "<!--[if IE 8]><html lang=\"en-us\" class=\"no-js ie8\"> <![endif]-->\n" +
                    "<!--[if gt IE 8]><!--> <html lang=\"en-us\" class=\"no-js\"> <!--<![endif]-->";
}
<f:view contentType="text/html"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core">
<h:outputText value="#{fooController.myUnescapedString}" escape="false"/>
</f:view>
( jsf, html, escape, h:outputText, f:view, unescape, xss )
Kaynak: http://stackoverflow.com/questions/10616944/jsf-2-1-ie-conditional-comments

7 Mart 2013 Perşembe

Ubuntu 12.10'a Oracle SQL Developer Kurulumu

Bu kurulum için ihtiyacımız olan bir kaç kurulum daha var. Öncelikle sistemde jre'nin kurulu olması gerekiyor. debhelper ve sqldeveloper-package paketlerine de ihtiyacımız var. Tabiki bir de ziplenmiş olarak indirdiğiniz SQL Developer'a ihtiyaç var.  Bu yazıda ben 'sqldeveloper64-3.2.20.09.87-no-jre.zip' kullanıyor olacağım.

sudo apt-get install sqldeveloper-package debhelper

Bu kodu çalıştırıp gerekli paketleri kurduktan sonra aşağıdaki komutla .deb dosyasını oluşturuyoruz:

make-sqldeveloper-package sqldeveloper64-3.2.20.09.87-no-jre.zip

Bu esnada make-sqldeveloper-package paketinde bulunan bir bugdan ötürü chmod: missing operand after `755' hatası alabilirsiniz. Bu hatayı çözmek için bu paketin kodunda ufak bir değişiklik yapmamız gerekiyor. Paketin versiyonuna göer değişiyor fakat 370 ile 385. satırlar arasında bir yerlerde bulunan aşağıdaki kodu, bir alttakiyle değiştirmeniz gerekiyor:

Silinecek Satır
${FIND} "${OPTDIR}" ! \( -type d -o -name "*.jar" \) |${XARGS} ${XARGS_OPTS} ${FILE} ${FILE_OPTS} |${GREP} ${GREP_OPTS} "shell script text executable" |${CUT} ${CUT_OPTS_FUNC_CLEAN} |${XARGS} ${XARGS_OPTS} ${CHMOD} ${CHMOD_OPTS}

Yerine Eklenecek Satır
${FIND} "${OPTDIR}" ! \( -type d -o -name "*.jar" \) |${XARGS} ${XARGS_OPTS} ${FILE} ${FILE_OPTS} |${GREP} ${GREP_OPTS} "shell script" | ${GREP} ${GREP_OPTS} "text executable" |${CUT} ${CUT_OPTS_FUNC_CLEAN} |${XARGS} ${XARGS_OPTS} ${CHMOD} ${CHMOD_OPTS}

Bu işlemden sonra hatadan kurtulmuş oluyoruz ve kodu yeniden çalıştırdığımızda .deb uzantılı dosyamız oluşmuş oluyor. Aşağıdaki şekilde .deb paketini açıyoruz:

sudo dpkg -i sqldeveloper.......deb

Böylece kurulum tamamlanmış oluyor. Dash Home'a "sqldeveloper" yazdıktan sonra uygulamamız açılacak. Yalnız yapmamız gereken son bir işlem daha var. Uygulama ilk kez açılırken size yüklü olan JRE'nin lokasyonunu soracak. Buraya da yüklediğimiz JRE'nin lokasyonunu yazacağız. Örneğin benimki şu şekildeydi:

/usr/lib/jvm/java-7-oracle

Artık IDE'miz kullanıma hazır durumdadır.

( ubuntu 12.04, oracle, sql developer, chmod, 755 )
Kaynak : https://bugs.launchpad.net/ubuntu/+source/sqldeveloper-package/+bug/985810

1 Mart 2013 Cuma

Spring MVC @Autowired NullPointerException

Spring MVC'de, nesnelerin yönetimini framework'e bırakma olayı sıkça kullanılan bir durumdur ve Spring'in ana kullanım amaçlarından birisidir. Bu kullanımlar esnasında, @Autowired annotation'unu kullanarak ya da getBean() metodu ile nesnelere ulaşmak istediğimizde alınan NullPointerException da oldukça sık karşılaşılan bir durumdur:) Ben yazının geri kalanında Annotation kullanımı ile devam edeceğim.

Burada, hataya sebebiyet verecek milyonlarca ihtimal vardır. Internette araştırdığınızda da bir dolu yazı karşınıza çıkacaktır. Bu sebeplerden bir kaçı:

  • @Autowired kulllandığınız nesneye sahip sınıfın Spring tarafından inject edilmemiş olması. Yani bu nesneye ait sınıfın başında @Component, @Controller gibi Spring'e özgü ve o sınıfın Spring tarafından yönetildiğini belirten annotationlar kullanılmalıdır.
  • Annotation kullanılan durumlarda, springContext.xml içerisinde '<tx:annotation-driven />' ve '<context:component-scan base-package />' taglerinin kullanılması gerekir.
  • Başına @Autowired eklediğiniz bir nesneyi 'new MyClass()' şeklinde kendiniz oluşturmamalısınız; bu nesnenin yönetimi artık Spring'dedir.

Yukarıdaki maddelere eklenecek başka maddeler de vardır. Bu hatalardan bir ya da birkaçına düştüyseniz kullanmak istediğiniz nesnenin null olması ihtimal dahilindedir. Peki herşeyi denediniz, bütün kodlama doğru ve hala bu hatayı alıyorsanız? O zaman benim karşılaştığım durumla karşılaşmış olma ihtimaliniz var. Spring MVC, kontrolüne verdiğiniz sınıfın instance'ını oluştururken, constructor'ı çalıştırma esnasında autowired nesneyi henüz inject etmiyor. Dolayısıyla bu nesneyi consturctor içerisinde kullanıyorsanız NullPointerException alıyorsunuz. Bu sorunun çözümü ise, eğer sınıfın instance'ını oluştururken yapmanız gereken bir iş yok ise, constructor içerisindeki bütün kod bloğunu @PostConstruct annotation'una sahip bir metoda vermeniz. Böylece ilgili nesne Spring tarafından oluşturulmuş ve kullanıma hazır hale gelmiş olacaktır. Aşağıda örnek kod parçalarını bulabilirsiniz.

Yanlış Kullanım

@Controller("userController")
public class UserController implements Serializable{
    @Autowired
    transient private SessionController sessionController;
    
    public UserController() {
        System.out.println(sessionController.getActiveUser().getUserName());
    }
}

Doğru Kullanım

@Controller("userController")
public class UserController implements Serializable{
    @Autowired
    transient private SessionController sessionController;
    
    public UserController() {}
    
    @PostConstruct
    public onLoad() {
        System.out.println(sessionController.getActiveUser().getUserName());
    }
}

spring mvc, injection, autowiring, @autowired, nullpointerexception, constructor, postconstruct )