001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *       http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.sequencer.ddl.node;
017
018import static org.modeshape.jcr.api.JcrConstants.JCR_MIXIN_TYPES;
019import static org.modeshape.jcr.api.JcrConstants.JCR_PRIMARY_TYPE;
020import static org.modeshape.jcr.api.JcrConstants.NT_UNSTRUCTURED;
021import java.util.ArrayList;
022import java.util.List;
023import org.modeshape.common.util.CheckArg;
024
025/**
026 * Utility class which provides construction, editing and assorted methods to work with AstNodes.
027 */
028public final class AstNodeFactory {
029
030    /**
031     * Constructs an {@link AstNode} with the given string name
032     * 
033     * @param name the name property of the node; may not be null
034     * @return the tree node
035     */
036    public AstNode node( String name ) {
037        CheckArg.isNotNull(name, "name");
038        AstNode node = new AstNode(name);
039        node.setProperty(JCR_PRIMARY_TYPE, NT_UNSTRUCTURED);
040        return node;
041    }
042
043    /**
044     * Constructs an {@link AstNode} with the given name, types and parent node.
045     * 
046     * @param name the name property of the node; may not be null
047     * @param parent the parent of the node; may not be null
048     * @param types the mixin types; may not be null, but may be empty
049     * @return the tree node
050     */
051    public AstNode node( String name,
052                         AstNode parent,
053                         Object... types ) {
054        CheckArg.isNotNull(name, "name");
055        CheckArg.isNotNull(parent, "parent");
056        CheckArg.isNotEmpty(types, "types");
057
058        AstNode node = new AstNode(parent, name);
059        node.setProperty(JCR_MIXIN_TYPES, types);
060        node.setProperty(JCR_PRIMARY_TYPE, NT_UNSTRUCTURED);
061        return node;
062    }
063
064    /**
065     * Constructs an {@link AstNode} with the given name, type and parent node.
066     * 
067     * @param name the name property of the node; may not be null
068     * @param parent the parent of the node; may not be null
069     * @param type the mixin type {@link String} for the requested node; may not be null
070     * @return the tree node
071     */
072    public AstNode node( String name,
073                         AstNode parent,
074                         String type ) {
075        CheckArg.isNotNull(name, "name");
076        CheckArg.isNotNull(parent, "parent");
077        CheckArg.isNotNull(type, "type");
078
079        AstNode node = new AstNode(parent, name);
080        node.setProperty(JCR_MIXIN_TYPES, type);
081        node.setProperty(JCR_PRIMARY_TYPE, NT_UNSTRUCTURED);
082        return node;
083    }
084
085    /**
086     * Sets the mixin type property for an {@link AstNode}
087     * 
088     * @param node the node to set the property on; may not be null
089     * @param type the mixin type {@link String}; may not be null
090     */
091    public void setType( AstNode node,
092                         String type ) {
093        CheckArg.isNotNull(node, "node");
094        CheckArg.isNotNull(type, "parent");
095        node.setProperty(JCR_MIXIN_TYPES, type);
096    }
097
098    /**
099     * Utility method to obtain the children of a given node that match the given type
100     * 
101     * @param astNode the parent node; may not be null
102     * @param nodeType the type property of the target child node; may not be null
103     * @return the list of typed nodes (may be empty)
104     */
105    public List<AstNode> getChildrenForType( AstNode astNode,
106                                             String nodeType ) {
107        CheckArg.isNotNull(astNode, "astNode");
108        CheckArg.isNotNull(nodeType, "nodeType");
109
110        List<AstNode> childrenOfType = new ArrayList<AstNode>();
111        for (AstNode child : astNode.getChildren()) {
112            if (hasMixinType(child, nodeType)) {
113                childrenOfType.add(child);
114            }
115            List<AstNode> subChildrenOfType = getChildrenForType(child, nodeType);
116            childrenOfType.addAll(subChildrenOfType);
117        }
118
119        return childrenOfType;
120    }
121
122    /**
123     * Utility method to obtain a {@link AstNode} child of a parent {@link AstNode} with the given string name and node type.
124     * 
125     * @param astNode the parent node; may not be null
126     * @param name the name property of the node; may not be null
127     * @param nodeType the type property of the target child node; may not be null
128     * @return the matched child (may be null)
129     */
130    public AstNode getChildforNameAndType( AstNode astNode,
131                                           String name,
132                                           String nodeType ) {
133        CheckArg.isNotNull(astNode, "astNode");
134        CheckArg.isNotNull(name, "name");
135        CheckArg.isNotNull(nodeType, "nodeType");
136
137        for (AstNode child : astNode.getChildren()) {
138            if (hasMixinType(child, nodeType)) {
139                if (name.equalsIgnoreCase(child.getName())) {
140                    return child;
141                }
142            }
143        }
144        return null;
145    }
146
147    /**
148     * Utility method to determine if an {@link AstNode} contains a specific mixin type.
149     * 
150     * @param node the AstNode
151     * @param mixinType the target mixin type {@link String}; may not be null;
152     * @return true if the mixinType exists for this node
153     */
154    public boolean hasMixinType( AstNode node,
155                                 String mixinType ) {
156        CheckArg.isNotNull(node, "node");
157        CheckArg.isNotNull(mixinType, "mixinType");
158        return node.getMixins().contains(mixinType);
159    }
160}