Placebo is a java based web server/library designed to work well with small admin
portals or web based control panels. Its capable of handling sessions, and has
a built in "plugin" format for designing simple http apps. To launch placebo, simply
run the jar file and the application will start in gui mode. For command line options
try launching with --help
front end
detailed logging
Creating a plugin
Here is a sample plugin class. This is a simple keystore using a JSONObject.
/*
Copyright (C) 2010 Brian Dunigan
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 .
*/
package org.openstatic.placebo.plugins;
import org.openstatic.http.HttpRequest;
import org.openstatic.http.HttpResponse;
import org.openstatic.placebo.*;
import org.openstatic.util.JSONUtil;
import java.util.Date;
import java.util.Properties;
import java.util.Enumeration;
import java.util.StringTokenizer;
import javax.swing.JTextPane;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import java.awt.Font;
import org.json.*;
public class KeyStore implements PlaceboPlugin
{
protected JSONObject store;
private JTextPane json_box;
private boolean swing_mode;
protected boolean keep_running;
private Thread key_gc;
private int key_timeout;
public boolean startup(CoreServer core, String mount_location)
{
System.err.println("KeyStore: Initializing Keystore");
this.keep_running = true;
this.key_timeout = Integer.valueOf(core.getSettings().getProperty("keystore_timeout", "3600")).intValue();
store = new JSONObject();
key_gc = new Thread()
{
public void run()
{
while(KeyStore.this.keep_running)
{
try
{
expire_check(KeyStore.this.store);
Thread.sleep(1000);
} catch (Exception e) {}
}
}
public void expire_check(JSONObject jo) throws Exception
{
String[] fnames = JSONObject.getNames(jo);
if (fnames != null)
{
for (int i = 0; i < fnames.length; i++)
{
Object value = jo.get(fnames[i]);
if (value instanceof JSONObject)
{
JSONObject nd = (JSONObject) value;
boolean expired = false;
try
{
int exp = nd.getInt("_expires");
exp--;
if (exp <= 0)
expired = true;
nd.put("_expires", exp);
} catch (Exception e) {}
if (expired)
jo.remove(fnames[i]);
else
expire_check(nd);
}
}
}
}
};
key_gc.start();
if (core.isSwingOk())
{
json_box = new JTextPane();
json_box.setContentType("text/html");
Font font = new Font("Monospaced", Font.BOLD, 12);
json_box.setFont(font);
JScrollPane scroller = new JScrollPane(json_box);
scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
core.addPanel("Keystore [" + mount_location + "]", scroller);
this.swing_mode = true;
} else {
this.swing_mode = false;
}
return true;
}
public void updateBox(JSONObject data) throws Exception
{
if (this.swing_mode)
json_box.setText("" + JSONUtil.json2table(store) + "");
}
public void onRequest(HttpRequest request) throws Exception
{
HttpResponse response = new HttpResponse();
if (request.getPath().equals("/set/"))
{
for(Enumeration keys = request.getGetKeys(); keys.hasMoreElements(); )
{
String key = keys.nextElement();
store.put(key, request.getGetValue(key));
}
updateBox(store);
} else if (request.getPath().startsWith("/set/") && request.getPath().endsWith("/")) {
String storage_path = request.getPath().substring(5);
storage_path = storage_path.substring(0, storage_path.length() - 1);
StringTokenizer st = new StringTokenizer(storage_path, "/");
JSONObject current_object = this.store;
while (st.hasMoreTokens())
{
String current_node = st.nextToken();
try
{
current_object = current_object.getJSONObject(current_node);
current_object.put("_expires", this.key_timeout);
} catch (Exception js_exc) {
JSONObject new_obj = new JSONObject();
new_obj.put("_expires", this.key_timeout);
current_object.put(current_node, new_obj);
current_object = current_object.getJSONObject(current_node);
}
if (!st.hasMoreTokens())
{
for(Enumeration keys = request.getGetKeys(); keys.hasMoreElements(); )
{
String key = keys.nextElement();
current_object.put(key, request.getGetValue(key));
}
}
}
updateBox(store);
}
if (request.getPath().equals("/get/"))
{
response.setData(store);
} else if (request.getPath().startsWith("/get/") && request.getPath().endsWith("/")) {
JSONObject this_response = new JSONObject();
String requested_key = request.getPath().substring(5);
requested_key = requested_key.substring(0, requested_key.length() - 1);
StringTokenizer st = new StringTokenizer(requested_key,"/");
JSONObject current_object = this.store;
while (st.hasMoreTokens())
{
String current_node = st.nextToken();
Object temp_object = current_object.get(current_node);
if (temp_object instanceof JSONObject)
{
current_object = (JSONObject) temp_object;
if (!st.hasMoreTokens())
{
response.setData(current_object);
}
} else {
if (!st.hasMoreTokens())
{
response.setData((String) temp_object);
}
}
}
}
request.sendResponse(response);
}
public boolean shutdown()
{
this.keep_running = false;
System.err.println("KeyStore: Shutdown");
return true;
}
}
This demo program is built into the placebo library and can be executed using java -jar placebohttp.jar --start --debug --plugin /keystore/ org.openstatic.placebo.plugins.KeyStore
When this simple program is mounted within placebo, It can be used like this
http://127.0.0.1:8090/keystore/set/?food=delicious
http://127.0.0.1:8090/keystore/get/food/
(delicious is returned)
Also /keystore/get/ would return a json object with all keys
{"food": "delicious"}
This keystore also supports layered keys with paths
http://127.0.0.1:8090/keystore/set/car/door/?handle=broken
http://127.0.0.1:8090/keystore/set/car/winshield/?glass=cracked
Calling:
http://127.0.0.1:8090/keystore/get/car/
Would result in a json object returned with all of the subkeys and objects of car
{"winshield":{"glass":"cracked"},"door":{"handle":"broken"}}