Java tutorial
/* * 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()); } } }