Projelerde komponent tabanlı çalışmaya özen gösteriyorum. Komponent olarak geliştirdiğim bir modülü, konfigürasyon değişikliği yaparak başka bir projede kullanabilmeliyim. Komponentler kodun tekrar kullanımını (reuse) ve programcının daha az kod yazmasını mümkün kılar.
Komponent bünyelerinde Hibernate kullanarak, komponent verilerini bilgibankasında sakliyorum. Şu an geliştirdiğim JugTR.org projesinde JPA anotasyonlarını kullandım. Aşağıda blog kayıtlarını temsil eden Blog Entity sınıfı yer alıyor.
package bt.common.manager.blog.domain; import java.io.Serializable; import java.sql.Timestamp; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="blog") public class Blog implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; @Column(name = "subject", nullable = false) private String subject; @Column(name = "body", nullable = false) private String body; @Column(name = "userid", nullable = false) private Long user; @Column(name = "created", nullable = false) private Timestamp created; public Blog(long blogId) { this.id = blogId; } public Blog() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } public Long getUser() { return user; } public void setUser(Long user) { this.user = user; } public Timestamp getCreated() { return created; } public void setCreated(Timestamp created) { this.created = created; } }
@Table anotasyonunu kullanarak bilgibankası tablosunu belirliyorum. Örnekte görüldüğü gibi Blog nesnesinin ihtiva ettiği veriler blog isimli tabloda saklanmakta.
Blog komponentini (Blog.java ve diger komponent sınıfları) daha önce başka projelerde de kullandım. Komponenti tekrar kullanmak (reuse) benim için kod üzerinde değişiklik yapmamak anlamına gelmektedir. Eğer blog verilerini jugtr_blog isimli tabloda tutmak istersem, Blog.java sınıfında yer alan @Table anotasyonunu değiştirmem gerekiyor. Bu durumda komponentin kodunu değiştirmiş olacağım. Bu da bir nevi tekrar kullanım, lakin bu durumda komponentin birden fazla versiyonu oluşmakta ve bunların bakımı zamanla güçleşmektedir. Benim hayalimde kod üzerinde değişiklik yapmadan Blog komponenentini istediğim projede kullanabilmek ve bilgibankası tablo ismini projeye göre değiştirebilmek var. Bu ne yazik ki JPA anotasyonlarını kullanarak mümkün değil. Eğer @Table anotasyonu ile tablo ismini belirlediyseniz, o zaman tablo ismini değiştirmek için sınıfı değiştirmeniz gerekiyor.
Bu çoktan beri üzerinde çalıştığım bir sorun. Sorunu Hibernate bünyesinde bir interceptor sınıf oluşturarak çözebildim. Interceptor sınıfı aşağıdaki yapıya sahip:
package bt.jugtr.application.common.hibernate; import org.hibernate.EmptyInterceptor; public class JugTRHibernateInterceptor extends EmptyInterceptor { private static final long serialVersionUID = 1L; @Override public String onPrepareStatement(String sql) { String prepedStatement = super.onPrepareStatement(sql); prepedStatement = prepedStatement.replaceAll("public.", "jugtr."); return prepedStatement; } }
Bu interceptor sınıfını aktive etmek için SessionFactory konfigürasyonunu (Spring applicationContext.xml bünyesinde) aşağıdaki şekilde değiştiriyorum:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="entityInterceptor"> <bean class="bt.jugtr.application.common.hibernate.JugTRHibernateInterceptor" /> </property> <property name="configurationClass"> <value>org.hibernate.cfg.AnnotationConfiguration</value> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> ${hibernate.dialect} </prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.use_sql_comments">true</prop> <prop key="hibernate.connection.release_mode">after_transaction</prop> <prop key="hibernate.current_session_context_class">thread</prop> </props> </property> <property name="dataSource"> <ref bean="dataSource" /> </property> <property name="annotatedClasses"> <list> <value>bt.common.manager.user.domain.BTUser</value> <value>bt.common.manager.user.domain.Authorities</value> <value>bt.common.manager.blog.domain.Blog</value> <value>bt.common.manager.blog.domain.BlogComment</value> </list> </property> </bean>
Hibernate, oluşturduğu SQL komutunu bilgibankasına göndermeden önce JugTRHibernateInterceptor sınıfının onPrepareStatement() metodunu koşturur. Bu metot bünyesinde public. ile başlayan tablo isimlerini jugtr. olarak değiştiriyorum. public. ve jugtr. bilgibankasında kullandığım şemalar (schema). Hibernate tarafından oluşturulan SQL komutlarında public. isminin kullanımını @Table anotasyonuna schema değişkenini ekleyerek sağlayabilirim:
@Entity @Table(name="blog", schema="public") public class Blog implements Serializable { }
Bu değişikliğin ardından Hibernate tarafından oluşturulan bir SQL aşağıdaki şekilde olacaktır:
/* from Blog order by id desc */ select top ? blog0_.id as id2_, blog0_.body as body2_, blog0_.created as created2_, blog0_.subject as subject2_, blog0_.userid as userid2_ from public.blog blog0_ order by blog0_.id desc
Görüldüğü gibi Hibernate blog tablosunu public.blog seklinde adreslemeye başladı. Tekrar JugTRHibernateInterceptor sınıfına geri dönelim. onPrepareStatement() metodu bünyesinde SQL komutunda yer alan public. kelimesinin jugtr. olarak değiştirilmesini sağlıyorum. Bu şekilde dinamik olarak başka bir şemayı ve bu şemada bulunan blog tablosunu adreslemiş oluyorum. JugTRHibernateInterceptor devreye girdikten sonra SQL komutu aşağıdaki şekilde değişikliğe uğruyor. Bu şekilde başka bir şema içinde bulunan blog isimli tablo kullanımı mümkün oluyor. Görüldüğü gibi Blog.java kodunu değiştirmek zorunda kalmadan başka bir tabloyu kullanabildik.
/* from Blog order by id desc */ select top ? blog0_.id as id2_, blog0_.body as body2_, blog0_.created as created2_, blog0_.subject as subject2_, blog0_.userid as userid2_ from jugtr.blog blog0_ order by blog0_.id desc
EOF ( End Of Fun)
Özcan Acar
Great blog and posts, If I were in the Oscars, your blog would probably been awarded.