blob: 2e1e74009251ba56c90d38e76661d562b34329de [file] [log] [blame]
/*
* 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.felix.ipojo;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;
import org.apache.felix.ipojo.metadata.Element;
import org.osgi.framework.BundleContext;
/**
* The handler manager manages an handler instance.
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class HandlerManager extends InstanceManager {
/**
* The internal handler object.
* Immutable once set.
*/
private Handler m_handler;
/**
* Creates a handler manager.
* @param factory the handler factory
* @param context the bundle context
* @param handlers the handler array
*/
public HandlerManager(ComponentFactory factory, BundleContext context, HandlerManager[] handlers) {
super(factory, context, handlers);
}
/**
* Gets the contained handler object.
* If not already created it creates the object.
* @return the handler object.
*/
public Handler getHandler() {
if (m_handler == null) {
createHandlerObject();
}
return m_handler;
}
/**
* Creates and initializes the handler object.
* @param instance the component instance on which the handler will be attached.
* @param metadata the component metadata.
* @param configuration the instance configuration.
* @throws ConfigurationException if the handler configuration failed.
*/
public void init(ComponentInstance instance, Element metadata, Dictionary configuration) throws ConfigurationException {
createHandlerObject();
m_handler.setFactory(instance.getFactory());
m_handler.attach(instance);
m_handler.configure(metadata, configuration);
}
/**
* Creates the handler object.
* This method does nothing if the object is already created.
* This method does not need locking protocol as only one thread (the creator thread) can create an instance.
*/
private void createHandlerObject() {
if (m_handler != null) { return; }
m_handler = (Handler) createPojoObject();
}
/**
* Creates an instance of the content.
* This method needs to be called once only for singleton provided service.
* This methods call the {@link InstanceManager#createObject()} method, and adds
* the created object to the {@link InstanceManager#m_pojoObjects} list. Then,
* it calls the {@link PrimitiveHandler#onCreation(Object)} methods on attached
* handlers.
* @return a new instance or <code>null</code> if an error occurs during the
* creation.
*/
public Object createPojoObject() {
Object instance = createObject();
// Add the new instance in the instance list.
synchronized (this) {
if (m_pojoObjects == null) {
m_pojoObjects = new ArrayList(1);
}
m_pojoObjects.add(instance);
}
//Do not call onCreation, this will be done in the start method.
return instance;
}
/**
* Starts the instance manager.
*/
public void start() {
synchronized (this) {
if (m_state != STOPPED) {
return; // Instance already started
} else {
m_state = -2; // Temporary starting state, avoiding concurrent starts.
}
}
// Start attached handler.
for (int i = 0; i < m_handlers.length; i++) {
m_handlers[i].addInstanceStateListener(this);
m_handlers[i].start();
}
// Call the onCreation method.
for (int i = 0; i < m_handlers.length; i++) {
((PrimitiveHandler) m_handlers[i].getHandler()).onCreation(m_handler);
}
m_handler.start(); // Call the handler start method, the instance might be invalid.
for (int i = 0; i < m_handlers.length; i++) {
if (!m_handlers[i].getHandler().isValid()) {
setState(INVALID);
return;
}
}
if (m_handler.getValidity()) {
setState(VALID);
} else {
setState(INVALID);
}
// Now, the state is necessary different from the temporary state.
}
/**
* Stops the instance manager.
*/
public void stop() {
synchronized (this) {
if (m_state == STOPPED) {
return; // Instance already stopped
} else {
m_state = -2; // Temporary state avoiding concurrent stopping.
}
}
setState(INVALID);
if (m_handler != null) {
m_handler.stop();
}
// Stop all the handlers
for (int i = m_handlers.length - 1; i > -1; i--) {
m_handlers[i].removeInstanceStateListener(this);
m_handlers[i].stop();
}
List listeners = null;
synchronized (this) {
m_state = STOPPED;
if (m_listeners != null) {
listeners = new ArrayList(m_listeners); // Stack confinement.
}
}
if (listeners != null) {
for (int i = 0; i < listeners.size(); i++) {
((InstanceStateListener) listeners.get(i)).stateChanged(this, STOPPED);
}
}
}
/**
* Disposes the instance.
* @see org.apache.felix.ipojo.ComponentInstance#dispose()
*/
public void dispose() {
super.dispose();
m_handler = null;
}
/**
* Kills the current instance.
* Only the factory of this instance can call this method.
*/
protected void kill() {
super.dispose();
m_handler = null;
}
/**
* State Change listener callback.
* This method is notified at each time a plugged handler becomes invalid.
* @param instance the changing instance
* @param newState the new state
* @see org.apache.felix.ipojo.InstanceStateListener#stateChanged(org.apache.felix.ipojo.ComponentInstance, int)
*/
public void stateChanged(ComponentInstance instance, int newState) {
int state;
synchronized (this) {
if (m_state <= STOPPED) {
return;
} else {
state = m_state; // Stack confinement
}
}
// Update the component state if necessary
if (newState == INVALID && state == VALID) {
// Need to update the state to UNRESOLVED
setState(INVALID);
return;
}
if (newState == VALID && state == INVALID) {
// An handler becomes valid => check if all handlers are valid
if (!m_handler.getValidity()) { return; }
for (int i = 0; i < m_handlers.length; i++) {
if (m_handlers[i].getState() != VALID) { return; }
}
setState(VALID);
return;
}
}
}