blob: 315138901ae4f3957988828249c76b8392d894b7 [file] [log] [blame]
package org.apache.felix.ipojo.webconsole;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.Factory;
import org.apache.felix.ipojo.HandlerFactory;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Instantiate;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.Requires;
import org.apache.felix.ipojo.annotations.ServiceProperty;
import org.apache.felix.ipojo.architecture.Architecture;
import org.apache.felix.ipojo.architecture.PropertyDescription;
import org.apache.felix.webconsole.AbstractWebConsolePlugin;
import org.apache.felix.webconsole.DefaultVariableResolver;
import org.apache.felix.webconsole.WebConsoleUtil;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@Component(immediate=true)
@Provides
@Instantiate
public class IPOJOPlugin extends AbstractWebConsolePlugin {
private static final String CSS[] = { "/res/ui/bundles.css" , "/iPOJO_2/res/ui/ipojo.css" }; // TODO Change
private final String INSTANCES;
private final String FACTORIES;
private final String HANDLERS;
private final String FACTORY_DETAILS;
/**
* Label used by the web console.
*/
@ServiceProperty(name = "felix.webconsole.label")
private String m_label = "iPOJO_2"; // TODO CHANGE
/**
* Title used by the web console.
*/
@ServiceProperty(name = "felix.webconsole.title")
private String m_title = "iPOJO_2"; // TODO CHANGE
@ServiceProperty(name= "felix.webconsole.css")
protected String[] m_css = CSS;
/**
* List of available Architecture service.
*/
@Requires(optional = true, specification = "org.apache.felix.ipojo.architecture.Architecture")
private List<Architecture> m_archs;
/**
* List of available Factories.
*/
@Requires(optional = true, specification = "org.apache.felix.ipojo.Factory")
private List<Factory> m_factories;
/**
* List of available Handler Factories.
*/
@Requires(optional = true, specification = "org.apache.felix.ipojo.HandlerFactory")
private List<HandlerFactory> m_handlers;
public IPOJOPlugin() {
INSTANCES = readTemplateFile(this.getClass(), "/res/instances.html" );
FACTORIES = readTemplateFile(this.getClass(), "/res/factories.html" );
HANDLERS = readTemplateFile(this.getClass(), "/res/handlers.html" );
FACTORY_DETAILS = readTemplateFile(this.getClass(), "/res/factory.html" );
}
private final String readTemplateFile(final Class clazz,
final String templateFile) {
InputStream templateStream = getClass().getResourceAsStream(
templateFile);
if (templateStream != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] data = new byte[1024];
try {
int len = 0;
while ((len = templateStream.read(data)) > 0) {
baos.write(data, 0, len);
}
return baos.toString("UTF-8");
} catch (IOException e) {
// don't use new Exception(message, cause) because cause is 1.4+
throw new RuntimeException("readTemplateFile: Error loading "
+ templateFile + ": " + e);
} finally {
try {
templateStream.close();
} catch (IOException e) {
/* ignore */
}
}
}
// template file does not exist, return an empty string
log("readTemplateFile: File '" + templateFile
+ "' not found through class " + clazz);
return "";
}
@Override
protected void renderContent(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// get request info from request attribute
final RequestInfo reqInfo = getRequestInfo(request);
// prepare variables
DefaultVariableResolver vars = ( ( DefaultVariableResolver ) WebConsoleUtil.getVariableResolver( request ) );
System.out.println("Render content for " + request.getPathInfo());
if (reqInfo.instances) {
if (reqInfo.name == null) {
response.getWriter().print( INSTANCES );
} else {
// TODO
}
} else if (reqInfo.factories) {
if (reqInfo.name == null) {
response.getWriter().print( FACTORIES );
} else {
vars.put("name", reqInfo.name);
response.getWriter().print( FACTORY_DETAILS );
}
} else if (reqInfo.handlers) {
response.getWriter().print( HANDLERS );
} else {
// Default
response.getWriter().print( INSTANCES );
}
}
private void renderAllInstances(PrintWriter pw) {
try {
JSONObject resp = new JSONObject();
resp.put("count", m_archs.size());
resp.put("valid_count", getValidCount());
resp.put("invalid_count", getInvalidCount());
JSONArray instances = new JSONArray();
for (Architecture arch : m_archs) {
JSONObject instance = new JSONObject();
instance.put("name", arch.getInstanceDescription().getName());
instance.put("factory", arch.getInstanceDescription().getComponentDescription().getName());
instance.put("state", getInstanceState(arch.getInstanceDescription().getState()));
instances.put(instance);
}
resp.put("data", instances);
pw.print(resp.toString());
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void renderAllFactories(PrintWriter pw) {
try {
JSONObject resp = new JSONObject();
resp.put("count", m_factories.size());
resp.put("valid_count", getValidFactoriesCount());
resp.put("invalid_count", getInvalidFactoriesCount());
JSONArray factories = new JSONArray();
for (Factory factory : m_factories) {
String version = factory.getVersion();
String name = factory.getName();
String state = getFactoryState(factory.getState());
String bundle = factory.getBundleContext().getBundle().getSymbolicName()
+ " (" + factory.getBundleContext().getBundle().getBundleId() + ")";
JSONObject fact = new JSONObject();
fact.put("name", name);
if (version != null) {
fact.put("version", version);
}
fact.put("bundle", bundle);
fact.put("state", state);
factories.put(fact);
}
resp.put("data", factories);
pw.print(resp.toString());
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void renderAllHandlers(PrintWriter pw) {
try {
JSONObject resp = new JSONObject();
resp.put("count", m_handlers.size());
resp.put("valid_count", getValidHandlersCount());
resp.put("invalid_count", getInvalidHandlersCount());
JSONArray factories = new JSONArray();
for (HandlerFactory factory : m_handlers) {
String version = factory.getVersion();
String name = factory.getHandlerName();
String state = getFactoryState(factory.getState());
String bundle = factory.getBundleContext().getBundle().getSymbolicName()
+ " (" + factory.getBundleContext().getBundle().getBundleId() + ")";
JSONObject fact = new JSONObject();
fact.put("name", name);
if (version != null) {
fact.put("version", version);
}
fact.put("bundle", bundle);
fact.put("state", state);
fact.put("type", factory.getType());
if (! factory.getMissingHandlers().isEmpty()) {
fact.put("missing", factory.getMissingHandlers().toString());
}
factories.put(fact);
}
resp.put("data", factories);
pw.print(resp.toString());
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void renderFactoryDetail(PrintWriter pw, String name) {
System.out.println("Render factory detail for " + name);
// Find the factory
Factory factory = null;
for (Factory fact : m_factories) {
if (fact.getName().equals(name)) {
factory = fact;
}
}
if (factory == null) {
// TODO Error management
System.err.println("factory " + name + " not found");
return;
}
try {
JSONObject resp = new JSONObject();
resp.put("count", m_factories.size());
resp.put("valid_count", getValidFactoriesCount());
resp.put("invalid_count", getInvalidFactoriesCount());
// Factory object
JSONObject data = new JSONObject();
data.put("name", factory.getName());
data.put("state", getFactoryState(factory.getState()));
String bundle = factory.getBundleContext().getBundle().getSymbolicName()
+ " (" + factory.getBundleContext().getBundle().getBundleId() + ")";
data.put("bundle", bundle);
if (factory.getComponentDescription().getprovidedServiceSpecification().length != 0) {
JSONArray services = new JSONArray
(Arrays.asList(factory.getComponentDescription().getprovidedServiceSpecification()));
data.put("services", services);
}
PropertyDescription[] props = factory.getComponentDescription().getProperties();
if (props != null && props.length != 0) {
JSONArray properties = new JSONArray();
for (int i = 0; i < props.length; i++) {
JSONObject prop = new JSONObject();
prop.put("name", props[i].getName());
prop.put("type", props[i].getType());
prop.put("mandatory", props[i].isMandatory());
prop.put("immutable", props[i].isImmutable());
if (props[i].getValue() != null) {
prop.put("value", props[i].getValue());
}
properties.put(prop);
}
data.put("properties", properties);
}
if (! factory.getRequiredHandlers().isEmpty()) {
JSONArray req = new JSONArray
(factory.getRequiredHandlers());
data.put("requiredHandlers", req);
}
if (! factory.getMissingHandlers().isEmpty()) {
JSONArray req = new JSONArray
(factory.getMissingHandlers());
data.put("missingHandlers", req);
}
List instances = getInstanceList(name);
if (! instances.isEmpty()) {
JSONArray req = new JSONArray(instances);
data.put("instances", req);
}
data.put("architecture", factory.getDescription().toString());
resp.put("data", data);
pw.print(resp.toString());
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
final RequestInfo reqInfo = new RequestInfo(request);
if ( reqInfo.extension.equals("json") )
{
response.setContentType( "application/json" );
//response.setCharacterEncoding( "UTF-8" );
if (reqInfo.instances) {
if (reqInfo.name == null) {
this.renderAllInstances(response.getWriter());
return;
} else {
// TODO
return;
}
}
if (reqInfo.factories) {
if (reqInfo.name == null) {
this.renderAllFactories(response.getWriter());
return;
} else {
System.out.println("Render details for " + reqInfo.name);
this.renderFactoryDetail(response.getWriter(), reqInfo.name);
return;
}
}
if (reqInfo.handlers) {
this.renderAllHandlers(response.getWriter());
}
// nothing more to do
return;
}
super.doGet( request, response );
}
public URL getResource(String path) {
if (path.contains("/res/ui/")) {
return this.getClass().getResource(
path.substring(m_label.length() + 1));
}
return null;
}
/**
* Gets the number of valid instances.
* @return the number of valid instances.
*/
private int getValidCount() {
int i = 0;
for (Architecture a : m_archs) { // Cannot be null, an empty list is returned.
if (a.getInstanceDescription().getState() == ComponentInstance.VALID) {
i ++;
}
}
return i;
}
/**
* Gets the number of invalid instances.
* @return the number of invalid instances.
*/
private int getInvalidCount() {
int i = 0;
for (Architecture a : m_archs) { // Cannot be null, an empty list is returned.
if (a.getInstanceDescription().getState() == ComponentInstance.INVALID) {
i ++;
}
}
return i;
}
private int getValidFactoriesCount() {
int i = 0;
for (Factory a : m_factories) { // Cannot be null, an empty list is returned.
if (a.getState() == Factory.VALID) {
i ++;
}
}
return i;
}
private int getInvalidFactoriesCount() {
int i = 0;
for (Factory a : m_factories) { // Cannot be null, an empty list is returned.
if (a.getState() == Factory.INVALID) {
i ++;
}
}
return i;
}
private int getValidHandlersCount() {
int i = 0;
for (Factory a : m_handlers) { // Cannot be null, an empty list is returned.
if (a.getState() == Factory.VALID) {
i ++;
}
}
return i;
}
private int getInvalidHandlersCount() {
int i = 0;
for (Factory a : m_handlers) { // Cannot be null, an empty list is returned.
if (a.getState() == Factory.INVALID) {
i ++;
}
}
return i;
}
/**
* Gets the instance state as a String.
* @param state the state.
* @return the String form of the state.
*/
private static String getInstanceState(int state) {
switch(state) {
case ComponentInstance.VALID :
return "valid";
case ComponentInstance.INVALID :
return "invalid";
case ComponentInstance.DISPOSED :
return "disposed";
case ComponentInstance.STOPPED :
return "stopped";
default :
return "unknown";
}
}
/**
* Gets the factory state as a String.
* @param state the state.
* @return the String form of the state.
*/
private static String getFactoryState(int state) {
switch(state) {
case Factory.VALID :
return "valid";
case Factory.INVALID :
return "invalid";
default :
return "unknown";
}
}
/**
* Gets the instance list created by the given factory.
* @param factory the factory name
* @return the list containing the created instances (name)
*/
private List getInstanceList(String factory) {
List list = new ArrayList();
for (Architecture arch : m_archs) { // Cannot be null, an empty list is returned.
String n = arch.getInstanceDescription().getComponentDescription().getName();
if (factory.equals(n)) {
list.add(arch.getInstanceDescription().getName());
}
}
return list;
}
private final class RequestInfo {
public final String extension;
public final String path;
public final boolean instances;
public final boolean factories;
public final boolean handlers;
public final String name;
protected RequestInfo( final HttpServletRequest request ) {
String info = request.getPathInfo();
// remove label and starting slash
info = info.substring(getLabel().length() + 1);
// get extension
if (info.endsWith(".json")) {
extension = "json";
info = info.substring(0, info.length() - 5);
} else {
extension = "html";
}
if (info.startsWith("/")) {
path = info.substring(1);
System.out.println("Info " + info);
instances = path.startsWith("instances");
factories = path.startsWith("factories");
handlers = path.startsWith("handlers");
System.out.println("Path " + path);
if (instances && path.startsWith("instances/")) {
name = path.substring("instances".length() + 1);
} else if (factories && path.startsWith("factories/")) {
name = path.substring("factories".length() + 1);
} else {
name = null;
}
} else {
path = null;
name = null;
instances = false;
factories = false;
handlers = false;
}
request.setAttribute(IPOJOPlugin.class.getName(), this);
}
}
static RequestInfo getRequestInfo(final HttpServletRequest request) {
return (RequestInfo) request.getAttribute(IPOJOPlugin.class.getName());
}
@Override
public String getLabel() {
return m_label;
}
@Override
public String getTitle() {
return m_title;
}
@Override
protected String[] getCssReferences() {
return CSS;
}
}