View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.configuration2.tree;
18  
19  import org.apache.commons.lang3.StringUtils;
20  import org.apache.commons.lang3.builder.EqualsBuilder;
21  import org.apache.commons.lang3.builder.HashCodeBuilder;
22  import org.apache.commons.lang3.builder.ToStringBuilder;
23  
24  /**
25   * <p>
26   * A data class representing a single query result produced by an {@link ExpressionEngine}.
27   * </p>
28   * <p>
29   * When passing a key to the {@code query()} method of {@code ExpressionEngine} the result can be a set of nodes or
30   * attributes - depending on the key. This class can represent both types of results. The aim is to give a user of
31   * {@code ExpressionEngine} all information needed for evaluating the results returned.
32   * </p>
33   * <p>
34   * Implementation note: Instances are immutable. They are created using the static factory methods.
35   * </p>
36   *
37   * @param <T> the type of the result nodes
38   * @since 2.0
39   */
40  public final class QueryResult<T> {
41  
42      /**
43       * Creates a {@code QueryResult} instance representing an attribute result. An attribute result consists of the node the
44       * attribute belongs to and the attribute name. (The value can be obtained based on this information.)
45       *
46       * @param parentNode the node which owns the attribute
47       * @param attrName the attribute name
48       * @param <T> the type of the parent node
49       * @return the newly created instance
50       */
51      public static <T> QueryResult<T> createAttributeResult(final T parentNode, final String attrName) {
52          return new QueryResult<>(parentNode, attrName);
53      }
54  
55      /**
56       * Creates a {@code QueryResult} instance representing the specified result node.
57       *
58       * @param <T> the type of the result node
59       * @param resultNode the result node
60       * @return the newly created instance
61       */
62      public static <T> QueryResult<T> createNodeResult(final T resultNode) {
63          return new QueryResult<>(resultNode, null);
64      }
65  
66      /** The node result. */
67      private final T node;
68  
69      /** The name of the result attribute. */
70      private final String attributeName;
71  
72      /**
73       * Creates a new instance of {@code QueryResult}.
74       *
75       * @param nd the node
76       * @param attr the attribute name
77       */
78      private QueryResult(final T nd, final String attr) {
79          node = nd;
80          attributeName = attr;
81      }
82  
83      /**
84       * Compares this object with another one. Two instances of {@code QueryResult} are considered equal if they are of the
85       * same result type and have the same properties.
86       *
87       * @param obj the object to compare to
88       * @return a flag whether these objects are equal
89       */
90      @Override
91      public boolean equals(final Object obj) {
92          if (this == obj) {
93              return true;
94          }
95          if (!(obj instanceof QueryResult)) {
96              return false;
97          }
98  
99          final QueryResult<?> c = (QueryResult<?>) obj;
100         return new EqualsBuilder().append(getNode(), c.getNode()).append(getAttributeName(), c.getAttributeName()).isEquals();
101     }
102 
103     /**
104      * Gets the name of the attribute. This method is defined only for results of type attribute.
105      *
106      * @return the attribute name
107      */
108     public String getAttributeName() {
109         return attributeName;
110     }
111 
112     /**
113      * Gets the attribute value if this is an attribute result. If this is not an attribute result, an exception is
114      * thrown.
115      *
116      * @param handler the {@code NodeHandler}
117      * @return the attribute value
118      * @throws IllegalStateException if this is not an attribute result
119      */
120     public Object getAttributeValue(final NodeHandler<T> handler) {
121         if (!isAttributeResult()) {
122             throw new IllegalStateException("This is not an attribute result! Attribute value cannot be fetched.");
123         }
124         return handler.getAttributeValue(getNode(), getAttributeName());
125     }
126 
127     /**
128      * Gets the node referenced by this object. Depending on the result type, this is either the result node or the
129      * parent node of the represented attribute.
130      *
131      * @return the referenced node
132      */
133     public T getNode() {
134         return node;
135     }
136 
137     @Override
138     public int hashCode() {
139         return new HashCodeBuilder().append(getNode()).append(getAttributeName()).toHashCode();
140     }
141 
142     /**
143      * Returns a flag whether this is a result of type attribute. If result is <strong>true</strong>, the attribute name and value can
144      * be queried. Otherwise, only the result node is available.
145      *
146      * @return <strong>true</strong> for an attribute result, <strong>false</strong> otherwise
147      */
148     public boolean isAttributeResult() {
149         return StringUtils.isNotEmpty(getAttributeName());
150     }
151 
152     /**
153      * Returns a string representation of this object. Depending on the result type either the result node or the parent
154      * node and the attribute name are contained in this string.
155      *
156      * @return a string for this object
157      */
158     @Override
159     public String toString() {
160         final ToStringBuilder sb = new ToStringBuilder(this);
161         if (isAttributeResult()) {
162             sb.append("parentNode", getNode()).append("attribute", getAttributeName());
163         } else {
164             sb.append("resultNode", getNode());
165         }
166         return sb.toString();
167     }
168 }