/* Copyright (c) 2007, 2008 Bug Labs, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program 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 version 2 for more details (a copy is
* included at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
package com.buglabs.bug.ws.program;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.log.LogService;
import com.buglabs.bug.ws.Activator;
import com.buglabs.services.ws.PublicWSProvider;
import com.buglabs.util.osgi.ConfigAdminUtil;
import com.buglabs.util.xml.XmlNode;
import com.buglabs.util.xml.XmlParser;
/**
* A servlet that interacts with bug's configuration.
*
* @author akravets
*
*/
public class ConfigAdminServlet extends HttpServlet {
private static final long serialVersionUID = -4552308543439876937L;
private ConfigurationAdmin configAdmin;
private boolean isStateSet = false;
/**
* @param context BundleContext
* @param configAdmin ConfigurationAdmin
*/
public ConfigAdminServlet(BundleContext context, ConfigurationAdmin configAdmin) {
this.configAdmin = configAdmin;
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String response = null;
isStateSet = false;
resp.setContentType("text/xml");
try {
response = getConfigurationXml(response);
resp.getWriter().print(response);
} catch (InvalidSyntaxException e) {
Activator.getLog().log(LogService.LOG_ERROR, "Unable to get configuration xml.", e);
resp.sendError(500);
}
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BufferedReader br;
StringBuffer reqStr = null;
String response = "";
resp.setContentType("text/xml");
try {
br = new BufferedReader(req.getReader());
reqStr = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
reqStr.append(line);
}
updateConfiguration(reqStr);
} catch (IOException e) {
response = getErrorDetails(e);
}
resp.getWriter().print(response);
}
/**
* Updates configuration.
*
* @param reqStr
* payload in xml format
* @throws IOException on configadmin error
*/
private void updateConfiguration(StringBuffer reqStr) throws IOException {
XmlNode node = XmlParser.parse(reqStr.toString());
String type = node.getAttribute("type");
if (type.equals("PROPERTY_TYPE_REGULAR")) {
XmlNode child = node.getChild("property");
String pid = child.getAttribute("pid");
String moduleId = child.getAttribute("id");
String newValue = child.getAttribute("newValue");
Configuration configuration = configAdmin.getConfiguration(pid);
Dictionary props = new Hashtable();
// normalize property name
if (pid.indexOf(PublicWSProvider.PACKAGE_ID) != -1 && moduleId.indexOf("enabled") != -1) {
moduleId = moduleId.substring(moduleId.indexOf("-") + 1, moduleId.length());
props.put(moduleId, new Boolean(newValue));
} else {
props.put(moduleId, newValue);
}
configuration.update(props);
} else if (type.equals("PROPERTY_TYPE_APP_STATE")) {
XmlNode child = node.getChild("property");
String pid = child.getAttribute("pid");
String applicationName = child.getAttribute("applicationName");
String newValue = child.getAttribute("newValue");
Configuration configuration = configAdmin.getConfiguration(pid);
Dictionary properties = ConfigAdminUtil.getPropertiesSafely(configuration);
Map appState = (Map) properties.get("app.state");
String bundlePath = (String) properties.get("app.bundle.path");
String keyByAppName = bundlePath + File.separator + applicationName + ".jar";
appState.remove(keyByAppName);
appState.put(new File(keyByAppName), new Integer(newValue));
properties.put("app.state", appState);
configuration.update(properties);
}
}
/**
*
* @param response
* @return Returns XML representing current state of all
* {@link Configuration}s for the bug
* @throws IOException
* @throws InvalidSyntaxException
*/
private String getConfigurationXml(String response) throws IOException, InvalidSyntaxException {
Configuration[] configuration = configAdmin.listConfigurations(null);
XmlNode configurationsNode = new XmlNode("configurations");
if (configuration == null) {
return configurationsNode.toString();
}
for (int i = 0; i < configuration.length; i++) {
XmlNode configurationNode = new XmlNode("configuration");
configurationNode.addAttribute("pid", configuration[i].getPid());
Dictionary properties = ConfigAdminUtil.getPropertiesSafely(configuration[i]);
Enumeration keys = properties.keys();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
Object value = properties.get(key);
XmlNode property = new XmlNode("property");
if (key.equals(Constants.SERVICE_PID)) {
continue;
}
if (key.equals("app.state")) {
if (!isStateSet) {
createAppStateProperties(configurationNode, value);
isStateSet = true;
continue;
}
}
property.addAttribute("name", key);
property.addAttribute("value", String.valueOf(value));
configurationNode.addChild(property);
}
configurationsNode.addChild(configurationNode);
}
return configurationsNode.toString();
}
/**
* @param configurationNode config xml
* @param map
*/
private void createAppStateProperties(XmlNode configurationNode, Object map) {
XmlNode property = new XmlNode("property");
property.addAttribute("name", "app.state");
for (Iterator it = ((Map) map).entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
String app = ((File) entry.getKey()).toString();
String state = ((Integer) entry.getValue()).toString();
XmlNode childProperty = new XmlNode("applicationState");
childProperty.addAttribute("appName", app.substring(app.lastIndexOf(File.separator) + 1, app.indexOf(".jar")));
childProperty.addAttribute("state", state);
property.addChild(childProperty);
}
configurationNode.addChild(property);
}
/**
* @param e exception
* @return Error message
*/
private String getErrorDetails(Exception e) {
StringWriter wr = new StringWriter();
e.printStackTrace(new PrintWriter(wr));
return "<error>" + wr.toString() + "</error>";
}
}