summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorEndi S. Dewata <edewata@redhat.com>2013-09-12 13:24:32 -0400
committerEndi S. Dewata <edewata@redhat.com>2013-09-17 14:37:27 -0400
commit3567f557307606c5f09496469a92f6972f5d5750 (patch)
tree50d62ae7032da4bbfb073274ebdde0256bcb7aa3 /base
parentb5796dfde426414ac81614751c33f23aa356eae4 (diff)
downloadpki-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')
-rw-r--r--base/common/src/com/netscape/certsrv/dbs/IDBSSession.java2
-rw-r--r--base/common/src/com/netscape/cmscore/dbs/DBAttribute.java30
-rw-r--r--base/common/src/com/netscape/cmscore/dbs/DBObjectClasses.java30
-rw-r--r--base/common/src/com/netscape/cmscore/dbs/DBRecord.java98
-rw-r--r--base/common/src/com/netscape/cmscore/dbs/Database.java10
-rw-r--r--base/common/src/com/netscape/cmscore/dbs/LDAPDatabase.java171
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);
+ }
+ }
+
+}