| /* |
| * 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.plugins.ds.internal; |
| |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| |
| import org.apache.felix.inventory.Format; |
| import org.apache.felix.inventory.InventoryPrinter; |
| import org.apache.felix.utils.json.JSONWriter; |
| import org.apache.felix.webconsole.WebConsoleUtil; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.dto.ServiceReferenceDTO; |
| import org.osgi.service.component.ComponentConstants; |
| import org.osgi.service.component.runtime.ServiceComponentRuntime; |
| import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO; |
| import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO; |
| import org.osgi.service.component.runtime.dto.ReferenceDTO; |
| import org.osgi.service.component.runtime.dto.SatisfiedReferenceDTO; |
| |
| /** |
| * ComponentConfigurationPrinter prints the available SCR services. |
| */ |
| class ComponentConfigurationPrinter implements InventoryPrinter |
| { |
| |
| private final ServiceComponentRuntime scrService; |
| private final WebConsolePlugin plugin; |
| |
| ComponentConfigurationPrinter(ServiceComponentRuntime scrService, WebConsolePlugin plugin) |
| { |
| this.scrService = scrService; |
| this.plugin = plugin; |
| } |
| |
| /** |
| * @see org.apache.felix.inventory.InventoryPrinter#print(java.io.PrintWriter, org.apache.felix.inventory.Format, boolean) |
| */ |
| @Override |
| public void print(PrintWriter pw, Format format, boolean isZip) |
| { |
| final List<ComponentDescriptionDTO> noConfig = new ArrayList<>(); |
| final List<ComponentDescriptionDTO> disabled = new ArrayList<>(); |
| final List<ComponentConfigurationDTO> configurations = new ArrayList<>(); |
| |
| final Collection<ComponentDescriptionDTO> descs = scrService.getComponentDescriptionDTOs(); |
| for(final ComponentDescriptionDTO d : descs) |
| { |
| if ( !scrService.isComponentEnabled(d) ) |
| { |
| disabled.add(d); |
| } |
| else |
| { |
| final Collection<ComponentConfigurationDTO> configs = scrService.getComponentConfigurationDTOs(d); |
| if ( configs.isEmpty() ) |
| { |
| noConfig.add(d); |
| } |
| else |
| { |
| configurations.addAll(configs); |
| } |
| } |
| } |
| Collections.sort(configurations, Util.COMPONENT_COMPARATOR); |
| |
| if (Format.JSON.equals(format)) |
| { |
| disabled.addAll(noConfig); |
| try |
| { |
| printComponentsJson(pw, disabled, configurations, isZip); |
| } catch (IOException ignore) |
| { |
| // ignore |
| } |
| } |
| else |
| { |
| printComponentsText(pw, disabled, noConfig, configurations); |
| } |
| } |
| |
| private final void printComponentsJson(final PrintWriter pw, |
| final List<ComponentDescriptionDTO> disabled, |
| final List<ComponentConfigurationDTO> configurations, |
| final boolean details) throws IOException |
| { |
| final JSONWriter jw = new JSONWriter(pw); |
| jw.object(); |
| jw.key("components"); //$NON-NLS-1$ |
| jw.array(); |
| |
| // render disabled descriptions |
| for(final ComponentDescriptionDTO cd : disabled) |
| { |
| plugin.component(jw, cd, null, details); |
| } |
| // render configurations |
| for (final ComponentConfigurationDTO cfg : configurations) |
| { |
| plugin.component(jw, cfg.description, cfg, details); |
| } |
| |
| jw.endArray(); |
| jw.endObject(); |
| } |
| |
| private static final String SEP = "----------------------------------------------------------------------"; |
| |
| private static final void printComponentsText(final PrintWriter pw, |
| final List<ComponentDescriptionDTO> disabled, |
| final List<ComponentDescriptionDTO> noConfig, |
| final List<ComponentConfigurationDTO> configurations) |
| { |
| if ( !disabled.isEmpty()) |
| { |
| pw.println(SEP); |
| pw.println("Disabled components:"); |
| pw.println(SEP); |
| for(final ComponentDescriptionDTO cd : disabled) |
| { |
| disabledComponent(pw, cd); |
| } |
| pw.println(); |
| } |
| if ( !noConfig.isEmpty()) |
| { |
| pw.println(SEP); |
| pw.println("Components with missing configuration in Config Admin:"); |
| pw.println(SEP); |
| for(final ComponentDescriptionDTO cd : noConfig) |
| { |
| disabledComponent(pw, cd); |
| } |
| pw.println(); |
| } |
| |
| pw.println(SEP); |
| if (configurations.isEmpty()) |
| { |
| pw.println("Status: No Component Configurations"); |
| pw.println(SEP); |
| } |
| else |
| { |
| pw.println("Component Configurations:"); |
| pw.println(SEP); |
| // order components by id |
| TreeMap<Long, ComponentConfigurationDTO> componentMap = new TreeMap<>(); |
| for(final ComponentConfigurationDTO cfg : configurations) |
| { |
| componentMap.put(new Long(cfg.id), cfg); |
| } |
| |
| // render components |
| for (final ComponentConfigurationDTO cfg : componentMap.values()) |
| { |
| component(pw, cfg); |
| } |
| } |
| } |
| |
| private static final void component(PrintWriter pw, final ComponentConfigurationDTO cfg) |
| { |
| |
| pw.print(cfg.id); |
| pw.print("=["); |
| pw.print(cfg.description.name); |
| pw.println("]"); |
| |
| pw.println(" Bundle=" + cfg.description.bundle.symbolicName + " (" |
| + cfg.description.bundle.id + ")"); |
| pw.println(" State=" + toStateString(cfg.state)); |
| if ( cfg.state == ComponentConfigurationDTO.FAILED_ACTIVATION ) { |
| pw.println(" Failure=" + cfg.failure); |
| } |
| pw.println(" DefaultState=" |
| + (cfg.description.defaultEnabled ? "enabled" : "disabled")); |
| pw.println(" Activation=" + (cfg.description.immediate ? "immediate" : "delayed")); |
| pw.println(" ConfigurationPolicy=" + cfg.description.configurationPolicy); |
| |
| listServices(pw, cfg.description); |
| if ( cfg.service != null ) { |
| pw.println(" ServiceId=" + String.valueOf(cfg.service.id)); |
| } |
| |
| listReferences(pw, cfg.description, cfg); |
| listProperties(pw, cfg.description, cfg); |
| |
| pw.println(); |
| } |
| |
| private static final void disabledComponent(PrintWriter pw, final ComponentDescriptionDTO description) |
| { |
| |
| pw.println(description.name); |
| |
| pw.println(" Bundle=" + description.bundle.symbolicName + " (" |
| + description.bundle.id + ")"); |
| pw.println(" DefaultState=" |
| + (description.defaultEnabled ? "enabled" : "disabled")); |
| pw.println(" Activation=" + (description.immediate ? "immediate" : "delayed")); |
| pw.println(" ConfigurationPolicy=" + description.configurationPolicy); |
| |
| listServices(pw, description); |
| listReferences(pw, description, null); |
| listProperties(pw, description, null); |
| |
| pw.println(); |
| } |
| |
| private static void listServices(PrintWriter pw, final ComponentDescriptionDTO cfg) |
| { |
| String[] services = cfg.serviceInterfaces; |
| if (services == null) |
| { |
| return; |
| } |
| |
| if ( cfg.scope != null ) { |
| pw.println(" ServiceType=" + cfg.scope); |
| } |
| |
| StringBuffer buf = new StringBuffer(); |
| for (int i = 0; i < services.length; i++) |
| { |
| if (i > 0) |
| { |
| buf.append(", "); |
| } |
| buf.append(services[i]); |
| } |
| |
| pw.println(" Services=" + buf); |
| } |
| |
| private static SatisfiedReferenceDTO findReference(final ComponentConfigurationDTO component, final String name) |
| { |
| for(final SatisfiedReferenceDTO dto : component.satisfiedReferences) |
| { |
| if ( dto.name.equals(name)) |
| { |
| return dto; |
| } |
| } |
| return null; |
| } |
| |
| private static final void listReferences(PrintWriter pw, |
| final ComponentDescriptionDTO description, |
| final ComponentConfigurationDTO configuration) |
| { |
| for(final ReferenceDTO dto : description.references) |
| { |
| final SatisfiedReferenceDTO satisfiedRef = configuration == null ? null : findReference(configuration, dto.name); |
| |
| pw.print(" Reference="); |
| pw.print(dto.name); |
| if ( configuration != null ) |
| { |
| pw.print(", "); |
| pw.print(satisfiedRef != null ? "Satisfied" : "Unsatisfied"); |
| } |
| pw.println(); |
| pw.println(" Service Name: " + dto.interfaceName); |
| |
| if (dto.target != null) |
| { |
| pw.println(" Target Filter: " + dto.target); |
| } |
| |
| pw.println(" Cardinality: " + dto.cardinality); |
| pw.println(" Policy: " + dto.policy); |
| pw.println(" Policy Option: " + dto.policyOption); |
| |
| // list bound services |
| if ( satisfiedRef != null ) |
| { |
| for(final ServiceReferenceDTO sref : satisfiedRef.boundServices ) |
| { |
| pw.print(" Bound Service: ID "); |
| pw.print(sref.properties.get(Constants.SERVICE_ID)); |
| |
| String name = (String) sref.properties.get(ComponentConstants.COMPONENT_NAME); |
| if (name == null) |
| { |
| name = (String) sref.properties.get(Constants.SERVICE_PID); |
| if (name == null) |
| { |
| name = (String) sref.properties.get(Constants.SERVICE_DESCRIPTION); |
| } |
| } |
| if (name != null) |
| { |
| pw.print(" ("); |
| pw.print(name); |
| pw.print(")"); |
| } |
| pw.println(); |
| } |
| } |
| else |
| { |
| pw.println(" No Services bound"); |
| } |
| } |
| } |
| |
| private static final void listProperties(PrintWriter pw, |
| final ComponentDescriptionDTO description, |
| final ComponentConfigurationDTO cfg) |
| { |
| Map<String, Object> props = cfg == null ? description.properties : cfg.properties; |
| if (props != null) |
| { |
| |
| pw.println(" Properties="); |
| TreeSet<String> keys = new TreeSet<>(props.keySet()); |
| for (Iterator<String> ki = keys.iterator(); ki.hasNext();) |
| { |
| String key = ki.next(); |
| Object value = props.get(key); |
| value = WebConsoleUtil.toString(value); |
| if (value.getClass().isArray()) |
| { |
| value = Arrays.asList((Object[]) value); |
| } |
| pw.println(" " + key + "=" + value); |
| } |
| } |
| if ( cfg == null && description.factoryProperties != null ) { |
| pw.println(" FactoryProperties="); |
| TreeSet<String> keys = new TreeSet<>(description.factoryProperties.keySet()); |
| for (Iterator<String> ki = keys.iterator(); ki.hasNext();) |
| { |
| String key = ki.next(); |
| Object value = props.get(key); |
| value = WebConsoleUtil.toString(value); |
| if (value.getClass().isArray()) |
| { |
| value = Arrays.asList((Object[]) value); |
| } |
| pw.println(" " + key + "=" + value); |
| } |
| } |
| } |
| |
| static final String toStateString(int state) |
| { |
| switch (state) |
| { |
| case ComponentConfigurationDTO.ACTIVE: |
| return "active"; |
| case ComponentConfigurationDTO.SATISFIED: |
| return "satisfied"; |
| case ComponentConfigurationDTO.UNSATISFIED_CONFIGURATION: |
| return "unsatisfied (configuration)"; |
| case ComponentConfigurationDTO.UNSATISFIED_REFERENCE: |
| return "unsatisfied (reference)"; |
| case ComponentConfigurationDTO.FAILED_ACTIVATION: |
| return "failed activation"; |
| default: |
| return String.valueOf(state); |
| } |
| } |
| } |