Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 170 additions & 0 deletions MODULE_SYSTEM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# Java Module System (JPMS) for ODF Toolkit

## Overview

The ODF Toolkit has been extended with Java Module System (JPMS) support. All artifacts (JARs and WARs) are now configured as Java modules.

## Modules

### 1. `org.odftoolkit.odfdom`

The main module for ODFDOM - the core API for ODF documents.

**Exported Packages:**
- `org.odftoolkit.odfdom` - Core API
- `org.odftoolkit.odfdom.doc.*` - Document Layer (high-level API)
- `org.odftoolkit.odfdom.pkg.*` - Package Layer
- `org.odftoolkit.odfdom.type` - Data types
- `org.odftoolkit.odfdom.changes` - Collaboration API
- `org.odftoolkit.odfdom.dom.*` - DOM Layer (for advanced users)

**Not Exported:**
- `org.odftoolkit.odfdom.incubator.*` - Experimental APIs (explicitly marked as "Incubator Status")

### 2. `org.odftoolkit.odfvalidator`

The Validator module for ODF validation.

**Exported Packages:**
- `org.odftoolkit.odfvalidator` - Validator API

**Dependencies:**
- `org.odftoolkit.odfdom` - Requires ODFDOM

### 3. `org.odftoolkit.odfxsltrunner`

The XSLT Runner module for XSLT transformations in ODF documents.

**Exported Packages:**
- `org.odftoolkit.odfxsltrunner` - XSLT Runner API

**Dependencies:**
- `org.odftoolkit.odfdom` - Requires ODFDOM

## Usage

### As Modules (Java 9+)

```java
module com.example.myapp {
requires org.odftoolkit.odfdom;
requires org.odftoolkit.odfvalidator; // optional
requires org.odftoolkit.odfxsltrunner; // optional
}
```

### On the Module Path

```bash
java --module-path lib/odfdom-java-0.14.0.jar \
--module org.odftoolkit.odfdom
```

### On the Classpath (Backward Compatibility)

The modules continue to work on the classpath for Java 8+ applications:

```bash
java -cp lib/odfdom-java-0.14.0.jar:lib/other.jar MyApp
```

## Validation

### Automatic Validation

Run the validation script:

**Linux/macOS:**
```bash
chmod +x src/site/validate-modules.sh
./src/site/validate-modules.sh
```

**Windows:**
```cmd
src\site\validate-modules.bat
```

### Manual Validation

#### 1. Check Compilation
```bash
mvn clean compile
```

#### 2. Analyze Module Dependencies
```bash
jdeps --module-path odfdom/target/classes \
--add-modules org.odftoolkit.odfdom \
--list-deps \
odfdom/target/odfdom-java-*.jar
```

#### 3. Generate Module Graph
```bash
jdeps --module-path odfdom/target/classes \
--dot-output module-graph.dot \
odfdom/target/odfdom-java-*.jar

# Visualize with Graphviz
dot -Tpng module-graph.dot -o module-graph.png
```

#### 4. Check JAR Contents
```bash
jar tf odfdom/target/odfdom-java-*.jar | grep module-info
```

## Known Issues and Solutions

### Automatic Modules

Many dependencies do not yet have a `module-info.java` and are treated as "automatic modules". Module names are derived from JAR file names:

- `xercesImpl-2.12.2.jar` → `xerces.impl`
- `commons-validator-1.10.1.jar` → `commons.validator`
- `jena-core-5.6.0.jar` → `org.apache.jena.core`

### Reflection Access

If frameworks need to access internal classes via reflection, corresponding `opens` directives have been added:

```java
opens org.odftoolkit.odfdom.pkg.rdfa to org.apache.jena.core;
```

### WAR Deployment

The Validator is provided as a WAR file. Modern servlet containers (Tomcat 10+, Jetty 11+) support modules in WARs. For older containers, classpath mode continues to work.

## Migration from Existing Code

### Before (Classpath)
```java
import org.odftoolkit.odfdom.doc.OdfTextDocument;
// ...
```

### After (Module Path)
```java
module myapp {
requires org.odftoolkit.odfdom;
}

import org.odftoolkit.odfdom.doc.OdfTextDocument;
// ... (code remains the same!)
```

**Important:** The code itself does not need to be changed! Only the `module-info.java` needs to be added.

## Additional Information

- [Java Platform Module System (JEP 261)](https://openjdk.java.net/projects/jigsaw/spec/)
- [The State of the Module System](https://openjdk.java.net/projects/jigsaw/spec/sotms/)
- [Maven Guide to Java Modules](https://maven.apache.org/guides/mini/guide-multiple-modules.html)

## Support

For questions or issues:
- GitHub Issues: https://github.com/tdf/odftoolkit/issues
- Mailing List: dev@odftoolkit.org
15 changes: 15 additions & 0 deletions odfdom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@
<excludes>
<exclude>${project.basedir}/target/odf/generation/**/*.java</exclude>
</excludes>
<!-- Note: Warning about jena-core-tests.jar module conflict is harmless.
Maven automatically handles this by keeping only the main jena-core on module path.
Test classes are still available on the classpath. -->
</configuration>
</plugin>
<plugin>
Expand Down Expand Up @@ -207,6 +210,10 @@
<excludes>
<exclude>**/integrationtest/PerformanceIT.java</exclude>
</excludes>
<!-- Disable module path for tests to avoid conflict with jena-core-tests.jar -->
<!-- The jena-core-tests JAR defines the same module as jena-core, causing conflicts -->
<!-- Test classes are available on the classpath, so module path is not required for tests -->
<useModulePath>false</useModulePath>
</configuration>
</plugin>
<plugin>
Expand Down Expand Up @@ -322,6 +329,10 @@
<odfdom.version>${project.version}</odfdom.version>
<org.odftoolkit.odfdom.validation>org.odftoolkit.odfdom.pkg.DefaultErrorHandler</org.odftoolkit.odfdom.validation>
</systemPropertyVariables>
<!-- Disable module path for integration tests to avoid conflict with jena-core-tests.jar -->
<!-- The jena-core-tests JAR defines the same module as jena-core, causing conflicts -->
<!-- Test classes are available on the classpath, so module path is not required for tests -->
<useModulePath>false</useModulePath>
</configuration>
<executions>
<execution>
Expand Down Expand Up @@ -577,6 +588,10 @@
<executetimes>1</executetimes>
<testflag>test</testflag>
</systemPropertyVariables>
<!-- Disable module path for integration tests to avoid conflict with jena-core-tests.jar -->
<!-- The jena-core-tests JAR defines the same module as jena-core, causing conflicts -->
<!-- Test classes are available on the classpath, so module path is not required for tests -->
<useModulePath>false</useModulePath>
</configuration>
<executions>
<execution>
Expand Down
127 changes: 127 additions & 0 deletions odfdom/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* **********************************************************************
*
* <p>DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* <p>Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved. Copyright 2018-2026
* The Document Foundation. All rights reserved.
*
* <p>Use is subject to license terms.
*
* <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
* http://odftoolkit.org/docs/license.txt
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
*
* <p>See the License for the specific language governing permissions and limitations under the
* License.
*
* <p>**********************************************************************
*/

/**
* ODFDOM - OpenDocument Format DOM API
*
* <p>This module provides the core ODFDOM API for creating, accessing and manipulating Open
* Document Format (ODF) documents.
*
* <p>The main entry points are:
*
* <ul>
* <li>{@link org.odftoolkit.odfdom.doc OdfDocument classes} - High-level document API
* <li>{@link org.odftoolkit.odfdom.pkg OdfPackage} - Package-level access
* <li>{@link org.odftoolkit.odfdom.dom OdfSchemaDocument} - DOM-level access
* <li>{@link org.odftoolkit.odfdom.changes CollabTextDocument} - Collaboration API
* </ul>
*
* @moduleGraph
* @since 0.14.0
*/
module org.odftoolkit.odfdom {
// ============================================================================
// PUBLIC API EXPORTS - Stable, documented APIs for external use
// ============================================================================

// Core API
exports org.odftoolkit.odfdom;

// Document Layer - High-level document API (stable)
exports org.odftoolkit.odfdom.doc;
exports org.odftoolkit.odfdom.doc.table;
exports org.odftoolkit.odfdom.doc.presentation;

// Package Layer - Package-level access (stable)
exports org.odftoolkit.odfdom.pkg;
exports org.odftoolkit.odfdom.pkg.manifest;
exports org.odftoolkit.odfdom.pkg.rdfa;

// Type System - Data types (stable)
exports org.odftoolkit.odfdom.type;

// Changes API - Collaboration API (stable)
exports org.odftoolkit.odfdom.changes;

// DOM Layer - Schema-based DOM access (for advanced users)
exports org.odftoolkit.odfdom.dom;
exports org.odftoolkit.odfdom.dom.style;
exports org.odftoolkit.odfdom.dom.element;
// Note: org.odftoolkit.odfdom.dom.attribute contains only subpackages, not exported directly
// Subpackages like org.odftoolkit.odfdom.dom.attribute.text are accessible via parent package
exports org.odftoolkit.odfdom.dom.rdfa;

// ============================================================================
// OPENS - For reflection access (frameworks, serialization, etc.)
// ============================================================================

// Open for Apache Jena (RDF processing)
opens org.odftoolkit.odfdom.pkg.rdfa to
org.apache.jena.core;

// Open for XML processing frameworks that use reflection
opens org.odftoolkit.odfdom.pkg to
java.xml;

// ============================================================================
// REQUIRES - Module dependencies
// ============================================================================

// Java Platform Modules
requires java.base;
requires java.desktop; // for javax.xml.*
requires java.logging;
requires java.xml;
requires java.xml.crypto; // for digital signatures

// Automatic Modules (JARs without module-info.java)
// Note: Module names are derived from JAR file names or Automatic-Module-Name manifest attribute
// Maven compiler plugin automatically places dependencies on module path when module-info.java
// exists
requires xercesImpl; // xerces:xercesImpl (xercesImpl-2.12.2.jar -> xercesImpl, derived from
// filename)
requires serializer; // xalan:serializer (serializer-2.7.3.jar -> serializer) - confirmed working
requires org.apache.jena.core; // org.apache.jena:jena-core (has Automatic-Module-Name)
requires java.rdfa; // net.rootdev:java-rdfa (java-rdfa-1.0.0-BETA1.jar -> java.rdfa) - confirmed
// working
requires org.apache
.commons
.validator; // commons-validator:commons-validator (has Automatic-Module-Name)
requires org.apache
.commons
.compress; // org.apache.commons:commons-compress (has Automatic-Module-Name)
requires org.apache.commons.lang3; // org.apache.commons:commons-lang3 (has Automatic-Module-Name)
requires org.json; // org.json:json (has Automatic-Module-Name)
requires org.bouncycastle.provider; // org.bouncycastle:bcprov-jdk18on (has Automatic-Module-Name)

// Optional dependencies (may not be present at runtime)
requires static org.slf4j; // org.slf4j:slf4j-api (has Automatic-Module-Name: org.slf4j)

// ============================================================================
// SERVICES - Service provider interfaces (if any)
// ============================================================================

// Currently no services defined
}
10 changes: 7 additions & 3 deletions odfdom/src/test/java/org/odftoolkit/odfdom/pkg/GRDDLTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,26 @@
import javax.xml.transform.stream.StreamResult;
import junit.framework.TestCase;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.test.ModelTestBase;
import org.apache.jena.rdf.model.ModelFactory;
import org.junit.Assert;
import org.junit.Test;
import org.odftoolkit.odfdom.doc.OdfDocument;
import org.odftoolkit.odfdom.doc.OdfTextDocument;
import org.odftoolkit.odfdom.utils.ResourceUtilities;
import org.xml.sax.InputSource;

public class GRDDLTest extends ModelTestBase {
public class GRDDLTest extends TestCase {

private static final Logger LOG = Logger.getLogger(GRDDLTest.class.getName());
private static final String SIMPLE_ODT = "test_rdfmeta.odt";

public GRDDLTest(String name) {
super(name);
// TODO: Auto-generated constructor stub
}

/** Creates an in-memory RDF model. Replaces the ModelTestBase.createMemModel() method. */
protected Model createMemModel() {
return ModelFactory.createDefaultModel();
}

/**
Expand Down
Loading