diff --git a/src/org/openbravo/retail/storeserver/synchronization/RecomputeVersionModuleHandler.java b/src/org/openbravo/retail/storeserver/synchronization/RecomputeVersionModuleHandler.java
--- a/src/org/openbravo/retail/storeserver/synchronization/RecomputeVersionModuleHandler.java
+++ b/src/org/openbravo/retail/storeserver/synchronization/RecomputeVersionModuleHandler.java
@@ -46,9 +46,4 @@
     }
     return response;
   }
-
-  @Override
-  protected boolean ignoreTransitioningStatus() {
-    return true;
-  }
 }
diff --git a/src/org/openbravo/retail/storeserver/synchronization/RetailSynchronizationRequestAllowedHandler.java b/src/org/openbravo/retail/storeserver/synchronization/RetailSynchronizationRequestAllowedHandler.java
deleted file mode 100644
--- a/src/org/openbravo/retail/storeserver/synchronization/RetailSynchronizationRequestAllowedHandler.java
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- *************************************************************************
- * Openbravo DB Synchronization module for Retail
- * Copyright (C) 2017 Openbravo SLU 
- *
- * The content of this file is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- ************************************************************************
- */
-
-package org.openbravo.retail.storeserver.synchronization;
-
-import java.io.BufferedReader;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import javax.enterprise.event.Observes;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.log4j.Logger;
-import org.codehaus.jettison.json.JSONObject;
-import org.jfree.util.Log;
-import org.openbravo.base.exception.OBException;
-import org.openbravo.base.model.Entity;
-import org.openbravo.base.model.ModelProvider;
-import org.openbravo.client.kernel.event.EntityDeleteEvent;
-import org.openbravo.client.kernel.event.EntityNewEvent;
-import org.openbravo.client.kernel.event.EntityPersistenceEventObserver;
-import org.openbravo.client.kernel.event.EntityUpdateEvent;
-import org.openbravo.dal.core.OBContext;
-import org.openbravo.dal.service.OBDal;
-import org.openbravo.mobile.core.MobileServerDefinition;
-import org.openbravo.mobile.core.process.MobileService.MobileServiceRequestAllowedHandler;
-import org.openbravo.mobile.core.servercontroller.MobileServerController;
-import org.openbravo.mobile.core.servercontroller.MobileServerRequestExecutor;
-import org.openbravo.mobile.core.servercontroller.MobileServerState;
-import org.openbravo.mobile.core.servercontroller.MobileServerStatusInformation;
-import org.openbravo.mobile.core.servercontroller.MobileServerUtils;
-import org.openbravo.mobile.core.utils.OBMOBCUtils;
-import org.openbravo.replication.symmetricds.diagnosis.RemoteStoreServerDiagnosisProcess;
-import org.openbravo.retail.storeserver.synchronization.eventhandler.MobileServerEventHandler;
-
-import com.google.common.net.HttpHeaders;
-
-/**
- * Prevents requests from happening if the server is reloading or forwards requests to the central server or in another way in a state which
- * does not allow WebPOS connections.
- * 
- * @author Martin Taal
- */
-public class RetailSynchronizationRequestAllowedHandler extends MobileServiceRequestAllowedHandler {
-
-  private static final Logger log = Logger.getLogger(RetailSynchronizationRequestAllowedHandler.class);
-
-  // on purpose static to let it be nullified by eventhandler
-  private static Collection<String> domainRegExList = null;
-  private static Set<String> allowedReferers = new HashSet<String>();
-
-  @Override
-  public boolean allowRequest(HttpServletRequest request, HttpServletResponse response) {
-    // do not check reload/version status if a central server
-    if (MobileServerController.getInstance().isThisACentralServer()) {
-      return true;
-    }
-
-    MobileServerDefinition thisServerDefinition = MobileServerController.getInstance()
-        .getThisServerDefinition();
-
-    if (thisServerDefinition == null) {
-      return true;
-    }
-
-    if (!MobileServerUtils.isMultiServerEnabled()) {
-      return true;
-    }
-
-    // always allow ping service
-    if (isAllowedService(request)) {
-      return true;
-    }
-
-    if (isMandatoryReload(thisServerDefinition)) {
-      writeResponseJSON(response, "RELOADING");
-      return false;
-    }
-    
-    final boolean isOffline = thisServerDefinition.getStatus().equals(MobileServerState.OFFLINE.getValue());
-    if (isOffline && MobileServerController.getInstance().isThisAStoreServer() && thisServerDefinition.isOfflineIncomingErrors() && MobileServerEventHandler.doIncomingSyncErrorsExist()) {
-      // send back invalid offline status
-      writeResponseJSON(response, "INVALID_OFFLINE");
-      return false;
-    }
-
-    if (forwardedToCentralServer(request, response)) {
-      return false;
-    }
-    
-    if (isOffline && !isRequestRefererFromThisServer(request)
-        && !StoreServerVersionHandler.getInstance().areCentralStoreServerVersionsCompatible()) {
-      // send back incompat status
-      try {
-        // special case, if there are batches pending to sync then webpos is not allowed to work on
-        // central
-        // either, in that case direct the user to use a different url
-        if (RetrieveSyncStatus.countBatchesPendingToSyncToCentral() > 0) {
-          writeResponseJSON(response, "INCOMPATIBLE_VERSION_DATA_PENDING_TO_SYNC");
-          return false;
-        }
-
-        writeResponseJSON(response, "INCOMPATIBLE_VERSION");
-      } catch (Throwable t) {
-        throw new OBException(t);
-      }
-      return false;
-    }
-    
-    // allow all other cases
-    return true;
-  }
-
-  private boolean isMandatoryReload(MobileServerDefinition sd) {
-    return "MANDATORY_RELOADING".equals(sd.getStrsyncReloadStatus())
-        || "MANDATORY_ON_STARTUP".equals(sd.getStrsyncReloadStatus());
-  }
-    
-  private void writeResponseJSON(HttpServletResponse response, String serverStatusSignal) {
-    try {
-      final JSONObject json = new JSONObject();
-      final JSONObject responseJson = new JSONObject();
-      json.put("serverStatusSignal", serverStatusSignal);
-      responseJson.put("response", json);
-      final Writer w = response.getWriter();
-      w.write(responseJson.toString());
-      w.close();
-    } catch (Throwable t) {
-      throw new OBException(t);
-    }
-  }
-
-  private boolean isAllowedService(HttpServletRequest request) {
-    if (request.getRequestURL().toString().contains(MobileServerStatusInformation.class.getName())) {
-      return true;
-    }
-    if (request.getRequestURL().toString().contains(RetrieveServerVersionStatus.class.getName())) {
-      return true;
-    }
-    if (request.getRequestURL().toString()
-        .contains(RemoteStoreServerDiagnosisProcess.class.getName())) {
-      return true;
-    }
-    if (request.getRequestURL().toString().contains(RecomputeVersionModuleHandler.class.getName())) {
-      return true;
-    }
-
-    return false;
-  }
-
-  private boolean forwardedToCentralServer(HttpServletRequest request, HttpServletResponse response) {
-    try {
-      // don't let the CS forward to itself
-      if (MobileServerController.getInstance().isThisACentralServer()) {
-        return false;
-      }
-
-      // only forward to CS if online
-      if (!MobileServerController.getInstance().getThisMobileServerState().equals(MobileServerState.ONLINE)) {
-        return false;
-      }
-
-      // only handle it here if the request is from webpos
-      // use querystring to prevent null content
-      final String qs = request.getQueryString();
-      boolean sourceWebPOS = !qs.contains(MobileServerRequestExecutor.SOURCE_PROP);
-      sourceWebPOS |= qs.contains(MobileServerRequestExecutor.SOURCE_PROP + "=" + MobileServerRequestExecutor.SOURCE_WEBPOS);
-      if (sourceWebPOS) {
-        final String content = getRequestContent(request);
-        final String requestPath = request.getRequestURI().substring(request.getContextPath().length()) + "?" + request.getQueryString();
-        final JSONObject requestContent = content == null || content.length() == 0 ? null : new JSONObject(content);
-        JSONObject result = null;
-        try {
-          result = MobileServerRequestExecutor.getInstance().executeCentralRequest(requestPath, 
-              requestContent);
-        } catch (Throwable t) {
-          result = handleCentralServerRequestException(t);
-        }
-
-        response.setContentType("application/json");
-        response.setCharacterEncoding("UTF-8");
-
-        final Writer w = response.getWriter();
-        w.write("{\"response\":");
-        w.write(result.toString());
-        w.write("}");
-        w.close();
-        return true;  
-      }
-      // offline --> is handled by request allowed handlers
-      // transitioning states --> let the service handle it as some services need to be callable in transition state also
-      return false;
-    } catch (Exception e) {
-      throw new OBException("Error when handling request " + request.getPathInfo(), e);
-    }
-  }
-
-  private JSONObject handleCentralServerRequestException(Throwable t) throws Exception {
-    log.error(t.getMessage(), t);
-
-    OBContext.setAdminMode(false);
-    try {
-      // set the central server as not being reachable
-      final MobileServerDefinition centralServer = MobileServerController.getInstance()
-          .getCentralServer();
-      centralServer.setStatus(MobileServerState.OFFLINE.getValue());
-      OBDal.getInstance().save(centralServer);
-    } finally {
-      OBContext.restorePreviousMode();
-    }
-
-    if (!MobileServerState.TRANSITION_TO_OFFLINE.equals(MobileServerController.getInstance()
-        .getThisMobileServerState())) {
-      // transition to offline,
-      // which causes the next if to be executed
-      log.info("Could not communicate with the central server, starting transition to offline");
-      MobileServerController.getInstance().transitionToOffline();
-    }
-
-    if (MobileServerController.getInstance().serverHasTransitioningStatus()) {
-      final JSONObject result = new JSONObject();
-      MobileServerController.getInstance().setServerStatusJSON(result);
-      return result;
-    }
-
-    // return a exception json, the transaction will be committed is fine
-    // as the central server will move to offline so database action
-    // happened
-    return OBMOBCUtils.createSimpleErrorJson("OBMOBC_MsgCentralServerNotAvailable");
-  }
-
-  private String getRequestContent(HttpServletRequest request) throws Exception {
-    final BufferedReader reader = request.getReader();
-    if (reader == null) {
-      return null;
-    }
-    String line;
-    final StringBuilder sb = new StringBuilder();
-    while ((line = reader.readLine()) != null) {
-      if (sb.length() > 0) {
-        sb.append("\n");
-      }
-      sb.append(line);
-    }
-    return sb.toString();
-  }
-
-  public boolean isRequestRefererFromThisServer(HttpServletRequest request) {
-    String referer = request.getHeader(HttpHeaders.REFERER);
-
-    if (referer == null) {
-      return false;
-    }
-
-    // do some repairs on the referer to only get the host part
-    int index = referer.indexOf("//");
-    index = referer.indexOf("/", index + 2);
-    if (index == -1) {
-      index = referer.length();
-    }
-    referer = referer.substring(0, index);
-
-    if (domainRegExList == null) {
-      buildDomainList();
-    }
-
-    if (allowedReferers.contains(referer)) {
-      return true;
-    }
-
-    if (domainRegExList.isEmpty()) {
-      return false;
-    }
-
-    for (String domainRegEx : domainRegExList) {
-      // matches is 5 times slower than precompile regex
-      // but as we cache allowed domains anyway (see allowedDomains set)
-      // there is less need to optimize
-      if (referer.matches(domainRegEx)) {
-        allowedReferers.add(referer);
-        return true;
-      }
-    }
-
-    return false;
-  }
-  
-  private synchronized void buildDomainList() {
-    allowedReferers = new HashSet<String>();
-
-    if (!MobileServerUtils.isMultiServerEnabled()) {
-      domainRegExList = new ArrayList<String>();
-      return;
-    }
-
-    final Collection<String> localDomainList = new ArrayList<String>();
-    localDomainList.addAll(getAllowedDomains(MobileServerController.getInstance()
-        .getThisServerDefinition()));
-    domainRegExList = localDomainList;
-  }
-
-  private List<String> getAllowedDomains(MobileServerDefinition serverDefinition) {
-    final List<String> result = new ArrayList<String>();
-    if (serverDefinition.getURL() != null) {
-      result.add(getAllowedOriginExp(serverDefinition.getURL()));
-    }
-    if (serverDefinition.getAlloweddomains() != null) {
-      String tmpDomains = serverDefinition.getAlloweddomains();
-      // support line breaks instead of commas, support all the platforms
-      // as the browser may run in different OS on the client side
-      tmpDomains = tmpDomains.replace("\r\n", ",");
-      tmpDomains = tmpDomains.replace("\n", ",");
-      tmpDomains = tmpDomains.replace("\r", ",");
-      // all the separators are now commas, split on it
-      final String[] domains = tmpDomains.split(",");
-      for (String domain : domains) {
-        String regEx = getAllowedOriginExp(domain.trim());
-        // test the regEx
-        try {
-          Pattern.compile(regEx);
-          result.add(regEx);
-        } catch (Exception logIt) {
-          Log.error("Reg ex " + regEx + " does not compile " + logIt.getMessage(), logIt);
-        }
-      }
-    }
-    return result;
-  }
-
-  private String getAllowedOriginExp(String url) {
-    // note url can contain dots, but on purpose not escaping those
-    // to allow flexibility, if the user wants explicit dots he/she
-    // should escape them
-
-    String localUrl = url.toLowerCase();
-    int nextIndex = 2 + localUrl.indexOf("//");
-    if (localUrl.indexOf("/", nextIndex) == -1) {
-      return localUrl;
-    }
-    localUrl = localUrl.substring(0, localUrl.indexOf("/", nextIndex));
-    return localUrl;
-  }
-
-  /**
-   * Clear the cache when a mobile server definition is saved.
-   */
-  public static class MobileServerDefinitionEventHandler extends EntityPersistenceEventObserver {
-
-    private static Entity[] entities = { ModelProvider.getInstance().getEntity(
-        MobileServerDefinition.ENTITY_NAME) };
-    protected Logger logger = Logger.getLogger(this.getClass());
-
-    @Override
-    protected Entity[] getObservedEntities() {
-      return entities;
-    }
-
-    public void onSave(@Observes EntityNewEvent event) {
-      if (!isValidEvent(event)) {
-        return;
-      }
-      domainRegExList = null;
-    }
-
-    public void onUpdate(@Observes EntityUpdateEvent event) {
-      if (!isValidEvent(event)) {
-        return;
-      }
-      domainRegExList = null;
-    }
-
-    public void onDelete(@Observes EntityDeleteEvent event) {
-      if (!isValidEvent(event)) {
-        return;
-      }
-      domainRegExList = null;
-    }
-  }
-
-}
diff --git a/src/org/openbravo/retail/storeserver/synchronization/RetailSynchronizationRequestHandler.java b/src/org/openbravo/retail/storeserver/synchronization/RetailSynchronizationRequestHandler.java
new file mode 100644
--- /dev/null
+++ b/src/org/openbravo/retail/storeserver/synchronization/RetailSynchronizationRequestHandler.java
@@ -0,0 +1,421 @@
+/*
+ *************************************************************************
+ * Openbravo DB Synchronization module for Retail
+ * Copyright (C) 2018 Openbravo SLU 
+ *
+ * The content of this file is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ************************************************************************
+ */
+
+package org.openbravo.retail.storeserver.synchronization;
+
+import java.io.BufferedReader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import javax.enterprise.event.Observes;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+import org.codehaus.jettison.json.JSONObject;
+import org.jfree.util.Log;
+import org.openbravo.base.exception.OBException;
+import org.openbravo.base.model.Entity;
+import org.openbravo.base.model.ModelProvider;
+import org.openbravo.client.kernel.event.EntityDeleteEvent;
+import org.openbravo.client.kernel.event.EntityNewEvent;
+import org.openbravo.client.kernel.event.EntityPersistenceEventObserver;
+import org.openbravo.client.kernel.event.EntityUpdateEvent;
+import org.openbravo.dal.core.OBContext;
+import org.openbravo.dal.service.OBDal;
+import org.openbravo.mobile.core.MobileServerDefinition;
+import org.openbravo.mobile.core.process.MobileService.MobileServiceRequestHandler;
+import org.openbravo.mobile.core.servercontroller.MobileServerController;
+import org.openbravo.mobile.core.servercontroller.MobileServerRequestExecutor;
+import org.openbravo.mobile.core.servercontroller.MobileServerState;
+import org.openbravo.mobile.core.servercontroller.MobileServerStatusInformation;
+import org.openbravo.mobile.core.servercontroller.MobileServerUtils;
+import org.openbravo.mobile.core.utils.OBMOBCUtils;
+import org.openbravo.replication.symmetricds.diagnosis.RemoteStoreServerDiagnosisProcess;
+import org.openbravo.retail.storeserver.synchronization.eventhandler.MobileServerEventHandler;
+
+import com.google.common.net.HttpHeaders;
+
+/**
+ * Prevents requests from happening if the server is reloading or forwards requests to the central server or in another way in a
+ * state which does not allow WebPOS connections.
+ * 
+ * @author Martin Taal
+ */
+public class RetailSynchronizationRequestHandler extends MobileServiceRequestHandler {
+
+  private static final Logger log = Logger.getLogger(RetailSynchronizationRequestHandler.class);
+
+  // on purpose static to let it be nullified by eventhandler
+  private static Collection<String> domainRegExList = null;
+  private static Set<String> allowedReferers = new HashSet<String>();
+
+  @Override
+  public boolean requestHandled(HttpServletRequest request, HttpServletResponse response) {
+    // CS code should be done in standard way
+    if (MobileServerController.getInstance().isThisACentralServer()) {
+      return false;
+    }
+
+    // no multi-server, do not handle here
+    if (!MobileServerUtils.isMultiServerEnabled()) {
+      return false;
+    }
+
+    MobileServerDefinition thisServerDefinition = MobileServerController.getInstance()
+        .getThisServerDefinition();
+    // no multi-server, do not handle here
+    if (thisServerDefinition == null) {
+      return false;
+    }
+
+    if (doNotHandleServiceHere(request)) {
+      return false;
+    }
+
+    // handle mandatory reload here
+    if (isMandatoryReload(thisServerDefinition)) {
+      writeResponseJSON(response, "RELOADING");
+      return true;
+    }
+
+    // transitioning do not allow any other requests
+    if (MobileServerController.getInstance().serverHasTransitioningStatus()) {
+      writeResponseJSON(response, MobileServerController.getInstance().getThisMobileServerState()
+          .getValue());
+      return true;
+    }
+
+    // handle invalid offline here
+    final boolean isOffline = thisServerDefinition.getStatus().equals(
+        MobileServerState.OFFLINE.getValue());
+    if (isOffline && MobileServerController.getInstance().isThisAStoreServer()
+        && thisServerDefinition.isOfflineIncomingErrors()
+        && MobileServerEventHandler.doIncomingSyncErrorsExist()) {
+      // send back invalid offline status
+      writeResponseJSON(response, "INVALID_OFFLINE");
+      return false;
+    }
+
+    // try forward to CS
+    if (forwardedToCentralServer(request, response)) {
+      return true;
+    }
+
+    if (isOffline && !isRequestRefererFromThisServer(request)
+        && !StoreServerVersionHandler.getInstance().areCentralStoreServerVersionsCompatible()) {
+      // send back incompat status
+      try {
+        // special case, if there are batches pending to sync then webpos is not allowed to work on
+        // central
+        // either, in that case direct the user to use a different url
+        if (RetrieveSyncStatus.countBatchesPendingToSyncToCentral() > 0) {
+          writeResponseJSON(response, "INCOMPATIBLE_VERSION_DATA_PENDING_TO_SYNC");
+          return true;
+        }
+
+        writeResponseJSON(response, "INCOMPATIBLE_VERSION");
+      } catch (Throwable t) {
+        throw new OBException(t);
+      }
+      return true;
+    }
+
+    // all other cases are done by the MobileService
+    return false;
+  }
+
+  private boolean isMandatoryReload(MobileServerDefinition sd) {
+    return "MANDATORY_RELOADING".equals(sd.getStrsyncReloadStatus())
+        || "MANDATORY_ON_STARTUP".equals(sd.getStrsyncReloadStatus());
+  }
+
+  private void writeResponseJSON(HttpServletResponse response, String serverStatusSignal) {
+    try {
+      final JSONObject json = new JSONObject();
+      final JSONObject responseJson = new JSONObject();
+      json.put("serverStatusSignal", serverStatusSignal);
+      responseJson.put("response", json);
+      final Writer w = response.getWriter();
+      w.write(responseJson.toString());
+      w.close();
+    } catch (Throwable t) {
+      throw new OBException(t);
+    }
+  }
+
+  private boolean doNotHandleServiceHere(HttpServletRequest request) {
+    if (request.getRequestURL().toString().contains(MobileServerStatusInformation.class.getName())) {
+      return true;
+    }
+    if (request.getRequestURL().toString().contains(RetrieveServerVersionStatus.class.getName())) {
+      return true;
+    }
+    if (request.getRequestURL().toString()
+        .contains(RemoteStoreServerDiagnosisProcess.class.getName())) {
+      return true;
+    }
+    if (request.getRequestURL().toString().contains(RecomputeVersionModuleHandler.class.getName())) {
+      return true;
+    }
+
+    return false;
+  }
+
+  private boolean forwardedToCentralServer(HttpServletRequest request, HttpServletResponse response) {
+    try {
+      // don't let the CS forward to itself
+      if (MobileServerController.getInstance().isThisACentralServer()) {
+        return false;
+      }
+
+      // only forward to CS if online
+      if (!MobileServerController.getInstance().getThisMobileServerState()
+          .equals(MobileServerState.ONLINE)) {
+        return false;
+      }
+
+      // only handle it here if the request is from webpos
+      // use querystring to prevent null content
+      final String qs = request.getQueryString();
+      boolean sourceWebPOS = qs == null || !qs.contains(MobileServerRequestExecutor.SOURCE_PROP);
+      sourceWebPOS |= qs != null
+          && qs.contains(MobileServerRequestExecutor.SOURCE_PROP + "="
+          + MobileServerRequestExecutor.SOURCE_WEBPOS);
+      if (sourceWebPOS) {
+        final String content = getRequestContent(request);
+        final String requestPath = request.getRequestURI().substring(
+            request.getContextPath().length())
+            + "?" + (qs != null ? qs : "");
+        final JSONObject requestContent = content == null || content.length() == 0 ? null
+            : new JSONObject(content);
+        JSONObject result = null;
+        try {
+          result = MobileServerRequestExecutor.getInstance().executeCentralRequest(requestPath,
+              requestContent);
+        } catch (Throwable t) {
+          result = handleCentralServerRequestException(t);
+        }
+
+        response.setContentType("application/json");
+        response.setCharacterEncoding("UTF-8");
+
+        final Writer w = response.getWriter();
+        w.write("{\"response\":");
+        w.write(result.toString());
+        w.write("}");
+        w.close();
+        return true;
+      }
+      // not from webpos, handle locally
+      return false;
+    } catch (Exception e) {
+      throw new OBException("Error when handling request " + request.getPathInfo(), e);
+    }
+  }
+
+  private JSONObject handleCentralServerRequestException(Throwable t) throws Exception {
+    log.error(t.getMessage(), t);
+
+    OBContext.setAdminMode(false);
+    try {
+      // set the central server as not being reachable
+      final MobileServerDefinition centralServer = MobileServerController.getInstance()
+          .getCentralServer();
+      centralServer.setStatus(MobileServerState.OFFLINE.getValue());
+      OBDal.getInstance().save(centralServer);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+
+    if (!MobileServerState.TRANSITION_TO_OFFLINE.equals(MobileServerController.getInstance()
+        .getThisMobileServerState())) {
+      // transition to offline,
+      // which causes the next if to be executed
+      log.info("Could not communicate with the central server, starting transition to offline");
+      MobileServerController.getInstance().transitionToOffline();
+    }
+
+    if (MobileServerController.getInstance().serverHasTransitioningStatus()) {
+      final JSONObject result = new JSONObject();
+      MobileServerController.getInstance().setServerStatusJSON(result);
+      return result;
+    }
+
+    // return a exception json, the transaction will be committed is fine
+    // as the central server will move to offline so database action
+    // happened
+    return OBMOBCUtils.createSimpleErrorJson("OBMOBC_MsgCentralServerNotAvailable");
+  }
+
+  private String getRequestContent(HttpServletRequest request) throws Exception {
+    final BufferedReader reader = request.getReader();
+    if (reader == null) {
+      return null;
+    }
+    String line;
+    final StringBuilder sb = new StringBuilder();
+    while ((line = reader.readLine()) != null) {
+      if (sb.length() > 0) {
+        sb.append("\n");
+      }
+      sb.append(line);
+    }
+    return sb.toString();
+  }
+
+  public boolean isRequestRefererFromThisServer(HttpServletRequest request) {
+    String referer = request.getHeader(HttpHeaders.REFERER);
+
+    if (referer == null) {
+      return false;
+    }
+
+    // do some repairs on the referer to only get the host part
+    int index = referer.indexOf("//");
+    index = referer.indexOf("/", index + 2);
+    if (index == -1) {
+      index = referer.length();
+    }
+    referer = referer.substring(0, index);
+
+    if (domainRegExList == null) {
+      buildDomainList();
+    }
+
+    if (allowedReferers.contains(referer)) {
+      return true;
+    }
+
+    if (domainRegExList.isEmpty()) {
+      return false;
+    }
+
+    for (String domainRegEx : domainRegExList) {
+      // matches is 5 times slower than precompile regex
+      // but as we cache allowed domains anyway (see allowedDomains set)
+      // there is less need to optimize
+      if (referer.matches(domainRegEx)) {
+        allowedReferers.add(referer);
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  private synchronized void buildDomainList() {
+    allowedReferers = new HashSet<String>();
+
+    if (!MobileServerUtils.isMultiServerEnabled()) {
+      domainRegExList = new ArrayList<String>();
+      return;
+    }
+
+    final Collection<String> localDomainList = new ArrayList<String>();
+    localDomainList.addAll(getAllowedDomains(MobileServerController.getInstance()
+        .getThisServerDefinition()));
+    domainRegExList = localDomainList;
+  }
+
+  private List<String> getAllowedDomains(MobileServerDefinition serverDefinition) {
+    final List<String> result = new ArrayList<String>();
+    if (serverDefinition.getURL() != null) {
+      result.add(getAllowedOriginExp(serverDefinition.getURL()));
+    }
+    if (serverDefinition.getAlloweddomains() != null) {
+      String tmpDomains = serverDefinition.getAlloweddomains();
+      // support line breaks instead of commas, support all the platforms
+      // as the browser may run in different OS on the client side
+      tmpDomains = tmpDomains.replace("\r\n", ",");
+      tmpDomains = tmpDomains.replace("\n", ",");
+      tmpDomains = tmpDomains.replace("\r", ",");
+      // all the separators are now commas, split on it
+      final String[] domains = tmpDomains.split(",");
+      for (String domain : domains) {
+        String regEx = getAllowedOriginExp(domain.trim());
+        // test the regEx
+        try {
+          Pattern.compile(regEx);
+          result.add(regEx);
+        } catch (Exception logIt) {
+          Log.error("Reg ex " + regEx + " does not compile " + logIt.getMessage(), logIt);
+        }
+      }
+    }
+    return result;
+  }
+
+  private String getAllowedOriginExp(String url) {
+    // note url can contain dots, but on purpose not escaping those
+    // to allow flexibility, if the user wants explicit dots he/she
+    // should escape them
+
+    String localUrl = url.toLowerCase();
+    int nextIndex = 2 + localUrl.indexOf("//");
+    if (localUrl.indexOf("/", nextIndex) == -1) {
+      return localUrl;
+    }
+    localUrl = localUrl.substring(0, localUrl.indexOf("/", nextIndex));
+    return localUrl;
+  }
+
+  /**
+   * Clear the cache when a mobile server definition is saved.
+   */
+  public static class MobileServerDefinitionEventHandler extends EntityPersistenceEventObserver {
+
+    private static Entity[] entities = { ModelProvider.getInstance().getEntity(
+        MobileServerDefinition.ENTITY_NAME) };
+    protected Logger logger = Logger.getLogger(this.getClass());
+
+    @Override
+    protected Entity[] getObservedEntities() {
+      return entities;
+    }
+
+    public void onSave(@Observes EntityNewEvent event) {
+      if (!isValidEvent(event)) {
+        return;
+      }
+      domainRegExList = null;
+    }
+
+    public void onUpdate(@Observes EntityUpdateEvent event) {
+      if (!isValidEvent(event)) {
+        return;
+      }
+      domainRegExList = null;
+    }
+
+    public void onDelete(@Observes EntityDeleteEvent event) {
+      if (!isValidEvent(event)) {
+        return;
+      }
+      domainRegExList = null;
+    }
+  }
+
+}
diff --git a/src/org/openbravo/retail/storeserver/synchronization/RetrieveServerVersionStatus.java b/src/org/openbravo/retail/storeserver/synchronization/RetrieveServerVersionStatus.java
--- a/src/org/openbravo/retail/storeserver/synchronization/RetrieveServerVersionStatus.java
+++ b/src/org/openbravo/retail/storeserver/synchronization/RetrieveServerVersionStatus.java
@@ -39,11 +39,6 @@
 public class RetrieveServerVersionStatus extends JSONProcessSimple {
 
   @Override
-  protected boolean ignoreTransitioningStatus() {
-    return true;
-  }
-
-  @Override
   public JSONObject exec(JSONObject jsonSent) throws JSONException, ServletException {
     final MobileServerDefinition thisServer = MobileServerController.getInstance()
         .getThisServerDefinition();
diff --git a/src/org/openbravo/retail/storeserver/synchronization/StoreServerVersionHandler.java b/src/org/openbravo/retail/storeserver/synchronization/StoreServerVersionHandler.java
--- a/src/org/openbravo/retail/storeserver/synchronization/StoreServerVersionHandler.java
+++ b/src/org/openbravo/retail/storeserver/synchronization/StoreServerVersionHandler.java
@@ -1,7 +1,7 @@
 /*
  *************************************************************************
  * Openbravo DB Synchronization module for Retail
- * Copyright (C) 2017 Openbravo SLU 
+ * Copyright (C) 2018 Openbravo SLU 
  *
  * The content of this file is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -43,38 +43,33 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * Class which manages store server versions and version checks to prevent servers in different
- * versions to exchange information.
+ * Class which manages store server versions and version checks to prevent servers in different versions to exchange information.
  * 
- * Some background information: - when a server starts the system checks if modules have been
- * installed/updated - if this is the case then the server will regenerate the modules-by-server
- * table for this server and compute - a new version number - the list of modules by server are
- * replicated, from a store to central, and for the central server (so the modules of the central
- * server) to all stores.
+ * Some background information: - when a server starts the system checks if modules have been installed/updated - if this is the
+ * case then the server will regenerate the modules-by-server table for this server and compute - a new version number - the list
+ * of modules by server are replicated, from a store to central, and for the central server (so the modules of the central server)
+ * to all stores.
  * 
  * For the central and store server there are different consequences.
  * 
- * If the central server modules change then the new module list is replicated to all store servers.
- * The {@link VersionCacheResetWriterFilterAdapter} class runs in the store server and listens to
- * this replication. If the central server modules change then automatically the store server
- * version information is recomputed/checked against the new central server version. If the store
- * and central server have different versions for the same modules then the store server will move
- * to offline and to the Different-From-Central version status.
+ * If the central server modules change then the new module list is replicated to all store servers. The
+ * {@link VersionCacheResetWriterFilterAdapter} class runs in the store server and listens to this replication. If the central
+ * server modules change then automatically the store server version information is recomputed/checked against the new central
+ * server version. If the store and central server have different versions for the same modules then the store server will move to
+ * offline and to the Different-From-Central version status.
  * 
- * If the store server modules change then the store server will recompute its version and replicate
- * its modules-by-server to the central server.
+ * If the store server modules change then the store server will recompute its version and replicate its modules-by-server to the
+ * central server.
  * 
- * There is also a writer adapter {@link PreferenceWriterFilterAdapter} which listens to replication
- * of the writer filter adapter from the central to the store server. If the ignore-version-check
- * preference changes then the store servers version status is recomputed also.
+ * There is also a writer adapter {@link PreferenceWriterFilterAdapter} which listens to replication of the writer filter adapter
+ * from the central to the store server. If the ignore-version-check preference changes then the store servers version status is
+ * recomputed also.
  * 
- * When the store server is incompatible with the central server then the
- * {@link StoreServerIncomingSynchronizationPreventer} will prevent data to be replicated from
- * central to the store.
+ * When the store server is incompatible with the central server then the {@link StoreServerIncomingSynchronizationPreventer} will
+ * prevent data to be replicated from central to the store.
  * 
- * The {@link RetailSynchronizationRequestAllowedHandler} plays a role in preventing a webpos which
- * is not loaded from the store server to connect to the store server if the store/central server
- * have different versions.
+ * The {@link RetailSynchronizationRequestHandler} plays a role in preventing a webpos which is not loaded from the store server
+ * to connect to the store server if the store/central server have different versions.
  * 
  * @author mtaal
  */
@@ -120,9 +115,8 @@
   }
 
   /**
-   * Returns true if the caller should take into account if the store and central server have
-   * different versions. Returns false in other cases, for example if the ignore version differences
-   * preference is set.
+   * Returns true if the caller should take into account if the store and central server have different versions. Returns false in
+   * other cases, for example if the ignore version differences preference is set.
    */
   public boolean doVersionCheck() {
     if (doResetCachedInformation || ignoreVersionCheck == null) {
@@ -253,8 +247,7 @@
   }
 
   /**
-   * Creates the entries in the modules by server table. Only does this if the version of the
-   * modules changed.
+   * Creates the entries in the modules by server table. Only does this if the version of the modules changed.
    */
   public void recomputeCurrentServerVersions() {
     // read the modules and add the version
@@ -523,8 +516,7 @@
   }
 
   /**
-   * Return true if the store and central versions are the same or if no version differences should
-   * be checked.
+   * Return true if the store and central versions are the same or if no version differences should be checked.
    * 
    * @return
    */
diff --git a/src/org/openbravo/retail/storeserver/synchronization/StoreSynchronizationComponentProvider.java b/src/org/openbravo/retail/storeserver/synchronization/StoreSynchronizationComponentProvider.java
--- a/src/org/openbravo/retail/storeserver/synchronization/StoreSynchronizationComponentProvider.java
+++ b/src/org/openbravo/retail/storeserver/synchronization/StoreSynchronizationComponentProvider.java
@@ -1,7 +1,7 @@
 /*
  *************************************************************************
  * Openbravo DB Synchronization module for Retail
- * Copyright (C) 2016 Openbravo SLU 
+ * Copyright (C) 2016-2018 Openbravo SLU 
  *
  * The content of this file is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,11 +56,11 @@
     globalResources.add(createComponentResource(ComponentResourceType.Static,
         "web/org.openbravo.retail.storeserver.synchronization/js/serverReloadHandler.js",
         POSUtils.APP_NAME));
- 
+
     globalResources.add(createComponentResource(ComponentResourceType.Static,
         "web/org.openbravo.retail.storeserver.synchronization/js/responseCallbackHandler.js",
         POSUtils.APP_NAME));
-    
+
     globalResources.add(createComponentResource(ComponentResourceType.Static,
         "web/org.openbravo.retail.storeserver.synchronization/js/incompatibleVersionHandler.js",
         POSUtils.APP_NAME));
diff --git a/src/org/openbravo/retail/storeserver/synchronization/SyncStatusOnlineTransitionHandler.java b/src/org/openbravo/retail/storeserver/synchronization/SyncStatusOnlineTransitionHandler.java
--- a/src/org/openbravo/retail/storeserver/synchronization/SyncStatusOnlineTransitionHandler.java
+++ b/src/org/openbravo/retail/storeserver/synchronization/SyncStatusOnlineTransitionHandler.java
@@ -1,7 +1,7 @@
 /*
  *************************************************************************
  * Openbravo DB Synchronization module for Retail
- * Copyright (C) 2016-2017 Openbravo SLU 
+ * Copyright (C) 2016-2018 Openbravo SLU 
  *
  * The content of this file is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,17 +20,20 @@
 
 package org.openbravo.retail.storeserver.synchronization;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
+import org.codehaus.jettison.json.JSONObject;
 import org.jumpmind.symmetric.web.ServerSymmetricEngine;
 import org.openbravo.base.exception.OBException;
 import org.openbravo.mobile.core.servercontroller.MobileServerController;
+import org.openbravo.mobile.core.servercontroller.MobileServerRequestExecutor;
 import org.openbravo.mobile.core.servercontroller.MobileServerTransitionToOnlineHandler;
+import org.openbravo.mobile.core.servercontroller.MobileServerUtils;
 import org.openbravo.replication.symmetricds.SynchronizationEngineProvider;
 
 /**
- * This class checks if there are is any data pending to be synced from store to central or vice
- * versa. Also it checks if there are import entries to be processed. If so then the store needs to
- * wait with going online.
+ * This class checks if there are is any data pending to be synced from store to central or vice versa. Also it checks if there
+ * are import entries to be processed. If so then the store needs to wait with going online.
  * 
  * @see RetrieveSyncStatus
  * @author mtaal
@@ -76,11 +79,43 @@
             .countWaitingBatchesAndImportEntries(null);
       }
 
+      // nothing on our side
       if (countWaitingEntriesAndBatches == 0) {
-        goOnline = true;
+        // now call the central server to check the status of things to be sent
+        // to the store server
+        final JSONObject parameters = new JSONObject();
+        parameters.put("serverKey", MobileServerController.getInstance().getThisServerDefinition()
+            .getMobileServerKey());
+        try {
+          final JSONObject result = MobileServerRequestExecutor.getInstance()
+              .executeCentralRequest(
+                  MobileServerUtils.OBWSPATH + RetrieveSyncStatus.class.getName(), parameters);
+          if (result == null) {
+            // didn't get a valid reply from the server
+            // very basic webservice, if it fails server must be offline
+            goOnline = false;
+          } else if (result.has("batchToSyncCount")) {
+            goOnline = 0 == result.getInt("batchToSyncCount");
+            if (!goOnline) {
+              offLineLog = this.getClass().getSimpleName() + " the central server has "
+                  + result.getInt("batchToSyncCount")
+                  + " waiting importentries/synchronization-batches for this server ";
+            }
+          } else {
+            // incorrect json, report error but still go online
+            log.error("Incorrect json format, no batchToSyncCount: " + result);
+            goOnline = true;
+          }
+        } catch (Throwable t) {
+          // remain false
+          log.error(t.getMessage(), t);
+          return;
+        }
       } else {
         offLineLog = this.getClass().getSimpleName() + " this server has "
             + countWaitingEntriesAndBatches + " waiting importentries/synchronization-batches ";
+      }
+      if (!goOnline && !StringUtils.isBlank(offLineLog)) {
         log.warn("Not going online because: " + offLineLog);
       }
     } catch (Throwable t) {
@@ -98,4 +133,4 @@
     return goOnline;
   }
 
-}
+}
\ No newline at end of file
diff --git a/src/org/openbravo/retail/storeserver/synchronization/eventhandler/MobileServerEventHandler.java b/src/org/openbravo/retail/storeserver/synchronization/eventhandler/MobileServerEventHandler.java
--- a/src/org/openbravo/retail/storeserver/synchronization/eventhandler/MobileServerEventHandler.java
+++ b/src/org/openbravo/retail/storeserver/synchronization/eventhandler/MobileServerEventHandler.java
@@ -1,7 +1,7 @@
 /*
  *************************************************************************
  * Openbravo DB Synchronization module for Retail
- * Copyright (C) 2017 Openbravo SLU 
+ * Copyright (C) 2017-2018 Openbravo SLU 
  *
  * The content of this file is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -73,7 +73,7 @@
       throw new OBException("This method can only be called in multi-server-mode");
     }
 
-    final String strSql = "select 1 from sym_incoming_error";
+    final String strSql = "select 1 from sym_incoming_error where batch_id in (select batch_id from sym_incoming_batch where status = 'ER')";
     // use a separate/new dal connection to prevent infinite loops in hibernate
     ConnectionProvider readOnlyCP = DalConnectionProvider.getReadOnlyConnectionProvider();
     Connection conn = null;
@@ -101,7 +101,8 @@
         if (st != null) {
           try {
             st.close();
-          } catch (Throwable ignore) {}
+          } catch (Throwable ignore) {
+          }
         }
         readOnlyCP.releaseCommitConnection(conn);
       } catch (Exception e) {
@@ -139,7 +140,7 @@
       }
     }
   }
-  
+
   private void updateOfflineIncomingErrorsFlag(EntityUpdateEvent event) {
     final String currentState = (String) event.getCurrentState(STATUS_PROPERTY);
     final String previousState = (String) event.getPreviousState(STATUS_PROPERTY);
@@ -147,10 +148,10 @@
     final boolean currentStateOffline = MobileServerState.OFFLINE.getValue().equals(currentState);
     final boolean previousStateOffline = MobileServerState.OFFLINE.getValue().equals(previousState);
     final boolean currentStateOnline = MobileServerState.ONLINE.getValue().equals(currentState);
-    
+    final Boolean offlineError = (Boolean) event.getCurrentState(OFFLINE_ERROR_PROPERTY);
     if (currentStateOffline && !previousStateOffline) {
       event.setCurrentState(OFFLINE_ERROR_PROPERTY, doIncomingSyncErrorsExist());
-    } else if (currentStateOnline) {
+    } else if (currentStateOnline && offlineError != null && offlineError) {
       event.setCurrentState(OFFLINE_ERROR_PROPERTY, false);
     }
   }
