Javanın Geleceği Hakkında Tahminler

Java dünyasında yakın bir gelecekte meydana gelebilecek gelişmeler ve yeniliklerle ilgili güzel bir makale. Makalede artık Java’nın multicore donanım mimarilerindeki gelişmeleri concurrent execution ve memory management noktalarından JVM düzeyinde daha doğrudan ele alacağı, JVM’in bir mult-language runtime platform olarak evrileceği belirtiliyor. RIA tarafında ise JavaFX yolunun tercih edileceği söylenmiş.

Yakın zamanda Çankaya ve Gazi Üniversitelerindeki Java, Kariyer ve Gelecek konulu sunumlarımızda bunların bir kısmını tartışmıştık. Son zamanlarda çevremde de JVM’in thread düzeyinde multicore desteği ile ilgili soruların arttığını gözlüyorum. Scala, Groovy ve JRuby gibi dillerin hali hazırda JVM üzerinde çalışmaları da multi-lang JVM’e doğru gidildiğini gösteren gelişmelerdi. RIA tarafında ise Oracle’ın JavaFX’e yöneleceği belirtilmiş. Bu noktada ise benim tereddütlerim var. Hala Flex benzeri bir yaklaşım yerine GWT modelinin uzun vadede daha doğru olacağını düşünüyorum. Bakalım dizginlerin Oracle’ın elinde olduğu bu yeni dönem hepimize neler getirecek, izleyip göreceğiz.

JBPM Spring WebFlow Entegrasyonu

JBPM ile Business Process Management kabiliyetinin mevcut mimarimize dahil edilmesindeki ikinci adım Spring WebFlow entegrasyonu oldu. Bu noktada daha fazla devam etmeden evvel, önceki yazımda bahsettiğim JPA kullanan uygulamalarımızın JBPM ile aynı transaction context içerisinde çalıştırılması, bu ve diğer yazılarımda üzerinde duracağım JBPM – Spring WebFlow entegrasyonu konularında çalışma arkadaşım İlker Çelik’in çok büyük katkısı olduğunu belirtmek isterim.

SWF kullanıcı senaryolarını flow’lar olarak tasarlayıp implement etmek için çok güzel bir ortam sunmaktadır. JBPM ile de bir iş akışı baştan sona modellenerek execute edilmektedir. JBPM’de iş akışının her bir adımında belirli task’ların kullanıcı veya dış servisler tarafından yürütülmesi gerekmektedir. JBPM genel olarak bir iş akışını yönetmeye odaklanırken, SWF ise bu iş akışındaki her bir task’ın yürütülmesine odaklanmaktadır. Yani JBPM makro düzeyede çalışırken, SWF ise mikro düzeyde kalmaktadır.

İş akışındaki her bir task SWF’de bir flow’a karşılık gelmektedir. Bunun yanı sıra SWF tarafında execute edilen bir flowun herhangi bir aşamasında iş akışının başlatılması da söz konusu olabilir. Bu şekilde JBPM tarafındaki herhangi bir iş akışı SWF tarafından yönlendirilip, gerekli kullanıcı girdilerini temin ederek taskları çalıştırılabilmektedir.

SWF tarafından JBPM iş akışlarının ve taskların yönetilmesi için geliştirdiğimiz temel entegrasyon çözümleri şöyle sıralayabiliriz:

  1. SWF tarafında yeni bir flow başlaması ile birlikte JBPM tarafında da yeni bir iş akışı başlatmak
  2. Flow içerisinde herhangi bir adımda iş akışına bulunduğu node’un default transition’ından devam etmesini söylemek
  3. Flow içerisinden iş akışını save etmek
  4. SWF tarafında yeni bir flow başlatırken JBPM tarafındaki belirli bir task’ı SWF tarafında execute etmek için yüklemek (task –flow eşleşmesi)
  5. Flow sonlanırken flowun karşılık geldiği JBPM taskını default transition’ı veya spesifik herhangi başka bir transition’ını tetikleyerek sonlandırmak
  6. Herhangi bir JBPM process ve task instance’ının barındırdığı değişkenlere normal SWF scoped değişkenlere erişime benzer biçimde erişim sağlamak (processScope, taskScope)

SWF de bu işlemleri gerçekleştirmek için FlowExecutionListener vasıtası ile flow event’lerinden yararlandık. JBPM tarafında belirli kullanıcılara atanan task’ların SWF tarafında hangi flow’u tetikleyeceği konusunu ise JBPM process definition oluştururken task isimlerini SWF flow isimleri ile eşleştirerek çözdük. Herhangi bir flow sonlanırken JBPM tarafındaki task’ında hangi transition’ı sinyal edeceğini flow’u end-state’e getiren son transition’ın event id’si ile JBPM transition name’lerini eşleştirerek tespit ettik.

Şimdi JbpmFlowExecutionListener üzerinde detaylı bir inceleme yaparak SWF-JBPM entegrasyonunu detaylandıralım.

SWF tarafında yeni bir flow içerisinden herhangi bir JBPM process’inin yeni bir instance’ını yaratmak için flow tanımı içerisine jbpmStartProcess attribute’unu tanımladık. jbpmStartProcess attribute’una değer olarak process tanım adının verilmesi yeterlidir.


public void sessionstarted(RequestContext context, FlowSession session) {
	String processName = (String) session.getDefinition().getAttributes().get(“jbpmStartProcess”);
	if(processName != null){
		ProcessInstance processInstance = workflowService.createProcessInstance(processName);
		session.getScope().put(“processInstance”, processInstance);
	}
}

JbpmFlowExecutionListener’ın sessionstarted metodu içerisinde jbpmStartProcess attribute değeri varsa, bu değere karşılık gelen process tanımından yeni bir processInstance yaratılır. JBPM operasyonlarını gerçekleştirmek için geliştirdiğimiz workflowService spring managed bean’ı arka tarafta bütün JBPM erişimlerini Spring Modules projesinin JbpmTemplate sınıfı ile gerçekleştirmektedir. Örnek olarak workflowService.createProcessInstance metoduna bakabiliriz.

public ProcessInstance createProcessInstance(final String processName) {
	return (ProcessInstance) jbpmTemplate.execute(new JbpmCallback() {
		public Object doInJbpm(JbpmContext context) throws JbpmException {
			ProcessDefinition processDefinition = context.getGraphSession().findLatestProcessDefinition(processName);
			if(processDefinition == null) {
				throw new ProcessDefinitionNotFoundException("JBPM process with name " + processName + " not found.");
			}
			return processDefinition.createProcessInstance();
		}
	});
}

Flow içerisinde JBPM process instance’ının aktif node’una devam sinyali göndermek için ise SWF transition’ı içerisinde kullanılabilen jbpmSignalProcess attribute’unu tanımladık.

public void stateEntered(RequestContext context, StateDefinition previousState, StateDefinition state) {
	TransitionDefinition lastTransition = context.getCurrentTransition();
	if (lastTransition != null) {
		Boolean saveProcess = (Boolean) lastTransition.getAttributes().get(“jbpmSaveProcess”, false);
		Boolean signalProcess = (Boolean) lastTransition.getAttributes().get(“jbpmSignalProcess”, false); 
		if (signalProcess)
			workflowService.signalProcessInstanceProcessInstance) context.getFlowScope().get(“processInstance”“processInstance”" class="wiki wikinew">?;
		if (saveProcess)
			workflowService.saveProcessInstanceProcessInstance) context.getFlowScope().get(“processInstance”“processInstance”" class="wiki wikinew">?; 
	}
}

JbpmFlowExecutionListener’da stateEntered metodu içerisinde flow’un yeni state’e geçmesine neden olan son transition içerisinde jbpmSignalProcess attribute’una bakılır. Eğer bu attribute mevcut ve değeri true ise workflowService yardımı ile halihazırda flow scope’da tutulan JBPM processInstance’a bir sonraki node’a geçmesi için sinyal gönderilir.

stateEntered metodunda son transition’da aynı zamanda jbpmSaveProcess attribute’u aranır. Eğer bu attribute mevcut ve değeri true ise processInstance workflowService ile save edilir.

SWF içerisinde yeni bir flow başlatılırken bu flow’a karşılık gelen task’a ait bir task instance’ını JBPM tarafından alıp flow içinden yürütmek için flow request url’ine ilgili task instance’ının id’sini _jbpmTaskId request parametresi ile veriyoruz.

public void sessionstarting(RequestContext context, FlowSession session, MutableAttributeMap input) {
	String task = context.getRequestParameters().get(“_jbpmTaskId”);
	if (task != null) {
		TaskInstance taskInstance = workflowService.getTaskInstance(Long.parseLong(task));
		if (taskInstance != null) {
			context.getFlowScope().put(“taskInstance”, taskInstance);
			context.getFlowScope().put(“processInstance”, taskInstance.getProcessInstance());
		}
	}
}

sessionstarting metodu içerisinde halihazırdaki request’in _jbpmTaskId request parametresinin değeri alınarak, bu id’ye karşılık gelen JBPM taskInstance nesnesi ve onun ait olduğu processInstance nesnesi workflowService vasıtası ile alınır ve SWF’nin flow scope’una konur. Böylece başlatılan flow’un ilgili JBPM süreci ile bağlantılandırılması sağlanmış olur.

SWF tarafında bir flow sona ererken JBPM tarafında da o flowun karşılığı olan taskInstance’ının sonlandırılması gerekir. Bu ya JBPM task’ının default transition’ını ya da spesifik bir transition’ı belirterek gerçekleştirilebilir. Bunun için SWF state’leri içerisinde kullanılmak üzere jbpmEndTask ve jbpmEndTaskWithTransition attribute’larını tanımladık.

public void sessionEnding(RequestContext context, FlowSession session, String outcome, MutableAttributeMap output) {
	Boolean endTask = (Boolean) context.getCurrentState().getAttributes().get("jbpmEndTask", false);
	Boolean endTaskWithTransition = (Boolean) context.getCurrentState().getAttributes().get("jbpmEndTaskWithTransition", false);

	if(endTask && endTaskWithTransition) {
		throw new IllegalStateException("Only jbpmEndTask or jbpmEndTaskWithTransition is allowed");
	}

	if (endTask) {
		workflowService.endTaskInstanceTaskInstance) context.getFlowScope().get("taskInstance""taskInstance"" class="wiki wikinew">?;
	} else if(endTaskWithTransition) {
		TransitionDefinition lastTransition = context.getCurrentTransition();
		String jbpmTransition = (String)session.getScope().get("jbpmTransition");
		if(StringUtils.isEmpty(jbpmTransition)) {
			jbpmTransition = (String) lastTransition.getAttributes().get("jbpmTransition",String.class);
		}

		if(jbpmTransition == null) {
			jbpmTransition = context.getCurrentEvent().getId();
		}
		workflowService.endTaskInstance((TaskInstance) context.getFlowScope().get("taskInstance"),jbpmTransition);
	}
}

JbpmFlowExecutionListener’ın sessionEnding metodunda end-state’de jbpmEndTask veya jbpmEndTaskWithTransition attribute’larından birisine bakılır. Eğer jbpmEndTask mevcutsa ve değeri true ise flow scope’da tutulan JBPM taskInstance’ı default transition çağırılarak sonlandırılır. Eğer jbpmEndTaskWithTransition attribute’u mevcutsa ve değeri true ise bu sefer JBPM task’ının hangi transition’ının sinyal edilerek sonlandırılacağı tespit edilir. Burada önce flow scope jbmTransition değişkeninden bu değer alınır, eğer burada mevcut değilse bu sefer end-state’e gelmemize neden olan son transition’da jbpmTransition attribute’una bakılır. Burada da mevcut değilse transition adı end-state’e gelmemize neden olan transition’ı tetikleyen event’in id’si olarak set edilerek taskInstance sonlandırılır.

SWF tarafında taskInstance ve processInstance nesnelerinin barındırdıkları değişkenlere erişmek, bu değişkenlere yeni değer atamak için SWF’nin kendi scopelarındaki değişkenlere erişim, bunları manipülasyon için sağladığı syntax’a benzer bir syntax sağlamak için RequestControlContextImpl sınıfını extend ettik. Malesef SWF her flow request’i için bu ExtendedRequestControlContextImpl sınıfını kullanması için yeterli esnekliği sağlamadığından yeni sınıfı RequestControlContextImpl ile aynı “full classname”’de yaratarak class loading aşamasında SWF’nin sınıfı yerine bizim sınıfımızın yüklenmesini sağladık. Bu sayede process ve task instance’larındaki değişkenlere flow tanımlarında erişim şu şekilde olabiliyor:


Bir sonraki yazımda ise küçük bir iş akışı örneği üzerinden giderek JBPM üzerindeki çalışmalarımızdan bahsetmeye devam edeceğim.

First Impression Is Really Important

I have attended a 3 day workshop for Oracle Coherence Product. Altough I am a veteran Eclipse user, we used JDeveloper 11g Technology Preview 3 during our lab sessions. During those lab sessions, I noticed an ugly thing related with JDeveloper. JDeveloper provides some IDE mechanism to generate equals and hashCode methods for your classes. However, it fails to generate hashCode methods correctly when your classes contain primitive fields which need to be included in hashCode generation.

public class Foo {
	private int id;
	public int hashCode() {
		final int PRIME = 37;
		int result = 1;
		return result;
	}
}

Above is the code block I just generated using JDeveloper. Altough I chosed id to include in when generating hashCode, it doesn’t have it. As a result, you have same hashCode value for all your Foo objects. Not good if you are dealing with data structures like Hashtable in your application. In order to generate it correctly, you simply need to convert your primitive type to its Java wrapper equivalent. After this conversion, it looks more appropriate than above;

public int hashCode() {
	final int PRIME = 37;
	int result = 1;
	result = PRIME * result + id == null) ? 0 : id.hashCode(?;
	return result;
}

In summary, I think, it is really important for a new product to handle some fundamental tasks appropriately in order to get acceptance by its users.

Cold Boot Saldırısı ve Java

Daha önceki bir yazımda “cold booting” yöntemi ile kapanmasının üzerinden az bir zaman geçmiş olan bir bilgisayarın hafızasındaki verilerin kopyalanıp, bu veriler arasından sizin parolanızın ele geçirilebileceğini veya kişisel bilgilerinizin öğrenilebileceğini söylemiştim. “Cold boot” saldırılarına karşı değişik düzeylerde önemler alınabilir. Peki programlama düzeyinde bu tür bir veri hırsızlığına karşı ne yapabiliriz?

Örneğin Java ile uygulama geliştiriyoruz diyelim. Uygulamamız kimliklendirme aşamasında kullanıcının girdiği kullanıcı adı ve şifre bilgilerini veritabanından elde ettiği bilgilerle karşılaştırıyor ve sonuca göre kullanıcının sisteme girişine izin veriyor. Burada kullanıcıdan alınan şifre bilgisinin hangi veri yapısında tutulduğu bir cold boot saldırısında önem arz etmektedir. Uygulama içerisindeki şifre, kredikartı gibi kullanıcılarla ilgili hassas bilgilerin uygun veri yapılarına alınıp, bunlarla ilgili işlem sonlandıktan sonra bu veri yapılarının içeriğinin hafıza da temizlenmesi gerekmektedir.

Örnek olarak şöyle bir java kodumuz olsun;

String userPasswd = fetchPasswdFromUser();String userPasswdEnced = encryptPasswd(userPasswd);

userPasswd = "";//just to be sure we get rid of passwduserPasswd = null;

String encPasswd = getEncPasswdForUser(username);

if(!encPasswd.equals(userPasswdEnced)) { throw new AuthenticationException();}

//let the user log into the system…

Sizce userPasswd ile işimiz bittikten hemen sonra önce değişkene boş bir String değer atamamız, ardından da bununla da yetinmeyip null’a set etmemiz hafızadan şifrenin silinmesi için yeterli midir? Java’da String nesnelerin immutable yani değiştirilemez, salt okunur olduklarını biliyoruz. Öyleyse userPasswd nesnesine atanan bir String nesne hiçbir şekilde scope’dan çıkana kadar değiştirilemeyecektir. Bu nesnenin tutulduğu değişkeni boş String’e veya null’a set etmemiz de ancak o değişkenin hafızada başka bir yeri göstermeye başlamasından öte bir işe yaramayacaktır. Değişken scope’dan çıktıktan sonra garbage collection tarafından ele alınana kadar hafızada öylece duracaktır. Garbage collection çalıştıktan sonra bile işgal ettiği hafıza alanı başka bir nesne tarafından tamamen yazılmadıkça şifre erişilebilir olacaktır. Problem, String değerin bir String sabiti olması durumunda daha da kötüdür. String sabitler için Java’da bir sabit havuzu mevcuttur ve uygulama çalıştığı müddetçe sabitler bu havuzda tutulmaya devam edecektir.

İşimiz bittiğinde şifre bilgisini hafızadan temizlemek için String değişkenlerin uygun olmadığını anladık. Bu amaca daha uygun bir değişken char[] array, ya da CharBuffer, StringBuffer veya StringBuilder tiplerinden birisi olabilir. Önemli olan String bilginin değiştirilebilmesidir. Örneğin;

char[] userPasswd = fetchPasswdFromUser();...for(int i = 0; i < userPasswd.length; i++) { userPasswd[i] = 'x';}

Tabi CharBuffer, StringBuffer veya StringBuilder kullanırken toString() metodunu çağırmamaya dikkat etmelisiniz. Aksi takdirde StringBuffer içerisinde char[] array değişkende tutulan şifre bilgisi String değişken olarak döndürülecektir ve yukarıdaki durum söz konusu olacaktır. Dikkat edilmesi gereken bir diğer nokta bu değişkenlerin herbirisinin arka tarafta veriyi char[] array içerisinde tutmalarıdır. Herhangi bir kapasite artırımı durumunda eski array’in yeni bir array’e kopyalandığını bilmek gerekir. Array kopyalaması sonucunda hasas bilginin bir kısmı yine hafızada kalabilir.

Belki de bu şekilde programlama yapmak, cold boot saldırılarına karşı tedbirli olmak size paranoyakça gelmiş olabilir. Önceleri bende aynı şekilde düşünmüştüm. Ancak youtube’taki cold boot saldırı örneklerini izleyince bunun hiç de imkansız olmadığını anladım. Defansif web programlama böyle birşey olsa gerek.

Applet Life Cycle Issues in Internet Explorer

In previous blog entry, I had just mentioned about our server side context sharing mechanism between an applet and an web pages in our GIS enabled project. Users will try to accomplish their scenarios by using those two views. Obviously there will be switches many times between them during execution of any use case. Simply, users will enter some data via web interface and then switch to the applet view and enter some further data in there and then switch back to the web interface and submit data. Later they will switch to applet view again to see the results of that submit action.

There is one big problem here. As web interface part and applet view part will be in different web pages, IE calls destroy method of applet instance each time when we leave the page in which applet resides, an calls init each time when we enter into that page again. IE behaves like this between page back and forward operations, too.According to specified operations above, the life cycle of an applet in IE is as follows:

init() -> start()	: when we enter the page, in which our applet is contained

stop() -> destory()	: when we leave applet page, or click page back/forward buttons

init() -> start()	: when we again come back to the applet's web page

As a result of the above behaviour, our GIS applet gets initialized several times during execution of a user scenario, which is unacceptable, because users may enter some data, open several maps during their operations and may also switch back and forward between applet and web interface part.

I tried to find an elegant solution to this multiple init -> destroy problem. I looked for a way to prevent browser from calling those methods but came without a solution. Through a deep googling around the web, I found relatively old discussions (dating back to year 2000 in comp.lang.java.programmer) related with our problem. I think the only possible solution to this problem is caching state, data or graphics, which you don’t want to get destroyed and again initialized in a static data strutcture in your applet code. In init() method, or during other phases of applet, you first look at the cache before you create your graphics, or load user data, and only create or initialize them unless they exist in the static cache. This cache could simply be a Hashtable. The trick is here that loaded applet class definition and, therefore static variable is kept alive until all open browser windows are closed.

JPA, Hibernate ve JDBC Kullanırken AutoCommit Özelliği ve TXler

Doğrudan JDBC Kullanırken

JDBC spesifikasyonuna göre veritabanı bağlantılarının default autocommit değeri true’dur. Bu nedenle doğrudan JDBC ile işlem yaptığınızda veri üzerinde değişiklik yapan operasyonların her birisi kendi başına ayrı bir transaction’da ele alınacaktır. Transactional çalışabilmek için öncelikle bağlantının automcommit özelliğini false yapmanız gerekmektedir. Eğer veritabanı bağlantısı yaratılırken autocommit değerinin false olmasını istiyorsanız bunu DataSource’un defaultAutoCommit property’si üzerinden yapabilirsiniz. Yada doğrudan veritabanı üzerinde autocommit’i false olarak set edebilirsiniz. Örneğin hsqldb’de “set autocommit false” komutunu çalıştırmanız yeterlidir. Eğer Spring kullanıyorsanız, DriverManagerDataSource bean’ının connectionProperties property’si ile defaultAutoCommit’i false a set edebilirsiniz. Test ortamları için yazılmış olan SingleConnectionDataSource bean’ını kullanıyorsanız ya connectionProperties ile yada doğrudan autoCommit propertysi üzerinden false yapabilirsiniz.

Doğrudan Hibernate Kullanırken

Hibernate tarafında autocommit davranışı hibernate.connection.autocommit property’si ile düzenlenmektedir. Default olarak Hibernate autocommit’i false olarak set etmektedir, ve bu property ile oynanmaması önerilmektedir. Detaylar için Hibernate’in sitesindeki bu yazıyı okuyabilirsiniz. Peki autocommit false olunca ne oluyor? Autocommit false olduğunda veri erişim işlemleri yine eskiden olduğu gibi problemsiz gerçekleşiyor. Ancak insert, update, delete gibi veri üzerinde değişikliklere neden olan işlemler için Hibernate Session üzerinde mutlaka transaction başlatılması gerekiyor. Yapılan işlemler sonrasında ise iş akışına göre transaction commit veya rollback edilmeli ki yapılan değişiklikler veritabanına yansısın. Transaction başlatılmadan yapılan insert,delete, update işlemleri ile ilgili hiçbir hata olmamaktadır, Hibernate bu işlemleri sessizce göz ardı etmektedir.

<hibernate-configuration>
    <session-factory>
        <property name="connection.autocommit">true</property>
        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>
        <mapping class="examples.Foo"/>
    </session-factory>
</hibernate-configuration>
Foo foo = new Foo();
Configuration configuration = new AnnotationConfiguration().configure();
SessionFactory factory = configuration.buildSessionFactory();
Session session = factory.openSession();
session.save(foo);
session.close();

Eğer Hibernate ile çalışırken autocommit davranışını doğrudan JDBC kullanımı gibi yapmak istiyorsanız yapmanız gereken yukarıdaki örnekte gördüğünüz connection.commit property değerini true olarak set etmekten ibarettir. Bu durumda Hibernate Session üzerinde hiç transaction oluşturmandan veri manipülasyonu gerçekleştirebilirsiniz.

Spring ile Hibernate Kullanırken

Eğer Spring üzerinden Hibernate’i kullanıyorsanız işler biraz farklılaşmaktadır. Muhtemelen Hibernate SessionFactory nesnesini Spring’in LocalSessionFactoryBean factory bean’ı ile oluşturuyorsunuzdur. Hibernate SessionFactory bu durumda “user supplied connection” kullandığını düşünerek JDBC bağlantısını kendisi oluşturmak yerine doğrudan Spring’in inject ettiği DataSource bean’ından beklemektedir. Bu durumda da Hibernate’in hibernate.cfg.xml dosyası içerisinde belirteceğiniz connection.autocommit değişkeninin bir etkisi olmamaktadır. Veritabanı bağlantısının autocommit özelliği DataSource bean’ı nasıl konfigüre edilmişse ona göre değişmektedir. DriverManagerDataSource bean’ı defaultAutoCommit değerine bir değişiklik yapmadığı için de bu değer true olarak kalmakta ve Hibernate üzerinden gerçekleşen veri manipülasyonlarıda ortada bir transaction olmasa bile veritabanına yansıtılmaktadır. Doğrudan Hibernate kullanırken ki default Hibernate davranışını sağlamak için Spring ile konfigüre ettiğiniz DataSource bean’ına veritabanı bağlantısı oluşturuken autocommit’i false yapmasını söylemeniz gerekmektedir.

Foo foo = new Foo();
hibernateTemplate.persist(foo);

JPA ile Hibernate Kullanırken

Hibernate’i JPA ile kullanırken durum biraz daha değişmektedir. JPA, veri üzerinde manipülasyon yapan işlemler için mutlaka bir transaction beklemektedir. Sizin DataSource bean’ı üzerinde veya hibernate.cfg.xml içerisinde autocommit davranışını true yapmanızın bir etkisi olmamaktadır. Her iki durumda da transaction olmadan yapılan bir veri manipülasyonu javax.persistence.TransactionRequiredException ile sonuçlanmaktadır.

Foo foo = new Foo();
jpaTemplate.persist(foo);
jpaTemplate.flush();
Eğer yukarıdaki işlemin başarılı biçimde sonuçlanmasını istiyorsanız bu işlemi mutlaka bir transaciton içerisinde çalıştırmanız gerekmektedir.
Kısacası autocommit özelliği, Hibernate’in doğrudan kullanımı veya SessionFactory’nin Spring tarafından yönetilmesi, JPA üzerinden Hibernate kullanılması durumlarının her birinde farklı biçimlerde ele alınmaktadır. Bu nedenle yazdığınız servislerin veri erişim mekanizmaları farklılaştığında davranışlarında da değişiklikler söz konusu oluyorsa saşırmayın.

JdbcTemplate ve IN clause

Farz edelim ki elinizde “select r.id, r.rolename from role_table r where r.rolename in (?)” şeklinde bir sorgu olsun. Başka bir deyişle bir veya daha fazla sayıda rolename değeri içeren bir liste ile role_table’daki kayıtların bir bölümünü sorgulamak istiyorsunuz. Eğer aşağıdaki gibi bir kod yazarsanız;

List listOfRoleNames = new ArrayList();
listOfRoleNames.add("role_user");
listOfRoleNames.add("role_editor");
jdbcTemplate.query("select r.id, r.rolename from role_table r where r.rolename in (?)", 
    new Object[]{listOfRoleNames}, new RowMapper() {    
        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {        
        return new Role(rs.getLong(1),rs.getString(2));    
    }
});

yazdığınız kod beklediğiniz sonucu vermeyecektir. Çünkü buradaki sorgunun where condition’ında listOfRoleNames’de kaç tane eleman bulunuyorsa o kadar sayıda ? koymanız gerekmektedir. JdbcTemplate sorgudaki ? işareti kadar verilen Object array üzerinde iterate edecek ve her bir ? işareti için array’den bir eleman alacaktır. Eğer sorgularınızın where condition’ında dinamik olarak değişen sayıda input değişken kullanmak istiyorsanız bunun için NamedParameterJdbcTemplate kullanmanız ve sorgunuzu da “select r.id, r.rolename from role_table r where r.rolename in (:roleNames)” şeklinde yazmanız gerekir.

List listOfRoleNames = new ArrayList();
listOfRoleNames.add("role_user");
listOfRoleNames.add("role_editor");
namedParameterJdbcTemplate.query("select r.id, r.rolename from role_table r where r.rolename in (:roleNames)", new Object[]{listOfRoleNames}, 
new RowMapper() {    
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {        
return new Role(rs.getLong(1),rs.getString(2));    
}});

NamedParameterJdbcTemplate asıl işi yine kendi içindeki sıradan JdbcTemplate nesnesine delege etmektedir. Bu arada roleNames listesindeki elemanların sayısının, veritabanları değişken sayıdaki input parametreler için “hard limit” koyduklarından, bu değeri aşmadığından emin olmalısınız.

Veri Hırsızlığının Sonu Yok

Veri Hırsızlığının Sonu Yok

Son dönemlerde dizüstü bilgisayarların yaygınlaşması ile beraber şirketlere özel bilgilerin, kaybolan veya çalınan dizüstü bilgisayarlar nedeni ile istenmeyen kimselerin eline geçmemesi için değişik önlemlerin kullanımı gün geçtikçe artıyor. Örneğin artık biyometrik tanıma araçları dizüstü bilgisayarlara kadar girdi. Parmak izi okuyucular vasıtası ile bilgisayarın sadece sizin tarafınızdan açılması sağlanabiliyor. Gittikçe yaygınlaşan bir diğer güvenlik önlemi ise dizüstü bilgisayarlar üzerindeki bütün verinin şifrelenmiş halde saklanmasıdır. Kullanıcı, bilgisayarı açılırken girdiği parola aracılığı ile işletim sisteminin açılması ve şifrelenmiş verilerin disklerden okunması sağlanıyor. Dizüstü bilgisayar kaybolsa veya çalınsa bile üzerindeki kişisel bilgilerin istenmeyen kişiler tarafından görülmemesi sağlanmış oluyor.

Tabi güvenlikle ilgili teknolojik kabiliyetler ne kadar ilerlerse ilerlesin hackerlar da mutlaka bunları alt etmenin bir yolunu buluyorlar. Dizüstü bilgisayarınızdaki tüm verinizi şifreli olarak tutsanız, bilgisayarınızı kapatsanız bile tam manası ile güvenliği sağlamış olamıyorsunuz. Tecrübeli bir hacker, kapanmasının üzerinden az bir zaman geçmiş olan bir bilgisayarın hafızasındaki verileri kopyalayıp, bu veriler arasından sizin parolanızı ele geçirebilir veya kişisel bilgilerinizi öğrenebilir. “Cold boot” saldırısı olarak bilinen bu yöntem verinin güç kesilse bile RAM olarak bilinen hafıza kartlarında belli bir süre kaybolmadan kalması özelliğini kullanıyor. Hafıza kartı üzerindeki veri başka bir yere transfer edilerek kullanıcı tarafından diske erişim için bir kereliğine de olsa sisteme girilmiş şifreyi elde etmek mümkün olabiliyor.

Peki saldırı tam olarak nasıl gerçekleşiyor? Öncelikle bilgisayar, güç düğmesinden kapatılıp açılıyor. Bilgisayarın açılması esnasında hacker, içerisinde küçük bir işletim sistemi barındıran USB belleği bilgisayara bağlıyor ve bilgisayarın bu USB üzerindeki işletim sistemi ile açılmasını sağlıyor. Bu aşamada hafıza kartı üzerinde kapatılmadan önce bulunan verilerin görüntüsü hızlıca başka bir dosyaya aktarılıyor. Bundan sonra hacker hafıza kartı üzerinden elde ettiği veriyi ayrı bir yerde rahat rahat analiz ederek mevcut şifreleri veya diğer önemli bilgileri elde edebiliyor. Bilgisayara bir USB bağlamak yerine hafıza kartlarını söküp başka bir bilgisayara takarak bu analizi yapılabiliyor. Hatta bilgisayardan çıkarılan hafıza kartlarının özel bir takım soğutucu spreyler vasıtası ile dondurularak saatler sonra bile bu bilgilerin elde edilmesi de mümkün olabiliyor.

Öyleyse bu tür bir saldırıdan nasıl korunmalıyız derseniz, öncelikle dizüstü bilgisayarlarınızı bir yerden başka bir yere giderken veya topluluk içerisinde yanlız bırakırken kesinlikle uyku modunda bırakmayın. Mutlaka bilgisayarınızın işletim siteminden düzgün biçimde kapanmasını sağlayın. Disk üzerindeki veriyi şifreli biçimde tutuyorsanız bilgisayarın işletim sistemi üzerinden kapatılması genellikle hafızada tutulan parolanın kaybolmasını da sağlamaktadır. Hackerların işini zorlaştırın, açılış sırasında kullanılabilecek cihazlara sınırlama getirin, mesela sistemin USB’den yüklenmesini engelleyin. Ama son söz olarak hiç bir önlemin sizi yüzde yüz güvenli kılamayacağını bilin.

“Cold boot” saldırısının nasıl birşey olduğunu merak edenler Youtube’dan değişik örnekleri seyredebilirler. İşte bunlardan birisi;

Ama youtube yasaklı erişemiyoruz demeyin sakın. Biliyorsunuz (bazı) yasaklar delinmek içindir.

Not: Bu yazı ilk olarak 18 Ocak 2010 tarihinde www.skyturk.net haber sitesinde yayımlanmıştır.