Question How to use java classes in 4gl code?

juninhopolo

New Member
Hey guys, here I am again after a long time without posting nothing.

Recently I came across with some features requests hoping to be able to solve them with 4gl code. I need to generate and manipulate .docx files and .xlsx files in progress 4gl but without using ActiveX / OCX (due to some specific vendor locking issues).

Doing some research I found that Open Edge can execute .NET (so far, nothing new), but expanding on that I found out that it can also execute java code (really?), something about Open Clients (I don't really know what it is). Since nowadays everyone uses AI, I used chatgpt with some prompts like "How to use java classes in progress 4gl?", "Is it possible to use java classes in progress 4gl?" and it gave to results along the lines of: "Yes, it is possible to use Java classes in Progress 4GL (OpenEdge ABL) via the Java Open Client or by using the Java Interface provided by OpenEdge.".

After spending some time playing with some prompts, it became clear that Open Client is something for APIs (i assume, correct if I'm wrong). But the "Java Interface" topic caught my eyes and I spend some more time with that.

A lot of prompts later, I could start to understand "how to do it". I'll summarize some key points gived to me by chatgpt: "Ensure the JVM is Configured (%DLC%/properties/java.properties)", "Add JAR Files to the OpenEdge Classpath", "Set the JAVA_HOME Environment Variable" and so on. It even gave to me some snippets to try, but nothing worked. Check it out:


Code:
USING java.lang.String.


DEFINE VARIABLE javaString AS CLASS java.lang.String NO-UNDO.


javaString = NEW java.lang.String("Hello from Java").

MESSAGE javaString:toString().


Code:
/* Define a variable of type java.lang.String */

DEFINE VARIABLE javaString AS CLASS java.lang.String NO-UNDO.


/* Create an instance of the Java String class */

ASSIGN javaString = NEW java.lang.String("Hello from Java in OpenEdge!").


MESSAGE javaString:toUpperCase() VIEW-AS ALERT-BOX INFO.


Even this one, which is just...


Code:
/* Import the java.lang.String class */

IMPORT java.lang.String.


/* Define a variable of type java.lang.String */

DEFINE VARIABLE javaString AS CLASS java.lang.String NO-UNDO.


/* Create an instance of the Java String class */

CREATE javaString.


ASSIGN javaString = NEW java.lang.String("Hello from Java in OpenEdge!").


MESSAGE javaString:toUpperCase() VIEW-AS ALERT-BOX INFO.

Anyways, in summary, I was hopping to code those features with some Java Classes but in 4gl code. Is it possible or all that AI "research" is just AI hallucination?
 
It's a hallucination.

You can use an openclient (java or .NET) to call ABL on an AppServer.
You can call .NET classes from ABL clients (over the "bridge").
You can call java classes that are exposed via something like the IKVM in .NET.

But you cannot call java classes directly in ABL.

In 12.8 you can run .NET classes on Linux. You can use .NET Core classes to do the Office stuff.

The java properties files you saw are related to the bits of the OpenEdge product (eg PDSOE or Admin server or PASOE) that use java.
 
Hello Peter!
Thanks very much for the clarifications.

Also, thanks for providing alternatives. Given the circumstances, I'm going to dig deeper into the use of .NET classes in a linux instance. I think this is heading for a success.

Best regards!
 
I cant make it work. Here it is what I have so far.

I follow this tutorial to generate the assemblies.xml containing the following namespaces / classes, based on this .NET doc. The generated xml looks like the following:
XML:
<?xml version="1.0" encoding="utf-8"?>
<references xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <assembly name="DocumentFormat.OpenXml, Version=3.1.0.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17" />
  <assembly name="DocumentFormat.OpenXml.Framework, Version=3.1.0.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17" />
  <assembly name="System.IO.Packaging, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</references>

My .p file looks like this, very simple, just to make sure everything is up to code.

Code:
using System.*.
using DocumentFormat.OpenXml.*.
using DocumentFormat.OpenXml.Packaging.*.
using DocumentFormat.OpenXml.Spreadsheet.

But when I run it with: prowin.exe -assemblies "~assemblies-folder~" -p "~my-p-file~"

It fails with the following message:
Code:
Could not find class or interface DocumentFormat.OpenXml.Spreadsheet. (12886). Could not understand line 4.

What am I missing? It has to be able to locate the dll, not just the assemblies.xml, right? Do I put it in the PROPATH? Does it have to configure something in the .pf file?

I also tried to put the "from assembly" after like so:
Code:
// Even though System don't have to
using System.* from assembly.
using DocumentFormat.OpenXml.* from assembly.
using DocumentFormat.OpenXml.Packaging.* from assembly.
using DocumentFormat.OpenXml.Spreadsheet from assembly.

I for sure know that the problem is in the referencing, but dont know how to fix it.
Do I have to use this "+" sintax? Referencing inner classes and interfaces

Do I have to worry about the "inheritance"? Incorporation of the .NET object model

Maybe putting in the Global Assembly Cache would be easier, but eventually I'll have to make it work with assemblies.xml.

I will be very grateful for your help.
 
Last edited:
I have never used the DocumentFormat classes so if a problem with these do not know the answer, but if it is the case of your program not seeing the dll then hopefully a bit of information that may help.

For deployment, if only running compiled programs then you do not actually require access to assemblies.xml. When you run from r-code, you don't need the assemblies.xml file because the assembly-qualified name of all referenced classes are in the r-code.

The main problem can be the accessing of the dll and there are basically three options without it being in the Global Assembly Cache:
  • Place the dll(s) in the Progress session working directory as per the value here: MESSAGE SESSION:TEMP-DIRECTORY VIEW-AS ALERT-BOX INFORMATION.
  • Use the -assemblies startup parameter to point to where the dll(s) reside. From what you say you have tried exactly this but it does not seem to be working.
  • Try dynamically loading: Progress Customer Community, Progress Customer Community.
Hope this helps.
 
It took me a while, but i manage to load the dlls! But (there is always a "but"), i can seem to be able to instantiate a class that has no constructor, but it has a static method that returns an instance (a.k.a Create() or GetInstance()).

The class in question is this one:
Code:
DocumentFormat.OpenXml.Packaging.SpreadsheetDocument

I can "import it" like so:
Code:
using DocumentFormat.OpenXml.Packaging.SpreadsheetDocument from assembly.

But when I try to even declare a variable of it is type the error is just: "Can't understand the line X. (198)".
Code:
using DocumentFormat.OpenXml.Packaging.SpreadsheetDocument from assembly.
// Code fails to compile right here
define variable my_sd as class DocumentFormat.OpenXml.Packaging.SpreadsheetDocument no-undo.

Here it is the .NET documentation DocumentFormat.OpenXml.Packaging.SpreadsheetDocument and a little code snippet in .NET.
C#:
// Create a spreadsheet document by supplying the file name. 
SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument. 
    Create(fileName, SpreadsheetDocumentType.Workbook);

I tried a couple of things:

Declaring the variable as System.Object (from .NET),
Code:
define variable my_sd_1 as System.Object no-undo.
assign my_sd = DocumentFormat.OpenXml.Packaging.SpreadsheetDocument:Create(
    'file_path',
    DocumentFormat.OpenXlm.SpreadsheetDocumentType:Workbook
).

as Progress.Lang.Object:
Code:
define variable my_sd_1 as Progress.Lang.Object no-undo.
assign my_sd = DocumentFormat.OpenXml.Packaging.SpreadsheetDocument:Create(
    'file_path',
    DocumentFormat.OpenXlm.SpreadsheetDocumentType:Workbook
).

and providing an initial value right in the declaration:
Code:
define variable my_sd as class DocumentFormat.OpenXml.Packaging.SpreadsheetDocument
    initial DocumentFormat.OpenXml.Packaging.SpreadsheetDocument:Create(
        '',
        DocumentFormat.OpenXml.SpreadsheetDocumentType:Xlsx
) no-undo.

I also considered the possibility of the dll were "bugged", but that not seems to be the case by the fact that I was able to instantiate another class of the same .NET namespace that has a constructor (DocumentFormat.OpenXml.Packaging.OpenSettings).
Code:
using DocumentFormat.OpenXml.Packaging.OpenSettings from assembly.
// Code do not fails rigth here.
define variable my_op as class DocumentFormat.OpenXml.Packaging.OpenSettings no-undo.
assign my_op = new DocumentFormat.OpenXml.Packaging.OpenSettings().

You guys have some wisdow to share in that matter?
 
Hello again!
Thank you so much for your time and research!

I'm glad this was so well documented though. maybe in the near future this will become a possibility.
 
Back
Top