001 /* 002 * JBoss DNA (http://www.jboss.org/dna) 003 * See the COPYRIGHT.txt file distributed with this work for information 004 * regarding copyright ownership. Some portions may be licensed 005 * to Red Hat, Inc. under one or more contributor license agreements. 006 * See the AUTHORS.txt file in the distribution for a full listing of 007 * individual contributors. 008 * 009 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA 010 * is licensed to you under the terms of the GNU Lesser General Public License as 011 * published by the Free Software Foundation; either version 2.1 of 012 * the License, or (at your option) any later version. 013 * 014 * JBoss DNA is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 017 * Lesser General Public License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this software; if not, write to the Free 021 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 022 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 023 */ 024 package org.jboss.dna.graph.request; 025 026 import java.util.LinkedList; 027 import java.util.List; 028 import org.jboss.dna.common.util.CheckArg; 029 import org.jboss.dna.graph.GraphI18n; 030 import org.jboss.dna.graph.Location; 031 import org.jboss.dna.graph.connector.RepositoryConnection; 032 import org.jboss.dna.graph.property.Path; 033 import org.jboss.dna.graph.property.Property; 034 035 /** 036 * Instruction to read a block of the children of a node, where the block is dictated by the {@link #startingAfter location of the 037 * child preceding the block} and the {@link #count() maximum number of children} to include in the block. This command is useful 038 * when paging through a large number of children, when the previous block of children was already retrieved and the next block is 039 * to be read. 040 * 041 * @see ReadBlockOfChildrenRequest 042 * @author Randall Hauch 043 */ 044 public class ReadNextBlockOfChildrenRequest extends CacheableRequest { 045 046 public static final int INDEX_NOT_USED = -1; 047 048 private static final long serialVersionUID = 1L; 049 050 private final List<Location> children = new LinkedList<Location>(); 051 private final Location startingAfter; 052 private final String workspaceName; 053 private final int count; 054 private Location actualStartingAfter; 055 056 /** 057 * Create a request to read those children of a node that are immediately after a supplied sibling node. 058 * 059 * @param startingAfter the location of the previous sibling that was the last child of the previous block of children read 060 * @param workspaceName the name of the workspace containing the node 061 * @param count the maximum number of children that should be included in the block 062 * @throws IllegalArgumentException if the workspace name or <code>startingAfter</code> location is null, or if 063 * <code>count</count> is less than 1. 064 */ 065 public ReadNextBlockOfChildrenRequest( Location startingAfter, 066 String workspaceName, 067 int count ) { 068 CheckArg.isNotNull(startingAfter, "startingAfter"); 069 CheckArg.isPositive(count, "count"); 070 CheckArg.isNotNull(workspaceName, "workspaceName"); 071 this.workspaceName = workspaceName; 072 this.startingAfter = startingAfter; 073 this.count = count; 074 } 075 076 /** 077 * {@inheritDoc} 078 * 079 * @see org.jboss.dna.graph.request.Request#isReadOnly() 080 */ 081 @Override 082 public boolean isReadOnly() { 083 return true; 084 } 085 086 /** 087 * Get the maximum number of children that may be returned in the block. 088 * 089 * @return the block's maximum count 090 * @see #startingAfter() 091 */ 092 public int count() { 093 return this.count; 094 } 095 096 /** 097 * Get the location of the child after which the block begins. This form may be easier to use when paging through blocks, as 098 * the last children retrieved with the previous block can be supplied with the next read request. 099 * 100 * @return the location of the child that is immediately before the start of the block; index at which this block starts; 101 * never negative 102 * @see #count() 103 */ 104 public Location startingAfter() { 105 return this.startingAfter; 106 } 107 108 /** 109 * Get the name of the workspace in which the parent and children exist. 110 * 111 * @return the name of the workspace; never null 112 */ 113 public String inWorkspace() { 114 return workspaceName; 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 = Location.create(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 = Location.create(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 #startingAfter() starting after location} 180 * should be used 181 * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same 182 * location} as the {@link #startingAfter() starting after location}, or if the actual location does not have a path. 183 */ 184 public void setActualLocationOfStartingAfterNode( Location actual ) { 185 if (!startingAfter.isSame(actual)) { // not same if actual is null 186 throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, startingAfter)); 187 } 188 assert actual != null; 189 if (!actual.hasPath()) { 190 throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual)); 191 } 192 this.actualStartingAfter = actual; 193 } 194 195 /** 196 * Get the actual location of the {@link #startingAfter() starting after} sibling. 197 * 198 * @return the actual location, or null if the actual location was not set 199 */ 200 public Location getActualLocationOfStartingAfterNode() { 201 return actualStartingAfter; 202 } 203 204 /** 205 * {@inheritDoc} 206 * 207 * @see java.lang.Object#equals(java.lang.Object) 208 */ 209 @Override 210 public boolean equals( Object obj ) { 211 if (obj == this) return true; 212 if (this.getClass().isInstance(obj)) { 213 ReadNextBlockOfChildrenRequest that = (ReadNextBlockOfChildrenRequest)obj; 214 if (!this.startingAfter().equals(that.startingAfter())) return false; 215 if (this.count() != that.count()) return false; 216 if (!this.inWorkspace().equals(that.inWorkspace())) return false; 217 return true; 218 } 219 return false; 220 } 221 222 /** 223 * {@inheritDoc} 224 * 225 * @see java.lang.Object#toString() 226 */ 227 @Override 228 public String toString() { 229 if (count() == 1) { 230 return "read the next child after " + startingAfter() + " in the \"" + workspaceName + "\" workspace"; 231 } 232 return "read the next " + count() + " children after " + startingAfter() + " in the \"" + workspaceName + "\" workspace"; 233 } 234 235 }