/*******************************************************************************
* Copyright 2011 Alex 'Ript' Malyshev <alexript@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package net.autosauler.ballance.server.model;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.script.ScriptException;
import net.autosauler.ballance.server.mongodb.Database;
import net.autosauler.ballance.server.util.Base64;
import net.autosauler.ballance.server.vm.VM;
import net.autosauler.ballance.shared.datatypes.DataTypes;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import com.allen_sauer.gwt.log.client.Log;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
/**
* The Class Scripts.
*
* @author alexript
*/
public class Scripts {
/** The Constant TABLENAME. */
private final static String TABLENAME = "scripts";
/**
* Dump.
*
* @param domain
* the domain
* @return the string
*/
public static String dump(String domain) {
StringBuilder sb = new StringBuilder();
sb.append("<scripts>\n");
DB db = Database.get(domain);
if (db != null) {
Database.retain();
DBCollection coll = db.getCollection(TABLENAME);
BasicDBObject q = new BasicDBObject();
q.put("domain", domain);
DBCursor cur = coll.find(q);
while (cur.hasNext()) {
DBObject myDoc = cur.next();
String txt;
try {
txt = Base64.encodeBytes(((String) myDoc.get("text"))
.getBytes("UTF-8"));
sb.append("<script name=\"");
sb.append((String) myDoc.get("name"));
sb.append("\">");
sb.append(txt);
sb.append("</script>\n");
} catch (IOException e) {
Log.error(e.getMessage());
}
}
Database.release();
}
sb.append("</scripts>\n");
return sb.toString();
}
/** The domain. */
private final String domain;
/** The name. */
private String name;
/** The text. */
private String text;
/** The vm. */
private VM vm = null;
/** The caller. */
private final IScriptableObject caller;
private final String username;
public Scripts(IScriptableObject obj, String domain, String username,
String name) {
this(obj, domain, username, name, null);
}
/**
* Instantiates a new scripts.
*
* @param obj
* the obj
* @param domain
* the domain
* @param name
* the name
*/
public Scripts(IScriptableObject obj, String domain, String username,
String name, VM vm2) {
this.name = name;
this.domain = domain;
this.username = username;
caller = obj;
initVM(vm2);
initStruct();
loadText();
if (vm != null) {
if (text != null) {
try {
vm.eval(text);
} catch (Exception e) {
Log.error(e.getMessage());
}
} else {
Log.error("There is no text for script " + name);
}
} else {
Log.error("My vm is null!!!!");
}
}
/**
* Instantiates a new scripts. WARNING: only for database restore case
*
* @param domain
* the domain
*/
public Scripts(String domain, String username) {
name = "";
this.domain = domain;
this.username = username;
caller = null;
initStruct();
}
public Scripts(String domain, String username, String name) {
this(domain, username, name, null);
}
/**
* Instantiates a new scripts.
*
* @param domain
* the domain
* @param name
* the name
*/
public Scripts(String domain, String username, String name, VM vm2) {
this.name = name;
this.domain = domain;
this.username = username;
caller = null;
initVM(vm2);
initStruct();
loadText();
if (vm != null) {
if (text != null) {
try {
vm.eval(text);
} catch (Exception e) {
Log.error(e.getMessage());
}
} else {
Log.error("There is no text for script " + name);
}
}
}
/**
* Call.
*
* @param funcname
* the funcname
* @param args
* the args
* @return the object
* @throws ScriptException
* the script exception
* @throws NoSuchMethodException
* the no such method exception
*/
public Object call(String funcname, final Object... args)
throws ScriptException, NoSuchMethodException {
Object result = null;
if (vm != null) {
result = vm.call(funcname, args);
}
return result;
}
/**
* Eval.
*
* @param cmd
* the cmd
* @return the object
*/
public Object eval(String cmd) {
if (vm != null) {
try {
return vm.eval(cmd);
} catch (ScriptException e) {
Log.error(e.getMessage());
}
}
return null;
}
/**
* Eval.
*
* @param evalstring
* the evalstring
* @param params
* the params
* @param types
* the types
* @return the hash map
* @throws ScriptException
* the script exception
* @throws NoSuchMethodException
* the no such method exception
*/
public HashMap<String, String> eval(String evalstring,
HashMap<String, String> params, HashMap<String, Integer> types)
throws ScriptException, NoSuchMethodException {
Hashtable<String, Object> input = new Hashtable<String, Object>();
Set<String> names = params.keySet();
Iterator<String> i = names.iterator();
while (i.hasNext()) {
String name = i.next();
if (types.containsKey(name)) {
input.put(name,
DataTypes.fromString(types.get(name), params.get(name)));
}
}
HashMap<String, String> result = new HashMap<String, String>();
Object eval = null;
if (vm != null) {
eval = vm.call(evalstring, input);
}
// ---------------------
if (eval != null) {
if (Hashtable.class.isInstance(eval)) {
@SuppressWarnings("unchecked")
Hashtable<String, Object> output = (Hashtable<String, Object>) eval;
if ((output != null) && !output.isEmpty()) {
Set<String> cnames = output.keySet();
Iterator<String> j = cnames.iterator();
while (j.hasNext()) {
String name = new String(j.next());
if (types.containsKey(name)) {
result.put(
name,
DataTypes.toString(types.get(name),
output.get(name)));
}
}
} else {
Log.error("Empty eval's result");
}
} else {
Log.error("Eval result is not HashMap: "
+ eval.getClass().getCanonicalName());
}
}
return result;
}
public HashMap<String, String> eval(String evalstring, String changedfield,
HashMap<String, String> params, HashMap<String, Integer> types)
throws ScriptException, NoSuchMethodException {
Hashtable<String, Object> input = new Hashtable<String, Object>();
Set<String> names = params.keySet();
Iterator<String> i = names.iterator();
while (i.hasNext()) {
String name = i.next();
if (types.containsKey(name)) {
input.put(name,
DataTypes.fromString(types.get(name), params.get(name)));
}
}
HashMap<String, String> result = new HashMap<String, String>();
Object eval = null;
if (vm != null) {
eval = vm.call(evalstring, changedfield, input);
}
// ---------------------
if (eval != null) {
if (Hashtable.class.isInstance(eval)) {
@SuppressWarnings("unchecked")
Hashtable<String, Object> output = (Hashtable<String, Object>) eval;
if ((output != null) && !output.isEmpty()) {
Set<String> cnames = output.keySet();
Iterator<String> j = cnames.iterator();
while (j.hasNext()) {
String name = new String(j.next());
if (types.containsKey(name)) {
result.put(
name,
DataTypes.toString(types.get(name),
output.get(name)));
}
}
} else {
Log.error("Empty eval's result");
}
} else {
Log.error("Eval result is not HashMap: "
+ eval.getClass().getCanonicalName());
}
}
return result;
}
/**
* @param evalstring
* @param tablename
* @param changedfield
* @param params
* @param types
* @return
* @throws ScriptException
* @throws NoSuchMethodException
*/
public HashMap<String, String> eval(String evalstring, String tablename,
String changedfield, HashMap<String, String> params,
HashMap<String, Integer> types) throws ScriptException,
NoSuchMethodException {
Hashtable<String, Object> input = new Hashtable<String, Object>();
Set<String> names = params.keySet();
Iterator<String> i = names.iterator();
while (i.hasNext()) {
String name = i.next();
if (types.containsKey(name)) {
input.put(name,
DataTypes.fromString(types.get(name), params.get(name)));
}
}
HashMap<String, String> result = new HashMap<String, String>();
Object eval = null;
if (vm != null) {
eval = vm.call(evalstring, tablename, changedfield, input);
}
// ---------------------
if (eval != null) {
if (Hashtable.class.isInstance(eval)) {
@SuppressWarnings("unchecked")
Hashtable<String, Object> output = (Hashtable<String, Object>) eval;
if ((output != null) && !output.isEmpty()) {
Set<String> cnames = output.keySet();
Iterator<String> j = cnames.iterator();
while (j.hasNext()) {
String name = new String(j.next());
if (types.containsKey(name)) {
result.put(
name,
DataTypes.toString(types.get(name),
output.get(name)));
}
}
} else {
Log.error("Empty eval's result");
}
} else {
Log.error("Eval result is not HashMap: "
+ eval.getClass().getCanonicalName());
}
}
return result;
}
/**
* Gets the text.
*
* @return the text
*/
public String getText() {
return text;
}
/**
* Inits the struct.
*/
private void initStruct() {
DB db = Database.get(domain);
if (db != null) {
Database.retain();
DBCollection coll = db.getCollection(TABLENAME);
List<DBObject> indexes = coll.getIndexInfo();
if (indexes.size() < 1) {
BasicDBObject i = new BasicDBObject();
i.put("domain", 1);
i.put("name", 1);
coll.createIndex(i);
}
Database.release();
}
}
/**
* Inits the vm.
*/
private void initVM(VM parentvm) {
Log.trace("init vm");
if (parentvm == null) {
vm = new VM(domain, username);
} else {
vm = parentvm;
}
if (!name.equals("global")) {
Scripts global = new Scripts(domain, username, "global", vm);
global.nop();
}
}
/**
* Load text.
*/
private void loadText() {
String txt = "";
DBObject doc = null;
DB db = Database.get(domain);
if (db != null) {
Database.retain();
DBCollection coll = db.getCollection(TABLENAME);
BasicDBObject query = new BasicDBObject();
query.put("domain", domain);
query.put("name", name);
doc = coll.findOne(query);
Database.release();
if (doc != null) {
txt = (String) doc.get("text");
}
}
if ((txt == null) || txt.isEmpty()) {
if (!domain.equals("127.0.0.1")) {
Scripts s = new Scripts(caller, "127.0.0.1", username, name, vm);
txt = s.getText();
}
}
if ((txt == null) || txt.isEmpty()) {
if (domain.equals("127.0.0.1") && name.equals("global")) {
txt = "import java.lang\nLog.error('Global script evaluated')\n";
}
if (caller != null) {
txt = caller.generateDefaultScript();
}
setText(txt, true);
return;
}
setText(txt, false);
}
/**
* Nop. (no operations)
*/
private void nop() {
return;
}
/**
* Restore.
*
* @param vals
* the vals
*/
public void restore(Element vals) {
NodeList nodes = vals.getElementsByTagName("script");
for (int i = 0; i < nodes.getLength(); i++) {
Element val = (Element) nodes.item(i);
String name = val.getAttribute("name");
String b64 = val.getTextContent();
try {
String text = new String(Base64.decode(b64), "UTF-8");
this.name = name;
setText(text, true);
} catch (IOException e) {
Log.error(e.getMessage());
}
}
}
/**
* Sets the text.
*
* @param txt
* the new text
*/
public void setText(String txt) {
setText(txt, true);
}
/**
* Sets the text.
*
* @param txt
* the txt
* @param andstore
* the andstore
*/
public void setText(String txt, boolean andstore) {
text = txt;
if (andstore) {
DBObject doc = null;
DB db = Database.get(domain);
if (db != null) {
Database.retain();
DBCollection coll = db.getCollection(TABLENAME);
BasicDBObject query = new BasicDBObject();
query.put("domain", domain);
query.put("name", name);
doc = coll.findOne(query);
if (doc != null) {
doc.put("text", text);
coll.save(doc);
} else {
doc = new BasicDBObject();
doc.put("domain", domain);
doc.put("name", name);
doc.put("text", text);
coll.insert(doc);
}
Database.release();
initVM(null);
}
}
}
}