Question

Custom FME Transformer implemented in Java


Hello everyone,

 

I am trying to write a custom FME transformer using the FME Plug-in SDK with Java.

 

I installed the FME Plug-in SDK and successfully followed the steps of the Java tutorial document (after installing the SDK, the tutorial document is located at '<FME>\pluginbuilder\samples\doc\FMEPlugInSDK_Java.pdf'; I attached it to this posting; especially section 4 "Installing and Testing a Transformer" is relevant to my question; ). In section 4 of this document

 

  • the custom transfomer defined in file 'CenterOfMassCalculator_Java.fmx' is installed
  • after installing, the FME workspace '..\java\test\function_test.fmw' is run which contains the 'CenterOfMassCalculator_Java' transformer as second element in the translation flow

 

Eventually, running 'function_test.fmw' in the FME workbench results in that the method 'execute(.)' of the Java class '<FME>\pluginbuilder\samples\java\com\mycompany\myfunction\center.java' is executed.

01_CenterOfMassCalculator_Java in FME Workbench 

I am able to attach with the debugger of my IDE and track the code execution there. Moreover, I can also 

  • change the code in this method,
  • build a new JAR with the changed code, 
  • replace '<FME>\plugins\tfs.jar' with this new JAR, 
  • and observe the effects of my changes in FME:

 

02_Changed Java code and effect on results in FMESo all good with regard to the tutorial itself.

 

However, what I do not understand is how the connection between the transformer definition in the 'CenterOfMassCalculator_Java.fmx' file and the 'center.java' class is achieved.

 

Can anyone explain how FME "knows" that 

  • - the 'execute(.)' method 
  • - of class 'com.mycompany.myfunction.center.java
  • - in the JAR '<FME>\plugins\tfs.jar

shall be executed?

 

Moreover, imagine I have a class 'com.mycompany.myfunction.Center2.java' which---just like 'com.mycompany.myfunction.center.java'---implements the interface IFMEFunction. How can I tell the transformer to jump into the class 'Center2.java' instead of jumping into class 'center.java'?

03_Example for custom Java class to executeThe 'CenterOfMassCalculator_Java.fmx' file definition is understandable to me up to the point when the template definition is reached (I attached the entire .fmx file to this posting):

...
TEMPLATE_START
 
FACTORY_DEF * TeeFactory
   FACTORY_NAME $(XFORMER_NAME)
   $(INPUT_LINES)
   OUTPUT FEATURE_TYPE $(OUTPUT_OUTPUT_FTYPE)
      @JavaCenter($(X_ATTR),$(Y_ATTR),$(Z_ATTR))
      $(OUTPUT_OUTPUT_FUNCS)
 
TEMPLATE_END

I found some documentation on the definition of .fmx files and the so-called TeeFactory which is used in the template:

However, from these documents, I could not deviate how the connection from .fmx definitions to concrete Java code is achieved. I think the key part is the '@JavaCenter' annotation. 

 

Is anyone able to help? Or is the only way to contact Safe Software for an integration project (as suggested here in step 4: https://community.safe.com/s/article/developing-a-new-transformer-using-the-fme-plug-in)? 

 

(I also compiled the posting into a PDF which might be easier to read than the posting here in the forum, please see attachments.)

 

Any help would be greatly appreciated! 


4 replies

Userlevel 2
Badge +17

Hi @lbd-kufers​,

You can call the new function by using the full path of the function within the jar file:

@com.mycompany.myfunction.center()

 

You can also create an alias for the full path by adding the appropriate mapping (.db file) to the FME\\pluginsinfo\\function folder. The format for this file is:

<function alias>|<function path>|<plugin type>

ie.

JavaCenter|com.mycompany.myfunction.center|JAVA

 

The use of the alias file is not well described in our present documentation, so I have created an enhancement request to have it improved.

Hi @lbd-kufers​,

You can call the new function by using the full path of the function within the jar file:

@com.mycompany.myfunction.center()

 

You can also create an alias for the full path by adding the appropriate mapping (.db file) to the FME\pluginsinfo\function folder. The format for this file is:

<function alias>|<function path>|<plugin type>

ie. 

JavaCenter|com.mycompany.myfunction.center|JAVA

 

The use of the alias file is not well described in our present documentation, so I have created an enhancement request to have it improved.

Hi @daveatsafe​ ,

thank you very much for your response! 

With the .db mapping file, I was able to connect FME to my custom Java code. 😎 

 

With the full path of the function, I was not able to achieve the connection, though. Using the following template definition in the FMX file

TEMPLATE_START
 
FACTORY_DEF * TeeFactory
   FACTORY_NAME $(XFORMER_NAME)
   $(INPUT_LINES)
   OUTPUT FEATURE_TYPE $(OUTPUT_OUTPUT_FTYPE)
      @com.mycompany.myfunction.center()($(X_ATTR),$(Y_ATTR),$(Z_ATTR))
      $(OUTPUT_OUTPUT_FUNCS)
 
TEMPLATE_END

the following error is printed to the FME translation log:

BADNEWS: Module 'com.mycompany.myfunction.center_func' is unavailable for use with this FME edition
(C:\code\fme\foundation\pluginbuilder\pluginbuilder_cpp\dynaload.cpp:1206) class StatusInfo *__cdecl DynaLoad_loadModule2(const class ObsoleteString &,const class ObsoleteString &,const enum fme::internal::_v0::detail::PluginType &)
(C:\code\fme\foundation\pluginbuilder\pluginbuilder_cpp\dynaload.cpp:1351) class StatusInfo *__cdecl DynaLoad_loadModule(const class ObsoleteString &,const enum fme::internal::_v0::detail::PluginType &)
(C:\code\fme\foundation\pluginbuilder\pluginbuilder_cpp\dynaload.cpp:2068) class StatusInfo *__cdecl DynaLoad_getFunction(const class ObsoleteString &,class IFMEFunction *&)
Exception Name: stk::ex::Throwable
CenterOfMassCalculator_Java (TeeFactory): This FME edition does not recognize the `com.mycompany.myfunction.center' function. Please ensure that the current platform supports this function, the function name is spelled correctly, and that you have installed all required plug-ins
This FME edition does not recognize the `com.mycompany.myfunction.center' function. Please ensure that the current platform supports this function, the function name is spelled correctly, and that you have installed all required plug-ins
(C:\code\fme\foundation\framework\engine\cmdparm.cpp:1533) class StatusInfo *__cdecl CommandParmList::Impl::parseCommand(const class stk::ex::UString<0> &)
(C:\code\fme\foundation\framework\engine\stfspec.cpp:231) class StatusInfo *__cdecl STFSpec::init(const class stk::ex::UStringArray<0> &,const class stk::ex::UString<0> *,const class stk::ex::UString<0> *)
(C:\code\fme\foundation\factories\fcttee.cpp:165) class StatusInfo *__cdecl STFTeeFactory::do_processClause(const class FactoryClause &)
(C:\code\fme\foundation\factories\factory.cpp:756) class StatusInfo *__cdecl STFFactory::configure(class FactoryDef)
(C:\code\fme\foundation\factories\pipeline.cpp:557) class StatusInfo *__cdecl STFFactoryPipeline::createFactory(const class stk::ex::UStringArray<0> &,class STFFactory *&,long)
(C:\code\fme\foundation\factories\pipeline.cpp:388) class StatusInfo *__cdecl STFFactoryPipeline::configure(const class stk::ex::UString<0> &,class STFTranslator &,class STFGrouper &,class STFCorrelator &)
(C:\code\fme\foundation\kernel\simptran.cpp:631) class StatusInfo *__cdecl STFSimpleTranslator::convert(void)
(C:\code\fme\foundation\framework\engine\stftrans.cpp:282) class StatusInfo *__cdecl STFTranslator::translate(void)
Exception Name: stk::ex::Throwable
Translation FAILED with 3 error(s) and 0 warning(s) (0 feature(s) output)

Since it appeared unexpected to me that the class name is suffixed with opening and closing parantheses "()", I also tried replacing 

@com.mycompany.myfunction.center()($(X_ATTR),$(Y_ATTR),$(Z_ATTR))

with

@com.mycompany.myfunction.center($(X_ATTR),$(Y_ATTR),$(Z_ATTR))
com.mycompany.myfunction.center()($(X_ATTR),$(Y_ATTR),$(Z_ATTR))

and

com.mycompany.myfunction.center($(X_ATTR),$(Y_ATTR),$(Z_ATTR))

, but no success with any of these. 

Any idea why the error occurs?

 

(The solution with the mapping file is sufficient for me, but maybe it would be nice for other guys running into similar problems if we could also clarify on the "full path linking". )

 

Thanks again and best regards!

 

 

Userlevel 2
Badge +17

Hi @daveatsafe​ ,

thank you very much for your response! 

With the .db mapping file, I was able to connect FME to my custom Java code. 😎 

 

With the full path of the function, I was not able to achieve the connection, though. Using the following template definition in the FMX file

TEMPLATE_START
 
FACTORY_DEF * TeeFactory
   FACTORY_NAME $(XFORMER_NAME)
   $(INPUT_LINES)
   OUTPUT FEATURE_TYPE $(OUTPUT_OUTPUT_FTYPE)
      @com.mycompany.myfunction.center()($(X_ATTR),$(Y_ATTR),$(Z_ATTR))
      $(OUTPUT_OUTPUT_FUNCS)
 
TEMPLATE_END

the following error is printed to the FME translation log:

BADNEWS: Module 'com.mycompany.myfunction.center_func' is unavailable for use with this FME edition
(C:\code\fme\foundation\pluginbuilder\pluginbuilder_cpp\dynaload.cpp:1206) class StatusInfo *__cdecl DynaLoad_loadModule2(const class ObsoleteString &,const class ObsoleteString &,const enum fme::internal::_v0::detail::PluginType &)
(C:\code\fme\foundation\pluginbuilder\pluginbuilder_cpp\dynaload.cpp:1351) class StatusInfo *__cdecl DynaLoad_loadModule(const class ObsoleteString &,const enum fme::internal::_v0::detail::PluginType &)
(C:\code\fme\foundation\pluginbuilder\pluginbuilder_cpp\dynaload.cpp:2068) class StatusInfo *__cdecl DynaLoad_getFunction(const class ObsoleteString &,class IFMEFunction *&)
Exception Name: stk::ex::Throwable
CenterOfMassCalculator_Java (TeeFactory): This FME edition does not recognize the `com.mycompany.myfunction.center' function. Please ensure that the current platform supports this function, the function name is spelled correctly, and that you have installed all required plug-ins
This FME edition does not recognize the `com.mycompany.myfunction.center' function. Please ensure that the current platform supports this function, the function name is spelled correctly, and that you have installed all required plug-ins
(C:\code\fme\foundation\framework\engine\cmdparm.cpp:1533) class StatusInfo *__cdecl CommandParmList::Impl::parseCommand(const class stk::ex::UString<0> &)
(C:\code\fme\foundation\framework\engine\stfspec.cpp:231) class StatusInfo *__cdecl STFSpec::init(const class stk::ex::UStringArray<0> &,const class stk::ex::UString<0> *,const class stk::ex::UString<0> *)
(C:\code\fme\foundation\factories\fcttee.cpp:165) class StatusInfo *__cdecl STFTeeFactory::do_processClause(const class FactoryClause &)
(C:\code\fme\foundation\factories\factory.cpp:756) class StatusInfo *__cdecl STFFactory::configure(class FactoryDef)
(C:\code\fme\foundation\factories\pipeline.cpp:557) class StatusInfo *__cdecl STFFactoryPipeline::createFactory(const class stk::ex::UStringArray<0> &,class STFFactory *&,long)
(C:\code\fme\foundation\factories\pipeline.cpp:388) class StatusInfo *__cdecl STFFactoryPipeline::configure(const class stk::ex::UString<0> &,class STFTranslator &,class STFGrouper &,class STFCorrelator &)
(C:\code\fme\foundation\kernel\simptran.cpp:631) class StatusInfo *__cdecl STFSimpleTranslator::convert(void)
(C:\code\fme\foundation\framework\engine\stftrans.cpp:282) class StatusInfo *__cdecl STFTranslator::translate(void)
Exception Name: stk::ex::Throwable
Translation FAILED with 3 error(s) and 0 warning(s) (0 feature(s) output)

Since it appeared unexpected to me that the class name is suffixed with opening and closing parantheses "()", I also tried replacing 

@com.mycompany.myfunction.center()($(X_ATTR),$(Y_ATTR),$(Z_ATTR))

with

@com.mycompany.myfunction.center($(X_ATTR),$(Y_ATTR),$(Z_ATTR))
com.mycompany.myfunction.center()($(X_ATTR),$(Y_ATTR),$(Z_ATTR))

and

com.mycompany.myfunction.center($(X_ATTR),$(Y_ATTR),$(Z_ATTR))

, but no success with any of these. 

Any idea why the error occurs?

 

(The solution with the mapping file is sufficient for me, but maybe it would be nice for other guys running into similar problems if we could also clarify on the "full path linking". )

 

Thanks again and best regards!

 

 

Hi @lbd-kufers​,

It seems that we may have disabled the direct '@com.mycompany.myfunction.center()' method when we implemented the mapping file setup. This contradicts the Java plugin API docs, so I have created a problem report to get this sorted out. I apologize for the confusion on my part.

I'm also trying to understand all of this at the moment. What exactly does the @JavaCenter do?

Is @Java the call and "Center" says what function name?

It would be logical if it would be @center. Don't understand how "Java" is processed.

This looks more logical: @com.mycompany.myfunction.center()

 

Reply