Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    FileItem/binary datasource field type

    When a datasource defines a field of type 'binary' and the datasource is applied to a ListGrid instance, as the user starts editing a cell relating to the field, a button with ellipsis is automatically placed into the cell which allows the user to select a file - this is great!

    However, in my IDACall extended class I am unable so far to get access to the byte stream that should be available via DSRequest.getUploadedFile() as this function returns null.

    I have read all the information in the Uploading Files section (SmartClient_Reference.html#group..upload) but there doesn't seem anything which answers the problem I am currently experiencing.

    [I notice on the server side whilst debugging that the requestData element of the DSRequest instance contains only the filename (no fully specified path) to the file that was originally selected and additionally that the ISCHttpServletRequest instance as part of RequestContext for the DSRequest has an empty fileItemParts array; I'm including this info in case it is of use.]

    Could you give me some pointer to help me solve this problem please?

    #2
    Are you using Struts/Spring or any other 3rd party servlet filters in front of IDACall? If so, they are likely the problem, as they will sometimes parse the uploaded file and provide a modified httpServletRequest to IDACall with no file.

    To confirm, get rid of any filters in front of IDACall and try it out.

    Comment


      #3
      Originally posted by Isomorphic
      Are you using Struts/Spring or any other 3rd party servlet filters in front of IDACall? If so, they are likely the problem, as they will sometimes parse the uploaded file and provide a modified httpServletRequest to IDACall with no file.

      To confirm, get rid of any filters in front of IDACall and try it out.
      No, I'm not using any other servlet filters (I did see the comments relating to the use of DMI if Struts is in the processing chain).

      Comment


        #4
        Have you looked with Firebug, Fiddler or a similar tool at the actual request to verify the browser is submitting something? If it's not, look for problems in the client side code (and post it here for help).

        If you can see the file going to the server, please show your server-side code.

        Comment


          #5
          Here is a bitmap of the stack call on the server side.
          Attached Files

          Comment


            #6
            Originally posted by Isomorphic
            Have you looked with Firebug, Fiddler or a similar tool at the actual request to verify the browser is submitting something? If it's not, look for problems in the client side code (and post it here for help).

            If you can see the file going to the server, please show your server-side code.
            There is no doubt that the request is going through. I've debugged the whole transaction on the server side and all the correct data is there with the exception of the file stream.

            Comment


              #7
              Sorry, neither of these is what's needed. It's not a matter of whether the request is going to the server, it's a matter of whether the request contains the file. Firebug or Fiddler will show you that.

              Comment


                #8
                Originally posted by Isomorphic
                Sorry, neither of these is what's needed. It's not a matter of whether the request is going to the server, it's a matter of whether the request contains the file. Firebug or Fiddler will show you that.
                Here is the output from Firebug when the logging option is set to debug.

                Code:
                19:55:51.636:MUP1:INFO:DataSource:images1272908924779ds:performDSOperation(update) 1 records
                19:55:51.798:MUP1:INFO:RPCManager:sendQueue[13]: 1 RPCRequest(s); transport: xmlHttpRequest; target: http://localhost:8080/isomorphic/IDACall?isc_rpc=1&isc_v=7.0rc2&isc_xhr=1&isc_tnum=13
                19:55:51.965:MUP1:DEBUG:RPCManager:XMLHttpRequest POST to http://localhost:8080/isomorphic/IDACall?isc_rpc=1&isc_v=7.0rc2&isc_xhr=1&isc_tnum=13 contentType: application/x-www-form-urlencoded; charset=UTF-8 with body -->_transaction=<transaction xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" xsi:type="xsd:Object"><transactionNum xsi:type="xsd:long">13</transactionNum><operations xsi:type="xsd:List"><elem xsi:type="xsd:Object"><criteria xsi:type="xsd:Object"><id xsi:type="xsd:long">3</id></criteria><values xsi:type="xsd:Object"><id xsi:type="xsd:long">3</id><picture>ca30209.jpg</picture></values><operationConfig xsi:type="xsd:Object"><dataSource>images1272908924779ds</dataSource><operationType>update</operationType></operationConfig><componentId>recordsGrid</componentId><appID>builtinApplication</appID><operation>images1272908924779ds_update</operation><oldValues xsi:type="xsd:Object"><picture></picture><id xsi:type="xsd:long">3</id><description>ca12345</description></oldValues></elem></operations></transaction>&protocolVersion=1.0<--
                It is possible to see that the record which was updated had id 3 and that the selected file name was ca30209.jpg, but clearly the actual file stream (as bytes presumably) is not included.

                Please note that I have not written any custom client side jsp code to handle the updating; this occurs automatically when the cell loses focus.

                Comment


                  #9
                  That's not from Firebug, that's from the Developer Console. With the real Firebug, you would want to look at the "Net" panel to see the request.

                  Regardless, this clearly indicates no file is being sent, so, as previously indicated, you need to show your client-side code.

                  Comment


                    #10
                    Originally posted by Isomorphic
                    Regardless, this clearly indicates no file is being sent, so, as previously indicated, you need to show your client-side code.
                    Originally posted by somewhereinbelgium
                    Please note that I have not written any custom client side jsp code to handle the updating; this occurs automatically when the cell loses focus.
                    As I mentioned previously, I have not written any client side code to handle the update so I can't put a breakpoint on my client side code and inspect the state of the request before it is sent. Can you suggest a method I can override to make this inspection?

                    Comment


                      #11
                      Not sure if there's a language barrier here :) We need to see the client-side code for whatever component is submitting the request.

                      Comment


                        #12
                        :-) Yes, I was kind of thinking the same thing.

                        I will try to cull all the relevant bits and put them together in an understandable and concise fashion.

                        Comment


                          #13
                          Hang on, we just spotted something. The grid inherits some behavior from the form and hence shows an upload control, but grids are not actually capable of file upload from inline editing.

                          Probably the simplest thing to do is use setEditorType() with a StaticTextItem with a FormItemIcon set, which launches a Window containing a form to do the upload. There's an example showing a form that does an upload in the latest nightly (it's not in a pop-up, but that's the easier part).

                          Comment


                            #14
                            Server side:

                            I have a custom IDACall servlet registered in web.xml which directly extends from com.isomorphic.servlet.IDACall. This class is responsible for handling all the usual OP_FETCH/OP_ADD/OP_UPDATE functionality (communicating with a SQL Server database), but also handles two other custom RPC requests.

                            i) Return a list of table names for which data can be displayed/edited in a ListGrid;
                            ii) Return an instance of a DataSource which can be applied to any ListGrid (given a table name) so that it knows which columns should be displayed in the grid.

                            So my overridden handleDSRequest method looks like this:

                            Code:
                            	@Override
                            	public DSResponse handleDSRequest( final DSRequest dsReq, final RPCManager rpcManager, final RequestContext reqContext ) throws Exception
                            	{
                            		DSResponse response = null;
                            		
                            		final String operationType = dsReq.getOperationType();
                            		
                            		if ( operationType.equals( DataSource.OP_UPDATE ) )
                            		{
                            			response = this.handleUpdate( dsReq, rpcManager, reqContext );
                            		}
                            		if ( operationType.equals( DataSource.OP_FETCH ) )
                            		{
                            			response = this.handleFetch( dsReq, rpcManager, reqContext );
                            		}
                            		if ( operationType.equals( DataSource.OP_ADD ) )
                            		{
                            			response = this.handleAdd( dsReq, rpcManager, reqContext );
                            		}
                            		
                            		if ( response == null )
                            		{
                            			response = super.handleDSRequest( dsReq, rpcManager, reqContext );
                            		}
                            		
                            		return response;
                            	}
                            All pretty standard stuff.

                            I have also overridden handleRPCRequest which looks like this:

                            Code:
                            		final List<RPCRequest> requests = rpcManager.getRequests();
                            		for ( final RPCRequest nthReq : requests )
                            		{
                            			final Object nthReqData = nthReq.getData();
                            			if ( nthReqData instanceof Map )
                            			{
                            				final Map dataMap = (Map)nthReqData;
                            				final Object transactionType = dataMap.get( "transactionType" );
                            				if ( transactionType != null )
                            				{
                            					if ( transactionType.toString().equalsIgnoreCase( "requestDataSources" ) )
                            					{
                            						final List<String> tables = SQLServerHelper.getTableList();
                            						response = new RPCResponse();
                            						response.setData( tables );
                            						response.setStatus( RPCResponse.STATUS_SUCCESS );
                            					}
                            					else
                            					{
                            						if ( transactionType.toString().equalsIgnoreCase( "requestFieldsForDataSource" ) )
                            						{
                            							final Object dataSourceObject = dataMap.get( "dataSource" );
                            							if ( dataSourceObject != null )
                            							{
                            								try
                            								{
                            									final StringBuilder dataSourceId = new StringBuilder();
                            									dataSourceId.append( dataSourceObject.toString() + new Date().getTime() + "ds" );
                            									final StringBuilder xmlDefinition = SQLServerHelper.generateXMLDeclarationForTable( dataSourceObject.toString(), dataSourceId.toString() );
                            									final DataSource ds = DataSource.fromXML( xmlDefinition.toString() );
                            									response = new RPCResponse();
                            									response.setData( ds );
                            									this.mapDSIdToDataSource.put( dataSourceId.toString(), ds );
                            									this.mapDSIdToTableName.put( dataSourceId.toString(), dataSourceObject.toString() );
                            								}
                            								catch ( final Exception exception )
                            								{
                            									exception.printStackTrace();
                            								}
                            							}
                            						}
                            					}
                            				}
                            			}
                            		}
                            		
                            		if ( response == null )
                            		{
                            			response = super.handleRPCRequest( rpcRequest, rpcManager, reqContext );
                            		}
                            		
                            		return response;
                            	}
                            So essentially I handle two specific types of RPC requests which my client side code makes and let the default implementation handle everything else.

                            Client side code:

                            Creation of the grid which is capable of displaying data from any table:

                            Code:
                            thisGrid = isc.ListGrid.create
                            (
                            	{
                            		"xsi:type":"ListGrid",
                            		editByCell:true,
                            		listEndEditAction:"next",
                            		autoSaveEdits: true,
                            		showFilterEditor:true,
                            		showResizeBar:true,
                            		autoFitData:"both",
                            		autoFitMaxWidth:600,
                            		autoFitMaxHeight:400,
                            		canEdit:true,
                            		ID:"recordsGrid",
                            		width:1000,
                            		height:300,
                            		autoDraw:true
                            	}
                            )
                            Creation of the SelectItem component which allows the user to select a particular table:

                            Code:
                            isc.DynamicForm.create
                            (
                            	{
                            		fields:
                            		[
                            			{
                            				name: "SelectTableComboBox", _constructor: "SelectItem",
                            				changed:function( form, item, value )
                            				{
                            					rpcRequest.transactionType = "requestFieldsForDataSource";
                            					rpcRequest.dataSource = value;
                            					rpcRequest.currentRecord = null;
                            					rpcRequest.result = null;
                            
                            					RPCManager.send
                            					(
                            						rpcRequest,
                            						function( rpcResponse, rawData, request )
                            						{
                            							thisGrid.autoFitMaxWidth = 1200;
                            							thisGrid.autoFitData = "both";
                            							thisGrid.dataSource = rawData;
                            							thisGrid.setFields( null );
                            							thisGrid.refreshFields();
                            							thisGrid.fetchData();
                            						}
                            					);
                            				}
                            			}
                            		],
                            		ID: "SelectTableDynamicForm",
                            		autoDraw: false
                            	}
                            )
                            Population of the SelectItem with all available tables:

                            Code:
                            // Populate SelectTableComboBox with the list of tables available for editing.
                            rpcRequest.transactionType = "requestDataSources";
                            rpcRequest.dataSource = null;
                            rpcRequest.currentRecord = null;
                            rpcRequest.result = null;
                            
                            RPCManager.send
                            (
                            	rpcRequest,
                            	function( rpcResponse, rawData, request )
                            	{
                            		//  Need to populate SelectTableComboBox with result.
                            		var formItem = SelectTableDynamicForm.getItem( "SelectTableComboBox" );
                            		formItem.setValueMap( rawData );
                            	}
                            );
                            A sample XML string generated on the server side from which the DataSource is instantiated

                            Code:
                            <DataSource id="images1272912956023ds">
                            	<fields>
                            		<field name="id" type="sequence" hidden="false" primaryKey="true" canEdit="false"/>
                            		<field name="description" type="text" hidden="false" primaryKey="false" />
                            		<field name="picture" type="binary" hidden="false" primaryKey="false" />
                            	</fields>
                            </DataSource>
                            Can you see anything that I'm doing wrong which would cause this problem for binary type fields (updating all other field types are fine)?

                            Comment


                              #15
                              Originally posted by Isomorphic
                              Hang on, we just spotted something. The grid inherits some behavior from the form and hence shows an upload control, but grids are not actually capable of file upload from inline editing.

                              Probably the simplest thing to do is use setEditorType() with a StaticTextItem with a FormItemIcon set, which launches a Window containing a form to do the upload. There's an example showing a form that does an upload in the latest nightly (it's not in a pop-up, but that's the easier part).
                              I was busy getting my last reply and didn't see that you got your reply in first ;-) I'll have a look now.

                              Comment

                              Working...
                              X