Announcement

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

    #16
    The AS400 class referenced in your latest code doesn't appear to be defined anywhere. Also, where is the definiition of AS400Utilities.returnAS400? If CommandCall is something you've implemented, that also needs to be defined.

    Comment


      #17
      AS400 and CommandCall are part of a third party tool, jt400.jar (the jtopen project).

      Here's returnAS400():
      Code:
      public static void returnAS400(AS400 as400) {
          getConnectionPool().returnConnectionToPool(as400);
      }
      Code:
      public static AS400ConnectionPool getConnectionPool() {
          if (myConnectionPool == null) {
              myConnectionPool = new AS400ConnectionPool();
          }
          return myConnectionPool;
      }
      I'm working on a standalone test case but am not convinced I'm going to be able to isolate it. If you suspect you know what the problem is, we'd be happy to test the solution.

      Comment


        #18
        I thought the code we have here that we're trying to get running is the repro case?

        Comment


          #19
          The code we've been posting is from the application.

          Comment


            #20
            Originally posted by lgorlin View Post
            AS400 and CommandCall are part of a third party tool, jt400.jar (the jtopen project).

            Here's returnAS400():
            Code:
            public static void returnAS400(AS400 as400) {
                getConnectionPool().returnConnectionToPool(as400);
            }
            Code:
            public static AS400ConnectionPool getConnectionPool() {
                if (myConnectionPool == null) {
                    myConnectionPool = new AS400ConnectionPool();
                }
                return myConnectionPool;
            }
            I'm working on a standalone test case but am not convinced I'm going to be able to isolate it. If you suspect you know what the problem is, we'd be happy to test the solution.
            This still won't compile. What's the definition of AS400Utilities getAS400()? And where is the variable referenced in getConnectionPool() defined (myConnectionPool) - is it supposed to be a class variable of AS400Utilities?
            Last edited by Isomorphic; 26 Jun 2013, 12:25.

            Comment


              #21
              I've found the problem.

              We have a client-side program that maintains data sources in static global variables:

              Code:
              private static DataSource myAs400CommandDS = DataSource.get(IslandPacificDSConstants.DATASOURCE_AS400Command);
              private static DataSource myGTINValidatorDS = DataSource.get(IslandPacificDSConstants.DATASOURCE_GTINValidator);
              private static DataSource myISBNValidatorDS = DataSource.get(IslandPacificDSConstants.DATASOURCE_ISBNValidator);
              We use one of those saved datasources to execute a fetch against our server command datasource:

              Code:
              myAs400CommandDS.fetchData(criteria, new DSCallback() {
              	@Override
              	public void execute(DSResponse response, Object rawData,
              			DSRequest request) {
              		Record values = (Record) response.getData()[0];
              		boolean commandSuccessful = values.getAttributeAsBoolean("Success");
              		if (commandSuccessful) {
              			callback.onTrue();
              		}
              		else {
              			callback.onFalse();
              		}
              	}
              }, request);
              This has always worked fine. However, now that we have the new isomorphic version, something has changed. Once the user logs out of our application and signs back in without exiting the browser, something happens to those datasource variables. Though they still exist as javascript objects, they no longer contain what they used to. For example, the id field once contained the datasource name and now contains a null.

              I've found that once the bad datasource object is used used to do a fetch, the id field is assigned one of the random generated datasource names (ex: isc_Datasource_618).

              Here's the RPC call:

              Code:
              {
                  dataSource:"isc_DataSource_618", 
                  operationType:"fetch", 
                  data:{
                      Command:"CHKOBJ OBJ(DORDHDR) OBJTYPE(*FILE)"
                  }, 
                  showPrompt:true, 
                  oldValues:{
                      Command:"CHKOBJ OBJ(DORDHDR) OBJTYPE(*FILE)"
                  }, 
                  requestId:"isc_DataSource_618$62793", 
                  fallbackToEval:false, 
                  bypassCache:true
              }
              To fix this, I have simply made the Datasource variable local to the method and all works fine:

              Code:
              DataSource as400CommandDS = DataSource.get(IslandPacificDSConstants.DATASOURCE_AS400Command);
              as400CommandDS.fetchData(criteria, new DSCallback() {
              	@Override
              	public void execute(DSResponse response, Object rawData,
              			DSRequest request) {
              		Record values = (Record) response.getData()[0];
              		boolean commandSuccessful = values.getAttributeAsBoolean("Success");
              		if (commandSuccessful) {
              			callback.onTrue();
              		}
              		else {
              			callback.onFalse();
              		}
              	}
              }, request);
              Last edited by lgorlin; 26 Jun 2013, 15:33.

              Comment


                #22
                Can you please resolve the last two questions asked about getting the sample compiled? The modifications you say "fix everything" really only mask the problem and we'd like to address it correctly. Thanks.

                Comment


                  #23
                  This is not a sample, it's the actual application. You won't be able to compile it, there will be too much missing. Even if you could compile it, that section of code has little to do with the actual problem.

                  I was hoping the information I gave you would be enough for you to understand what the problem is. I agree that my fix is not your fix.

                  The bottom line is that when a datasource object is held on the client in a static variable, the variable will become corrupt if you reload the datasource. Our datasources are created via a DynamicDSGenerator. They get recreated when the user logs off and back on. It's when the datasource gets recreated that the client side static variable becomes unusable.

                  Here are the steps we go through when creating or recreating the data source:

                  On the client, a call is made to our datasource loader:

                  Code:
                  String url = "sc/IslandPacificDSLoader"; 
                  loadDS.setActionURL(url);
                  loadDS.setParams(new HashMap () {{
                         put("dataSource", getDataSourceList()); 	
                         put("locale", LocaleInfo.getCurrentLocale().getLocaleName()); 
                  }});
                  loadDS.setEvalResult(true);
                  
                  RPCManager.sendRequest(loadDS, new RPCCallback () {
                  
                  	@Override
                  	public void execute(RPCResponse response, Object rawData, RPCRequest request) {
                                   .
                                   .
                                   .
                  	}
                  });
                  Here's the datasource loader:

                  Code:
                  public class IslandPacificDSLoader extends DataSourceLoader {
                  	private static Logger log = new Logger(IslandPacificDSLoader.class.getName());
                  	@Override
                  	public void processRequest(HttpServletRequest request, HttpServletResponse response)
                  			throws ServletException, IOException {
                  
                  		log.info("********** Loading IP DataSources ***************");
                  		
                  		// Ensure that the home path is available to any other code that needs it
                  		// without having to rely on access to the servlet context.
                  		String homePath = IpAuthenticationManager.getHomePath();
                  		if (homePath == null) {
                  			homePath = getServletContext().getRealPath("/");
                  			synchronized (homePath) {
                  				IpAuthenticationManager.setHomePath(homePath);
                  			}
                  		}
                  
                  		// Register our dynamic datasource constructor.
                  		IpDynamicDataSource ddsg = new IpDynamicDataSource();
                  		DataSource.addDynamicDSGenerator(ddsg);
                  		
                  		// Make sure the browser realizes this in utf-8 encoded data
                  		response.setContentType("text/javascript");
                  		response.setCharacterEncoding("utf-8");
                  		
                  		// Parse list of data sources to load and the locale
                  		String[] dsNames = request.getParameter("dataSource").split(",");
                  
                  		// See if IPWM is installed by checking for existence of IPSTOCK file.
                  		boolean ipwmInstalled = AS400Utilities.isWarehouseEnabled();
                  		
                  		// For each data source ...
                  		for (String dsName : dsNames) {
                  			
                  			// Skip loading the IPWM data sources if IPWM is not installed.
                  			if (!ipwmInstalled 
                  					&& dsName.equals("IPCYCOD")) {
                  				continue;
                  			}
                  			
                  			// Skip loading release 4.0 data sources if not on that release or greater
                  			if (!AS400Utilities.isIpmsRelease40OrGreater()) {
                  				if (dsName.equals(IslandPacificDSConstants.DATASOURCE_IPCNCPT)) {
                  					continue;
                  				}
                  			}
                  
                  			// Try to construct the data source to send back to the client.
                  			try {
                  				
                  				// Construct a data source from the XML
                  				DataSource ds = ddsg.getDataSource(dsName, null);
                  				
                  				// Skip loading datasource that are only used by server side code.
                  				if (ds != null && ds.getConfig().get("serverOnly")!=null
                  						&& ((String)ds.getConfig().get("serverOnly")).equalsIgnoreCase("true"))
                  					continue;
                  					
                  				// Translate it into JSON
                  				JSTranslater jst = new JSTranslater();
                  
                  				// Return it to the client
                  				response.getWriter().write(jst.toJS(ds));
                  
                  			} catch (TransformerFactoryConfigurationError e) {
                  				e.printStackTrace();
                  				throw new ServletException(e);
                  			} catch (UnconvertableException e) {
                  				e.printStackTrace();
                  				throw new ServletException(e);
                  			} catch (Exception e) {
                  				e.printStackTrace();
                  				throw new ServletException(e);
                  			}
                  		}
                  	}
                  
                  	public static String xmlToString(Node node) {
                          try {
                              Source source = new DOMSource(node);
                              StringWriter stringWriter = new StringWriter();
                              Result result = new StreamResult(stringWriter);
                              TransformerFactory factory = TransformerFactory.newInstance();
                              Transformer transformer = factory.newTransformer();
                              transformer.transform(source, result);
                              return stringWriter.getBuffer().toString();
                          } catch (TransformerConfigurationException e) {
                              e.printStackTrace();
                          } catch (TransformerException e) {
                              e.printStackTrace();
                          }
                          return null;
                      }
                  }
                  Here's our dynamic datasource generator:

                  Code:
                  public class IpDynamicDataSource implements DynamicDSGenerator {
                  
                  	@Override
                  	public DataSource getDataSource(String dsName, DSRequest request) {
                  
                  		/*
                  		 * If it's pre-login, and there's been no user details established,
                  		 * let the system find the datasource. 
                  		 */
                  		if (IpAuthenticationManager.getUserDetails() == null) {
                  			return null;
                  		}
                  		
                  		// If the data source name ends with _batchUpload this request came from the batch
                  		// uploader, So set the componentId to "_batchUpload" so IpDataSource can intercept
                  		// BatchUploader add requests and try to do an update first, then add if it doesn't exist.
                  		// Strip off the _batchUpload suffix from the name so we use the real data source name.
                  		if (dsName.contains(IpDataSource.BATCH_UPLOAD)) {
                  			request.setComponentId(IpDataSource.BATCH_UPLOAD);
                  			dsName = dsName.substring(0, dsName.indexOf(IpDataSource.BATCH_UPLOAD));
                  			request.setDataSourceName(dsName);
                  		}
                  		
                  		// We only override the data sources identified in the IslandPacificDSConstants array
                  		// Return null for any other requests for the default handling.
                  		for(int i = 0; i<IslandPacificDSConstants.DATA_SOURCES.length; ++i) {
                  			if(IslandPacificDSConstants.DATA_SOURCES[i].equals(dsName))
                  				return getIPDataSource(dsName, request);
                  		}
                  		return null;
                  	}
                  
                  	/**
                  	 * Return a customized Island Pacific data source.
                  	 * @param dsName The data source name.
                  	 * @param request The DSRequest being processed.
                  	 * @return The DataSource object.
                  	 */
                  	private DataSource getIPDataSource(String dsName, DSRequest request) {
                  		try {
                  			Document doc = IslandPacificDS.getDSXml(dsName);
                  			DataSource ds = DataSource.fromXML(doc); 
                  			return ds;
                  		} catch (Exception e) {
                  			e.printStackTrace();
                  		}
                  		return null;
                  	}
                  	/**
                  	 * Convert Document to String
                  	 * @param doc The Document to convert.
                  	 * @return The string.
                  	 */
                  	public String getStringFromDocument(Document doc)
                  	{
                  		try
                  		{
                  			DOMSource domSource = new DOMSource(doc);
                  			StringWriter writer = new StringWriter();
                  			StreamResult result = new StreamResult(writer);
                  			TransformerFactory tf = TransformerFactory.newInstance();
                  			Transformer transformer = tf.newTransformer();
                  			transformer.transform(domSource, result);
                  			return writer.toString();
                  		}
                  		catch(TransformerException ex)
                  		{
                  			ex.printStackTrace();
                  			return null;
                  		}
                  	} 
                  }

                  Comment


                    #24
                    OK, the use of DynamicDSGenerator does give us a point to start analysis, and we can see whether a typical use case hits your issue.

                    From the documention here: http://www.smartclient.com/smartgwte...mentation.html I would suggest one possible fix with your old code. Try setting datasources.pool.enabled and see whether it makes a difference.

                    Comment


                      #25
                      Setting datasources.pool.enabled made no difference.

                      If it did, I don't believe we could use it anyway. There's a reason we re-create the datasources when the user logs off and back on. There are many datasources that will look and behave differently based on the environment the user logs in to. For example, in some cases, we actually modify the XML. For that reason, I believe we would need to control the caching of datasources.

                      Comment

                      Working...
                      X