001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.configuration2.tree; 018 019import org.apache.commons.lang3.StringUtils; 020import org.apache.commons.lang3.builder.EqualsBuilder; 021import org.apache.commons.lang3.builder.HashCodeBuilder; 022import org.apache.commons.lang3.builder.ToStringBuilder; 023 024/** 025 * <p> 026 * A data class representing a single query result produced by an {@link ExpressionEngine}. 027 * </p> 028 * <p> 029 * When passing a key to the {@code query()} method of {@code ExpressionEngine} the result can be a set of nodes or 030 * attributes - depending on the key. This class can represent both types of results. The aim is to give a user of 031 * {@code ExpressionEngine} all information needed for evaluating the results returned. 032 * </p> 033 * <p> 034 * Implementation note: Instances are immutable. They are created using the static factory methods. 035 * </p> 036 * 037 * @param <T> the type of the result nodes 038 * @since 2.0 039 */ 040public final class QueryResult<T> { 041 042 /** 043 * Creates a {@code QueryResult} instance representing an attribute result. An attribute result consists of the node the 044 * attribute belongs to and the attribute name. (The value can be obtained based on this information.) 045 * 046 * @param parentNode the node which owns the attribute 047 * @param attrName the attribute name 048 * @param <T> the type of the parent node 049 * @return the newly created instance 050 */ 051 public static <T> QueryResult<T> createAttributeResult(final T parentNode, final String attrName) { 052 return new QueryResult<>(parentNode, attrName); 053 } 054 055 /** 056 * Creates a {@code QueryResult} instance representing the specified result node. 057 * 058 * @param <T> the type of the result node 059 * @param resultNode the result node 060 * @return the newly created instance 061 */ 062 public static <T> QueryResult<T> createNodeResult(final T resultNode) { 063 return new QueryResult<>(resultNode, null); 064 } 065 066 /** The node result. */ 067 private final T node; 068 069 /** The name of the result attribute. */ 070 private final String attributeName; 071 072 /** 073 * Creates a new instance of {@code QueryResult}. 074 * 075 * @param nd the node 076 * @param attr the attribute name 077 */ 078 private QueryResult(final T nd, final String attr) { 079 node = nd; 080 attributeName = attr; 081 } 082 083 /** 084 * Compares this object with another one. Two instances of {@code QueryResult} are considered equal if they are of the 085 * same result type and have the same properties. 086 * 087 * @param obj the object to compare to 088 * @return a flag whether these objects are equal 089 */ 090 @Override 091 public boolean equals(final Object obj) { 092 if (this == obj) { 093 return true; 094 } 095 if (!(obj instanceof QueryResult)) { 096 return false; 097 } 098 099 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}