/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2007-2009 Sun Microsystems, Inc.
*/
package org.opends.server.admin.server;
import static org.opends.messages.AdminMessages.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import java.util.LinkedList;
import java.util.List;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.Constraint;
import org.opends.server.admin.DecodingException;
import org.opends.server.admin.DefinitionDecodingException;
import org.opends.server.admin.InstantiableRelationDefinition;
import org.opends.server.admin.ManagedObjectDefinition;
import org.opends.server.admin.ManagedObjectPath;
import org.opends.server.admin.OptionalRelationDefinition;
import org.opends.server.admin.SetRelationDefinition;
import org.opends.server.admin.DefinitionDecodingException.Reason;
import org.opends.server.api.ConfigDeleteListener;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.ResultCode;
/**
* An adaptor class which converts {@link ConfigDeleteListener}
* callbacks to {@link ServerManagedObjectDeleteListener} callbacks.
*
* @param <S>
* The type of server configuration handled by the delete
* listener.
*/
final class ConfigDeleteListenerAdaptor<S extends Configuration> extends
AbstractConfigListenerAdaptor implements ConfigDeleteListener {
/**
* The tracer object for the debug logger.
*/
private static final DebugTracer TRACER = getTracer();
// Cached managed object between accept/apply callbacks.
private ServerManagedObject<? extends S> cachedManagedObject;
// The instantiable relation.
private final InstantiableRelationDefinition<?, S> instantiableRelation;
// The set relation.
private final SetRelationDefinition<?, S> setRelation;
// The underlying delete listener.
private final ServerManagedObjectDeleteListener<S> listener;
// The optional relation.
private final OptionalRelationDefinition<?, S> optionalRelation;
// The managed object path of the parent.
private final ManagedObjectPath<?, ?> path;
/**
* Create a new configuration delete listener adaptor for an
* instantiable relation.
*
* @param path
* The managed object path of the parent.
* @param relation
* The instantiable relation.
* @param listener
* The underlying delete listener.
*/
public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path,
InstantiableRelationDefinition<?, S> relation,
ServerManagedObjectDeleteListener<S> listener) {
this.path = path;
this.optionalRelation = null;
this.instantiableRelation = relation;
this.setRelation = null;
this.listener = listener;
this.cachedManagedObject = null;
}
/**
* Create a new configuration delete listener adaptor for an
* optional relation.
*
* @param path
* The managed object path of the parent.
* @param relation
* The optional relation.
* @param listener
* The underlying delete listener.
*/
public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path,
OptionalRelationDefinition<?, S> relation,
ServerManagedObjectDeleteListener<S> listener) {
this.path = path;
this.optionalRelation = relation;
this.instantiableRelation = null;
this.setRelation = null;
this.listener = listener;
this.cachedManagedObject = null;
}
/**
* Create a new configuration delete listener adaptor for an
* set relation.
*
* @param path
* The managed object path of the parent.
* @param relation
* The set relation.
* @param listener
* The underlying delete listener.
*/
public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path,
SetRelationDefinition<?, S> relation,
ServerManagedObjectDeleteListener<S> listener) {
this.path = path;
this.optionalRelation = null;
this.instantiableRelation = null;
this.setRelation = relation;
this.listener = listener;
this.cachedManagedObject = null;
}
/**
* {@inheritDoc}
*/
public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) {
if (optionalRelation != null) {
// Optional managed objects are located directly beneath the
// parent and have a well-defined name. We need to make sure
// that we are handling the correct entry.
ManagedObjectPath<?, ?> childPath = path.child(optionalRelation);
DN expectedDN = DNBuilder.create(childPath);
if (!configEntry.getDN().equals(expectedDN)) {
// Doesn't apply to us.
return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
}
// Cached objects are guaranteed to be from previous acceptable
// callback.
ConfigChangeResult result = listener
.applyConfigurationDelete(cachedManagedObject);
// Now apply post constraint call-backs.
if (result.getResultCode() == ResultCode.SUCCESS) {
ManagedObjectDefinition<?, ?> d = cachedManagedObject
.getManagedObjectDefinition();
for (Constraint constraint : d.getAllConstraints()) {
for (ServerConstraintHandler handler : constraint
.getServerConstraintHandlers()) {
try {
handler.performPostDelete(cachedManagedObject);
} catch (ConfigException e) {
if (debugEnabled()) {
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
}
}
}
}
return result;
}
/**
* {@inheritDoc}
*/
public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
MessageBuilder unacceptableReason) {
DN dn = configEntry.getDN();
AttributeValue av = dn.getRDN().getAttributeValue(0);
String name = av.getValue().toString().trim();
try {
ManagedObjectPath<?, ? extends S> childPath;
if (instantiableRelation != null) {
childPath = path.child(instantiableRelation, name);
} else if (setRelation != null) {
try {
childPath = path.child(setRelation, name);
} catch (IllegalArgumentException e) {
throw new DefinitionDecodingException(setRelation
.getChildDefinition(), Reason.WRONG_TYPE_INFORMATION);
}
} else {
// Optional managed objects are located directly beneath the
// parent and have a well-defined name. We need to make sure
// that we are handling the correct entry.
childPath = path.child(optionalRelation);
DN expectedDN = DNBuilder.create(childPath);
if (!dn.equals(expectedDN)) {
// Doesn't apply to us.
return true;
}
}
ServerManagementContext context = ServerManagementContext.getInstance();
cachedManagedObject = context.decode(childPath, configEntry);
} catch (DecodingException e) {
unacceptableReason.append(e.getMessageObject());
return false;
}
List<Message> reasons = new LinkedList<Message>();
// Enforce any constraints.
boolean isDeleteAllowed = true;
ManagedObjectDefinition<?, ?> d = cachedManagedObject
.getManagedObjectDefinition();
for (Constraint constraint : d.getAllConstraints()) {
for (ServerConstraintHandler handler : constraint
.getServerConstraintHandlers()) {
try {
if (!handler.isDeleteAllowed(cachedManagedObject, reasons)) {
isDeleteAllowed = false;
}
} catch (ConfigException e) {
Message message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e
.getMessageObject());
reasons.add(message);
isDeleteAllowed = false;
}
}
}
// Give up immediately if a constraint violation occurs.
if (!isDeleteAllowed) {
generateUnacceptableReason(reasons, unacceptableReason);
return false;
}
// Let the delete listener decide.
if (listener.isConfigurationDeleteAcceptable(cachedManagedObject,
reasons)) {
return true;
} else {
generateUnacceptableReason(reasons, unacceptableReason);
return false;
}
}
/**
* Get the server managed object delete listener associated with
* this adaptor.
*
* @return Returns the server managed object delete listener
* associated with this adaptor.
*/
ServerManagedObjectDeleteListener<S> getServerManagedObjectDeleteListener() {
return listener;
}
}