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)
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 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?
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:
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(?):
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.
That sounds like a reasonable way to me. 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)
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.
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:
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 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:
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 ""
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…
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*
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.