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