/*******************************************************************************
* HelloNzb -- The Binary Usenet Tool
* Copyright (C) 2010-2013 Matthias F. Brandstetter
* https://sourceforge.net/projects/hellonzb/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package me.mabra.hellonzb.httpserver.nioengine;
import me.mabra.hellonzb.AppConnector;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.python.core.*;
import org.python.util.PythonInterpreter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Handle Python pages for the HelloNzb Web Server via built-in Jython.
*
* @author Matthias F. Brandstetter
*/
public class HttpJythonHandler
{
private final PythonInterpreter jython;
private HashMap<String, String> resourceFiles;
public HttpJythonHandler()
{
resourceFiles = new HashMap<String, String>();
// init. Jython
PySystemState.initialize();
PySystemState sys = Py.getSystemState();
sys.path.append(new PyString(System.getProperty("user.dir") + File.separator + "web" + File.separator + "python"));
jython = new PythonInterpreter(null, sys);
}
public void addResource(String uri, String path)
{
resourceFiles.put(uri, path);
}
public void messageReceived(HttpServerHandler parentHandler, MessageEvent e, HttpRequest request) throws IOException
{
// get name of file to handle
String path = null;
String page = parentHandler.requestedPage();
for(String key : resourceFiles.keySet())
{
if(page.startsWith(key))
{
path = resourceFiles.get(key);
break;
}
}
if(path == null)
{
System.err.println("Can't locate resource file to page " + page);
parentHandler.pageNotFound(e);
return;
}
File resource = new File(path);
if(!resource.isFile() || !resource.canRead())
{
System.err.println("Can't access resource file " + path);
throw new IOException(); // TODO
}
// retrieve parameters and pass them to the AppConnector
AppConnector._instance()._setQueryParams(parentHandler.getQueryParams());
// call Jython to generate HTML response
StringBuilder jythonResp = callJython(resource);
// redirect called from Python script?
String response = jythonResp.toString();
if(response.startsWith("Redirect:"))
{
parentHandler.redirect(e, response.split("\\:")[1]);
return;
}
// send Jython-generated HTML response back to client
parentHandler.writeResponse(e, "text/html", response);
}
private StringBuilder callJython(File script)
{
StringBuilder response = new StringBuilder();
resetJython();
AppConnector._instance()._resetHttpOutBuf();
AppConnector._instance()._resetRedirect();
try
{
// call Jython interpreter with Python source file
InputStream is = new FileInputStream(script);
jython.execfile(is);
is.close();
// redirect called from Python?
String redirect = AppConnector._instance()._getRedirect();
if(redirect != null)
{
response.append("Redirect:" + redirect);
}
else
{
// no redirect, parse output from Python file
ArrayList<String> httpOut = AppConnector._instance()._getHttpOutBuf();
for(String line : httpOut)
response.append(line);
}
}
catch(PyException ex)
{
AppConnector._instance()._getLogger().printStackTrace(ex);
for(String line : jythonErrorToHTML(ex))
response.append(line);
}
catch(Exception ex)
{
AppConnector._instance()._getLogger().printStackTrace(ex);
}
return response;
}
private void resetJython()
{
List<String> scriptLocals = new ArrayList<String>();
PyObject locals = jython.getLocals();
for(PyObject item : locals.__iter__().asIterable())
scriptLocals.add(item.toString());
for(String string : scriptLocals)
jython.set(string, null);
}
private ArrayList<String> jythonErrorToHTML(PyException err)
{
ArrayList<String> html = new ArrayList<String>();
html.add("<html><head><title>Jython Error</title></head><body>");
html.add("<h3>Python Code generated an Error</h3><pre>");
for(String line : err.toString().split("\n"))
html.add(line);
html.add("</pre></body></html>");
return html;
}
}