Fixing bug #306825: now shell.Global can be used as scope objects in servlets
git-svn-id: svn://10.0.0.236/trunk@179536 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
561750bb44
commit
41d85eb65f
@ -101,6 +101,19 @@ public class ToolErrorReporter implements ErrorReporter {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getExceptionMessage(RhinoException ex)
|
||||
{
|
||||
String msg;
|
||||
if (ex instanceof JavaScriptException) {
|
||||
msg = getMessage("msg.uncaughtJSException", ex.details());
|
||||
} else if (ex instanceof EcmaError) {
|
||||
msg = getMessage("msg.uncaughtEcmaError", ex.details());
|
||||
} else {
|
||||
msg = ex.toString();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void warning(String message, String sourceName, int line,
|
||||
String lineSource, int lineOffset)
|
||||
{
|
||||
@ -139,18 +152,27 @@ public class ToolErrorReporter implements ErrorReporter {
|
||||
this.reportWarnings = reportWarnings;
|
||||
}
|
||||
|
||||
public static void reportException(ErrorReporter er, RhinoException ex)
|
||||
{
|
||||
if (er instanceof ToolErrorReporter) {
|
||||
((ToolErrorReporter)er).reportException(ex);
|
||||
} else {
|
||||
String msg = getExceptionMessage(ex);
|
||||
er.error(msg, ex.sourceName(), ex.lineNumber(),
|
||||
ex.lineSource(), ex.columnNumber());
|
||||
}
|
||||
}
|
||||
|
||||
public void reportException(RhinoException ex)
|
||||
{
|
||||
String msg;
|
||||
if (ex instanceof JavaScriptException) {
|
||||
msg = getMessage("msg.uncaughtJSException", ex.details());
|
||||
} else if (ex instanceof EcmaError) {
|
||||
msg = getMessage("msg.uncaughtEcmaError", ex.details());
|
||||
if (ex instanceof WrappedException) {
|
||||
WrappedException we = (WrappedException)ex;
|
||||
we.printStackTrace(err);
|
||||
} else {
|
||||
msg = ex.toString();
|
||||
String msg = getExceptionMessage(ex);
|
||||
reportErrorMessage(msg, ex.sourceName(), ex.lineNumber(),
|
||||
ex.lineSource(), ex.columnNumber(), false);
|
||||
}
|
||||
reportErrorMessage(msg, ex.sourceName(), ex.lineNumber(),
|
||||
ex.lineSource(), ex.columnNumber(), false);
|
||||
}
|
||||
|
||||
private void reportErrorMessage(String message, String sourceName, int line,
|
||||
|
||||
@ -38,8 +38,11 @@
|
||||
|
||||
package org.mozilla.javascript.tools.debugger;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.mozilla.javascript.*;
|
||||
import java.io.*;
|
||||
import org.mozilla.javascript.tools.shell.Global;
|
||||
|
||||
|
||||
public class Main implements ContextListener
|
||||
@ -59,12 +62,20 @@ public class Main implements ContextListener
|
||||
static final int SCOPE_PROVIDER = 2;
|
||||
|
||||
private final int type;
|
||||
Scriptable scope;
|
||||
|
||||
IProxy(int type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static ScopeProvider newScopeProvider(Scriptable scope)
|
||||
{
|
||||
IProxy scopeProvider = new IProxy(SCOPE_PROVIDER);
|
||||
scopeProvider.scope = scope;
|
||||
return scopeProvider;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
if (type != EXIT_ACTION) Kit.codeBug();
|
||||
@ -74,7 +85,8 @@ public class Main implements ContextListener
|
||||
public Scriptable getScope()
|
||||
{
|
||||
if (type != SCOPE_PROVIDER) Kit.codeBug();
|
||||
return org.mozilla.javascript.tools.shell.Main.getScope();
|
||||
if (scope == null) Kit.codeBug();
|
||||
return scope;
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,6 +146,11 @@ public class Main implements ContextListener
|
||||
dim.go();
|
||||
}
|
||||
|
||||
public void setScope(Scriptable scope)
|
||||
{
|
||||
setScopeProvider(IProxy.newScopeProvider(scope));
|
||||
}
|
||||
|
||||
public void setScopeProvider(ScopeProvider p) {
|
||||
dim.scopeProvider = p;
|
||||
}
|
||||
@ -257,14 +274,20 @@ public class Main implements ContextListener
|
||||
Main main = new Main("Rhino JavaScript Debugger");
|
||||
main.doBreak();
|
||||
main.setExitAction(new IProxy(IProxy.EXIT_ACTION));
|
||||
|
||||
System.setIn(main.getIn());
|
||||
System.setOut(main.getOut());
|
||||
System.setErr(main.getErr());
|
||||
|
||||
Global global = org.mozilla.javascript.tools.shell.Main.getGlobal();
|
||||
global.setIn(main.getIn());
|
||||
global.setOut(main.getOut());
|
||||
global.setErr(main.getErr());
|
||||
|
||||
main.attachTo(
|
||||
org.mozilla.javascript.tools.shell.Main.shellContextFactory);
|
||||
|
||||
main.setScopeProvider(new IProxy(IProxy.SCOPE_PROVIDER));
|
||||
main.setScope(global);
|
||||
|
||||
main.pack();
|
||||
main.setSize(600, 460);
|
||||
@ -275,8 +298,19 @@ public class Main implements ContextListener
|
||||
|
||||
public static void mainEmbedded(String title)
|
||||
{
|
||||
IProxy scopeProvider = new IProxy(IProxy.SCOPE_PROVIDER);
|
||||
mainEmbedded(ContextFactory.getGlobal(), scopeProvider, title);
|
||||
ContextFactory factory = ContextFactory.getGlobal();
|
||||
Global global = new Global();
|
||||
global.init(factory);
|
||||
mainEmbedded(factory, global, title);
|
||||
}
|
||||
|
||||
// same as plain main(), stdin/out/err redirection removed and
|
||||
// explicit ContextFactory and scope
|
||||
public static void mainEmbedded(ContextFactory factory,
|
||||
Scriptable scope,
|
||||
String title)
|
||||
{
|
||||
mainEmbeddedImpl(factory, scope, title);
|
||||
}
|
||||
|
||||
// same as plain main(), stdin/out/err redirection removed and
|
||||
@ -284,6 +318,14 @@ public class Main implements ContextListener
|
||||
public static void mainEmbedded(ContextFactory factory,
|
||||
ScopeProvider scopeProvider,
|
||||
String title)
|
||||
{
|
||||
mainEmbeddedImpl(factory, scopeProvider, title);
|
||||
}
|
||||
|
||||
|
||||
private static void mainEmbeddedImpl(ContextFactory factory,
|
||||
Object scopeProvider,
|
||||
String title)
|
||||
{
|
||||
if (title == null) {
|
||||
title = "Rhino JavaScript Debugger (embedded usage)";
|
||||
@ -293,7 +335,18 @@ public class Main implements ContextListener
|
||||
main.setExitAction(new IProxy(IProxy.EXIT_ACTION));
|
||||
|
||||
main.attachTo(factory);
|
||||
main.setScopeProvider(scopeProvider);
|
||||
if (scopeProvider instanceof ScopeProvider) {
|
||||
main.setScopeProvider((ScopeProvider)scopeProvider);
|
||||
} else {
|
||||
Scriptable scope = (Scriptable)scopeProvider;
|
||||
if (scope instanceof Global) {
|
||||
Global global = (Global)scope;
|
||||
global.setIn(main.getIn());
|
||||
global.setOut(main.getOut());
|
||||
global.setErr(main.getErr());
|
||||
}
|
||||
main.setScope(scope);
|
||||
}
|
||||
|
||||
main.pack();
|
||||
main.setSize(600, 460);
|
||||
|
||||
@ -173,6 +173,9 @@ msg.shell.readFile.bad.args =\
|
||||
msg.shell.readUrl.bad.args =\
|
||||
readUrl require at least file path to be specified
|
||||
|
||||
msg.shell.bad.function.scope =\
|
||||
Wrong scope object for shell function: {0}
|
||||
|
||||
msg.idswitch.same_string =\
|
||||
The string {0} is used second time in the switch code. \
|
||||
Previous occurrence was at line {1}
|
||||
|
||||
@ -66,11 +66,22 @@ public class Global extends ImporterTopLevel
|
||||
init(cx);
|
||||
}
|
||||
|
||||
public void init(ContextFactory factory)
|
||||
{
|
||||
factory.call(new ContextAction() {
|
||||
public Object run(Context cx)
|
||||
{
|
||||
init(cx);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void init(Context cx)
|
||||
{
|
||||
// Define some global functions particular to the shell. Note
|
||||
// that these functions are not part of ECMA.
|
||||
initStandardObjects(cx, Main.sealedStdLib);
|
||||
initStandardObjects(cx, sealedStdLib);
|
||||
String[] names = { "print", "quit", "version", "load", "help",
|
||||
"loadClass", "defineClass", "spawn", "sync",
|
||||
"serialize", "deserialize", "runCommand",
|
||||
@ -98,7 +109,7 @@ public class Global extends ImporterTopLevel
|
||||
public static void help(Context cx, Scriptable thisObj,
|
||||
Object[] args, Function funObj)
|
||||
{
|
||||
PrintStream out = getInstance(thisObj).getOut();
|
||||
PrintStream out = getInstance(funObj).getOut();
|
||||
out.println(ToolErrorReporter.getMessage("msg.help"));
|
||||
}
|
||||
|
||||
@ -114,7 +125,7 @@ public class Global extends ImporterTopLevel
|
||||
public static Object print(Context cx, Scriptable thisObj,
|
||||
Object[] args, Function funObj)
|
||||
{
|
||||
PrintStream out = getInstance(thisObj).getOut();
|
||||
PrintStream out = getInstance(funObj).getOut();
|
||||
for (int i=0; i < args.length; i++) {
|
||||
if (i > 0)
|
||||
out.print(" ");
|
||||
@ -168,7 +179,7 @@ public class Global extends ImporterTopLevel
|
||||
public static void load(Context cx, Scriptable thisObj,
|
||||
Object[] args, Function funObj)
|
||||
{
|
||||
for (int i=0; i < args.length; i++) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
Main.processFile(cx, thisObj, Context.toString(args[i]));
|
||||
}
|
||||
}
|
||||
@ -313,6 +324,7 @@ public class Global extends ImporterTopLevel
|
||||
} else {
|
||||
throw reportRuntimeError("msg.spawn.args");
|
||||
}
|
||||
runner.factory = cx.getFactory();
|
||||
Thread thread = new Thread(runner);
|
||||
thread.start();
|
||||
return thread;
|
||||
@ -459,7 +471,7 @@ public class Global extends ImporterTopLevel
|
||||
addArgs = cx.getElements(s);
|
||||
}
|
||||
}
|
||||
Global global = getInstance(thisObj);
|
||||
Global global = getInstance(funObj);
|
||||
if (out == null) {
|
||||
out = (global != null) ? global.getOut() : System.out;
|
||||
}
|
||||
@ -602,17 +614,18 @@ public class Global extends ImporterTopLevel
|
||||
errStream = err;
|
||||
}
|
||||
|
||||
public static Global getInstance(Scriptable scope)
|
||||
public void setSealedStdLib(boolean value)
|
||||
{
|
||||
scope = ScriptableObject.getTopLevelScope(scope);
|
||||
do {
|
||||
if (scope instanceof Global) {
|
||||
return (Global)scope;
|
||||
}
|
||||
scope = scope.getPrototype();
|
||||
} while (scope != null);
|
||||
sealedStdLib = value;
|
||||
}
|
||||
|
||||
return null;
|
||||
private static Global getInstance(Function function)
|
||||
{
|
||||
Scriptable scope = function.getParentScope();
|
||||
if (!(scope instanceof Global))
|
||||
throw reportRuntimeError("msg.bad.shell.function.scope",
|
||||
String.valueOf(scope));
|
||||
return (Global)scope;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -925,9 +938,10 @@ public class Global extends ImporterTopLevel
|
||||
}
|
||||
|
||||
NativeArray history;
|
||||
public InputStream inStream;
|
||||
public PrintStream outStream;
|
||||
public PrintStream errStream;
|
||||
private InputStream inStream;
|
||||
private PrintStream outStream;
|
||||
private PrintStream errStream;
|
||||
private boolean sealedStdLib = false;
|
||||
boolean initialized;
|
||||
}
|
||||
|
||||
@ -947,7 +961,7 @@ class Runner implements Runnable, ContextAction {
|
||||
|
||||
public void run()
|
||||
{
|
||||
Main.shellContextFactory.call(this);
|
||||
factory.call(this);
|
||||
}
|
||||
|
||||
public Object run(Context cx)
|
||||
@ -958,6 +972,7 @@ class Runner implements Runnable, ContextAction {
|
||||
return s.exec(cx, scope);
|
||||
}
|
||||
|
||||
ContextFactory factory;
|
||||
private Scriptable scope;
|
||||
private Function f;
|
||||
private Script s;
|
||||
|
||||
@ -94,7 +94,6 @@ public class Main
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main entry point.
|
||||
*
|
||||
@ -123,21 +122,15 @@ public class Main
|
||||
*/
|
||||
public static int exec(String origArgs[])
|
||||
{
|
||||
|
||||
for (int i=0; i < origArgs.length; i++) {
|
||||
String arg = origArgs[i];
|
||||
if (arg.equals("-sealedlib")) {
|
||||
sealedStdLib = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
errorReporter = new ToolErrorReporter(false, global.getErr());
|
||||
shellContextFactory.setErrorReporter(errorReporter);
|
||||
String[] args = processOptions(origArgs);
|
||||
if (processStdin)
|
||||
fileList.addElement(null);
|
||||
|
||||
if (!global.initialized) {
|
||||
global.init(shellContextFactory);
|
||||
}
|
||||
IProxy iproxy = new IProxy(IProxy.PROCESS_FILES);
|
||||
iproxy.args = args;
|
||||
shellContextFactory.call(iproxy);
|
||||
@ -147,9 +140,6 @@ public class Main
|
||||
|
||||
static void processFiles(Context cx, String[] args)
|
||||
{
|
||||
if (!global.initialized) {
|
||||
global.init(cx);
|
||||
}
|
||||
// define "arguments" array in the top-level object:
|
||||
// need to allocate new array since newArray requires instances
|
||||
// of exactly Object[], not ObjectSubclass[]
|
||||
@ -239,6 +229,9 @@ public class Main
|
||||
usageError = arg;
|
||||
break goodUsage;
|
||||
}
|
||||
if (!global.initialized) {
|
||||
global.init(shellContextFactory);
|
||||
}
|
||||
IProxy iproxy = new IProxy(IProxy.EVAL_INLINE_SCRIPT);
|
||||
iproxy.scriptText = args[i];
|
||||
shellContextFactory.call(iproxy);
|
||||
@ -258,15 +251,15 @@ public class Main
|
||||
continue;
|
||||
}
|
||||
if (arg.equals("-sealedlib")) {
|
||||
// Should already be processed
|
||||
if (!sealedStdLib) Kit.codeBug();
|
||||
global.setSealedStdLib(true);
|
||||
continue;
|
||||
}
|
||||
usageError = arg;
|
||||
break goodUsage;
|
||||
}
|
||||
// print usage message
|
||||
p(ToolErrorReporter.getMessage("msg.shell.usage", usageError));
|
||||
global.getOut().println(
|
||||
ToolErrorReporter.getMessage("msg.shell.usage", usageError));
|
||||
System.exit(1);
|
||||
return null;
|
||||
}
|
||||
@ -303,9 +296,10 @@ public class Main
|
||||
public static void processSource(Context cx, String filename)
|
||||
{
|
||||
if (filename == null || filename.equals("-")) {
|
||||
PrintStream ps = global.getErr();
|
||||
if (filename == null) {
|
||||
// print implementation version
|
||||
getOut().println(cx.getImplementationVersion());
|
||||
ps.println(cx.getImplementationVersion());
|
||||
}
|
||||
|
||||
// Use the interpreter for interactive input
|
||||
@ -318,8 +312,8 @@ public class Main
|
||||
while (!hitEOF) {
|
||||
int startline = lineno;
|
||||
if (filename == null)
|
||||
global.getErr().print("js> ");
|
||||
global.getErr().flush();
|
||||
ps.print("js> ");
|
||||
ps.flush();
|
||||
String source = "";
|
||||
|
||||
// Collect lines of source to compile.
|
||||
@ -329,7 +323,7 @@ public class Main
|
||||
newline = in.readLine();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
global.getErr().println(ioe.toString());
|
||||
ps.println(ioe.toString());
|
||||
break;
|
||||
}
|
||||
if (newline == null) {
|
||||
@ -347,16 +341,17 @@ public class Main
|
||||
Object result = evaluateScript(script, cx, global);
|
||||
if (result != Context.getUndefinedValue()) {
|
||||
try {
|
||||
global.getErr().println(Context.toString(result));
|
||||
ps.println(Context.toString(result));
|
||||
} catch (RhinoException rex) {
|
||||
errorReporter.reportException(rex);
|
||||
ToolErrorReporter.reportException(
|
||||
cx.getErrorReporter(), rex);
|
||||
}
|
||||
}
|
||||
NativeArray h = global.history;
|
||||
h.put((int)h.getLength(), h, source);
|
||||
}
|
||||
}
|
||||
global.getErr().println();
|
||||
ps.println();
|
||||
} else {
|
||||
processFile(cx, global, filename);
|
||||
}
|
||||
@ -412,14 +407,12 @@ public class Main
|
||||
try {
|
||||
return cx.compileString(scriptSource, path, lineno,
|
||||
securityDomain);
|
||||
} catch (WrappedException we) {
|
||||
global.getErr().println(we.getWrappedException().toString());
|
||||
we.printStackTrace();
|
||||
} catch (EvaluatorException ee) {
|
||||
// Already printed message.
|
||||
exitCode = EXITCODE_RUNTIME_ERROR;
|
||||
} catch (RhinoException rex) {
|
||||
errorReporter.reportException(rex);
|
||||
ToolErrorReporter.reportException(
|
||||
cx.getErrorReporter(), rex);
|
||||
exitCode = EXITCODE_RUNTIME_ERROR;
|
||||
} catch (VirtualMachineError ex) {
|
||||
// Treat StackOverflow and OutOfMemory as runtime errors
|
||||
@ -464,7 +457,8 @@ public class Main
|
||||
}
|
||||
return (Script) clazz.newInstance();
|
||||
} catch (RhinoException rex) {
|
||||
errorReporter.reportException(rex);
|
||||
ToolErrorReporter.reportException(
|
||||
cx.getErrorReporter(), rex);
|
||||
exitCode = EXITCODE_RUNTIME_ERROR;
|
||||
} catch (IllegalAccessException iaex) {
|
||||
exitCode = EXITCODE_RUNTIME_ERROR;
|
||||
@ -479,16 +473,11 @@ public class Main
|
||||
public static Object evaluateScript(Script script, Context cx,
|
||||
Scriptable scope)
|
||||
{
|
||||
if (!global.initialized) {
|
||||
global.init(cx);
|
||||
}
|
||||
try {
|
||||
return script.exec(cx, scope);
|
||||
} catch (WrappedException we) {
|
||||
global.getErr().println(we.getWrappedException().toString());
|
||||
we.printStackTrace();
|
||||
} catch (RhinoException rex) {
|
||||
errorReporter.reportException(rex);
|
||||
ToolErrorReporter.reportException(
|
||||
cx.getErrorReporter(), rex);
|
||||
exitCode = EXITCODE_RUNTIME_ERROR;
|
||||
} catch (VirtualMachineError ex) {
|
||||
// Treat StackOverflow and OutOfMemory as runtime errors
|
||||
@ -501,39 +490,28 @@ public class Main
|
||||
return Context.getUndefinedValue();
|
||||
}
|
||||
|
||||
private static void p(String s) {
|
||||
global.getOut().println(s);
|
||||
}
|
||||
|
||||
public static ScriptableObject getScope() {
|
||||
if (!global.initialized) {
|
||||
global.init(Context.getCurrentContext());
|
||||
}
|
||||
return global;
|
||||
}
|
||||
|
||||
public static InputStream getIn() {
|
||||
return Global.getInstance(getGlobal()).getIn();
|
||||
return getGlobal().getIn();
|
||||
}
|
||||
|
||||
public static void setIn(InputStream in) {
|
||||
Global.getInstance(getGlobal()).setIn(in);
|
||||
getGlobal().setIn(in);
|
||||
}
|
||||
|
||||
public static PrintStream getOut() {
|
||||
return Global.getInstance(getGlobal()).getOut();
|
||||
return getGlobal().getOut();
|
||||
}
|
||||
|
||||
public static void setOut(PrintStream out) {
|
||||
Global.getInstance(getGlobal()).setOut(out);
|
||||
getGlobal().setOut(out);
|
||||
}
|
||||
|
||||
public static PrintStream getErr() {
|
||||
return Global.getInstance(getGlobal()).getErr();
|
||||
return getGlobal().getErr();
|
||||
}
|
||||
|
||||
public static void setErr(PrintStream err) {
|
||||
Global.getInstance(getGlobal()).setErr(err);
|
||||
getGlobal().setErr(err);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -613,9 +591,7 @@ public class Main
|
||||
static protected int exitCode = 0;
|
||||
static private final int EXITCODE_RUNTIME_ERROR = 3;
|
||||
static private final int EXITCODE_FILE_NOT_FOUND = 4;
|
||||
//static private DebugShell debugShell;
|
||||
static boolean processStdin = true;
|
||||
static boolean sealedStdLib = false;
|
||||
static Vector fileList = new Vector(5);
|
||||
private static SecurityProxy securityImpl;
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ import org.mozilla.javascript.*;
|
||||
class Namespace extends IdScriptableObject
|
||||
{
|
||||
static final long serialVersionUID = -5765755238131301744L;
|
||||
|
||||
|
||||
private static final Object NAMESPACE_TAG = new Object();
|
||||
|
||||
private XMLLibImpl lib;
|
||||
|
||||
@ -46,7 +46,7 @@ import org.mozilla.javascript.*;
|
||||
final class QName extends IdScriptableObject
|
||||
{
|
||||
static final long serialVersionUID = 416745167693026750L;
|
||||
|
||||
|
||||
private static final Object QNAME_TAG = new Object();
|
||||
|
||||
XMLLibImpl lib;
|
||||
|
||||
@ -51,7 +51,7 @@ import org.apache.xmlbeans.XmlOptions;
|
||||
class XML extends XMLObjectImpl
|
||||
{
|
||||
static final long serialVersionUID = -630969919086449092L;
|
||||
|
||||
|
||||
final static class XScriptAnnotation extends XmlBookmark
|
||||
{
|
||||
javax.xml.namespace.QName _name;
|
||||
|
||||
@ -40,7 +40,7 @@ import org.mozilla.javascript.*;
|
||||
class XMLCtor extends IdFunctionObject
|
||||
{
|
||||
static final long serialVersionUID = -8708195078359817341L;
|
||||
|
||||
|
||||
private static final Object XMLCTOR_TAG = new Object();
|
||||
|
||||
private XMLLibImpl lib;
|
||||
|
||||
@ -47,7 +47,7 @@ import org.apache.xmlbeans.XmlCursor;
|
||||
class XMLList extends XMLObjectImpl implements Function
|
||||
{
|
||||
static final long serialVersionUID = -4543618751670781135L;
|
||||
|
||||
|
||||
static class AnnotationList
|
||||
{
|
||||
private Vector v;
|
||||
|
||||
@ -45,7 +45,7 @@ import org.mozilla.javascript.Undefined;
|
||||
class XMLName extends Ref
|
||||
{
|
||||
static final long serialVersionUID = 3832176310755686977L;
|
||||
|
||||
|
||||
private String uri;
|
||||
private String localName;
|
||||
private boolean isAttributeName;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user