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       * Creates a {@code QueryResult} instance representing an attribute result. An attribute result consists of the node the
43       * attribute belongs to and the attribute name. (The value can be obtained based on this information.)
44       *
45       * @param parentNode the node which owns the attribute
46       * @param attrName the attribute name
47       * @param <T> the type of the parent node
48       * @return the newly created instance
49       */
50      public static <T> QueryResult<T> createAttributeResult(final T parentNode, final String attrName) {
51          return new QueryResult<>(parentNode, attrName);
52      }
53  
54      /**
55       * Creates a {@code QueryResult} instance representing the specified result node.
56       *
57       * @param <T> the type of the result node
58       * @param resultNode the result node
59       * @return the newly created instance
60       */
61      public static <T> QueryResult<T> createNodeResult(final T resultNode) {
62          return new QueryResult<>(resultNode, null);
63      }
64  
65      /** The node result. */
66      private final T node;
67  
68      /** The name of the result attribute. */
69      private final String attributeName;
70  
71      /**
72       * Creates a new instance of {@code QueryResult}.
73       *
74       * @param nd the node
75       * @param attr the attribute name
76       */
77      private QueryResult(final T nd, final String attr) {
78          node = nd;
79          attributeName = attr;
80      }
81  
82      /**
83       * Compares this object with another one. Two instances of {@code QueryResult} are considered equal if they are of the
84       * same result type and have the same properties.
85       *
86       * @param obj the object to compare to
87       * @return a flag whether these objects are equal
88       */
89      @Override
90      public boolean equals(final Object obj) {
91          if (this == obj) {
92              return true;
93          }
94          if (!(obj instanceof QueryResult)) {
95              return false;
96          }
97  
98          final QueryResult<?> c = (QueryResult<?>) obj;
99          return new EqualsBuilder().append(getNode(), c.getNode()).append(getAttributeName(), c.getAttributeName()).isEquals();
100     }
101 
102     /**
103      * Gets the name of the attribute. This method is defined only for results of type attribute.
104      *
105      * @return the attribute name
106      */
107     public String getAttributeName() {
108         return attributeName;
109     }
110 
111     /**
112      * Gets the attribute value if this is an attribute result. If this is not an attribute result, an exception is
113      * thrown.
114      *
115      * @param handler the {@code NodeHandler}
116      * @return the attribute value
117      * @throws IllegalStateException if this is not an attribute result
118      */
119     public Object getAttributeValue(final NodeHandler<T> handler) {
120         if (!isAttributeResult()) {
121             throw new IllegalStateException("This is not an attribute result! Attribute value cannot be fetched.");
122         }
123         return handler.getAttributeValue(getNode(), getAttributeName());
124     }
125 
126     /**
127      * Gets the node referenced by this object. Depending on the result type, this is either the result node or the
128      * parent node of the represented attribute.
129      *
130      * @return the referenced node
131      */
132     public T getNode() {
133         return node;
134     }
135 
136     @Override
137     public int hashCode() {
138         return new HashCodeBuilder().append(getNode()).append(getAttributeName()).toHashCode();
139     }
140 
141     /**
142      * Returns a flag whether this is a result of type attribute. If result is <strong>true</strong>, the attribute name and value can
143      * be queried. Otherwise, only the result node is available.
144      *
145      * @return <strong>true</strong> for an attribute result, <strong>false</strong> otherwise
146      */
147     public boolean isAttributeResult() {
148         return StringUtils.isNotEmpty(getAttributeName());
149     }
150 
151     /**
152      * Returns a string representation of this object. Depending on the result type either the result node or the parent
153      * node and the attribute name are contained in this string.
154      *
155      * @return a string for this object
156      */
157     @Override
158     public String toString() {
159         final ToStringBuilder sb = new ToStringBuilder(this);
160         if (isAttributeResult()) {
161             sb.append("parentNode", getNode()).append("attribute", getAttributeName());
162         } else {
163             sb.append("resultNode", getNode());
164         }
165         return sb.toString();
166     }
167 }