in xbean-naming/src/main/java/org/apache/xbean/naming/context/AbstractContext.java [377:441]
protected void removeDeepBinding(Name name, boolean pruneEmptyContexts, boolean removeNotEmptyContext) throws NamingException {
if (name == null) throw new NullPointerException("name is null");
if (name.isEmpty()) {
throw new InvalidNameException("Name is empty");
}
if (name.size() == 1) {
removeBinding(name.get(0), removeNotEmptyContext);
return;
}
if (!pruneEmptyContexts) {
Context context = lookupFinalContext(name);
context.unbind(name.getSuffix(name.size() - 1));
} else {
// we serch the tree for a target context and name to remove
// this is normally the last context in the tree and the final name part, but
// it may be farther up the path if the intervening nodes are empty
Context targetContext = this;
String targetName = name.get(0);
Context currentContext = this;
for (int i = 0; i < name.size(); i++) {
String part = name.get(i);
// empty path parts are not allowed
if (part.length() == 0) {
throw new InvalidNameException("Name part " + i + " is empty: " + name);
}
// update targets
if (getSize(currentContext) > 1) {
targetContext = currentContext;
targetName = part;
}
// Is this the last element in the name?
if (i == name.size() - 1) {
// we're at the end... unbind value
unbind(targetContext, targetName, true);
// all done... this is redundant but makes the code more readable
break;
} else {
Object currentValue = getBinding(currentContext, part);
if (currentValue == null) {
// path not found we are done, but first prune the empty contexts
if (targetContext != currentContext) {
unbind(targetContext, targetName, false);
}
break;
} else {
// the current value must be a context
if (!(currentValue instanceof Context)) {
throw new NotContextException("Expected an instance of context to be bound at " +
part + " but found an instance of " + currentValue.getClass().getName());
}
currentContext = (Context) currentValue;
// now we recurse into the current context
}
}
}
}
}