/*
* Copyright 2007-2010 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*/
package com.sun.sgs.impl.util;
import com.sun.sgs.app.DataManager;
import com.sun.sgs.app.ManagedObject;
import com.sun.sgs.service.DataService;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* A utility class for obtaining an iterator for a set of bound names
* (matching a prefix) in a data service.
*/
public final class BoundNamesUtil {
/** Prevents instantiation. */
private BoundNamesUtil() { }
/**
* Returns an {@code Iterable} that can be used to obtain an
* {@code Iterator} for the set of service bound names matching
* the specified {@code prefix} in the specified {@code
* dataService}. Only names starting with the specified prefix and
* containing additional characters after the prefix will be
* returned. The returned {@code Iterable} is not serializable.
*
* <p>The {@code iterator} method of the returned {@code Iterable}
* returns the result of invoking {@link
* #getServiceBoundNamesIterator getServiceBoundNamesIterator}
* with the specified {@code dataService} and {@code prefix}.
*
* @param dataService a data service
* @param prefix the prefix of service bound names
* @return an {@code Iterable} for the set of service bound names
* matching the {@code prefix}
* @see #getServiceBoundNamesIterator
*/
public static Iterable<String> getServiceBoundNamesIterable(
DataService dataService, String prefix)
{
if (dataService == null || prefix == null) {
throw new NullPointerException("null argument");
}
return new BoundNamesIterable(dataService, prefix);
}
/**
* Returns an {@code Iterator} for the set of service bound names
* matching the specified {@code prefix} in the specified {@code
* dataService}. Only names starting with the specified prefix and
* containing additional characters after the prefix will be
* returned. The returned {@code Iterator} is not serializable.
*
* <p>The {@code remove} method of the returned iterator removes
* the binding of the last name returned by {@code next} by
* invoking {@link DataService#removeServiceBinding
* removeServiceBinding} on the given {@code dataService} passing
* the name.
*
* <p>Note: the {@code remove} method does not remove from the
* data store the {@link ManagedObject} bound to the name. If the
* {@code ManagedObject} needs to be removed, that object should
* be removed by invoking the {@code dataService}'s {@link
* DataManager#removeObject removeObject} method passing the
* {@code ManagedObject} bound to the name.
*
* @param dataService a data service
* @param prefix the prefix of service bound names
* @return an {@code Iterator} for the set of service bound names
* matching the {@code prefix}
*/
public static Iterator<String> getServiceBoundNamesIterator(
DataService dataService, String prefix)
{
if (dataService == null || prefix == null) {
throw new NullPointerException("null argument");
}
return new BoundNamesIterator(dataService, prefix);
}
/* -- other classes -- */
/**
* An {@code Iterable} that is a container for a {@code
* BoundNamesIterator}.
*/
private static class BoundNamesIterable implements Iterable<String> {
/** The data service. */
private final DataService dataService;
/** The prefix for service bound names. */
private final String prefix;
BoundNamesIterable(DataService dataService, String prefix) {
this.dataService = dataService;
this.prefix = prefix;
}
/** {@inheritDoc} */
public Iterator<String> iterator() {
return new BoundNamesIterator(dataService, prefix);
}
}
/**
* An {@code Iterator} for the set of service bound names matching
* the {@code prefix} of the {@code dataService} both specified
* during construction.
*/
private static class BoundNamesIterator implements Iterator<String> {
/** The data service. */
private final DataService dataService;
/** The prefix for service bound names. */
private final String prefix;
/** The key used to look up next service bound name, or null. */
private String key;
/** The key returned by {@code next}, or null. */
private String keyReturnedByNext;
/** The name fetched in the {@code hasNext} method, which
* is only valid if {@code hasNext} returns {@code true}. */
private String nextName;
BoundNamesIterator(DataService dataService, String prefix) {
this.dataService = dataService;
this.prefix = prefix;
this.key = prefix;
}
/** {@inheritDoc} */
public boolean hasNext() {
if (key == null) {
return false;
}
if (nextName != null) {
return true;
}
String name = dataService.nextServiceBoundName(key);
if (name != null && name.startsWith(prefix)) {
nextName = name;
return true;
} else {
key = null;
return false;
}
}
/** {@inheritDoc} */
public String next() {
try {
if (!hasNext()) {
throw new NoSuchElementException();
}
keyReturnedByNext = nextName;
key = nextName;
return keyReturnedByNext;
} finally {
nextName = null;
}
}
/** {@inheritDoc} */
public void remove() {
if (keyReturnedByNext == null) {
throw new IllegalStateException();
}
dataService.removeServiceBinding(keyReturnedByNext);
keyReturnedByNext = null;
}
}
}