- Implement server actions
- Implement automated processes
- Implement import/export/synchronization interfaces
Frequently XSLT based solutions are appropriate or even more appropriate than Java development (not covered here).
Development setup
- Use release distribution or git (export) distribution
- When using git distribution, perform
bin/build.sh init jar
to generate classes and jars - Open project in Eclipse or setup IntelliJ (or use vi…)
- Possible to start server within Eclipse but not recommended
- Start server locally (does run on macOS and Windows), needs Oracle
- Use Remote Java Application Debug setup in Eclipse (or IntelliJ)
In launcher.xml
enable remote debugging:
|
Note: Performance/Memory profiler like YourKit highly recommended!
|
Modules
- Are in the following directories:
- censhare-product/censhare-Server/app/modules directory (default)
- censhare-product/censhare-Custom/censhare-Server/app/modules (custom)
- Consist of:
- XML description file (“command-xml”)
- Java (source) code
- Java properties files for localization
- Hot deployable, Java source code is compiled and loaded:
- Use UI admin client to “refresh” or
- Use shell admin client
bin/AdminClient.sh -b refresh
Persistence Architecture
- Relational database has tables
- In Java need „objects“ and/or XML
- Like to have Plain Old Java Object (POJO)
- Use as data transfer object (DTO)
- Serializable
- Should support changes / transactions
- Like to have XML
Class stack:
- AXml (abstract base class)
- XML node (we are not using org.w3c.dom)
- CXml / BXml implementation
- CXml is object instance based
- BXml is byte[] based (CDB, online channel)
- DXml adds change tracking / transactions
- DataObject adds (database) persistence
- AssetBase (automatically generated from db-schema)
- Asset (additional methods)
Memory demand for a 1,9 MB XML file
- When setting the asset name using the setName method, the corresponding XML node attribute gets updated:
|
|
- How to know what to tell the database?
- Database wants insert / update / delete
- In transactional „mode“ DXml intercepts and notes the changes.
- corpus:dto_flags
new
- must insertdelete
- should deletemodified
- must updatetransactional
- is in transactional modepersistent
- is in database already
|
- How to set the transactional mode?
- You can do this manually (see below)
- But typically the persistence manager does that for you
|
|
Typical pattern:
|
|
Note: tm and pm have a one-to-one relationship („separation of concerns“…)
|
tm.begin
- Starts a new transaction
- Marks objects in pm as transactional
|
pm.makePersistent
- Creates primary keys
- Attaches object to pm (put’s it into pm)
|
tm.end
- Performs SQL statements but no commit
- Marks objects in pm as non-transactional
tm.commit
additionally does SQL commit and issues eventstm.commit
is done automatically on command completion- Objects stay in pm!
Common mistakes
- pm is like a bag that keeps all objects
- Some APIs attach (insert) assets to the pm, others don‘t. (E.g.:
AssetCacheService cacheGetAsset
vs.cacheGetAssetNoAttach
) - For bulk changes you need to manage that manually to avoid an
OutOfMemoryException
(E.g. calltm.end
andpm.reset
) - New assets don‘t have
new-val
Missing or too frequent am.update.
|
The persistence layer does write the change in the database. But:
- doesn’t know how to handle files added to an asset
- doesn’t create asset events that notify the clients
- cannot perform checkout / checkin
- doesn’t update versioned
asset_relation
/asset_element_relation
table
Cannot perform checkout / checkin in one step, must use
tm.begin
/tm.end
- Events are posted with
tm.commit()
, don’t commit every single change! - To avoid deadlocks if working with multiple assets in one transaction the assets must be processed in ascending asset id order !!! (E.g. use TreeSet / TreeMap to collect assets first)
|
- Use bulk operations for performance:
- to get 10 assets using
cacheGetAsset(DBTransactionManager tm, AssetCacheKey key)
: costs 10 x about 12 sql statements - if not using CDB - to get 10 assets using
cacheGetAsset(DBTransactionManager tm, AssetCacheKey[] keys)
: costs about 12 sql statements - if not using CDB
- to get 10 assets using
- If transaction is “dirty” – first SQL insert/update statement executed – CDB no longer used to allow for read after write
Notes on CDB
- Stores current asset versions
- Almost all queries for current versions are handled through it (if transaction not dirty)
- All returned assets are checked to be „up to date“ using the ccn with a fallback to Oracle (use
queryAssetsLazy
if not required) asset.ccn
is a change control number- tcn incremented with each update
- to allow for change detection without locking assets and updating their tcn (e.g. new asset relation)
|
Asset API
- Hidden in
asset.struct()
to avoid messy code completion suggestions
|
Query API
- Common API for embedded DB and Oracle
- Compatibility for legacy implementations
- XPath queries
Query Builder
- Fluent interface for creating queries - with types (refactoring!)
- Works together with schema created classes
- Works stand alone!
|
Asset Query Service
|
AssetAutomation
- AssetAutomation allows combined code for server actions and automated processes
- See
modules.lib.asset_automation.AssetAutomationSample
- All “AAxxx” modules are implemented that way