Center
Database Objects
Overview
The DataBaseObject (DBO) is a Center class allowing for a custom object (backed by Java code) to be added directly to the database schema.
This is similar to adding tables, procedures, timers, and other Center objects.
General Setup
DBOs are set up similarly to other custom Java plugins, the instructions for which can be found here.
To create and use DBOs, the following is required:
-
Create a Java package with the necessary classes containing your DBO logic:
- A factory for the DBO containing method and callback definitions
- The DBO implementation
-
Save the package as a .jar file to then be added to your installation's amione/lib directory.
-
Add the DBO plugin to your local.properties:
| ami.db.dbo.plugins=fully_qualified_java_class_name
|
-
Restart your 3forge instance and use the AMIDB shell tool to create and interact with DBOs.
Tip
A fully guided example is provided below.
AmiScript Syntax
The below table contains the list of Center commands that can be called on DBOs.
| Center Command |
Additional Argument(s) |
Description |
CREATE DBO dbo_name OFTYPE dbo_type |
USE callback_someCallback = "..." |
- Creates a DBO of the supplied DBO type
- Optionally supply user-defined callbacks and their arguments
- Arguments can be additional AmiScript commands for upserting tables
|
DROP DBO dbo_name |
|
- Drop/delete the supplied DBO
|
DESCRIBE DBO dbo_name |
|
- Drop/delete the supplied DBO
|
SHOW DBOS |
|
- Returns a list of the existing DBOs including their type, name, and options
|
SHOW DBO dbo_name |
FULL |
- Returns a table of the given DBO and its associated methods and callbacks
- Optionally supply the keyword
FULL for the full DBO name (can cause text wrapping on the console)
|
SHOW METHODS WHERE TargetType=="dbo_name" |
|
- Return all the methods associated to the given DBO type
|
SHOW PLUGINS WHERE PluginType=="DBO" |
FULL |
- Returns a table with all the DBO types available in AMI
- Dependent on which DBO plugins have been included in
local.properties
|
ENABLE DBO dbo_name |
|
|
DISABLE DBO dbo_name |
|
|
RENAME DBO dbo_name TO different_name |
|
- Rename a given DBO with a different name
|
ALTER DBO dbo_name USE callback_someCallback = "..." |
|
- Redefine a given DBO by changing its behavior
- Supply the new AmiScript arguments with the callback
|
Tip
DBOs can also be displayed with the SHOW VARS command.
Features
DBOs are intended to give developers the means to communicate both in and out of the Center -- i.e, a DBO can receive some input from a feed and output some behavior. DBOs can therefore be thought of as 2-way communication message buses.
The key features of a DBO are as follows:
- When a DBO is created, it gets added to the managed schema. It will then be available the next time the database is started up.
- DBOs have names and types like other objects and are mutable.
- For example: a DBO named
myFirstDbo can call myFirstDbo.getClassName() to return the type of the DBO
- In this way DBOs are identical to
ami.web.amiscript.custom.classes
- DBOs can have callbacks which can be defined at runtime using custom AmiScript. These callbacks are thread-safe.
Example: A Timer Based DBO
Setup
Follow the general setup steps laid out above.
-
Create a Java package called "test_dbo" and add the following line to your local.properties file:
| ami.db.dbo.plugins=test_dbo.SimpleTimerDboPlugin
|
-
Then define both the plugin and functionality for the DBO in 2 separate Java files. In this example, we will implement a thread-safe, basic DBO type called SimpleTimer.
-
Within the Java package, create the following 2 classes:
Remember to include out.jar and autocode.jar in the classpath.
Java Files
SimpleTimerDboPlugin.java
This file contains the factory for the callbacks available to the DBO. In this case, we want to create 2 callbacks that can be called within 3forge:
onPeriodChanged()
onTimer()
| package test_dbo;
import com.f1.ami.center.dbo.*;
import com.f1.utils.structs.table.derived.ParamsDefinition;
public class SimpleTimerDboPlugin extends AmiDboFactory_Reflection {
public SimpleTimerDboPlugin() {
super(SimpleTimerDbo.class);
addCallback(new ParamsDefinition("onPeriodChanged", Object.class, "Integer old,Integer nuw"));
addCallback(new ParamsDefinition("onTimer", Object.class, "Long now,Integer count"));
}
}
|
The implementation for these callbacks and other methods like getters and setters are done in the second class.
SimpleTimerDbo.java
This class contains the functionality for the SimpleTimer DBO.
Note
Any method that is intended to be called within 3forge must use the com.f1.ami.amicommon.customobjects.AmiScriptAccessible annotation.
In Java, this is denoted with the override @AmiScriptAccessible.
| package test_dbo;
import java.util.Map;
import com.f1.ami.amicommon.customobjects.AmiScriptAccessible;
import com.f1.ami.center.dbo.AmiDbo;
import com.f1.ami.center.dbo.AmiDboBinding;
import com.f1.utils.CH;
import com.f1.utils.OH;
@AmiScriptAccessible(name = "SimpleTimer")
public class SimpleTimerDbo extends Thread implements AmiDbo {
private int sleep = 1000;
private AmiDboBinding binding;
private boolean closed = false;
@AmiScriptAccessible(name = "setPeriod", params = { "millis" })
public void setPeriod(int n) {
if (n <= 0)
throw new RuntimeException("Bad value");
if (n != this.sleep)
this.binding.executeCallbackNoThrow("onPeriodChanged", (Map) CH.m("old", sleep, "nuw", n));
this.sleep = n;
}
@AmiScriptAccessible(name = "getPeriod")
public int getPeriod() {
return this.sleep;
}
@Override
public void run() {
int n = 0;
while (!closed) {
OH.sleep(Math.max(this.sleep, 1));
this.binding.executeCallbackNoThrow("onTimer", (Map) CH.m("now", System.currentTimeMillis(), "count", n));
n++;
}
}
@Override
public void startAmiDbo(AmiDboBinding peer) {
this.binding = peer;
start();
}
@Override
public void closeAmiDbo() {
this.closed = true;
}
@Override
public AmiDboBinding getAmiDboBinding() {
return this.binding;
}
@Override
public String toString() {
return "SimpleTimer[Period=" + this.sleep + "]";
}
}
|
Exporting the DBO into 3forge
Export the package containing both Java files into a .jar file and add it to the amione/lib folder of the 3forge instance you wish to use the DBO in.
The DBO will be available the next time 3forge is launched.
Sample Instructions
Listed below are some sample instructions and their given outputs of how the SimpleTimer DBO can be created and called in the AMIDB Shell Tool:
Show Methods
-
| AMIDB-DEV> show methods where TargetType=="SimpleTimer"
+---------------------------------------------------------------------------------+
| METHODS |
+-----------+----------+----------+-------------------------------------+---------+
|TargetType |MethodName|ReturnType|Definition |DefinedBy|
|String |String |String |String |String |
+-----------+----------+----------+-------------------------------------+---------+
|SimpleTimer|getPeriod |Integer |SimpleTimer.getPeriod() |SYSTEM |
|SimpleTimer|setPeriod |Object |SimpleTimer.setPeriod(Integer millis)|SYSTEM |
+-----------+----------+----------+-------------------------------------+---------+
|
Show Plugins
-
| AMIDB-DEV> show full plugins where PluginType=="DBO"
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| PLUGINS |
+-----------+----------+--------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+
|PluginName |PluginType|ClassType |Arguments |
|String |String |String |String |
+-----------+----------+--------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+
|SimpleTimer|DBO |com.f1.ami.center.AmiDboFactoryWrapper|callback_onPeriodChanged String /*onPeriodChanged(Integer old,Integer nuw)*/,callback_onTimer String /*onTimer(Long now,Integer count)*/|
+-----------+----------+--------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+
|
Show Variables (Including DBOs)
-
| AMIDB-DEV> CREATE PUBLIC TABLE test(value Integer)
AMIDB-DEV> CREATE DBO mytimer OFTYPE SimpleTimer use callback_onTimer="insert into test values(count)";
AMIDB-DEV> show vars;
+---------------------------------------------------------+
| VARS |
+-----------+-----------+------------------------+--------+
|Name |Type |Value |Readonly|
|String |String |String |Boolean |
+-----------+-----------+------------------------+--------+
|__SESSIONID|long |8 |true |
|__USERNAME |String |demo |true |
|mytimer |SimpleTimer|SimpleTimer[Period=1000]|true |
+-----------+-----------+------------------------+--------+
|
Getters and Setters
-
| AMIDB-DEV> mytimer.setPeriod(1234);
(AFFECTED 0 ROWS, EXECUTED IN 0.288 MILLISECONDS)
AMIDB-DEV> mytimer.getPeriod();
(Integer)1234
(AFFECTED 0 ROWS, 1 VALUE, EXECUTED IN 0.24 MILLISECONDS)
AMIDB-DEV> show dbo mytimer;
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| DBO |
+--------+-----------------------------------------------+------------------------------+-------------+-----------+------------------+-----------+---------+
|Category|Description |AmiScript |ExecutedCount|MillisSpent|AvgMillisSpent |ErrorsCount|LastError|
|String |String |String |Long |Double |Double |Long |String |
+--------+-----------------------------------------------+------------------------------+-------------+-----------+------------------+-----------+---------+
|METHOD |Object setPeriod(Integer p1) !null |1 |0.0408 |0.0408 |0 !null |
|METHOD |Integer getPeriod() !null |1 |0.0147 |0.0147 |0 !null |
|CALLBACK|Object onPeriodChanged(Integer old,Integer nuw)!null |0 |0.0 |NaN |0 !null |
|CALLBACK|Object onTimer(long now,Integer count) |insert into test values(count)|46 |9.3913 |0.2041586956521739|0 !null |
+--------+-----------------------------------------------+------------------------------+-------------+-----------+------------------+-----------+---------+
|
Add a Value Manually (Alter)
-
| AMIDB-DEV> alter dbo mytimer use callback_onTimer="insert into test values(this.getPeriod())";
(AFFECTED 0 ROWS, EXECUTED IN 7.264 MILLISECONDS)
AMIDB-DEV> truncate test;//wait a few seconds
AMIDB-DEV> select * from test;
+-------+
| test |
+-------+
|value |
|Integer|
+-------+
|1234 |
|1234 |
|1234 |
|1234 |
+-------+
|
Disable
-
| AMIDB-DEV> disable dbo mytimer;
(AFFECTED 0 ROWS, EXECUTED IN 2.201 MILLISECONDS)
AMIDB-DEV> mytimer.getPeriod();// this will return null because the dbo is disabled
(Integer)null
(AFFECTED 0 ROWS, 1 VALUE, EXECUTED IN 0.13 MILLISECONDS)
|