diff options
author | Endi S. Dewata <edewata@redhat.com> | 2013-09-12 13:24:32 -0400 |
---|---|---|
committer | Endi S. Dewata <edewata@redhat.com> | 2013-09-17 14:37:27 -0400 |
commit | 3567f557307606c5f09496469a92f6972f5d5750 (patch) | |
tree | 50d62ae7032da4bbfb073274ebdde0256bcb7aa3 /base | |
parent | b5796dfde426414ac81614751c33f23aa356eae4 (diff) | |
download | pki-3567f557307606c5f09496469a92f6972f5d5750.tar.gz pki-3567f557307606c5f09496469a92f6972f5d5750.tar.xz pki-3567f557307606c5f09496469a92f6972f5d5750.zip |
Added LDAPDatabase.
A new LDAPDatabase class was added as a base class for LDAP-based
databases. A new DBRecord class was added to provide the default
implementation for record classes. New annotation classes were added
to specify the object class and attribute mappings.
Diffstat (limited to 'base')
6 files changed, 337 insertions, 4 deletions
diff --git a/base/common/src/com/netscape/certsrv/dbs/IDBSSession.java b/base/common/src/com/netscape/certsrv/dbs/IDBSSession.java index a4c05f40a..1a1f58d60 100644 --- a/base/common/src/com/netscape/certsrv/dbs/IDBSSession.java +++ b/base/common/src/com/netscape/certsrv/dbs/IDBSSession.java @@ -31,7 +31,7 @@ import com.netscape.certsrv.base.ISubsystem; * * @version $Revision$, $Date$ */ -public interface IDBSSession { +public interface IDBSSession extends AutoCloseable { /** * Returns database subsystem. diff --git a/base/common/src/com/netscape/cmscore/dbs/DBAttribute.java b/base/common/src/com/netscape/cmscore/dbs/DBAttribute.java new file mode 100644 index 000000000..d89c56e7c --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DBAttribute.java @@ -0,0 +1,30 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2013 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +package com.netscape.cmscore.dbs; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author Endi S. Dewata + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface DBAttribute { + public String value(); +} diff --git a/base/common/src/com/netscape/cmscore/dbs/DBObjectClasses.java b/base/common/src/com/netscape/cmscore/dbs/DBObjectClasses.java new file mode 100644 index 000000000..8920a4f97 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DBObjectClasses.java @@ -0,0 +1,30 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2013 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +package com.netscape.cmscore.dbs; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author Endi S. Dewata + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface DBObjectClasses { + public String[] value(); +} diff --git a/base/common/src/com/netscape/cmscore/dbs/DBRecord.java b/base/common/src/com/netscape/cmscore/dbs/DBRecord.java new file mode 100644 index 000000000..8d62b00d2 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DBRecord.java @@ -0,0 +1,98 @@ +package com.netscape.cmscore.dbs; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Enumeration; +import java.util.Vector; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBObj; + +public class DBRecord implements IDBObj { + + private static final long serialVersionUID = 1L; + + @Override + public void set(String name, Object value) throws EBaseException { + try { + // find setter + String setter = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1); + for (Method method : getClass().getMethods()) { + if (!method.getName().equals(setter)) continue; + + // invoke setter + method.invoke(this, value); + return; + } + + // if setter not available, set field directly + Field field = getClass().getField(name); + field.set(this, value); + + } catch (InvocationTargetException|NoSuchFieldException|IllegalAccessException e) { + throw new EBaseException(e.getMessage(), e); + } + } + + @Override + public Object get(String name) throws EBaseException { + try { + // find getter + String getter = "get" + Character.toUpperCase(name.charAt(0)) + name.substring(1); + for (Method method : getClass().getMethods()) { + if (!method.getName().equals(getter)) continue; + + // invoke getter + return method.invoke(this); + } + + // if getter not available, get field directly + Field field = getClass().getField(name); + return field.get(this); + + } catch (InvocationTargetException|NoSuchFieldException|IllegalAccessException e) { + throw new EBaseException(e.getMessage(), e); + } + } + + @Override + public void delete(String name) throws EBaseException { + set(name, null); + } + + @Override + public Enumeration<String> getElements() { + return getSerializableAttrNames(); + } + + @Override + public Enumeration<String> getSerializableAttrNames() { + Vector<String> list = new Vector<String>(); + + // get attributes defined in setters/getters + for (Method method : getClass().getMethods()) { + DBAttribute dbAttribute = method.getAnnotation(DBAttribute.class); + if (dbAttribute == null) continue; + + String name = method.getName(); + if (!name.matches("^set.+") && !name.matches("^get.+")) continue; + + // get attribute name from method name + name = Character.toLowerCase(name.charAt(3)) + name.substring(4); + list.add(name); + } + + // get attributes defined in fields + for (Field field : getClass().getFields()) { + DBAttribute dbAttribute = field.getAnnotation(DBAttribute.class); + if (dbAttribute == null) continue; + + String name = field.getName(); + list.add(name); + } + + return list.elements(); + } + +}
\ No newline at end of file diff --git a/base/common/src/com/netscape/cmscore/dbs/Database.java b/base/common/src/com/netscape/cmscore/dbs/Database.java index 5128298e6..3df2d5919 100644 --- a/base/common/src/com/netscape/cmscore/dbs/Database.java +++ b/base/common/src/com/netscape/cmscore/dbs/Database.java @@ -22,9 +22,10 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; +import com.netscape.certsrv.apps.CMS; + /** - * This class implements in-memory token database. In the future this - * will be replaced with LDAP database. + * This class implements in-memory database. * * @author Endi S. Dewata */ @@ -32,11 +33,14 @@ public class Database<E> { public final static int DEFAULT_SIZE = 20; - public String name ; + public String name; + public Map<String, E> records = new LinkedHashMap<String, E>(); public Database(String name) { this.name = name; + + CMS.debug("Initializing " + name + " database"); } public Collection<E> getRecords() throws Exception { diff --git a/base/common/src/com/netscape/cmscore/dbs/LDAPDatabase.java b/base/common/src/com/netscape/cmscore/dbs/LDAPDatabase.java new file mode 100644 index 000000000..f6ded787b --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/LDAPDatabase.java @@ -0,0 +1,171 @@ +package com.netscape.cmscore.dbs; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Enumeration; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.IDBRegistry; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSearchResults; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; + +/** + * This class implements LDAP database. + * + * @author Endi S. Dewata + */ +public abstract class LDAPDatabase<E extends IDBObj> extends Database<E> { + + public IDBSubsystem dbSubsystem; + public String baseDN; + public Class<E> recordType; + + public LDAPDatabase(String name, IDBSubsystem dbSubsystem, String baseDN, Class<E> recordType) throws EBaseException { + super(name); + + this.dbSubsystem = dbSubsystem; + this.baseDN = baseDN; + this.recordType = recordType; + + register(recordType); + } + + public IDBAttrMapper createMapper(Class<?> attrType, DBAttribute dbAttribute) throws EBaseException { + String attrName = dbAttribute.value(); + + if (attrType == String.class) { + return new StringMapper(attrName); + + } else if (attrType == Date.class) { + return new DateMapper(attrName); + + } else { + // TODO: add other mappers + throw new EBaseException("Unsupported attribute type: " + attrType); + } + } + + public void register(Class<E> recordType) throws EBaseException { + IDBRegistry dbRegistry = dbSubsystem.getRegistry(); + + // register object classes + DBObjectClasses dbObjectClasses = recordType.getAnnotation(DBObjectClasses.class); + if (dbObjectClasses == null) { + throw new EBaseException("Missing object class mapping in " + recordType.getName()); + } + dbRegistry.registerObjectClass(recordType.getName(), dbObjectClasses.value()); + + // register attributes defined in setters/getters + for (Method method : recordType.getMethods()) { + DBAttribute dbAttribute = method.getAnnotation(DBAttribute.class); + if (dbAttribute == null) continue; + + String name = method.getName(); + if (!name.matches("^set.+") && !name.matches("^get.+")) continue; + + // get attribute name from method name + name = Character.toLowerCase(name.charAt(3)) + name.substring(4); + + Class<?> attrType = method.getReturnType(); + IDBAttrMapper mapper = createMapper(attrType, dbAttribute); + + dbRegistry.registerAttribute(name, mapper); + } + + // register attributes defined in fields + for (Field field : recordType.getFields()) { + DBAttribute dbAttribute = field.getAnnotation(DBAttribute.class); + if (dbAttribute == null) continue; + + String name = field.getName(); + Class<?> attrType = field.getType(); + IDBAttrMapper mapper = createMapper(attrType, dbAttribute); + + dbRegistry.registerAttribute(name, mapper); + } + } + + public abstract String createDN(String id); + public abstract String createFilter(String filter); + + @Override + public Collection<E> getRecords() throws Exception { + CMS.debug("LDAPDatabase: getRecords()"); + + try (IDBSSession session = dbSubsystem.createSession()) { + Collection<E> list = new ArrayList<E>(); + + CMS.debug("LDAPDatabase: searching " + baseDN); + IDBSearchResults results = session.search(baseDN, createFilter(null)); + + while (results.hasMoreElements()) { + @SuppressWarnings("unchecked") + E result = (E)results.nextElement(); + list.add(result); + } + + return list; + } + } + + @SuppressWarnings("unchecked") + @Override + public E getRecord(String id) throws Exception { + CMS.debug("LDAPDatabase: getRecord(\"" + id + "\")"); + try (IDBSSession session = dbSubsystem.createSession()) { + String dn = createDN(id); + CMS.debug("LDAPDatabase: reading " + baseDN); + return (E)session.read(dn); + } + } + + @Override + public void addRecord(String id, E record) throws Exception { + CMS.debug("LDAPDatabase: addRecord(\"" + id + "\")"); + try (IDBSSession session = dbSubsystem.createSession()) { + String dn = createDN(id); + + CMS.debug("LDAPDatabase: adding " + dn); + session.add(dn, record); + } + } + + @Override + public void updateRecord(String id, E record) throws Exception { + CMS.debug("LDAPDatabase: updateRecord(\"" + id + "\")"); + try (IDBSSession session = dbSubsystem.createSession()) { + String dn = createDN(id); + + ModificationSet mods = new ModificationSet(); + for (Enumeration<String> names = record.getSerializableAttrNames(); names.hasMoreElements(); ) { + String name = names.nextElement(); + Object value = record.get(name); + mods.add(name, Modification.MOD_REPLACE, value); + } + + CMS.debug("LDAPDatabase: modifying " + dn); + session.modify(dn, mods); + } + } + + @Override + public void removeRecord(String id) throws Exception { + CMS.debug("LDAPDatabase: removeRecord(\"" + id + "\")"); + try (IDBSSession session = dbSubsystem.createSession()) { + String dn = createDN(id); + + CMS.debug("LDAPDatabase: removing " + dn); + session.delete(dn); + } + } + +} |