opehD8copy - Developer Mahual

hIIp://opendbcopy.org
openD8copy is an Open Source ProjecI hosIed aI Sourcelorge
hIIp://www.sourceíorge.neI/projecIs/opendbcopy/
Release 0.5!
DaIe 26.07.04
Re!erehce developermanual0.5!
© 2004 by AnIhony SmiIh, Puzzle lTC GmbH all righIs reserved.
ch200407J0w5874
Puzzle lTC GmbH
MaulbeersIrasse !5
CHJ0!! 8ern
SwiIzerland
Phone: ÷4! (0)J! J98 44 77
lax: ÷4! (0)J! J98 44 78
www.puzzle.ch
openD8copy Developer Manual Pelease 0.5!
DocumehI HisIory
DaIe Versioh Persoh CommehIs
26/07/04 0.5! A. SmiIh lirsI issue
28/07/04 0.5! A. SmiIh lurIher chapIers added and reviewed
1able o! CohIehIs
! Overview .............................................................................................................................................. J
2 SoíIware PequiremenIs ....................................................................................................................... J
J openD8copy Core lramework and Plugins on Ihe Web ..................................................................... 4
4 ArchiIecIure ......................................................................................................................................... 5
4.! MainConIroller .............................................................................................................................. 5
4.2 !obManager .................................................................................................................................. 6
4.J PluginManager ............................................................................................................................. 6
4.4 PluginScheduler ............................................................................................................................ 6
4.5 DynamicPluginThread ................................................................................................................... 6
4.6 A Plugin lmplemenIaIion .............................................................................................................. 6
5 Plugin ComponenIs ............................................................................................................................. 7
5.! Plugin Model ................................................................................................................................. 7
5.!.! Plugin ConíiguraIion .............................................................................................................. 7
5.!.2 CreaIing new Plugin Models .................................................................................................. 9
5.2 Graphical User lnIeríaces ............................................................................................................ !0
5.2.! GUl ConíiguraIion ................................................................................................................ !!
5.2.2 CreaIing your own GUls ....................................................................................................... !!
5.J Plugin Thread .............................................................................................................................. !2
5.4 Language Pesources ................................................................................................................... !2
6 Lxample The Copy Plugin ................................................................................................................ !J
6.! Overview ..................................................................................................................................... !J
6.2 Plugin DaIabaseModel ................................................................................................................ !J
6.2.! Plugin ConíiguraIion lile ...................................................................................................... !J
6.2.2 Plugin AIIribuIes .................................................................................................................. !J
6.2.J Coní LlemenIs ...................................................................................................................... !4
6.2.4 Threads LlemenI(s) ............................................................................................................... !4
6.2.5 lnpuI / OuIpuI LlemenIs ...................................................................................................... !5
6.2.6 Source & DesIinaIion DaIabase LlemenIs ............................................................................ !5
6.2.7 Mapping LlemenI ................................................................................................................ !6
6.2.8 lilIer LlemenIs ...................................................................................................................... !6
6.J Graphical User lnIeríaces ............................................................................................................ !6
6.J.! GUl AIIribuIes ...................................................................................................................... !7
6.4 Plugin Thread .............................................................................................................................. !7
6.5 Language Pesource liles ............................................................................................................. 22
7 8uilding, TesIing and Deploying Plugins ............................................................................................ 2J
2/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
1 Overview
openD8copy is an open source projecI by AnIhony SmiIh, Puzzle lTC GmbH. The projecI is hosIed aI
Sourceíorge and published under Ihe Ierms oí Ihe GNU General Public License.
openD8copy musI be undersIood as a íramework Io coníigure and execuIe plugins. A plugin can do
ANYTHlNG. Some plugins are daIabase speciíic, oIhers provide íeaIures Io do íile manipulaIions and
Iransíers eIc. There is no limiIaIion oí whaI a plugin can or could do.
The core íramework iIselí is managed and checked in as one separaIe projecI in Ihe CVS PeposiIory aI
Sourcelorge. Lach plugin is managed in a separaIe projecI paIh wiIhin Ihe same CVS PeposiIory.
Please use Ihe public íorum Io posI quesIions. There are also links Io requesI new íeaIures and Irack
bugs. The mailing lisIs have been deleIed because excepI one person were posIing quesIions using Ihe
íorum.
lor simple plugin developmenI and deploymenI use an exisIing plugin.
Name WebsiIe
openD8copy aI Sourcelorge hIIp://sourceíorge.neI/projecIs/opendbcopy/
openD8copy Download hIIp://sourceíorge.neI/projecI/showíiles.php?group_id~9!406
openD8copy lorum hIIp://sourceíorge.neI/íorum/?group_id~9!406
openD8copy WebsiIe hIIp://opendbcopy.org
hIIp://opendbcopy.ch
GNU General Public License hIIp://www.gnu.org/licenses/gpl.IxI
Puzzle lTC WebsiIe hIIp://www.puzzle.ch
(Puzzle provides a compleIe Sourceíorge mirror :)
2 So!Iware RequiremehIs
openD8copy requires a !ava PunIime LnvironmenI. lí noI yeI insIalled, please download an acIual
!ava PunIime LnvironmenI or SIandard Developer KiI !.4 írom hIIp:// java.sun.com .
To develop and / or debug openD8copy or plugins you require a !ava lDL. Am currenIly using
Lclipse J.0, see hIIp://www.eclipse.org.
OpenD8copy Core lramework and Plugins are builI and deployed using Apache AnI. Download
Apache AnI (hIIp://anI.apache.org) ií you have noI yeI insIalled an acIual version (!.5 or higher).
An acIual !D8C driver íor each daIabase sysIem one plans Io access.
OIher libraries required íor new plugins
OpenD8copy 0.5 has been IesIed using !2SDK !.4.2_0J.
The laIesI sources can be checked ouI írom Ihe CVS PeposiIory. lor deIails see Ihe projecIs websiIe.
J/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
3 opehD8copy Core Framework ahd Plugihs oh Ihe Web
The openD8copy core íramework and plugins are managed and sIored wiIhin separaIe direcIories in
Ihe CVS PeposiIory aI Sourcelorge.
The core írameworks direcIory is named opendbcopy. Lach plugins direcIory is preíixed wiIh
opendbcopy. L.g. opendbcopy.copy (as highlighIed) conIains Ihe Copy Plugin íor openD8copy.
Please noIe IhaI Ihe sources are someIimes noI commiIed beíore a new release is posIed. lí you
require an updaIe please do noI hesiIaIe Io conIacI Ihe developer Ieam.
4/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
4 ArchiIecIure
Plugins are execuIed wiIhin separaIe Threads. The Ihreads liíecycle is managed by openD8copys core
íramework.
The above diagram is noI compleIe. lI shows some imporIanI classes wiIh aIIribuIes and meIhods.
4.! MainConIroller
MainController is Ihe main class Io launch openD8copy. lI is Ihe cenIral class and parenI oí all
Iop manager classes. openD8copy is designed using Ihe ModelViewConIroller PaIIern MVC. The
conIrollers job is Io handle requesIs on Ihe model and handover errors írom Ihe model Io any view
(caller oí a requesI).
openD8copy can be run in inIeracIive or baIch mode. Graphical User lnIeríaces (GUl) provide Ihe
abiliIy Io coníigure jobs and plugins, execuIe single plugins and plugin chains, also called jobs. All
coníiguraIion parameIers can be sIored in xml íiles. Once a job is coníigured and ready íor producIion,
openD8copy can be execuIed in baIch mode, wiIhouI loading any GUls. This allows saving memory
and place openD8copy on a server noI providing any Window ComponenIs (X Server). A job is sIored
in a single xml íile and conIains plugin meIadaIa oí one or several plugin models.
5/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
4.2 !obManager
JobManager is owned and creaIed by MainController. JobManager is Ihe owner oí a job
model. A job may conIain zero Io n plugins. A JobManager insIance iIselí uses a PluginManager
insIance Io manage plugins. JobManager provides meIhods Io imporI and exporI a job
coníiguraIion. An execute() meIhod handles requesIs on Ihe job model or handles requesIs over Io
Ihe appropriaIe plugin model, which is parI oí Ihe job model.
4.J PluginManager
PluginManager is owned and creaIed by JobManager. lIs responsibiliIy is Io parse and
dynamically load plugin resources írom direcIories. AíIer loading resources and meIadaIa oí plugins,
PluginManager is able Io add a plugin Io one oí Iwo lisIs. One lisI conIains plugins which are noI
bound Io a job, only available in memory. A second lisI conIains plugins which are parI oí a plugin
chain bound Io a job which can be saved as a single uniI.
While PluginManager is responsible íor loading plugin resources and models, iI is noI responsible
íor loading and managing Graphical User lnIeríaces oí plugins. This is done by PluginGuiManager.
4.4 PluginScheduler
PluginScheduler is a singleIon, owned by PluginManager. PluginScheduler receives a lisI oí
plugins Io execuIe a plugin chain or a single plugin model. lIs responsibiliIy is Io dynamically load a
plugin Ihread, pass ouIpuI parameIers as inpuI Io íollowing plugins, inIerrupI single plugins and
plugin chains when requesIed and íinally schedule plugins. A plugin which has been successíully
execuIed is removed írom PluginSchedulers lisI. NoI so írom a plugin chain sIored in
PluginManager.
4.5 DynamicPluginThread
DynamicPluginThread exIends java.lang.Thread and implemenIs Ihe lnIeríace IExecute.
IExecute only deíines one meIhod execute().
The íinal public run() meIhod implemenIed by DynamicPluginThread calls setUp(),
execute() and tearDown(). lI also handles Ihe sIaIe oí a plugin.
Plugins implemenIed musI overwriIe Ihe execute() meIhod oí DynamicPluginThread.
OpIionally setUp() and tearDown() meIhods oí DynamicPluginThread can be overwriIIen.
setUp() and tearDown() are called beíore, respecIively aíIer execute() has been successíully
compleIed (no excepIion Ihrown). Use Ihe setUp() meIhod Io read coníiguraIion parameIers, seIup
daIabase connecIions eIc. The execuIe meIhod is called aíIer successíul setUp(), e.g. coníiguraIion
parameIers were successíully read and validaIed, daIabase connecIion(s) opened eIc. Do noI use Ihe
tearDown() meIhod Io close daIabase connecIions as Ihis meIhod is only called aíIer successíul
execute(). Use tearDown() íor example Io close íile wriIers or whaIever else. Close connecIions
in a finally block oí your execute() meIhod body.
4.6 A Plugin lmplemenIaIion
A plugins Ihread class, e.g. CopyMappingPlugin, musI exIend DynamicPluginThread.
The only required meIhod Io implemenI is
public final void execute() throws PluginException
6/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
5 Plugih CompohehIs
Lach openD8copy plugin consisIs oí Ihe íollowing componenIs:
Plugin Model
Graphical User lnIeríaces
Plugin Thread
Language Pesource liles
lor an example please have a look aI Ihe íollowing chapIer.
5.! Plugin Model
The model oí a plugin is represenIed using a plugin.xml íile and !ava Model class. All parameIers
speciíied wiIhin such a plugin.xml íile can be used when seIIing up, execuIing or Iearing down a
plugin. One can provide iIs own !ava Model, exIend exisIing ones or jusI use exisIing ones.
All plugin.xml íiles musI conIain Ihe íollowing elemenIs
ElemehI Name DescripIioh
conf
This elemenI conIains coníiguraIion elemenIs. openD8copy provides a
generic graphical user inIeríace Io display and manipulaIe plugin
coníiguraIion parameIers. See Ihe nexI chapIer, Generic AIIribuIes íor GUl
ConíiguraIion íor deIails.
threads
luIure releases may provide Ihe abiliIy Io speciíy more Ihan one Ihread.
CurrenIly Ihe elemenI threads musI conIain one childelemenI called
thread, speciíying Ihe Ihread class Io execuIe and a description
aIIribuIe.
input
Used Io place ouIpuI írom a íormer plugin as inpuI íor Ihe acIual plugin
output
Used Io sIore possible ouIpuI oí a plugin model
Lxample plugin model wiIh minimum required elemenIs (replace aIIribuIe values accordingly)
<plugin identifier="id" model_class="org.abc.ModelClass">
<conf />
<threads>
<thread thread_class="org.abc.ThreadClass" description="key" />
</threads>
<input />
<output />
</plugin>
5.!.! Plugin ConíiguraIion
Using Ihe graphical user inIeríace opendbcopy.gui.PluginConfiguration Io display and
manipulaIe parameIers is noI mandaIory. One can also provide iIs own graphical user inIeríace(s) Io
manipulaIe daIa and coníiguraIion parameIers. WiIhin Ihe coní elemenI one can add child elemenIs.
To add parameIers which can be coníigured using Ihe generic GUl PanelConfiguration, Ihe
íollowing aIIribuIes are currenIly supporIed, see an example below.
AIIribuIe Name DescripIioh
type
WhaI GUl Iype is required Io coníigure a parameIers value
7/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
AIIribuIe Name DescripIioh
value
May conIain a deíaulI value or be empIy
required
true or false currenIly noI IesIed auIomaIically
description
key Io resource enIry in resource íile (language speciíic descripIions)
The aIIribuIe type currenIly supporIs Ihe íollowing Iypes. Type names are case insensiIive.
type values DescripIioh
string
SIring parameIers
boolean
ParameIers which musI be Irue or íalse
int
lnIeger value parameIers. TesIed when user enIers a
value.
file_dir_filelists_selection
Drop down box íor selecIion oí íile, direcIory or íilelisI
file
lile browser
dir
DirecIory browser
hibernate_dialect
Drop down box íor HibernaIe dialecI selecIion
(see
hIIp://www.hibernaIe.org/hib_docs/api/neI/sí/hibernaIe/di
alecI/packagesummary.hIml)
An example íor selecIion oí a direcIory. The deíaulI direcIory is „dump“, which may be relaIive or
absoluIe (e.g. /home/smitha/.opendbcopy/inout/dump, c:\temp).
<conf>
<!-- path may be relative or absolute -->
<dir required="true" value="dump" type="dir"
description="plugin.opendbcopy.dump.conf.outputDir" />
</conf>
8/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
5.!.2 CreaIing new Plugin Models
A plugins daIa conIainer is a model. OperaIions on a model can be implemenIed in separaIe classes or
Ihe model iIselí. A models íile represenIaIion is plugin.xml providing Ihe basic sIrucIure. LxIending
an exisIing !ava Model class is noI necessary as you can browse Ihe model elemenIs írom Iop Io
boIIom using pure XML APls. lI is up Io you Io decide whaI is simpler and nicer. Providing meIhods
Io seI and geI daIa írom Ihe model is oíIen more comíorIable and more ílexible íor íuIure exIensions
Ihan direcIly parsing Ihe XML Iree.
The íollowing diagram shows a simpliíied hierarchy oí Ihe model archiIecIure. Please noIe IhaI
DatabaseModel provides Ions oí meIhods which cannoI be shown on on simple diagram.
9/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
5.2 Graphical User lnIeríaces
Lvery plugin musI provide a gui.xml íile, even ií no GUls are required. ln baIch mode no GUls are
loaded aI all ií noI enabled. Use gui.xml Io speciíy GUls Io load, order wiIhin wizard and GUl IiIle.
To develop your own GUls and add Ihose Io Ihe Iab selecIion, exIend Ihe super class DynamicPanel.
The íollowing diagram shows Ihe relaIion oí some imporIanI GUl classes. NoIe IhaI one imporIanI
aIIribuIe is Ielling openD8copy ií a GUl shall be regisIered as an observer oí Ihe observable model
PluginGuiManager. The diagram is on only an exIracI and noI compleIe.
8oxes in yellow are sIandard GUls which are used in sIandard plugins and can be used wiIhin your
own plugins. To creaIe your own GUls, see orange box on Ihe leíI hand side, exIend Ihe class
DynamicPanel.
!0/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
5.2.! GUl ConíiguraIion
GUl coníiguraIion is sIored in a íile called gui.xml. lIs sIrucIure looks like:
<gui identifier="id" display_order="numeric_value"
resource_name="resource_file_name_without_file_ending">
<title value="key for title" />
<panels>
<panel title="key for first gui title">
<class name="class name for first gui" register_as_observer="true" />
</panel>
<panel title="key for second gui title">
<class name="class name for second gui" register_as_observer="false" />
</panel>
</panels>
</gui>
All gui.xml íiles musI conIain Ihe íollowing elemenIs as children oí Ihe rooI elemenI gui.
ElemehI Name DescripIioh
title
An aIIribuIe value conIains Ihe key íor Ihe language dependenI IiIle.
panels
May conIain 0 Io n panel elemenIs
The elemenI gui musI conIain Ihe íollowing aIIribuIes:
AIIribuIe Name DescripIioh
identifier
The unique idenIiíier used wiIhin Ihe plugin.xml
display_order
The display_order aIIribuIe musI be a numeric number and allows Io
conIrol Ihe posiIion oí Ihis plugins IiIle wiIhin Ihe plugin selecIion menu.
resource_name
The resource properIy name íor Ihis plugin wiIhouI íile ending
.properties.
A gui.xml only conIains one elemenI panels (plural). This plugins elemenI may conIain 0 Io n
elemenIs named plugin. Lach plugin elemenI musI provide a title aIIribuIe. The titles
aIIribuIe value is Ihe key íor Ihe resources (language dependenI). Lach panel elemenI musI conIain a
child elemenI named class.
The elemenI class musI conIain Ihe íollowing aIIribuIe:
AIIribuIe Name DescripIioh
name name musI conIain Ihe java package and class name íor Ihe sIandard or
cusIom GUl. This aIIribuIe is required.
regisIer_as_observer Use Ihis aIIribuIe Io Iell PluginGui ií Ihis GUl shall be regisIered as observer
oí Ihe model observed. This aIIribuIe is noI mandaIory.
5.2.2 CreaIing your own GUls
When creaIing a new plugin iI may be IhaI you require new GUls. To do such is very simple.
openD8copy already provides Ihe íramework Io puI a new GUl inIo a workílow wizard, regisIer Ihe
new GUl as observer, provide a next buIIon íor your wizard eIc. lí your new plugin is oí general
inIeresI, why noI donaIe Ihe source code back Io Ihe openD8copy projecI?
Have a look aI some oIher GUls exIending Ihe DynamicPanel beíore you sIarI creaIing your own
GUls Io íamiliarise yourselí. lI is up Io you ií you wanI Io overwriIe Ihe supermeIhods oí
DynamicPanel, such as Ihe meIhod update(...) or onSelect(). onSelect() is
auIomaIically called whenever a user clicks on Ihe appropriaIe Iab íor Ihis GUl. OverwriIe Ihis meIhod
when Ihis GUl shall updaIe iIs componenIs, load daIa or whaIever.
!!/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
A word abouI GUl design using Swing. Generally you are íree Io use whaIever LayoutManager you
like. There is no limiIaIion pure !ava. All new GUls oí openD8copy will be replaced using
TableLayout (see hIIp://www.clearIhoughI.inío/soíIware/TableLayouI), ií noI yeI already done as
Ihis LayoutManager is very good.
Have a look aI how LxcepIions are caughI, respecIively Ihrown. Do noI caIch LxcepIions and handle
Ihem ií iI is noI Ihe GUls responsibiliIy. When Ihrowing LxcepIions Ihose are íinally caughI by
FrameMain and presenIed Io Ihe user and also logged properly.
5.J Plugin Thread
Lvery plugin musI implemenI a plugin Ihread class, exIending Ihe super class
DynamicPluginThread. This plugin Ihread class musI implemenI an execute() meIhod.
AddiIional meIhods, classes or oIher !ava libraries, even exIernal programmes can be used.
The plugin Ihread class IogeIher wiIh opIional classes and archives musI be deployed as jar archive(s)
or zip íile(s) preíerrably jar íile(s). Using Ihe deíaulI plugin build.xml íile, all class íiles including
source code are added Io one single jar íile, including language resource íiles. When deploying a
plugin Io Ihe openD8copy environmenI, all jar íiles oí Ihe plugins lib direcIory are deployed Ioo.
5.4 Language Pesources
Lvery plugin musI provide aI leasI one resource íile. Pesource íiles are normal .properties íiles,
using key / value pairs.
The suííix oí Ihe resource íile name speciíies Ihe language, e.g. „de“ íor german (,deuIsch¨). The
deíaulI language resource íile is expecIed Io conIain Lnglish key / value pairs, wiIh no íile suííix íor
Lnglish.
Pesource values may conIain parameIers speciíied using {0}, {1}, {...} as placeholders wiIhin a
value. The number speciíies Ihe parameIer number, beginning aI 0 (zero). When reading language
dependenI resource values conIaining dynamic parameIers, such as numbers, names eIc., parameIers
can be replaced by providing SIring arrays.
Here an example: message.model.successful=capturing {0} done
The key is message.model.successful. The Lnglish IexI íor Ihis key is capturing {0} done.
The value wiIhin brackeIs {0} is variable.
To read Ihe value according Io Ihe language currenIly seI use Ihe íollowing code.
String[] param = { "testmodel" };
rm.getString("message.model.successful", param);
rm is Ihe PesourceManager owned by MainConIroller, which is available in any GUl exIending
DynamicPanel.
To read values wiIhouI parameIers use Ihe íollowing synIax:
rm.getString("key");
Please noIe IhaI openD8copy has an advanced ResourceManager implemenIed. One does noI have
Io provide Ihe bundle id as preíix íor keys, Locale eIc. A value íor a given key is íound ií Ihe key /
value pair was loaded properly, independenI oí íile. The only disadvanIage oí Ihis model is uniqueness
oí keys which musI be guaranIeed Io avoid overwriIing oí key / value pairs.
!2/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
6 Example - 1he Copy Plugih
6.! Overview
This plugin, called opendbcopy.copy, copies records oí selecIed source Iables and columns inIo
selecIed desIinaIion Iables.
lí Ihe underlying PD8MS supporIs PeíerenIial lnIegriIy ConsIrainIs, Ihe order oí Iables Io process is
respecIed, buI Ihis íeaIure is parI oí Ihe openD8copy core íramework and musI noI be implemenIed
wiIhin Ihis plugin. The plugin direcIly geIs an ordered lisI oí Iables Io process.
lí copy errors occur, Ihose are logged inIo comma separaIed value íiles, ií enabled by Ihe user. The
plugin wriIes a new íile íor each Iable conIaining copy errors, including Ihe records values and error
message.
6.2 Plugin DaIabaseModel
This plugin uses Ihe DatabaseModel class Io hold and manipulaIe model daIa. DatabaseModel
inheriIs írom iIs superclass Model.
6.2.! Plugin ConíiguraIion lile
The plugin coníiguraIion íile conIains Ihe íollowing elemenIs and aIIribuIes
<plugin identifier="copy" model_class="opendbcopy.plugin.model.database.DatabaseModel">
<conf>
<!-- path may be relative or absolute -->
<dir required="true" value="" type="dir" description="plugin.opendbcopy.copy.conf.outputDirErrorLogs" />
<log_error value="true" type="boolean" description="plugin.opendbcopy.copy.conf.logError" />
<output>
<filelist value="error_logs" type="string"
description="plugin.opendbcopy.copy.conf.output.filelistIdentifier" />
</output>
</conf>
<threads>
<thread thread_class="opendbcopy.plugin.copy.CopyMappingPlugin" description="title.plugin.opendbcopy.copy" />
</threads>
<input />
<output />
<source_db>
<driver />
<metadata />
<connection />
<catalog value="" />
<schema value="%" />
<table_pattern value="%" />
<model />
</source_db>
<destination_db>
<driver />
<metadata />
<connection />
<catalog value="" />
<schema value="%" />
<table_pattern value="%" />
<model />
</destination_db>
<mapping />
<filter>
<string name="trim" process="false" />
<string name="remove_intermediate_whitespaces" process="false" />
<string name="set_null" process="false" />
</filter>
</plugin>
6.2.2 Plugin AIIribuIes
AIIribuIe Name DescripIioh
identifier
„copy“ a unique sIring idenIiíier
!J/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
AIIribuIe Name DescripIioh
model_class „opendbcopy.plugin.model.database.DatabaseModel“
Model class providing elemenIs íor source daIabase, desIinaIion daIabase,
daIabase mapping and íilIer elemenIs. Values seI in Ihe above íile are deíaulI
values. DatabaseModel can be used íor single daIabase mode by removing
Ihe elemenI desIinaIion_db.
6.2.J Coní LlemenIs
ElemehI Name DescripIioh
dir <dir required="true" value="" type="dir"
description="plugin.opendbcopy.copy.conf.outputDirError
Logs" />
Speciíy Ihe ouIpuI paIh íor error log íiles
required ~ ,true“ means Ihis parameIer musI be seI
value ~ „“ no deíaulI direcIory seI
type ~ „dir“ pops up a direcIory browser when clicked by user
description key íor resource properIy
log_error <log_error value="true" type="boolean"
description="plugin.opendbcopy.copy.conf.logError" />
Shall errors occuring be logged or noI
value ~ ,Irue¨ by deíaulI errors are logged
type ~ ,boolean¨ pops up a dialog box Io selecI Irue or íalse
description key íor resource properIy
output
filelist elemenI
<filelist value="error_logs" type="string"
description="plugin.opendbcopy.copy.conf.output.filelis
tIdentifier" />
lí errors occur during Ihe copy process, Ihis ouIpuI elemenI conIains a íilelisI
wiIh paIh and íilenames Io error log íiles íor possible íurIher processing oí
íollowing plugins
value ~ „error_logs“ a sIring name íor íilelisI idenIiíicaIion
type ~ „string“ pops up a dialog allowing Io speciíy a sIring
description key íor resource properIy
6.2.4 Threads LlemenI(s)
ElemehI Name DescripIioh
thread <thread
thread_class="opendbcopy.plugin.copy.CopyMappingPlugin"
description="title.plugin.opendbcopy.copy" />
CurrenIly only one thread_class elemenI is allowed per plugin. The
elemenI threads musI conIain an elemenI called thread.
thread_class ~
„opendbcopy.plugin.copy.CopyMappingPlugin“
paIh and class name oí Ihe Thread class implemenIing Ihe execute()
meIhod
description key íor resource properIy
!4/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
6.2.5 lnpuI / OuIpuI LlemenIs
The input and output elemenI are seI aI runIime. Do noI use Ihese elemenIs Io save coníiguraIion
input or output as Ihese elemenIs may be overwriIIen by PluginScheduler.
6.2.6 Source & DesIinaIion DaIabase LlemenIs
The íollowing elemenIs are íilled by reading daIabase meIadaIa and model(s). DaIabase MeIadaIa is
read when IesIing a daIabase connecIion. Models are read when a user clicks on CapIure Source
Model or CapIure DesIinaIion Model. lor more iníormaIion abouI Iypes, consIanIs and meIadaIa
available please see Ihe !ava APl, class java.sql.DatabaseMetaData.
ElemehI Name DescripIioh
driver
ConIains iníormaIion abouI Ihe driver used íor Ihe appropriaIe daIabase.
CurrenIly a drivers name and version are sIored as aIIribuIes.
metadata
ConIains íurIher subelemenIs:
db_product_name e.g. ,Oracle“, „PostgreSQL“
db_product_version daIabase producI version
catalog_separator separaIor beIween caIalog name and Iable
name oíIen Ihis is a doI (,.¨)
identifier_quote_string How are sIrings quoIed
catalog
lí available lisIs all caIalogs available as separaIe elemenIs
schema
lí available lisIs all schemas available as separaIe elemenIs
type_info
lisIs all available daIa Iypes speciíying:
type_name (e.g. ,VARCHAR2“)
locale_type_name (e.g. ,VARCHAR2“ normally Ihe same as
type_name or null)
data_type (e.g. ,12“ java.sql.Types ConsIanI)
precision (e.g. ,4000“)
literal_prefix (e.g. ,¨ preíix íor Ihis daIa Iype)
literal_suffix (e.g. ,¨ suííix íor Ihis daIa Iype)
nullable (,true“ or ,false“ is Ihis daIa Iype nullable)
case_sensitive (e.g. ,0“ or „1“ is Ihis daIa Iype case sensiIive)
connection
ConIains aIIribuIes íor:
driver_class (e.g. ,oracle.jdbc.driver.OracleDriver“)
url (e.g. ,jdbc:oracle:thin:@localhost:1521:test“)
username
password
catalog
CaIalog selecIed ií supporIed
schema
Schema selecIed ií supporIed
table_pattern
Table paIIern allows Io speciíy an SQL like paIIern Io use when capIuring Iable
meIadaIa, e.g. ,TA%“ only capIures Iables beginning wiIh TA íollowed by any
characIer or none. See !ava APl íor more deIails.
!5/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
ElemehI Name DescripIioh
model
When a model is capIured, Ihis elemenI conIains an aIIribuIe
capture_date. CapIure a daIabase model, save Ihe plugin as job and Ihen
have a look aI Ihe XML íile creaIed. The model hierarchy should be selí
explaining.
Model conIains children named table. A table elemenI can be oí Iype
TABLE or VIEW, idenIiíied by Ihe aIIribuIe table_type. An aIIribuIe
process (true or false) allows Io speciíy ií a Iable shall be processed or
noI.
Table conIains column elemenIs íor each column in Ihe underlying Iable /
view column. These column elemenIs conIain aIIribuIes such as name,
type_name, data_type, column_size, decimal_digits,
nullable and process. When primary, íoreign keys and indexes are
enabled, appropriaIe elemenIs are added Io Ihe table elemenI. The
aIIribuIes oí Ihe Ihese elemenIs are selí explaining, comparing Ihem wiIh Ihe
DaIabaseMeIaDaIa meIhods íor reading primary, imporIed and exporIed keys
as well as index iníormaIion.
6.2.7 Mapping LlemenI
This elemenI conIains iníormaIion Io map source Iables Io desIinaIion Iables. Same íor columns. This
elemenIs sIrucIure is likely Io be changed in a íuIure version Io allow more complex mapping and
merging rules Io be deíined.
6.2.8 lilIer LlemenIs
The sIrucIure oí Ihis elemenI is likely Io be changed in íuIure versions. CurrenIly iI conIains a sIring
elemenI íor each sIring íilIer implemenIed. A name aIIribuIe idenIiíies a sIring íilIer and a process
aIIribuIe true or false allow Io enable or disable appropriaIe sIring íilIer.
6.J Graphical User lnIeríaces
gui.xml conIains Ihe panels used Io speciíy and execuIe Ihis plugin.
The rooI elemenI gui musI conIain Iwo elemenIs. title and panels. Title musI conIain an
aIIribuIe value speciíying Ihe resource key íor Ihe plugins IiIle Io show wiIhin Ihe GUl oí openD8copy.
plugins can conIain children named panel íor Ihe individual panels íor Ihis plugin. The order oí
Ihese plugin elemenIs wiIhin Iheir plugins parenI elemenI speciíies Ihe order oí Ihe panels added
wiIhin Ihe Iab in Ihe GUl oí openD8copy, e.g. Ihe íirsI panel elemenI is Ihe íirsI GUl in Ihe wizard
creaIed eIc.
A panel elemenI musI conIain a class elemenI. LlemenI class musI conIain one aIIribuIe, name
oí Ihe Panel class Io load. The second aIIribuIe, register_as_observer (true or false) is noI
mandaIory, as described in previous chapIers.
The copy plugin uses 7 GUls Io coníigure, gaIher daIabase meIadaIa and íinally execuIe Ihe plugin. All
excepI PanelConfiguration and PanelExecute are regisIered as observers oí Ihe model.
PanelExecute iIselí conIains iIs own regisIraIion mechanism see code oí PanelExecute íor
deIails.
The íile looks like:
<gui identifier="copy" display_order="20" resource_name="plugin_opendbcopy_copy">
<title value="title.plugin.opendbcopy.copy" />
<panels>
<panel title="title.plugin.opendbcopy.copy.panel.0">
<class name="opendbcopy.gui.PanelConfiguration" />
</panel>
!6/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
<panel title="title.plugin.opendbcopy.copy.panel.1">
<class name="opendbcopy.gui.database.PanelConnection" register_as_observer="true" />
</panel>
<panel title="title.plugin.opendbcopy.copy.panel.2">
<class name="opendbcopy.gui.database.PanelModel" register_as_observer="true" />
</panel>
<panel title="title.plugin.opendbcopy.copy.panel.3">
<class name="opendbcopy.gui.database.dual.PanelMappingTable" register_as_observer="true" />
</panel>
<panel title="title.plugin.opendbcopy.copy.panel.4">
<class name="opendbcopy.gui.database.dual.PanelMappingColumn" register_as_observer="true" />
</panel>
<panel title="title.plugin.opendbcopy.copy.panel.5">
<class name="opendbcopy.gui.database.PanelFilter" register_as_observer="true" />
</panel>
<panel title="title.plugin.opendbcopy.copy.panel.6">
<class name="opendbcopy.gui.PanelExecute" />
</panel>
</panels>
</gui>
6.J.! GUl AIIribuIes
AIIribuIe Name DescripIioh
identifier
„copy“ a unique sIring idenIiíier musI be Ihe same as used wiIhin
plugin.xml
display_order „20“
Allows Io speciíy Ihe posiIion oí Ihis plugin wiIhin Ihe plugin menu selecIion.
When adding new plugins leave some space beIween numbers íor addiIions.
Have a look aI Ihe oIher display_order numbers oí oIher plugins.
resource_name „plugin_opendbcopy_copy“
The name oí Ihe resource íile name (language dependenI IexIs). NoIe IhaI Ihe
name speciíied musI noI conIain Ihe íile ending .properties and Ihe íile
iIselí musI be accessible wiIhin Ihe plugins classpaIh.
6.4 Plugin Thread
CopyMappingPlugin is Ihe Ihread class oí Ihe Copy Plugin, see opendbcopy.copy.
CopyMappingPlugin is Ihe only class required Io copy daIa írom a source inIo a desIinaIion
daIabase, independenI oí underlying daIabase managemenI sysIem. Thereíore Ihe deployed jar íile
currenIly only conIains Ihis one class íile, CopyMappingPlugin. Pesource properIies íiles are added
Io Ihis jar íile Ioo inIo Ihe jar archives rooI. lor simpler debugging oí Ihis plugin Ihe source code is
also added Io Ihe jar íile. See Ihe anI jar target íor deIails.
The source code oí Ihe class CopyMappingPlugin is as íollows:
/*
* Copyright (C) 2004 Anthony Smith
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* ----------------------------------------------------------------------------
* TITLE $Id: CopyMappingPlugin.java,v 1.2 2004/04/08 11:21:05 iloveopensource Exp $
* ---------------------------------------------------------------------------
*
* --------------------------------------------------------------------------*/
package opendbcopy.plugin.copy;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
!7/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import opendbcopy.config.XMLTags;
import opendbcopy.connection.DBConnection;
import opendbcopy.connection.exception.CloseConnectionException;
import opendbcopy.controller.MainController;
import opendbcopy.filter.StringConverter;
import opendbcopy.plugin.model.DynamicPluginThread;
import opendbcopy.plugin.model.Model;
import opendbcopy.plugin.model.database.DatabaseModel;
import opendbcopy.plugin.model.exception.PluginException;
import opendbcopy.sql.Helper;
import opendbcopy.util.InputOutputHelper;
import org.jdom.Element;
/**
* Copies records of selected source tables and columns into selected destination tables. If the underlying
* RDBMS supports Referential Integrity Constraints, the order of tables to process is respected. If possible
* errors shall be logged, those are logged into comma separated value files.
*
* @author Anthony Smith
* @version $Revision: 1.2 $
*/
public class CopyMappingPlugin extends DynamicPluginThread {
private static final String fileType = "csv";
private DatabaseModel model; // this plugin's model
private Connection connSource;
private Connection connDestination;
private Statement stmSource;
private PreparedStatement pstmtDestination;
private ResultSet rs;
private StringBuffer recordBuffer; // to hold records contents
private StringBuffer recordErrorBuffer; // in case of errors records are written to file
private String stmSelect = "";
private String stmInsert = "";
private String sourceTableName = "";
private String destinationTableName = "";
private String newLine = "";
private File outputPath = null;
private String fileName = "";
private String delimiter = "";
private boolean log_error = false;
private boolean errorLogSetup = false;
private int counterRecords = 0;
private int counterTables = 0;
private List processColumns;
private List processTables;
boolean trimString = false;
boolean trimAndRemoveMultipleIntermediateWhitespaces = false;
boolean trimAndReturnNullWhenEmpty = false;
/**
* Creates a new CopyMappingPlugin object.
*
* @param controller DOCUMENT ME!
* @param baseModel DOCUMENT ME!
*
* @throws PluginException DOCUMENT ME!
*/
public CopyMappingPlugin(MainController controller,
Model baseModel) throws PluginException {
// Call the super constructor
super(controller, baseModel);

// cast the super base model into a specific database model
this.model = (DatabaseModel) baseModel;
}
/**
* Read configuration and setup database connections
*
* @throws PluginException DOCUMENT ME!
*/
protected final void setUp() throws PluginException {
// set the new line character as this differs from OS to OS
newLine = MainController.lineSep;
// get the plugin configuration
Element conf = model.getConf();
if (conf == null) {
throw new PluginException("Missing conf element");
}
try {
// set the output path selected by user
outputPath = new File(conf.getChild(XMLTags.DIR).getAttributeValue(XMLTags.VALUE));
// create the output directory if it does not yet exist
if (!outputPath.exists()) {
boolean mkDirOk = outputPath.mkdir();
!8/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
if (!mkDirOk) {
throw new PluginException("Could not create " + outputPath.getAbsolutePath());
}
}
// shall errors be logged?
log_error = Boolean.valueOf(conf.getChild(XMLTags.LOG_ERROR).getAttributeValue
(XMLTags.VALUE)).booleanValue();
if (log_error) {
recordBuffer = new StringBuffer();
recordErrorBuffer = new StringBuffer();
}
// check string filters
if (model.getStringFilterTrim().getAttributeValue(XMLTags.PROCESS).compareTo("true") == 0) {
trimString = true;
}
if (model.getStringFilterRemoveIntermediateWhitespaces().getAttributeValue(XMLTags.PROCESS).compareTo("true")
== 0) {
trimAndRemoveMultipleIntermediateWhitespaces = true;
}
if (model.getStringFilterSetNull().getAttributeValue(XMLTags.PROCESS).compareTo("true") == 0) {
trimAndReturnNullWhenEmpty = true;
}
// get connections
connSource = DBConnection.getConnection(model.getSourceConnection());
connDestination = DBConnection.getConnection(model.getDestinationConnection());
// extract the tables to copy
processTables = model.getDestinationTablesToProcessOrdered();
} catch (Exception e) {
throw new PluginException(e);
}
// now set the number of tables that need to be copied
model.setLengthProgressTable(processTables.size());
}
/**
* Copies records of selected source tables and columns into selected destination tables.
* If requested and occuring, errors are logged
*
* @throws PluginException DOCUMENT ME!
*/
public final void execute() throws PluginException {
Iterator itColumns;
Element tableProcess;
Element columnDestination;
int colCounter;
Object input;
try {
stmSource = connSource.createStatement();
Iterator itProcessTables = processTables.iterator();

ArrayList generatedFiles = new ArrayList();
while (!isInterrupted() && itProcessTables.hasNext()) {
tableProcess = (Element) itProcessTables.next();
sourceTableName = tableProcess.getAttributeValue(XMLTags.SOURCE_DB);
destinationTableName = tableProcess.getAttributeValue(XMLTags.DESTINATION_DB);
// file name for error logs
if (log_error) {
fileName = destinationTableName + "_ERRORS" + "." + fileType;
}
// get the columns to process
processColumns = model.getMappingColumnsToProcessByDestinationTable(destinationTableName);
// setting record counter to minimum of progress bar
model.setCurrentProgressRecord(0);
model.setLengthProgressRecord(0);
// Reading number of records for progress bar
model.setLengthProgressRecord(Helper.getNumberOfRecordsFiltered(stmSource, model, XMLTags.SOURCE_DB,
sourceTableName));
// get Select Statement for source model
stmSelect = Helper.getSelectStatement(model, sourceTableName, XMLTags.SOURCE_DB, processColumns);
// get Insert Statement for destination model
stmInsert = Helper.getInsertPreparedStatement(model.getQualifiedDestinationTableName
(destinationTableName), processColumns);
pstmtDestination = connDestination.prepareStatement(stmInsert);
model.setCurrentProgressTable(counterTables);
// Execute SELECT
!9/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
rs = stmSource.executeQuery(stmSelect);
// do some logging
model.setProgressMessage("Copying " + model.getQualifiedSourceTableName(sourceTableName) + " into " +
model.getQualifiedDestinationTableName(destinationTableName) + " ...");
logger.info("Copying " + model.getQualifiedSourceTableName(sourceTableName) + " into " +
model.getQualifiedDestinationTableName(destinationTableName) + " ...");
// while there are more records to process and the process is not interrupted by the user
while (!isInterrupted() && rs.next()) {
colCounter = 1;
// process columns
itColumns = processColumns.iterator();
while (itColumns.hasNext()) {
columnDestination = model.getDestinationColumn(destinationTableName, ((Element)
itColumns.next()).getAttributeValue(XMLTags.DESTINATION_DB));
input = rs.getObject(colCounter);
if (input != null) {
input = applyStringFilters(input, Boolean.valueOf(columnDestination.getAttributeValue
(XMLTags.NULLABLE)).booleanValue());
if (input != null) {
if (log_error) {
recordBuffer.append(input + delimiter);
}
pstmtDestination.setObject(colCounter, input);
} else {
if (log_error) {
recordBuffer.append("null" + delimiter);
}
pstmtDestination.setNull(colCounter, Integer.parseInt(columnDestination.getAttributeValue
(XMLTags.DATA_TYPE)));
}
} else {
if (log_error) {
recordBuffer.append("null" + delimiter);
}
pstmtDestination.setNull(colCounter, Integer.parseInt(columnDestination.getAttributeValue
(XMLTags.DATA_TYPE)));
}
colCounter++;
}
// execute the prepared statement and log the error ... and continue without disturbing other
business
try {
// Execute INSERT
pstmtDestination.executeUpdate();
pstmtDestination.clearParameters();
counterRecords++;
model.setCurrentProgressRecord(counterRecords);
} catch (SQLException e) {
connDestination.rollback();
if (log_error && !errorLogSetup) {
initErrorLog(processColumns);
}
if (log_error) {
recordErrorBuffer.append(recordBuffer + e.toString() + newLine);
}
} finally {
// reset recordBuffer
if (log_error) {
recordBuffer = new StringBuffer();
}
}
}
if (!isInterrupted()) {
// commit INSERTs. Commit behaviour depends on RDBMS used
connDestination.commit();

// close the result set
rs.close();
logger.info(counterRecords + " records inserted into table " + destinationTableName);
counterRecords = 0;
// required in case of last table that had to be copied
counterTables++;
model.setCurrentProgressTable(counterTables);
// set processed
tableProcess.setAttribute(XMLTags.PROCESSED, "true");
} else {
// rollback insert in case the user interrupts the process
connDestination.rollback();
20/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!

// close the result set
rs.close();
counterRecords = 0;
}
if (log_error) {
if (recordErrorBuffer.length() > 0) {
// open file writer
File errorFile = new File(outputPath.getAbsolutePath() + MainController.fileSep +
fileName);
OutputStreamWriter fileWriter = new OutputStreamWriter(new FileOutputStream(errorFile),
MainController.getEncoding());
fileWriter.write(recordErrorBuffer.toString());
fileWriter.close();
generatedFiles.add(errorFile);
logger.error(errorFile + " contains records which could not be processed");
recordErrorBuffer = new StringBuffer();
errorLogSetup = false;
}
}
}
stmSource.close();
pstmtDestination.close();
// close database connections
DBConnection.closeConnection(connSource);
DBConnection.closeConnection(connDestination);
if (!isInterrupted()) {
if (generatedFiles != null && generatedFiles.size() > 0) {
File[] outputFiles = new File[generatedFiles.size()];
outputFiles = (File[]) generatedFiles.toArray(outputFiles);
Element outputConf = model.getConf().getChild(XMLTags.OUTPUT);
model.appendToOutput(InputOutputHelper.createFileListElement(outputFiles, outputConf.getChild
(XMLTags.FILELIST).getAttributeValue(XMLTags.VALUE)));
}
logger.info(counterTables + " table(s) processed");
}
} catch (SQLException sqle) {
throw new PluginException(sqle);
} catch (Exception e1) {
// clean up if required
try {
DBConnection.closeConnection(connSource);
DBConnection.closeConnection(connDestination);
} catch (CloseConnectionException e2) {
// bad luck ... don't worry
}
throw new PluginException(e1);
}
}
/**
* If global string filters were selected by user, those are applied using this method
*
* @param in DOCUMENT ME!
* @param returnNullWhenEmpty DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private Object applyStringFilters(Object in,
boolean returnNullWhenEmpty) {
if (in instanceof String || in instanceof Character) {
if (trimAndRemoveMultipleIntermediateWhitespaces && trimAndReturnNullWhenEmpty) {
return StringConverter.trimAndRemoveMultipleIntermediateWhitespaces(in, returnNullWhenEmpty);
} else if (trimAndRemoveMultipleIntermediateWhitespaces && !trimAndReturnNullWhenEmpty) {
return StringConverter.trimAndRemoveMultipleIntermediateWhitespaces(in, false);
} else if (trimString && trimAndReturnNullWhenEmpty) {
return StringConverter.trimString(in, returnNullWhenEmpty);
} else if (trimString && !trimAndReturnNullWhenEmpty) {
return StringConverter.trimString(in, false);
} else {
return in;
}
} else {
return in;
}
}
/**
* Called to write a nice row header of column names in possible error logs
*
* @param processColumns DOCUMENT ME!
*/
private void initErrorLog(List processColumns) {
Iterator itColumns = processColumns.iterator();
// set the column headings for the possible error log
while (itColumns.hasNext()) {
recordErrorBuffer.append(((Element) itColumns.next()).getAttributeValue(XMLTags.DESTINATION_DB) + delimiter);
2!/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
}
recordErrorBuffer.append("ERROR" + newLine);
errorLogSetup = true;
}
}
6.5 Language Pesource liles
The copy plugin provides resource íiles íor Lnglish and German.
The source properIies íiles are sIored under resource/bundle.
The Lnglish properIies íile is named plugin_opendbcopy_copy.properties. The German
version is named plugin_opendbcopy_copy_de.properties. The exIension de is
according Io Ihe !ava Locale speciíicaIion.
The Lnglish version looks as íollows:
title.plugin.opendbcopy.copy=Copy data from a source into a destination database
title.plugin.opendbcopy.copy.panel.0=0. Plugin Configuration
title.plugin.opendbcopy.copy.panel.1=1. Database Connections
title.plugin.opendbcopy.copy.panel.2=2. Models
title.plugin.opendbcopy.copy.panel.3=3. Table Mapping
title.plugin.opendbcopy.copy.panel.4=4. Column Mapping
title.plugin.opendbcopy.copy.panel.5=5. Global String Filters
title.plugin.opendbcopy.copy.panel.6=6. Execute Plugin
plugin.opendbcopy.copy.conf.outputDirErrorLogs=Output dir for error logs
plugin.opendbcopy.copy.conf.logError=Log errors into comma separated files (csv) including
error message
plugin.opendbcopy.copy.conf.appendFileAfterRecords=After how many records shall disk I/O
occur? Depends on available memory and table width
plugin.opendbcopy.copy.conf.output.filelistIdentifier=Filelist identifier for error logs
Please noIe IhaI Ihe IiIle íor Ihe panels in a Iab musI be speciíied íor each plugin as Ihe meaning oí
Ihe same GUl may vary, depending on Ihe plugin used.
22/2J
Puzzle lTC GmbH
openD8copy Developer Manual Pelease 0.5!
7 8uildihg, 1esIihg ahd Deployihg Plugihs
OpenD8copy and plugins are compiled and deployed using Apache AnI.
To IesI your plugin(s) your require an openD8copy Core lramework environmenI. The mosI
comíorIable soluIion is Io have openD8copy Core lramework and Plugin ProjecI(s) open and linked
wiIhin Ihe same !ava lDL. CurrenIly Ihere are no !UniI IesI classes implemenIed Io IesI openD8copy
Core lramework nor Plugins.
Lach plugin provides a build.xml and build.properties íile. The laIIer conIains plugin speciíic
deIails such as plugin name eIc. MosI plugins are released using an idenIical copy oí build.xml as
oIher plugins.
Thereíore when sIarIing a new plugin projecI, Ihe simplesI way Io seIup your environmenI is Io copy
an exisIing plugin projecI inIo a new direcIory and modiíy Ihe new build.properIies íile. This íile
conIains a hardcoded reíerence Io your openD8copy projecI locaIion. You musI modiíy Ihis
parameIer, nexI Io plugin idenIiíier, auIhor name eIc.
The deíaulI build IargeI is deploy. See Ihe build.xml íile and Apache AnI User Manual íor íurIher
deIails.
2J/2J
Puzzle lTC GmbH