You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by jd...@apache.org on 2008/09/24 18:53:26 UTC

svn commit: r698648 - in /geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src: main/java/org/apache/geronimo/gshell/wisdom/config/ main/resources/org/apache/geronimo/gshell/wisdom/config/ test/java/org/apache/geronimo/gshell/wisdom/config/ test/...

Author: jdillon
Date: Wed Sep 24 09:53:26 2008
New Revision: 698648

URL: http://svn.apache.org/viewvc?rev=698648&view=rev
Log:
Have the basic functionality working for the spring "gshell" namespace

Added:
    geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/
    geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/DummyAction.java   (with props)
    geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/PluginParserTest.java
    geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/resources/org/apache/geronimo/gshell/wisdom/config/
    geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/resources/org/apache/geronimo/gshell/wisdom/config/PluginParserTest-context.xml   (with props)
Modified:
    geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/main/java/org/apache/geronimo/gshell/wisdom/config/PluginParser.java
    geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/main/resources/org/apache/geronimo/gshell/wisdom/config/wisdom-gshell.xsd

Modified: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/main/java/org/apache/geronimo/gshell/wisdom/config/PluginParser.java
URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/main/java/org/apache/geronimo/gshell/wisdom/config/PluginParser.java?rev=698648&r1=698647&r2=698648&view=diff
==============================================================================
--- geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/main/java/org/apache/geronimo/gshell/wisdom/config/PluginParser.java (original)
+++ geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/main/java/org/apache/geronimo/gshell/wisdom/config/PluginParser.java Wed Sep 24 09:53:26 2008
@@ -20,13 +20,24 @@
 package org.apache.geronimo.gshell.wisdom.config;
 
 import org.apache.geronimo.gshell.wisdom.plugin.PluginImpl;
+import org.apache.geronimo.gshell.wisdom.plugin.bundle.CommandBundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.ManagedList;
 import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
+import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
 import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
 import org.springframework.util.xml.DomUtils;
+import org.w3c.dom.Attr;
 import org.w3c.dom.Element;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -37,26 +48,284 @@
 public class PluginParser
     extends AbstractBeanDefinitionParser
 {
-    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext) {
+    @Override
+    protected boolean shouldGenerateId() {
+		return true;
+	}
+
+    @Override
+	protected boolean shouldGenerateIdAsFallback() {
+		return true;
+	}
+
+    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext context) {
         assert element != null;
-        assert parserContext != null;
+        assert context != null;
+
+        Builder builder = new Builder(context);
+        BeanDefinitionBuilder plugin = builder.buildPlugin(element);
+        return plugin.getBeanDefinition();
+    }
 
-        BeanDefinitionBuilder plugin = BeanDefinitionBuilder.rootBeanDefinition(PluginImpl.class);
-        plugin.addPropertyValue("id", element.getAttribute("name"));
+    /**
+     * Helper to deal with command type.
+     */
+    private enum CommandType
+    {
+        STATELESS,
+        STATEFUL;
 
-        @SuppressWarnings({"unchecked"})
-        List<Element> children = DomUtils.getChildElementsByTagName(element, "command-bundle");
-        if (children != null && children.size() > 0) {
-            parseCommandBundles(plugin, children);
+        public static CommandType parse(final String text) {
+            assert text != null;
+
+            return valueOf(text.toUpperCase());
         }
 
-        return plugin.getBeanDefinition();
+        public String getTemplateName() {
+            return name().toLowerCase() + "CommandTemplate";
+        }
+
+        public void wire(final BeanDefinitionBuilder command, final BeanDefinitionHolder action) {
+            assert command != null;
+            assert action != null;
+
+            switch (this) {
+                case STATELESS:
+                    command.addPropertyReference("action", action.getBeanName());
+                    break;
+
+                case STATEFUL:
+                    command.addPropertyValue("actionId", action.getBeanName());
+                    break;
+            }
+        }
     }
 
-    private void parseCommandBundles(final BeanDefinitionBuilder plugin, final List<Element> elements) {
-        assert elements != null;
-        assert plugin != null;
+    /**
+     * Helper to build plugin related bean definitions.
+     */
+    private class Builder
+    {
+        private final Logger log = LoggerFactory.getLogger(getClass());
+
+        private ParserContext context;
+
+        public Builder(final ParserContext context) {
+            assert context != null;
+
+            this.context = context;
+        }
+
+        private String resolveId(final Element element, final BeanDefinition def) throws BeanDefinitionStoreException {
+            assert element != null;
+            assert def != null;
+
+            if (shouldGenerateId()) {
+                return context.getReaderContext().generateBeanName(def);
+            }
+
+            String id = element.getAttribute(ID_ATTRIBUTE);
+
+            if (!StringUtils.hasText(id) && shouldGenerateIdAsFallback()) {
+                id = context.getReaderContext().generateBeanName(def);
+            }
+
+            return id;
+        }
+
+        @SuppressWarnings({"unchecked"})
+        private List<Element> getChildElements(final Element element, final String name) {
+            assert element != null;
+            assert name != null;
+
+            return DomUtils.getChildElementsByTagName(element, name);
+        }
+
+        @SuppressWarnings({"unchecked"})
+        private Element getChildElement(final Element element, final String name) {
+            assert element != null;
+            assert name != null;
+
+            List<Element> elements = DomUtils.getChildElementsByTagName(element, name);
+            if (elements != null && !elements.isEmpty()) {
+                return elements.get(0);
+            }
+            return null;
+        }
+
+        private BeanDefinitionHolder parseBeanDefinitionElement(final Element element) {
+            assert element != null;
+
+            BeanDefinitionParserDelegate parser = new BeanDefinitionParserDelegate(context.getReaderContext());
+            parser.initDefaults(element.getOwnerDocument().getDocumentElement());
+            return parser.parseBeanDefinitionElement(element);
+        }
+
+        private BeanDefinitionHolder register(final BeanDefinitionHolder holder) {
+            assert holder != null;
+
+            registerBeanDefinition(holder, context.getRegistry());
+            return holder;
+        }
+
+        private BeanDefinitionHolder register(final BeanDefinition def, final String id) {
+            assert def != null;
+            assert id != null;
+
+            BeanDefinitionHolder holder = new BeanDefinitionHolder(def, id);
+            return register(holder);
+        }
+
+        public BeanDefinitionBuilder buildPlugin(final Element element) {
+            assert element != null;
+
+            BeanDefinitionBuilder plugin = parsePlugin(element);
+
+            List<BeanDefinitionHolder> bundles = parseCommandBundles(element);
+
+            for (BeanDefinitionHolder holder : bundles) {
+                // TODO: Handle registration of the bundles?
+            }
 
+            return plugin;
+        }
+
+        private BeanDefinitionBuilder parsePlugin(final Element element) {
+            assert element != null;
+
+            log.info("Parse plugin; element: {}", element);
+
+            BeanDefinitionBuilder plugin = BeanDefinitionBuilder.rootBeanDefinition(PluginImpl.class);
+            plugin.addPropertyValue("id", element.getAttribute("name"));
+
+            return plugin;
+        }
+
+        private List<BeanDefinitionHolder> parseCommandBundles(final Element element) {
+            assert element != null;
+
+            log.info("Parse command bundles; element: {}", element);
+
+            List<Element> children = getChildElements(element, "command-bundle");
+            List<BeanDefinitionHolder> holders = new ArrayList<BeanDefinitionHolder>();
+
+            for (Element child : children) {
+                BeanDefinitionBuilder bundle = parseCommandBundle(child);
+
+                // Generate id and register the bean
+                AbstractBeanDefinition def = bundle.getBeanDefinition();
+                String id = resolveId(child, def);
+                BeanDefinitionHolder holder = register(def, id);
+
+                // noinspection unchecked
+                holders.add(holder);
+            }
+
+            return holders;
+        }
+
+        private BeanDefinitionBuilder parseCommandBundle(final Element element) {
+            assert element != null;
+
+            log.info("Parse command bundle; element; {}", element);
+
+            BeanDefinitionBuilder bundle = BeanDefinitionBuilder.rootBeanDefinition(CommandBundle.class);
+            bundle.addPropertyValue("id", element.getAttribute("name"));
+            bundle.setLazyInit(true);
+
+            List commands = parseCommands(element);
+            bundle.addPropertyValue("commands", commands);
+            
+            return bundle;
+        }
+
+        private List parseCommands(final Element element) {
+            assert element != null;
+
+            log.info("Parse commands; element; {}", element);
+
+            List<Element> children = getChildElements(element, "command");
+            ManagedList defs = new ManagedList();
 
+            for (Element child : children) {
+                BeanDefinitionBuilder command = parseCommand(child);
+
+                // noinspection unchecked
+                defs.add(command.getBeanDefinition());
+            }
+
+            return defs;
+        }
+
+        private BeanDefinitionBuilder parseCommand(final Element element) {
+            assert element != null;
+
+            log.info("Parse command; element; {}", element);
+
+            CommandType type = CommandType.parse(element.getAttribute("type"));
+            BeanDefinitionBuilder command = BeanDefinitionBuilder.childBeanDefinition(type.getTemplateName());
+
+            // TODO: Currently name is pulled from the documentor, need to change that
+            // command.addPropertyValue("name", element.getAttribute("name"));
+
+            BeanDefinitionHolder action = parseCommandAction(element);
+
+            // Wire up the action based on the type
+            type.wire(command, action);
+
+            return command;
+        }
+
+        private BeanDefinitionHolder parseCommandAction(final Element element) {
+            assert element != null;
+
+            log.info("Parse command action; element; {}", element);
+
+            Attr actionAttr = element.getAttributeNode("action");
+            Element actionElement = getChildElement(element, "action");
+
+            // Validate that we only have one action
+            if (actionAttr != null && actionElement != null) {
+                throw new RuntimeException("Must specify only one action attribute or action element");
+            }
+            if (actionAttr == null && actionElement == null) {
+                throw new RuntimeException("Missing action attribute or action element");
+            }
+
+            // Construct the action
+            BeanDefinition action;
+
+            if (actionAttr != null) {
+                action = BeanDefinitionBuilder.rootBeanDefinition(actionAttr.getValue()).getBeanDefinition();
+            }
+            else {
+                // TODO: Can probably just treat the "action" element as a "bean" element?
+                
+                Attr classAttr = actionElement.getAttributeNode("class");
+                Element beanElement = getChildElement(actionElement, "bean");
+
+                // Validate we only have one configuration for the action
+                if (classAttr != null && beanElement != null) {
+                    throw new RuntimeException("Must specify only one class attribute or bean element");
+                }
+                if (classAttr == null && beanElement == null) {
+                    throw new RuntimeException("Missing action class attribute or action bean element");
+                }
+
+                if (classAttr != null) {
+                    action = BeanDefinitionBuilder.rootBeanDefinition(classAttr.getValue()).getBeanDefinition();
+                }
+                else {
+                    action = parseBeanDefinitionElement(beanElement).getBeanDefinition();
+                }
+            }
+
+            // All actions are configured as prototypes
+            action.setScope("prototype");
+
+            // Generate id and register the bean
+            String id = resolveId(element, action);
+            return register(action, id);
+        }
     }
 }
\ No newline at end of file

Modified: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/main/resources/org/apache/geronimo/gshell/wisdom/config/wisdom-gshell.xsd
URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/main/resources/org/apache/geronimo/gshell/wisdom/config/wisdom-gshell.xsd?rev=698648&r1=698647&r2=698648&view=diff
==============================================================================
--- geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/main/resources/org/apache/geronimo/gshell/wisdom/config/wisdom-gshell.xsd (original)
+++ geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/main/resources/org/apache/geronimo/gshell/wisdom/config/wisdom-gshell.xsd Wed Sep 24 09:53:26 2008
@@ -28,11 +28,11 @@
         attributeFormDefault="unqualified">
 
     <xsd:import namespace="http://www.springframework.org/schema/beans"/>
-
+    
     <xsd:annotation>
-        <xsd:documentation><![CDATA[
+        <xsd:documentation>
             Defines the configuration elements for GShell Wisdom application context support.
-        ]]></xsd:documentation>
+        </xsd:documentation>
     </xsd:annotation>
 
     <xsd:element name="plugin">
@@ -74,7 +74,7 @@
                 <xsd:element ref="action" minOccurs="0" maxOccurs="1"/>
             </xsd:sequence>
             <xsd:attribute name="name" type="xsd:string" use="required"/>
-            <xsd:attribute name="type" type="xsd:string" use="optional" default="stateful">
+            <xsd:attribute name="type" use="optional" default="stateful">
                 <xsd:annotation>
                     <xsd:documentation>
                         The command type.
@@ -98,9 +98,9 @@
                     Defines a command action.
                 </xsd:documentation>
             </xsd:annotation>
-            <!--
-            TODO: Allow nested beans:bean
-            -->
+            <xsd:sequence>
+                <xsd:element ref="beans:bean" minOccurs="0" maxOccurs="1"/>
+            </xsd:sequence>
             <xsd:attribute name="class" type="xsd:string" use="optional"/>
         </xsd:complexType>
     </xsd:element>

Added: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/DummyAction.java
URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/DummyAction.java?rev=698648&view=auto
==============================================================================
--- geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/DummyAction.java (added)
+++ geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/DummyAction.java Wed Sep 24 09:53:26 2008
@@ -0,0 +1,49 @@
+/*
+ * 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.geronimo.gshell.wisdom.config;
+
+import org.apache.geronimo.gshell.spring.LoggingProcessor;
+import org.apache.geronimo.gshell.spring.SpringTestSupport;
+import org.apache.geronimo.gshell.command.CommandAction;
+import org.apache.geronimo.gshell.command.CommandContext;
+import org.apache.geronimo.gshell.notification.Notification;
+
+/**
+ * ???
+ *
+ * @version $Rev$ $Date$
+ */
+public class DummyAction
+    implements CommandAction
+{
+    private String text;
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public Object execute(CommandContext context) throws Notification, Exception {
+        return null;
+    }
+}
\ No newline at end of file

Propchange: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/DummyAction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/DummyAction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/DummyAction.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/PluginParserTest.java
URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/PluginParserTest.java?rev=698648&view=auto
==============================================================================
--- geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/PluginParserTest.java (added)
+++ geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/java/org/apache/geronimo/gshell/wisdom/config/PluginParserTest.java Wed Sep 24 09:53:26 2008
@@ -0,0 +1,40 @@
+/*
+ * 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.geronimo.gshell.wisdom.config;
+
+import org.apache.geronimo.gshell.spring.LoggingProcessor;
+import org.apache.geronimo.gshell.spring.SpringTestSupport;
+
+/**
+ * Unit tests for the {@link LoggingProcessor} class.
+ *
+ * @version $Rev: 698145 $ $Date: 2008-09-23 18:39:31 +0700 (Tue, 23 Sep 2008) $
+ */
+public class PluginParserTest
+    extends SpringTestSupport
+{
+    public void testParser() throws Exception {
+        LoggingProcessor processor = new LoggingProcessor();
+        String xml = processor.render(applicationContext.getBeanFactory());
+        assertNotNull(xml);
+
+        System.out.println("XML:\n" + xml);
+    }
+}
\ No newline at end of file

Added: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/resources/org/apache/geronimo/gshell/wisdom/config/PluginParserTest-context.xml
URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/resources/org/apache/geronimo/gshell/wisdom/config/PluginParserTest-context.xml?rev=698648&view=auto
==============================================================================
--- geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/resources/org/apache/geronimo/gshell/wisdom/config/PluginParserTest-context.xml (added)
+++ geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/resources/org/apache/geronimo/gshell/wisdom/config/PluginParserTest-context.xml Wed Sep 24 09:53:26 2008
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+
+<!-- $Rev$ $Date$ -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:gshell="http://gshell.org/schema/wisdom-gshell"
+       xsi:schemaLocation="
+            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+            http://gshell.org/schema/wisdom-gshell http://gshell.org/schema/wisdom-gshell/wisdom-gshell.xsd">
+
+    <gshell:plugin name="test-plugin">
+        <gshell:command-bundle name="test">
+            <gshell:command name="a" action="org.apache.geronimo.gshell.commands.SomeAction"/>
+
+            <gshell:command name="b" type="stateless" action="org.apache.geronimo.gshell.commands.SomeAction"/>
+
+            <gshell:command name="c" type="stateful" action="org.apache.geronimo.gshell.commands.SomeAction"/>
+
+            <gshell:command name="d">
+                <gshell:action>
+                    <bean class="org.apache.geronimo.gshell.wisdom.config.DummyAction">
+                        <property name="text" value="b"/>
+                    </bean>
+                </gshell:action>
+            </gshell:command>
+
+            <gshell:command name="e">
+                <gshell:action class="org.apache.geronimo.gshell.wisdom.config.DummyAction"/>
+            </gshell:command>
+        </gshell:command-bundle>
+    </gshell:plugin>
+
+</beans>
\ No newline at end of file

Propchange: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/resources/org/apache/geronimo/gshell/wisdom/config/PluginParserTest-context.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/resources/org/apache/geronimo/gshell/wisdom/config/PluginParserTest-context.xml
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: geronimo/gshell/trunk/gshell-wisdom/gshell-wisdom-core/src/test/resources/org/apache/geronimo/gshell/wisdom/config/PluginParserTest-context.xml
------------------------------------------------------------------------------
    svn:mime-type = text/xml