[Java] Spring LDAP LDIF Parsing(2)

上一篇 [Java] Spring LDAP LDIF Parsing(1) 主要講的是如何 parse ldif 檔。

這篇主要是實作 RecordMapper 的部分。

在上一篇有講到如果要整合 spring batch 的話,我們需實做 RecordMapper 這隻 interface

MappingLdifReader<Entity> mappingLdifReader = new MappingLdifReader<>();
    mappingLdifReader.setRecordMapper(new RecordMapper<Entity>(){
        @Override
        public Entity mapRecord(LdapAttributes attributes) {
            // do something you want
            Entity entity = new Entity();
            entity.setDn(attributes.getName());
            return entity;
        }
    });
mappingLdifReader.setResource(new ClassPathResource("data.ldif"));
mappingLdifReader.open(new ExecutionContext());

try {
    Entity entity = mappingLdifReader.read();
} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
mappingLdifReader.close();

其中 Entity 的部份如下:

public class Entity{
    private Name dn;

    public Name getDn() {
        return dn;
    }

    public void setDn(Name dn) {
        this.dn = dn;
    }
}

今天我們要轉換的物件假設不是 Entity 這麼簡單,是一個 objectclass 為 inetOrgPerson 的 Person 物件呢?

首先我們的 Person 類別如下:

@Entry(objectClasses = {"top", "inetOrgPerson"})
public class Person extends Person  {

    @Id
    private Name dn;

    @Attribute(name="cn")
    private String name;

    @Attribute(name="sn")
    private String lastName;

    @Attribute(name="uid")
    private String uid;

    @Attribute(name="userPassword")
    private String password;

    @Override
    public Name getDn() {
        return dn;
    }

    @Override
    public void setDn(Name dn) {
        this.dn = dn;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String getLastName() {
        return lastName;
    }

    @Override
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String getUid() {
        return uid;
    }

    @Override
    public void setUid(String uid) {
        this.uid = uid;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public void setPassword(String password) {
        this.password = password;
    }

}

這邊我們是利用 Object-Directory Mapping (ODM)。也就是類似 Hibernate 和 JPA 利用 annotations 將 java 物件與資料庫 tables 的 mapping 方式。

那原先的程式碼就會變這樣:

MappingLdifReader<Person> mappingLdifReader = new MappingLdifReader<>();
    mappingLdifReader.setRecordMapper(new RecordMapper<Person>(){
        @Override
        public Person mapRecord(LdapAttributes attributes) {
            // 假設我們的 ldif 檔這些 attributes 都有值
            Person person = new Person();
            person.setDn(attributes.getName());
            person.setName((String) attributes.get("cn"));
            person.setLastName((String)attributes.get("sn"));
            person.setUid((String) attributes.get("uid"));
            person.setPassword(DatatypeConverter.printBase64Binary((byte[]) 
                    attributes.get(PASSWORD).get()));
            return person;
        }
    });
mappingLdifReader.setResource(new ClassPathResource("data.ldif"));
mappingLdifReader.open(new ExecutionContext());

try {
    // 這裡我們就拿到轉換完成的 person 物件了
    Person person = mappingLdifReader.read();
} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} 

mappingLdifReader.close();

其中假設我們的 ldif 檔如下:

uid=1,o=keeplearning,dc=blog
objectclass: organizationalPerson
objectclass: person
objectclass: inetOrgPerson
objectclass: top
cn: Dennis
sn: Shen
uid: 1
userPassword:: 12345

當初一直不知道為什麼讀進來的 password 有問題,後來看 source code,之後發現是有經過 base64(base64 並不是壓縮也不是加密)的轉換。

其實 userPassword: 12345 這樣的話,讀進來的就會是 String。因為 LdapAttributes 這隻在 toString 時有特別處理 ::

另外有點要注意的就是:如果是利用 ApacheDS(其他的我沒試過) 將 ldif 檔案匯出來的,這時的 password 是有經過加密的,這時就無法將他轉回原先字串了。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *