To integrate Spring Security with Ldap, add the dependency to your build path first. You don’t have to define the second dependency, it is for using the latest version of spring ldap core.
<dependency> <groupid>org.springframework.security</groupid> <artifactid>spring-security-ldap</artifactid> <version>3.0.5</version> </dependency> <dependency> <groupid>org.springframework.ldap</groupid> <artifactid>spring-ldap-core</artifactid> <version>1.3.1.RELEASE</version> </dependency>
Bugün Hibernate’den çok güzel bir Exception yedim. Başta Exception biraz ilginç geldi ama, sebebini anlayınca Hibernate’e acayip hak verdim.
@Embeddable ile notlandırdığım bir sınıfı başka bir entity sınıfının içinde @Embedded ile tanımladığımda, Hibernate ayağa kalkarken şu hatayı attı:
“org.hibernate.AnnotationException: A component cannot hold properties split into 2 different tables”
@Embeddable dediğim sınıfın içeriği şuna benzer bişeydi:
@Embeddable public class Details { // ... // primitif alanlar // ... @ManyToOne @JoinTable(...) private Category category; // getters & setters }
Hatanın sebebi, @JoinTable annotation’ı. @JoinTable’ı kullandığımızda, @Embeddable sınıf, embed edilebilirliğini kaybediyor. @Embeddable için javadoc’ta “Defines a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity. Each of the persistent properties or fields of the embedded object is mapped to the database table for the entity….” diyor. JoinTable’ı kullandığımızda ise, entity’ler arasındaki ilişki, ayrı bir tabloda kurulduğundan, category alanı embed eden sınıfın tablosuna eklenemiyor.
Çözüm @JoinTable yerine ilişkiyi @JoinColumn ile kurmak. @JoinTable yerine @JoinColumn kullandığımızda, embed eden entity’yi category’ye bağlayacak foreign key, entity’nin tablosuna ekleneceğinden, hata durumu oluşmuyor.
Aşağıda, bu akşam netten derlediğim, kullanışlı kod şablonları var. Kod şablonları, Sysout, try gibi kelimeleri yazıp CTRL + SPACE’e basarak Eclipse’in bizim için tamamladığı System.out… try{}catch… gibi kodlar. Sysout, try gibi kısayol kelimelerini çokça kullanmama rağmen, yeni kod şablonları vs. için hiç uğraşmamıştım. Ta ki bugün sahibinden’den Berkay abi Logger için kısayol gösterene dek
Sağolasın Berkay abi. Çoğzel oldu bu iş.
Windows > Preferences > Java > Editor > Templates yolundan ulaşılan şablonlara mutlaka bir göz atmanızı, aşağıdaki şablonlardan işinize yarayanları da eklemenizi tavsiye ederim.
ifNull
if (${var} != null){
${cursor}
}
ifNotNull
if (${var} != null){
${cursor}
}
logger
${:import(org.slf4j.Logger,
org.slf4j.LoggerFactory)}
private static final Logger logger =
LoggerFactory.getLogger(${enclosing_type}.class);
logd
logger.debug(${word_selection}${});
${cursor}
loge
logger.error(${word_selection}${});
${cursor}
logi
logger.info(${word_selection}${});
${cursor}
logt
logger.trace(${word_selection}${});
${cursor}
logw
logger.warn(${word_selection}${});
${cursor}
before
${:import (org.junit.Before)}
@Before
public void setUp() {
${cursor}
}
after
${:import (org.junit.After)}
@After
public void tearDown() {
${cursor}
}
beforeclass
${:import (org.junit.BeforeClass)}
@BeforeClass
public static void oneTimeSetUp() {
// one-time initialization code
${cursor}
}
afterclass
${:import (org.junit.AfterClass)}
@AfterClass
public static void oneTimeTearDown() {
// one-time cleanup code
${cursor}
}
list
${:import(java.util.List, java.util.ArrayList)}
List ${newName} = new ArrayList();
map
${:import(java.util.Map, java.util.HashMap)}
Map<${keyType},${valueType}> ${newName} = new HashMap<${keyType},${valueType}>();
set
${:import(java.util.Set, java.util.HashSet)}
Set<${type}> ${newName} = new HashSet<${type}>();
Şurada da bir sürü template var: http://stackoverflow.com/questions/1028858/useful-eclipse-java-code-templates
Spring, Hibernate gibi bir çok framework; bir paket altındaki sınıfları tarayıp annotation’ları vs. işleyerek bir takım ilklendirmeler, işlemler yapıyor. Bu tarz bir gereksinimle karşılaşıp işe koyulduğumuzda, bunun çok da kolay olmadığını görüyoruz. Reflection Api bize sınıf metadatalarına ulaşmamız için güzellikler sağlasa da, böyle bir işlem için malesef yetersiz kalıyor.
Neyse ki Spring, bize classpath üzerinde sınıfları tarama gibi işlemler yapmamızı sağlayan sınıflar sağlıyor. Spring’in sunduğu sınıflar ile bir paket altındaki sınıfları tarayabiliyor, sınıfı yüklemeden sınıfın metadatasına, annotationlarına ulaşabiliyor; sınıfı Class.forName() ile class nesnesine erişebiliyoruz.
private List> scan(String packageToScan) { ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver); String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolve(packageToScan) + "/" + "**/*.class"; List> candidates = new ArrayList>(); try { Resource[] resources = resourcePatternResolver .getResources(packageSearchPath); for (Resource resource : resources) { if (resource.isReadable()) { MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource); ClassMetadata classMetadata = metadataReader.getClassMetadata(); AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); } } } catch (Throwable e) { e.printStackTrace(); } return candidates; } private String resolve (String packageToScan) { return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils .resolvePlaceholders(packageToScan)); }
Öncelikle PathMatchingResourcePatternResolver gerçekleştirimi ile bir ResourcePatternResolver tanımlıyoruz. ResourcePatternResolver interface’i, location pattern’larını Resource nesnelerine dönüştürme işlemini tanımlıyor. MetadataReaderFactory interface’i ise, ResourcePatternResolver ile elde ettiğimiz Resource nesnelerinin bilgilerini okumamızı sağlayacak olan MetadataReader nesnelerinin yaratılmasını işlemini tanımlayan interface. CachingMetadataReaderFactory gerçekleştirimi, Resource nesnelerine karşılık olan MetadataReader nesnelerini, her çağrıda yaratmak yerine cacheliyor.
ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX ise “classpath*:” stringini tutuyor ki bu string, PathMatchingResourcePatternResolver’in classes dizininin yanısıra classpath’teki jar’ları da taramasını sağlıyor.
Elde ettiğimiz MetadataReader nesnesi üzerinden, ClassMetadata ve AnnotationMetadata gerçekleştirimlerine ulaşarak, ilgili sınıfa ait metadata bilgilerine ulaşabiliyoruz. Ayrıca ClassMetadata.getClassName() çağrısı sınıfın adına ulaştıktan sonra Class.forName() çağrısı ile sınıfın Class nesnesine ulaşabilir, reflection api ile Class nesnesi üzerinde işlem yapabiliriz.
Yukarıdaki kodda yer almıyor ama TypeFilter interface’i sayesinde de, MetadataReader’ı kullanarak filtreleme yapabiliyoruz. TypeFilter’ın AnnotationTypeFilter, AssignableTypeFilter gibi gerçekleştirimleri bulunuyor.
http://stackoverflow.com/questions/1456930/read-all-classes-from-java-package-in-classpath
http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/core/type/filter/TypeFilter.html
Spring Security’yle entegre çalışan bir uygulamada, kullanıcıların oturumlarına yönelik bilgiler SecurityContext nesnelerinde tutuluyor. SecurityContext nesneleri ise SecurityContextHolder içerisinde tutuluyor.
Varsayılan olarak SecurityContextHolder, SecurityContext nesnelerini ThreadLocal kullanarak saklıyor. Böylelikle aynı thread’de çalışan metodlar aynı SecurityContext nesnesine ulaşabiliyorlar. SecurityContextHolder’in çalışma modu da istenildiği takdirde değiştirilebiliyor.
Uygulamanın oturumla alakalı işlerini Spring Security halletse de, bazen oturum açan kullanıcıya yönelik bilgiler bize de gerekebiliyor. Bunun için öncelikle SecurityContext nesnesine ulaşmamız gerekiyor. Onu da şöyle yapabiliyoruz.
SecurityContext securityContext = SecurityContextHolder.getContext();
Bu çağrıyla elde ettiğimiz securityContext üzerinden Authentication ve UserPrincipal’a erişebiliyoruz. Fakat bu kullanım şurdaki abimin dediği gibi test edilebilirliği bozuyor. Bunun için bu çağrıyı gizlemek daha uygun bir yaklaşım.
public class SecurityContextUtils { public SecurityContext getSecurityContext() { return SecurityContext.getContext(); } }
SecurityContextUtils sınıfının içine UserPrincipal veya username’i de getiren metodlar yazılabilir. Bu yöntemle statik metod çağrısını, normal bir metodun içerisine gizledik ve SecurityContextUtils’i ve SecurityContext’i mocklayabilir hale geldik.
Uygulamada Spring de kullanıyorsak şöyle bir sınıf da yazabiliriz.
@Component public class SecurityContextUtils { private SecurityContextHolderStrategy securityContextHolderStrategy; @PostConstruct void init() { securityContextHolderStrategy = SecurityContextHolder .getContextHolderStrategy(); } public SecurityContext getSecurityContext() { return securityContextHolderStrategy.getContext(); } }
SecurityContext nesneleri HTTP request’leri boyunca ThreadLocal’de tutuluyor. Request sonlanınca, ilgili SecurityContext ThreadLocal’den silinip bir sonra request’te tekrar ThreadLocal’e alınıyor. Bunun sebebi ise request’in sonlandığı thread’in, servlet container’in thread pool’una alınıp başka bir request’i ele alması ihtimali. Eski SecurityContext ThreadLocal’den silinmezse thread’de çalışan yeni request yanlış SecurityContext nesnesine erişir. Bu durumu düşünmemiş olmamdan dolayı, ben bir hatayla karşılaştım; onu da yazmak istiyorum.
Spring Security filtrelerini kapattığım bir URL’e sahip sayfada, SecurityContext’e erişmeye çalıştım. Filtreler kapalı olduğundan SecurityContext nesnesine ThreadLocal’e alınmıyordu ve erişmeye çalıştığımda null dönüyordu. Buna dikkat etmek gerekiyor.
ResultTransformer, adından da az çok anlaşılacağı gibi, Hibernate sorgularından dönen değerleri bean, map, list gibi nesnelere dönüştürmeye yarıyor.
Ogrenci, Ders, DersKaydi entity’lerimiz olduğunu varsayalım. Ogrenci entity’miz sistemde kayıtlı öğrencileri, Ders entity’si açılan dersleri, DersKaydi entity’miz de Ogrenci ile Ders nesnelerini eşleştiren ve öğrencinin ders kaydına yönelik bilgileri tutan entity olsun.
Yazacağımız sorguyla sadece ihtiyacımız olan <öğrenci adı, kayıt yaptığı ders adı> ikilisini çekmek isteyelim. OgrenciDTO sınıfımızda da ogrenciAdi ve dersAdi alanlarının olduğunu varsayalım.
<öğrenci adı, kayıt yaptığı ders adı> bilgisini çekmek için yazacağımız HQL veya Criteria sorgusu default olarak bize bir Object[] listesi döner. Listenin her bir elemanı olan Object[]‘in ilk elemanı öğrenci adı iken, ikinci elemanı da kayıt yaptığı dersin adı olur. Bu davranışı Criteria veya Query nesnesi üzerinde setResultTransformer(Transformers(Transformers.ALIAS_TO_ENTITY_MAP); çağrısı ile Object[] yerine Map dönecek şekilde değiştirebiliriz. Bu çağrı ile dönen listenin her elemanı Object[] yerine Map olur ve sorgudan dönen listeden aldığımız map nesnelerinin üzerinde map.get(“ogrenciAdi”); gibi bir çağrı ile öğrenci adı değerine ulaşabiliriz.
Daha da güzeli, sorgudan dönen değerleri doğrudan bir sınıfın alanlarına eşleştirip Hibernate’in bizim için sorgudan dönen değerleri nesnelere dönüştürmesini sağlayabiliriz. Az önce bahsettiğim OgrenciDTO nesnesi üzerinde bunu mesela şöyle yapıyoruz.
public class OgrenciDTO { private String ogrenciAdi; private String dersAdi; public OgrenciDTO() { } // getter, setter metodlar... }
List ogrencilerinDersleri = s.createCriteria(DersKaydi.class) .createAlias("ogrenci", "ogr").createAlias("ders", "drs") .setProjection(Projections.projectionList() .add(Projections.property("ogr.ad"), "ogrenciAdi") .add(Projections.property("drs.ad"), "dersAdi") ) .setResultTransformer(Transformers.aliasToBean(OgrenciDTO.class)) .list();
Gördüğünüz gibi DersKaydi sınıfı üzerinde yarattığımız Criteria‘da öncelikle DersKaydi sınıfının ogrenci ve ders alanlarına alias‘lar atadık. Sonra öğrenci adı ve ders adı değerleri üzerinde Projection yaparak sorgumuzdan yalnızca bu değerlerin dönmesini sağladık ve son olarak yaptığımız .setResultTransformer(Transformers.aliasToBean(OgrenciDTO.class)) çağrısı ile dönen ikilileri üzerinden OgrenciDTO nesneleri yaratılmasını ve değerlerinin atanmasını sağladık.
Hibernate içerisinde bir çok ResultTransformer gerçekleştirimi hazır olarak geliyor. Şu bağlantıdan ResultTransformer gerçekleştirimlerine göz atabilirsiniz.
Bilgiyi HQL ile çekseydik de şöyle yapacaktık:
List ogrencilerinDersleri = s.createQuery( "SELECT dk.ogrenci.ad AS ogrenciAdi, dk.ders.ad AS dersAdi" + "FROM DersKaydi AS dk") .setResultTransformer(Transformers.aliasToBean(OgrenciDTO.class)) .list();
Başlık konusunda çok sıkıntı çekiyorum ya.
Spring, bize IoC container’ını genişletmek (extend) için çeşitli entegrasyon arayüzleri (interface) ve bu arayüzlerin -out of the box- gerçekleştirimlerini (implementation) sunuyor. BeanPostProcessor bunlardan biri. BeanPostProcessor kullanarak, Spring conteiner’i bir bean’i yaratıp ilklendirdikten (initialize) sonra, bean üzerinde istediğimiz işlemleri gerçekleştirebiliyoruz. Önceki yazılardan birinde bahsettiğim Spring ile Logger enjektesi, bunun bir örneği. BeanPostProcessor gerçekleştirimlerinin bir diğer örneği ise Spring ile gelen RequiredAnnotationBeanPostProcessor sınıfı.
BeanFactoryPostProcessor arayüzü ise, Spring IoC container’ının bir başka genişleme noktası. Bu arayüz sayesinde konfigürasyon metadata’sı üzerinde çalışabiliyoruz. Spring IoC container’ı bean’leri yaratmaya başlamadan önce BeanFactoryPostProcessor gerçekleştirimlerine konfigürasyon metadata’larını okuma ve değiştirme imkanı sağlıyor.
ApplicationContext, içerisinde tanımlanan BeanFactoryPostProcessor gerçekleştirimlerini otomatik olarak saptayıp konfigürasyon metadatası üzerinde çalışmaları için otomatik olarak işletiyor. Birden fazla BeanFactoryPostProcessor’umuz varsa ve işletim sırası önemliyse order değeri ile işletim sıralarını da ayarlayabiliyoruz.
Yazının asıl mevzusu ise, Spring ile gelen ve esasında BeanFactoryPostProcessor arayüzünün bir gerçekleştirimi olan PropertyPlaceHolderConfigurer sınıfı. PropertyPlaceHolderConfigurer sınıfı sayesinde, kodumuza yönelik konfigürasyon parametrelerini bean tanımlarından ayırıp standart java property dosyalarına koyabiliyoruz. JDBC parametreleri mesela. Böylelikle parametrelerde bir değişiklik yapacağımız zaman bean tanımlarıyla uğraşmak yerine property dosyalarından kolayca değişiklikleri hallediyoruz.
sana gitme demeyeceğim.
üşüyorsun ceketimi al.
günün en güzel saatleri bunlar.
yanımda kal.
sana gitme demeyeceğim.
gene de sen bilirsin.
yalanlar istiyorsan yalanlar söyleyeyim,
incinirsin.
sana gitme demeyeceğim,
ama gitme, lavinia.
adını gizleyecegim
sen de bilme, lavinia.
(özdemir asaf)
“Why read if you can watch?” diyenlere
çok acıtıyor lan
Yok böyle harika bir şarkı. Dün geceden beri aralıksız dinliyorum.
Kaybedenler Külübü’nde nejat işler abimizle filmde hayatının aşkı ablamız ilk gecelerini son derece dirty bir şekilde geçirirken çalıyor. Sanheye tam uymuş yalan yok
Şu da orijinali:
Troublemakers – get misunderstood
Filmdeki daha güzel ama.
Ant’ı kullanmaya başlayalı daha 3-4 gün oldu. İlk küçük gereksinimimi ufak bir google aramasıyla hallettim. Ant’ta scripti çalıştırıp bir yerlerdeki jar’ları yeniden build ediyorsanız, Eclipse’in yeni build edilen jar dosyalarını görmesi için workspace’i yenilemeniz gerekebiliyor. Bunu ilk 5-10-20 seferde elle F5′e basarak yapabilirsiniz. Ama bir süre sonra bundan bıkıp mutlaka bir çözüm arıyosunuz.
Ant scriptimize refresh taskı ekleyerek Eclipse’in workspace’i otomatik olarak yenilemesini sağlayabiliyoruz. Bunun için Ant scriptimize şu taskı ekleyelim:
<eclipse.refreshLocal resource=”MyProject/MyFolder” depth=”infinite”/>
Burada resource kısmı yenilemek istediğimiz dizin olurken, depth de yenileme işleminin alt dizinlerde ne kadar derinlikte yapılacağı oluyor. depth değerine zero, one, infinite değerlerinden birini verebilirsiniz.
Ant script’ini çalıştırdığınızda refreshLocal komutunun tanınmadığına yönelik bir hata alırsınız. Bunu çözmek için de:
“Run > External Tools > External Tools Configurations > JRE” yoluna gidip “Run in the same JRE as the workspace” seçeneğini işaretliyoruz.
Bundan sonra Ant scriptini çalıştırdığımızda workspace de otomatik olarak yenileniyor.


