class JcrNamespaceRegistry implements org.modeshape.jcr.api.NamespaceRegistry {

    @Override
    public synchronized void registerNamespace( String prefix,
                                                String uri ) throws NamespaceException, RepositoryException {
        CheckArg.isNotNull(prefix, "prefix");
        CheckArg.isNotNull(uri, "uri");
        checkSession();

        // Check the zero-length prefix and zero-length URI ...
        if (DEFAULT_NAMESPACE_PREFIX.equals(prefix) || DEFAULT_NAMESPACE_URI.equals(uri)) {
            throw new NamespaceException(JcrI18n.unableToChangeTheDefaultNamespace.text());
        }

        // Check whether the prefix begins with 'xml' (in any case) ...
        if (prefix.toLowerCase().startsWith(XML_NAMESPACE_PREFIX)) {
            throw new NamespaceException(JcrI18n.unableToRegisterNamespaceUsingXmlPrefix.text(prefix, uri));
        }

        // The prefix must be a valid XML Namespace prefix (i.e., a valid NCName) ...
        if (!XmlCharacters.isValidNcName(prefix)) {
            throw new NamespaceException(JcrI18n.unableToRegisterNamespaceWithInvalidPrefix.text(prefix, uri));
        }

        // The prefix must also be a valid JCR name ...
        try {
            session.nameFactory().create(prefix);
        } catch (ValueFormatException e) {
            throw new NamespaceException(JcrI18n.unableToRegisterNamespaceWithInvalidPrefix.text(prefix, uri));
        }

        String existingPrefixForURI = registry.getPrefixForNamespaceUri(uri, false);
        if (prefix.equals(existingPrefixForURI)) {
            //this is a no-op because we're trying to register the URI under the same prefix
            return;
        }

        boolean global = false;
        switch (behavior) {
            case SESSION:
                // --------------------------------------
                // JSR-283 Session remapping behavior ...
                // --------------------------------------
                // Section 5.11:
                // "All local mappings already present in the Session that include either the specified prefix
                // or the specified uri are removed and the new mapping is added."
                String existingUriForPrefix = registry.getNamespaceForPrefix(prefix);
                if (existingUriForPrefix != null) {
                    registry.unregister(existingUriForPrefix);
                }
                registry.unregister(uri);

                break;
            case WORKSPACE:
                // --------------------------------------------------
                // JSR-170 & JSR-283 Workspace namespace registry ...
                // --------------------------------------------------
                global = true;
                // Check whether the prefix or URI are reserved (case-sensitive) ...
                if (STANDARD_BUILT_IN_PREFIXES.contains(prefix)) {
                    throw new NamespaceException(JcrI18n.unableToRegisterReservedNamespacePrefix.text(prefix, uri));
                }
                if (STANDARD_BUILT_IN_URIS.contains(uri)) {
                    throw new NamespaceException(JcrI18n.unableToRegisterReservedNamespaceUri.text(prefix, uri));
                }

                try {
                    session.checkWorkspacePermission(session.workspaceName(), ModeShapePermissions.REGISTER_NAMESPACE);
                } catch (AccessControlException ace) {
                    throw new AccessDeniedException(ace);
                }

                if (existingPrefixForURI != null) {
                    //the uri is already mapped under a different prefix so check that it's not in use
                    checkURINotInUse(uri);
                }
                registry.unregister(uri);
                break;
            default:
                assert false; // should never happen
        }

        // Now we're sure the prefix and URI are valid and okay for a custom mapping ...
        try {
            registry.register(prefix, uri);
            // Signal the local node type manager ...
            session.signalNamespaceChanges(global);
        } catch (RuntimeException e) {
            throw new RepositoryException(e.getMessage(), e.getCause());
        }
    }

    protected  JcrNamespaceRegistry( NamespaceRegistry workspaceRegistry,
                                    JcrSession session );
      JcrNamespaceRegistry( Behavior behavior,
                          NamespaceRegistry localRegistry,
                          NamespaceRegistry workspaceRegistry,
                          JcrSession session );

}