Java DataProcessor

Are there samples of DataProcessor in java? Can someone give me a link? Thanks!

PS - My server side is java based and the data that will populate the tree and grids will not be directly from a database, but will be retrieved using a JCR API on the server side. So, I’m assuming I cannot use dhtmlxConnector (as it is designed to work directly with the DB)? but will need to write a DataProcessor on the server side that will map the operations to the JCR APIs… is that correct?

Package at
dhtmlx.com/x/download/regula … 9_java.zip
contains samples.war

So, I’m assuming I cannot use dhtmlxConnector
To load data you can just use any custom script which will format data as valid XML ( which can be loaded by grid or tree)

To save data you can
a) create your custom solution
b) still use connector, but instead of its auto-updates, attach custom code to onBeforeProcessing server side event, and provide your own code for data saving. In such case connector will maintain data protocol with grid, while your custom code will do actual saving.

I have a question on the proposed approach:

“To save data you can
a) create your custom solution
b) still use connector, but instead of its auto-updates, attach custom code to onBeforeProcessing server side event, and provide your own code for data saving. In such case connector will maintain data protocol with grid, while your custom code will do actual saving.”

In my case I have no database. Wouldn’t I need to allocate a GridConnector(conn) in my “configure()” method, passing in a connection object to a DB?

What I need to do is just get control whenever the grid is updated, a row is added, deleted, etc.

I think what you are saying is (please correct me if I’m wrong):

  1. Create a “MyConnectorServlet” class which extends ConnectorServlet()
  2. Override “configure()” and create a GridConnector instance (but I have no DB connection?)
  3. Create a “MyConnectorBehavior” class which extends ConnectorBehavior
  4. Attach my behavior class to the Grid Connector: "grid.event.attach(new MyConnectorBehavior());
  5. Override the beforeProcessing method and add my custom “save” logic

Connection object will not be used if you will handle all logic through onBeforeProcessing, so you can provide a null value.

What I need to do is just get control whenever
BeforeProcessing behavior - it will be called for all operations
docs.dhtmlx.com/doku.php?id=dhtm … ex_updates

I think what you are saying is
Yep, exactly.

Stanislav:

It is not quite working… :unamused:

I have a grid control and am using loadXML() to fetch the content from a servlet. This part works OK.

I have attached a DataProcessor to the grid to handle updates, like this:

    			var dp = new dataProcessor("rulesummaryupdate");
    			dp.init(rulegrid);

I have created a new Servlet which extends ConnectorServlet to handle the updates. This is not the same servlet that is used for the load. The URL mapping is “rulesummaryupdate”.

When I click on a row and edit a cell, I receive control in my new servlet in the configure() method.

Then, I have the following code in configure():

            GridConnector gc = new GridConnector(null);  // No connection object
	gc.event.attach(new RuleSummaryConnectorBehavior());

This executes with no exceptions, but none of the override methods get control in RuleSummaryConnectorBehavior.

For example, I expected “beforeProcessing” would get control (below). Actually, I overrode all methods but none of them get control. What am I missing?

public class RuleSummaryConnectorBehavior extends ConnectorBehavior {

@Override
public void beforeProcessing(DataAction action) {
// Breakpoint set on next line, never gets control
	System.out.println(action);
	
	super.beforeProcessing(action);
}

You need to have one more command

GridConnector gc = new GridConnector(null); // No connection object
gc.event.attach(new RuleSummaryConnectorBehavior());
gc.render_table(“table”,“id”,“fieldA,fieldB”);

the first two parameters doesn’t matter, the third one - list of fields - those will be field names, which you will be able to access through action.get_value

the names can be not related to actual table or fields, because there will be no connector to the real DB in any case.

I am getting a NullPointerException in DBDataWrapper… seems it is assuming there is a connection?

protected Statement getStatement() throws SQLException{
	return [b]this.get_connection()[/b].createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
}

Here is the stack trace:

java.lang.NullPointerException
at com.dhtmlx.connector.DBDataWrapper.getStatement(DBDataWrapper.java:336)
at com.dhtmlx.connector.DBDataWrapper.query(DBDataWrapper.java:351)
at com.dhtmlx.connector.DBDataWrapper.select(DBDataWrapper.java:214)
at com.dhtmlx.connector.BaseConnector.render(BaseConnector.java:308)
at com.dhtmlx.connector.BaseConnector.render_table(BaseConnector.java:210)
at com.dhtmlx.connector.BaseConnector.render_table(BaseConnector.java:178)
at com.genesyslab.brs.brgui.servlet.RuleSummaryDataConnectorServlet.configure(RuleSummaryDataConnectorServlet.java:28)
at com.dhtmlx.connector.ConnectorServlet.doGet(ConnectorServlet.java:28)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Unknown Source)

Do you have at the end of custom behavior

action.success()

or

action.error()

Those commands will inform that operation executed and no any automatic DB actions are required.

Also be sure that you are not using the same feed for data loading, because above solution is only actual for usage with DataProcessor ( which must be in send-all-data-at-once, send-by-post modes )

I added it, but I am not getting that far:

Below is the source for the DataConnectorServlet configure() method and the ConnectorBehavior class…

It dies inside MySQLDBDataWrapper.getStatement() since the connection is null. Why is it using MYSQLData wrapper anyway?

protected Statement getStatement() throws SQLException{
return this.get_connection().createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
}

Source code below…

@Override
protected void configure() {

	/**
	 * Initialize GridConnector object
	 * 
	 * Connection object will not be used if we are handling all logic
	 * through onBeforeProcessing, so you can provide a null value. 
	 */
	 
	GridConnector gc = new GridConnector(null);
	gc.event.attach(new RuleSummaryConnectorBehavior());
	
	/**
	 * There is no real DB (null connector) because we are overriding
	 * all save/update behavior. However you need to do the render_table
	 * with dummy values for table and id in order to make it work.
	 */
	gc.render_table("table","id","ID,Name,Hierarchy,Phase,Pending Deployment,Start Date,End Date,Order");

And here is the ConnectorBehavior… right now I’m only overriding beforeProcessing():

public class RuleSummaryConnectorBehavior extends ConnectorBehavior {

@Override
public void beforeProcessing(DataAction action) {
	// TODO Auto-generated method stub
	
	super.beforeProcessing(action);
	
	action.success();
}

}

Does anyone have an answer? Should I start modifying source code in the sample java (I hate to do that… I’m sure it is something simple I’m doing wrong!)… please help!

One thing I’ve noticed when stepping through the code. I make a change to one of the fields in the grid and press enter.

In stepping through GridConnector -->
render_table -> render() -> parse_request()->BaseConnector.parse_request()

protected void parse_request(){
if (dynloading)
request.set_limit(0, dynloading_size);

	if (http_request.getParameter("[b]editing[/b]")!=null)
		editing = true;
	
	if (http_request.getParameter("[b]ids[/b]")!=null)
		editing = true;
	
	//sorting
	HashMap<String,String> data = new HashMap<String,String>();

I notice that the following request parameters are null:
“editing”
“ids”

and in parse_request (below) I see that request parameters dhx_colls, posStart, and count are null. Is this expected?

protected void parse_request(){
super.parse_request();

	String colls = http_request.getParameter("dhx_colls");
	
	if (colls!=null){
		try {
			fill_collections(colls.split(","));
		} catch (ConnectorConfigException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
	
	String pos = http_request.getParameter("posStart");
	String count = http_request.getParameter("count");
	
	if (pos!=null || count!=null)
		request.set_limit(pos,count);

The result is in render(), I take the “editing == false” path and go into MYSQLDBDataWrapper.select() method, where it dies with a NPE because the
connection is null:

java.lang.NullPointerException
at com.dhtmlx.connector.DBDataWrapper.getStatement(DBDataWrapper.java:336)
at com.dhtmlx.connector.DBDataWrapper.query(DBDataWrapper.java:351)
at com.dhtmlx.connector.DBDataWrapper.select(DBDataWrapper.java:214)
at com.dhtmlx.connector.BaseConnector.render(BaseConnector.java:308)

Why are these request parameters coming from the grid control all null? Is there something
wrong on the client side? Or is this expected?

As I am stepping through the code I noticed something that may be a clue.

When in BaseConnector.parse_request(), the code looks for parameters “editing” and “ids”, both are null. Then in GridConnector.parse_request(), parameters “dhx_colls” and “posStart” and "count’ are also all null.

This causes us to go down the “editing == false” path in GridConnector.render(), which ultimately leads us to the NPE in DBDataWrapper because get_connection() returns null:

protected Statement getStatement() throws SQLException{
return this.get_connection().createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
}

Seems like the client grid is not sending down the proper parameters on the http request causing us to take a wrong turn?

Why are these request parameters coming from the grid control all null? Is there something
wrong on the client side? Or is this expected?

It seems that client side sends incorrect data to the server side, so it doesn’t recognize it as edit operation and process as data loading request.

Possible reasons

a) connector.js is not included on the page, or included before dataprocessor.js
b) you have reconfigured dataprocessor, if connector.js was included it is set to “send data by post”, “send all data at once” modes - if you changed any of this settings , then server side will not be able to recognize data saving mode.

Stanislav:

You were correct, the problem was that connector.js was included before the dhtmlxdataprocessor.js. I am not changing any of the other settings (“send data by post”, “send data all at once”, etc.).

I am now getting farther, but it is still failing. I am getting a null pointer exception because “status” is null (see detail below):

Actually, I’m seeing that in the post request (after I make an update to a column in the grid and hit enter), the only parameters being passed are: “editing=true” and “ids=1002”.

In stepping through the code, I noticed that in DataProcessor.process(), “status” is null. See the following code:

	for (int i=0; i<id_keys.length; i++){
			String id = id_keys[i];

HashMap<String,String> item_data = data.get(id);
String status = item_data.get("!nativeeditor_status");

			[b]DataAction action = new DataAction(status,id,item_data);[/b]
			result.add(action);
			inner_process(action);
	}

The HashMap item_data, only contains the following:
{id=1002}

So, the link “status = item_data.get(”!nativeeditor_status") returns null. This causes an exception further down stream in status_to_mode because “status” is null:

protected OperationType status_to_mode(String status) throws ConnectorOperationException{
if (status.equals(“updated”)) return OperationType.Update;
else if (status.equals(“inserted”)) return OperationType.Insert;
else if (status.equals(“deleted”)) return OperationType.Delete;

	throw new ConnectorOperationException("Unknown action type: "+status);

}

On the client side, I have included the debug log. I simply double click on one of the rows and make a change. When I hit enter, it sends the update request to the server:

Log:
row 1002 marked [updated,valid]
Initiating data sending for 1002
Initiating data sending for all rows
Sending all data at once
Server url: rulesummaryupdate?editing=true parameters

00 = &
_dhx_trim = function () { return this.replace(/ /g, " ").replace(/(^[ \t]*)|([ \t]*$)/g, ""); }
10 = i
_dhx_trim = function () { return this.replace(/ /g, " ").replace(/(^[ \t]*)|([ \t]*$)/g, ""); }
20 = d
_dhx_trim = function () { return this.replace(/ /g, " ").replace(/(^[ \t]*)|([ \t]*$)/g, ""); }
30 = s
_dhx_trim = function () { return this.replace(/ /g, " ").replace(/(^[ \t]*)|([ \t]*$)/g, ""); }
40 = =
_dhx_trim = function () { return this.replace(/ /g, " ").replace(/(^[ \t]*)|([ \t]*$)/g, ""); }
50 = 1
_dhx_trim = function () { return this.replace(/ /g, " ").replace(/(^[ \t]*)|([ \t]*$)/g, ""); }
60 = 0
_dhx_trim = function () { return this.replace(/ /g, " ").replace(/(^[ \t]*)|([ \t]*$)/g, ""); }
70 = 0
_dhx_trim = function () { return this.replace(/ /g, " ").replace(/(^[ \t]*)|([ \t]*$)/g, ""); }
80 = 2
_dhx_trim = function () { return this.replace(/ /g, " ").replace(/(^[ \t]*)|([ \t]*$)/g, ""); }
_dhx_trim

Latest version of dataprocessor and connector js are attached
Be sure that you are using grid 2.6 ( not 2.5 )
codebase.zip (6.36 KB)

The new code did the trick! Thank you…:slight_smile:

Is there a way to get access to the HTTP Session inside beforeProcessing?

I see that HttpRequest is passed into beforeOutput() but not to any other function. I need to be able to store and retrieve session related data.

You can override doGet or doPost method of servlet class, and store values from session for later usage.

Something like
viewtopic.php?f=14&t=11331&start=0

If I am doing an addRow() on the grid, and specifying an index (third, optional parameter), how is this passed on to the ConnectorBehavior class?

I am looking through DataAction and cannot find where the desired “index” is passed into the servlet, so that it would be added in the correct location.

Thank you!
Mike

index info is not sent to server side normally
You can store index in the userdata of row ( grid.setUserData ) - all userdata records will be sent with row’s info, and available in both request and through action.get_value(name)