JavaCompiler と ClassLoader を使用したユーザー コードのコンパイルと実行
-
23-09-2019 - |
質問
Java学習用のWebアプリを作成しています。どのユーザーが自分のサーバー上でコードをコンパイルし、そのコードを実行できるかを使用します。JavaCompiler を使用するとコンパイルが簡単になります。
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, prepareFile(nazwa, content));
task.call();
List<String> returnErrors = new ArrayList<String>();
String tmp = new String();
for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
tmp = String.valueOf(diagnostic.getLineNumber());
tmp += " msg: " + diagnostic.getMessage(null);
returnErrors.add(tmp.replaceAll("\n", " "));
}
コードを使用してクラスをロードすることができました。
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
try {
URL[] urls = {new URL("file:///root/"), new URL("file://C:\\serv\\Apache Tomcat 6.0.20\\bin\\")};
ClassLoader cl_old = Thread.currentThread().getContextClassLoader();
ClassLoader cl_new = new URLClassLoader(urls, cl_old);
Class compiledClass = cl_new.loadClass(CLASS_NAME);
Method myMethod = compiledClass.getMethod(METHOD_NAME);
Object tmp = myMethod.invoke(null);
} catch (Exception ex) {
Logger.getLogger(ITaskCompile.class.getName()).log(Level.SEVERE, null, ex);
}
無限ループや邪悪な学生からアプリを守るにはどうすればよいですか ;)
- そのコードを存続期間付きで実行する方法はありますか?
- メモリリークによるリスクはありますか?これを修正するにはどうすればよいですか?
- これは良い解決策ですか、それとももっと良い解決策を提案していただけますか?
THX。ツィム
解決
どのように私は私の無限ループからのアプリ、と悪の学生を保護することができます;)
あなたは1つのJVMにすることはできません。悪の学生は、スマートなものがあなたの制御機構を破壊するためにいくつかの方法を考え出すになるために対処するのが特に困難である。
1)生涯でそのコードを実行する方法はありますか?
いいえ、あなたは別のJVMでそれを実行しない限ります。
2)のメモリリークを持つ危険性があり、私はこれを修正するために何を行うことができます。
はい、あり、そしてあなたが(離れて別々のJVMから)それについてできることは何もありません。あなたも、塗布後に...アプリケーションは、Javaクラスライブラリは、メモリ/リソースリークが発生する可能性がありますことを、おそらく多くの方法がありますなど、ループにはまり、学生のプログラムを殺すことができたとしても実際には、これは問題になりますそれ自体は終了しGC'edされています。
3)は、この良い解決策である、またはあなたがより良いものを提案することができますか?
ファイル名を指定して実行あなたがProcess
や友人を使用してサーバーから起動することを別のJVM内の各学生のアプリケーション。あなたは、設定された実行時間制限への書き込みホストオペレーティングシステムの特定のものにする必要がありますし、学生のアプリケーションデッドロックの殺すために。プラスあなたが誤ってあまりにも多くのJVMをオフに焼成することにより、ホストマシンのパフォーマンスをゴミ箱していないことを確認して作るの問題のすべての種類を持っています。
より良い答えは、各学生にデスクトップコンピュータまたは仮想マシンを提供し、彼らは自分自身のことを行うようにすることです。
他のヒント
生涯とそのコードを実行する方法はありますか?
子プロセスを監視し、それは時間がかかりすぎる場合は、それを終了し、プロセスを作成します。
メモリリークを持つ危険性があり、私はこれを修正するために何を行うことができます。
あなたは(SunのJVMに-Xmx
パラメータと同様に)割り当てられているどのくらいのメモリ制御することで、ある程度、それを行うことができる必要があります。
は、この優れたソリューションである、またはあなたがより良いものを提案することができますか?
私は必ず解決策が提案されているではないんだけど、ここでは考えがあります。大幅には何を制限していることのSecurityManager のインストール実行されるコードは、このようなアクセスなど、など、ファイルシステム、産卵のプロセスを、行うことができますプロセスでタイムアウトのモニターには、割り当てられたメモリを制限していることなど、別のユーザーアカウントでアプリケーションを実行し、私はあなたが何かを持っていることができると思うことを組み合わせます実用ます。
あなたが探していることは可能ですが、あなたはJavaだけに制限場合は、完全にそうではないかもしれない。
Kalebの回答に加えて、厳格なヒープリミットとターゲットJVMを実行するようにしてください(例。-Xmx16M)。そして、もちろん、あなたが実行しているJVMの数を制限することをお勧めします。
そのような私の現在のソリューションになります。
実行コードます:
@RequestMapping("/student/runITask.action")
public String student_runITask(@ModelAttribute(value = "program") ProgramToCompile program, ModelMap map) {
//1. code compile
ITaskCompile itcompile = new ITaskCompile();
List<String> errorList = itcompile.compileTask(program.getClassname(), program.getProgram());
Date tmp = new Date();
this.setPathName(program.getClassname() + tmp.hashCode());
//2. if compiled...
if (errorList.size() < 1) {
try {
String[] cmd = {"/bin/sh", "-c", "java -Xmx16M -Xms2M -cp /root/ " + program.getClassname() + "> " + getPathName() + ".data"};
Runtime rt = Runtime.getRuntime();
final Process proc = rt.exec(cmd);
Thread.sleep(1000);
proc.destroy();
if (proc.exitValue() > 0) {
try {
killJavaProcesses();
map.addAttribute("comment", "Endless LOOP!");
} catch (Exception ex1) {
Logger.getLogger(CompileITaskControler.class.getName()).log(Level.SEVERE, null, ex1);
}
} else {
StringBuffer fileData = new StringBuffer(1000);
BufferedReader reader = new BufferedReader(new FileReader("/root/" + getPathName() + ".data"));
char[] buf = new char[1024];
int numRead = 0;
while ((numRead = reader.read(buf)) != -1) {
fileData.append(buf, 0, numRead);
}
reader.close();
map.addAttribute("comment","Output: <br/><br/><br/><pre>"+fileData.toString()+"</pre>");
}
} catch (Exception ex) {
try {
killJavaProcesses();
map.addAttribute("comment", "Endless LOOP!");
} catch (Exception ex1) {
Logger.getLogger(CompileITaskControler.class.getName()).log(Level.SEVERE, null, ex1);
}
}
} else {
map.addAttribute("errorList", errorList);
map.addAttribute("comment", "PROGRAM NIE ZOSTAŁ URUCHOMIONY");
} //3. return
return DISPLAY_COMP_MSG;
}
ここでkillJavaProcesses()のようになります。
public void killJavaProcesses() throws IOException, InterruptedException {
String[] getProcessList = {"/bin/sh", "-c", "ps | grep java"};
String[] killProcessByIdList = {"/bin/sh", "-c", "kill -9 "};
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(getProcessList);
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String line2;
String kill = new String();
while ((line2 = bufferedreader.readLine()) != null) {
kill += line2 + "\n";
}
proc.destroy();
String arraykill[] = kill.split("\n");
String element2kill = "";
String[] tmp;
if (arraykill.length >= 1) {
element2kill = arraykill[arraykill.length - 1].trim().split(" ")[0];
}
killProcessByIdList[2] += element2kill;
Process proc2 = rt.exec(killProcessByIdList);
proc2.waitFor();
}
私は、プロセスの異なるを殺すことはできません。 proc.destroy()を使用すると、右のUbuntu / WinのXPマシンでは動作しません。 今私は、のSecurityManager 設定しようと使用しますA>。