package example;

import java.io.BufferedReader;
import java.io.Console;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import ognl.ClassResolver;
import ognl.DefaultClassResolver;
import ognl.Ognl;
import ognl.OgnlException;

/**
 *
 * @author <a href="https://github.com/naokikimura">naokikimura</a>
 *
 */
public abstract class App {

    private static final Logger LOG = Logger.getLogger(App.class.getName());

    private static final ResourceBundle resources = ResourceBundle.getBundle(App.class.getName());

    public abstract void execute(final Map context, final Object root) throws Exception;

    public void execute(final Map context) throws Exception {
        execute(context, Ognl.getRoot(context));
    }

    static App create(final InputStream in, final PrintStream out, final PrintStream err) {
        return new App() {
            @Override
            public void execute(final Map context, final Object root) throws Exception {
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                String expression;
                while ((expression = reader.readLine()) != null) {
                    try {
                        Object value = Ognl.getValue(expression, context, root);
                        out.printf(resources.getString("out.printf.format"), value);
                    } catch (OgnlException e) {
                        err.printf(resources.getString("err.printf.format"), e);
                    }
                }
            }
        };
    }

    static App create(final Console console, final PrintWriter out, final PrintStream err) {
        return new App() {
            @Override
            public void execute(final Map context, final Object root) throws Exception {
                int line = 0;
                while (true) {
                    String expression = console.readLine(resources.getString("console.readLine.format"), ++line);
                    if (expression == null) {
                        console.printf("%n");
                        return;
                    } else if (expression.trim().equals("")) {
                        continue;
                    }

                    try {
                        Object value = Ognl.getValue(expression, context, root);
                        out.printf(resources.getString("console.printf.format"), value);
                    } catch (OgnlException e) {
                        err.printf(resources.getString("err.printf.format"), e);
                    }
                }
            }
        };
    }

    static App create() {
        Console console = System.console();
        if (console == null) {
            return App.create(System.in, System.out, System.err);
        } else {
            return App.create(console, console.writer(), System.err);
        }
    }

    static ClassResolver createClassResolver() throws MalformedURLException {
        String classpath = System.getProperty("ognl.repl.classpath");
        LOG.config(String.format("ognl.repl.classpath = %s", classpath));
        List<URL> urls = new ArrayList<URL>();
        for (String path : (classpath == null ? "" : classpath).split(":")) {
            URL url = new File(path).toURI().toURL();
            LOG.config(String.format("classpath = %s", url));
            urls.add(url);
        }
        final ClassLoader classLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]));
        return new DefaultClassResolver() {

            @Override
            public Class classForName(String className, Map context) throws ClassNotFoundException {
                try {
                    return Class.forName(className, true, classLoader);
                } catch (ClassNotFoundException e) {
                    LOG.log(Level.FINE, null, e);
                    return super.classForName(className, context);
                }
            }
        };
    }

    static Object newRootInstance() throws OgnlException {
        String expression = System.getProperty("ognl.repl.root.expression");
        return expression == null || expression.equals("") ? null : Ognl.getValue(expression, null);
    }

    public static void main(String[] args) throws Exception {
        App app = create();
        app.execute(Ognl.createDefaultContext(newRootInstance(), createClassResolver()));
    }
}

@@ -547,16 +547,41 @@
 l.Ognl;%0A
+import ognl.OgnlContext;%0A
 import o
@@ -785,24 +785,382 @@
 etName());%0A%0A
+    static final String DEFAULT_ROOT_EXPRESSION = %22#%7B%5C%22out%5C%22:@java.lang.System@out,%5C%22err%5C%22:@java.lang.System@err,%5C%22env%5C%22:@java.lang.System@getenv(),%5C%22properties%5C%22:@java.lang.System@getProperties(),%5C%22in%5C%22:@java.lang.System@class.getField(%5C%22in%5C%22).get(null),%5C%22console%5C%22:@java.lang.System@console(),%5C%22securityManager%5C%22:@java.lang.System@getSecurityManager()%7D%22;%0A%0A
     private 
@@ -4714,32 +4714,314 @@
 OgnlException %7B%0A
+        return newRootInstance(new OgnlContext());%0A    %7D%0A%0A    static Object newRootInstance(Map context) throws OgnlException %7B%0A        return newRootInstance(context, Ognl.getRoot(context));%0A    %7D%0A%0A    static Object newRootInstance(Map context, Object root) throws OgnlException %7B%0A
         String e
@@ -5089,23 +5089,57 @@
         
-return 
+LOG.config(String.format(%22ognl.repl.root.
 expressi
@@ -5146,17 +5146,13 @@
 on =
-= null %7C%7C
+ %25s%22,
  exp
@@ -5158,26 +5158,55 @@
 pression
-.equals(%22%22
+));%0A        return %22%22.equals(expression
 ) ? null
@@ -5232,22 +5232,78 @@
 pression
-,
+ ==
  null
+ ? DEFAULT_ROOT_EXPRESSION : expression, context, root
 );%0A    %7D
@@ -5406,72 +5406,201 @@
     
-app.execute(Ognl.createDefaultContext(newRootInstance(), createC
+ClassResolver classResolver = createClassResolver();%0A        Object root = newRootInstance(Ognl.createDefaultContext(null, classResolver));%0A        app.execute(Ognl.createDefaultContext(root, c
 lass
@@ -5607,18 +5607,16 @@
 Resolver
-()
 ));%0A    
@@ -5618,9 +5618,8 @@
 %0A    %7D%0A%7D
-%0A

Update App.java