diff --git a/org.adempiere.base/src/org/compiere/model/MInOut.java b/org.adempiere.base/src/org/compiere/model/MInOut.java index 3c3ff21d4b..fc10039433 100644 --- a/org.adempiere.base/src/org/compiere/model/MInOut.java +++ b/org.adempiere.base/src/org/compiere/model/MInOut.java @@ -1344,13 +1344,16 @@ public class MInOut extends X_M_InOut implements DocAction { if (!isReversal()) { - BigDecimal toDelivered = oLine.getQtyOrdered().subtract(oLine.getQtyDelivered()); - if (sLine.getMovementQty().compareTo(toDelivered) > 0) - overReceipt = sLine.getMovementQty().subtract(toDelivered); - if (overReceipt.signum() != 0) + if (oLine != null) { - sLine.setQtyOverReceipt(overReceipt); - sLine.saveEx(); + BigDecimal toDelivered = oLine.getQtyOrdered().subtract(oLine.getQtyDelivered()); + if (sLine.getMovementQty().compareTo(toDelivered) > 0) + overReceipt = sLine.getMovementQty().subtract(toDelivered); + if (overReceipt.signum() != 0) + { + sLine.setQtyOverReceipt(overReceipt); + sLine.saveEx(); + } } } else diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java index 0fd0358742..f841b47a2d 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/AdempiereWebUI.java @@ -18,8 +18,6 @@ package org.adempiere.webui; import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -53,23 +51,15 @@ import org.zkforge.keylistener.Keylistener; import org.zkoss.web.Attributes; import org.zkoss.web.servlet.Servlets; import org.zkoss.zk.au.out.AuScript; -import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Desktop; import org.zkoss.zk.ui.Executions; -import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.Session; -import org.zkoss.zk.ui.UiException; import org.zkoss.zk.ui.event.ClientInfoEvent; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; -import org.zkoss.zk.ui.impl.ExecutionCarryOver; import org.zkoss.zk.ui.sys.DesktopCache; -import org.zkoss.zk.ui.sys.DesktopCtrl; -import org.zkoss.zk.ui.sys.ExecutionCtrl; -import org.zkoss.zk.ui.sys.ExecutionsCtrl; import org.zkoss.zk.ui.sys.SessionCtrl; -import org.zkoss.zk.ui.sys.Visualizer; import org.zkoss.zk.ui.util.Clients; import org.zkoss.zul.Window; @@ -100,8 +90,6 @@ public class AdempiereWebUI extends Window implements EventListener, IWeb private WLogin loginDesktop; - private IDesktop appDesktop; - private ClientInfo clientInfo = new ClientInfo(); private String langSession; @@ -243,107 +231,15 @@ public class AdempiereWebUI extends Window implements EventListener, IWeb keyListener.setCtrlKeys("@a@c@d@e@f@h@n@o@p@r@s@t@z@x@#left@#right@#up@#down@#home@#end#enter^u@u"); keyListener.setAutoBlur(false); - @SuppressWarnings("unchecked") - WeakReference desktopRef = (WeakReference) currSess.getAttribute(APPLICATION_DESKTOP_KEY); - IDesktop d = desktopRef != null ? desktopRef.get() : null; - if (d != null && d instanceof IDesktop) - { - @SuppressWarnings("unchecked") - WeakReference ecoRef = (WeakReference) currSess.getAttribute(EXECUTION_CARRYOVER_SESSION_KEY);; - ExecutionCarryOver eco = ecoRef != null ? ecoRef.get() : null; - if (eco != null) { - //try restore - try { - appDesktop = (IDesktop) d; - - ExecutionCarryOver current = new ExecutionCarryOver(this.getPage().getDesktop()); - ExecutionCtrl ctrl = ExecutionsCtrl.getCurrentCtrl(); - Visualizer vi = ctrl.getVisualizer(); - eco.carryOver(); - Collection rootComponents = new ArrayList(); - try { - ctrl = ExecutionsCtrl.getCurrentCtrl(); - ((DesktopCtrl)Executions.getCurrent().getDesktop()).setVisualizer(vi); - - //detach root component from old page - Page page = appDesktop.getComponent().getPage(); - if (page.getDesktop() != null) { - Collection collection = page.getRoots(); - for(Component comp : collection) { - try { - comp.detach(); - if (!(comp instanceof Keylistener) && !(comp instanceof AdempiereWebUI)) { - rootComponents.add(comp); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - appDesktop.getComponent().detach(); - - DesktopCache desktopCache = ((SessionCtrl)currSess).getDesktopCache(); - if (desktopCache != null) - desktopCache.removeDesktop(Executions.getCurrent().getDesktop()); - } else { - appDesktop = null; - } - } catch (Exception e) { - e.printStackTrace(); - appDesktop = null; - } finally { - eco.cleanup(); - current.carryOver(); - } - - if (appDesktop != null) { - //re-attach root components - for (Component component : rootComponents) { - try { - component.setPage(this.getPage()); - } catch (UiException e) { - // e.printStackTrace(); - // an exception is thrown here when refreshing the page, it seems is harmless to catch and ignore it - // i.e.: org.zkoss.zk.ui.UiException: Not unique in the ID space of [Page z_kg_0]: zk_comp_2 - } - } - appDesktop.setPage(this.getPage()); - Clients.response(new AuScript("$('.slimScroll .z-anchorlayout-body').slimScroll({height: '100%',railVisible: true, alwaysVisible: false});")); - currSess.setAttribute(EXECUTION_CARRYOVER_SESSION_KEY, new WeakReference(current)); - } - - currSess.setAttribute(ZK_DESKTOP_SESSION_KEY, new WeakReference(this.getPage().getDesktop())); - ctx.put(ZK_DESKTOP_SESSION_KEY, new WeakReference(this.getPage().getDesktop())); - ClientInfo sessionClientInfo = (ClientInfo) currSess.getAttribute(CLIENT_INFO); - if (sessionClientInfo != null) { - clientInfo = sessionClientInfo; - } - } catch (Throwable t) { - //restore fail - t.printStackTrace(); - appDesktop = null; - Collection roots = this.getPage().getRoots(); - for(Component comp : roots) { - if (!(comp instanceof Keylistener) && !(comp instanceof AdempiereWebUI)) { - comp.detach(); - } - } - } - - } - } - - if (appDesktop == null) - { - //create new desktop - createDesktop(); - appDesktop.setClientInfo(clientInfo); - appDesktop.createPart(this.getPage()); - currSess.setAttribute(APPLICATION_DESKTOP_KEY, new WeakReference(appDesktop)); - ExecutionCarryOver eco = new ExecutionCarryOver(this.getPage().getDesktop()); - currSess.setAttribute(EXECUTION_CARRYOVER_SESSION_KEY, new WeakReference(eco)); - currSess.setAttribute(ZK_DESKTOP_SESSION_KEY, new WeakReference(this.getPage().getDesktop())); - ctx.put(ZK_DESKTOP_SESSION_KEY, new WeakReference(this.getPage().getDesktop())); - } + //create new desktop + IDesktop appDesktop = createDesktop(); + appDesktop.setClientInfo(clientInfo); + appDesktop.createPart(this.getPage()); + ctx.put(ZK_DESKTOP_SESSION_KEY, new WeakReference(this.getPage().getDesktop())); + this.getPage().getDesktop().setAttribute(APPLICATION_DESKTOP_KEY, new WeakReference(appDesktop)); + + //track browser tab per session + SessionContextListener.addDesktopId(mSession.getAD_Session_ID(), getPage().getDesktop().getId()); //ensure server push is on if (!this.getPage().getDesktop().isServerPushEnabled()) @@ -381,9 +277,9 @@ public class AdempiereWebUI extends Window implements EventListener, IWeb return keyListener; } - private void createDesktop() + private IDesktop createDesktop() { - appDesktop = null; + IDesktop appDesktop = null; String className = MSysConfig.getValue(MSysConfig.ZK_DESKTOP_CLASS); if ( className != null && className.trim().length() > 0) { @@ -400,6 +296,8 @@ public class AdempiereWebUI extends Window implements EventListener, IWeb //fallback to default if (appDesktop == null) appDesktop = new DefaultDesktop(); + + return appDesktop; } /* (non-Javadoc) @@ -438,6 +336,7 @@ public class AdempiereWebUI extends Window implements EventListener, IWeb } //stop background thread + IDesktop appDesktop = getAppDeskop(); if (appDesktop != null) appDesktop.logout(); @@ -458,6 +357,18 @@ public class AdempiereWebUI extends Window implements EventListener, IWeb */ public IDesktop getAppDeskop() { + Desktop desktop = Executions.getCurrent() != null ? Executions.getCurrent().getDesktop() : null; + IDesktop appDesktop = null; + if (desktop != null) + { + @SuppressWarnings("unchecked") + WeakReference ref = (WeakReference) desktop.getAttribute(APPLICATION_DESKTOP_KEY); + if (ref != null) + { + appDesktop = ref.get(); + } + } + return appDesktop; } @@ -475,6 +386,7 @@ public class AdempiereWebUI extends Window implements EventListener, IWeb clientInfo.desktopYOffset = c.getDesktopYOffset(); clientInfo.orientation = c.getOrientation(); clientInfo.timeZone = c.getTimeZone(); + IDesktop appDesktop = getAppDeskop(); if (appDesktop != null) appDesktop.setClientInfo(clientInfo); String ua = Servlets.getUserAgent((ServletRequest) Executions.getCurrent().getNativeRequest()); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionContextListener.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionContextListener.java index 68c0a7275e..920e10f7d5 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionContextListener.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionContextListener.java @@ -17,6 +17,9 @@ package org.adempiere.webui.session; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Properties; @@ -24,6 +27,7 @@ import javax.servlet.http.HttpSession; import org.adempiere.util.ServerContext; import org.adempiere.util.ServerContextURLHandler; +import org.adempiere.webui.AdempiereWebUI; import org.compiere.model.MSession; import org.compiere.util.Env; import org.zkoss.util.Locales; @@ -37,8 +41,10 @@ import org.zkoss.zk.ui.event.EventThreadCleanup; import org.zkoss.zk.ui.event.EventThreadInit; import org.zkoss.zk.ui.event.EventThreadResume; import org.zkoss.zk.ui.event.EventThreadSuspend; +import org.zkoss.zk.ui.sys.DesktopCache; import org.zkoss.zk.ui.sys.DesktopCtrl; import org.zkoss.zk.ui.sys.ServerPush; +import org.zkoss.zk.ui.sys.SessionCtrl; import org.zkoss.zk.ui.util.DesktopCleanup; import org.zkoss.zk.ui.util.DesktopInit; import org.zkoss.zk.ui.util.ExecutionCleanup; @@ -65,6 +71,19 @@ public class SessionContextListener implements ExecutionInit, Session session = exec.getDesktop().getSession(); Properties ctx = (Properties)session.getAttribute(SESSION_CTX); HttpSession httpSession = (HttpSession)session.getNativeSession(); + //create empty context if there's no valid native session + if (httpSession == null) + { + ctx = new Properties(); + ctx.put(ServerContextURLHandler.SERVER_CONTEXT_URL_HANDLER, new ServerContextURLHandler() { + public void showURL(String url) { + SessionManager.getAppDesktop().showURL(url, true); + } + }); + ServerContext.setCurrentInstance(ctx); + return; + } + if (ctx != null) { //verify ctx @@ -107,6 +126,8 @@ public class SessionContextListener implements ExecutionInit, //set locale Locales.setThreadLocal(Env.getLanguage(ServerContext.getCurrentInstance()).getLocale()); } + Properties ctx = ServerContext.getCurrentInstance(); + ctx.put(AdempiereWebUI.ZK_DESKTOP_SESSION_KEY, new WeakReference(exec.getDesktop())); } } @@ -283,7 +304,7 @@ public class SessionContextListener implements ExecutionInit, HttpSession httpSession = (HttpSession)session.getNativeSession(); //verify ctx String cacheId = ctx.getProperty(SERVLET_SESSION_ID); - if (cacheId == null || !cacheId.equals(httpSession.getId()) ) + if (cacheId == null || httpSession == null || !cacheId.equals(httpSession.getId()) ) { return false; } @@ -323,10 +344,12 @@ public class SessionContextListener implements ExecutionInit, } int AD_Session_ID = Env.getContextAsInt(Env.getCtx(), "#AD_Session_ID"); if (AD_Session_ID > 0) { - String key = "ad_session."+AD_Session_ID+".desktop"; - String dtid = (String) Env.getCtx().get(key); - if (dtid != null) { - if (!dtid.equals(desktop.getId())) { + String key = getSessionDesktopListKey(AD_Session_ID); + @SuppressWarnings("unchecked") + List list = (List) Env.getCtx().get(key); + if (list != null) { + list.remove(desktop.getId()); + if (!isEmpty(list, desktop.getSession())) { return; } else { Env.getCtx().remove(key); @@ -343,6 +366,38 @@ public class SessionContextListener implements ExecutionInit, } } + private boolean isEmpty(List list, Session session) { + if (list.isEmpty()) + return true; + + if (session == null) + return false; + + DesktopCache desktopCache = ((SessionCtrl)session).getDesktopCache(); + if (desktopCache == null) + return false; + + int count = 0; + for(String dtid : list) { + Desktop desktop = desktopCache.getDesktopIfAny(dtid); + if (desktop == null) continue; + if (desktop.getFirstPage() == null) continue; + Collection roots = desktop.getFirstPage().getRoots(); + if (roots == null || roots.isEmpty()) continue; + boolean found = false; + for (Component root : roots) { + if (root instanceof AdempiereWebUI) { + found = true; + break; + } + } + if (!found) continue; + count++; + } + + return count == 0; + } + @Override public void init(Desktop desktop, Object request) throws Exception { if(Executions.getCurrent()==null) @@ -358,7 +413,32 @@ public class SessionContextListener implements ExecutionInit, mSession.setProcessed(false); mSession.saveEx(); } - Env.getCtx().put("ad_session."+mSession.getAD_Session_ID()+".desktop", desktop.getId()); + addDesktopId(mSession.getAD_Session_ID(), desktop.getId()); + } + } + + public static void addDesktopId(int AD_Session_ID, String dtid) + { + String key = getSessionDesktopListKey(AD_Session_ID); + @SuppressWarnings("unchecked") + List list = (List) Env.getCtx().get(key); + if (list == null) { + list = new ArrayList(); + Env.getCtx().put(key, list); + } + if (!list.contains(dtid)) + { + list.add(dtid); } } + + /** + * @param AD_Session_ID + * @return desktop list key + */ + public static String getSessionDesktopListKey(int AD_Session_ID) + { + String key = "ad_session."+AD_Session_ID+".desktop"; + return key; + } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionManager.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionManager.java index adccb34ef7..6d04638d2e 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionManager.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/session/SessionManager.java @@ -20,15 +20,12 @@ package org.adempiere.webui.session; import java.lang.ref.WeakReference; import java.util.Properties; -import org.adempiere.webui.AdempiereWebUI; import org.adempiere.webui.IWebClient; +import org.adempiere.webui.apps.AEnv; import org.adempiere.webui.desktop.IDesktop; import org.compiere.model.MUser; import org.compiere.util.Env; import org.zkoss.zk.ui.Desktop; -import org.zkoss.zk.ui.Execution; -import org.zkoss.zk.ui.Executions; -import org.zkoss.zk.ui.Session; /** * @@ -51,28 +48,11 @@ public class SessionManager && !"".equals(adClientId) && !"".equals(adOrgId)); } - private static Session getSession() - { - Execution execution = Executions.getCurrent(); - Desktop desktop = null; - if (execution != null) - { - desktop = execution.getDesktop(); - } - else - { - @SuppressWarnings("unchecked") - WeakReference ref = (WeakReference) Env.getCtx().get(AdempiereWebUI.ZK_DESKTOP_SESSION_KEY); - desktop = ref != null ? ref.get() : null; - } - return desktop != null ? desktop.getSession() : null; - } - public static void setSessionApplication(IWebClient app) { - Session session = getSession(); - if (session != null) - session.setAttribute(SESSION_APPLICATION, new WeakReference(app)); + Desktop desktop = AEnv.getDesktop(); + if (desktop != null) + desktop.setAttribute(SESSION_APPLICATION, new WeakReference(app)); } public static IDesktop getAppDesktop() @@ -83,12 +63,12 @@ public class SessionManager public static IWebClient getSessionApplication() { - Session session = getSession(); + Desktop desktop = AEnv.getDesktop(); IWebClient app = null; - if (session != null) + if (desktop != null) { @SuppressWarnings("unchecked") - WeakReference wref = (WeakReference) session.getAttribute(SESSION_APPLICATION); + WeakReference wref = (WeakReference) desktop.getAttribute(SESSION_APPLICATION); app = wref != null ? wref.get() : null; } return app;