|
|
Developed
at the Polish-Japanese Institute of Information
Technology © Copyright by ODRA team, © Copyright by PJIIT |
||||||||||||
|
ODRA – Object
Database for Rapid Application development Description and Programmer Manual |
|||||||||||||
|
by Jacek Wiślicki and the ODRA team |
|||||||||||||
14. Generic Wrapper to Relational Databases |
|||||||||||||
|
The goal of the generic wrapper to
relational databases is to enable integration of data stored in a relational
database into a virtual repository. Wrapped relational tables can be
transparently queried and updated with object-oriented features SBQL. They
can also be mapped with updateable object-oriented views in order to comply
with the global schema of a virtual repository. In this way relational data
can be made indistinguishable from other ODRA objects. There is no limits in
sophistication of the mapping between relational tables and ODRA objects, due
to the fact that SBQL updatable views offer the full algorithmic power. This
is a significant difference with many currently available Object-Relational
Mappers (ORM-s). During the development of the wrapper we put much effort on
effective query optimization. The optimization is performed both at the ODRA
side and the wrapped relational database side. In particular, the wrapper is
developed in such a way that major SQL optimization methods (fast joins,
rewriting, indices) are fully utilized. This is a second significant
difference with existing ORM-s, which offer proper performance for simple
mappings between object-oriented queries and SQL, but totally compromise
performance if the mapping is sophisticated. The wrapper can realize two main goals:
·
Storage of data presented in the virtual repository in relational
databases (top-down approach). The first goal strictly complies
with the eGov-Bus project objectives, i.e. assembling, integrating and
combining pre-existing information systems and business solutions (based
mainly on relational databases) in the final environment. The other one is
implied by the reasonable assumption that designers of future systems
integrated with the virtual repository would still tend to use familiar
relational databases, being somehow afraid of the new object-oriented
database technology. Both usage scenarios can be successfully realized by the
wrapper. 14.1 Wrapper ArchitectureThe wrapper is realized in a
client-server architecture. The client is transparently embedded in the ODRA
server, while the wrapper server is a standalone application. The schematic
wrapper structure is presented in Fig.14-1:
14-1. General wrapper architecture An ODRA virtual repository uses
object-oriented views to map virtual data delivered by the wrapper to
the form assumed by the virtual
repository canonical data model. The virtual repository itself does not see
the wrapper, since the ODRA database is opaque – the wrapped relational
schema is presented via a regular ODRA schema. The actual processing is
executed between the wrapper server and the client. The client is responsible
for issuing SQL queries (implied by SBQL queries from global virtual
repository clients) to the server, receiving results and creating temporary
ODRA results returned to the ODRA database. Such temporary results are then
returned to the virtual repository and to the global client. 14.2 Adding and Querying WrappersWhen the wrapper server is running
and its host is available from the ODRA server machine, the wrapper can be
used from within ODRA (the server configuration and startup procedures are
described with illustrative examples below). The wrapper is realized as an
ODRA database module, therefore the syntax is similar: add module
<modulename> as wrapper on <host>:<port> where <modulename> is a name of a module to add, <host> is a wrapper server host
(IP or name), and <port> is
its listener port. A new wrapper module is created as a submodule of the
current module. A wrapper is instantiated when a
wrapper module is created. A wrapper module is a regular database module, but
it asserts that all the names within the module are “relational”
(i.e. imported from a relational schema) except for automatically generated
views referring to these names (this procedure is described in the following
paragraphs). A wrapper instance contains a wrapper client capable of
communication with the appropriate server. All the wrapper instances are
stored in a global (static) session object and are available with a wrapper
module name. Thus, once a wrapper is created, it is available to any session
(including the ones initialized in the future) as its module is. A wrapper module can be dropped with the same
command as any other ODRA module. All relational names appearing in
the wrapped resource XML description are available with a View postfix (e.g. an employees table is visible as employeesView, its name column is nameView, etc.). The primary wrapper views are introduced
automatically so that virtual pointers corresponding to primary-foreign key
relations and integrity constraints are preserved. The wrapper objects can be
queried as other ODRA objects. Queries combining regular ODRA objects and
virtual objects delivered by the wrapper are allowed. Before querying wrappers make sure
that the current optimization sequence contains view rewriting and wrapper
optimization. Otherwise queries are not sent to appropriate wrappers and
empty results are returned. 14.3 Top-Down Usage ScenarioAssume that some object-oriented
schema is given (according to the virtual repository integration and
contribution model) and its data is to be stored in a relational database.
This is the case of the top-down design,
i.e. the system designer is obliged to create a relational database schema
capable for storing and retrieving data being a part of the virtual
repository. The main relational schema
designing rule is that all the tables must have unique row identifiers
– primary keys (the current prototype implementation supports only
single-column keys, this limitation will be removed in the future wrapper
development). The unique identifiers are used (usually in background) for
data updates, as they allow for keeping data integrity. The designer must also realize
that the wrapper creates virtual pointers for each primary-foreign key pair.
Therefore whenever a pointer appears in the assumed object-oriented schema,
the foreign key must be created in the corresponding relational schema.
Another temporary wrapper prototype limitation that is to be removed in the
future is that only a single primary-foreign key constraint per table is
supported. The top-down designing procedure
can be illustrated with the following simple example. Consider an
object-oriented schema for people and their cars, Fig.14-2:
14-2. Base object-oriented schema This simple schema corresponds to
a two-table relational schema. Each table should have its primary key (some
automatically incremented sequences are a good choice). The pointers (owns and isOwnedBy) should be realized as foreign keys. The resulting
relational schema could look as the one shown in the figure below:
14-3. Designed relational schema During the relational schema wrapping
procedure the wrapper creates automatically views covering plain metaobjects.
The procedure is described in details in the following. The resulting names
differ from the ones in the relational database, thus the designer should
cover the wrapped schema with additional views mapping the automatic wrapper
views one-to-one to the desired names (assumed in the target object-oriented
schema), including virtual pointers. In case of more complex
object-oriented schemata the designer may need to create a more sophisticated
relational schema (introducing additional tables not resulting directly form
the object-oriented schema) that can be adjusted to the desired
object-oriented one with appropriate views – a single SBQL view can
operate on an arbitrary join of wrapped tables so that the actual relational
schema is not visible to the users. 14.4 Bottom-Up Usage ScenarioConsider wrapping an existing
(legacy) relational database, used e.g. by some company or public
organization. In the eGovernment domain this is the main wrapper application.
The approach we call bottom-up. In
this approach some object-oriented model, preferably a set of views, must be
designed to cover the existing relational schema. We present the following very simple
example. It consists of three tables: employees,
departments and locations. The tables are related by
primary-foreign key constraints: an employee works in some department that in
turn is located in some town/location. Each table has a primary key column
(named id); there are also
non-unique (secondary) indices on
employees’ surnames and salaries, departments’ names and
locations’ names. The schema is presented in Fig. 14-4.
14- The primary step of creation of
the schema description expressed as an XML document; technical issues are
described in details below. This wrapper reads this description and it
creates appropriate metadata in the ODRA metabase (one-to-one mapping
applied, each table is represented as a single complex object). The
corresponding object-oriented schema is presented in Fig.14-5. 14-5. Imported
object-oriented schema Names generated by the wrapper are
prefixed with $, which prevents from using them in ad-hoc queries. Thus, the
metaobjects are covered by automatically generated views. This is the final
automatically generated stage for the wrapped relational schema. It can be
already queried or covered by a set of views so it can contribute to the
global schema of the virtual repository. The views shown below are
query-ready, however they do not support relational integrity constraints and
they allow full access to wrapped data (including updating and deleting),
which is not always a good choice. 14-6. Automatically generated views The next stage is performed by the
administrator or programmer who should design final end-user views. Relational integrity constraints
and table relations should be mapped as virtual pointers (notice that in
these views subobjects corresponding to foreign key columns are expressed as
virtual pointers). The resulting relational schema representation (available
for querying and further processing) is shown in the Fig.14-7. 14-7. Final
end-user relational schema The end-user views provide virtual
pointers instead of foreign-key columns, for simplicity of the example they
do not modify the schema further. The assumed security constraints do not
allow updating foreign-key columns (virtual pointers) and primary key
columns. Sample code for the views is listed below: add view EmployeeDef { virtual
objects Employee: record
{e:employees;}[0..*]{ return
(employees) as e; } on_retrieve:
record { id: integer; name: string;
surname: string; sex: string; salary: real;
info: string; birthDate:
date; worksIn: integer; } { return
( deref(e.id) as id, deref(e.name) as name,
deref(e.surname) as
surname, deref(e.sex) as sex, deref(e.salary) as
salary, deref(e.info)
as info, deref(e.birth_date) as
birthDate, deref(e.department_id) as
worksIn ); } on_delete
{ delete
e; } view
idDef { virtual
objects id: record { _id:
employees.id; } { return
e.id as _id; } on_retrieve:
integer { return
deref(_id); } } view
nameDef { virtual
objects name: record
{_name:employees.name;}{ return
e.name as _name; } on_retrieve:
string { return
deref(_name); } on_update(newName:
string) { e.name := newName; } } view
surnameDef { virtual
objects surname: record
{ _surname: employees.surname; } { return
e.surname as _surname; } on_retrieve:
string { return
deref(_surname); } on_update(newSurname:
string) { e.surname := newSurname; } } view
sexDef { virtual
objects sex: record
{_sex:employees.sex;}{ return
e.sex as _sex; } on_retrieve:
string { return
deref(_sex); } on_update(newSex:
string) { e.sex := newSex; } } view
salaryDef { virtual
objects salary: record
{ _salary: employees.salary; } { return
e.salary as _salary; } on_retrieve:
real { return
deref(_salary); } on_update(newSalary:
real) { e.salary := newSalary; } } view
infoDef { virtual
objects info: record
{_info:employees.info;}{ return
e.info as _info; } on_retrieve:
string { return
deref(_info); } on_update(newInfo:
string) { e.info := newInfo; } } view
birthDateDef { virtual
objects birthDate: record{_birthDate:employees.birth_date;}
{ return
e.birth_date as _birthDate; } on_retrieve:
date { return
deref(_birthDate); } on_update(newBirthDate:
date) { e.birth_date := newBirthDate; } } view
worksInDef { virtual
objects worksIn: record{_worksIn:employees.department_id;}
{ on_navigate:
Department { return
Department where id = _worksIn; } } } add view DepartmentDef { virtual
objects Department: record{d:departments;}[0..*]{ return
(departments) as d; } on_retrieve:
record{id:integer; name:string; isLocatedIn:integer;}{ return
( deref(d.id) as id, deref(d.name) as name, deref(d.location_id) as
location ); } on_delete
{ delete
d; } view
idDef { virtual
objects id: record { _id:
departments.id; } { return d.id as _id; } on_retrieve:
integer { return
deref(_id); } } view
nameDef { virtual
objects name: record{_name:departments.name;}{
return
d.name as _name; } on_retrieve:
string { return
deref(_name); } on_update(newName:
string) { d.name := newName; } } view
isLocatedInDef { virtual
objects isLocatedIn: record {_isLocatedIn:departments.location_id;}{ return
d.location_id as _isLocatedIn; } on_navigate: Location { return
Location where id = _isLocatedIn; } } } add view LocationDef { virtual
objects Location: record{l:locations;}[0..*]{ return
(locations) as l; } on_retrieve:
record { id: integer; name: string;
} { return ( deref(l.id) as id, deref(l.name) as name ); } on_delete
{ delete
l; } view
idDef { virtual
objects id: record { _id:
locations.id; } { return
l.id as _id; } on_retrieve:
integer { return
deref(_id); } } view
nameDef { virtual
objects name: record{_name:locations.name;}{
return
l.name as _name; } on_retrieve:
string { return
deref(_name); } on_update(newName:
string) { l.name := newName; } } } The sample queries concerning
directly the given schema (i.e. the views designed by the
administrator/programmer) are presented below: Retrieve names and surnames of employees
earning more than 1000: (Employee
where salary > 1000).(name,
surname) Retrieve employees with their departments
(application of a join by a virtual pointer): Employee
join worksIn.Department Calculate the sum of salaries of all
employees named Smith working in any department located in sum((Employee where
surname = "Smith" and worksIn.Department.isLocatedIn.Location.name
=
" Retrieve the surname and the
department’s location name for the employee with the ABC12345 identifier: ((Employee where id = “ABC12345”) as e join
e.worksIn.Department as d join
d.isLocatedIn.Location as
l).(e.surname, l.name) The wrapped schema transformations
for the global schema are performed by means of updateable object-oriented
views. Below, there are shown a few sample views covering the wrapped sample
schema. Notice that views’ definitions can completely rearrange the
wrapped schema, also relational integrity constraints expressed as virtual
pointers can be overridden (ignored) as other virtual pointers can be
introduced in the upper-level views covering the presented wrapper schema. The view retrieves full names, sexes and
salaries of rich employees, i.e. employees earning more than 2000: add view RichEmployeeDef {
virtual objects RichEmployee:
record e Employee }[0..*]{
return (Employee where salary > 2000) as e;
}
on_retrieve:
record{fullname:string; sex:string; salary:real;}{
return ((deref(e.name)+" "+deref(e.surname)) as fullname, deref(e.sex) as sex, deref(e.salary) as salary);
}
view fullnameDef {
virtual objects fullname: record{_fullname:string;}{
return(deref(e.name)+" "+deref(e.surname))
as _fullname;
}
on_retrieve: string {
return _fullname;
}
}
view sexDef {
virtual objects sex: record{_sex:Employee.sex;}{
return e.sex as _sex;
}
on_retrieve: string {
return deref(_sex);
}
}
view salaryDef {
virtual objects salary: record{_salary:Employee.salary;}{
return e.salary as _salary;
}
on_retrieve: real {
return deref(_salary);
}
} } The next presented view presents
employees’ full names and salaries with names of departments they work
in: add view
EmployeeDepartmentDef {
virtual objects
EmployeeDepartment:
record { e: Employee; d:
Department; }[0..*] {
return Employee as e join e.worksIn.Department as
d;
}
on_retrieve:
record{fullname:string; salary:real; department:string;}{
return((deref(e.name)+" "+deref(e.surname)) as fullname, deref(e.salary) as
salary, deref(d.name) as
department);
}
view fullnameDef {
virtual objects fullname: record{_fullname:string;}{
return(deref(e.name)+" "+deref(e.surname))
as _fullname;
}
on_retrieve: string {
return _fullname;
}
}
view salaryDef {
virtual objects salary: record{_salary:real;}{
return deref(e.salary) as
_salary;
}
on_retrieve: real {
return _salary;
}
}
view departmentDef {
virtual objects department:record{_department:string;}{
return deref(d.name) as
_department;
}
on_retrieve: string {
return deref(d.name);
}
} } The RichEmployee and EmployeeDepartment
views can be queried directly or further referenced by other views, e.g. in
the data integration process executed by the virtual repository. Some simple
direct queries referring these views are presented below: count(RichEmployee) min(RichEmployee.salary) (RichEmployee
where salary = 5000).fullname sum(EmployeeDepartment.salary) (EmployeeDepartment
where salary <
2000).(fullname,department) The next view example presents
integration of two separate schemata – the “employees”
schema is the same wrapped relational schema as the one used above, the
“cars” schema is wrapped from another relational database whose
model is shown below. The wrapping process description is skipped as it is performed
analogically to the previous one. This example realizes a very simple case of
integration of distributed data. 14-8. Logically related separate relational schema The cars.owner_id column (marked with light gray) is logically
related to the employees.id column
in the other database, nevertheless both schemata are maintained locally in
different locations and they are physically independent. The EmployeeCar view combines both wrapped schemata and retrieves
employees’ full names and salaries with their cars’ make names,
model names, colours and manufacturing years: add view
EmployeeCarDef {
virtual objects
EmployeeCar:
record {e:Employee; c:Car;
ma:Make; mo:Model;}[0..*]{
return Employee as e
join (Car where ownerId = e.id) as c
join (Model where id = c.modelId) as mo join (Make where id = mo.makeId) as ma;
}
on_retrieve: record { fullname: string; salary: real; make: string; model: string; colour: string; year: integer; } {
return ((deref(e.name)+" "+deref(e.surname)) as fullname, deref(e.salary) as
salary, deref(ma.name) as
make, deref(mo.name) as
model, deref(c.colour)
as colour, deref(c.year) as
year);
}
view fullnameDef {
virtual objects fullname: record { _fullname: string; } {
return (deref(e.name) + " " + deref(e.surname)) as _fullname;
}
on_retrieve: string {
return _fullname;
}
}
view salaryDef {
virtual objects salary: record { _salary: real; } {
return deref(e.salary) as
_salary;
}
on_retrieve: real {
return _salary;
} }
view makeDef {
virtual objects make: record { _make: string; } {
return deref(ma.name) as
_make;
}
on_retrieve: string {
return _make;
}
}
view modelDef {
virtual objects model: record { _model: string; } {
return deref(mo.name) as _model;
}
on_retrieve: string {
return _model;
}
}
view colourDef {
virtual objects colour: record { _colour: string; } {
return deref(c.colour) as
_colour;
}
on_retrieve: string {
return _colour;
}
}
view yearDef {
virtual objects year: record { _year: integer; } {
return deref(c.year) as
_year;
}
on_retrieve: integer {
return _year;
}
} } Here are some simple queries targeting the EmployeeCar view: (EmployeeCar where salary > 2000).(fullname,
colour) (EmployeeCar where salary > 2000 and colour = "white"). (fullname, make + " " +
model) Similarly, the wrapped data can be
combined with native ODRA objects, including local declarations in views. All
the queries, including views’ retrieved objects, are processed by the
ODRA optimizers and their executed in the resources; the partial results are
then composed and the final result is returned to the client. 14.5 Type MappingThe wrapping procedure requires
some deterministic mapping between relational data types and primitive ODRA
data types. The default type applied for an undefined relational data type (due
to heterogeneity between various RDBMSs there might be some types not covered
by the prototype definitions) is string.
The string type is also assumed for
relational data types currently not implemented in ODRA (including binary
data types like BLOB). The type mapping table is presented below: Table 14-1. Type mapping between SQL and SBQL
14.6 Wrapper Configuration and RunningThe wrapper is realized in the
client-server architecture. A client is embedded in an ODRA database; a server
needs individual configuration and startup (usually it runs on a separate
machine). A wrapper server requires a JDBC
driver for a database to be connected. The currently supported databases are:
Axion, Cloudscape, DB2, DB2/AS400, 14.6.1 Resource Connection ConfigurationA connection configuration file is
connection.properties whose sample can be found the project root
directory is the standard Apache Torque configuration file. Its content is
listed below: torque.database.default
= postgres_employees #configuration for
the postgres database (employees) torque.database.postgres_employees.adapter
= postgresql torque.dsfactory.postgres_employees.factory
= org.apache.torque.dsfactory.SharedPoolDataSourceFactory torque.dsfactory.postgres_employees.connection.driver
= org.postgresql.Driver torque.dsfactory.postgres_employees.connection.url
= jdbc:postgresql://localhost:5432/wrapper torque.dsfactory.postgres_employees.connection.user
= wrapper torque.dsfactory.postgres_employees.connection.password
= wrapper #configuration for
the firebird database (employees) torque.database.firebird_employees.adapter
= firebird torque.dsfactory.firebird_employees.factory
= org.apache.torque.dsfactory.SharedPoolDataSourceFactory torque.dsfactory.firebird_employees.connection.driver
= org.firebirdsql.jdbc.FBDriver torque.dsfactory.firebird_employees.connection.url
= jdbc:firebirdsql:localhost/3050:c:/tmp/wrapper.gdb torque.dsfactory.firebird_employees.connection.user
= wrapper torque.dsfactory.firebird_employees.connection.password
= wrapper #configuration for
the postgres database (cars) torque.database.postgres_cars.adapter
= postgresql torque.dsfactory.postgres_cars.factory
= org.apache.torque.dsfactory.SharedPoolDataSourceFactory torque.dsfactory.postgres_cars.connection.driver
= org.postgresql.Driver torque.dsfactory.postgres_cars.connection.url
= jdbc:postgresql://localhost:5432/wrapper2 torque.dsfactory.postgres_cars.connection.user
= wrapper torque.dsfactory.postgres_cars.connection.password
= wrapper #configuration for
the ms sql database (SD-SQL) torque.database.sdsql.adapter
= mssql torque.dsfactory.sdsql.factory
= org.apache.torque.dsfactory.SharedPoolDataSourceFactory torque.dsfactory.sdsql.connection.driver
= net.sourceforge.jtds.jdbc.Driver torque.dsfactory.sdsql.connection.url
= jdbc:jtds:sqlserver://212.191.89.51:1433/SkyServer torque.dsfactory.sdsql.connection.user
= sa torque.dsfactory.sdsql.connection.password
= The sample file contains four data sources
defined (named postgres_employees, firebird_employees, postgres_cars and sdsql) for different RDBMSs and schemata – the same
configuration file can be used for different wrapped databases. However, a
separate server must be started for each resource. A torque.database.default property defines a default database if none
is specified as an input of an application (e.g., a wrapper server). The
other properties mean:
The xxx word should be substituted with a unique data source name
that is further used for pointing at the resource. 14.6.2 Relational Schema Description GenerationA schema description file in an
XML document is similar to the one used by Apache Torque. Its DTD is
available at http://jacenty.kis.p.lodz.pl/relational-schema.dtd.
In most cases the file is automatically generated, nevertheless if such
solution for some reasons is impossible or some changes must be introduced
(e.g. only selected relational tables or views should be exposed to the
wrapper), the file can be also created or edited manually. The schema
description file is generated (typed) only once and it can be reused until
resource schema changes. After, the wrapper server must be restarted too and
a new description is to be loaded. The automatic generation process
requires the connection configuration file described above available. Once a configuration.properties is defined
for a wrapped RDBMS, the schema generator can be launched by odra.wrapper.generator.SchemaGeneratorApp.
The application can run without parameters (a configuration.properties file is searched in the application home
directory) and the default database name is used. One can also specify an
optional parameter for a configuration file path. If it is specified, also a
database name can be provided as the second parameter. The schema generator application standard
output is as below: Schema generation
started... Schema
generation finished in 5875 ms... As a result the schema description
XML file is created in the application home (launch) directory. The file name
is created according to a pattern <dbnam>e-schema.generated.xml,
where <dbname> is a database name
specified as an application startup parameter or a default one in the
properties file. 14.6.3 Wrapper Server RunningThe server (odra.wrapper.net.Server) is a multithreaded application (a
separate parallel thread is invoked for each client request). It can be
launched as a standalone application or as a system service. Standalone Launch A standalone launch should not be
used in a production environment, its aim are only testing purposes. In order
to start the server a system service, read the instructions in the next
subsection. If the server is launched without
startup parameters, it searches for the connection.properties
file in the application home directory and uses a default database name
declared in this file. Other default values are a listener port (specified as
2000) and a verbose mode (specified as true).
If one needs to override these values, use syntax as in the sample below: odra.wrapper.net.Server -Ddbname -Vfalse
-P5124 -C/path/to/config/ All the startup parameters are optional and
their order is arbitrary:
The path denoted with a -C parameter must be a valid directory
where all the configuration files are stored, including connection.properties and schema description XML document(s). A server output at a successful startup is
shown below: Database model
successfully build from schema in './postgres-schema.generated.xml' SBQL wrapper
listener started on port 2000... SBQL wrapper
listener is running under Java Service Wrapper Big thanks to Tanuki Software http://wrapper.tanukisoftware.org Service Launch Running the server as a system
service is realized with the Java Service Wrapper (JSW, http://wrapper.tanukisoftware.org).
The JSW can be downloaded as binaries or a source code. It can be run on
different platforms (e.g., MS Windows, Linux, Solaris, MacOS X) and the
appropriate version must be installed in a system (binary download should be
enough). The following instructions refer
to MS Windows environment (they are similar on other platforms). Detailed
descriptions and examples of installation and configuration procedures are
available at the JSW web site. Below, $JSW_HOME
denotes a home directory of JSW. The main JSW configuration is
defined in $JSW_HOME/conf/wrapper.conf.
The file example is listed below: #*************************************************************** # TestWrapper
Properties # # NOTE - Please use
src/conf/wrapper.conf.in as a template for your # own application
rather than the values used for the # TestWrapper sample. #*************************************************************** # Java Application wrapper.java.command=java # Java Main class.
This class must implement the WrapperListener interface # or guarantee that
the WrapperManager class is initialized. Helper # classes are
provided to do this for you. See the Integration section # of the
documentation for details. wrapper.java.mainclass=
org.tanukisoftware.wrapper.WrapperSimpleApp # Java Classpath
(include wrapper.jar) Add class path elements as # needed starting
from 1 wrapper.java.classpath.1=../lib/wrapper.jar wrapper.java.classpath.2=C:/Documents
and Settings/jacek/eclipse/EGB/dist/lib/jodra.jar wrapper.java.classpath.3=C:/Documents
and Settings/jacek/eclipse/EGB/lib/postgresql-8.1-405.jdbc3.jar wrapper.java.classpath.4=C:/Documents
and Settings/jacek/eclipse/EGB/lib/jaybird-full-2.1.1.jar wrapper.java.classpath.5=C:/Documents
and Settings/jacek/eclipse/EGB/lib/jdom.jar wrapper.java.classpath.6=C:/Documents
and Settings/jacek/eclipse/EGB/lib/zql.jar wrapper.java.classpath.7=C:/Documents
and Settings/jacek/eclipse/EGB/lib/commons-configuration-1.1.jar wrapper.java.classpath.8=C:/Documents
and Settings/jacek/eclipse/EGB/lib/commons-collections-3.1.jar wrapper.java.classpath.9=C:/Documents
and Settings/jacek/eclipse/EGB/lib/commons-lang-2.1.jar wrapper.java.classpath.10=C:/Documents
and Settings/jacek/eclipse/EGB/lib/commons-logging-1.0.4.jar # Java Library Path
(location of Wrapper.DLL or libwrapper.so) wrapper.java.library.path.1=../lib # Java Additional
Parameters wrapper.java.additional.1=-ea # Initial Java Heap
Size (in MB) #wrapper.java.initmemory=3 # Maximum Java Heap
Size (in MB) #wrapper.java.maxmemory=64 # Application
parameters. Add parameters as needed starting from 1 wrapper.app.parameter.1=odra.wrapper.net.Server wrapper.app.parameter.2=-C"C:/Documents
and Settings/jacek/eclipse/EGB/" wrapper.app.parameter.2.stripquotes=TRUE #wrapper.app.parameter.3=-Dfirebird #wrapper.app.parameter.4=-P2000 #wrapper.app.parameter.5=-Vtrue #*************************************************************** # Wrapper Logging
Properties #*************************************************************** # Format of output for
the console. (See docs for formats) wrapper.console.format=PM # Log Level for
console output. (See docs for log levels) wrapper.console.loglevel=INFO # Log file to use
for wrapper output logging. wrapper.logfile=../logs/wrapper.log # Format of output
for the log file. (See docs for formats) wrapper.logfile.format=LPTM # Log Level for log
file output. (See docs for log levels) wrapper.logfile.loglevel=INFO # Maximum size that
the log file will be allowed to grow to before # the log is
rolled. Size is specified in bytes. The default value # of 0, disables
log rolling. May abbreviate with the 'k' (kb) or # 'm' (mb) suffix.
For example: 10m = 10 megabytes. wrapper.logfile.maxsize=1m # Maximum number of
rolled log files which will be allowed before old # files are
deleted. The default value of 0 implies no limit. wrapper.logfile.maxfiles=10 # Log Level for
sys/event log output. (See docs for log levels) wrapper.syslog.loglevel=NONE #*************************************************************** # Wrapper Windows
Properties #*************************************************************** # Title to use when
running as a console wrapper.console.title=ODRA
wrapper server #*************************************************************** # Wrapper Windows
NT/2000/XP Service Properties #*************************************************************** # WARNING - Do not
modify any of these properties when an application # using this
configuration file has been installed as a service. # Please uninstall
the service before modifying this section. The # service can then
be reinstalled. # Name of the
service wrapper.ntservice.name=ODRAwrapper # Display name of
the service wrapper.ntservice.displayname=ODRA
wrapper server # Description of
the service wrapper.ntservice.description=ODRA
relational database wrapper server # Service
dependencies. Add dependencies as needed starting from 1 wrapper.ntservice.dependency.1= # Mode in which the
service is installed. AUTO_START or DEMAND_START wrapper.ntservice.starttype=AUTO_START # Allow the service
to interact with the desktop. wrapper.ntservice.interactive=false The most important properties in wrapper.conf are: ·
wrapper.java.command – which JVM use (depending
on a system configuration one might need to specify a full path to the java
program), ·
wrapper.java.mainclass – an JSW integration method
(with the value specified in the above listing it does not require a JSW
implementation, do not modify this one), ·
wrapper.java.classpath.N – Java classpath elements
(do not modify the first classpath element, as it denotes a JSW JAR location,
the other elements refer to libraries used by the ODRA wrapper server,
including JDBC drivers), ·
wrapper.java.additional.N – JVM startup parameters
(in the example only -ea used for
enabling assertions), ·
wrapper.java.maxmemory – JVM heap size, probably
it would require more than the default 64 MB for real-life databases, ·
wrapper.app.parameter.1 – ODRA wrapper server main
class (do not modify this one), ·
wrapper.app.parameter.2 – a path to ODRA wrapper
server configuration files directory (i.e. connection.properties and <dbname>-schema.generated.xml)
passed as a server startup parameter, ·
wrapper.app.parameter.2.stripquotes – important when a
parameter name contains extra quotes, ·
wrapper.app.parameter.3 – database name passed as a
server startup parameter, ·
wrapper.app.parameter.4 – server listener port
passed as a server startup parameter, ·
wrapper.app.parameter.5 – server verbose mode
passed as a server startup parameter, ·
wrapper.logfile.maxsize – a maximum size of a
single log file before it is split, ·
wrapper.logfile.maxfiles – a maximum number of log
files until the old ones are deleted. Notice that wrapper.app.parameter.[2...5] conform server startup parameters
syntax described above. They are optional and their order is arbitrary. Other
configuration properties' descriptions are available at the JSW web site. In order to test a configuration
one can run $JSW_HOME/bin/test.bat.
The JSW is launched as a standalone application and runs the ODRA wrapper
server (any misconfiguration can be easily detected). If a test succeeds, a
JSW is ready to install as a system service. A service is installed with install.bat and deinstalled with uninstall.bat. A sample preconfigured
JSW installation for MS Windows can be downloaded from http://jacenty.kis.p.lodz.pl/jsw.win.zip
– only some paths need to be adjusted. |
|||||||||||||
|
Last modified: July 9, 2008 |