Plugin: Keikai Spreadsheet Enterprise Component
From iDempiere en
- Creator: James Chu
- SPONSOR: zkoss.org
- iDempiere version: 13
- License: The plugin source code is licensed under the GNU GPLv2 or later and contains no Keikai or ZK binaries. See Licensing for what that means in practice.
- Source: GitHub repository
- Related: Plugin: ZK Enterprise Components – the same fragment pattern, and the repository this one was generated from.
Description
- This plugin makes Keikai Spreadsheet Enterprise – an Excel-compatible spreadsheet component – available inside iDempiere as an optional OSGi add-on, without modifying iDempiere core.
- It follows the OSGi fragment + plugin pattern: the fragment attaches the Keikai runtime jars to iDempiere's ZK host bundle so ZK can discover the Keikai components, resources and exporters; the example plugin is an ordinary iDempiere form that uses them.
- Install and uninstall it like any other iDempiere OSGi plugin. Nothing in the iDempiere repository or in the application dictionary is changed.
- Keikai EE requires a commercial license or subscription from ZK; see Licensing. The build here uses Evaluation artifacts so the plugin can be tried at no cost.
What you get
- A full spreadsheet inside an iDempiere form: cell editing, formulas, a toolbar, a formula bar and a context menu, loading and saving real
.xlsxworkbooks. - Export to PDF natively, through Keikai's own PDF exporter – registered by the fragment, not by your form.
- The point of interest for implementors is that this is a genuine ZK component in a normal
CustomForm, so a workbook can be driven from iDempiere data like any other UI.
Requirements
| Item | Version |
|---|---|
| iDempiere | 13 |
| Java runtime | 17 |
| ZK CE bundled with iDempiere | 10.0.1 |
| Keikai EE | 6.3.0-Eval
|
- Keikai is not a single-jar add-on. The fragment carries the base runtime plus several feature and support modules, and they must be kept in step with each other – see Components.
Components
| Bundle | Kind | Purpose |
|---|---|---|
org.idempiere.keikai.fragment |
OSGi fragment | Attaches the Keikai runtime to the class loader of org.adempiere.ui.zk, and carries the Keikai-specific zk.xml. Required.
|
org.idempiere.keikai.example |
Plugin | An example form rendering a Keikai spreadsheet, with New Book, Save Book and Export PDF wired up. Optional. |
What the fragment carries
- Twenty-eight jars, in five groups. A fragment has no dependency resolution of its own – whatever the runtime needs must be listed in
Bundle-ClassPathand present underlib/, transitive dependencies included.
| Group | Jars | Why |
|---|---|---|
| Keikai runtime | keikai, keikai-model |
The spreadsheet component and its workbook model |
| Keikai EE features | keikai-ex |
Required: the base jar marks some toolbar actions, Save Book among them, as EE-only |
| Workbook file I/O | poi (io.keikai:poi – Keikai's own build of Apache POI, versioned with Keikai), poi-ooxml, poi-ooxml-lite, poi-ooxml-full, xmlbeans, curvesapi, commons-compress, commons-codec, commons-collections4, SparseBitSet |
Reading and writing real .xlsx files
|
| Charts in a workbook | zkcharts, jfreechart, jcommon |
Rendering charts that live inside a spreadsheet |
| PDF export | keikai-pdf, openpdf |
The native PDF exporter, so Exporters.getExporter("pdf") resolves
|
| ZK PE components | zkex |
Keikai's UI is built on the ZK PE component set |
| Other transitive dependencies | commons-io, commons-math3, filters, failureaccess, jsoup, rtree2, log4j-api, byte-buddy, byte-buddy-agent |
Pulled in by the jars above; the fragment must carry them because OSGi resolves nothing from Maven at runtime |
- The fragment's
src/metainfo/zk/zk.xmlsets two ZK library properties:io.keikaiex.model.default.ExporterFactory.class = pdf=io.keikai.model.impl.pdf.PdfExporterFactory– registers the PDF exporter.org.zkoss.zkmax.au.IWBS.disable = true– required for iDempiere 13, whose login flow echoes events to an initially invisible window.
Why a fragment is needed
- ZK discovers its components through
metainfo/zk/lang-addon.xml, which is loaded with the class loader of the bundle ZK runs in – in iDempiere that isorg.adempiere.ui.zk. - OSGi bundles have isolated class loaders, and a fragment is the only standard way to add resources to another bundle's class loader without modifying it.
- That is why the Keikai jars are delivered as a fragment of
org.adempiere.ui.zkrather than embedded in a plugin.
Installation
- Obtain the two jars – see Building from source.
- The order matters – a fragment only takes effect after its host bundle is re-resolved, which means a restart:
- Install
org.idempiere.keikai.fragmentthrough the Apache Felix Web Console (/osgi/system/console/bundles), or drop it into the runtime's plugin directory. - Restart the iDempiere web application or OSGi runtime. This is not optional: besides re-resolving the host, ZK reads the fragment's
zk.xmllibrary properties during web application initialization, so hot-swapping only the example bundle will not pick up the PDF exporter registration. - Install
org.idempiere.keikai.exampleif you want the example form. - On the Bundles page, confirm the fragment shows as Fragment of
org.adempiere.ui.zkand the example plugin as Active – not merely Resolved. - Log out and back in, so the menu tree is rebuilt with the entry the plugin adds.
- Install
- The example plugin registers its menu entry through a 2Pack applied by its bundle activator; no manual import is required.
- If you also run another ZK fragment – Plugin: ZK Enterprise Components or Plugin: ZK Charts Components – note that this fragment already carries its own
zkexandzkcharts, and at different versions:zkchartshere is12.2.0.0-Eval, while the ZK Charts fragment ships12.5.0.0-Eval. Two fragments contributing the same jar to the same host, at two versions, is a resolution problem waiting to happen. Align the versions, or install only the fragment that covers what you need.
Usage
Verifying the installation
- Open Keikai Spreadsheet Example from the menu. The sample workbook (
blank.xlsx) should render with a toolbar, a formula bar and a working context menu.
| Check | What it proves |
|---|---|
| The spreadsheet grid renders at all | The fragment resolved and ZK discovered Keikai's lang-addon.xml through the host
|
| Cells accept typing and formulas | The Keikai runtime and workbook model are live, not just the widget |
Save Book downloads an .xlsx |
keikai-ex is present – this action is EE-only and is absent without it
|
| Export PDF downloads a PDF | keikai-pdf resolved and the fragment's zk.xml was read. If this fails while everything else works, the runtime was not restarted
|
Using Keikai in your own plugin
- In ZUL, the component needs nothing declared. Once the fragment is installed,
<spreadsheet>is part of the ZUL language for every page in the runtime:
<?xml version="1.0" encoding="UTF-8"?>
<zk>
<div hflex="1" vflex="1">
<spreadsheet id="spreadsheet" hflex="1" vflex="1" src="web/blank.xlsx"
showToolbar="true" showFormulabar="true" showContextMenu="true"
maxVisibleRows="100" maxVisibleColumns="40"/>
</div>
</zk>
- The workbook path is not a ZK resource path. Use
src="web/blank.xlsx", not~./blank.xlsx– Keikai resolvesSpreadsheet.setSrc()through its own workbook loader, which is a different mechanism from ZK's component-creation path. The ZUL itself is still loaded the normal way, withExecutions.createComponents("~./keikai-form.zul", ...). - Swap the context class loader around that call. ZK resolves
~./resources through the thread context class loader; without the swap it looks inorg.adempiere.ui.zkinstead of your bundle and fails to find the ZUL. Restore it infinally. - In Java, the fragment exports nothing.
org.idempiere.keikai.fragmentdeclares noExport-Package, so Keikai classes sit on the host's class loader but are not visible to your bundle at compile or resolve time. There are two ways forward:- Add an
Export-Packagefor the Keikai packages you need to the fragment's manifest and rebuild it – the approach the ZK Charts fragment takes. - Reach the classes reflectively through the component's own class loader – what the example form does, so that it needs no manifest change:
- Add an
Component spreadsheet = form.getFellow("spreadsheet");
ClassLoader keikaiCl = spreadsheet.getClass().getClassLoader();
Class<?> exporters = Class.forName("io.keikai.api.Exporters", true, keikaiCl);
Object exporter = exporters.getMethod("getExporter", String.class).invoke(null, "pdf");
- Reflection keeps the fragment untouched but gives up compile-time checking; exporting packages is cleaner if you are building a real form rather than a demo. Pick one deliberately.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Bundle stays Resolved or Installed, never Active | The fragment is missing, or the runtime was not restarted after installing it | Install the fragment, then restart |
| The fragment itself stays Resolved | Expected – fragments never become Active | No action needed; confirm it is listed as a fragment of org.adempiere.ui.zk
|
| Everything works except Export PDF | The fragment's zk.xml was not read; ZK loads library properties at web application initialization |
Restart the web application, not just the bundle |
| Save Book is greyed out or missing | keikai-ex is not in the fragment – the base jar marks this action EE-only |
Check Bundle-ClassPath and that lib/keikai-ex.jar exists in the built fragment
|
| The spreadsheet renders but the workbook is empty | src was written as ~./blank.xlsx |
Use the workbook-loader form, src="web/blank.xlsx"
|
Page not found: ~./keikai-form.zul |
The context class loader was not swapped before Executions.createComponents |
Swap to the plugin's class loader, restore in finally
|
A jar in Bundle-ClassPath has no file under lib/ |
The jar list drifted between pom.xml and MANIFEST.MF |
Re-align the two; see Building from source |
NoClassDefFoundError for a third-party class after a version bump |
A new transitive dependency was not added to the fragment – OSGi will not fetch it from Maven at runtime | Add the jar to both pom.xml and Bundle-ClassPath
|
Licensing
- The plugin source is GPLv2 or later and contains no Keikai or ZK binaries. Nothing in the iDempiere repository is modified.
- Keikai EE is a commercial product and is not covered by the plugin's open-source license. The build pulls the jars from ZK's Evaluation repository, so everything on this page can be tried at no cost; a valid license or subscription must be obtained separately before production use.
- What uninstalling gives back. Removing the fragment leaves iDempiere core exactly as it was – there is nothing to migrate back. Be aware, though, that any form you wrote against the spreadsheet component stops working when the fragment goes, so plan that boundary deliberately.
- To obtain a license or ask about terms, contact the ZK Framework team at [email protected] or see the Keikai product site.
Building from source
- Requires Git, Maven, JDK 17 and a local p2 repository built from iDempiere core.
git clone --branch release-13 https://github.com/idempiere/idempiere.git idempiere
cd idempiere && mvn clean install
git clone https://github.com/zkoss-demo/zkoss-idempiere-keikai-plugin.git
cd zkoss-idempiere-keikai-plugin
mvn clean verify -f parent-repository-pom.xml
- The first build must have network access: the Keikai jars come from the ZK Evaluation repository, not from Maven Central.
- Keep the jar list synchronized. Because Keikai is a multi-jar product with real transitive dependencies, adding or upgrading a module means touching:
org.idempiere.keikai.fragment/pom.xml– the dependency-copy artifacts, which populatelib/during thevalidatephaseorg.idempiere.keikai.fragment/META-INF/MANIFEST.MF–Bundle-ClassPath, one entry per jarorg.idempiere.keikai.fragment/src/metainfo/zk/zk.xml– only if the module needs a ZK library property, askeikai-pdfdoes
build.propertiespackages the wholelib/directory, so it needs no per-jar edit – but that also means a jar left behind by an earlier build is packaged silently even when nothing references it. Cleanlib/when changing versions.- After building, verify that every jar named in
Bundle-ClassPathactually exists underlib/:
cd org.idempiere.keikai.fragment
find lib -maxdepth 1 -type f -name '*.jar' -exec basename {} \; | sort
grep -o 'lib/[^ ,]*\.jar' META-INF/MANIFEST.MF build.properties
Feedback
- If you would like to discuss specific use cases or workflows for this plugin, we’d be happy to hear from you. Please feel free to contact the ZK Framework team at [email protected].
- If you want to provide additional comments, please use:
- General support forum: iDempiere Community
- Issues for this plugin: GitHub Issues
See also
- Other ZK plugins for iDempiere:
- Plugin development:
- Keikai · Keikai live demo
