You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2007/01/08 23:09:02 UTC

svn commit: r494219 - in /jackrabbit/trunk/jackrabbit-jcr-commons/src: main/java/org/apache/jackrabbit/name/ test/java/org/apache/jackrabbit/name/

Author: jukka
Date: Mon Jan  8 14:09:02 2007
New Revision: 494219

URL: http://svn.apache.org/viewvc?view=rev&rev=494219
Log:
JCR-688: Added the NameResolver interface, default implementation classes, and some tests.

Added:
    jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/CachingNameResolver.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/NameResolver.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/ParsingNameResolver.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/DummyNamespaceResolver.java   (with props)
    jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/ParsingNameResolverTest.java   (with props)

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/CachingNameResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/CachingNameResolver.java?view=auto&rev=494219
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/CachingNameResolver.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/CachingNameResolver.java Mon Jan  8 14:09:02 2007
@@ -0,0 +1,212 @@
+/*
+ * 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.name;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.jcr.NamespaceException;
+
+/**
+ * Name resolver decorator that uses a generational cache to speed up
+ * parsing and formatting of JCR names. Uncached names are resolved using
+ * the underlying decorated name resolver.
+ * <p>
+ * The cache consists of three parts: a long term cache and two generations
+ * of recent cache entries. The two generations are used to collect recent new
+ * entries, and those entries that are used within two successive generations
+ * get promoted to the long term cache. The entries within the long term cache
+ * are discarded only when the size of the cache exceeds the given maximum
+ * cache size.
+ */
+public class CachingNameResolver implements NameResolver {
+
+    /**
+     * Default maximum cache size.
+     */
+    private static final int DEFAULT_CACHE_SIZE = 1000;
+
+    /**
+     * Divisor used to determine the default generation age from the
+     * maximum cache size.
+     */
+    private static final int DEFAULT_SIZE_AGE_RATIO = 10;
+
+    /**
+     * Decorated name resolver.
+     */
+    private final NameResolver resolver;
+
+    /**
+     * Maximum size of the name cache.
+     */
+    private final int maxSize;
+
+    /**
+     * Maximum age of a cache generation.
+     */
+    private final int maxAge;
+
+    /**
+     * Long term name cache. Read only.
+     */
+    private Map cache = new HashMap();
+
+    /**
+     * Old cache generation. Read only.
+     */
+    private Map old = new HashMap();
+
+    /**
+     * Young cache generation. Write only.
+     */
+    private Map young = new HashMap();
+
+    /**
+     * Age of the young cache generation.
+     */
+    private int age = 0;
+
+    /**
+     * Creates a caching name resolver.
+     *
+     * @param resolver decorated name resolver
+     * @param maxSize maximum size of the long term cache
+     * @param maxAge maximum age of a cache generation
+     */
+    public CachingNameResolver(NameResolver resolver, int maxSize, int maxAge) {
+        this.resolver = resolver;
+        this.maxSize = maxSize;
+        this.maxAge = maxAge;
+    }
+
+    /**
+     * Creates a caching name resolver using the default generation age for
+     * the given cache size.
+     *
+     * @param resolver decorated name resolver
+     * @param maxSize maximum size of the long term cache
+     */
+    public CachingNameResolver(NameResolver resolver, int maxSize) {
+        this(resolver, maxSize, maxSize / DEFAULT_SIZE_AGE_RATIO);
+    }
+
+    /**
+     * Creates a caching name resolver using the default size and
+     * generation age.
+     *
+     * @param resolver decorated name resolver
+     */
+    public CachingNameResolver(NameResolver resolver) {
+        this(resolver, DEFAULT_CACHE_SIZE);
+    }
+
+    /**
+     * Caches the given key-value pair and increases the age of the current
+     * cache generation. When the maximum age of a generation is reached,
+     * the following steps are taken:
+     * <ol>
+     *   <li>The union of the two cache generations is calculated</li>
+     *   <li>The union is added to the long term name cache</li>
+     *   <li>If the cache size exceeds the maximum, only the union is kept</li>
+     *   <li>A new cache generation is started</li>
+     * </ol>
+     *
+     * @param key key of the cache entry
+     * @param value value of the cache entry
+     */
+    private synchronized void cache(Object key, Object value) {
+        young.put(key, value);
+
+        if (++age == maxAge) {
+            Map union = new HashMap();
+            Iterator iterator = old.entrySet().iterator();
+            while (iterator.hasNext()) {
+                Map.Entry entry = (Map.Entry) iterator.next();
+                if (young.containsKey(entry.getKey())) {
+                    union.put(entry.getKey(), entry.getValue());
+                }
+            }
+
+            if (!union.isEmpty()) {
+                if (cache.size() + union.size() <= maxSize) {
+                    union.putAll(cache);
+                }
+                cache = union;
+            }
+
+            old = young;
+            young = new HashMap();
+            age = 0;
+        }
+    }
+
+    //--------------------------------------------------------< NameResolver >
+
+    /**
+     * Returns the qualified name for the given prefixed JCR name. The name
+     * is first looked up form the generational cache and the call gets
+     * delegated to the decorated name resolver only if the cache misses.
+     *
+     * @param name prefixed JCR name
+     * @return qualified name
+     * @throws NameException if the JCR name format is invalid
+     * @throws NamespaceException if the namespace prefix can not be resolved
+     */
+    public QName getQName(String name)
+            throws NameException, NamespaceException {
+        QName qname = (QName) cache.get(name);
+        if (qname == null) {
+            qname = (QName) old.get(name);
+            if (qname == null) {
+                qname = resolver.getQName(name);
+            }
+            cache(name, qname);
+        }
+        return qname;
+    }
+
+
+    /**
+     * Returns the prefixed JCR name for the given qualified name.
+     * If the name is in the default namespace, then the local name
+     * is returned without a prefix. Otherwise the name is first looked
+     * up form the generational cache and the call gets delegated to the
+     * decorated name resolver only if the cache misses.
+     *
+     * @param qname qualified name
+     * @return prefixed JCR name
+     * @throws NamespaceException if the namespace URI can not be resolved
+     */
+    public String getJCRName(QName qname) throws NamespaceException {
+        if (qname.getNamespaceURI().length() == 0) {
+            return qname.getLocalName();
+        }
+
+        String name = (String) cache.get(qname);
+        if (name == null) {
+            name = (String) old.get(qname);
+            if (name == null) {
+                name = resolver.getJCRName(qname);
+            }
+            cache(qname, name);
+        }
+        return name;
+    }
+
+}

Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/CachingNameResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/NameResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/NameResolver.java?view=auto&rev=494219
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/NameResolver.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/NameResolver.java Mon Jan  8 14:09:02 2007
@@ -0,0 +1,46 @@
+/*
+ * 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.name;
+
+import javax.jcr.NamespaceException;
+
+/**
+ * Resolver for prefixed JCR names and namespace-qualified
+ * {@link QName QNames}.
+ */
+public interface NameResolver {
+
+    /**
+     * Returns the qualified name for the given prefixed JCR name.
+     *
+     * @param name prefixed JCR name
+     * @return qualified name
+     * @throws NameException if the JCR name format is invalid
+     * @throws NamespaceException if the namespace prefix can not be resolved
+     */
+    QName getQName(String name) throws NameException, NamespaceException;
+
+    /**
+     * Returns the prefixed JCR name for the given qualified name.
+     *
+     * @param name qualified name
+     * @return prefixed JCR name
+     * @throws NamespaceException if the namespace URI can not be resolved
+     */
+    String getJCRName(QName name) throws NamespaceException;
+
+}

Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/NameResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/ParsingNameResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/ParsingNameResolver.java?view=auto&rev=494219
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/ParsingNameResolver.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/ParsingNameResolver.java Mon Jan  8 14:09:02 2007
@@ -0,0 +1,154 @@
+/*
+ * 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.name;
+
+import javax.jcr.NamespaceException;
+import javax.jcr.Session;
+
+/**
+ * Name resolver that parsers and formats prefixed JCR names.
+ * A {@link NamespaceResolver} is used for resolving the namespace prefixes.
+ */
+public class ParsingNameResolver implements NameResolver {
+
+    /**
+     * Set of invalid or potentially invalid name characters.
+     * Organized as a boolean array indexed by the ASCII character
+     * code for maximum lookup performance.
+     */
+    private static final boolean[] MAYBE_INVALID = new boolean[128];
+
+    /**
+     * Initializes the set of invalid or potentially invalid name characters.
+     */
+    static {
+        for (char ch = 0; ch < MAYBE_INVALID.length; ch++) {
+            MAYBE_INVALID[ch] = Character.isSpaceChar(ch);
+        }
+        MAYBE_INVALID['.'] = true;
+        MAYBE_INVALID[':'] = true;
+        MAYBE_INVALID['/'] = true;
+        MAYBE_INVALID['['] = true;
+        MAYBE_INVALID[']'] = true;
+        MAYBE_INVALID['*'] = true;
+        MAYBE_INVALID['|'] = true;
+        MAYBE_INVALID['"'] = true;
+        MAYBE_INVALID['\''] = true;
+    }
+
+    /**
+     * Checks whether the given character is an invalid or potentially an
+     * invalid name character.
+     *
+     * @param ch character
+     * @return <code>true</code> if the character maybe is invalid in a name,
+     *         <code>false</code> if it is valid in any place within a name
+     */
+    private static boolean maybeInvalid(char ch) {
+        if (ch < MAYBE_INVALID.length) {
+            return MAYBE_INVALID[ch];
+        } else {
+            return Character.isSpaceChar(ch);
+        }
+    }
+
+    /**
+     * Namespace resolver.
+     */
+    private final NamespaceResolver resolver;
+
+    /**
+     * Creates a parsing name resolver.
+     *
+     * @param resolver namespace resolver
+     */
+    public ParsingNameResolver(NamespaceResolver resolver) {
+        this.resolver = resolver;
+    }
+
+    /**
+     * Creates a parsing name resolver for a JCR session.
+     *
+     * @param session JCR session
+     */
+    public ParsingNameResolver(Session session) {
+        this(new SessionNamespaceResolver(session));
+    }
+
+    //--------------------------------------------------------< NameResolver >
+
+    /**
+     * Parses the prefixed JCR name and returns the resolved qualified name.
+     *
+     * @param name prefixed JCR name
+     * @return qualified name
+     * @throws NameException if the JCR name format is invalid
+     * @throws NamespaceException if the namespace prefix can not be resolved
+     */
+    public QName getQName(String name)
+            throws NameException, NamespaceException {
+        int length = name.length();
+        int colon = -1;
+
+        for (int i = 0; i < length; i++) {
+            char ch = name.charAt(i);
+            if (maybeInvalid(ch)) {
+                if (ch == ':' && colon == -1 && 0 < i && i + 1 < length) {
+                    colon = i; // Detect the position of the first colon
+                } else if (ch == ' ' && colon + 1 < i && i + 1 < length) {
+                    // Allow spaces in the middle of the local name
+                } else if (ch == '.'
+                           && (i > 0 || length > 2
+                               || (length == 2 && name.charAt(1) != '.'))) {
+                    // Allow dots when the name is not "." or ".."
+                } else {
+                    throw new IllegalNameException("Invalid name: " + name);
+                }
+            }
+        }
+
+        if (length == 0) {
+            throw new IllegalNameException("Empty name");
+        } else if (colon == -1) {
+            return new QName(QName.NS_DEFAULT_URI, name);
+        } else {
+            // Resolve the prefix (and validate the prefix format!)
+            String uri = resolver.getURI(name.substring(0, colon));
+            return new QName(uri, name.substring(colon + 1));
+        }
+    }
+
+    /**
+     * Returns the prefixed JCR name for the given qualified name.
+     * If the name is in the default namespace, then the local name
+     * is returned without a prefix. Otherwise the prefix for the
+     * namespace is resolved and used to construct returned the JCR name.
+     *
+     * @param name qualified name
+     * @return prefixed JCR name
+     * @throws NamespaceException if the namespace URI can not be resolved
+     */
+    public String getJCRName(QName name) throws NamespaceException {
+        String uri = name.getNamespaceURI();
+        if (uri.length() == 0) {
+            return name.getLocalName();
+        } else {
+            return resolver.getPrefix(uri) + ":" + name.getLocalName();
+        }
+    }
+
+}

Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/name/ParsingNameResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/DummyNamespaceResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/DummyNamespaceResolver.java?view=auto&rev=494219
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/DummyNamespaceResolver.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/DummyNamespaceResolver.java Mon Jan  8 14:09:02 2007
@@ -0,0 +1,78 @@
+/*
+ * 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.name;
+
+import javax.jcr.NamespaceException;
+
+import org.apache.jackrabbit.util.XMLChar;
+
+/**
+ * Dummy namespace resolver for use in unit testing. This namespace resolver
+ * maps each valid XML prefix string to the same string as the namespace URI
+ * and vice versa.
+ */
+class DummyNamespaceResolver implements NamespaceResolver {
+
+    /**
+     * Returns the given prefix as the corresponding namespace URI after
+     * validating the correct format of the prefix.
+     *
+     * @param prefix namespace prefix
+     * @return the given prefix
+     * @throws NamespaceException if the given prefix is not a valid XML prefix
+     */
+    public String getURI(String prefix) throws NamespaceException {
+        if (XMLChar.isValidNCName(prefix)) {
+            return prefix;
+        } else {
+            throw new NamespaceException("Invalid prefix: " + prefix);
+        }
+    }
+
+    /**
+     * Returns the given namespace URI as the corresponding prefix.
+     *
+     * @param uri namespace URI
+     * @return the given URI
+     */
+    public String getPrefix(String uri) {
+        return uri;
+    }
+
+    /**
+     * Not implemented.
+     *
+     * @param qName ignored
+     * @return nothing
+     * @throws UnsupportedOperationException always thrown
+     */
+    public String getJCRName(QName qName) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Not implemented.
+     *
+     * @param jcrName ignored
+     * @return nothing
+     * @throws UnsupportedOperationException always thrown
+     */
+    public QName getQName(String jcrName) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+}

Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/DummyNamespaceResolver.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/ParsingNameResolverTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/ParsingNameResolverTest.java?view=auto&rev=494219
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/ParsingNameResolverTest.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/ParsingNameResolverTest.java Mon Jan  8 14:09:02 2007
@@ -0,0 +1,106 @@
+/*
+ * 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.name;
+
+import javax.jcr.NamespaceException;
+
+
+import junit.framework.TestCase;
+
+/**
+ * Test cases for the {@link ParsingNameResolver} class.
+ */
+public class ParsingNameResolverTest extends TestCase {
+
+    /**
+     * Name resolver being tested.
+     */
+    private NameResolver resolver =
+        new ParsingNameResolver(new DummyNamespaceResolver());
+
+    /**
+     * Checks that the given name resolves to the given namespace URI and
+     * local part.
+     *
+     * @param name JCR name
+     * @param uri namespace URI
+     * @param local local part
+     */
+    private void assertValidName(String name, String uri, String local) {
+        try {
+            QName qname = resolver.getQName(name);
+            assertEquals(name, uri, qname.getNamespaceURI());
+            assertEquals(name, local, qname.getLocalName());
+            assertEquals(name, name, resolver.getJCRName(qname));
+        } catch (NameException e) {
+            fail(name);
+        } catch (NamespaceException e) {
+            fail(name);
+        }
+    }
+
+    /**
+     * Tests that valid names are properly resolved.
+     */
+    public void testValidNames() {
+        assertValidName("x", "", "x");
+        assertValidName("name", "", "name");
+        assertValidName("space name", "", "space name");
+        assertValidName("x:y", "x", "y");
+        assertValidName("prefix:name", "prefix", "name");
+        assertValidName("prefix:space name", "prefix", "space name");
+    }
+
+    /**
+     * Checks that the given name fails to resolve.
+     *
+     * @param name JCR name
+     */
+    private void assertInvalidName(String name) {
+        try {
+            resolver.getQName(name);
+            fail(name);
+        } catch (NameException e) {
+        } catch (NamespaceException e) {
+        }
+    }
+
+    /**
+     * Tests that resolution of invalid names fails.
+     */
+    public void testInvalidNames() {
+        assertInvalidName("");
+        assertInvalidName(":name");
+        assertInvalidName(".");
+        assertInvalidName("..");
+        assertInvalidName("pre:");
+        assertInvalidName(" name");
+        assertInvalidName(" prefix: name");
+        assertInvalidName("prefix: name");
+        assertInvalidName("prefix:name ");
+        assertInvalidName("pre fix:name");
+        assertInvalidName("prefix :name");
+        assertInvalidName("name/name");
+        assertInvalidName("name[]");
+        assertInvalidName("name[1]");
+        assertInvalidName("name[name");
+        assertInvalidName("name]name");
+        assertInvalidName("name*name");
+        assertInvalidName("prefix:name:name");
+    }
+
+}

Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/name/ParsingNameResolverTest.java
------------------------------------------------------------------------------
    svn:eol-style = native