/**
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed 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.geronimo.system.configuration;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.management.ObjectName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.geronimo.gbean.GBeanLifecycle;
import org.apache.geronimo.kernel.Kernel;
import org.apache.geronimo.kernel.lifecycle.LifecycleListener;
import org.apache.geronimo.kernel.lifecycle.LifecycleAdapter;
import org.apache.geronimo.kernel.config.ConfigurationInfo;
import org.apache.geronimo.kernel.config.NoSuchStoreException;
import org.apache.geronimo.kernel.config.PersistentConfigurationList;
import org.apache.geronimo.kernel.config.ConfigurationManager;
import org.apache.geronimo.kernel.management.State;
import org.apache.geronimo.system.serverinfo.ServerInfo;
/**
* GBean that saves a list of configurations, for example to allow
* a server to restart automatically.
*
* @version $Rev$ $Date$
*/
public class FileConfigurationList implements GBeanLifecycle, PersistentConfigurationList {
private static final Log log = LogFactory.getLog(PersistentConfigurationList.class);
/**
* The kernel for which we are persisting the configuration list.
*/
private final Kernel kernel;
/**
* The ConfigurationManager for the kernel
*/
private final ConfigurationManager configurationManager;
/**
* Used to resolve the location of the configuration file.
*/
private final ServerInfo serverInfo;
/**
* The file to which we are saving the configurations. This is relative to the
* server base directory in server info.
*/
private final String configFile;
/**
* Is the kernel fully started? Until the kernel is fully started, we will
* not write out a new configuration list. This stops a crtl^c during start up
* from completely overwriting the startup file with no content.
*/
private boolean kernelFullyStarted = false;
/**
* The actual absolute file where we write the configuration list.
*/
private File configList;
/**
* Listener to make this GBean save every time a configuration is started
* or stopped.
*/
private LifecycleListener listener;
public FileConfigurationList(Kernel kernel, ServerInfo serverInfo, ConfigurationManager configurationManager, String configDir) {
this.kernel = kernel;
this.configurationManager = configurationManager;
this.serverInfo = serverInfo;
this.configFile = configDir;
this.listener = new LifecycleAdapter() {
public void stopped(ObjectName objectName) {
if(kernelFullyStarted && FileConfigurationList.this.kernel.isRunning()) {
doSave();
}
}
public void running(ObjectName objectName) {
if(kernelFullyStarted && FileConfigurationList.this.kernel.isRunning()) {
doSave();
}
}
private void doSave() {
try {
save();
} catch (IOException e) {
log.error("Unable to save list of running configurations", e);
}
}
};
}
public void doStart() throws Exception {
configList = serverInfo.resolve(configFile);
File parent = configList.getParentFile();
if (!parent.isDirectory()) {
if (!parent.mkdirs()) {
throw new IOException("Unable to create directory for list:" + parent);
}
}
kernel.getLifecycleMonitor().addLifecycleListener(listener, new ObjectName("geronimo.config:*"));
}
public void doStop() throws Exception {
doFail();
}
public void doFail() {
kernel.getLifecycleMonitor().removeLifecycleListener(listener);
configList = null;
}
public synchronized boolean isKernelFullyStarted() {
return kernelFullyStarted;
}
public synchronized void setKernelFullyStarted(boolean kernelFullyStarted) {
this.kernelFullyStarted = kernelFullyStarted;
}
public synchronized void save() throws IOException {
if (!kernelFullyStarted) {
log.debug("Configuration list was not saved. Kernel was never fully started.");
return;
}
if (!kernel.isRunning()) {
log.debug("Configuration list was not saved. Kernel is shutting down.");
return;
}
BufferedWriter writer = new BufferedWriter(new FileWriter(configList));
try {
List stores = configurationManager.listStores();
for (Iterator i = stores.iterator(); i.hasNext();) {
ObjectName storeName = (ObjectName) i.next();
List configList = configurationManager.listConfigurations(storeName);
for (Iterator j = configList.iterator(); j.hasNext();) {
ConfigurationInfo info = (ConfigurationInfo) j.next();
if (info.getState() == State.RUNNING) {
writer.write(info.getConfigID().toString());
writer.newLine();
}
}
}
writer.close();
} catch (NoSuchStoreException e) {
writer.close();
configList.delete();
}
log.info("Saved running configuration list");
}
public List restore() throws IOException {
FileReader fileReader;
try {
fileReader = new FileReader(configList);
} catch (FileNotFoundException e) {
return Collections.EMPTY_LIST;
}
BufferedReader reader = new BufferedReader(fileReader);
try {
List configs = new ArrayList();
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if(line.equals("") || line.startsWith("#")) {
continue;
}
try {
configs.add(new URI(line));
} catch (URISyntaxException e) {
throw new IOException("Invalid URI in config list: " + line);
}
}
return configs;
} finally {
reader.close();
}
}
public void addConfiguration(String configName) {
try {
save();
} catch (IOException e) {
log.warn("Couldn't save while adding " + configName, e);
}
}
public void removeConfiguration(String configName) {
try {
save();
} catch (IOException e) {
log.warn("Couldnt save while removing " + configName, e);
}
}
public static final GBeanInfo GBEAN_INFO;
static {
GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(FileConfigurationList.class, "PersistentConfigurationList");
infoFactory.addInterface(PersistentConfigurationList.class);
infoFactory.addAttribute("kernel", Kernel.class, false);
infoFactory.addAttribute("kernelFullyStarted", boolean.class, false);
infoFactory.addReference("ServerInfo", ServerInfo.class, "GBean");
infoFactory.addReference("ConfigurationManager", ConfigurationManager.class, "ConfigurationManager");
infoFactory.addAttribute("configFile", String.class, true);
infoFactory.setConstructor(new String[]{"kernel", "ServerInfo", "ConfigurationManager", "configFile"});
GBEAN_INFO = infoFactory.getBeanInfo();
}
public static GBeanInfo getGBeanInfo() {
return GBEAN_INFO;
}
}