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    *     http://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   * @since 2.0
38   * @param <T> the type of the result nodes
39   */
40  public final class QueryResult<T> {
41      /** The node result. */
42      private final T node;
43  
44      /** The name of the result attribute. */
45      private final String attributeName;
46  
47      /**
48       * Creates a new instance of {@code QueryResult}.
49       *
50       * @param nd the node
51       * @param attr the attribute name
52       */
53      private QueryResult(final T nd, final String attr) {
54          node = nd;
55          attributeName = attr;
56      }
57  
58      /**
59       * Creates a {@code QueryResult} instance representing the specified result node.
60       *
61       * @param <T> the type of the result node
62       * @param resultNode the result node
63       * @return the newly created instance
64       */
65      public static <T> QueryResult<T> createNodeResult(final T resultNode) {
66          return new QueryResult<>(resultNode, null);
67      }
68  
69      /**
70       * Creates a {@code QueryResult} instance representing an attribute result. An attribute result consists of the node the
71       * attribute belongs to and the attribute name. (The value can be obtained based on this information.)
72       *
73       * @param parentNode the node which owns the attribute
74       * @param attrName the attribute name
75       * @param <T> the type of the parent node
76       * @return the newly created instance
77       */
78      public static <T> QueryResult<T> createAttributeResult(final T parentNode, final String attrName) {
79          return new QueryResult<>(parentNode, attrName);
80      }
81  
82      /**
83       * Gets the node referenced by this object. Depending on the result type, this is either the result node or the
84       * parent node of the represented attribute.
85       *
86       * @return the referenced node
87       */
88      public T getNode() {
89          return node;
90      }
91  
92      /**
93       * Gets the name of the attribute. This method is defined only for results of type attribute.
94       *
95       * @return the attribute name
96       */
97      public String getAttributeName() {
98          return attributeName;
99      }
100 
101     /**
102      * Returns a flag whether this is a result of type attribute. If result is <b>true</b>, the attribute name and value can
103      * be queried. Otherwise, only the result node is available.
104      *
105      * @return <b>true</b> for an attribute result, <b>false</b> otherwise
106      */
107     public boolean isAttributeResult() {
108         return StringUtils.isNotEmpty(getAttributeName());
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     @Override
127     public int hashCode() {
128         return new HashCodeBuilder().append(getNode()).append(getAttributeName()).toHashCode();
129     }
130 
131     /**
132      * Compares this object with another one. Two instances of {@code QueryResult} are considered equal if they are of the
133      * same result type and have the same properties.
134      *
135      * @param obj the object to compare to
136      * @return a flag whether these objects are equal
137      */
138     @Override
139     public boolean equals(final Object obj) {
140         if (this == obj) {
141             return true;
142         }
143         if (!(obj instanceof QueryResult)) {
144             return false;
145         }
146 
147         final QueryResult<?> c = (QueryResult<?>) obj;
148         return new EqualsBuilder().append(getNode(), c.getNode()).append(getAttributeName(), c.getAttributeName()).isEquals();
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 }