You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2008/03/04 17:53:03 UTC

svn commit: r633546 - in /jackrabbit/trunk: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/ jackrabbit-site...

Author: dpfister
Date: Tue Mar  4 08:53:00 2008
New Revision: 633546

URL: http://svn.apache.org/viewvc?rev=633546&view=rev
Log:
JCR-1441 - Support workspace event listeners that will be created/registered on initialization time

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceAuditLogger.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/EventListenerConfig.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/WorkspaceConfig.java
    jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-1.4.dtd
    jackrabbit/trunk/jackrabbit-site/src/site/resources/dtd/repository-1.4.dtd

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=633546&r1=633545&r2=633546&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Tue Mar  4 08:53:00 2008
@@ -32,6 +32,7 @@
 import org.apache.jackrabbit.core.cluster.UpdateEventListener;
 import org.apache.jackrabbit.core.config.ClusterConfig;
 import org.apache.jackrabbit.core.config.DataStoreConfig;
+import org.apache.jackrabbit.core.config.EventListenerConfig;
 import org.apache.jackrabbit.core.config.FileSystemConfig;
 import org.apache.jackrabbit.core.config.LoginModuleConfig;
 import org.apache.jackrabbit.core.config.PersistenceManagerConfig;
@@ -603,6 +604,24 @@
                     | Event.PROPERTY_ADDED | Event.PROPERTY_REMOVED
                     | Event.PROPERTY_CHANGED,
                     "/", true, null, null, false);
+        }
+        
+        // create and register user-defined event listeners
+        EventListenerConfig[] elcs = wspInfo.config.getEventListenersConfig();
+        if (elcs != null) {
+            for (int i = 0; i < elcs.length; i++) {
+                EventListenerConfig elc = elcs[i];
+                
+                try {
+                    EventListener el = elcs[i].createEventListener();
+                    wsp.getObservationManager().addEventListener(el, 
+                            elc.getEventTypes(), elc.getAbsPath(), elc.isDeep(),
+                            elc.getUUID(), elc.getNodeTypeName(), elc.isNoLocal());
+                } catch (RepositoryException e) {
+                    log.error("Unable to create and register event listener: " +
+                            elc.getClassName() + ": " + e.getMessage(), e);
+                }
+            }
         }
     }
 

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceAuditLogger.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceAuditLogger.java?rev=633546&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceAuditLogger.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceAuditLogger.java Tue Mar  4 08:53:00 2008
@@ -0,0 +1,307 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Audit logger for some workspace, logging all events observed. The logger
+ * used is obtained by asking the central <code>LoggerFactory</code> for
+ * a logger named <code>audit.<i>workspace</i></code>. If such a logger has not
+ * been declared, the standard logger will be used.
+ * <p/>The output format of this logger is as follows:
+ * <pre>[counter] type path (userid@workspace)</pre>
+ * <p/>The following bean properties are available:
+ * <ul>
+ * <li><code>workspace</code>: workspace name. </li>
+ * <li><code>granularity</code>: logging granularity. If the value is <i>property</i>
+ * all events are logged. If the value is <i>node</i>, events associated with
+ * properties are consolidated and logged as node modification events.</li>
+ * </ul>
+ */
+public class WorkspaceAuditLogger implements EventListener {
+    
+    /**
+     * Logger.
+     */
+    private static final Logger log = LoggerFactory.getLogger(WorkspaceAuditLogger.class);
+    
+    /**
+     * Logger name prefix.
+     */
+    private static final String LOGGER_NAME_PREFIX = "audit.";
+    
+    /**
+     * Node granularity.
+     */
+    private static final String NODE_GRANULARITY = "node";
+
+    /**
+     * Property granularity.
+     */
+    private static final String PROPERTY_GRANULARITY = "property";
+
+    /**
+     * Workspace name.
+     */
+    private String workspace;
+    
+    /**
+     * Granularity.
+     */
+    private String granularity;
+    
+    /**
+     * Event processor based on granularity.
+     */
+    private EventListener processor;
+
+    /**
+     * Private audit logger.
+     */
+    private Logger audit;
+    
+    /**
+     * Event counter.
+     */
+    protected int counter;
+    
+    /**
+     * Initialize this audit logger.
+     */
+    protected void init() {
+        audit = createLogger(getWorkspace());
+        processor = createEventProcessor(getGranularity());
+    }
+    
+    /**
+     * Create the logger associated with this audit's workspace.
+     */
+    protected Logger createLogger(String workspace) {
+        return LoggerFactory.getLogger(LOGGER_NAME_PREFIX + workspace);
+    }
+    
+    /**
+     * Create the event processor associated with this audit's granularity.
+     * 
+     * @param granularity granularity
+     * @return event listener
+     */
+    protected EventListener createEventProcessor(String granularity) {
+        if (PROPERTY_GRANULARITY.equals(granularity)) {
+            return new FullEventLogger();
+        }
+        if (NODE_GRANULARITY.equals(granularity) || granularity == null) {
+            return new ConsolidateLogger();
+        }
+        log.warn("Granularity unknown: " + granularity);
+        return new ConsolidateLogger();
+    }
+    
+    /* (non-Javadoc)
+     * @see javax.jcr.observation.EventListener#onEvent(javax.jcr.observation.EventIterator)
+     * 
+     * Initialize the audit log and event processor if this is the first event 
+     * received and pass the events on.
+     */
+    public synchronized final void onEvent(EventIterator events) {
+        if (audit == null) {
+            init();
+        }
+        counter++;
+        processor.onEvent(events);
+    }
+    
+    /**
+     * Log an event, given type, path and user ID.
+     * @param type type
+     * @param path path
+     * @param userID user ID
+     */
+    protected void log(String type, String path, String userID) {
+        StringBuffer buf = new StringBuffer();
+        buf.append('[');
+        buf.append(String.valueOf(counter));
+        buf.append("] ");
+        buf.append(type);
+        buf.append(" ");
+        buf.append(path);
+        buf.append(" (");
+        buf.append(userID + "@" + workspace);
+        buf.append(")");
+        audit.info(buf.toString());
+    }
+    
+    /**
+     * Return a event type's string representation. In this implementation,
+     * this is either <code>ADD</code>, <code>DEL</code>, <code>MOD</code>
+     * 
+     * @param type event type
+     * @return string representation
+     */
+    protected String typeToString(int type) {
+        switch (type) {
+        case Event.NODE_ADDED:
+            return "ADD";
+        case Event.NODE_REMOVED:
+            return "DEL";
+        case Event.PROPERTY_ADDED:
+            return "add";
+        case Event.PROPERTY_REMOVED:
+            return "del";
+        case Event.PROPERTY_CHANGED:
+            return "mod";
+        }
+        return "???";
+    }
+    
+    /**
+     * Return a flag indicating whether an event is associated with a property.
+     * @param evt event
+     * @return <code>true</code> if the event is associated with a property;
+     *         <code>false</code> otherwise.
+     */
+    public static final boolean isPropertyEvent(Event evt) {
+        switch (evt.getType()) {
+        case Event.NODE_ADDED:
+        case Event.NODE_REMOVED:
+            return false;
+        case Event.PROPERTY_ADDED:
+        case Event.PROPERTY_CHANGED:
+        case Event.PROPERTY_REMOVED:
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * Bean getters.
+     */
+    public String getWorkspace() {
+        return workspace;
+    }
+    
+    public String getGranularity() {
+        return granularity;
+    }
+
+    /**
+     * Bean setters.
+     */
+    public void setWorkspace(String workspace) {
+        this.workspace = workspace;
+    }
+
+    public void setGranularity(String granularity) {
+        this.granularity = granularity;
+    }
+
+    /**
+     * Event processor that will log all events.
+     */
+    private class FullEventLogger implements EventListener {
+
+        /* (non-Javadoc)
+         * @see javax.jcr.observation.EventListener#onEvent(javax.jcr.observation.EventIterator)
+         * 
+         * Log every event.
+         */
+        public void onEvent(EventIterator events) {
+            while (events.hasNext()) {
+                Event event = events.nextEvent();
+                String path = "?";
+                
+                try {
+                    path = event.getPath();
+                } catch (RepositoryException e) {
+                    // ignore
+                }
+                log(typeToString(event.getType()), path, event.getUserID());
+            }
+        }
+    }
+    
+    /**
+     * Event processor that will log node events and consolidate property
+     * events.
+     */
+    private class ConsolidateLogger implements EventListener {
+        
+        /**
+         * Internal structure class that holds node path and user ID. 
+         */
+        class NodeModified {
+            public final String path;
+            public final String userID;
+            
+            NodeModified(String path, String userID) {
+                this.path = path;
+                this.userID = userID;
+            }
+        }
+        
+        /* (non-Javadoc)
+         * @see javax.jcr.observation.EventListener#onEvent(javax.jcr.observation.EventIterator)
+         * 
+         * Consolidate property events, logging a 'node modified' event at the
+         * end if the node itself has neither been added nor removed.
+         */
+        public void onEvent(EventIterator events) {
+            HashMap modifiedNodes = new HashMap();
+            
+            while (events.hasNext()) {
+                Event event = events.nextEvent();
+                String path = "?";
+                
+                try {
+                    path = event.getPath();
+                    if (isPropertyEvent(event)) {
+                        String parentPath = path;
+                        int index = parentPath.lastIndexOf('/');
+                        if (index > 0) {
+                            parentPath = parentPath.substring(0, index);
+                        }
+                        NodeModified nme = new NodeModified(
+                                parentPath, event.getUserID());
+                        modifiedNodes.put(parentPath, nme);
+                        continue;
+                    } else {
+                        modifiedNodes.remove(path);
+                    }
+                } catch (RepositoryException e) { 
+                    // ignore
+                }
+                log(typeToString(event.getType()), path, event.getUserID());
+            }
+            Iterator iter = modifiedNodes.values().iterator();
+            while (iter.hasNext()) {
+                NodeModified nme = (NodeModified) iter.next();
+                log("MOD", nme.path, nme.userID);
+            }
+        }
+    }
+
+}
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java?rev=633546&r1=633545&r2=633546&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/ConfigurationParser.java Tue Mar  4 08:53:00 2008
@@ -286,4 +286,49 @@
         }
     }
 
+    /**
+     * Returns the value of the named attribute of the given element.
+     * If the attribute is not found, then the given default value is returned.
+     *
+     * @param element element
+     * @param name attribute name
+     * @param def default value
+     * @return attribute value, or the default value
+     */
+    protected boolean getAttribute(Element element, String name, boolean def) {
+        Attr attribute = element.getAttributeNode(name);
+        if (attribute != null) {
+            return Boolean.valueOf(attribute.getValue()).booleanValue();
+        } else {
+            return def;
+        }
+    }
+
+    /**
+     * Returns the value of the named attribute of the given element.
+     * If the attribute is not found, then the given default value is returned.
+     *
+     * @param element element
+     * @param name attribute name
+     * @param def default value
+     * @return attribute value, or the default value
+     */
+    protected int getAttribute(Element element, String name, int def) 
+            throws ConfigurationException {
+        
+        Attr attribute = element.getAttributeNode(name);
+        if (attribute != null) {
+            String s = attribute.getValue();
+            
+            try {
+                return Integer.parseInt(s);
+            } catch (NumberFormatException e) {
+                throw new ConfigurationException(
+                        "Value of attribute " + name + 
+                        " is not an integer: " + s, e);
+            }
+        } else {
+            return def;
+        }
+    }
 }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/EventListenerConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/EventListenerConfig.java?rev=633546&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/EventListenerConfig.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/EventListenerConfig.java Tue Mar  4 08:53:00 2008
@@ -0,0 +1,130 @@
+/*
+ * 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 java.util.Properties;
+
+import javax.jcr.observation.EventListener;
+
+/**
+ * Event listener configuration. This bean configuration class
+ * is used to create configured event listener objects.
+ */
+public class EventListenerConfig extends BeanConfig {
+
+    /**
+     * Event types.
+     */
+    private int eventTypes;
+    
+    /**
+     * Absolute path.
+     */
+    private String absPath;
+    
+    /**
+     * Deep flag.
+     */
+    private boolean isDeep;
+    
+    /**
+     * UUID array.
+     */
+    private String[] uuid;
+    
+    /**
+     * Node type name array.
+     */
+    private String[] nodeTypeName;
+    
+    /**
+     * NoLocal flag.
+     */
+    private boolean noLocal;
+    
+    /**
+     * Creates a new event listener configuration.
+     *
+     * @param className  the class name of the event listener implementation.
+     * @param parameters configuration parameters.
+     */
+    public EventListenerConfig(String className, Properties parameters) {
+        super(className, parameters);
+    }
+
+    /**
+     * @return a new event listener instance based on this configuration.
+     * @throws ConfigurationException on bean configuration errors.
+     */
+    public EventListener createEventListener() throws ConfigurationException {
+        return (EventListener) newInstance();
+    }
+
+    /**
+     * Bean getters
+     */
+    public int getEventTypes() {
+        return eventTypes;
+    }
+
+    public String getAbsPath() {
+        return absPath;
+    }
+
+    public boolean isDeep() {
+        return isDeep;
+    }
+
+    public String[] getUUID() {
+        return uuid;
+    }
+
+    public String[] getNodeTypeName() {
+        return nodeTypeName;
+    }
+
+    public boolean isNoLocal() {
+        return noLocal;
+    }
+
+    /**
+     * Bean setters.
+     */
+    public void setEventTypes(int eventTypes) {
+        this.eventTypes = eventTypes;
+    }
+
+    public void setAbsPath(String absPath) {
+        this.absPath = absPath;
+    }
+
+    public void setDeep(boolean isDeep) {
+        this.isDeep = isDeep;
+    }
+
+    public void setUUID(String[] uuid) {
+        this.uuid = uuid;
+    }
+
+    public void setNodeTypeName(String[] nodeTypeName) {
+        this.nodeTypeName = nodeTypeName;
+    }
+
+    public void setNoLocal(boolean noLocal) {
+        this.noLocal = noLocal;
+    }
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java?rev=633546&r1=633545&r2=633546&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java Tue Mar  4 08:53:00 2008
@@ -17,8 +17,11 @@
 package org.apache.jackrabbit.core.config;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.Properties;
 
+import javax.jcr.observation.Event;
+
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -92,6 +95,9 @@
     /** Name of the ism locking configuration element. */
     public static final String ISM_LOCKING_ELEMENT = "ISMLocking";
 
+    /** Name of the event listener configuration element. */
+    public static final String EVENT_LISTENER_ELEMENT = "EventListener";
+    
     /** Name of the application name configuration attribute. */
     public static final String APP_NAME_ATTRIBUTE = "appName";
 
@@ -124,6 +130,32 @@
     /** Default synchronization delay, in milliseconds. */
     public static final String DEFAULT_SYNC_DELAY = "5000";
 
+    /** Name of the eventTypes attribute */
+    public static final String EVENT_TYPES_ATTRIBUTE = "eventTypes";
+    
+    /** Default value of the eventTypes attribute */
+    public static final int EVENT_TYPES_VALUE = 
+        Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED |
+        Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
+
+    /** Name of the absPath attribute */
+    public static final String ABS_PATH_ATTRIBUTE = "absPath";
+
+    /** Name of the isDeep attribute */
+    public static final String IS_DEEP_ATTRIBUTE = "isDeep";
+
+    /** Name of the uuid attribute */
+    public static final String UUID_ATTRIBUTE = "uuid";
+
+    /** Name of the nodeTypeName attribute */
+    public static final String NODE_TYPE_NAME_ATTRIBUTE = "nodeTypeName";
+    
+    /** Name of the noLocal attribute */
+    public static final String NO_LOCAL_ATTRIBUTE = "noLocal";
+    
+    /** Name of the workspace property */
+    public static final String WORKSPACE_PROP_NAME = "workspace";
+    
     /**
      * Creates a new configuration parser with the given parser variables.
      *
@@ -371,7 +403,10 @@
         // Item state manager locking configuration (optional)
         ISMLockingConfig ismLockingConfig = tmpParser.parseISMLockingConfig(root);
 
-        return new WorkspaceConfig(home, name, clustered, fsc, pmc, sc, ismLockingConfig);
+        // Event listeners configuration (optional)
+        EventListenerConfig[] elcs = tmpParser.parseEventListenersConfig(root);
+        
+        return new WorkspaceConfig(home, name, clustered, fsc, pmc, sc, ismLockingConfig, elcs);
     }
 
     /**
@@ -472,6 +507,70 @@
         return null;
     }
 
+    
+    /**
+     * Parse event listeners config.
+     * 
+     * @param parent parent of the <code>EventListener</code> elements.
+     * @return event listener configuration array
+     * @throws ConfigurationException if the configuration is broken
+     */
+    protected EventListenerConfig[] parseEventListenersConfig(Element parent)
+            throws ConfigurationException {
+        
+        ArrayList configs = new ArrayList();
+        
+        NodeList children = parent.getChildNodes();
+        for (int i = 0; i < children.getLength(); i++) {
+            Node child = children.item(i);
+            if (child.getNodeType() == Node.ELEMENT_NODE
+                    && EVENT_LISTENER_ELEMENT.equals(child.getNodeName())) {
+                Element element = (Element) child;
+                configs.add(parseEventListenerConfig(element));
+            }
+        }
+        EventListenerConfig[] rv = new EventListenerConfig[configs.size()];
+        configs.toArray(rv);
+        return rv;
+    }
+
+    /**
+     * Parse event listener config.
+     * 
+     * @param element an  <code>EventListener</code> element.
+     * @return event listener configuration
+     * @throws ConfigurationException if the configuration is broken
+     */
+    protected EventListenerConfig parseEventListenerConfig(Element element)
+            throws ConfigurationException {
+        
+        String className = getAttribute(element, CLASS_ATTRIBUTE);
+        Properties parameters = parseParameters(element);
+        
+        // Provide a meaningful default for the workspace property
+        if (!parameters.containsKey(WORKSPACE_PROP_NAME)) {
+            parameters.put(WORKSPACE_PROP_NAME, 
+                    replaceVariables("${" + WORKSPACE_NAME_VARIABLE + "}"));
+        }
+
+        EventListenerConfig config = new EventListenerConfig(className, parameters);
+        config.setEventTypes(getAttribute(element, 
+                EVENT_TYPES_ATTRIBUTE, EVENT_TYPES_VALUE));
+        config.setAbsPath(getAttribute(element, ABS_PATH_ATTRIBUTE, "/"));
+        config.setDeep(getAttribute(element, IS_DEEP_ATTRIBUTE, true));
+        
+        String s = getAttribute(element, UUID_ATTRIBUTE, null);
+        if (s != null) {
+            config.setUUID(s.split(","));
+        }
+        s = getAttribute(element, NODE_TYPE_NAME_ATTRIBUTE, null);
+        if (s != null) {
+            config.setNodeTypeName(s.split(","));
+        }
+        config.setNoLocal(getAttribute(element, NO_LOCAL_ATTRIBUTE, false));
+        return config;
+    }
+    
     /**
      * Parses versioning configuration. Versioning configuration uses the
      * following format:

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/WorkspaceConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/WorkspaceConfig.java?rev=633546&r1=633545&r2=633546&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/WorkspaceConfig.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/WorkspaceConfig.java Tue Mar  4 08:53:00 2008
@@ -63,6 +63,11 @@
     private ISMLockingConfig ismLockingConfig;
 
     /**
+     * Event listeners configuration.
+     */
+    private EventListenerConfig[] elcs;
+    
+    /**
      * Creates a workspace configuration object.
      *
      * @param home home directory
@@ -75,7 +80,8 @@
      */
     public WorkspaceConfig(String home, String name, boolean clustered,
                            FileSystemConfig fsc, PersistenceManagerConfig pmc,
-                           SearchConfig sc, ISMLockingConfig ismLockingConfig) {
+                           SearchConfig sc, ISMLockingConfig ismLockingConfig,
+                           EventListenerConfig[] elcs) {
         this.home = home;
         this.name = name;
         this.clustered = clustered;
@@ -87,6 +93,7 @@
         } else {
             this.ismLockingConfig = ISMLockingConfig.createDefaultConfig();
         }
+        this.elcs = elcs;
     }
 
     /**
@@ -124,6 +131,13 @@
         return ismLockingConfig;
     }
 
+    /**
+     * @return the configuration for the event listeners.
+     */
+    public EventListenerConfig[] getEventListenersConfig() {
+        return elcs;
+    }
+    
     /**
      * Returns the file system configuration.
      *

Modified: jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-1.4.dtd
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-1.4.dtd?rev=633546&r1=633545&r2=633546&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-1.4.dtd (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/config/repository-1.4.dtd Tue Mar  4 08:53:00 2008
@@ -119,7 +119,7 @@
     it is used to create the initial workspace if there's no workspace yet
     and for creating additional workspaces through the api
 -->
-<!ELEMENT Workspace (FileSystem,PersistenceManager,SearchIndex?,ISMLocking?)>
+<!ELEMENT Workspace (FileSystem,PersistenceManager,SearchIndex?,ISMLocking?,EventListener*)>
 <!ATTLIST Workspace name CDATA #REQUIRED>
 
 <!--
@@ -172,3 +172,16 @@
 -->
 <!ELEMENT ISMLocking (param*)>
 <!ATTLIST ISMLocking class CDATA #REQUIRED>
+
+<!--
+    The EventListener element configures a user-defined event listener that
+    will be created and registered on workspace initialization.
+-->
+<!ELEMENT EventListener (param*)>
+<!ATTLIST EventListener class        CDATA #REQUIRED
+                        eventTypes   CDATA #IMPLIED
+                        absPath      CDATA #IMPLIED
+                        isDeep       CDATA #IMPLIED
+                        uuid         CDATA #IMPLIED
+                        nodeTypeName CDATA #IMPLIED
+                        noLocal      CDATA #IMPLIED>

Modified: jackrabbit/trunk/jackrabbit-site/src/site/resources/dtd/repository-1.4.dtd
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-site/src/site/resources/dtd/repository-1.4.dtd?rev=633546&r1=633545&r2=633546&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-site/src/site/resources/dtd/repository-1.4.dtd (original)
+++ jackrabbit/trunk/jackrabbit-site/src/site/resources/dtd/repository-1.4.dtd Tue Mar  4 08:53:00 2008
@@ -119,7 +119,7 @@
     it is used to create the initial workspace if there's no workspace yet
     and for creating additional workspaces through the api
 -->
-<!ELEMENT Workspace (FileSystem,PersistenceManager,SearchIndex?,ISMLocking?)>
+<!ELEMENT Workspace (FileSystem,PersistenceManager,SearchIndex?,ISMLocking?,EventListener*)>
 <!ATTLIST Workspace name CDATA #REQUIRED>
 
 <!--
@@ -180,3 +180,17 @@
 -->
 <!ELEMENT DataStore (param*)>
 <!ATTLIST DataStore class CDATA #REQUIRED>
+
+<!--
+    The EventListener element configures a user-defined event listener that
+    will be created and registered on workspace initialization.
+-->
+<!ELEMENT EventListener (param*)>
+<!ATTLIST EventListener class        CDATA #REQUIRED
+                        eventTypes   CDATA #IMPLIED
+                        absPath      CDATA #IMPLIED
+                        isDeep       CDATA #IMPLIED
+                        uuid         CDATA #IMPLIED
+                        nodeTypeName CDATA #IMPLIED
+                        noLocal      CDATA #IMPLIED>
+