1/**
2 * Copyright (c) 2008, http://www.snakeyaml.org
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.yaml.snakeyaml.nodes;
17
18import org.yaml.snakeyaml.error.Mark;
19
20/**
21 * Base class for all nodes.
22 * <p>
23 * The nodes form the node-graph described in the <a
24 * href="http://yaml.org/spec/1.1/">YAML Specification</a>.
25 * </p>
26 * <p>
27 * While loading, the node graph is usually created by the
28 * {@link org.yaml.snakeyaml.composer.Composer}, and later transformed into
29 * application specific Java classes by the classes from the
30 * {@link org.yaml.snakeyaml.constructor} package.
31 * </p>
32 */
33public abstract class Node {
34    private Tag tag;
35    private Mark startMark;
36    protected Mark endMark;
37    private Class<? extends Object> type;
38    private boolean twoStepsConstruction;
39    /**
40     * true when the tag is assigned by the resolver
41     */
42    protected boolean resolved;
43    protected Boolean useClassConstructor;
44
45    public Node(Tag tag, Mark startMark, Mark endMark) {
46        setTag(tag);
47        this.startMark = startMark;
48        this.endMark = endMark;
49        this.type = Object.class;
50        this.twoStepsConstruction = false;
51        this.resolved = true;
52        this.useClassConstructor = null;
53    }
54
55    /**
56     * Tag of this node.
57     * <p>
58     * Every node has a tag assigned. The tag is either local or global.
59     *
60     * @return Tag of this node.
61     */
62    public Tag getTag() {
63        return this.tag;
64    }
65
66    public Mark getEndMark() {
67        return endMark;
68    }
69
70    /**
71     * For error reporting.
72     *
73     * @see "class variable 'id' in PyYAML"
74     * @return scalar, sequence, mapping
75     */
76    public abstract NodeId getNodeId();
77
78    public Mark getStartMark() {
79        return startMark;
80    }
81
82    public void setTag(Tag tag) {
83        if (tag == null) {
84            throw new NullPointerException("tag in a Node is required.");
85        }
86        this.tag = tag;
87    }
88
89    /**
90     * Two Nodes are never equal.
91     */
92    @Override
93    public final boolean equals(Object obj) {
94        return super.equals(obj);
95    }
96
97    public Class<? extends Object> getType() {
98        return type;
99    }
100
101    public void setType(Class<? extends Object> type) {
102        if (!type.isAssignableFrom(this.type)) {
103            this.type = type;
104        }
105    }
106
107    public void setTwoStepsConstruction(boolean twoStepsConstruction) {
108        this.twoStepsConstruction = twoStepsConstruction;
109    }
110
111    /**
112     * Indicates if this node must be constructed in two steps.
113     * <p>
114     * Two-step construction is required whenever a node is a child (direct or
115     * indirect) of it self. That is, if a recursive structure is build using
116     * anchors and aliases.
117     * </p>
118     * <p>
119     * Set by {@link org.yaml.snakeyaml.composer.Composer}, used during the
120     * construction process.
121     * </p>
122     * <p>
123     * Only relevant during loading.
124     * </p>
125     *
126     * @return <code>true</code> if the node is self referenced.
127     */
128    public boolean isTwoStepsConstruction() {
129        return twoStepsConstruction;
130    }
131
132    @Override
133    public final int hashCode() {
134        return super.hashCode();
135    }
136
137    public boolean useClassConstructor() {
138        if (useClassConstructor == null) {
139            if (!tag.isSecondary() && isResolved() && !Object.class.equals(type)
140                    && !tag.equals(Tag.NULL)) {
141                return true;
142            } else if (tag.isCompatible(getType())) {
143                // the tag is compatible with the runtime class
144                // the tag will be ignored
145                return true;
146            } else {
147                return false;
148            }
149        }
150        return useClassConstructor.booleanValue();
151    }
152
153    public void setUseClassConstructor(Boolean useClassConstructor) {
154        this.useClassConstructor = useClassConstructor;
155    }
156
157    /**
158     * Indicates if the tag was added by
159     * {@link org.yaml.snakeyaml.resolver.Resolver}.
160     *
161     * @return <code>true</code> if the tag of this node was resolved</code>
162     */
163    public boolean isResolved() {
164        return resolved;
165    }
166}
167