001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.activemq.karaf.commands; 019 020import java.lang.reflect.Field; 021import java.lang.reflect.Type; 022import java.util.ArrayList; 023import java.util.HashMap; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Map; 027 028import org.apache.felix.gogo.commands.Action; 029import org.apache.felix.gogo.commands.Argument; 030import org.apache.felix.gogo.commands.basic.AbstractCommand; 031import org.apache.felix.gogo.commands.basic.ActionPreparator; 032import org.apache.felix.gogo.commands.basic.DefaultActionPreparator; 033import org.apache.felix.service.command.CommandSession; 034import org.apache.karaf.shell.console.BlueprintContainerAware; 035import org.apache.karaf.shell.console.BundleContextAware; 036import org.apache.karaf.shell.console.CompletableFunction; 037import org.apache.karaf.shell.console.Completer; 038import org.apache.karaf.shell.console.commands.GenericType; 039import org.osgi.framework.BundleContext; 040import org.osgi.service.blueprint.container.BlueprintContainer; 041import org.osgi.service.blueprint.container.Converter; 042 043/** 044 * Base command to process options and wrap native ActiveMQ console commands. 045 */ 046public class ActiveMQCommand extends AbstractCommand implements CompletableFunction 047{ 048 protected BlueprintContainer blueprintContainer; 049 protected Converter blueprintConverter; 050 protected String actionId; 051 protected List<Completer> completers; 052 053 public void setBlueprintContainer(BlueprintContainer blueprintContainer) { 054 this.blueprintContainer = blueprintContainer; 055 } 056 057 public void setBlueprintConverter(Converter blueprintConverter) { 058 this.blueprintConverter = blueprintConverter; 059 } 060 061 public void setActionId(String actionId) { 062 this.actionId = actionId; 063 } 064 065 @Override 066 public List<Completer> getCompleters() { 067 return completers; 068 } 069 070 public void setCompleters(List<Completer> completers) { 071 this.completers = completers; 072 } 073 074 @Override 075 protected ActionPreparator getPreparator() throws Exception { 076 return new ActiveMQActionPreparator(); 077 } 078 079 class ActiveMQActionPreparator extends DefaultActionPreparator { 080 @Override 081 public boolean prepare(Action action, CommandSession session, List<Object> params) throws Exception 082 { 083 Map<Argument, Field> arguments = new HashMap<Argument, Field>(); 084 List<Argument> orderedArguments = new ArrayList<Argument>(); 085 // Introspect 086 for (Class type = action.getClass(); type != null; type = type.getSuperclass()) { 087 for (Field field : type.getDeclaredFields()) { 088 Argument argument = field.getAnnotation(Argument.class); 089 if (argument != null) { 090 arguments.put(argument, field); 091 int index = argument.index(); 092 while (orderedArguments.size() <= index) { 093 orderedArguments.add(null); 094 } 095 if (orderedArguments.get(index) != null) { 096 throw new IllegalArgumentException("Duplicate argument index: " + index); 097 } 098 orderedArguments.set(index, argument); 099 } 100 } 101 } 102 // Check indexes are correct 103 for (int i = 0; i < orderedArguments.size(); i++) { 104 if (orderedArguments.get(i) == null) { 105 throw new IllegalArgumentException("Missing argument for index: " + i); 106 } 107 } 108 // Populate 109 Map<Argument, Object> argumentValues = new HashMap<Argument, Object>(); 110 int argIndex = 0; 111 for (Iterator<Object> it = params.iterator(); it.hasNext();) { 112 Object param = it.next(); 113 if (argIndex >= orderedArguments.size()) { 114 throw new IllegalArgumentException("Too many arguments specified"); 115 } 116 Argument argument = orderedArguments.get(argIndex); 117 if (!argument.multiValued()) { 118 argIndex++; 119 } 120 if (argument.multiValued()) { 121 List<Object> l = (List<Object>) argumentValues.get(argument); 122 if (l == null) { 123 l = new ArrayList<Object>(); 124 argumentValues.put(argument, l); 125 } 126 l.add(param); 127 } else { 128 argumentValues.put(argument, param); 129 } 130 } 131 132 if (argumentValues.size() == 1 && arguments.size() == 1) { 133 Object val = argumentValues.values().iterator().next(); 134 // short circut convert via blueprint... cause all our commands match this 135 // bluepring was failing to convert the last long param to a string for browse 136 // where dest is a numeric value - activemq-karaf-itests 137 // see: org.apache.activemq.karaf.itest.ActiveMQBrokerFeatureTest.test() 138 if (val instanceof List) { 139 Field field = arguments.values().iterator().next(); 140 List<Object> values = (List<Object>) val; 141 ArrayList<String> convertedValues = new ArrayList<String>(values.size()); 142 for (Object o : values) { 143 convertedValues.add(String.valueOf(o)); 144 } 145 field.setAccessible(true); 146 field.set(action, convertedValues); 147 return true; 148 } 149 } 150 151 for (Map.Entry<Argument, Object> entry : argumentValues.entrySet()) { 152 Field field = arguments.get(entry.getKey()); 153 Object value = convert(action, session, entry.getValue(), field.getGenericType()); 154 field.setAccessible(true); 155 field.set(action, value); 156 } 157 return true; 158 } 159 160 @Override 161 protected Object convert(Action action, CommandSession commandSession, Object o, Type type) throws Exception { 162 return blueprintConverter.convert(o, new GenericType(type)); 163 } 164 } 165 166 @Override 167 public Action createNewAction() { 168 Action action = (Action) blueprintContainer.getComponentInstance(actionId); 169 if (action instanceof BlueprintContainerAware) { 170 ((BlueprintContainerAware) action).setBlueprintContainer(blueprintContainer); 171 } 172 if (action instanceof BundleContextAware) { 173 BundleContext context = (BundleContext) blueprintContainer.getComponentInstance("blueprintBundleContext"); 174 ((BundleContextAware) action).setBundleContext(context); 175 } 176 return action; 177 } 178 179 @Override 180 public Map<String, Completer> getOptionalCompleters() { 181 //TODO implement completers 182 return null; 183 } 184}