Pass connection from Java Application to Birt report - java

I'm new to Birt.
I'm trying to pass the connection to the report from my java application, but I get an error:
The following items have errors:
ReportDesign (id = 1):
+ There are errors evaluating script "importPackage(Packages.it.lfiammetta.birt); var conn = new
ReportRenderer();
reportContext.getAppContext().put("OdaJDBCDriverPassInConnection",
conn);": Fail to execute script in function __bm_beforeOpen(). Source:
" + importPackage(Packages.it.lfiammetta.birt); var conn = new
ReportRenderer();
reportContext.getAppContext().put("OdaJDBCDriverPassInConnection",
conn); + "
A BIRT exception occurred. See next exception for more information.
Error evaluating Javascript expression. Script engine error:
ReferenceError: "ReportRenderer" is not defined.
(/report/data-sources/oda-data-source[#id="43"]/method[#name="beforeOpen"]#2)
Script source:
/report/data-sources/oda-data-source[#id="43"]/method[#name="beforeOpen"],
line: 0, text:
__bm_beforeOpen(). (Element ID:1)
This is my java code that creates and launches report:
package it.lfiammetta.birt;
public class ReportRenderer {
public void executeReport() {
code...
Map<String, Object> appContext = task.getAppContext();
appContext.put("OdaJDBCDriverPassInConnection", myConnection);
appContext.put("OdaJDBCDriverPassInConnectionCloseAfterUse", false);
task.setAppContext(appContext);
task.run();
code...
}
}
This is the code I wrote in the script 'beforeOpen' the datasource:
importPackage(Packages.it.lfiammetta.birt);
var conn = new ReportRenderer();
reportContext.getAppContext().put("OdaJDBCDriverPassInConnection", conn);
I set the classpath.
Birt version I'm using is 4.2.1.
Thanks in advance for your help and I apologize for my English.

I'm doing that from Java code (IJDBCParameters - actually parameters for JDBC connections, I'm looking connection by name - OdaDataSourceHandle.getName()):
#SuppressWarnings("rawtypes")
private static void substituteJDBCConnections(IReportRunnable pReportRunnable) {
final Map<String, IJDBCParameters> jdbcConnections = reportParameters.getJdbcConnections();
if (jdbcConnections != null ){
for (Iterator iter = pReportRunnable.getDesignHandle().getModuleHandle().getDataSources().iterator(); iter.hasNext();){
// http://wiki.eclipse.org/Java_-_Execute_Modified_Report_(BIRT)
Object element = iter.next();
if (element instanceof OdaDataSourceHandle){
OdaDataSourceHandle dsHandle = (OdaDataSourceHandle) element;
String key = dsHandle.getName();
if (key == null){
continue;
}
IJDBCParameters jdbcParams = jdbcConnections.get(key);
if (jdbcParams == null){
continue;
}
try {
dsHandle.setProperty( "odaDriverClass", jdbcParams.getDriverName());
dsHandle.setProperty( "odaURL", jdbcParams.getConnectionString());
dsHandle.setProperty( "odaUser", jdbcParams.getUserName());
dsHandle.setProperty( "odaPassword", jdbcParams.getPassword());
} catch (SemanticException e) {
throw new UncheckedException(e);
}
}
}
}

Probably you fixed your issue already, but maybe someone will be looking for this in the future. First of all 4.2.x versions had problems with passed connections. I did not observed the same errors in 4.4.2.
Other thing, I do not get why you are trying to pass ReportRenderer as a connection in lines:
var conn = new ReportRenderer();
reportContext.getAppContext().put("OdaJDBCDriverPassInConnection", conn);
The passed object in here should be a java.sql.Connection object.
Therefore,
Map<String, Object> appContext = task.getAppContext();
appContext.put("OdaJDBCDriverPassInConnection", myConnection);
appContext.put("OdaJDBCDriverPassInConnectionCloseAfterUse", false);
task.setAppContext(appContext);
looks correct as long as myConnection is an implementation of java.sql.Connection

Related

JDBC callable statement executes locally, but "The value is not set for the parameter number 2" when run in Jenkins

I'm using jdbc.SQLServerDriver in a Java Maven project to insert test records into a test reporting database. When I run a test locally either through Intellij or by running 'mvn clean compile', 'mvn test' in Powershell, the records are successfully inserted into the database. However, when I run through Jenkins (declarative pipeline), I get the following error message: com.microsoft.sqlserver.jdbc.SQLServerException: The value is not set for the parameter number 2.
I have looked at several resources around CallableStatement and several StackOverflow posts about the error message, but I do not understand why the parameter would be set when running locally, but not in Jenkins.
Here is my Jenkinsfile:
pipeline {
agent any
stages {
stage('Compile') {
steps {
withMaven(maven: 'LocalMaven'){
bat 'mvn clean compile'
}
}
}
stage('Test') {
steps {
withMaven(maven: 'LocalMaven'){
bat 'mvn test'
}
}
}
}
}
Here is my code to execute the stored proc:
public static void ExecuteStoredProc(String procedureName, Hashtable parameters, Connection connection)
{
try {
String paraAppender;
StringBuilder builder = new StringBuilder();
// Build the paramters list to be passed in the stored proc
for (int i = 0; i < parameters.size(); i++) {
builder.append("?,");
}
paraAppender = builder.toString();
paraAppender = paraAppender.substring(0,
paraAppender.length() - 1);
CallableStatement stmt = connection.prepareCall("{Call "
+ procedureName + "(" + paraAppender + ")}");
// Creates Enumeration for getting the keys for the parameters
Enumeration params = parameters.keys();
// Iterate in all the Elements till there is no keys
while (params.hasMoreElements()) {
// Get the Key from the parameters
String paramsName = (String) params.nextElement();
// Set Paramters name and Value
stmt.setString(paramsName, parameters.get(paramsName)
.toString());
}
// Execute Query
stmt.execute();
} catch (Exception e) {
System.out.println(procedureName);
System.out.println(parameters.keySet());
System.out.println(e.getMessage());
}
}
}
Here are the values I am passing in in the Hashtable:
public static void CreateRun(Connection connection)
{
//Params
Hashtable table = new Hashtable();
table.put("Machine", "Machine");
table.put("ClientOS", "CLientOS");
table.put("Environment", "Environment");
table.put("Browser", "Browser");
table.put("BrowserVersion", "BrowserVersion");
table.put("RunBuild", "RunBuild");
table.put("DevMachine", "1");
table.put("ExpectedCases", "1");
DatabaseUtil.ExecuteStoredProc("sp_CreateRun",table, connection );
}
And here is the stored proc:
... PROC [dbo].[sp_CreateRun]
#Machine varchar(45),
#ClientOS varchar(45),
#Environment varchar(45),
#Browser varchar(45),
#BrowserVersion varchar(45),
#RunBuild varchar(45),
#DevMachine bit,
#ExpectedCases int
AS
BEGIN
INSERT into Run (Start_Time, End_Time, Machine, Client_OS, Environment, Browser, Browser_Version, Run_Build, Dev_Machine, Expected_Cases)
values (GETDATE(),GetDate(),#Machine,#ClientOS,#Environment,#Browser, #BrowserVersion,#RunBuild,#DevMachine,#ExpectedCases)
END
Thanks in advance for taking a look.
Thanks, all, for the helpful comments. I never did figure out how to make this work with CallableStatement, but I did get it working both locally and on Jenkins using Spring SimpleJdbcCall. I really like how much cleaner the code is now.
public static void ExecuteStoredProc(String procedureName, Map<String, String> parameters)
{
JdbcTemplate template = new JdbcTemplate(SpringJDBCConfig.sqlDataSource());
MapSqlParameterSource sqlParameterSource = new MapSqlParameterSource();
for (String key : parameters.keySet()) {
sqlParameterSource.addValue(key, parameters.get(key));
}
SimpleJdbcCall call = new SimpleJdbcCall(template)
.withCatalogName("matrix")
.withSchemaName("dbo")
.withProcedureName(procedureName);
call.execute(sqlParameterSource);
}

Whats the correct and efficient way to delete a versioned document in Filenet P8 4.5 or higher?

I want to delete documents for which a specific property has been set in the current version. If this property has been set all versions of that document need to be removed.
My current implementation which searches for IsCurrentVersion = TRUE and foo = 'bar' has the problem that only the current version gets removed and not the older ones. So I assume that I need to delete the complete VersionSeries ?
Till now I use
doc.delete();
doc.save(RefreshMode.NO_REFRESH);
for each document I find. How can I retrieve all documents from the series and have them deleted too ? And is it more efficient if I add this to a batch ?
You should call the
delete()
method for the VersionSeries (http://www-304.ibm.com/support/knowledgecenter/SSNW2F_5.2.0/com.ibm.p8.ce.dev.java.doc/com/filenet/api/core/VersionSeries.html) instance,
VersionSeries vs = doc.getVersionSeries();
vs.delete();
vs.save(Refresh.NO_REFRESH);
Quote from docs
Caution: The delete and moveContent methods impact all document versions in the version series. That is, all document versions are deleted, and the content of all document versions are moved.
Method for deleting all the versions of a document from FileNet
public void deleteDocumentFromCE(String filenetDocGUID) throws Exception
{
System.out.println("In deleteDocumentFromCE() method");
System.out.println("Input Parameter filenetDocGUID is : " + filenetDocGUID);
Document document = null;
UserContext uc = null;
ObjectStore os = null;
Subject subject = null;
VersionSeries vs = null;
try
{
if (filenetDocGUID != null)
{
getCESession(); //This method will get the CE session and set it in ceSessionData private class variable
os = ceSessionData.getObjectStore();
System.out.println("ObjectStore fetched from CESession static reference is : " + os.get_Name());
subject = ceSessionData.getSubject();
System.out.println("Subject fetched from CESession static reference.");
uc = UserContext.get();
uc.pushSubject(subject);
if (os != null)
{
document = Factory.Document.fetchInstance(os, filenetDocGUID, null);
vs = document.get_VersionSeries();
vs.delete();
vs.save(RefreshMode.NO_REFRESH);
System.out.println("All Document Versions deleted : " + filenetDocGUID);
}
else
{
System.out.println("Error :: Object Store is not available.");
}
}
}
catch (Exception e)
{
System.out.println("Exception in deleteDocumentFromCE() Method : "+ e.getMessage());
//pass the error to the calling method
throw new Exception("System Error occurred while deleting the document in CE.. "+e.getMessage());
}
finally
{
if (uc != null)
uc.popSubject();
}
System.out.println("End of deleteDocumentFromCE() method");
}

WebSphere 7: WSCallbackHandlerImpl + InitialContext

When performing a programmatic login using WSCallbackHandlerImpl and there is no java.naming.provider.url set as a system property or in the jndi.properties file, one needs to call:
Object obj = initialContext.lookup("");
prior to performing the login.
Afterwards the following code works:
LoginContext lc = null;
try {
lc = new LoginContext("WSLogin",
new WSCallbackHandlerImpl("userName", "realm", "password"));
} catch (LoginException le) {
System.out.println("Cannot create LoginContext. " + le.getMessage());
// insert error processing code
} catch(SecurityException se) {
System.out.printlin("Cannot create LoginContext." + se.getMessage();
// Insert error processing
}
See: http://publib.boulder.ibm.com/infocenter/wsdoc400/v6r0/index.jsp?topic=/com.ibm.websphere.iseries.doc/info/ae/ae/xsec_jaas.html
Neither the obj nor the initialContext gets passed to the WSCallbackHandlerImpl or the LoginContext.
According to the Javadoc, InitialContext.lookup("") returns a new instance of the context.
Questions:
Why is this empty string lookup needed in this case?
How does WSCallbackHandlerImpl get the server URL?
Is this WebSphere specific?

Object doesn't support this method or property error

Hi I created a jni jar and i call the jar using applet in java script. I use the following applet tag to create a object to call jar functions through java script. when i call the function i got the following error Object doesn't support this method or property.
Here is my code.
document.write('<applet code="BiomAPI.Legend.class" width="0" height="0" archive="BiomAPI.jar" id="Obj"></applet>');
function GetTemplateAccurate (sUserID,iFingerID)
{
document.getElementsByName("Enroll")[0].value = "";
document.getElementsByName("Image")[0].value = "";
var lsFeature = null;
var lsImage = null;
Obj.EnableLog(0);
Obj.LocalFilePath("C:\\IMAGE\\");
Obj.EnableEncryption(0);
Obj.SaveImage(1);
Obj.SessionID("abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde");
Obj.GetFeatureAccrual(sUserID,iFingerID);
lsFeature = Obj.Feature();
lsImage = Obj.StringImage();
if (lsFeature != null && lsImage != null )
{
document.getElementsByName("Enroll")[0].value = lsFeature;
document.getElementsByName("Image")[0].value = lsImage;
alert("Scanner Working Properly");
}
else
{
alert("Fingerprint not captured");
}
}
function GetTemplate(sUserID,iFingerID)
{
document.getElementsByName("Verify")[0].value = "";
var lsFeature = null;
Obj.EnableLog(0);
Obj.LocalFilePath("C:\\IMAGE\\");
Obj.EnableEncryption(0);
Obj.SessionID("abcde");
Obj.SaveImage(1);
Obj.GetFeature(sUserID,iFingerID);
lsFeature = Obj.Feature();
lsImage = Obj.StringImage();
if (lsFeature != null)
{
document.getElementsByName("Verify")[0].value = lsFeature;
alert("Scanner Working Properly");
}
else
{
alert("Fingerprint not captured");
}
}
as exception itself is describing:
Object doesn't support this method or property error
the property or method you are trying to access with an object is not supported by that object. Please debug or see on error console the object throwing exception and find whether it support that property you are trying to access.

Cannot connect multiple times to mysql

I am writing an own databse in scala. To verify my results are correct, I check with a MySQL inside of a specs2 specification. I get the right result and everything is just fine. But if I run the test again without any changes, I get a SQLException: No suitable driver found for jdbc:mysql://localhost:3306/DBNAME?user=DBUSER (null:-1). Why is the driver not loaded again?
Edit
import java.sql.{ Connection, DriverManager, ResultSet }
import org.specs2.mutable.Specification
// SDDB imports ...
class DBValidationSpec extends Specification {
"SDDB and MySQl" should {
// SDDB
// ...
// JDBC
val connectionString = "jdbc:mysql://localhost:3306/sddb_test?user=root"
val query = """SELECT content, SUM( duration ) duration
FROM test
WHERE times
BETWEEN '2011-12-08'
AND '2011-12-09'
GROUP BY content"""
classOf[com.mysql.jdbc.Driver]
"give the same result" in {
// ...
//sddbResult
lazy val conn = DriverManager.getConnection(connectionString)
try{
val rs = conn.createStatement().executeQuery(query)
var mysqlResult = Map[List[String], Int]()
while (rs.next) {
mysqlResult += (rs.getString("content") :: Nil) -> rs.getInt("duration")
}
sddbResult == mysqlResult && sddbResult.size == 478 must beTrue
} finally {
conn.close()
}
}
}
}
I left out some parts of my code because they don't belong to the question.
Edit #2
The problem became even weirder. I added a second testcase. The testcase uses the same connectionString. The Exception was only raised once. The second test succeeded. I added sequential to my test definition and saw that only the first executed test raises the Exception. Afterwards I traced the classLoader to check if it is the same one. It is.
I did the following workaround:
trait PreExecuting extends Before {
override def before {
var conn: Option[Connection] = None
try {
val connectionString = "jdbc:mysql://localhost:3306/sddb_test?user=root"
conn = Some(DriverManager.getConnection(connectionString))
} catch {
case _ =>
} finally {
conn map (_.close())
}
}
}
I don't get the Exception any more because I suppress it by using the PreExecution tait. But I still wonder what is going wrong here.
I cannot pin down the error, to the following, but at least better also close the result set and statement.
val stmt = conn.createStatement()
val rs = stmt.executeQuery(query)
var mysqlResult = Map[List[String], Int]()
while (rs.next) {
mysqlResult += (rs.getString("content") :: Nil) -> rs.getInt("duration")
}
sddbResult == mysqlResult && sddbResult.size == 478 must beTrue
rs.close()
stmt.close()
It's seems to be a problem with the Driver registration, the Driver has to be registered some like this...
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
or some like this...
DriverManager.registerDriver(new DriverWrapper((Driver) Class.forName(props.getProperty("dbg.driver"), true, gcloader).newInstance()));
before use getConnection. I hope this help.
The driver is only loaded once.
No suitable driver usually means that the connection URL syntax is incorrect.

Categories