Question

I am trying to use <xe:jdbcConnectionManager> with <xe:jdbcRowSet>. Should this work? The book (XPages Extension Library) seems to imply it should, but the example NSF (XPagesJDBC.nsf) does not contain any examples with that combination. Of course, the jdbcRowSet accepts connectionManager attribute.

I get this error:

com.ibm.xsp.FacesExceptionEx: Unknown ConnectionManager jdbcConnectionManager1
com.ibm.xsp.extlib.util.JdbcUtil.createManagedConnection(JdbcUtil.java:106)
com.ibm.xsp.extlib.jdbc.model.JdbcRowSetAccessor.findConnection(JdbcRowSetAccessor.java:467)

EXTLIB CODE

The problem seems to be in JdbcUtil.java function findConnectionManager(). It returns null and that's why I get the above exception. Here's the function:

public static IJdbcConnectionManager findConnectionManager(FacesContext context, UIComponent from, String name) throws SQLException {
    UIComponent c = FacesUtil.getComponentFor(from, name);
    if(c!=null) {
        return (IJdbcConnectionManager)c;
    }
    return null;
}

The parameter name is not null since it is referenced in the exception message. The parameter contextis not used at all. And the parameter from, if null, is acquired like this (on row 102): from = context.getViewRoot();.

Here's the function throwing the exception:

public static Connection createManagedConnection(FacesContext context, UIComponent from, String name) throws SQLException {
    if(from==null) {
        from = context.getViewRoot(); // ROW 102
    }
    IJdbcConnectionManager manager = findConnectionManager(context, from, name);
    if(manager==null) {
        throw new FacesExceptionEx(null,"Unknown ConnectionManager {0}",name); // ROW 106
    }
    return manager.getConnection();
}

MY CODE

So, this works:

<xp:this.data>
<xe:jdbcRowSet var="jdbcRowSet1" maxRows="10"
  sqlQuery="SELECT * FROM test.reportcode;"
  connectionName="mysql_pooled">
</xe:jdbcRowSet>
</xp:this.data>

And this doesn't work:

<xe:jdbcConnectionManager id="jdbcConnectionManager1"               
  connectionName="mysql_pooled">
</xe:jdbcConnectionManager>

<xp:this.data>
<xe:jdbcRowSet var="jdbcRowSet1" maxRows="10"
  sqlQuery="SELECT * FROM test.reportcode;"
  connectionManager="jdbcConnectionManager1">
</xe:jdbcRowSet>
</xp:this.data>

Note that the connectionName is identical, and works perfectly when used directly by jdbcRowSet. The only change is replacing that attribute with a reference to jdbcConnectionManager using that same connectionName. The setup works also perfectly with the jdbcQuery datasource.

How can I make this work? Or can it be done?

Was it helpful?

Solution

NOTE: I'm guessing you know why adding a panel fixes the problem, but I'm including additional detail for the benefit of others who might encounter the same behavior.

Almost everything in XPages is processed hierarchically. So variables, data sources, and component references are often only valid within the context of a container.

Given the source code you listed in your question, the data source is attached to the "view root", so it's valid anywhere on that page (or Custom Control). As the page is evaluated at runtime, the root component will be processed first, and part of that evaluation is determining whether the data source attached to it needs to be created or already exists, based on its scope.

Once that's finished, it can start processing any child components, which -- again, in your example -- includes the jdbcConnectionManager.

This is why, as Panu mentioned, the data source can't refer to the component: it's attached to a parent.

But data sources can be associated with specific panels, not just view roots. If you add a panel as a sibling to the jdbcConnectionManager -- specifically, below it -- and move the data source to that panel, here's what then happens at runtime:

  • Domino starts processing the view root; not much to do here now, so it just hands off control to its children.
  • The first child is the jdbcConnectionManager, so whatever encoding needs to happen for that component occurs before dealing with the rest.
  • Next, the panel is evaluated. This includes evaluating the data source, which can now refer to the connection manager component, since it has already been loaded.
  • Finally, all of the panel's descendant components (its children, their children, and so on) are evaluated. So anything that needs to refer to the data source does need to be defined somewhere inside this panel, but the data source can refer to the connection manager without blowing up specifically because that component isn't inside the panel... it's already been processed by the time the panel is dealt with.

OTHER TIPS

The component xe:jdbcConnectionManager does not exist yet when <xp:this.data> is computed. Components often use XPage datasource and probably that's why datasource is computed before components are created.

You could try setting the connectionManager for example in afterPageLoad event.

EDIT

One thing to check is SPR#MKEE86YD5L Also search for components that are within facets. Not sure if this has been fixed or not.

it is because of sqljdbc driver bug. The code works fine with mysql.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top