org.apache.felix.webconsole.internal.compendium.ComponentsServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.felix.webconsole.internal.compendium.ComponentsServlet.java

Source

/*
 * 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.webconsole.internal.compendium;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.TreeSet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.felix.scr.Component;
import org.apache.felix.scr.Reference;
import org.apache.felix.scr.ScrService;
import org.apache.felix.webconsole.internal.BaseWebConsolePluginServlet;
import org.apache.felix.webconsole.internal.Util;
import org.apache.felix.webconsole.internal.servlet.OsgiManager;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONWriter;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.metatype.MetaTypeInformation;
import org.osgi.service.metatype.MetaTypeService;

public class ComponentsServlet extends BaseWebConsolePluginServlet {

    private final class RequestInfo {
        public final String fileExtension;
        public final Component servComponent;
        public final boolean hasComponentRequested;

        protected RequestInfo(final HttpServletRequest request) {
            String info = request.getPathInfo();
            // remove label and starting slash
            info = info.substring(getServletLabel().length() + 1);

            int extensionLength = 5;

            // get extension
            if (info.endsWith(".json")) {
                fileExtension = "json";
                info = info.substring(0, info.length() - extensionLength);
            } else {
                fileExtension = "html";
            }

            long componentId = getComponentId(info.substring(info.lastIndexOf('/') + 1));
            if (componentId == -1) {
                hasComponentRequested = false;
                servComponent = null;
            } else {
                hasComponentRequested = true;
                final ScrService scrService = getScrService();
                if (scrService != null) {
                    servComponent = scrService.getComponent(componentId);
                } else {
                    servComponent = null;
                }
            }
            request.setAttribute(ComponentsServlet.class.getName(), this);
        }

        protected long getComponentId(final String componentIdPar) {
            try {
                return Long.parseLong(componentIdPar);
            } catch (NumberFormatException nfe) {
                // TODO: log
            }

            // no bundleId or wrong format
            return -1;
        }

    }

    public static RequestInfo getRequestInfo(final HttpServletRequest inputRequest) {
        return (RequestInfo) inputRequest.getAttribute(ComponentsServlet.class.getName());
    }

    static String toStateString(int state) {
        switch (state) {
        case Component.STATE_DISABLED:
            return "disabled";
        case Component.STATE_ACTIVE:
            return "active";
        case Component.STATE_REGISTERED:
            return "registered";
        case Component.STATE_FACTORY:
            return "factory";
        case Component.STATE_DEACTIVATING:
            return "deactivating";
        case Component.STATE_ENABLED:
            return "enabled";
        case Component.STATE_UNSATISFIED:
            return "unsatisifed";
        case Component.STATE_ACTIVATING:
            return "activating";
        case Component.STATE_DESTROYED:
            return "destroyed";
        default:
            return String.valueOf(state);
        }
    }

    public static final String COMPONENT_ID = "componentId";

    public static final String OPERATION = "action";

    public static final String NAME = "components";

    public static final String LABEL = "Components";

    private static final String SCR_SERVICE_NAME = ScrService.class.getName();

    private static final String META_TYPE_CLASS_NAME = MetaTypeService.class.getName();

    private static final String CONFIGURATION_ADMIN_CLASS_NAME = ConfigurationAdmin.class.getName();

    public static final String COMMAND_ENABLE = "enable";

    public static final String COMMAND_DISABLE = "disable";

    public static final String COMMAND_CONFIGURE = "configure";

    private static final int STATUS_CODE_UNFOUND = 404;

    private static final int STATUS_CODE_INTERNAL_SERV_ERROR = 500;

    private void actionOnJSON(JSONWriter jsonWriter, boolean enabled, String op, String opLabel, String image)
            throws JSONException {
        jsonWriter.object();
        jsonWriter.key("enabled").value(enabled);
        jsonWriter.key("name").value(opLabel);
        jsonWriter.key("link").value(op);
        jsonWriter.key("image").value(image);
        jsonWriter.endObject();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        final RequestInfo getRequestInfo = new RequestInfo(request);
        if (getRequestInfo.servComponent == null && getRequestInfo.hasComponentRequested) {
            response.sendError(STATUS_CODE_UNFOUND);
            return;
        }
        if (getRequestInfo.fileExtension.equals("json")) {
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            this.renderServletResult(response.getWriter(), getRequestInfo.servComponent);

            // nothing more to do
            return;
        }
        super.doGet(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        final RequestInfo postReqInfo = new RequestInfo(request);
        if (postReqInfo.servComponent == null && postReqInfo.hasComponentRequested) {
            response.sendError(STATUS_CODE_UNFOUND);
            return;
        }
        if (!postReqInfo.hasComponentRequested) {
            response.sendError(STATUS_CODE_INTERNAL_SERV_ERROR);
            return;
        }
        String requestOperation = request.getParameter(OPERATION);
        if (COMMAND_ENABLE.equals(requestOperation)) {
            postReqInfo.servComponent.enable();
        } else if (COMMAND_DISABLE.equals(requestOperation)) {
            postReqInfo.servComponent.disable();
        }

        final PrintWriter printWriter = response.getWriter();
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        renderServletResult(printWriter, null);
    }

    private void gatherComponentDetails(JSONWriter jsonWriter, Component component) throws JSONException {
        jsonWriter.key("props");
        jsonWriter.array();

        printKeyVal(jsonWriter, "Bundle",
                component.getBundle().getSymbolicName() + " (" + component.getBundle().getBundleId() + ")");
        printKeyVal(jsonWriter, "Default State", component.isDefaultEnabled() ? "enabled" : "disabled");
        printKeyVal(jsonWriter, "Activation", component.isImmediate() ? "immediate" : "delayed");

        listServicesComponents(jsonWriter, component);
        listReferences(jsonWriter, component);
        listComponentProperties(jsonWriter, component);

        jsonWriter.endArray();
    }

    protected ConfigurationAdmin getConfigurationAdmin() {
        return (ConfigurationAdmin) getService(CONFIGURATION_ADMIN_CLASS_NAME);
    }

    protected MetaTypeService getMetaTypeService() {
        return (MetaTypeService) getService(META_TYPE_CLASS_NAME);
    }

    private ScrService getScrService() {
        return (ScrService) getService(SCR_SERVICE_NAME);
    }

    public String getServletCapital() {
        return LABEL;
    }

    public String getServletLabel() {
        return NAME;
    }

    private boolean isConfigurable(final String servicePid) {
        // we first check if the config admin has something for this pid
        final ConfigurationAdmin currConfigAdmin = this.getConfigurationAdmin();
        if (currConfigAdmin != null) {
            try {
                String stmt = "(" + Constants.SERVICE_PID + "=" + servicePid + ")";
                Configuration[] configs = currConfigAdmin.listConfigurations(stmt);
                if (configs != null && configs.length > 0) {
                    return true;
                }
            } catch (InvalidSyntaxException isEx) {
                // should print message
            } catch (IOException ioEx) {
                // should print message
            }
        }
        // second check is using the meta type service
        final MetaTypeService mTypeServ = this.getMetaTypeService();
        if (mTypeServ != null) {
            try {
                final ServiceReference[] servRef = this.getBundleContext().getServiceReferences(
                        ManagedService.class.getName(), '(' + "service.pid" + '=' + servicePid + ')');
                for (int i = 0; servRef != null && i < servRef.length; i++) {
                    if (servRef[i].getBundle() != null) {
                        final MetaTypeInformation mTypeInfo = mTypeServ
                                .getMetaTypeInformation(servRef[i].getBundle());
                        if (mTypeInfo != null) {
                            return mTypeInfo.getObjectClassDefinition(servicePid, null) != null;
                        }
                    }
                }

            } catch (InvalidSyntaxException ise) {
            }

        }
        return false;
    }

    private void jsonComponent(JSONWriter jsonWriter, Component component, boolean details) throws JSONException {
        String id = String.valueOf(component.getId());
        String name = component.getName();
        int state = component.getState();

        jsonWriter.object();

        // component information
        jsonWriter.key("id");
        jsonWriter.value(id);
        jsonWriter.key("name");
        jsonWriter.value(name);
        jsonWriter.key("state");
        jsonWriter.value(toStateString(state));

        final String pid = (String) component.getProperties().get(Constants.SERVICE_PID);
        if (pid != null) {
            jsonWriter.key("pid");
            jsonWriter.value(pid);
        }
        // component actions
        jsonWriter.key("actions");
        jsonWriter.array();

        if (state == Component.STATE_DISABLED) {
            actionOnJSON(jsonWriter, true, COMMAND_ENABLE, "Enable", "enable");
        }
        if (state != Component.STATE_DISABLED && state != Component.STATE_DESTROYED) {
            actionOnJSON(jsonWriter, true, COMMAND_DISABLE, "Disable", "disable");
        }
        if (pid != null) {
            if (isConfigurable(pid)) {
                actionOnJSON(jsonWriter, true, COMMAND_CONFIGURE, "Configure", "configure");
            }
        }

        jsonWriter.endArray();

        // component details
        if (details) {
            gatherComponentDetails(jsonWriter, component);
        }

        jsonWriter.endObject();
    }

    private void listComponentProperties(JSONWriter jsonWriter, Component inputComponent) {
        Dictionary propsBook = inputComponent.getProperties();
        if (propsBook != null) {
            JSONArray myBuf = new JSONArray();
            TreeSet bookKeys = new TreeSet(Collections.list(propsBook.keys()));
            for (Iterator keyIter = bookKeys.iterator(); keyIter.hasNext();) {
                final String key = (String) keyIter.next();
                final StringBuffer strBuffer = new StringBuffer();
                strBuffer.append(key).append(" = ");

                Object prop = propsBook.get(key);
                if (prop.getClass().isArray()) {
                    prop = Arrays.asList((Object[]) prop);
                }
                strBuffer.append(prop);
                myBuf.put(strBuffer.toString());
            }

            printKeyVal(jsonWriter, "Properties", myBuf);
        }

    }

    private void listReferences(JSONWriter jsonWriter, Component inputComponent) {
        Reference[] componentRef = inputComponent.getReferences();
        if (componentRef != null) {
            for (int i = 0; i < componentRef.length; i++) {
                JSONArray jsonBuff = new JSONArray();
                jsonBuff.put(componentRef[i].isSatisfied() ? "Satisfied" : "Unsatisfied");
                jsonBuff.put("Service Name: " + componentRef[i].getServiceName());
                if (componentRef[i].getTarget() != null) {
                    jsonBuff.put("Target Filter: " + componentRef[i].getTarget());
                }
                jsonBuff.put("Multiple: " + (componentRef[i].isMultiple() ? "multiple" : "single"));
                jsonBuff.put("Optional: " + (componentRef[i].isOptional() ? "optional" : "mandatory"));
                jsonBuff.put("Policy: " + (componentRef[i].isStatic() ? "static" : "dynamic"));

                // list bound services
                ServiceReference[] boundRefs = componentRef[i].getServiceReferences();
                if (boundRefs != null && boundRefs.length > 0) {
                    for (int j = 0; j < boundRefs.length; j++) {
                        final StringBuffer tempStrBuff = new StringBuffer();
                        tempStrBuff.append("Bound Service ID ");
                        tempStrBuff.append(boundRefs[j].getProperty(Constants.SERVICE_ID));

                        String componentName = (String) boundRefs[j].getProperty(ComponentConstants.COMPONENT_NAME);
                        if (componentName == null) {
                            componentName = (String) boundRefs[j].getProperty(Constants.SERVICE_PID);
                            if (componentName == null) {
                                componentName = (String) boundRefs[j].getProperty(Constants.SERVICE_DESCRIPTION);
                            }
                        }
                        if (componentName != null) {
                            tempStrBuff.append(" (");
                            tempStrBuff.append(componentName);
                            tempStrBuff.append(")");
                        }
                        jsonBuff.put(tempStrBuff.toString());
                    }
                } else {
                    jsonBuff.put("No Services bound");
                }

                printKeyVal(jsonWriter, "Reference " + componentRef[i].getName(), jsonBuff.toString());
            }
        }
    }

    private void listServicesComponents(JSONWriter jsonWriter, Component component) {
        String[] services = component.getServices();
        if (services == null) {
            return;
        }

        printKeyVal(jsonWriter, "Service Type", component.isServiceFactory() ? "service factory" : "service");

        JSONArray jsonBuffer = new JSONArray();
        for (int i = 0; i < services.length; i++) {
            jsonBuffer.put(services[i]);
        }

        printKeyVal(jsonWriter, "Services", jsonBuffer);
    }

    private void printKeyVal(JSONWriter jsonWriter, String inputKey, Object inputValue) {
        if (inputKey != null && inputValue != null) {
            try {
                jsonWriter.object();
                jsonWriter.key("key");
                jsonWriter.value(inputKey);
                jsonWriter.key("value");
                jsonWriter.value(inputValue);
                jsonWriter.endObject();
            } catch (JSONException jsonEx) {
                // don't care
            }
        }
    }

    protected void renderServletRequest(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        // get request info from request attribute
        final RequestInfo reqInfo = getRequestInfo(request);
        final PrintWriter printWriter = response.getWriter();

        final String attrAppRoot = (String) request.getAttribute(OsgiManager.OSGI_APP_ROOT);

        Util.startScript(printWriter);
        printWriter.println("var imgRoot = '" + attrAppRoot + "/res/imgs';");
        printWriter.println("var drawDetails = " + reqInfo.hasComponentRequested + ";");
        Util.endScript(printWriter);

        Util.printScriptBody(printWriter, attrAppRoot, "components.js");
        printWriter.println("<div id='plugin_content'/>");
        Util.startScript(printWriter);
        printWriter.print("renderComponents(");
        renderServletResult(printWriter, reqInfo.servComponent);
        printWriter.println(");");
        Util.endScript(printWriter);
    }

    private void renderServletResult(final PrintWriter printWriter, final Component component) throws IOException {
        final JSONWriter jsonWriter = new JSONWriter(printWriter);
        try {
            jsonWriter.object();

            final ScrService scrService = getScrService();
            if (scrService == null) {
                jsonWriter.key("status");
                jsonWriter.value("Apache Felix Declarative Service required for this function");
            } else {
                final Component[] serviceComponents = scrService.getComponents();

                if (serviceComponents == null || serviceComponents.length == 0) {
                    jsonWriter.key("status");
                    jsonWriter.value("No components installed currently");
                } else {
                    // order components by name
                    TreeMap componentMap = new TreeMap();
                    for (int i = 0; i < serviceComponents.length; i++) {
                        Component tempComp = serviceComponents[i];
                        componentMap.put(tempComp.getName(), tempComp);
                    }

                    final StringBuffer strBuffer = new StringBuffer();
                    strBuffer.append(componentMap.size());
                    strBuffer.append(" component");
                    if (componentMap.size() != 1) {
                        strBuffer.append('s');
                    }
                    strBuffer.append(" installed.");
                    jsonWriter.key("status");
                    jsonWriter.value(strBuffer.toString());

                    // render components
                    jsonWriter.key("data");
                    jsonWriter.array();
                    if (component != null) {
                        jsonComponent(jsonWriter, component, true);
                    } else {
                        for (Iterator ci = componentMap.values().iterator(); ci.hasNext();) {
                            jsonComponent(jsonWriter, (Component) ci.next(), false);
                        }
                    }
                    jsonWriter.endArray();
                }
            }

            jsonWriter.endObject();
        } catch (JSONException je) {
            throw new IOException(je.toString());
        }
    }
}