Sansür, bir toplumun kendine olan güvensizliğini yansıtır ve otoriter rejimlerin belirgin bir özelliğidir.

--Potter Stewart

14.05.2008

Richfaces FileUpload Bileşeni

Richfaces 3.2.0 sürümü 31 Mart 2008 tarihinde kararlı halde kullanıma sunuldu. Yeni sürümle gelen birkaç yeni bileşen mevcut. Bunlardan biri de kütük yükleme (fileupload) bileşeni. Richfaces’in bileşen demosu ve belgelemesi her ne kadar ihtiyaçları fazlasıyla karşılasa da kütük yükleme bileşeni için belgelemesinde backing bean gerçekleştirimi ile ilgili yeterli bilgiyi bulamadım. Biraz deneme yanılma biraz da Richfaces forumlarından okuduklarımla kütük yükleme bileşenini keşfetme imkanım oldu:

<rich:fileUpload id="upload"

acceptedTypes="#{fileUploadBean.acceptedTypes}"

disabled="#{fileUploadBean.disabled}"

autoclear="#{fileUploadBean.autoclear}"

required="#{fileUploadBean.required}"

requiredMessage="#{fileUploadBean.requiredMessage}"

rendered="#{fileUploadBean.rendered}"

listHeight="#{fileUploadBean.listHeight}"

listWidth="#{fileUploadBean.listWidth}"

fileUploadListener="#{fileUploadBean.fileUploadListener}"

maxFilesQuantity="#{fileUploadBean.maxFilesQuantity}"

immediateUpload="#{fileUploadBean.immediateUpdate}"

addControlLabel="#{fileUploadBean.addControlLabel}"

clearAllControlLabel="#{fileUploadBean.clearAllControlLabel}"

clearControlLabel="#{fileUploadBean.clearControlLabel}"

stopEntryControlLabel="#{fileUploadBean.stopEntryControlLabel}"

uploadControlLabel="#{fileUploadBean.uploadControlLabel}">

<a4j:support event="onuploadcomplete"

reRender="info" />

<f:facet name="progress">

<rich:progressBar style="height: 10px; width: 250px;">

</rich:progressBar>

</f:facet>

<f:facet name="label">

<h:outputText value="{_KB}KB from {KB}KB uploaded --- {mm}:{ss}" />

</f:facet>

</rich:fileUpload>

rich:fileUpload bileşeninin ihtiyaç duyduğu niteliklerden acceptedTypes yüklenecek kütüklerin tiplerini (jpg, gif, vb.) belirtmek için kullanılıyor. maxFilesQuantity niteliği yüklenebilecek kütük sayısını belirtebiliyorsunuz. *ControlLabel nitelikleri ile bileşende görünen etiketlerin değerleri verilebiliyor. fileUploadListener niteliği ile de backing beande yer alan ve herbir kütüğün yükleme işlemi bittikten sonra fırlatılan olayı(event) yakalayan bir listener tanımı veriliyor.

Yukarıdaki koda ayrıca yükleme işlemi sırasında gösterilecek olan durum çubuğu (progress bar) ile yüklenen KB sayısı/süresi bilgileri ve yükleme işlemi tamamlandıktan sonra “info” id’li alanı güncellemek için bir ajax istemi ekledik:

<h:panelGroup id="info">

<rich:panel>

<f:facet name="header">

<h:outputText value="Uploaded Files Info" />

</f:facet>

<h:outputText value="No files currently uploaded"

rendered="#{fileUploadBean.size==0}" />

<rich:dataGrid columns="1" value="#{fileUploadBean.files}"

var="file" rowKeyVar="row">

<rich:panel>

<h:panelGrid columns="2">

<a4j:mediaOutput element="img" mimeType="image/jpeg"

createContent="#{fileUploadBean.paint}" value="#{row}"

style="width:100px; height:100px;" />

<h:panelGrid columns="2">

<h:outputText value="File Name:" />

<h:outputText value="#{file.name}" />

<h:outputText value="File Length(bytes):" />

<h:outputText value="#{file.length}" />

</h:panelGrid>

</h:panelGrid>

</rich:panel>

</rich:dataGrid>

</rich:panel>

<rich:spacer height="3" />

<br />

<a4j:commandButton action="#{fileUploadBean.clearUploadData}"

reRender="info, upload"

value="Clear Uploaded Data" rendered="#{fileUploadBean.size>0}" />

</h:panelGroup>

info” id’li panel grupta ise yükleme sonrası backing beande tutulan jpg kütüklerin isim ve boyut bilgisi ile resmin görüntüsü a4j:mediaOutput yardımı ile ekranda gösterilmiştir. createContent="#{fileUploadBean.paint}" niteliği görüldüğü gibi backing beanimizin paint yöntemi ile ilişkilendirilmiştir. dataTable’ın row bilgisini kullanarak bir list veri yapısı ile tutulan kütükleri görüntülememizi sağlamaktadır. İstemciden sunucuya yüklenen ve henüz veritabanına yazılmamış kütükleri backing beanin list veri yapısından silinebilmek için kodun en altına da action="#{fileUploadBean.clearUploadData}" nitelikli bir a4j:commandButton bileşeni eklenmiştir.

Yukarıdaki JSF kodunun kullandığı ve fileUploadBean referansıyla tanımlanan bean sınıfı da şu şekildedir:

import org.apache.commons.io.FilenameUtils;

import org.richfaces.event.UploadEvent;

import org.richfaces.model.UploadItem;

public class FileUploadBean {

private boolean disabled;

private boolean autoclear;

private boolean rendered;

private boolean required;

private String acceptedTypes;

private String requiredMessage;

private String listHeight;

private boolean immediateUpdate;

private String listWidth;

private String addControlLabel;

private String clearAllControlLabel;

private String clearControlLabel;

private String stopEntryControlLabel;

private String uploadControlLabel;

private List<MyDocument> files;

private Integer maxFilesQuantity;

public FileUploadBean() {

disabled = false;

autoclear = false;

rendered = true;

required = false;

immediateUpdate = false;

acceptedTypes = "jpg";

requiredMessage = "requiredMessage";

listHeight = "300px";

listWidth = "400px";

addControlLabel = "Ekle";

clearAllControlLabel="Hepsini Temizle";

clearControlLabel = "Temizle";

stopEntryControlLabel = "Yuklemeyi Durdur";

uploadControlLabel = "Yukle";

maxFilesQuantity = 5;

files=new ArrayList<MyDocument>();

}

public List<MyDocument> getFiles() {

return files;

}

public void setFiles(List<MyDocument> files) {

this.files = files;

}

public Integer getMaxFilesQuantity() {

return maxFilesQuantity;

}

public void setMaxFilesQuantity(Integer maxFilesQuantity) {

this.maxFilesQuantity = maxFilesQuantity;

}

public void fileUploadListener(UploadEvent event) throws IOException {

UploadItem item = event.getUploadItem();

/*

* if you have createTempFiles context param defined with true -

* you should use getFile rather than getData in your listener

*/

if(item != null && item.getData() != null){

MyDocument fileData = new MyDocument();

fileData.setContent(item.getData());

fileData.setLength(item.getData().length);

fileData.setName(FilenameUtils.getName(item.getFileName()));

files.add(fileData);

maxFilesQuantity--;

}

}

public void paint(OutputStream stream, Object object) throws IOException {

stream.write(((MyDocument)getFiles().get((Integer) object)).getContent());

}

public Integer getSize() {

return getFiles().size();

}

public String clearUploadData() {

files.clear();

maxFilesQuantity = 5;

return null;

}

/*Getters - setters*/

}

MyDocument sınıfı ile de eklenen kütüklerin bilgilerini tutuyoruz:

public class MyDocument {

private Long id;

private String name;

private byte[] content;

private long length;

/*Getters - setters*/

}

Ayrıca web.xml’de Richfaces filter altında da iki parametre tanımı yapılması gerekiyor:

<filter>

<display-name>RichFaces Filter</display-name>

<filter-name>richfaces</filter-name>

<filter-class>org.ajax4jsf.Filter</filter-class>

<init-param>

<param-name>createTempFiles</param-name>

<param-value>false</param-value>

</init-param>

<init-param>

<param-name>maxRequestSize</param-name>

<param-value>100000000</param-value>

</init-param>

</filter>

createTempFiles parametresi false değerine sahipse yüklenen kütükler belleğine yazılıyor. true değerine sahipse yüklenen kütükler bu sefer geçici kütüklere yazılıyor. Bu parametrenin niteliğine göre fileUploadListener yönteminde UploadEvent nesnesinden yüklenen kütüğü elde ediş biçimimiz farklılık gösteriyor. Birinde örnekte olduğu gibi getData() ile byte dizisi okurken diğerinde getFile() yöntemi ile File nesnesi okuyoruz.

maxRequestSize parametresi de yüklenecek kütüğün maksimum boyutunu belirtiyor. Değeri sıfır olursa herhangi bir boyut kontrolü yapmıyor. Tüm bu yapılanlardan sonra bileşenimiz kullanıma hazır:



Richfaces LiveDemo: http://livedemo.exadel.com/richfaces-demo/index.jsp

Richfaces Developer Guide: http://www.jboss.org/file-access/default/members/jbossrichfaces/freezone/docs/devguide/en/html/index.html

28.04.2008

JSF DataTable Bileşeni için çoklu satır seçimi..

JSF’de dataTable bileşenini kullanarak iş modelinde yer olan sınıfıma ait nesneleri tabloda listeleme ve herbir satırına çoklu seçimi olanaklı kılacak seçim kutucuğu (checkbox) iliştirme gereği duydum. Her ne kadar ilk akla gelen ve kolay çözüm iş modeli sınıfıma ekrandaki seçim kutucuğuyla ilişkili Boolean tipinde bir nitelik eklemek olsa da iş modeli tasarımına aykırı olması sebebiyle başka çözüm yolları aradım:


public class Baglanti {

private Long id;

private String ip;

private Integer port;

private Boolean checkBox;

// Getters/Setters

...

}

public class ViewBean {

private List<Baglanti> baglantilar = new ArrayList<Baglanti>();

...

}

<h:dataTable id="kurumBaglantilar" rows="10"

value="#{viewBean.baglantilar}" var="baglanti" >

<h:column>

<h:selectBooleanCheckbox id="lbl_check"

value="#{baglanti.checkBox}"/> </h:column>

<h:column>

<h:outputText value="#{baglanti.ip}" />

</h:column>

<h:column>

<h:outputText value="#{baglanti.port}" />

</h:column>

...

</h:dataTable>


Akla gelen ikinci çözüm ViewBean içinde ayrı ayrı liste veri yapısı içinde veri listesini ve seçim kutucuğu listesini tutarak JSF sayfasında görünümü ayrı dataTable’lar ile ele almak; iş mantığında da iki listeyi index tabanlı birbirleriyle ilişkilendirmek (seçim kutucüğü listesinde n. Boolean true ise veri listesinde n. veri seçilmiştir) olsa da iki ayrı dataTable’ı yönetme zorluğundan daha iyi bir çözüm için araştırmaya devam ettim:


public class Baglanti {

private Long id;

private String ip;

private Integer port;

// Getters/Setters

...

}

public class ViewBean {

private List<Baglanti> baglantilar = new ArrayList<Baglanti>();

private List<Boolean> checkBoxList = new ArrayList<Boolean>();

}

<h:panelGrid>

<h:dataTable id="kurumBaglantilarSecim" rows="10"

value="#{viewBean.checkBoxList}" var="checkBox" >

<h:column>

<h:selectBooleanCheckbox id="lbl_check"

value="#{checkBox}"/>

</h:column>

</h:dataTable>

<h:dataTable id="kurumBaglantilar" rows="10"

value="#{viewBean.baglantilar}" var="baglanti" >

<h:column>

<h:outputText value="#{baglanti.ip}" />

</h:column>

<h:column>

<h:outputText value="#{baglanti.port}" />

</h:column>

...

</h:dataTable>

</h:panelGrid>


En sonunda bulduğum bir blog hem sorunuma çözüm oldu hem de dataTable bileşenin yönetilmesiyle ilgili yeni şeyler öğretti. Soruna çözüm olarak seçim kutucuklarını Map veri yapısıyla ViewBean içinde saklıyor ve dataTable içinde erişimi veri satırının biricik bilgisini kullanarak yapıyor:


public class Baglanti {

private Long id;

private String ip;

private Integer port;

// Getters/Setters

...

}

public class ViewBean {

private List<Baglanti> baglantilar = new ArrayList<Baglanti>();

private Map<Long, Boolean> checkBoxMap = new HashMap<Long, Boolean>();

}

<h:dataTable id="kurumBaglantilar" rows="10"

value="#{viewBean.baglantilar}" var="baglanti" >

<h:column>

<h:selectBooleanCheckbox id="lbl_check"

value="#{viewBean.checkBoxMap[baglanti.ip]}"/> </h:column>

<h:column>

<h:outputText value="#{baglanti.ip}" />

</h:column>

<h:column>

<h:outputText value="#{baglanti.port}" />

</h:column>

...

</h:dataTable>


Daha detaylı bilgi için söz konusu blog girdisinin adresi de şu şekilde:

http://balusc.blogspot.com/2006/06/using-datatables.html

14.03.2008

JMX - JConsole'da "Local Process" listesinin boş gelme sorunu..

JMX (Java Management eXtention) kısaca Java VM başta olmak üzere MBean Server'a kayıt olan Java uygulamalarının yönetim ve izlenmesini sağlayan; bunun için web-tabanlı, dağıtık, devingen ve modüler çözümler üretmek için servisler sunan standart bir Java SE kütüphanesi. Java SE, MBean Sunucuya kayıt olan uygulamaların kolayca yönetimi ve izlenebilirliği için de "JAVA_HOME/bin" dizinin altında "JConsole" isminde kullanıcı arayüzü de sunuyor. Şu sıralar bir projenin yönetim ve izleme gereksinimi için JMX nedir ne değildir diye bakınmaya başladım.

Karşılaştığım ilk problem de (dakika bir gol bir misali) JConsole uygulamasını çalıştırınca görmem gereken yerel uygulama listesini görememek oldu (En azından Java VM'yi görmeyi bekliyor insan).



Sorunun nedeni %TMP% çevre değişkeninin gösterdiği "Temp" dizinin altında "hsperfdata_kullaniciIsmi" dizinine erişim yetkisinin bulunmaması. Normal koşullarda çalışan her Java uygulaması için PID numarası ile burada bir kütük yaratılıyor. Erişim izni olmadığı için de kütük yaratımı gerçekleştirilemiyor. (Herhangi bir kütük yaratmayı deneyip erişim izniniz olup olmadığını kontrol edebilirsiniz.)

Sorunun çözümü ise başka bir "Temp" dizini oluşturup %TMP% çevre değişkenini yeni yaratılan dizini gösterecek şekilde ayarlamak. Örneğin eski "Temp" dizininin yanına "Temp_" dizini oluşturabilirsiniz.

12.03.2008

"searchme:" yeni bir icat..

Google'ın hayatımızda önemli bir yer edindiği, insanların yaşam biçimini değiştirdiği bir gerçek. Google da dahil olmak üzere yaşam biçimimizi değiştiren her yenilik, insanların kabul ettiği gerçekleri inkar ederek ortaya çıkmadı mı? Birileri de "hep Google, yat kalk Google, nereye kadar Google?" demiş olacak ki "searchme:" arama motorunu yaratmışlar. Farkı mı? İzleyip görelim:

http://www.searchme.com/
http://www.searchme.com/press/press_videos.php