blob: 3ec95662c3e1a773ec70d04e3fbe70764aa53d49 [file] [log] [blame]
/*
* 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.gogo.runtime;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import org.apache.felix.gogo.api.CommandSessionListener;
import org.apache.felix.service.command.CommandProcessor;
import org.apache.felix.service.command.CommandSession;
import org.apache.felix.service.command.Converter;
import org.apache.felix.service.command.Function;
import org.apache.felix.service.threadio.ThreadIO;
public class CommandProcessorImpl implements CommandProcessor
{
protected final Set<Converter> converters = new HashSet<Converter>();
protected final Set<CommandSessionListener> listeners = new CopyOnWriteArraySet<CommandSessionListener>();
protected final Map<String, Object> commands = new LinkedHashMap<String, Object>();
protected final Map<String, Object> constants = new HashMap<String, Object>();
protected final ThreadIO threadIO;
protected final WeakHashMap<CommandSession, Object> sessions = new WeakHashMap<CommandSession, Object>();
public CommandProcessorImpl(ThreadIO tio)
{
threadIO = tio;
}
public CommandSession createSession(InputStream in, PrintStream out, PrintStream err)
{
CommandSessionImpl session = new CommandSessionImpl(this, in, out, err);
sessions.put(session, null);
return session;
}
public void stop()
{
for (CommandSession session : sessions.keySet())
{
session.close();
}
}
public void addConverter(Converter c)
{
converters.add(c);
}
public void removeConverter(Converter c)
{
converters.remove(c);
}
public void addListener(CommandSessionListener l)
{
listeners.add(l);
}
public void removeListener(CommandSessionListener l)
{
listeners.remove(l);
}
public Set<String> getCommands()
{
return commands.keySet();
}
Function getCommand(String name, final Object path)
{
int colon = name.indexOf(':');
if (colon < 0)
{
return null;
}
name = name.toLowerCase();
Object cmd = commands.get(name);
String cfunction = name.substring(colon);
boolean anyScope = (colon == 1 && name.charAt(0) == '*');
if (null == cmd && anyScope)
{
String scopePath = (null == path ? "*" : path.toString());
for (String scope : scopePath.split(":"))
{
if (scope.equals("*"))
{
for (Entry<String, Object> entry : commands.entrySet())
{
if (entry.getKey().endsWith(cfunction))
{
cmd = entry.getValue();
break;
}
}
}
else
{
cmd = commands.get(scope + cfunction);
}
if (cmd != null)
{
break;
}
}
}
if ((null == cmd) || (cmd instanceof Function))
{
return (Function) cmd;
}
return new CommandProxy(cmd, cfunction.substring(1));
}
public void addCommand(String scope, Object target)
{
Class<?> tc = (target instanceof Class<?>) ? (Class<?>) target
: target.getClass();
addCommand(scope, target, tc);
}
public void addCommand(String scope, Object target, Class<?> functions)
{
if (target == null)
{
return;
}
String[] names = getFunctions(functions);
for (String function : names)
{
addCommand(scope, target, function);
}
}
public Object addConstant(String name, Object target)
{
return constants.put(name, target);
}
public Object removeConstant(String name)
{
return constants.remove(name);
}
public void addCommand(String scope, Object target, String function)
{
commands.put((scope + ":" + function).toLowerCase(), target);
}
public void removeCommand(String scope, String function)
{
String func = (scope + ":" + function).toLowerCase();
commands.remove(func);
}
public void removeCommand(Object target)
{
for (Iterator<Object> i = commands.values().iterator(); i.hasNext();)
{
if (i.next() == target)
{
i.remove();
}
}
}
private String[] getFunctions(Class<?> target)
{
String[] functions;
Set<String> list = new TreeSet<String>();
Method methods[] = target.getMethods();
for (Method m : methods)
{
if (m.getDeclaringClass().equals(Object.class))
{
continue;
}
list.add(m.getName());
if (m.getName().startsWith("get"))
{
String s = m.getName().substring(3);
if (s.length() > 0)
{
list.add(s.substring(0, 1).toLowerCase() + s.substring(1));
}
}
}
functions = list.toArray(new String[list.size()]);
return functions;
}
protected void put(String name, Object target)
{
commands.put(name, target);
}
public Object convert(Class<?> desiredType, Object in)
{
for (Converter c : converters)
{
try
{
Object converted = c.convert(desiredType, in);
if (converted != null)
{
return converted;
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
return null;
}
// eval is needed to force expansions to be treated as commands (FELIX-1473)
public Object eval(CommandSession session, Object[] argv) throws Exception
{
StringBuilder buf = new StringBuilder();
for (Object arg : argv)
{
if (buf.length() > 0)
buf.append(' ');
buf.append(arg);
}
return session.execute(buf);
}
void beforeExecute(CommandSession session, CharSequence commandline)
{
for (CommandSessionListener l : listeners)
{
try
{
l.beforeExecute(session, commandline);
}
catch (Throwable t)
{
// Ignore
}
}
}
void afterExecute(CommandSession session, CharSequence commandline, Exception exception)
{
for (CommandSessionListener l : listeners)
{
try
{
l.afterExecute(session, commandline, exception);
}
catch (Throwable t)
{
// Ignore
}
}
}
void afterExecute(CommandSession session, CharSequence commandline, Object result)
{
for (CommandSessionListener l : listeners)
{
try
{
l.afterExecute(session, commandline, result);
}
catch (Throwable t)
{
// Ignore
}
}
}
}