001 /* 002 * JBoss, Home of Professional Open Source. 003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors 004 * as indicated by the @author tags. See the copyright.txt file in the 005 * distribution for a full listing of individual contributors. 006 * 007 * This is free software; you can redistribute it and/or modify it 008 * under the terms of the GNU Lesser General Public License as 009 * published by the Free Software Foundation; either version 2.1 of 010 * the License, or (at your option) any later version. 011 * 012 * This software is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this software; if not, write to the Free 019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 021 */ 022 package org.jboss.dna.graph.requests; 023 024 import java.util.LinkedList; 025 import java.util.List; 026 import org.jboss.dna.common.util.CheckArg; 027 import org.jboss.dna.graph.GraphI18n; 028 import org.jboss.dna.graph.Location; 029 import org.jboss.dna.graph.connectors.RepositoryConnection; 030 import org.jboss.dna.graph.properties.Path; 031 import org.jboss.dna.graph.properties.Property; 032 033 /** 034 * Instruction to read a block of the children of a node, where the block is dictated by the {@link #startingAfter location of the 035 * child preceding the block} and the {@link #count() maximum number of children} to include in the block. This command is useful 036 * when paging through a large number of children. 037 * 038 * @see ReadBlockOfChildrenRequest 039 * @author Randall Hauch 040 */ 041 public class ReadNextBlockOfChildrenRequest extends CacheableRequest { 042 043 public static final int INDEX_NOT_USED = -1; 044 045 private static final long serialVersionUID = 1L; 046 047 private final Location of; 048 private final List<Location> children = new LinkedList<Location>(); 049 private final Location startingAfter; 050 private final int count; 051 private Location actualLocation; 052 053 /** 054 * Create a request to read a block of the children of a node at the supplied location. The block is defined by the starting 055 * index of the first child and the number of children to include. Note that this index is <i>not</i> the 056 * {@link Path.Segment#getIndex() same-name-sibiling index}, but rather is the index of the child as if the children were in 057 * an array. 058 * 059 * @param of the location of the node whose children are to be read 060 * @param startingAfter the child that was the last child of the previous block of children read 061 * @param count the maximum number of children that should be included in the block 062 * @throws IllegalArgumentException if the location is null, if <code>startingAfter</code> is null, or if 063 * <code>count</count> is less than 1. 064 */ 065 public ReadNextBlockOfChildrenRequest( Location of, 066 Location startingAfter, 067 int count ) { 068 CheckArg.isNotNull(of, "of"); 069 CheckArg.isNotNull(startingAfter, "startingAfter"); 070 CheckArg.isPositive(count, "count"); 071 this.of = of; 072 this.startingAfter = startingAfter; 073 this.count = count; 074 } 075 076 /** 077 * {@inheritDoc} 078 * 079 * @see org.jboss.dna.graph.requests.Request#isReadOnly() 080 */ 081 @Override 082 public boolean isReadOnly() { 083 return true; 084 } 085 086 /** 087 * Get the location defining the node whose children are to be read. 088 * 089 * @return the location of the parent node; never null 090 */ 091 public Location of() { 092 return of; 093 } 094 095 /** 096 * Get the maximum number of children that may be returned in the block. 097 * 098 * @return the block's maximum count 099 * @see #startingAfter() 100 */ 101 public int count() { 102 return this.count; 103 } 104 105 /** 106 * Get the location of the child after which the block begins. This form may be easier to use when paging through blocks, as 107 * the last children retrieved with the previous block can be supplied with the next read request. 108 * 109 * @return the location of the child that is immediately before the start of the block; index at which this block starts; 110 * never negative 111 * @see #count() 112 */ 113 public Location startingAfter() { 114 return this.startingAfter; 115 } 116 117 /** 118 * Get the children that were read from the {@link RepositoryConnection} after the request was processed. Each child is 119 * represented by a location. 120 * 121 * @return the children that were read; never null 122 */ 123 public List<Location> getChildren() { 124 return children; 125 } 126 127 /** 128 * Add to the list of children that has been read the child with the given path and identification properties. The children 129 * should be added in order. 130 * 131 * @param child the location of the child that was read 132 * @throws IllegalArgumentException if the location is null 133 * @see #addChild(Path, Property) 134 * @see #addChild(Path, Property, Property...) 135 */ 136 public void addChild( Location child ) { 137 CheckArg.isNotNull(child, "child"); 138 this.children.add(child); 139 } 140 141 /** 142 * Add to the list of children that has been read the child with the given path and identification properties. The children 143 * should be added in order. 144 * 145 * @param pathToChild the path of the child that was just read 146 * @param firstIdProperty the first identification property of the child that was just read 147 * @param remainingIdProperties the remaining identification properties of the child that was just read 148 * @throws IllegalArgumentException if the path or identification properties are null 149 * @see #addChild(Location) 150 * @see #addChild(Path, Property) 151 */ 152 public void addChild( Path pathToChild, 153 Property firstIdProperty, 154 Property... remainingIdProperties ) { 155 Location child = new Location(pathToChild, firstIdProperty, remainingIdProperties); 156 this.children.add(child); 157 } 158 159 /** 160 * Add to the list of children that has been read the child with the given path and identification property. The children 161 * should be added in order. 162 * 163 * @param pathToChild the path of the child that was just read 164 * @param idProperty the identification property of the child that was just read 165 * @throws IllegalArgumentException if the path or identification properties are null 166 * @see #addChild(Location) 167 * @see #addChild(Path, Property, Property...) 168 */ 169 public void addChild( Path pathToChild, 170 Property idProperty ) { 171 Location child = new Location(pathToChild, idProperty); 172 this.children.add(child); 173 } 174 175 /** 176 * Sets the actual and complete location of the node whose children have been read. This method must be called when processing 177 * the request, and the actual location must have a {@link Location#getPath() path}. 178 * 179 * @param actual the actual location of the node being read, or null if the {@link #of() current location} should be used 180 * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same 181 * location} as the {@link #of() current location}, or if the actual location does not have a path. 182 */ 183 public void setActualLocationOfNode( Location actual ) { 184 if (!of.isSame(actual)) { // not same if actual is null 185 throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, of)); 186 } 187 assert actual != null; 188 if (!actual.hasPath()) { 189 throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual)); 190 } 191 this.actualLocation = actual; 192 } 193 194 /** 195 * Get the actual location of the node whose children were read. 196 * 197 * @return the actual location, or null if the actual location was not set 198 */ 199 public Location getActualLocationOfNode() { 200 return actualLocation; 201 } 202 203 /** 204 * {@inheritDoc} 205 * 206 * @see java.lang.Object#equals(java.lang.Object) 207 */ 208 @Override 209 public boolean equals( Object obj ) { 210 if (this.getClass().isInstance(obj)) { 211 ReadNextBlockOfChildrenRequest that = (ReadNextBlockOfChildrenRequest)obj; 212 if (!this.of().equals(that.of())) return false; 213 if (!this.startingAfter().equals(that.startingAfter())) return false; 214 if (this.count() != that.count()) return false; 215 return true; 216 } 217 return false; 218 } 219 220 /** 221 * {@inheritDoc} 222 * 223 * @see java.lang.Object#toString() 224 */ 225 @Override 226 public String toString() { 227 if (count() == 1) { 228 return "read one child of " + of() + " starting after " + startingAfter(); 229 } 230 return "read " + count() + " children of " + of(); 231 } 232 233 }