From d825f272d7479de2a53725377ae9f77cc0ba2b73 Mon Sep 17 00:00:00 2001
From: Chetan Mehrotra <chetanm@adobe.com>
Date: Wed, 5 Sep 2012 22:26:47 +0530
Subject: [PATCH] Adding support for creating bean instance from configuration
 via a factory class. The factory class can be provided as a
 BeanFactory implementation as part of
 RepositoryConfigurationParser

-- Added a new attribute 'factoryType' for various class elements in the repository config. The DTD file has been updated for new attribute. To allow class to be created via factory set the factoryType to say 'osgi'. By default it is assumed to be simple. For example in case balow a custom BeanFacory would try to wire up an implementation of  AuthorizableAction interface

  <AuthorizableAction class="org.apache.jackrabbit.core.security.user.action.AuthorizableAction"  factoryType="osgi"/>

-- Added a  new BeanVisitor interface which would allow pre processing of BeanConfig before it is used for creating instance. This can be used to find out all the required service interfaces for determining dependencies in OSGi env
---
 .../apache/jackrabbit/core/config/BeanConfig.java  |   96 ++++++++++----------
 .../jackrabbit/core/config/BeanConfigVisitor.java  |   27 ++++++
 .../apache/jackrabbit/core/config/BeanFactory.java |   23 +++++
 .../core/config/ConfigurationParser.java           |   19 ++--
 .../jackrabbit/core/config/NoOpConfigVisitor.java  |   24 +++++
 .../core/config/RepositoryConfigurationParser.java |   19 +++-
 .../jackrabbit/core/config/SimpleBeanFactory.java  |   60 ++++++++++++
 .../core/config/repository-2.4-elements.dtd        |   37 ++++----
 8 files changed, 229 insertions(+), 76 deletions(-)
 create mode 100644 jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfigVisitor.java
 create mode 100644 jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanFactory.java
 create mode 100644 jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/NoOpConfigVisitor.java
 create mode 100644 jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SimpleBeanFactory.java

diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfig.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfig.java
index 8407d1e..e820420 100644
--- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfig.java
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfig.java
@@ -68,6 +68,13 @@
         BeanConfig.class.getClassLoader();
 
     /**
+     * Factory to create instance from Bean className
+     */
+    private BeanFactory instanceFactory = new SimpleBeanFactory();
+
+    private String factoryType = SimpleBeanFactory.TYPE;
+
+    /**
      * The current class loader used by this instance to create instances of
      * configured classes.
      */
@@ -127,6 +134,7 @@ public BeanConfig(String className, Properties properties) {
     public BeanConfig(BeanConfig config) {
         this(config.getClassName(), config.getParameters());
         setConnectionFactory(config.connectionFactory);
+        setFactoryType(config.factoryType);
     }
 
     /**
@@ -148,6 +156,14 @@ public void setConnectionFactory(ConnectionFactory connectionFactory) {
     }
 
     /**
+     *
+     * @param instanceFactory the {@link BeanFactory} to use to create bean instance
+     */
+    public void setInstanceFactory(BeanFactory instanceFactory) {
+        this.instanceFactory = instanceFactory;
+    }
+
+    /**
      * Returns the class name of the configured bean.
      *
      * @return class name of the bean
@@ -165,6 +181,14 @@ public Properties getParameters() {
         return properties;
     }
 
+    public String getFactoryType() {
+        return factoryType;
+    }
+
+    public void setFactoryType(String factoryType) {
+        this.factoryType = factoryType;
+    }
+
     /**
      * Creates a new instance of the configured bean class.
      *
@@ -174,59 +198,35 @@ public Properties getParameters() {
     @SuppressWarnings("unchecked")
     public <T> T newInstance(Class<T> klass) throws ConfigurationException {
         String cname = getClassName();
-        try {
-            Class<?> objectClass = Class.forName(cname, true, getClassLoader());
-            if (!klass.isAssignableFrom(objectClass)) {
-                throw new ConfigurationException(
-                        "Configured class " + cname
-                        + " does not implement " + klass.getName()
-                        + ". Please fix the repository configuration.");
-            }
-            if (objectClass.getAnnotation(Deprecated.class) != null) {
-                log.warn("{} has been deprecated", cname);
-            }
+        // Instantiate the object using the default constructor
+        Object instance = instanceFactory.newInstance(klass,this);
+        Class<?> objectClass = instance.getClass();
 
-            // Instantiate the object using the default constructor
-            Object instance = objectClass.newInstance();
-
-            // Set all configured bean properties
-            Map<String, Method> setters = getSetters(objectClass);
-            Enumeration<?> enumeration = properties.propertyNames();
-            while (enumeration.hasMoreElements()) {
-                String name = enumeration.nextElement().toString();
-                Method setter = setters.get(name);
-                if (setter != null) {
-                    if (setter.getAnnotation(Deprecated.class) != null) {
-                        log.warn("Parameter {} of {} has been deprecated",
-                                name, cname);
-                    }
-                    String value = properties.getProperty(name);
-                    setProperty(instance, name, setter, value);
-                } else if (validate) {
-                    throw new ConfigurationException(
-                            "Configured class " + cname
-                            + " does not contain a property named " + name);
+        // Set all configured bean properties
+        Map<String, Method> setters = getSetters(objectClass);
+        Enumeration<?> enumeration = properties.propertyNames();
+        while (enumeration.hasMoreElements()) {
+            String name = enumeration.nextElement().toString();
+            Method setter = setters.get(name);
+            if (setter != null) {
+                if (setter.getAnnotation(Deprecated.class) != null) {
+                    log.warn("Parameter {} of {} has been deprecated",
+                            name, cname);
                 }
+                String value = properties.getProperty(name);
+                setProperty(instance, name, setter, value);
+            } else if (validate) {
+                throw new ConfigurationException(
+                        "Configured class " + cname
+                        + " does not contain a property named " + name);
             }
+        }
 
-            if (instance instanceof DatabaseAware) {
-                ((DatabaseAware) instance).setConnectionFactory(connectionFactory);
-            }
-
-            return (T) instance;
-        } catch (ClassNotFoundException e) {
-            throw new ConfigurationException(
-                    "Configured bean implementation class " + cname
-                    + " was not found.", e);
-        } catch (InstantiationException e) {
-            throw new ConfigurationException(
-                    "Configured bean implementation class " + cname
-                    + " can not be instantiated.", e);
-        } catch (IllegalAccessException e) {
-            throw new ConfigurationException(
-                    "Configured bean implementation class " + cname
-                    + " is protected.", e);
+        if (instance instanceof DatabaseAware) {
+            ((DatabaseAware) instance).setConnectionFactory(connectionFactory);
         }
+
+        return (T) instance;
     }
 
     private Map<String, Method> getSetters(Class<?> klass) {
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfigVisitor.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfigVisitor.java
new file mode 100644
index 0000000..f43270a
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanConfigVisitor.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.config;
+
+/**
+ * A BeanConfig visitor which is invoked upon creation of BeanConfig before any
+ * instance is created from that bean configuration
+ */
+public interface BeanConfigVisitor {
+
+    void visit(BeanConfig config);
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanFactory.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanFactory.java
new file mode 100644
index 0000000..e4b37ca
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/BeanFactory.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.config;
+
+
+public interface BeanFactory {
+
+    Object newInstance(Class<?> klass, BeanConfig config) throws ConfigurationException;
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java
index 24bfbbf..d593dc7 100644
--- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java
@@ -58,6 +58,11 @@
     /** Name of the bean parameter value configuration attribute. */
     public static final String VALUE_ATTRIBUTE = "value";
 
+    /** Name of the bean parameter value configuration attribute. */
+    public static final String FACTORY_ATTRIBUTE = "factoryType";
+
+    private static final String DEFAULT_FACTORY_TYPE  = SimpleBeanFactory.TYPE;
+
     /**
      * The configuration parser variables. These name-value pairs
      * are used to substitute <code>${...}</code> variable references
@@ -109,13 +114,7 @@ protected BeanConfig parseBeanConfig(Element parent, String name)
         // Bean configuration element
         Element element = getElement(parent, name);
 
-        // Bean implementation class
-        String className = getAttribute(element, CLASS_ATTRIBUTE);
-
-        // Bean properties
-        Properties properties = parseParameters(element);
-
-        return new BeanConfig(className, properties);
+        return parseBeanConfig(element);
     }
 
     /**
@@ -141,11 +140,15 @@ protected BeanConfig parseBeanConfig(Element element)
             throws ConfigurationException {
         // Bean implementation class
         String className = getAttribute(element, CLASS_ATTRIBUTE);
+        String factoryType = getAttribute(element, FACTORY_ATTRIBUTE, DEFAULT_FACTORY_TYPE);
 
         // Bean properties
         Properties properties = parseParameters(element);
 
-        return new BeanConfig(className, properties);
+        BeanConfig bc = new BeanConfig(className, properties);
+        bc.setFactoryType(factoryType);
+
+        return bc;
     }
 
     /**
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/NoOpConfigVisitor.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/NoOpConfigVisitor.java
new file mode 100644
index 0000000..995bc7c
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/NoOpConfigVisitor.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.config;
+
+public class NoOpConfigVisitor implements BeanConfigVisitor{
+    @Override
+    public void visit(BeanConfig config) {
+
+    }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
index d94c8c0..5fa84d8 100644
--- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
@@ -203,6 +203,10 @@
      */
     protected final ConnectionFactory connectionFactory;
 
+    protected BeanFactory beanFactory = new SimpleBeanFactory();
+
+    protected BeanConfigVisitor configVisitor = new NoOpConfigVisitor();
+
     /**
      * Element specifying the class of principals used to retrieve the userID
      * in the 'class' attribute.
@@ -355,6 +359,8 @@ public RepositoryConfig parseRepositoryConfig(InputSource xml)
     protected BeanConfig parseBeanConfig(Element parent, String name) throws ConfigurationException {
         BeanConfig cfg = super.parseBeanConfig(parent, name);
         cfg.setConnectionFactory(connectionFactory);
+        cfg.setInstanceFactory(beanFactory);
+        configVisitor.visit(cfg);
         return cfg;
     }
 
@@ -365,6 +371,8 @@ protected BeanConfig parseBeanConfig(Element parent, String name) throws Configu
     protected BeanConfig parseBeanConfig(Element element) throws ConfigurationException {
         BeanConfig cfg = super.parseBeanConfig(element);
         cfg.setConnectionFactory(connectionFactory);
+        cfg.setInstanceFactory(beanFactory);
+        configVisitor.visit(cfg);
         return cfg;
     }
 
@@ -724,8 +732,7 @@ public ImportConfig parseImportConfig(Element parent) throws ConfigurationExcept
                     if (IMPORT_PNI_ELEMENT.equals(child.getNodeName()) ||
                             IMPORT_PPI_ELEMENT.equals(child.getNodeName()) ||
                             IMPORT_PII_ELEMENT.equals(child.getNodeName())) {
-                        String className = getAttribute((Element) child, CLASS_ATTRIBUTE);
-                        BeanConfig bc = new BeanConfig(className, parseParameters((Element) child));
+                        BeanConfig bc = parseBeanConfig((Element) child);
                         bc.setValidate(false);
                         protectedItemImporters.add(bc);
                     } // else: some other entry -> ignore.
@@ -1085,4 +1092,12 @@ public FileSystem getFileSystem() throws RepositoryException {
         };
     }
 
+
+    public void setBeanFactory(BeanFactory beanFactory) {
+        this.beanFactory = beanFactory;
+    }
+
+    public void setConfigVisitor(BeanConfigVisitor configVisitor) {
+        this.configVisitor = configVisitor;
+    }
 }
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SimpleBeanFactory.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SimpleBeanFactory.java
new file mode 100644
index 0000000..a628bf7
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/SimpleBeanFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.config;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SimpleBeanFactory implements BeanFactory {
+
+    public static final String TYPE = "simple";
+
+    private Logger log = LoggerFactory.getLogger(getClass());
+
+    @Override
+    public Object newInstance(Class<?> klass, BeanConfig config) throws ConfigurationException{
+        String cname = config.getClassName();
+        try {
+            Class<?> objectClass = Class.forName(cname, true, config.getClassLoader());
+            if (!klass.isAssignableFrom(objectClass)) {
+                throw new ConfigurationException(
+                        "Configured class " + cname
+                                + " does not implement " + klass.getName()
+                                + ". Please fix the repository configuration.");
+            }
+            if (objectClass.getAnnotation(Deprecated.class) != null) {
+                log.warn("{} has been deprecated", cname);
+            }
+
+            // Instantiate the object using the default constructor
+            return objectClass.newInstance();
+        } catch (ClassNotFoundException e) {
+            throw new ConfigurationException(
+                    "Configured bean implementation class " + cname
+                            + " was not found.", e);
+        } catch (InstantiationException e) {
+            throw new ConfigurationException(
+                    "Configured bean implementation class " + cname
+                            + " can not be instantiated.", e);
+        } catch (IllegalAccessException e) {
+            throw new ConfigurationException(
+                    "Configured bean implementation class " + cname
+                            + " is protected.", e);
+        }
+    }
+}
diff --git a/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-2.4-elements.dtd b/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-2.4-elements.dtd
index 8ead939..b65ffc1 100644
--- a/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-2.4-elements.dtd
+++ b/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-2.4-elements.dtd
@@ -19,13 +19,14 @@
 
 <!ENTITY % jackrabbit-repository-elements
          "DataSources|Cluster|FileSystem|DataStore|Security|Workspaces|Workspace|Versioning|SearchIndex|RepositoryLockMechanism">
-
+<!ENTITY % class-group "class CDATA #REQUIRED
+  factoryType CDATA #IMPLIED" >
 <!--
     The DataSources element configures the data sources of the repository.
 -->
 <!ELEMENT DataSources (DataSource*)>
 <!ELEMENT DataSource (param*)>
-<!ATTLIST DataSource name CDATA #REQUIRED>
+<!ATTLIST DataSource %class-group; >
 
 <!--
     a virtual file system
@@ -48,7 +49,7 @@
     class implementing the JackrabbitSecurityManager interface
 -->
 <!ELEMENT SecurityManager (WorkspaceAccessManager?,UserManager?,UserIdClass?, param*)>
-<!ATTLIST SecurityManager class CDATA #REQUIRED
+<!ATTLIST SecurityManager %class-group;
                           workspaceName CDATA #IMPLIED>
 
 <!--
@@ -57,7 +58,7 @@
     class implementing the AccessManager interface
 -->
 <!ELEMENT AccessManager (param*)>
-<!ATTLIST AccessManager class CDATA #REQUIRED>
+<!ATTLIST AccessManager %class-group;>
 
 <!--
     generic parameter (name/value pair)
@@ -72,7 +73,7 @@
     non-JAAS environment.
 -->
 <!ELEMENT LoginModule (param*)>
-<!ATTLIST LoginModule class CDATA #REQUIRED>
+<!ATTLIST LoginModule %class-group;>
 
 <!--
     the WorkspaceAccessManager element optionally configures the manager
@@ -82,7 +83,7 @@
     WorkspaceAccessManager interface
 -->
 <!ELEMENT WorkspaceAccessManager EMPTY>
-<!ATTLIST WorkspaceAccessManager class CDATA #REQUIRED>
+<!ATTLIST WorkspaceAccessManager %class-group;>
 
 <!--
     the Workspaces element specifies the physical workspaces root directory
@@ -123,7 +124,7 @@
     FQN of the class implementing the PersistenceManager interface
 -->
 <!ELEMENT PersistenceManager (param*)>
-<!ATTLIST PersistenceManager class CDATA #REQUIRED>
+<!ATTLIST PersistenceManager %class-group;>
 
 <!--
     the SearchIndex element specifies the locaction of the search index
@@ -131,7 +132,7 @@
     FQN of the class implementing the QueryHandler interface.
 -->
 <!ELEMENT SearchIndex (param*,FileSystem?)>
-<!ATTLIST SearchIndex class CDATA #REQUIRED>
+<!ATTLIST SearchIndex %class-group;>
 
 
 <!--
@@ -146,7 +147,7 @@
     The param(s) define implementation specific parameters.
 -->
 <!ELEMENT AccessControlProvider (param*)>
-<!ATTLIST AccessControlProvider class CDATA #REQUIRED>
+<!ATTLIST AccessControlProvider %class-group;>
 
 <!--
     the Versioning element configures the persistence manager
@@ -172,7 +173,7 @@
     Journal interface.
 -->
 <!ELEMENT Journal (param*)>
-<!ATTLIST Journal class CDATA #REQUIRED>
+<!ATTLIST Journal %class-group;>
 
 <!--
     the ISMLocking element configures the locking implementation
@@ -181,7 +182,7 @@
     ISMLocking interface.
 -->
 <!ELEMENT ISMLocking (param*)>
-<!ATTLIST ISMLocking class CDATA #REQUIRED>
+<!ATTLIST ISMLocking %class-group;>
 
 <!--
     the RepositoryLockMechanism element configures the mechanism
@@ -191,7 +192,7 @@
     RepositoryLockMechanism interface.
 -->
 <!ELEMENT RepositoryLockMechanism (param*)>
-<!ATTLIST RepositoryLockMechanism class CDATA #REQUIRED>
+<!ATTLIST RepositoryLockMechanism %class-group;>
 
 <!--
     the DataStore element configures the data store
@@ -199,7 +200,7 @@
     FQN of the class implementing the DataStore interface
 -->
 <!ELEMENT DataStore (param*)>
-<!ATTLIST DataStore class CDATA #REQUIRED>
+<!ATTLIST DataStore %class-group;>
 
 <!--
     The Import element configures how protected items are imported into a
@@ -214,7 +215,7 @@
     The param(s) define implementation specific parameters.
 -->
 <!ELEMENT ProtectedNodeImporter (param*)>
-<!ATTLIST ProtectedNodeImporter class CDATA #REQUIRED>
+<!ATTLIST ProtectedNodeImporter %class-group;>
 
 <!--
     The ProtectedPropertyImporter element configures an importer for protected
@@ -223,7 +224,7 @@
     The param(s) define implementation specific parameters.
 -->
 <!ELEMENT ProtectedPropertyImporter (param*)>
-<!ATTLIST ProtectedPropertyImporter class CDATA #REQUIRED>
+<!ATTLIST ProtectedPropertyImporter %class-group;>
 
 <!--
     The UserManager element configures the user manager implementation that is
@@ -232,7 +233,7 @@
     The param(s) define implementation specific parameters.
 -->
 <!ELEMENT UserManager (param*,AuthorizableAction*)>
-<!ATTLIST UserManager class CDATA #REQUIRED>
+<!ATTLIST UserManager %class-group;>
 
 <!--
    The optional AuthorizableAction element(s) configure additional custom
@@ -241,7 +242,7 @@
    The parameter(s) define the implementation specific configuration.
 -->
 <!ELEMENT AuthorizableAction (param*)>
-<!ATTLIST AuthorizableAction class CDATA #REQUIRED>
+<!ATTLIST AuthorizableAction %class-group;>
 
 
 <!--
@@ -250,4 +251,4 @@
     class implementing the java.security.Principal interface.
 -->
 <!ELEMENT UserIdClass EMPTY>
-<!ATTLIST UserIdClass class CDATA #REQUIRED>
+<!ATTLIST UserIdClass %class-group;>
-- 
1.7.10

