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 * http://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 027 * {@link ExpressionEngine}. 028 * </p> 029 * <p> 030 * When passing a key to the {@code query()} method of {@code ExpressionEngine} 031 * the result can be a set of nodes or attributes - depending on the key. This 032 * class can represent both types of results. The aim is to give a user of 033 * {@code ExpressionEngine} all information needed for evaluating the results 034 * returned. 035 * </p> 036 * <p> 037 * Implementation note: Instances are immutable. They are created using the 038 * static factory methods. 039 * </p> 040 * 041 * @version $Id: QueryResult.java 1790899 2017-04-10 21:56:46Z ggregory $ 042 * @since 2.0 043 * @param <T> the type of the result nodes 044 */ 045public final class QueryResult<T> 046{ 047 /** The node result. */ 048 private final T node; 049 050 /** The name of the result attribute. */ 051 private final String attributeName; 052 053 /** 054 * Creates a new instance of {@code QueryResult}. 055 * 056 * @param nd the node 057 * @param attr the attribute name 058 */ 059 private QueryResult(T nd, String attr) 060 { 061 node = nd; 062 attributeName = attr; 063 } 064 065 /** 066 * Creates a {@code QueryResult} instance representing the specified result 067 * node. 068 * 069 * @param <T> the type of the result node 070 * @param resultNode the result node 071 * @return the newly created instance 072 */ 073 public static <T> QueryResult<T> createNodeResult(T resultNode) 074 { 075 return new QueryResult<>(resultNode, null); 076 } 077 078 /** 079 * Creates a {@code QueryResult} instance representing an attribute result. 080 * An attribute result consists of the node the attribute belongs to and the 081 * attribute name. (The value can be obtained based on this information.) 082 * 083 * @param parentNode the node which owns the attribute 084 * @param attrName the attribute name 085 * @param <T> the type of the parent node 086 * @return the newly created instance 087 */ 088 public static <T> QueryResult<T> createAttributeResult(T parentNode, 089 String attrName) 090 { 091 return new QueryResult<>(parentNode, attrName); 092 } 093 094 /** 095 * Returns the node referenced by this object. Depending on the result type, 096 * this is either the result node or the parent node of the represented 097 * attribute. 098 * 099 * @return the referenced node 100 */ 101 public T getNode() 102 { 103 return node; 104 } 105 106 /** 107 * Returns the name of the attribute. This method is defined only for 108 * results of type attribute. 109 * 110 * @return the attribute name 111 */ 112 public String getAttributeName() 113 { 114 return attributeName; 115 } 116 117 /** 118 * Returns a flag whether this is a result of type attribute. If result is 119 * <b>true</b>, the attribute name and value can be queried. Otherwise, only 120 * the result node is available. 121 * 122 * @return <b>true</b> for an attribute result, <b>false</b> otherwise 123 */ 124 public boolean isAttributeResult() 125 { 126 return StringUtils.isNotEmpty(getAttributeName()); 127 } 128 129 /** 130 * Returns the attribute value if this is an attribute result. If this is 131 * not an attribute result, an exception is thrown. 132 * 133 * @param handler the {@code NodeHandler} 134 * @return the attribute value 135 * @throws IllegalStateException if this is not an attribute result 136 */ 137 public Object getAttributeValue(NodeHandler<T> handler) 138 { 139 if (!isAttributeResult()) 140 { 141 throw new IllegalStateException("This is not an attribute result! " 142 + "Attribute value cannot be fetched."); 143 } 144 return handler.getAttributeValue(getNode(), getAttributeName()); 145 } 146 147 @Override 148 public int hashCode() 149 { 150 return new HashCodeBuilder().append(getNode()) 151 .append(getAttributeName()).toHashCode(); 152 } 153 154 /** 155 * Compares this object with another one. Two instances of 156 * {@code QueryResult} are considered equal if they are of the same result 157 * type and have the same properties. 158 * 159 * @param obj the object to compare to 160 * @return a flag whether these objects are equal 161 */ 162 @Override 163 public boolean equals(Object obj) 164 { 165 if (this == obj) 166 { 167 return true; 168 } 169 if (!(obj instanceof QueryResult)) 170 { 171 return false; 172 } 173 174 QueryResult<?> c = (QueryResult<?>) obj; 175 return new EqualsBuilder().append(getNode(), c.getNode()) 176 .append(getAttributeName(), c.getAttributeName()).isEquals(); 177 } 178 179 /** 180 * Returns a string representation of this object. Depending on the result 181 * type either the result node or the parent node and the attribute name are 182 * contained in this string. 183 * 184 * @return a string for this object 185 */ 186 @Override 187 public String toString() 188 { 189 ToStringBuilder sb = new ToStringBuilder(this); 190 if (isAttributeResult()) 191 { 192 sb.append("parentNode", getNode()).append("attribute", 193 getAttributeName()); 194 } 195 else 196 { 197 sb.append("resultNode", getNode()); 198 } 199 return sb.toString(); 200 } 201}