import java.lang.reflect.*;

    // Interactively control an object of objectClass.
    // The assumption is that this Class has a no-arg constructor.
class DynamicProgram {
    public DynamicProgram(Class objectClass) throws RuntimeException {
        // Make sure objectClass has a no-arg constructor.
        try{
            Constructor noArgConstructor =
                        objectClass.getConstructor(new Class[0]);
            subject = noArgConstructor.newInstance(new Object[0]);
        }
        catch(NoSuchMethodException e){
            throw new RuntimeException(objectClass.getName()+
                                   " must have a no-arg constructor.");
        }
        catch(IllegalAccessException e){
            throw new RuntimeException(e.toString());
        }
        catch(InstantiationException e){
            throw new RuntimeException(e.toString());
        }
        catch(InvocationTargetException e){
            throw new RuntimeException(e.toString());
        }
    }

        // Interactively read commands from the user and send
        // them as messages to the subject object.
    public void run(){
        // The Object to be controlled.
        final Object subject = getSubject();
        final Class subjectClass = subject.getClass();
        final Method[] methods = subjectClass.getMethods();
        final SimpleInput reader = getReader();
        final String terminatingCommand = "quit!";
        System.out.println("Type "+terminatingCommand+" to finish.");
        String command = getCommand();
        while(!command.equalsIgnoreCase(terminatingCommand)){
            // Make sure the command maps to a method.
            Method method = matchMethod(methods,command);
            if(method != null){
                invokeMethod(method,subject);
            }
            else{
                System.err.println("No match found for: "+command);
            }
            command = getCommand();
        }
    }

        // Invoke the given method, with appropriate arguments,
        // on subject.
        // This method only copes with arguments of primitive type
        // int and double.
    protected void invokeMethod(Method method,Object subject){
        try{
            final Class[] argumentClasses = method.getParameterTypes();
            final int numArgs = argumentClasses.length;
            final Object[] args = new Object[numArgs];
            final SimpleInput reader = getReader();
            for(int i = 0; i < numArgs; i++){
                if(argumentClasses[i] == int.class){
                    args[i] = new Integer(reader.nextInt());
                }
                else if(argumentClasses[i] == double.class){
                    args[i] = new Double(reader.nextDouble());
                }
                else{
                    System.err.println(
                        "Only numerical arguments are possible.");
                    return;
                }
            }
            method.invoke(subject,args);
        }
        catch(IllegalAccessException e){
            System.err.println(e);
        }
        catch(InvocationTargetException e){
            System.err.println(e);
        }
    }

    protected Method matchMethod(Method[] methods, String command){
        final int numMethods = methods.length;
        for(int i = 0; i < numMethods; i++){
            if(methods[i].getName().equalsIgnoreCase(command)){
                return methods[i];
            }
        }
        return null;
    }

    protected String getCommand(){
        System.out.print("Command: ");
        System.out.flush();
        return getReader().nextWord();
    }

    protected Object getSubject(){
        return subject;
    }

    protected SimpleInput getReader(){
        return reader;
    }

    // The instance to be controlled.
    private final Object subject;
    // Where commands are read from.
    private final SimpleInput reader = new SimpleInput();
}
