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 }