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.
Announcement
Collapse
No announcement yet.
X
-
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; }
Comment
-
Originally posted by lgorlin View PostAS400 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; }
Last edited by Isomorphic; 26 Jun 2013, 12:25.
Comment
-
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);
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);
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 }
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
-
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) { . . . } });
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; } }
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
-
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
-
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
Comment