flex.management.ManageableComponent Maven / Gradle / Ivy
/*
* 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 flex.management;
import java.util.Date;
import flex.messaging.FlexComponent;
import flex.messaging.config.ConfigMap;
import flex.messaging.config.ConfigurationException;
import flex.messaging.log.Log;
/**
* An abstract base class that implements the Manageable
and FlexComponent
interfaces.
* This is an excellent starting point for a server component that may be instantiated, initialized, started and
* stopped, as well as exposing an optional management interface via a peer MBean.
* Support for changing component properties while the component is
* started should be determined on a per-property basis, and the started property is volatile to ensure consistent
* reads of the start state of the component across threads. This class performs no synchronization and is not safe for modification by multiple concurrent threads
* in the absence of external synchronization.
*
*/
public abstract class ManageableComponent implements Manageable, FlexComponent
{
//--------------------------------------------------------------------------
//
// Protected Static Constants
//
//--------------------------------------------------------------------------
/**
* Error code for attempting to change a property after starting.
*/
protected static final int PROPERTY_CHANGE_AFTER_STARTUP = 11115;
/**
* Error code to alert the user that a required component property is null.
*/
protected static final int NULL_COMPONENT_PROPERTY = 11116;
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructs a ManageableComponent
instance, specifying
* whether to enable management.
* Enabling management will trigger the creation of a peer MBean that exposes the
* management interface for this component.
*
* @param enableManagement true
to enable management, false
to disable
* management.
*/
public ManageableComponent(boolean enableManagement)
{
setManaged(enableManagement);
}
//--------------------------------------------------------------------------
//
// Public Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// control
//----------------------------------
/**
* The peer MBean of the ManageableComponent
that exposes a management interface.
*/
protected BaseControl control;
/**
* (non-JavaDoc)
* @see Manageable#getControl()
*/
public BaseControl getControl()
{
return control;
}
/**
* (non-JavaDoc)
* @see Manageable#setControl(BaseControl)
*/
public void setControl(BaseControl control)
{
this.control = control;
}
//----------------------------------
// id
//----------------------------------
/**
* The internal id value of the ManageableComponent
.
*/
protected String id;
/**
* Returns the id of the ManageableComponent
.
*
* @return The id of the ManageableComponent
.
*/
public String getId()
{
return id;
}
/**
* Sets the id of the ManageableComponent
. The id cannot be
* null and it cannot be changed after startup.
*
* @param id The id of the ManageableComponent
.
*/
public void setId(String id)
{
if (isStarted())
{
blockAssignmentWhileStarted("id");
}
if (id == null)
{
// Id of a component cannot be null.
blockNullAssignment("id");
}
this.id = id;
}
//----------------------------------
// managed
//----------------------------------
/**
* The internal managed flag of the ManageableComponent
.
*/
protected volatile boolean managed;
/**
* (non-JavaDoc)
* @see Manageable#isManaged()
*/
public boolean isManaged()
{
return managed;
}
/**
* Enables or disables management for the component. Management cannot be
* changed once the component is started and management cannot be
* true
if the parent of the component is not managed.
*
* @param enableManagement true
to enable management, false
to disable management.
*/
public void setManaged(boolean enableManagement)
{
if (isStarted() && control != null)
{
blockAssignmentWhileStarted("managed");
}
if (enableManagement && parent != null && !parent.isManaged())
{
if (Log.isWarn())
{
Log.getLogger(getLogCategory()).warn("Component: '" + id + "' cannot be managed" +
" since its parent is unmanaged.");
}
return;
}
managed = enableManagement;
}
//----------------------------------
// parent
//----------------------------------
/**
* The internal reference to the parent component (if any) of the ManageableComponent
.
*/
protected Manageable parent;
/**
* Returns the parent of the component.
*
* @return The parent of the component.
*/
public Manageable getParent()
{
return parent;
}
/**
* Sets the parent of the component. The parent cannot be changed
* after component startup and it cannot be null.
*
* @param parent The parent of the component.
*/
public void setParent(Manageable parent)
{
if (isStarted())
{
blockAssignmentWhileStarted("parent");
}
if (parent == null)
{
// Parent of a component cannot be null.
blockNullAssignment("parent");
}
if (!parent.isManaged() && isManaged())
{
if (Log.isWarn())
{
Log.getLogger(getLogCategory()).warn("Component: '" + id + "' cannot be managed" +
" since its parent is unmanaged.");
}
setManaged(false);
}
this.parent = parent;
}
//----------------------------------
// started
//----------------------------------
/**
* The internal started flag of the ManageableComponent
.
*/
protected volatile boolean started;
/**
* Returns if the component is started or not.
*
* @return true
if the component is started.
*/
public boolean isStarted()
{
return started;
}
/**
* Sets if the component is started.
*
* @param started true if the component is started.
*/
protected void setStarted(boolean started)
{
if (this.started != started)
{
this.started = started;
if (started && control != null)
{
control.setStartTimestamp(new Date());
}
}
}
//----------------------------------
// valid
//----------------------------------
/**
* The internal valid flag of the ManageableComponent
.
*/
protected boolean valid;
/**
* Returns if the component is valid.
*
* @return true
if the component is valid.
*/
public boolean isValid()
{
return valid;
}
/**
* Sets if the component is valid.
*
* @param valid true if the comoponent is valid.
*/
protected void setValid(boolean valid)
{
this.valid = valid;
}
//----------------------------------
// logCategory
//----------------------------------
/**
* Returns the log category of the component. Subclasses must provide an
* implementation that returns their desired log category.
*
* @return The log category of the component.
*/
protected abstract String getLogCategory();
//--------------------------------------------------------------------------
//
// Public Methods
//
//--------------------------------------------------------------------------
/**
* Invoked to initialize the ManageableComponent
.
* This base implementation calls setId()
passing the provided
* id and ignores the properties map argument.
* Subclasses should call super.initialize()
.
*
* @param id Id of the ManageableComponent
.
* @param properties Properties for the ManageableComponent
.
*/
public void initialize(String id, ConfigMap properties)
{
setId(id);
}
/**
* Validates and starts the component.
*
* Subclasses should call super.start()
.
*/
public void start()
{
validate();
setStarted(true);
}
/**
* Invalidates and stops the component.
*
* Subclasses should call super.stop()
.
*/
public void stop()
{
invalidate();
setStarted(false);
}
//--------------------------------------------------------------------------
//
// Protocted Methods
//
//--------------------------------------------------------------------------
/**
* Convenience method that may be used to generate and throw an Exception for an attempt to set the specified property if the
* component is started.
*
* @param propertyName The name of the property being incorrectly assigned; included in the Exception message.
*/
protected void blockAssignmentWhileStarted(String propertyName)
{
ConfigurationException ce = new ConfigurationException();
ce.setMessage(PROPERTY_CHANGE_AFTER_STARTUP, new Object[]{propertyName});
throw ce;
}
/**
* Convenience method that may be used to generate and throw an Exception for an attempt to assign a null value to a property that
* requires non-null values.
*
* @param propertyName The name of the property being incorrectly assigned.
*/
protected void blockNullAssignment(String propertyName)
{
ConfigurationException ce = new ConfigurationException();
ce.setMessage(NULL_COMPONENT_PROPERTY, new Object[]{propertyName});
throw ce;
}
/**
* Invoked from within the stop()
method to invalidate the component as part of shutdown.
* This base implementation sets the valid property to false.
* Subclasses should call super.invalidate()
.
*/
protected void invalidate()
{
setValid(false);
}
/**
* Hook method invoked from within the start()
method to validate that the component is in a
* startable state.
* This base implementation validates the component by ensuring it has an id and a parent and then sets
* the valid property to true.
* If the component is not in a valid, startable state an Exception is thrown.
* Subclasses should call super.validate()
.
*/
protected void validate()
{
if (getId() == null)
{
// Id of a component cannot be null.
blockNullAssignment("id");
}
if (getParent() == null)
{
// Parent of a component cannot be null.
blockNullAssignment("parent");
}
setValid(true);
}
}