001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.types; 028 029 import java.util.HashSet; 030 import java.util.Iterator; 031 import java.util.NoSuchElementException; 032 033 034 035 /** 036 * An iterable read-only view of of a set of attribute values returned 037 * from methods such as 038 * {@link org.opends.server.types.Entry#getAttribute(AttributeType)}. 039 * <p> 040 * Using instances of this class it is possible to filter out 041 * attribute values which do not have the correct options set. This is 042 * achieved without having to duplicate the set of attributes. 043 */ 044 @org.opends.server.types.PublicAPI( 045 stability=org.opends.server.types.StabilityLevel.VOLATILE, 046 mayInstantiate=false, 047 mayExtend=false, 048 mayInvoke=true) 049 public final class AttributeValueIterable implements 050 Iterable<AttributeValue> { 051 052 // The set of attributes having the same type and options. 053 private Iterable<Attribute> attributes; 054 055 // The set of options which all values must contain. 056 private HashSet<String> options; 057 058 059 060 /** 061 * Create a new attribute value iterable object. 062 * 063 * @param attributes The set of attributes having the same type. 064 * Can be {@code null}. 065 */ 066 public AttributeValueIterable(Iterable<Attribute> attributes) { 067 this(attributes, null); 068 069 } 070 071 /** 072 * Create a new attribute value iterable object. 073 * 074 * @param attributes The set of attributes having the same type. 075 * Can be {@code null}. 076 * @param options The set of options which all values must 077 * contain, or {@code null} if no options are 078 * required. 079 */ 080 public AttributeValueIterable(Iterable<Attribute> attributes, 081 HashSet<String> options) { 082 083 this.attributes = attributes; 084 this.options = options; 085 } 086 087 /** 088 * Retrieves an iterator that can be used to cursor through the set 089 * of attribute values. 090 * 091 * @return An iterator that can be used to cursor through the set 092 * of attribute values. 093 */ 094 public Iterator<AttributeValue> iterator() { 095 096 return new AttributeValueIterator(); 097 } 098 099 /** 100 * Private iterator implementation. 101 */ 102 private class AttributeValueIterator 103 implements Iterator<AttributeValue> { 104 // Flag indicating whether iteration can proceed. 105 private boolean hasNext; 106 107 // The current attribute iterator. 108 private Iterator<Attribute> attributeIterator; 109 110 // The current value iterator. 111 private Iterator<AttributeValue> valueIterator; 112 113 /** 114 * Create a new attribute value iterator over the attribute set. 115 */ 116 private AttributeValueIterator() { 117 118 this.valueIterator = null; 119 120 if (attributes != null) { 121 this.attributeIterator = attributes.iterator(); 122 this.hasNext = skipNonMatchingAttributes(); 123 } else { 124 this.attributeIterator = null; 125 this.hasNext = false; 126 } 127 } 128 129 /** 130 * Indicates whether there are more attribute values to return. 131 * 132 * @return {@code true} if there are more attribute values to 133 * return, or {@code false} if not. 134 */ 135 public boolean hasNext() { 136 137 return hasNext; 138 } 139 140 /** 141 * Retrieves the next attribute value in the set. 142 * 143 * @return The next attribute value in the set. 144 * 145 * @throws NoSuchElementException If there are no more values to 146 * return. 147 */ 148 public AttributeValue next() 149 throws NoSuchElementException 150 { 151 if (hasNext == false) { 152 throw new NoSuchElementException(); 153 } 154 155 AttributeValue value = valueIterator.next(); 156 157 // We've reached the end of this array list, so skip to the next 158 // non-empty one. 159 if (valueIterator.hasNext() == false) { 160 hasNext = skipNonMatchingAttributes(); 161 } 162 163 return value; 164 } 165 166 /** 167 * Removes the last attribute value retrieved from the set. Note 168 * that this operation is not supported and will always cause an 169 * {@code UnsupportedOperationException} to be thrown. 170 * 171 * @throws UnsupportedOperationException If the last value 172 * cannot be removed. 173 */ 174 public void remove() 175 throws UnsupportedOperationException 176 { 177 throw new UnsupportedOperationException(); 178 } 179 180 /** 181 * Skip past any empty attributes or attributes that do not have 182 * the correct set of options until we find one that contains some 183 * values. 184 * 185 * @return {@code true} if iteration can continue, or 186 * {@code false} if not. 187 */ 188 private boolean skipNonMatchingAttributes() { 189 190 while (attributeIterator.hasNext()) { 191 Attribute attribute = attributeIterator.next(); 192 193 if (attribute.hasOptions(options)) { 194 valueIterator = attribute.getValues().iterator(); 195 if (valueIterator.hasNext()) { 196 return true; 197 } 198 } 199 } 200 201 return false; 202 } 203 } 204 }