将 BIRT 与 Esproc 集成

Integrating BIRT with Esproc

我们在 BIRT 报告中使用 Esproc 已经有一段时间了,一切都运行良好。我们按照 this 教程进行操作,一切正常。然而,他们软件的最新版本包含了一些新功能,因此,我们现在需要升级版本 运行 BIRT。问题是,现在什么都不管用了。我们在尝试 运行 报告时不断收到 NullPointerException。这是我们目前得到的结果:

The following report will be sent to Eclipse:

------
STATUS
------
pluginId            org.eclipse.jface
pluginVersion       3.12.0.v20160518-1929
code                2
severity            4
message             Problems occurred when invoking code from plug-in: "org.eclipse.jface".
fingerprint         eb22eddc61b2abbaef12193bb7441fab

Exception:java.lang.NullPointerException: null
     at com.esproc.jdbc.Server.getDfxList(Unknown Source:88)
     at com.esproc.jdbc.InternalConnection.getMetaData(Unknown Source:314)
     at org.eclipse.birt.report.data.oda.jdbc.ui.provider.JdbcMetaDataProvider.isSupportSchema(JdbcMetaDataProvider.java:305)
     at org.eclipse.birt.report.data.oda.jdbc.ui.editors.SQLDataSetEditorPage.createDBMetaDataSelectionComposite(SQLDataSetEditorPage.java:405)
     at org.eclipse.birt.report.data.oda.jdbc.ui.editors.SQLDataSetEditorPage.createPageControl(SQLDataSetEditorPage.java:334)
     at org.eclipse.birt.report.data.oda.jdbc.ui.editors.SQLDataSetEditorPage.createPageCustomControl(SQLDataSetEditorPage.java:307)
     at org.eclipse.datatools.connectivity.oda.design.ui.wizards.DataSetWizardPage.createControl(DataSetWizardPage.java:123)
     at org.eclipse.datatools.connectivity.oda.design.internal.ui.DataSetEditorPageCore.createContents(DataSetEditorPageCore.java:74)
     at org.eclipse.jface.preference.PreferencePage.createControl(PreferencePage.java:241)
     at org.eclipse.birt.report.designer.data.ui.dataset.PropertyPageWrapper.createPageControl(PropertyPageWrapper.java:61)
     at org.eclipse.birt.report.designer.data.ui.property.PropertyNode.createPageControl(PropertyNode.java:238)
     at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog.showPage(AbstractPropertyDialog.java:577)
     at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog.showSelectionPage(AbstractPropertyDialog.java:482)
     at org.eclipse.birt.report.designer.data.ui.dataset.DataSetEditor.showSelectionPage(DataSetEditor.java:913)
     at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog.run(AbstractPropertyDialog.java:438)
     at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
     at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog.selectionChanged(AbstractPropertyDialog.java:433)
     at org.eclipse.jface.viewers.Viewer.run(Viewer.java:158)
     at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
     at org.eclipse.ui.internal.JFaceUtil.run(JFaceUtil.java:50)
     at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:173)
     at org.eclipse.jface.viewers.Viewer.fireSelectionChanged(Viewer.java:155)
     at org.eclipse.jface.viewers.StructuredViewer.updateSelection(StructuredViewer.java:2191)
     at org.eclipse.jface.viewers.StructuredViewer.setSelection(StructuredViewer.java:1728)
     at org.eclipse.jface.viewers.TreeViewer.setSelection(TreeViewer.java:1077)
     at org.eclipse.jface.viewers.Viewer.setSelection(Viewer.java:383)
     at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog.initTreeSelection(AbstractPropertyDialog.java:408)
     at org.eclipse.birt.report.designer.data.ui.property.AbstractPropertyDialog.createDialogArea(AbstractPropertyDialog.java:299)
     at org.eclipse.birt.report.designer.data.ui.dataset.DataSetEditor.createDialogArea(DataSetEditor.java:124)
     at org.eclipse.jface.dialogs.Dialog.createContents(Dialog.java:767)
     at org.eclipse.birt.report.designer.data.ui.dataset.DataSetEditor.createContents(DataSetEditor.java:602)
     at org.eclipse.jface.window.Window.create(Window.java:426)
     at org.eclipse.jface.dialogs.Dialog.create(Dialog.java:1095)
     at org.eclipse.birt.report.designer.ui.dialogs.BaseDialog.open(BaseDialog.java:107)
     at org.eclipse.birt.report.designer.data.ui.actions.EditDataSetAction.doAction(EditDataSetAction.java:105)
     at org.eclipse.birt.report.designer.internal.ui.views.actions.AbstractElementAction.run(AbstractElementAction.java:70)
     at org.eclipse.jface.action.Action.runWithEvent(Action.java:473)
     at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:565)
     at org.eclipse.jface.action.ActionContributionItem.lambda(ActionContributionItem.java:397)
     at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
     at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4410)
     at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1079)
     at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4228)
     at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3816)
     at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1121)
     at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:336)
     at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1022)
     at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:150)
     at org.eclipse.ui.internal.Workbench.run(Workbench.java:687)
     at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:336)
     at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:604)
     at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:148)
     at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:138)
     at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
     at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
     at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
     at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:388)
     at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:243)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(null:-2)
     at sun.reflect.NativeMethodAccessorImpl.invoke(null:-1)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(null:-1)
     at java.lang.reflect.Method.invoke(null:-1)
     at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:673)
     at org.eclipse.equinox.launcher.Main.basicRun(Main.java:610)
     at org.eclipse.equinox.launcher.Main.run(Main.java:1519)

------
REPORT
------
anonymousId         12355fbc-cb0f-41c4-b330-1d4a60fd5df2
name                
email               
comment             
eclipseBuildId      4.6.0.I20160606-1100
eclipseProduct      org.eclipse.epp.package.reporting.product
javaRuntimeVersion  1.8.0_71-b15
osgiWs              win32
osgiOs              Windows10
osgiOsVersion       10.0.0
osgiArch            x86_64
severity            UNKNOWN

-------
BUNDLES
-------
name                org.eclipse.birt.report.data.oda.jdbc.ui
version             4.6.0.v201606072122

name                org.eclipse.birt.report.data.oda.jdbc
version             4.6.0.v201606072122

name                org.eclipse.birt
version             4.6.0.v201606072122

name                org.eclipse.birt.report.designer.ui
version             4.6.0.v201606072122

name                org.eclipse.birt.report.designer.ui.views
version             4.6.0.v201606072122

name                org.eclipse.core.databinding.observable
version             1.6.0.v20160511-1747

name                org.eclipse.core.databinding
version             1.6.0.v20160412-0910

name                org.eclipse.core.runtime
version             3.12.0.v20160606-1342

name                org.eclipse.datatools.connectivity.oda.design.ui
version             3.3.0.201603142002

name                org.eclipse.datatools.connectivity.oda.design
version             3.4.0.201603142002

name                org.eclipse.datatools.connectivity.oda
version             3.5.0.201603142002

name                org.eclipse.datatools.connectivity
version             1.13.0.201603142002

name                org.eclipse.e4.ui.workbench
version             1.4.0.v20160517-1624

name                org.eclipse.e4.ui.workbench.swt
version             0.14.0.v20160523-1900

name                org.eclipse.equinox.app
version             1.3.400.v20150715-1528

name                org.eclipse.equinox.launcher
version             1.3.200.v20160318-1642

name                org.eclipse.jface
version             3.12.0.v20160518-1929

name                org.eclipse.swt
version             3.105.0.v20160603-0902

name                org.eclipse.ui
version             3.108.0.v20160518-1929

name                org.eclipse.ui.ide.application
version             1.1.100.v20160518-1929

name                org.eclipse.ui.ide
version             3.12.0.v20160601-1609

有人知道发生了什么事吗?

谢谢

好的,所以我实际上能够让事情正常进行,而且解决方案并不完全是我所说的微不足道的。我实际上不得不修改并重新编译三个 BIRT classes。如果您不想进行 Google 搜索,您可以轻松获取源代码 here。不管怎样,我们的第一个修改是上面引用的错误信息给我们的。我们需要修改位于 org.eclipse.birt.report.data.oda.jdbc.ui_4.6.0.v201606072122.jar 包中的 JdbcMetaDataProvider.java。我们正在寻找的是 isSupportSchema() 方法。更具体地说,这段代码:

try
{
    return connection.getMetaData( ).supportsSchemasInTableDefinitions( );
}
catch ( SQLException e )
{
    try 
    {
        reconnect( );
        return connection.getMetaData( ).supportsSchemasInTableDefinitions( );
    }
    catch ( Exception e1 )
    {
        try
        {
            ResultSet rs = connection.getMetaData( ).getSchemas( );
            if( rs != null )
                return true;
            else
                return false;
        }
        catch (SQLException e2)
        {
            logger.log( Level.WARNING, e.getMessage( ), e1 );
            return false;
        }
    }
}

无法访问 Esproc 的代码,我不能确切地说出它为什么这样做,但是 connection.getMetaData( ).supportsSchemasInTableDefinitions( ); 会抛出 NullPointerException。由于没有 "catch" 块来处理上述异常,Eclipse 将停止执行并阻止您访问数据集。所以我们需要像这样修复它:

try
{
    return connection.getMetaData( ).supportsSchemasInTableDefinitions( );
}
catch ( SQLException e )
{
    try 
    {
        reconnect( );
        return connection.getMetaData( ).supportsSchemasInTableDefinitions( );
    }
    catch ( Exception e1 )
    {
        try
        {
            ResultSet rs = connection.getMetaData( ).getSchemas( );
            if( rs != null )
                return true;
            else
                return false;
        }
        catch (SQLException e2)
        {
            logger.log( Level.WARNING, e.getMessage( ), e1 );
            return false;
        }
    }
}
catch (NullPointerException e)
{
    return false;
}

现在,我们需要更改的下两位代码位于 oda-jdbc.jar 包中。我们正在寻找的第一个是 Connection.java class 更具体地说是方法 populateConnectionProp( ).

private void populateConnectionProp( ) throws SQLException
{
    if( jdbcConn!= null )
    {
        if( this.autoCommit != null )
            jdbcConn.setAutoCommit( this.autoCommit );
        else
        {
            if  (DBConfig.getInstance().qualifyPolicy(
                        jdbcConn.getMetaData().getDriverName(),
                        DBConfig.SET_COMMIT_TO_FALSE) ) {
                this.autoCommit = false;
                jdbcConn.setAutoCommit( false );
            }
        }
        if( this.isolationMode!= Constants.TRANSCATION_ISOLATION_DEFAULT)
            jdbcConn.setTransactionIsolation( this.isolationMode );
    }
}

这次抛出NullPointerException的罪魁祸首就是这一行jdbcConn.getMetaData().getDriverName()。同样,无法访问 Esproc 的代码,我真的不知道为什么尝试恢复驱动程序的名称不起作用,但无论如何我们需要做的实际上是捕获异常并且一切都会再次正常工作:

private void populateConnectionProp( ) throws SQLException
{
    if( jdbcConn!= null )
    {
        if( this.autoCommit != null )
            jdbcConn.setAutoCommit( this.autoCommit );
        else
        {
            try
            {
                if  (DBConfig.getInstance().qualifyPolicy(
                            jdbcConn.getMetaData().getDriverName(),
                            DBConfig.SET_COMMIT_TO_FALSE) ) {
                    this.autoCommit = false;
                    jdbcConn.setAutoCommit( false );
                }
            }
            catch(NullPointerException e)
            {
                this.autoCommit = false;
                jdbcConn.setAutoCommit( false );
            }
        }
        if( this.isolationMode!= Constants.TRANSCATION_ISOLATION_DEFAULT)
            jdbcConn.setTransactionIsolation( this.isolationMode );
    }
}

我们正在寻找的另一个 class 是 CallStatement.java class。我们必须在其中找到我粘贴在下面的 getCallableParamMetaData() 方法:

private java.util.List getCallableParamMetaData( )
{
    java.util.List paramMetaDataList = new ArrayList( );
    try
    {
        DatabaseMetaData metaData = conn.getMetaData( );
        String cataLog = conn.getCatalog( );
        String procedureNamePattern = getNamePattern( this.paramUtil.getProcedure( ) );
        String schemaPattern = null;
        if ( this.paramUtil.getSchema( ) != null )
        {
            schemaPattern = getNamePattern( this.paramUtil.getSchema( ) );
        }

        // handles schema.package.storedprocedure for databases such as
        // Oracle
        if ( !metaData.supportsCatalogsInProcedureCalls( ) )
        {
            if (this.paramUtil.getPackage( ) != null)
            {
                cataLog = getNamePattern( this.paramUtil.getPackage( ) );
            }
        }

        java.sql.ResultSet rs = null;
        rs = metaData.getProcedureColumns( cataLog,
                schemaPattern,
                procedureNamePattern,
                null );
        while ( rs.next( ) )
        {
            ParameterDefn p = new ParameterDefn( );
            p.setParamName( rs.getString( "COLUMN_NAME" ) );
            p.setParamInOutType( rs.getInt( "COLUMN_TYPE" ) );
            p.setParamType( rs.getInt( "DATA_TYPE" ) );
            p.setParamTypeName( rs.getString( "TYPE_NAME" ) );
            p.setPrecision( rs.getInt( "PRECISION" ) );
            p.setScale( rs.getInt( "SCALE" ) );
            p.setIsNullable( rs.getInt( "NULLABLE" ) );
            if ( p.getParamType( ) == Types.OTHER )
                correctParamType( p );
            paramMetaDataList.add( p );
        }
        rs.close( );
    }
    catch ( SQLException e )
    {
        logger.log( Level.SEVERE, "Fail to get SP paramters", e );
    }
    catch( JDBCException ex)
    {
        logger.log( Level.SEVERE, "Fail to get SP paramters", ex );
    }

    return paramMetaDataList;
}

基本上,while ( rs.next( ) ) 循环中的某处是抛出 NullPointerException 的罪魁祸首。所以我们需要做的就是添加一个 catch 语句来处理它如下:

private java.util.List getCallableParamMetaData( )
{
    java.util.List paramMetaDataList = new ArrayList( );
    try
    {
        DatabaseMetaData metaData = conn.getMetaData( );
        String cataLog = conn.getCatalog( );
        String procedureNamePattern = getNamePattern( this.paramUtil.getProcedure( ) );
        String schemaPattern = null;
        if ( this.paramUtil.getSchema( ) != null )
        {
            schemaPattern = getNamePattern( this.paramUtil.getSchema( ) );
        }

        // handles schema.package.storedprocedure for databases such as
        // Oracle
        if ( !metaData.supportsCatalogsInProcedureCalls( ) )
        {
            if (this.paramUtil.getPackage( ) != null)
            {
                cataLog = getNamePattern( this.paramUtil.getPackage( ) );
            }
        }

        java.sql.ResultSet rs = null;
        rs = metaData.getProcedureColumns( cataLog,
                schemaPattern,
                procedureNamePattern,
                null );
        while ( rs.next( ) )
        {
            ParameterDefn p = new ParameterDefn( );
            p.setParamName( rs.getString( "COLUMN_NAME" ) );
            p.setParamInOutType( rs.getInt( "COLUMN_TYPE" ) );
            p.setParamType( rs.getInt( "DATA_TYPE" ) );
            p.setParamTypeName( rs.getString( "TYPE_NAME" ) );
            p.setPrecision( rs.getInt( "PRECISION" ) );
            p.setScale( rs.getInt( "SCALE" ) );
            p.setIsNullable( rs.getInt( "NULLABLE" ) );
            if ( p.getParamType( ) == Types.OTHER )
                correctParamType( p );
            paramMetaDataList.add( p );
        }
        rs.close( );
    }
    catch ( SQLException e )
    {
        logger.log( Level.SEVERE, "Fail to get SP paramters", e );
    }
    catch( JDBCException ex)
    {
        logger.log( Level.SEVERE, "Fail to get SP paramters", ex );
    }
    catch( NullPointerException ex1)
    {
        logger.log( Level.SEVERE, "Fail to get SP paramters", ex1 );
    }
    return paramMetaDataList;
}

对文件进行修改后,您实际上需要重新编译源代码。要成功地做到这一点,您需要将几个 jar 从 Eclipse 的插件文件夹复制到您放置要编译的文件的同一文件夹中。这些罐子在您需要输入以编译源代码的命令中给出。以下是编译每个文件需要输入的内容:

JdbcMetaDataProvider.java

javac -cp ".;
c:/mypath/org.eclipse.birt.report.data.bidi.utils_4.6.0.v201606072122.jar;
c:/mypath/org.eclipse.birt.report.data.oda.jdbc.ui_4.6.0.v201606072122.jar;
c:/mypath/oda-jdbc.jar;
c:/mypath/org.eclipse.datatools.connectivity.oda_3.5.0.201603142002.jar;
c:/mypath/org.eclipse.datatools.connectivity.oda.design_3.4.0.201603142002.jar;
c:/mypath/org.eclipse.datatools.connectivity.oda.design.ui_3.3.0.201603142002.jar;
c:/mypath/org.eclipse.emf.ecore_2.12.0.v20160420-0247.jar;
c:/mypath/org.eclipse.emf.common_2.12.0.v20160420-0247.jar" JdbcMetaDataProvider.java > log.txt 2>&1

Connection.java

javac -cp ".;
c:/mypath/org.eclipse.birt.report.data.bidi.utils_4.6.0.v201606072122.jar;
c:/mypath/oda-jdbc.jar;
c:/mypath/org.eclipse.datatools.connectivity.oda_3.5.0.201603142002.jar;
c:/mypath/com.ibm.icu_56.1.0.v201601250100.jar" Connection.java > log.txt 2>&1

CallStatement.java

javac -cp ".;
c:/mypath/oda-jdbc.jar;
c:/mypath/org.eclipse.datatools.connectivity.oda_3.5.0.201603142002.jar;
c:/mypath/com.ibm.icu_56.1.0.v201601250100.jar" CallStatement.java > log.txt 2>&1

现在,关于上面的两个命令,有几点需要说明:

1) 它们实际上需要在一行中输入。为了清楚起见,我只是像这样将它们分解,以便很容易发现所需的每个罐子。

2) 这实际上是一个windows命令。如果你是 运行 Linux 上的命令,每个 jar 需要用冒号 (:) 而不是分号 (;) 分隔。

编译成功后,您将得到以下 .class 文件:

JdbcMetaDataProviderTempThread.class
JdbcMetaDataProviderTempThread.class
JdbcMetaDataProvider.class

Connection$Constants.class
Connection.class

CallStatement.class

需要将这些文件复制回原始 jar 文件,以便它们替换已经存在的文件。幸运的是,jar 文件只不过是一个 zip 文件,因此在 windows 中,任何解压缩软件都可以轻松地为您打开文件并允许您导航到正确的文件夹。

以下是每个 jar 的相关文件夹:

org\eclipse\birt\report\data\oda\jdbc\ui\provider\
org\eclipse\birt\report\data\oda\jdbc\
org\eclipse\birt\report\data\oda\jdbc\

完成后,重新启动 Eclipse,事情应该会再次正常进行。我希望这对以后的人有所帮助。