1 /* 2 * Copyright (c) 1998-2002 The Jgroup Team. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU Lesser General Public License for more details. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program; if not, write to the Free Software 15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 16 * 17 */ 18 19 package jgroup.relacs.mss; 20 import java.util.NoSuchElementException; 21 22 import jgroup.util.OutMessage; 23 24 /** 25 * Provides an iterator over the fragments of a message. 26 * 27 * @author Hein Meling 28 * @since Jgroup 1.2 29 */ 30 class MsgFragmentIterator 31 implements FragmentIterator, MssTag 32 { 33 34 //////////////////////////////////////////////////////////////////////////////////////////// 35 // Fields 36 //////////////////////////////////////////////////////////////////////////////////////////// 37 38 /* Constants for the duration of this iterator */ 39 private byte[][] fragments; 40 private int fragmentCount; 41 private int defaultFragLen; 42 private int lastFragLen; 43 44 /* The actual message associated with this fragment iterator */ 45 private Msg msg; 46 47 /* The message control object */ 48 private MsgCntrl msgCntrl; 49 50 /* Indicates if the iterator has been initialized */ 51 private boolean initialized; 52 53 /* Pointer to the next fragment to be returned by the iterator */ 54 private int nextFragment; 55 56 /* The actual length of the fragment previously returned */ 57 private int fragLen; 58 59 /* The fragment identifier of the fragment previously returned */ 60 private int fragId; 61 62 /* The first fragment identifier represented by this iterator */ 63 private int firstFragId; 64 65 66 //////////////////////////////////////////////////////////////////////////////////////////// 67 // Constructor 68 //////////////////////////////////////////////////////////////////////////////////////////// 69 70 /** 71 * Creates a new <code>MsgFragmentIterator</code> instance, used to 72 * access the fragments of the given <code>OutMessage</code>. 73 */ 74 MsgFragmentIterator(Msg msg, MsgCntrl msgCntrl) 75 { 76 this.msgCntrl = msgCntrl; 77 this.msg = msg; 78 reset(msg.getOutMessage()); 79 } 80 81 82 //////////////////////////////////////////////////////////////////////////////////////////// 83 // Package methods 84 //////////////////////////////////////////////////////////////////////////////////////////// 85 86 /** 87 * Reset the iterator to start from the first fragment again. Note 88 * that this method should be used with care, especially in the case 89 * when a message may potentially be resent, based on the fragId. 90 * This is since, for each reuse, this iterator will change its 91 * fragment identifier. This requires that the iterator must be 92 * reinitialized with the correct fragment identifier before reuse. 93 */ 94 void reset(OutMessage outmsg) 95 { 96 initialized = false; 97 fragments = outmsg.getFragments(); 98 fragmentCount = outmsg.getFragmentCount(); 99 defaultFragLen = outmsg.getPayload() + outmsg.getHeader(); 100 lastFragLen = outmsg.getLastPayload() + outmsg.getHeader(); 101 102 nextFragment = 0; 103 fragLen = -1; 104 fragId = -1; 105 firstFragId = -1; 106 } 107 108 109 //////////////////////////////////////////////////////////////////////////////////////////// 110 // FragmentIterator methods 111 //////////////////////////////////////////////////////////////////////////////////////////// 112 113 /** 114 * Return the fragment associated with the given fragment identifier. 115 * 116 * @exception IllegalStateException 117 * Raised if the iterator has not been invoked prior to calling 118 * this method. This is since we cannot know the iterators 119 * fragment identifiers until we have invoked next. 120 * @exception IndexOutOfBoundsException 121 * Raised if the given fragment identifier is not represented by 122 * this iterator. 123 * @exception NoSuchElementException 124 * Thrown if the computed fragment position exceeds the fragment 125 * count of the iterator. This can never happen. 126 */ 127 public byte[] getFragment(int fragId) 128 { 129 if (!initialized) 130 throw new IllegalStateException("Cannot seek in the iterator before having iterated once"); 131 132 int lastFragId = fragmentCount + firstFragId - 1; 133 if (fragId > lastFragId || fragId < firstFragId) 134 throw new IndexOutOfBoundsException("The fragment identifier (" 135 + fragId + ") is not represented by this iterator: " + this); 136 137 nextFragment = fragId - firstFragId; 138 if (nextFragment >= fragmentCount) 139 throw new NoSuchElementException("There are no more fragments associated with this message."); 140 141 if (fragId == lastFragId) 142 fragLen = lastFragLen; 143 else 144 fragLen = defaultFragLen; 145 this.fragId = fragId; 146 147 return fragments[nextFragment]; 148 } 149 150 151 /** 152 * Returns the length (including the header) of the active 153 * fragment; that is, the one most recently retrieved through the 154 * <code>next()</code> method. <p> 155 * 156 * The last fragment will have a different length than the other 157 * fragments, for which this method will return the default payload 158 * length of a packet. Also a single fragment counts as a last 159 * fragment, and may thus not use the entire payload length. This 160 * method always returns the correct length of the active fragment. 161 * <p> 162 * 163 * It is not possible to use the fragment.length field, since we 164 * are not copying the data of the original; we are merely returning 165 * its reference. 166 */ 167 public int fragmentLength() 168 { 169 if (!initialized) 170 throw new IllegalStateException("No fragment is active; must invoke next() first"); 171 return fragLen; 172 } 173 174 175 /** 176 * Returns the fragment identifier of the active fragment. 177 */ 178 public int getFid() 179 { 180 if (!initialized) 181 throw new IllegalStateException("No fragment is active; must invoke next() first"); 182 return fragId; 183 } 184 185 186 /** 187 * Returns the actul message object assocaited with this fragment 188 * iterator. 189 */ 190 public Msg getMsg() 191 { 192 if (msg == null) 193 throw new NullPointerException("The message is null; iterator is not correctly initialized"); 194 return msg; 195 } 196 197 198 /** 199 * Returns true if the message stream has more fragments; false is 200 * returned otherwise. 201 */ 202 public boolean hasNext() 203 { 204 return nextFragment != fragmentCount; 205 } 206 207 208 /** 209 * Returns the next fragment of this message object's stream, 210 * including the marshalled fragment header which includes the message 211 * <code>tag</code> and <code>fragId</code>. The latter constitute 212 * the packet level header. 213 * 214 * @see jgroup.relacs.mss.MssTag 215 * @param broadcast 216 * Indicates if the message fragment should be broadcast, and 217 * thus sets a packet level broadcast field. 218 * @return 219 * A byte array containing the next fragment in the stream, 220 * including the header. 221 */ 222 public byte[] next(boolean broadcast) 223 { 224 if (nextFragment == fragmentCount) 225 throw new NoSuchElementException("There are no more fragments associated with this message."); 226 227 byte tag = msg.getTag(); 228 229 /* 230 * Set the correct tag for this message fragment. If there is only 231 * one fragment, it will be marked with the tag obtained from the 232 * message. The message tag will always mark the last fragment. If 233 * there are multiple fragments, the first <i>n - 1</i> fragments 234 * will be marked with the <code>NOTLASTFRAGMENT</code> tag, while 235 * the <i>n</i>-th fragment will be marked with the message tag. 236 */ 237 if (nextFragment + 1 == fragmentCount) { 238 fragLen = lastFragLen; 239 } else { 240 fragLen = defaultFragLen; 241 tag = NOTLASTFRAGMENT; 242 } 243 244 if (msg instanceof MsgJG) { 245 /* The msgSend() method blocks until the sending window is open */ 246 fragId = msgCntrl.msgSend(this); 247 } else { 248 /* IAMALIVE, ROUTING, NACK and SYN messages provide their own fragId */ 249 fragId = msg.getMid(); 250 } 251 252 if (firstFragId == -1) 253 firstFragId = fragId; 254 255 /* The iterator has now been initialized. */ 256 initialized = true; 257 258 FragmentHeader.marshal(tag, broadcast, fragId, fragments[nextFragment]); 259 260 return fragments[nextFragment++]; 261 } 262 263 264 //////////////////////////////////////////////////////////////////////////////////////////// 265 // Methods from Object 266 //////////////////////////////////////////////////////////////////////////////////////////// 267 268 public String toString() 269 { 270 StringBuilder buf = new StringBuilder("[MsgFragmentIterator: nxtFrag="); 271 buf.append(nextFragment); 272 buf.append(", fragLen="); 273 buf.append(fragLen); 274 buf.append(", fragId="); 275 buf.append(fragId); 276 buf.append(", firstFragId="); 277 buf.append(firstFragId); 278 buf.append(", lastFragId="); 279 buf.append((fragmentCount + firstFragId - 1)); 280 buf.append(", fragCnt="); 281 buf.append(fragmentCount); 282 buf.append(", lastFragLen="); 283 buf.append(lastFragLen); 284 buf.append("]"); 285 return buf.toString(); 286 } 287 288 } // END MsgFragmentIterator