Package org.apache.jackrabbit.core.nodetype

Source Code of org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl

/*
* 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.nodetype;

import org.apache.commons.collections.map.ReferenceMap;
import org.apache.jackrabbit.name.IllegalNameException;
import org.apache.jackrabbit.name.NameException;
import org.apache.jackrabbit.name.NamespaceResolver;
import org.apache.jackrabbit.name.QName;
import org.apache.jackrabbit.name.UnknownPrefixException;
import org.apache.jackrabbit.name.NameFormat;
import org.apache.jackrabbit.util.IteratorHelper;
import org.apache.jackrabbit.util.name.NamespaceMapping;
import org.apache.jackrabbit.api.JackrabbitNodeTypeManager;
import org.apache.jackrabbit.core.NamespaceRegistryImpl;
import org.apache.jackrabbit.core.nodetype.compact.CompactNodeTypeDefReader;
import org.apache.jackrabbit.core.nodetype.compact.ParseException;
import org.apache.jackrabbit.core.nodetype.xml.NodeTypeReader;
import org.apache.jackrabbit.core.util.Dumpable;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeIterator;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
* A <code>NodeTypeManagerImpl</code> implements a session dependant
* NodeTypeManager.
*/
public class NodeTypeManagerImpl implements JackrabbitNodeTypeManager,
        Dumpable, NodeTypeRegistryListener {

    /**
     * The wrapped node type registry.
     */
    private final NodeTypeRegistry ntReg;

    /**
     * The persistent namespace registry where any new namespaces are
     * automatically registered when new node type definition files are
     * read.
     */
    private final NamespaceRegistryImpl nsReg;

    /**
     * The root node definition.
     */
    private final NodeDefinitionImpl rootNodeDef;

    /**
     * The namespace resolver used to translate qualified names to JCR names.
     */
    private final NamespaceResolver nsResolver;

    /**
     * A cache for <code>NodeType</code> instances created by this
     * <code>NodeTypeManager</code>
     */
    private final Map ntCache;

    /**
     * A cache for <code>PropertyDefinition</code> instances created by this
     * <code>NodeTypeManager</code>
     */
    private final Map pdCache;

    /**
     * A cache for <code>NodeDefinition</code> instances created by this
     * <code>NodeTypeManager</code>
     */
    private final Map ndCache;

    /**
     * Creates a new <code>NodeTypeManagerImpl</code> instance.
     *
     * @param ntReg      node type registry
     * @param nsReg      namespace registry
     * @param nsResolver namespace resolver
     */
    public NodeTypeManagerImpl(
            NodeTypeRegistry ntReg, NamespaceRegistryImpl nsReg,
            NamespaceResolver nsResolver) {
        this.nsResolver = nsResolver;
        this.ntReg = ntReg;
        this.nsReg = nsReg;
        this.ntReg.addListener(this);

        // setup caches with soft references to node type
        // & item definition instances
        ntCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);
        pdCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);
        ndCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);

        rootNodeDef = new NodeDefinitionImpl(ntReg.getRootNodeDef(), this,
                nsResolver);
        ndCache.put(rootNodeDef.unwrap().getId(), rootNodeDef);
    }

    /**
     * @return the root node definition
     */
    public NodeDefinitionImpl getRootNodeDefinition() {
        return rootNodeDef;
    }

    /**
     * @param id
     * @return the node definition
     */
    public NodeDefinitionImpl getNodeDefinition(NodeDefId id) {
        synchronized (ndCache) {
            NodeDefinitionImpl ndi = (NodeDefinitionImpl) ndCache.get(id);
            if (ndi == null) {
                NodeDef nd = ntReg.getNodeDef(id);
                if (nd != null) {
                    ndi = new NodeDefinitionImpl(nd, this, nsResolver);
                    ndCache.put(id, ndi);
                }
            }
            return ndi;
        }
    }

    /**
     * @param id
     * @return the property definition
     */
    public PropertyDefinitionImpl getPropertyDefinition(PropDefId id) {
        synchronized (pdCache) {
            PropertyDefinitionImpl pdi = (PropertyDefinitionImpl) pdCache.get(id);
            if (pdi == null) {
                PropDef pd = ntReg.getPropDef(id);
                if (pd != null) {
                    pdi = new PropertyDefinitionImpl(pd, this, nsResolver);
                    pdCache.put(id, pdi);
                }
            }
            return pdi;
        }
    }

    /**
     * @param name
     * @return
     * @throws NoSuchNodeTypeException
     */
    public NodeTypeImpl getNodeType(QName name) throws NoSuchNodeTypeException {
        synchronized (ntCache) {
            NodeTypeImpl nt = (NodeTypeImpl) ntCache.get(name);
            if (nt == null) {
                EffectiveNodeType ent = ntReg.getEffectiveNodeType(name);
                NodeTypeDef def = ntReg.getNodeTypeDef(name);
                nt = new NodeTypeImpl(ent, def, this, nsResolver);
                ntCache.put(name, nt);
            }
            return nt;
        }
    }

    /**
     * @return the node type registry
     */
    public NodeTypeRegistry getNodeTypeRegistry() {
        return ntReg;
    }

    /**
     * Registers the node types defined in the given input stream depending
     * on the content type specified for the stream. This will also register
     * any namespaces identified in the input stream if they have not already
     * been registered.
     *
     * @param in node type XML stream
     * @param contentType type of the input stream
     * @param reregisterExisting flag indicating whether node types should be
     *                           reregistered if they already exist
     * @return registered node types
     * @throws IOException if the input stream could not be read or parsed
     * @throws RepositoryException if the node types are invalid or another
     *                             repository error occurs
     */
    public NodeType[] registerNodeTypes(InputStream in, String contentType,
            boolean reregisterExisting)
            throws IOException, RepositoryException {

        try {
            Map namespaceMap = new HashMap();
            List nodeTypeDefs = new ArrayList();

            if (contentType.equalsIgnoreCase(TEXT_XML)
                    || contentType.equalsIgnoreCase(APPLICATION_XML)) {
                try {
                    NodeTypeReader ntr = new NodeTypeReader(in);

                    Properties namespaces = ntr.getNamespaces();
                    if (namespaces != null) {
                        Enumeration prefixes = namespaces.propertyNames();
                        while (prefixes.hasMoreElements()) {
                            String prefix = (String) prefixes.nextElement();
                            String uri = namespaces.getProperty(prefix);
                            namespaceMap.put(prefix, uri);
                        }
                    }

                    NodeTypeDef[] defs = ntr.getNodeTypeDefs();
                    nodeTypeDefs.addAll(Arrays.asList(defs));
                } catch (IllegalNameException e) {
                    throw new RepositoryException("Illegal JCR name syntax", e);
                } catch (UnknownPrefixException e) {
                    throw new RepositoryException("Unknown namespace prefix", e);
                }
            } else if (contentType.equalsIgnoreCase(TEXT_X_JCR_CND)) {
                try {
                    NamespaceMapping mapping = new NamespaceMapping(nsResolver);
                    CompactNodeTypeDefReader reader = new CompactNodeTypeDefReader(
                            new InputStreamReader(in), "cnd input stream", mapping);

                    namespaceMap.putAll(mapping.getPrefixToURIMapping());

                    nodeTypeDefs.addAll(reader.getNodeTypeDefs());
                } catch (ParseException e) {
                    throw new IOException(e.getMessage());
                }
            } else {
                throw new UnsupportedRepositoryOperationException(
                        "Unsupported content type: " + contentType);
            }

            Iterator iterator = namespaceMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                nsReg.safeRegisterNamespace((String) entry.getKey(),
                        (String) entry.getValue());
            }

            if (reregisterExisting) {
                // split the node types into new and already registered node types.
                // this way we can register new node types together with already
                // registered node types which make circular dependencies possible
                List newNodeTypeDefs = new ArrayList();
                List registeredNodeTypeDefs = new ArrayList();
                for (Iterator iter = nodeTypeDefs.iterator(); iter.hasNext();) {
                    NodeTypeDef nodeTypeDef = (NodeTypeDef) iter.next();
                    if (ntReg.isRegistered(nodeTypeDef.getName())) {
                        registeredNodeTypeDefs.add(nodeTypeDef);
                    } else {
                        newNodeTypeDefs.add(nodeTypeDef);
                    }
                }

                ArrayList nodeTypes = new ArrayList();

                // register new node types
                nodeTypes.addAll(Arrays.asList(registerNodeTypes(newNodeTypeDefs)));

                // reregister already existing node types
                for (Iterator iter = registeredNodeTypeDefs.iterator(); iter.hasNext();) {
                    NodeTypeDef nodeTypeDef = (NodeTypeDef) iter.next();
                    ntReg.reregisterNodeType(nodeTypeDef);
                    nodeTypes.add(getNodeType(nodeTypeDef.getName()));
                }
                return (NodeType[]) nodeTypes.toArray(new NodeTypeDef[nodeTypes.size()]);
            } else {
                return registerNodeTypes(nodeTypeDefs);
            }

        } catch (InvalidNodeTypeDefException e) {
            throw new RepositoryException("Invalid node type definition", e);
        }
    }

    //---------------------------------------------< NodeTypeRegistryListener >
    /**
     * {@inheritDoc}
     */
    public void nodeTypeRegistered(QName ntName) {
        // not interested, ignore
    }

    /**
     * {@inheritDoc}
     */
    public void nodeTypeReRegistered(QName ntName) {
        // flush all affected cache entries
        ntCache.remove(ntName);
        synchronized (pdCache) {
            Iterator iter = pdCache.values().iterator();
            while (iter.hasNext()) {
                PropertyDefinitionImpl pd = (PropertyDefinitionImpl) iter.next();
                if (ntName.equals(pd.unwrap().getDeclaringNodeType())) {
                    iter.remove();
                }
            }
        }
        synchronized (ndCache) {
            Iterator iter = ndCache.values().iterator();
            while (iter.hasNext()) {
                NodeDefinitionImpl nd = (NodeDefinitionImpl) iter.next();
                if (ntName.equals(nd.unwrap().getDeclaringNodeType())) {
                    iter.remove();
                }
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public void nodeTypeUnregistered(QName ntName) {
        // flush all affected cache entries
        ntCache.remove(ntName);
        synchronized (pdCache) {
            Iterator iter = pdCache.values().iterator();
            while (iter.hasNext()) {
                PropertyDefinitionImpl pd = (PropertyDefinitionImpl) iter.next();
                if (ntName.equals(pd.unwrap().getDeclaringNodeType())) {
                    iter.remove();
                }
            }
        }
        synchronized (ndCache) {
            Iterator iter = ndCache.values().iterator();
            while (iter.hasNext()) {
                NodeDefinitionImpl nd = (NodeDefinitionImpl) iter.next();
                if (ntName.equals(nd.unwrap().getDeclaringNodeType())) {
                    iter.remove();
                }
            }
        }
    }

    //------------------------------------------------------< NodeTypeManager >
    /**
     * {@inheritDoc}
     */
    public NodeTypeIterator getAllNodeTypes() throws RepositoryException {
        QName[] ntNames = ntReg.getRegisteredNodeTypes();
        ArrayList list = new ArrayList(ntNames.length);
        for (int i = 0; i < ntNames.length; i++) {
            list.add(getNodeType(ntNames[i]));
        }
        return new IteratorHelper(Collections.unmodifiableCollection(list));
    }

    /**
     * {@inheritDoc}
     */
    public NodeTypeIterator getPrimaryNodeTypes() throws RepositoryException {
        QName[] ntNames = ntReg.getRegisteredNodeTypes();
        ArrayList list = new ArrayList(ntNames.length);
        for (int i = 0; i < ntNames.length; i++) {
            NodeType nt = getNodeType(ntNames[i]);
            if (!nt.isMixin()) {
                list.add(nt);
            }
        }
        return new IteratorHelper(Collections.unmodifiableCollection(list));
    }

    /**
     * {@inheritDoc}
     */
    public NodeTypeIterator getMixinNodeTypes() throws RepositoryException {
        QName[] ntNames = ntReg.getRegisteredNodeTypes();
        ArrayList list = new ArrayList(ntNames.length);
        for (int i = 0; i < ntNames.length; i++) {
            NodeType nt = getNodeType(ntNames[i]);
            if (nt.isMixin()) {
                list.add(nt);
            }
        }
        return new IteratorHelper(Collections.unmodifiableCollection(list));
    }

    /**
     * {@inheritDoc}
     */
    public NodeType getNodeType(String nodeTypeName)
            throws NoSuchNodeTypeException {
        try {
            return getNodeType(NameFormat.parse(nodeTypeName, nsResolver));
        } catch (UnknownPrefixException upe) {
            throw new NoSuchNodeTypeException(nodeTypeName, upe);
        } catch (IllegalNameException ine) {
            throw new NoSuchNodeTypeException(nodeTypeName, ine);
        }
    }

    //--------------------------------------------< JackrabbitNodeTypeManager >

    /**
     * Internal helper method for registering a list of node type definitions.
     * Returns an array containing the registered node types.
     *
     * @param defs a collection of <code>NodeTypeDef<code> objects
     * @returns registered node types
     * @throws InvalidNodeTypeDefException
     * @throws RepositoryException
     */
    private NodeType[] registerNodeTypes(List defs)
            throws InvalidNodeTypeDefException, RepositoryException {
        ntReg.registerNodeTypes(defs);

        Set types = new HashSet();
        Iterator iterator = defs.iterator();
        while (iterator.hasNext()) {
            try {
                NodeTypeDef def = (NodeTypeDef) iterator.next();
                types.add(getNodeType(def.getName()));
            } catch (NoSuchNodeTypeException e) {
                // ignore
            }
        }
        return (NodeType[]) types.toArray(new NodeType[types.size()]);
    }

    /**
     * Registers the node types defined in the given XML stream.  This
     * is a trivial implementation that just invokes the existing
     * {@link NodeTypeReader} and {@link NodeTypeRegistry} methods and
     * heuristically creates the returned node type array.  It will also
     * register any namespaces defined in the input source that have not
     * already been registered.
     *
     * {@inheritDoc}
     */
    public NodeType[] registerNodeTypes(InputSource in)
            throws SAXException, RepositoryException {
        try {
            return registerNodeTypes(in.getByteStream(), TEXT_XML);
        } catch (IOException e) {
            throw new SAXException("Error reading node type stream", e);
        }
    }

    private static final String APPLICATION_XML = "application/xml";

    /**
     * Registers the node types defined in the given input stream depending
     * on the content type specified for the stream. This will also register
     * any namespaces identified in the input stream if they have not already
     * been registered.
     *
     * {@inheritDoc}
     */
    public NodeType[] registerNodeTypes(InputStream in, String contentType)
            throws IOException, RepositoryException {
        return registerNodeTypes(in, contentType, false);
    }

    /**
     * {@inheritDoc}
     */
    public boolean hasNodeType(String name) throws RepositoryException {
        try {
            QName qname = NameFormat.parse(name, nsResolver);
            return getNodeTypeRegistry().isRegistered(qname);
        } catch (NameException e) {
           throw new RepositoryException();
        }     
    }

    //-------------------------------------------------------------< Dumpable >
    /**
     * {@inheritDoc}
     */
    public void dump(PrintStream ps) {
        ps.println("NodeTypeManager (" + this + ")");
        ps.println();
        ntReg.dump(ps);
   
}
TOP

Related Classes of org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.