/*
* 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.kernel;
import com.sun.sgs.app.ChannelManager;
import com.sun.sgs.app.DataManager;
import com.sun.sgs.app.ManagerNotFoundException;
import com.sun.sgs.app.TaskManager;
import com.sun.sgs.impl.sharedutil.LoggerWrapper;
import com.sun.sgs.kernel.ComponentRegistry;
import com.sun.sgs.service.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.MissingResourceException;
import java.util.logging.Logger;
import java.util.logging.Level;
/**
* This is the implementation of <code>KernelAppContext</code> used by
* the kernel to manage the context of a single application. It knows
* the name of an application, its available managers, and its backing
* services.
*
* FIXME: the context should check that it isn't shutdown before
* handing out services and managers
*/
class KernelContext {
// logger for this class
private static final LoggerWrapper logger =
new LoggerWrapper(Logger.getLogger(KernelContext.class.getName()));
// the application's name
private final String applicationName;
// the managers available in this context
protected final ComponentRegistry managerComponents;
// the services used in this context
protected final ComponentRegistry serviceComponents;
// the three standard managers, which are cached since they are used
// extremely frequently
private final ChannelManager channelManager;
private final DataManager dataManager;
private final TaskManager taskManager;
/**
* Creates an instance of <code>KernelContext</code> based on the
* components that have already been collected in another instance.
*
* @param context the existing <code>KernelContext</code> to use as a
* source of components
*/
KernelContext(KernelContext context) {
this(context.applicationName, context.serviceComponents,
context.managerComponents);
}
/**
* Creates an instance <code>KernelContext</code> with the given name
* and components. This is used by sub-classes to create an instance
* that can be provided components as needed by adding to the provided
* <code>ComponentRegistry</code> instances.
*
* @param applicationName the name of the application represented by
* this context
* @param serviceComponents the services available in this context
* @param managerComponents the managers available in this context
*/
protected KernelContext(String applicationName,
ComponentRegistry serviceComponents,
ComponentRegistry managerComponents) {
this.applicationName = applicationName;
this.serviceComponents = serviceComponents;
this.managerComponents = managerComponents;
// pre-fetch the three standard managers...if any of them isn't
// present then we're running without an application and with a
// sub-set of services, so just set that manager to null
ChannelManager cm;
try {
cm = managerComponents.getComponent(ChannelManager.class);
} catch (MissingResourceException mre) {
cm = null;
}
channelManager = cm;
DataManager dm;
try {
dm = managerComponents.getComponent(DataManager.class);
} catch (MissingResourceException mre) {
dm = null;
}
dataManager = dm;
TaskManager tm;
try {
tm = managerComponents.getComponent(TaskManager.class);
} catch (MissingResourceException mre) {
tm = null;
}
taskManager = tm;
}
/**
* Returns the <code>ChannelManager</code> used in this context.
*
* @return the context's <code>ChannelManager</code>
*/
ChannelManager getChannelManager() {
if (channelManager == null) {
throw new ManagerNotFoundException("this application is running " +
"without a ChannelManager");
}
return channelManager;
}
/**
* Returns the <code>DataManager</code> used in this context.
*
* @return the context's <code>DataManager</code>
*/
DataManager getDataManager() {
if (dataManager == null) {
throw new ManagerNotFoundException("this application is running " +
"without a DataManager");
}
return dataManager;
}
/**
* Returns the <code>TaskManager</code> used in this context.
*
* @return the context's <code>TaskManager</code>
*/
TaskManager getTaskManager() {
if (taskManager == null) {
throw new ManagerNotFoundException("this application is running " +
"without a TaskManager");
}
return taskManager;
}
/**
* Returns a manager based on the given type. If the manager type is
* unknown, or if there is more than one manager of the given type,
* <code>ManagerNotFoundException</code> is thrown. This may be used
* to find any available manager, including the three standard
* managers.
*
* @param type the <code>Class</code> of the requested manager
*
* @return the requested manager
*
* @throws ManagerNotFoundException if there wasn't exactly one match to
* the requested type
*/
<T> T getManager(Class<T> type) {
try {
return managerComponents.getComponent(type);
} catch (MissingResourceException mre) {
throw new ManagerNotFoundException("couldn't find manager: " +
type.getName());
}
}
/**
* Returns a <code>Service</code> based on the given type. If the type is
* unknown, or if there is more than one <code>Service</code> of the
* given type, <code>MissingResourceException</code> is thrown. This is
* the only way to resolve service components directly, and should be
* used with care, as <code>Service</code>s should not be resolved and
* invoked directly outside of a transactional context.
*
* @param type the <code>Class</code> of the requested <code>Service</code>
*
* @return the requested <code>Service</code>
*
* @throws MissingResourceException if there wasn't exactly one match to
* the requested type
*/
<T extends Service> T getService(Class<T> type) {
return serviceComponents.getComponent(type);
}
/**
* Notifies all included Services that the system is now ready.
*
* @throws Exception if there is any failure during notification
*/
void notifyReady() throws Exception {
for (Object service : serviceComponents) {
Service s = (Service) service;
s.ready();
if (logger.isLoggable(Level.CONFIG)) {
logger.log(Level.CONFIG, "The {0} is ready", s.getName());
}
}
}
/**
* Shut down all the service components in the reverse order that
* they were added.
*/
void shutdownServices() {
// reverse the list of services
ArrayList<Object> list = new ArrayList<Object>();
for (Object service : serviceComponents) {
list.add(service);
}
Collections.reverse(list);
for (Object service : list) {
((Service) service).shutdown();
}
}
/**
* Returns a unique representation of this context, in this case the
* name of the application.
*
* @return a <code>String</code> representation of the context
*/
public String toString() {
return applicationName;
}
}