Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one |
| 3 | * or more contributor license agreements. See the NOTICE file |
| 4 | * distributed with this work for additional information |
| 5 | * regarding copyright ownership. The ASF licenses this file |
| 6 | * to you under the Apache License, Version 2.0 (the |
| 7 | * "License"); you may not use this file except in compliance |
| 8 | * with the License. You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, |
| 13 | * software distributed under the License is distributed on an |
| 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | * KIND, either express or implied. See the License for the |
| 16 | * specific language governing permissions and limitations |
| 17 | * under the License. |
| 18 | */ |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 19 | package org.apache.felix.dependencymanager.shell; |
| 20 | |
| 21 | import java.io.PrintStream; |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 22 | import java.util.ArrayList; |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 23 | import java.util.Arrays; |
| 24 | import java.util.Comparator; |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 25 | import java.util.StringTokenizer; |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 26 | |
| 27 | import org.apache.felix.dependencymanager.ServiceComponent; |
| 28 | import org.apache.felix.dependencymanager.ServiceComponentDependency; |
| 29 | import org.apache.felix.shell.Command; |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 30 | import org.osgi.framework.Bundle; |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 31 | import org.osgi.framework.BundleContext; |
| 32 | import org.osgi.framework.InvalidSyntaxException; |
| 33 | import org.osgi.framework.ServiceReference; |
| 34 | |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 35 | /** |
| 36 | * Shell command for showing all services and dependencies that are managed |
| 37 | * by the dependency manager. |
| 38 | * |
| 39 | * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> |
| 40 | */ |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 41 | public class DMCommand implements Command { |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 42 | private static final BundleIdSorter SORTER = new BundleIdSorter(); |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 43 | private final BundleContext m_context; |
| 44 | |
| 45 | public DMCommand(BundleContext context) { |
| 46 | m_context = context; |
| 47 | } |
| 48 | |
| 49 | public void execute(String line, PrintStream out, PrintStream err) { |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 50 | boolean nodeps = false; |
| 51 | boolean notavail = false; |
| 52 | boolean compact = false; |
| 53 | ArrayList ids = new ArrayList(); |
| 54 | |
| 55 | // parse the command line |
| 56 | StringTokenizer st = new StringTokenizer(line); |
| 57 | if (st.hasMoreTokens()) { |
| 58 | st.nextToken(); |
| 59 | while (st.hasMoreTokens()) { |
| 60 | String token = st.nextToken(); |
| 61 | if ("nodeps".equals(token)) { |
| 62 | nodeps = true; |
| 63 | } |
| 64 | else if ("notavail".equals(token)) { |
| 65 | notavail = true; |
| 66 | } |
| 67 | else if ("compact".equals(token)) { |
| 68 | compact = true; |
| 69 | } |
| 70 | else { |
| 71 | try { |
| 72 | ids.add(Long.valueOf(token)); |
| 73 | } |
| 74 | catch (NumberFormatException e) { |
| 75 | // if it's not a number, we abort with an error |
| 76 | err.println("Argument " + token + " is not a valid number."); |
| 77 | return; |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | // lookup all dependency manager service components |
| 82 | try { |
| 83 | ServiceReference[] references = m_context.getServiceReferences(ServiceComponent.class.getName(), null); |
| 84 | // show their state |
| 85 | if (references != null) { |
| 86 | Arrays.sort(references, SORTER); |
| 87 | long lastBundleId = -1; |
| 88 | for (int i = 0; i < references.length; i++) { |
| 89 | ServiceReference ref = references[i]; |
| 90 | ServiceComponent sc = (ServiceComponent) m_context.getService(ref); |
| 91 | if (sc != null) { |
| 92 | String name = sc.getName(); |
| 93 | int state = sc.getState(); |
| 94 | Bundle bundle = ref.getBundle(); |
| 95 | long bundleId = bundle.getBundleId(); |
| 96 | if (ids.size() == 0 || ids.contains(Long.valueOf(bundleId))) { |
| 97 | if (!notavail || (notavail && sc.getState() == ServiceComponent.STATE_UNREGISTERED)) { |
| 98 | if (lastBundleId != bundleId) { |
| 99 | lastBundleId = bundleId; |
| 100 | if (compact) { |
| 101 | out.println("[" + bundleId + "] " + compactName(bundle.getSymbolicName())); |
| 102 | } |
| 103 | else { |
| 104 | out.println("[" + bundleId + "] " + bundle.getSymbolicName()); |
| 105 | } |
| 106 | } |
| 107 | if (compact) { |
| 108 | out.print(" " + compactName(name) + " " + compactState(ServiceComponent.STATE_NAMES[state])); |
| 109 | } |
| 110 | else { |
| 111 | out.println(" " + name + " " + ServiceComponent.STATE_NAMES[state]); |
| 112 | } |
| 113 | if (!nodeps) { |
| 114 | ServiceComponentDependency[] dependencies = sc.getComponentDependencies(); |
| 115 | if (dependencies != null && dependencies.length > 0) { |
| 116 | if (compact) { |
| 117 | out.print('('); |
| 118 | } |
| 119 | for (int j = 0; j < dependencies.length; j++) { |
| 120 | ServiceComponentDependency dep = dependencies[j]; |
| 121 | String depName = dep.getName(); |
| 122 | String depType = dep.getType(); |
| 123 | int depState = dep.getState(); |
| 124 | if (compact) { |
| 125 | if (j > 0) { |
| 126 | out.print(' '); |
| 127 | } |
| 128 | out.print(compactName(depName) + " " + compactState(depType) + " " + compactState(ServiceComponentDependency.STATE_NAMES[depState])); |
| 129 | } |
| 130 | else { |
| 131 | out.println(" " + depName + " " + depType + " " + ServiceComponentDependency.STATE_NAMES[depState]); |
| 132 | } |
| 133 | } |
| 134 | if (compact) { |
| 135 | out.print(')'); |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | if (compact) { |
| 140 | out.println(); |
| 141 | } |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 142 | } |
| 143 | } |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 144 | m_context.ungetService(ref); |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 145 | } |
| 146 | } |
| 147 | } |
| 148 | } |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 149 | catch (InvalidSyntaxException e) { |
| 150 | // very weird since I'm not specifying a filter |
| 151 | e.printStackTrace(err); |
| 152 | } |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 153 | } |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 154 | else { |
| 155 | err.println("Invalid command line: " + line); |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 156 | } |
| 157 | } |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 158 | |
| 159 | /** |
| 160 | * Compact names that look like state strings. State strings consist of |
| 161 | * one or more words. Each word will be shortened to the first letter, |
| 162 | * all letters concatenated and uppercased. |
| 163 | */ |
| 164 | private String compactState(String input) { |
| 165 | StringBuffer output = new StringBuffer(); |
| 166 | StringTokenizer st = new StringTokenizer(input); |
| 167 | while (st.hasMoreTokens()) { |
| 168 | output.append(st.nextToken().toUpperCase().charAt(0)); |
| 169 | } |
| 170 | return output.toString(); |
| 171 | } |
| 172 | |
| 173 | /** |
| 174 | * Compacts names that look like fully qualified class names. All packages |
| 175 | * will be shortened to the first letter, except for the last one. So |
| 176 | * something like "org.apache.felix.MyClass" will become "o.a.f.MyClass". |
| 177 | */ |
| 178 | private String compactName(String input) { |
| 179 | StringBuffer output = new StringBuffer(); |
| 180 | int lastIndex = 0; |
| 181 | for (int i = 0; i < input.length(); i++) { |
| 182 | char c = input.charAt(i); |
| 183 | switch (c) { |
| 184 | case '.': |
| 185 | output.append(input.charAt(lastIndex)); |
| 186 | output.append('.'); |
| 187 | lastIndex = i + 1; |
| 188 | break; |
| 189 | case ' ': |
| 190 | case ',': |
| 191 | if (lastIndex < i) { |
| 192 | output.append(input.substring(lastIndex, i)); |
| 193 | } |
| 194 | output.append(c); |
| 195 | lastIndex = i + 1; |
| 196 | break; |
| 197 | } |
| 198 | } |
| 199 | if (lastIndex < input.length()) { |
| 200 | output.append(input.substring(lastIndex)); |
| 201 | } |
| 202 | return output.toString(); |
| 203 | } |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 204 | |
| 205 | public String getName() { |
| 206 | return "dm"; |
| 207 | } |
| 208 | |
| 209 | public String getShortDescription() { |
| 210 | return "list dependency manager component diagnostics."; |
| 211 | } |
| 212 | |
| 213 | public String getUsage() { |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 214 | return "dm [nodeps] [notavail] [compact] [<bundleid> ...]"; |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 215 | } |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 216 | } |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 217 | |
Marcel Offermans | b264a2a | 2008-11-25 00:09:57 +0000 | [diff] [blame] | 218 | final class BundleIdSorter implements Comparator { |
| 219 | public int compare(Object o1, Object o2) { |
| 220 | ServiceReference r1 = (ServiceReference) o1; |
| 221 | ServiceReference r2 = (ServiceReference) o2; |
| 222 | long id1 = r1.getBundle().getBundleId(); |
| 223 | long id2 = r2.getBundle().getBundleId(); |
| 224 | return id1 > id2 ? 1 : -1; |
| 225 | } |
Marcel Offermans | b20ea20 | 2008-09-18 21:18:03 +0000 | [diff] [blame] | 226 | } |