https://github.com/firebirdsql/fbjava
FB/Java plugin for Firebird
https://github.com/firebirdsql/fbjava
Last synced: 7 days ago
JSON representation
FB/Java plugin for Firebird
- Host: GitHub
- URL: https://github.com/firebirdsql/fbjava
- Owner: FirebirdSQL
- Created: 2016-05-01T22:23:31.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2023-11-30T01:05:12.000Z (over 1 year ago)
- Last Synced: 2025-04-07T13:11:09.662Z (about 1 month ago)
- Language: C++
- Size: 565 KB
- Stars: 12
- Watchers: 14
- Forks: 6
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
[](https://github.com/FirebirdSQL/fbjava/actions)
[](https://maven-badges.herokuapp.com/maven-central/org.firebirdsql.fbjava/fbjava/)# FB/Java External Engine Plugin for Firebird
FB/Java is an External Engine plugin for Firebird that allows Firebird run
functions, procedures and triggers made in the Java platform.FB/Java has also a client utility with functions to install and uninstall the plugin in a
database and that users may use to deploy and undeploy Java classes and resources stored in
JAR files to a database.Jaybird is bundled with FB/Java and allows to run queries using standard JDBC code.
## Installing FB/Java in Firebird
Server installation of FB/Java is a simple task involving three passes. The first
necessary pass is to extract the zip/tarball package in a place (subsequently named here as
`` - this is the parent directory of the packaged bin and others directories).The second pass is to include a line in the end of `/plugins.conf` file
pointing to the plugin:```
include /conf/fbjava.conf
```The third pass is to define the environment variable JAVA_HOME pointing to the home directory
of a JDK or JRE installation. Optionally this can be configured in `/conf/fbjava.conf`.
FB/Java requires a Java 8 platform of the same architecture (32 or 64 bit) of Firebird.FB/Java can also be installed in the client making possible to use `fbjava-deployer`
utility remotely. In this case it's just necessary to extract the zip/tarball in some directory
and optionally add its bin directory to the `PATH` environment variable. Java `bin` directory must
also be in `PATH`.To develop external routines using Java, Maven/Gradle users need to add this dependency:
```
org.firebirdsql.fbjava
fbjava
1.0.0-beta-1
provided```
## Features
### Database and Java routines mappings
There are basically two ways to map database functions and procedures to Java
methods. By fixed or generic signatures. Triggers can be mapped only with generic signatures.:information_source: Generics here does not refer to Java generics in any way.
#### Fixed signatures
Fixed signatures means that for each database routine parameter there should be a
Java parameter in the method.#### Generic signatures
Generic signatures doesn't have parameters. The Java code can obtain from the
call Context all parameters or fields values passed by the database routine.### Security
One of the more important features of the Java platform is it security system, the so
called sandbox. FB/Java integrates the J2SE/JAAS security mechanism with Firebird so that
permissions may be assigned to database users running the Java code.Users permissions work at server level. They are stored in the
`/conf/java-security.fdb` database.That database contains the tables `PERMISSION_GROUP` (with columns `ID`, `NAME`),
`PERMISSION` (with columns `PERMISSION_GROUP`, `CLASS_NAME`, `ARG1`, `ARG2`) and
`PERMISSION_GROUP_GRANT` (with columns `PERMISSION_GROUP`, `DATABASE_PATTERN`,
`GRANTEE_TYPE`, `GRANTEE_PATTERN`).`PERMISSION_GROUP` names a set of `PERMISSION` associated by `PERMISSION.PERMISSION_GROUP`
column.In `PERMISSION` table, there is `CLASS_NAME` column which stores the Java permission class
name and `ARG1` / `ARG2` which stores the arguments passed to the permission class constructor.The `PERMISSION_GROUP_GRANT` table associates `PERMISSION_GROUP` with Firebird users and
roles. This association is done by a `DATABASE_PATTERN` and a `GRANTEE_TYPE` / `GRANTEE_PATTERN`.
Patterns are `SIMILAR TO` patterns escaped by the `'&'` symbol. Pay attention when using special
`SIMILAR TO` characters like underline, if they refer to actual database, user or role name
parts, they need to be escaped. `GRANTEE_TYPE` defines if `GRANTEE_PATTERN` refers to a `ROLE` or
`USER`.The plugin ships with a number of permissions grouped as `COMMON` and granted to all
(`%` pattern) users of all databases. They are:#### Default permissions granted
| CLASS_NAME | ARG1 | ARG2 |
| ---------------------------- | --------------- | ---- |
| java.util.PropertyPermission | file.separator | read |
| java.util.PropertyPermission | java.version | read |
| java.util.PropertyPermission | java.vendor | read |
| java.util.PropertyPermission | java.vendor.url | read |
| java.util.PropertyPermission | line.separator | read |
| java.util.PropertyPermission | os.* | read |
| java.util.PropertyPermission | path.separator | read |:warning: Permissions configured in java-security.fdb are valid only for classes stored inside
databases. Classes at file system are granted `java.security.AllPermission`.:information_source: The `java.security.AllPermission` is effectively valid in this context if
the code marks itself as privileged, like with `java.security.AccessController.doPrivileged` method.### ClassLoaders
FB/Java looks for classes in two different places: the file system and the current
database, in this order. It is general recommendation that users store they classes in the
database.Classes in the file system are shared between all databases handled by a Firebird process.
For example, static variables have per-process values. In an analogy with an application server,
they are the system classes. The internal classes necessary for FB/Java are in
`/jar/*.jar` and is not recommended to put more jar files there.Classes in the database are isolated per-database (and process) and unloaded when the last
user disconnects from the database/process. So static variables are shared between attachments
to the same database, but are reinitialized when a closed database is opened. In an analogy with
an application server, they are the application classes, although an application server does
not reload application classes when the application is idle.:information_source: Classes does not share static variables when used by different Classic or
embedded processes.:information_source: Classes are unloaded by closing the database classloader.
It is subject to garbage collection to really unload them.Classes can be stored in the database by two different methods: the `fbjava-deployer`
(`.bat` in Windows / `.sh` in Linux) utility or the `SQLJ` package.### `fbjava-deployer` utility
FB/Java allows execution of Java routines stored in the file system without any
per-database installation. But to have per-database classes, the plugin need to be installed
on the database.`fbjava-deployer` is the utility to install and uninstall the plugin in databases and to
install, remove and replace JAR files in databases. Its command line options are:- `--database ` - Jaybird connection string, without `jdbc:` prefix.
- `--user ` - Database user name.
- `--password ` - User password.
- `--install-plugin` - Installs the plugin in the database. The installation process consists of the
creation of some database objects, prefixed with `FB$JAVA$` and the `SQLJ` package.:information_source: Details of the install process can be seen in the install.sql file in the
scripts directory of the plugin.- `--uninstall-plugin` - Uninstalls the plugin from the database. The uninstall process consists of dropping
all the objects created by the installation process.:information_source: Details of the uninstall process can be seen in the uninstall.sql file in the
scripts directory of the plugin.:warning: All stored JARs are deleted when the plugin is uninstalled.
- `--install-jar ` - Installs a JAR in the database. `` is an unique
identifier to refer to the JAR in subsequent calls, like `--replace-jar`,
`--update-jar` or `--remove-jar`.- `--update-jar ` - Updates an existing JAR in the database. It is an error to try to update a JAR with a `` that is not installed.
- `--replace-jar ` - Replaces a JAR in the database. The replacement is done deleting the current JAR if it exists and installing the new one.
- `--remove-jar ` - Removes a JAR from the database.
### `SQLJ` package
JAR installation, replacement, updation and remotion can also be done with the help
of the `SQLJ` package. The `SQLJ` package just runs the same class used in `fbjava-deployer`, but in
the server, as Java stored procedures. With that package, paths and URLs are server-based. Its
procedures are:- `SQLJ.INSTALL_JAR(, )`
- `SQLJ.UPDATE_JAR(, )`
- `SQLJ.REPLACE_JAR(, )`
- `SQLJ.REMOVE_JAR()`
### Mapping database routines to Java methods
Database routines are mapped to Java methods by a database declaration with an external call
specification and usage of `ENGINE JAVA` clause. The call specification consists of the method
signature, in this format:```
::=
.(
[ [{, }...]])
[!]::=
|
```:information_source: The java.lang package prefix may be avoided in parameters types but not
in the class name containing the static method.:information_source: `` prefixed by an exclamation point is an optional info you
can pass to the Java method that it can obtain with the method `getNameInfo` from the
`Context` interface.#### Supported Java and Jaybird types
| Java or Jaybird Type | Compatible Firebird type | Notes |
| --------------------------------- | ------------------------ | ----- |
| byte[] | BLOB, CHAR, VARCHAR | |
| boolean | any | [1] |
| short | any | [1] |
| int | any | [1] |
| long | any | [1] |
| float | any | [1] |
| double | any | [1] |
| java.lang.Boolean | any | |
| java.lang.Short | any | |
| java.lang.Integer | any | |
| java.lang.Long | any | |
| java.lang.Float | any | |
| java.lang.Double | any | |
| java.lang.Object | any | [2] |
| java.lang.String | any | |
| java.math.BigDecimal | any | |
| java.sql.Blob | BLOB | |
| java.sql.Date | any | |
| java.sql.Time | any | |
| java.sql.Timestamp | any | |
| java.util.Date | any | |
| org.firebirdsql.jdbc.FirebirdBlob | BLOB | |:information_source: [1] A database NULL is converted to `0` (zero) when passed to
a primitive numeric type and `false` to `boolean`.:information_source: [2] Parameters and trigger values are converted accordingly to
default mapping rules.:information_source: Any compatible type means the plugin doesn't care about the
type, it just tries to get the value as a Firebird type compatible with the Java type.
Basically, this means that a CAST will be done from the Firebird value to the default
mapping type of the Java type, or vice-versa.#### Default mappings
| Firebird Type | Java type |
| ---------------- | -------------------- |
| NUMERIC | java.math.BigDecimal |
| DECIMAL | java.math.BigDecimal |
| SMALLINT | java.math.BigDecimal |
| INTEGER | java.math.BigDecimal |
| BIGINT | java.math.BigDecimal |
| FLOAT | java.lang.Float |
| DOUBLE PRECISION | java.lang.Double |
| BOOLEAN | java.lang.Boolean |
| CHAR | java.lang.String |
| VARCHAR | java.lang.String |
| BLOB | java.sql.Blob |
| DATE | java.sql.Date |
| TIME | java.sql.Time |
| TIMESTAMP | java.sql.Timestamp |#### Functions mapping
Functions are the only routine type that always requires a non-void return type in the Java method.
Examples:
```
create or alter function get_system_property (
name varchar(80)
) returns varchar(80)
external name 'java.lang.System.getProperty(String)'
engine java;-- A single method being mapped to two different Firebird functions.
create function funcSum2 (n1 integer, n2 integer) returns integer
external name 'org.firebirdsql.fbjava.FuncTest.sum()'
engine java;create function funcSum4 (n1 integer, n2 integer, n3 integer, n4 integer) returns integer
external name 'org.firebirdsql.fbjava.FuncTest.sum()'
engine java;
```#### Procedures mapping
Procedures can have a return type (of `org.firebirdsql.fbjava.ExternalResultSet` type or a
class implementing that interface) or `void`, depending of it being a selectable procedure or not.
Output parameters should appear on the call specification as arrays. FB/Java pass each output
parameter as an array of length 1, and routines can change their `[0]` element.Examples:
```
-- Executable procedure.
create procedure procInsert (n integer, s varchar(10))
external name 'org.firebirdsql.fbjava.ProcTest.insert(int, String)'
engine java;-- Selectable procedure.
create procedure procGenRows (numRows integer) returns (n integer)
external name 'org.firebirdsql.fbjava.ProcTest.genRows(int, int[])'
engine java;
```#### Triggers mapping
Call specification of triggers has always zero parameter and the Java method should
return `void`. Details of the call and the `OLD` and `NEW` values can be read and write from the
call context.Examples:
```
create or alter trigger employee_log_bdiu
before delete or insert or update on employee
external name 'org.firebirdsql.example.fbjava.FbLogger.info()'
engine java;
```### Context
Java code can obtain a `Context` object which has information about the Firebird routine
that mapped to the Java code as well inspect and manipulate metadata and data about the call.
The `Context` interface has the following hierarchy:- `CallableRoutineContext extends Context`
- `FunctionContext extends CallableRoutineContext`
- `ProcedureContext extends CallableRoutineContext`
- `TriggerContext extends Context`All these interfaces have a static get() method to obtain the object instance.
More details of what can be done from them can be consulted in the Java Docs present in
`/docs/apidocs` or [online](https://htmlpreview.github.io/?https://raw.githubusercontent.com/FirebirdSQL/fbjava/1.0.0-beta-1/apidocs/org/firebirdsql/fbjava/package-summary.html).## Example
There is an example project in `examples/fbjava-example` directory with instructions in the README file.
## Known issues
It's not possible to use Jaybird's non-pure-Java connection string protocols like embedded, native and local.
## Sponsors
The FB/Java team would like to thank YourKit for providing licenses to their [YourKit Java Profiler](https://www.yourkit.com/java/profiler/).
