简体   繁体   中英

XML-RPC stateful Java server not working

I dont understand what I may be doing wrong.

I am trying to follow this tutorial to implement a stateful servlet.

My org.apache.xmlrpc.webserver.XmlRpcServlet.properties looks like this:

com.mydbm.MyDBM=com.mydbm.MyDBMImpl

This is MyDBM interface and MyDBMImpl Code:

public interface MyDBM {
  public void setUp(DBConnection dbc) throws ClassNotFoundException, 
       SQLException, JSchException;

   public ArrayList<Database> getDatabases() throws SQLException; 

  .....
}
public class MyDBMImpl implements MyDBM {
private volatile Connection connection;
private volatile Class<?> driverClass;
private volatile Statement statement;
private volatile DBConnection dbConn;

@Override
public void setUp(DBConnection dbc) throws ClassNotFoundException,
        SQLException, JSchException {
    this.dbConn = dbc;
    if (dbConn.SSHEnabled()) {
        LOG.info("SSH Requested, enabling...");
        setUpSshConnection();
        LOG.info("SSH enabled!");
    } else {
        LOG.info("SSH not Requested, skipping...");
    }
    setupConnection();


}   
    .....

    @Override
public ArrayList<Database> getDatabases() throws SQLException {

    switch (dbConn.getDatabaseType()) {  // NULL POINTER EXCEPTION HERE, 
    case MYSQL:
        return getDatabasesMySQL();
    case MSSQLSERVER:
        return getDatabasesMSServerSQL();
    case SQLITE:
        return getDatabasesSQLite();
    case SYBASE:
        return getDatabasesSyBase();
    case POSTGRESQL:
        return getDatabasesPostgreSQL();
    case ORACLE:
        return getDatabasesOracle();
    }
    return null;
}

The following is my Handler Code:

public class MyDBMXmlRpcRequestProcessorFactoryFactory implements
    RequestProcessorFactoryFactory {
private final RequestProcessorFactory factory = new MyDBMRequestProcessorFactory();
private final MyDBM dbm;

public MyDBMXmlRpcRequestProcessorFactoryFactory(
        MyDBM dbm) {
    this.dbm = dbm;
}

@Override
public RequestProcessorFactory getRequestProcessorFactory(Class aClass)
        throws XmlRpcException {
    return factory;
}

private class MyDBMRequestProcessorFactory implements
        RequestProcessorFactory {
    @Override
    public Object getRequestProcessor(XmlRpcRequest xmlRpcRequest)
            throws XmlRpcException {
        return dbm;
    }
}

}

This is my Server Code:

    public class Server {
private static final int port = 8080;

public static void main(String[] args) throws Exception {
    WebServer webServer = new WebServer(port);
    XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer();
    PropertyHandlerMapping phm = new PropertyHandlerMapping();

    MyDBM dbm = new MyDBMImpl();
    phm.setRequestProcessorFactoryFactory(new   MyDBMXmlRpcRequestProcessorFactoryFactory(
            dbm));
    phm.setVoidMethodEnabled(true);
    phm.addHandler(MyDBM.class.getName(),
            MyDBM.class);
    xmlRpcServer.setHandlerMapping(phm);

    XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer
            .getConfig();
    serverConfig.setEnabledForExtensions(true);
    serverConfig.setContentLengthOptional(false);
    webServer.start();

}

}

web.xml content extract:

<web-app>
<!-- SOME PARTS LEFT OUT ->
<servlet>
<servlet-name>XmlRpcServlet</servlet-name>
<servlet-class>org.apache.xmlrpc.webserver.XmlRpcServlet</servlet-class>
<init-param>
  <param-name>enabledForExtensions</param-name>
  <param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>XmlRpcServlet</servlet-name>
<url-pattern>/xmlrpc</url-pattern>
</servlet-mapping>
</web-app>

And finally here is my Client Code:

public class MyClient {


  public static void main(String[] args) throws Exception {
      // create configuration
      XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
      config.setServerURL(new URL("http://127.0.0.1:8080/xmlrpctest/xmlrpc"));
      config.setEnabledForExtensions(true);  
      config.setConnectionTimeout(60 * 1000);
      config.setReplyTimeout(60 * 1000);

      XmlRpcClient client = new XmlRpcClient();

      // use Commons HttpClient as transport
      client.setTransportFactory(
          new XmlRpcCommonsTransportFactory(client));
      // set configuration
      client.setConfig(config);
           // make a call using dynamic proxy
      ClientFactory factory = new ClientFactory(client);

      MyDBM dbm = (MyDBM)factory.newInstance(MyDBM.class);
      try {
       dbm.setUp(new DBConnection("myconn", DatabaseType.MYSQL, "localhost", 0, "userid", "secret", "mysql")); // Connection is setup correctly
       ArrayList<Database> dbs = dbm.getDatabases(); // Fails with NullPointerException

      } catch(Exception e) {
          System.out.println(e.getCause().getMessage());
          e.printStackTrace();
      }
  }

}

Error log:

Sep 27, 2013 11:49:26 AM com.myapp.MyDBMImpl setUp
INFO: SSH not Requested, skipping...
jdbc:mysql://localhost/mysql?user=userid&password=secret
Sep 27, 2013 11:49:26 AM org.apache.xmlrpc.server.XmlRpcErrorLogger log
SEVERE: Failed to invoke method getDatabases in class com.myapp.MyDBMImpl: null
org.apache.xmlrpc.common.XmlRpcInvocationException: Failed to invoke method  getDatabases in class com.myapp.MyDBMImpl: null

The dbm.setUp(..) method executes correctly and creates the dbConn object on the server. However, when I ran the dbm.getDatabases(), I get a null pointer exception and I believe its because the server creates a new instance of the handler instead of using the initial state of the handler. I am not expert in this but from this tutorial, I was expecting that once dbConn has been set-up, I would be able to use it in subsequent invocations .

Someone kindly assist,I have no Idea where I may be going wrong as I followed the instructions from the tutorial to the latter.

I have tried to past as much information and I would be willing to add more if necessary.

Thank you.

Yes your problem is, that the server creates a new instance every time. I ran into the same problem and solved it with an extra handler class in which i invoked the instance of the earlier handler.

Something like this:

public class MyDBMXmlRpcRequestProcessorFactoryFactoryWrapper
{
   private MyDBMXmlRpcRequestProcessorFactoryFactoryWrapper attribute;
   public MyDBMXmlRpcRequestProcessorFactoryFactoryWrapper(class param)
   {
        attribute = MyDBMXmlRpcRequestProcessorFactoryFactory(param);
   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM