Problems using IDataMap in Application Platform

Hi everyone!

I was using a variable as a dynamic Map (IDataMap) in my application platform, however, its seems that it is breaking my code, since the exposed method is not actually appearing in my package navigation of the IS. If I remove it, the methods appears.

Here’s the exposed method that I have defined:
@Service
@ExposeToIS(packageName=“GF_PLS_GenericServices”)
public class EmailService {
@ExposedMethod
public String Send(String emailParamTO, String emailParamFROM, String emailParamCC, String emailParamSUBJECT, String emailParamCONTENT_TYPE, String emailContent, String templateName, IDataMap templateParams)

image

Any idea why? I believe this was working before…

2 Likes

Hi Rui,
Use of IS client collections ( IData and IDataMap ) is not a supported use case. Eliminating the need to use these objects is what App Platform is designed to do. The issue is with the distinction of classloaders. The App Platform service projects are loaded by an OSGi equinox classloader and are separate from the traditional Integration Server’s ‘ServerClassLoader’.

Rather than use IDataMap, please consider using Java Collections. I’ll attach a sample internal project that demonstrates the use of collections in Exposed methods.

-thanks!

ordersPojo.tar.txt (50 KB)

Please rename this .txt file and decompress the tar file.

Hi Warren,

Thanks a lot for your reply. Unfortunately, this doesn’t suit me because I wanted to use Dynamic Collections, where the user actually defines both the keys and values of a Map collection. In your sample, I can only see static collections (List and hence the LineItem fields are already defined) which doesn’t help me here that much.

The idea behind the project is having sending an email based on a template. All templates have different input variables names (for example: Template1 (Name, Age, Profession) and Template2 (Name, Country, City, Str. address)). The idea would be trying to make the code as much reusable as we could by getting these Dynamic Maps into our solution, where the user would simply add the keys and the values manually. Of course we could use a String array for the keys and values and connect them by their position (Keys {“name”, “age”,“profession”}; Values{“Rui”,“27”,“Software Developer”}) but this is not the best practice, as far as I know. I could also create a java service acting as an interface for the PLS, where It would accept IDataMap variables and then I would convert it to two String arrays (Keys and Values), but again, not the best solution.

Is there a way we could do this directly in the PLS?

Thanks,
Rui Gomes

Hi Rui, yes, the example I sent llustrates a List collection, but you can develop an app that uses a HashMap just as well.

But I am still getting the same error once I choose to use a HashMap as an input variable:

@Service
@ExposeToIS(packageName=“GF_PLS_GenericServices”)

@ExposedMethod
public String Send(String[] emailParamTO, String emailParamFROM, String[] emailParamCC, String emailParamSUBJECT, String emailParamCONTENT_TYPE, HashMap<String,String> emailContent)

image

Once I take that “HashMap” input variable out, the PLS exposed method pops up again in the Package Navigator.

Ok so I managed to create my own POJO and added in the input variable of my exposed method and now it seems to be working. However, if the Collection is a HashMap, I get this weird variable type:


NOTE: templateParameters is the HashMap instance.

If it’s a list, it’s fine, since you can add different rows with String values. If I choose the Map instance, it would be the same as having a List(?):

Exposed Method:

public String Send(String[] emailParamTO, String emailParamFROM, String[] emailParamCC, String emailParamSUBJECT, String emailParamCONTENT_TYPE, EmailContent emailContent)

Here are my classes:

public class EmailContent {

	String content;
	Template template;
	
	public EmailContent(String content, Template template) {
		super();
		this.content = content;
		this.template = template;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public Template getTemplate() {
		return template;
	}
	public void setTemplate(Template template) {
		this.template = template;
	}
	
}
class Template
{
	String templateName;
	Map<String,String> templateParameters;
	
	public Template(String templateName, Map<String,String> templateParameters) {
		super();
		this.templateName = templateName;
		this.templateParameters = templateParameters;
	}
	public String getTemplateName() {
		return templateName;
	}
	public void setTemplateName(String templateName) {
		this.templateName = templateName;
	}
	public Map<String,String> getTemplateParameters() {
		return templateParameters;
	}
	public void setTemplateParameters(Map<String,String> templateParameters) {
		this.templateParameters = templateParameters;
	}
	
}

Hi Rui, I was thinking something slightly different.
Your interface ‘send’ method would contain one or two POJO classes for its parameter that you write.
One of those classes could contain a HashMap of your key-value pairs.
If you pass a POJO in your service interface method insteadof a list of specific parameters it is less brittle.
i.e. You can add additional properties to the POJO and still remain back-ward compatible to older client code that calls your interface. It’s a matter of OO style, so if you agree, feel free to give that a try.

However, I would think what you are trying to do should also work, so I will investigate and get back to you.

-thanks

2 Likes

That sounds like a reasonable way to me. :slight_smile: Looking forward to seeing Rui’s test results.

BTW: Please note that using IDataMap in AppPlatform projects may even result in null pointer exceptions with the BundleLoader/ClassLoader and prevent IS from starting up again. See this excerpt from wrapper.log:

INFO | jvm 1 | 2020/08/26 20:46:00 | java.lang.NullPointerException
INFO | jvm 1 | 2020/08/26 20:46:00 | at org.eclipse.osgi.internal.loader.BundleLoader.findRequiredSource(BundleLoader.java:1163)
INFO | jvm 1 | 2020/08/26 20:46:00 | at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:436)
INFO | jvm 1 | 2020/08/26 20:46:00 | at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:395)
INFO | jvm 1 | 2020/08/26 20:46:00 | at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:387)
INFO | jvm 1 | 2020/08/26 20:46:00 | at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:150)
INFO | jvm 1 | 2020/08/26 20:46:00 | at java.lang.ClassLoader.loadClass(ClassLoader.java:411)
INFO | jvm 1 | 2020/08/26 20:46:00 | at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
INFO | jvm 1 | 2020/08/26 20:46:00 | at com.wm.app.b2b.server.ServerConfiguration.getMwSSamlResolverURL(ServerConfiguration.java:755)
INFO | jvm 1 | 2020/08/26 20:46:00 | at com.wm.app.b2b.server.ServerConfiguration.getDefaults(ServerConfiguration.java:711)
INFO | jvm 1 | 2020/08/26 20:46:00 | at com.wm.app.b2b.server.Server.loadConfiguration(Server.java:2148)
INFO | jvm 1 | 2020/08/26 20:46:00 | at com.wm.app.b2b.server.Server.run(Server.java:389)

Best regards,
Marcus

Hi Warren,

Actually, if you see my above post, I have already tried your proposed solution: Creating a POJO that contains a HashMap instance. In my example, this is the EmailContent object structure for the Send() method:

EmailContent:

  • String content;

  • Template template:

    • String templateName;
    • Map<String,String> templateParameters;

Let me know if there’s anything else that I could try.

Thanks,
Rui Gomes

Hi Marcus and Rui,

There is a defect that impacts any JDK collection type that contains more than one Typed parameter - e.g. Map<K,V>. This is why the use of HashMap is not working as expected. Also, note that App Platform does not currently support all the Collection interface types ( e.g. java.util.Set ). It looks like java.util.ArrayList is the only fully-supported JDK colection type at this time.

As an immediate work-around, I can suggest the following:

  1. Use java.util.List - e.g. List in your service signature
    2, Add a String key field to your Template type
    3, Add logic to your Send( ) implemenation method to iterate over the ArrayList of Template parameters to enforce key uniqueness constraints.

I understand this is a work-around, but it’s a way forward that does not require your waiting for a fix.

Please let me know. I can’t give an accurate estimate for the time until a fix in this response.

-thanks and sorry for the delay.

Hi Warren,

Thanks for the input. I tried something like adding a List instance of type “TemplateEntry”, which has 2 String fields (key and value) and then added to my EmailContent object. Everything seems to be working just fine since I am getting this:

image

However, when I execute this service, I get the following error:

Could not run 'Send'
java.lang.InstantiationException: com.gf.genericservices.EmailPLS.Input.TemplateEntry

This made me assume there’s no constructor without any input, which I also added, but then I get another error:

Could not run 'Send'
java.lang.IllegalAccessException: Class com.softwareag.applatform.pls.gateway.impl.IData2Pojo can not access a member of class com.gf.genericservices.EmailPLS.Input.TemplateEntry with modifiers ""

For some reason, it’s not working… : (

Thanks,
Rui Gomes

Ok got it working, by creating manually these documents as such:

image

And then publishing them into the PLS as POJOs.

@Warren_Cooper Out of the sudden, now my POJOs are not getting any content value from the service’s input fields.

public String Send(String[] emailParamTO, String emailParamFROM, String[] emailParamCC, String emailParamSUBJECT, String emailParamCONTENT_TYPE, PLS_EmailContent emailContent)

The PLS_EmailContent is my POJO object (document type) composed by:

// Copyright (c) 2017 Software AG, Darmstadt, Germany and/or Software AG USA, Inc., Reston, VA, USA, and/or its subsidiaries.
// This program is confidential, proprietary and a trade secret to Software AG and/or its licensors and may not be reproduced, published or disclosed to others without the express written consent of Software AG.

//         Wrapper Timestamp: Mon Oct 05 14:17:21 CEST 2020

package gf_pls_genericservices.docs.email.workaround.emailcontent;

import com.softwareag.applatform.pls.is.DataKey;


/**
  *** AUTO-GENERATED by Software AG Application Platform ***

  This class is a simple POJO with Java Bean-style properties/getters/setters.
  It is used to represent a data element in the signature of a Service from the IS namespace.
  In addition to getters and setters, it uses a few Application Platform annotations to assist
  with marshaling between POJOs and IS Service pipeline.
  


  @author Software AG Application Platform
  
 */
@com.softwareag.applatform.pls.is.DoctypeData(key="GF_PLS_GenericServices.docs.email.workaround:EmailContent")
public class PLS_EmailContent {

    public static final String IS_PACKAGE_VERSION="GF_PLS_GenericServices:1.0";

    /**
      Instance variable for the Content pipeline property.
     */
    @DataKey (key = "Content", isType = "string", isDim = 0)
    private String pls_content;

    public String getContent() {
        return pls_content;
    }

    public void setContent(String inContent) {
        pls_content = inContent;
    }


}

When I run the service and add the “Content” field as “Test”, the content variable continues to be null…


if (emailContent != null)
{
				String _emailParamCONTENT = "";
				String emailParamTEMPLATE_NAME = "";
				TemplateEntry[] emailParamTEMPLATE_PARAMS = null;
				stdLog.append("\r\nContent: " + emailContent.getContent());
}

Content: null
ERROR: java.lang.NullPointerException

Why isn’t it working now? I tried to recreate the POJO, republishing the PLS, etc… nothing seems to be working…

Hi Rui,
Please contact Global Support so a ticket can be opened.

Please upload your application as it stands now. - i.e. just zip up your Designer/Eclipse workspace containing your project. I’ll need to see the log files too. ( profiles/IS_default/logs/* and IntegrationServer/instances/default/logs/server*

thanks

Hi Warren,

I recreated the document type from scratch and republished to the AppPlatform and I think it did the trick. So far it’s working again. I’m guessing there was something corrupted in the genSource or something.

Thanks!