/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.harmony.jndi.provider.ldap; import java.util.Collection; import java.util.LinkedList; import java.util.NoSuchElementException; import javax.naming.CommunicationException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import org.apache.harmony.jndi.internal.nls.Messages; /** * TODO: dynamic load elements from server */ public class LdapNamingEnumeration<T> implements NamingEnumeration<T> { private LinkedList<T> values; private NamingException exception; /** * flag to indicate whether all element have been added */ private boolean isFinished; /** * max time to wait next element in millisconds */ private long timeout = DEFAULT_TIMEOUT; private static final long DEFAULT_TIMEOUT = 30000; /** * This constructor equals to * <code>LdapNamingEnumeration(Collection<T>, NamingException, true)</code> */ public LdapNamingEnumeration(Collection<T> list, NamingException ex) { this(list, ex, true); } /** * <code>list</code> and <code>ex</code> both can be <code>null</code>, * <code>null</code> of <code>list</code> will be treated as empty List. * * @param list * elements added to the enumeration. * @param ex * exception would be thrown when over iterate. * @param isFinished * if all elements have been added. */ public LdapNamingEnumeration(Collection<T> list, NamingException ex, boolean isFinished) { if (list == null) { values = new LinkedList<T>(); } else { values = new LinkedList<T>(list); } exception = ex; this.isFinished = isFinished; } /** * release all relative resources, current implementation just set * enumeration values to <code>null</code> which indicate the enumeration * is closed. */ public void close() { // no other resources need to release synchronized (values) { values.clear(); values = null; } } public boolean hasMore() throws NamingException { // has been closed if (values == null) { return false; } if (!values.isEmpty()) { return true; } synchronized (values) { if (values.isEmpty() && !isFinished) { waitMoreElement(); if (!values.isEmpty()) { return true; } } } close(); if (exception != null) { throw exception; } if (!isFinished) { // ldap.31=Read LDAP response message time out throw new CommunicationException(Messages.getString("ldap.31")); //$NON-NLS-1$ } return false; } /** * Retrieves the next element. <code>NoSuchElementException</code> will be * thrown, if there is no other elements or <code>close()</code> has been * invoked. */ public T next() throws NamingException { if (values == null || (values.isEmpty() && isFinished)) { throw new NoSuchElementException(); } synchronized (values) { if (values.isEmpty() && !isFinished) { waitMoreElement(); // wait timeout if (values.isEmpty() && !isFinished) { if (exception != null) { throw exception; } // ldap.31=Read LDAP response message time out throw new CommunicationException(Messages .getString("ldap.31")); //$NON-NLS-1$ } else if (values.isEmpty()) { throw new NoSuchElementException(); } } return values.poll(); } } public boolean hasMoreElements() { if (values == null) { return false; } if (!values.isEmpty()) { return true; } synchronized (values) { if (values.isEmpty() && !isFinished) { waitMoreElement(); if (!values.isEmpty()) { return true; } } } return false; } public T nextElement() { if (values == null || (values.isEmpty() && isFinished)) { throw new NoSuchElementException(); } synchronized (values) { if (values.isEmpty() && !isFinished) { waitMoreElement(); if (values.isEmpty()) { throw new NoSuchElementException(); } } return values.poll(); } } private void waitMoreElement() { try { values.wait(timeout); } catch (InterruptedException e) { // ignore } } void setException(NamingException exception) { this.exception = exception; } void add(T pair, boolean isFinished) { if (values == null) { return; } synchronized (values) { values.add(pair); if (isFinished) { this.isFinished = true; } values.notifyAll(); } } void add(Collection<T> list, boolean isFinished) { if (values == null) { return; } synchronized (values) { values.addAll(list); if (isFinished) { this.isFinished = true; } values.notifyAll(); } } boolean isFinished() { return isFinished; } void setFinished() { synchronized (values) { isFinished = true; values.notifyAll(); } } }