Questions and Answers
This chapter lists questions and answers about the Frank!Framework.
Adapter status page ManageDatabase error
Question: Why do I see an error in adapter ManageDatabase, saying that there is no datasource? See below:
Answer: You did not add this adapter yourself. This adapter is part of the Frank!Framework. You see here that the Frank!Framework fails to start. This happens when your file names are lowercase. For example, when your files are named
configuration.xml instead of
Configuration.xml, then this error occurs. Correct your file names to fix the issue.
On startup, syntax error in SQL
Question: In the output of the Frank!Runner I see a Java stacktrace of a JdbcSQLSyntaxErrorException, as shown below:
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "CREATE TABLE VISIT ( BOOKINGID INT NOT NULL, SEQ INT NOT NULL, HOSTID INT NOT NULL, PRODUCTID INT NOT NULL, STARTDATE DATE NOT NULL, ENDDATE DATE NOT NULL, PRICE DECIMAL NOT NULL, PRIMARY KEY (BOOKINGID, SEQ) ) ALTER[*] TABLE VISIT ADD FOREIGN KEY (BOOKINGID) REFERENCES BOOKING(ID)"; SQL statement: CREATE TABLE visit ( bookingId INT NOT NULL, seq INT NOT NULL, hostId INT NOT NULL, productId INT NOT NULL, startDate date NOT NULL, endDate date NOT NULL, price DECIMAL NOT NULL, PRIMARY KEY (bookingId, seq) ) ALTER TABLE visit ADD FOREIGN KEY (bookingId) REFERENCES booking(id) [42000-200] at org.h2.message.DbException.getJdbcSQLException(DbException.java:453) at org.h2.message.DbException.getJdbcSQLException(DbException.java:429) at org.h2.message.DbException.get(DbException.java:205) at org.h2.message.DbException.get(DbException.java:181) at org.h2.message.DbException.getSyntaxError(DbException.java:229) at org.h2.command.Parser.getSyntaxError(Parser.java:1051) at org.h2.command.Parser.prepareCommand(Parser.java:741) at org.h2.engine.Session.prepareLocal(Session.java:657) at org.h2.engine.Session.prepareCommand(Session.java:595) at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1235) at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:212) at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:201) at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:307) ... 35 more
What is wrong?
Answer: The SQL statements shown are in
DatabaseChangelog.xml. The error says that these statements have syntax errors. The error is in the following snippet of
<changeSet id="2" author="martijn"> <sql> CREATE TABLE visit ( bookingId INT NOT NULL, seq INT NOT NULL, hostId INT NOT NULL, productId INT NOT NULL, startDate date NOT NULL, endDate date NOT NULL, price DECIMAL NOT NULL, PRIMARY KEY (bookingId, seq) ) ALTER TABLE visit ADD FOREIGN KEY (bookingId) REFERENCES booking(id) </sql> </changeSet>
All SQL within a changeset is interpreted by the database engine. The shown example uses a H2 database, so the SQL dialect of H2 databases is being applied. A
; is needed between the
CREATE TABLE and the
ALTER TABLE statements, right after the closing
) of the
CREATE TABLE statement.
You can see which
<changeSet> has the SQL syntax error. Higher-up in the Java stack trace, there was a line
Migration failed for change set DatabaseChangelog.xml::2::martijn:. Here you see it was the change set with id
Passing XML parameter to XSLT
Question: I have an XSLT transformation that expects a parameter of type XML. When I pass the parameter from my Frank config, it is interpreted as a string. How can I fix this?
Answer: To execute an XSLT transformation with parameters, you use an
<Param> tags. Within a
<Param> tag, you can provide the value that will be passed to the XSLT transformation. For passing strings, this is all you have to know; you can find the details in the Frank!Doc. If your value is XML, you need one more trick. Within your
<Param> tag, set
type="domdoc". Here is an example:
<XsltPipe name="transformHermesMessage" styleSheetName="printBridge.xsl" omitXmlDeclaration="true" xsltVersion="2" getInputFromSessionKey="originalMessage"> <Param name="statistics" sessionKey="statistics" type="domdoc"/> <Forward name="success" path="sendToPrintBridge"/> </XsltPipe>
Using an Oracle database
Question: How to use the Frank!Framework with an Oracle database?
Answer: You may be used to installing Oracle on your development computer, but this is more complicated than necessary. For example if you have a corporate laptop, you should remember to use the right user account. On a corporate laptop you might have an admin account (WSA account) with administrator rights beside your normal user account. If you log in with your normal account and install Oracle, giving the installer administrator rights, then it does not work. You should log in with your admin account and then install Oracle.
You can avoid such issues by using a Docker container for your Oracle database. See the sources of the Frank!Framework for an example. Checkout https://github.com/ibissource/iaf and see directory
Inserting from XPath expression, default value null
Question: How to insert a table row from an XPath expression while using default value
Answer: You can use a FixedQuerySender to insert rows in a table. The values to insert are given in
<Param> elements. The value to insert can be given by an XPath expression, for example
<Param name="myParam" xpathExpression="/BIJKANT/PK/PK_NUMMER"/>. You cannot use the
defaultValue attribute to use a default value of
null, but you do not need to. When you omit the
defaultValue attribute, you will have
null when your XPath expression does not find anything.
Custom logging with log4j
You can write extra logging to (custom) log files using the
<LogSender>. When you do not set the logCategory, the message will be appended to the default Ibis4Name.log.
Currently the following log categories are available:
You can also create additional log categories by configuring a custom
log4jibis.xml in your
classes folder for non Maven projects) folder.
XSLT Testing with Larva
Question: How to test XSLT stylesheets with Larva?
Answer: Here is an example:
scenario.description = adapt input ldap insert into functionally expired passwords xpl.MaakLdapInput.className = nl.nn.adapterframework.testtool.XsltProviderListener xpl.MaakLdapInput.filename = ../../../JavaSource/CheckPasswordFunctionalExpired/xsl/AdaptInputLdapInsertIntoPasswordFunctionalExpired.xsl step1.xpl.MaakLdapInput.read = scenario01/step1.xml step1.xpl.MaakLdapInput.read.param1.name = userType step1.xpl.MaakLdapInput.read.param1.value = WN step2.xpl.MaakLdapInput.write = scenario01/step2.xml
No adapter restart needed after editing Larva tests
Question: I edited my Larva tests. Do I have to restart the Frank!Runner or reload my configurations?
Answer: No. When you edit your Larva tests, you can run them immediately and the Frank!Framework will use the updated files.
Parameters in Larva tests
Question: How to pass parameters to Larva services?
Answer: You can pass a parameter by referencing the value from a file, or you can put the value directly in your scenario. Here is an example of the latter:
And here is an example of fetching the value from a file:
Transaction attribute on receiver or pipeline?
Question: Both the
<Receiver> and the
<Pipeline> tag has attribute
transactionAttribute. Which element should you choose?
Answer: Normally you should choose the
<Receiver>. There are two reasons for this. First, the purpose of a transaction is that all data modifications should succeed or none should happen. The
<Receiver> already does part of the work, for example accepting a message from a queue. The second reason is that a pipeline can be fed by multiple receivers. Typically, some receivers support transactions and some do not. If a receivers that supports transactions has the
transactionAttribute, the pipeline after the receiver will inherit the transaction. If another receiver does not support transactions, then that receiver does not have a
transactionAttribute. In that case, there is no transaction as intended, because there is no
transactionAttribute on the pipeline and the pipeline does not inherit a transaction.
Load multiple configs at once
Question: I have about 20 different jars that I want to upload. How can I use the “Multiple Configurations” checkbox in the “Upload Configuration” screen (see below) to upload them all at once?
Answer: Pack all your configuration jar files into a single .zip, check the box and upload the zip file containing all the configurations you would like to upload.
Question: What is the use of the property configurations.<configname>.parentConfig exactly?
Answer: It changes the classloading of files and properties. In simpler terms, for every file or property the framework has to load, it will first look it up as a global setting (eq. classpath) then in the local configuration, then (if specified) the parent configuration, and lastly the war (
src/main/resources). Class loading is described in subsection How Properties Are Set, but that section needs some editing because the phrases “system property” and “classpath property” are used in a confusing way.
Flow diagram images
Question: The Frank!Console shows flow diagrams of Frank configurations. Where can I find image files of these diagrams?
Answer: There is a property
flow.adapter.dir. It holds the directory where the diagrams are saved as images. The Frank!Framework sets this property automatically. You can find the value of this property by choosing “Environment Variables” from the main menu of the Frank!Console.
XmlSwitchPipe exception “Premature end of file”
Question: Why does
XmlSwitchPipe throw “Premature end of file”?
Answer: As the pipe name indicates, it expects the input message to be valid XML. When the input is not in XML format or if the XML is invalid, this error is thrown. You have to configure an XSLT stylesheet that is applied to the incoming message. The pipe uses the result of the transformation as the forward to follow. See also GitHub issue https://github.com/ibissource/iaf/issues/1020.
Additional: But with the attribute
sessionKey, the XmlSwitchPipe can work without an XSLT transformation, the attribute value being used directly as the forward to follow.
Test ApiListener with authentication (without Larva)
Question: How can I locally test an ApiListener with authentication (without Larva)?
Answer: In the configuration, make the authenticationMethod a configurable property (for example
In StageSpecifics_LOC.properties, configure:
Question: Where can I find why Liquibase validation failed?
Answer: There will be a warning on the Frank!Console when Liquibase validation fails. From version 7.6 onwards, this warning includes the reason why validation failed. For older versions, no reason will be in that warning. You can also find the reason in the regular logfile when the log level is WARN or lower. Setting the log level is described here: https://frank-manual.readthedocs.io/en/latest/operator/diskUsage.html?highlight=log%20level#disk-usage.
Filling adapter response with session key
Question: My adapter stores some result in a session key. How can I change my adapter such that it produces a response message filled with the value of the session key?
Answer: Use the
EchoPipe. It is described in the Frank!Doc, see https://frank-manual.readthedocs.io/en/latest/gettingStarted/configurationSyntaxChecking.html.
Reading auto-generated keys when inserting into database
Question: I am inserting into or updating a database table that auto-generates values, which may be primary keys or the results of database functions. How can I get these values in my adapter?
Answer: You can use a
FixedQuerySender with an “INSERT” or “UPDATE” query. Fill the attribute
columnsReturned of the
FixedQuerySender with the columns for which you want to have the values. This is a comma-separated list of column names. See the Frank!Doc for more details.
This feature of the Frank!Framework does not work for all database drivers and/or versions. See issue https://github.com/ibissource/iaf/issues/1468.
By default, the value is wrapped into an XML message. If you just want a scalar, you can set the
scalar attribute of the
Iterating over CSV file
Question: How to iterate over a .csv file?
Answer: Here is an example to download:
Frank config. This example applies a
BatchFileTransformerPipe. This pipe may be more complicated to use then needed. Since version 7.6 you can use a
Liquibase script does not seem to work with H2 in-memory database
Question: I have a Frank config that uses an in-memory H2 database. When I load it into the Frank!Framework I see that there is no IBISSTORE database table, even though the catalina log shows correct execution of Liquibase. If I change the URL to have a file H2 database, the IBISSTORE table is created as it should. How is this possible?
Answer: You need to use the correct
driverClassName attributes in the
<Resource> element of
<Resource name="jdbc/ibis4pt" type="javax.sql.DataSource" driverClassName="org.h2.Driver" url="jdbc:h2:mem:ibis4pt" />
Watching the startup of the F!F
Question: I am starting my configuration with the F!F running on Apache Tomcat. How can I see whether my application is ready to receive HTTP requests?
Answer: You can open a browser and navigate to the main URL of the Frank!Framework, typically
http://localhost in a development environment. If you see the Frank!Framework on this URL, it is done with its startup. Alternatively, you can look at the console output. When you work with the Frank!Runner, take care to look at the console window that is created during boot, not the original command prompt from which you start the Frank!Runner. You see many messages passing by in the console. When you see
INFO [main] org.apache.catalina.core.ApplicationContext.log Starting IbisContext, Apache Tomcat has loaded the Frank!Framework and the Frank!Framework’s startup code starts executing. When you see
INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [xxx] milliseconds, the Frank!Framework should be ready to receive HTTP requests.