How to Setup MultiServer Dev Environment
The Openbravo Commerce Suite can be used in a multi-server architecture. The most common approach is to use a central server with store servers installed for individual stores or groups of stores.
The store and central server setup makes it possible to develop code running in different servers. Openbravo provides an api to detect in which environment (store or central) your logic runs, allowing you to implement store and central functionality in different ways.
The technological base of the store server is the same as the central server or any Openbravo instance. This gives a lot of benefits related to code management, releasing and updating of code artifacts. In addition you as a developer can focus on the current technologies already being used within Openbravo.
This howto focuses on setting up a multi-server development environment. This helps you to write code running on both central and store servers and makes it possible to test the complete flow from WebPOS to the store server and central server and back.
There are 2 ways of setting up multiple instances locally. The first is more comprehensive but slightly more work. The second makes sense to test simple scenarios.
Multiple Eclipse instances - workspaces
In this approach you create 2 (or more) separate workspaces and development projects. One development workspace corresponds to the central server, the other(s) to one or more store servers.
Each development project has its own source/project tree. Also each project should have its own database.
When setting op the webservers in the Eclipse servers view then make sure that each development project uses its own range of port numbers. In the illustration one server uses ports 8005, 8009 and 8080, the other uses: 9005, 9009 and 9080.
Even with multiple workspaces it is quite possible to share code and make changes made in one workspace visible in the other. The approach is to symlink from the modules directory from one workspace to the workspace of the other. Read this howto for more information. The result shows in linux like this:
Then when making a code change in one eclipse/workspace the change is directly also visible in the other workspace (after refreshing).
- if you symlink and have eclipse open with 2 projects, you make changes in one project then sometimes you need to manually refresh the other work space so eclipse sees the change.
- The thing to watch out for is export.database, when you make a change in the application dictionary then be sure to run export.database in the right project folder to not export the wrong database, as the different instances share the same (symlinked) folder.
One Eclipse IDE Instance
With a 'small trick' you can also use one Eclipse IDE instance and one workspace. You still need to create 2 projects (as above), one for the store and one for the central server. Each with their own database. Then change the project name of one of the projects. This can be done in .project.xml file, for example change the project name of the central to: openbravo-central.
Now you can import both development projects in the same workspace. Then also create 2 servers each running on different ports. Each server does one of the dev projects.
One Eclipse instance - multiple servers defined in Eclipse
In this setup you work with one workspace, development project and one project structure, running two server instances in Eclipse, each for different port numbers. This is a somewhat simpler setup but there are many limitations.
This setup is mainly appropriate to test multi-server requests from the WebPOS clients. It is only appropriate for testing logic where your code does not need to check if it runs on the store or central server to do different behavior. It is also not possible to test/work on communication and requests between central and store server.
Setting up multiple hostnames for localhost
It is important to test and work with different hostnames for your instances when setting up the environment.
If you run your multiple instances on the same localhost (which you do in a dev environment) then the approach is to give the instances different port numbers. The requests to the instances are then for example using http://localhost:8080 and http://localhost:9080. But as these requests share cookies also the session id and authentication information is shared between requests to the same host on different port numbers. This results in incorrect and unpredictable behavior.
Therefore it is important to use different host names when doing requests to multiple servers from a browser. Openbravo Commerce takes care of most other details such as cross-domain requests. So the only thing you need to do is setup different host names and use them. This is quite easy on Linux, add for example the following lines to the /etc/hosts file:
127.0.0.1 central.openbravo.com 127.0.0.1 central1.openbravo.com 127.0.0.1 central2.openbravo.com 127.0.0.1 products.openbravo.com 127.0.0.1 transactions.openbravo.com 127.0.0.1 store1.openbravo.com 127.0.0.1 store2.openbravo.com
Defining Mobile Servers
The next step is to start the instances and for each of them define the mobile servers. In the example there are two servers: Central and Store1. The Store1 is enabled for one organization. The central server works for all organizations. Both servers can provide all services.
- as your instances do not share a database the setup of mobile servers has to be done in each of them (or you can install Symmetric DS first)
- the hostname and port in the url (in the mobile server definition) should be reachable from the browser, for Linux be defined in /etc/hosts and the port number set in the Eclipse server definition (see previous sections)
- the specific mobile server key should be set in Openbravo.properties for each instance (see later section on Base Setup).
- when defining a store server you should check the 'can be registered' checkbox.
- an important field to set is the allowed Origin Domains field (available from 17Q1): it is a list of comma or new-line separate domain definitions. Each domain value can be a complete domain (including http/https and the port number) or a regular expression. See the screenshot below for some examples. WebPOS users are only allowed to use the domains (in the url/address bar of their browser) defined in any of the mobile server definitions or the domains used in the URL of any of the mobile server definition. The content of this field is used to support cross domain server calls from WebPOS to multiple servers.
Example of defining the central server:
Example of defining the store server for one store/organization:
Note for store servers, the trigger state checkbox is normally not checked/is off.
Base Setup: Preferences and Openbravo.properties
So when setting up a development environment with multiple instances also the base setup of preferences and Openbravo.properties should be done for each instance. See this section for the details.
To enable mobile server controlling logic set the relevant preference and the background process to automatically update the state. See here for more information.
For the above mentioned and other relevant preferences please visit this page.
If you don't setup Symmetric DS replication (see later section on this page) then make sure to also define a shared key as is described here.
Also the additional preferences can be of interest to try out.
Note: as you work with multiple instances and databases the preferences and Openbravo.properties setup has to be done for each instance.
Installing Symmetric DS & Store Server Sync module
The install and setup of Symmetric DS is described in this wiki page.
Next to Symmetric DS also install this module:
This module contains the list of tables to sync and the dataset to create a store server.
Updating a server in which SymmetricDS is currently installed
If SymmetricDS is installed in a server (that is, the install.symmetric.ds task has been run), there are two additional tasks that needs to be run before and after running the update.database task.
This is required because when SymmetricDS is installed, it adds triggers and triggers functions to the Openbravo tables that have been configured to be synchronized. These triggers and functions may not adhere to the conventions defined in Openbravo put in place to ensure they can be imported/exported properly. Not adhering to these convensions is not a problem because these triggers are functions are not meant to be imported or exported, but generated on each server.
To prevent error being shown in the log when update.database (or smartbuild with -Dlocal=no), the following commands needs to be run:
ant -f modules/org.openbravo.replication.symmetricds/build.xml uninstall.symmetric.ds.triggers.from.ob.tables
After that the compilation can be performed:
ant smartbuild -Dtr=no -Dlocal=no -Dforce=yes
After compiling and updating the database in a central server, this task needs to be executed:
ant -f modules/org.openbravo.replication.symmetricds/build.xml update.symmetric.ds.configuration
That task updates the SymmetricDS tables used for the trigger creation process and recreates the triggers based on the updated information. There is no need to run this last task in the store servers because their triggers will be updated/recreated automatically the next time the server is started. There is no problem is someone accidentally execute this task in a store server, the task will just do nothing.
Module structure: central versus store server code
In our view there is a lot of potential for code sharing between central and store server code. In addition the store will have a subset of the datamodel of the central server. Often sharing the same table definition for the shared tables. There are 2 ways of developing store and central code:
- creating separate modules for store and central server: this approach works best if there is no code sharing and the store and central server have different database models. Different database models implies that you can not setup Symmetric DS replication between them.
- creating one module sharing code and datamodel: in this case there is one code base and datamodel. The module is installed in the central server as well as in the store server(s). The Openbravo Commerce Suite offers an api to detect in what type of instance your code is running (example: MobileServerController.getInstance().isThisAStoreServer()). Even in this case it can make sense to separate the store and central code in different packages for clarity.
Offline handling: testing down servers
An important reason for having a multi-server architecture is robustness when a server is not available. Other servers can take over and provide the same services. So there is a fair change that you would want to test a server-down scenario from a WebPOS client in your development environment.
A WebPOS client will normally log in on a store server and obtain the client side code from the store server. So if you test a store-server down scenario the webbrowser will see this as being offline and use the browser's appcache to obtain the source code.
But there are several cases in which the appcache will not be available/filled:
- when one or more modules are in development mode, or
- if you have the test.environment=true setting in Openbravo.properties.
- if you use the anonymous mode in browsing with chrome
So to test store-server down scenarios all your modules in the store server dev instance must be set as not in development and there should not be a test.environment=true setting in Openbravo.properties.
Browsing with multiple tabs in chrome - good to know
When using chrome as a developer you often/always open multiple tabs. For example to have the central server backoffice open in one tab and the store server backoffice or webpos in another tab. Therefore it is good to understand specific specialities with chrome multi-tab in combination with Openbravo multi-server.
Some things to know:
- The WebPOS client in multi-server can access both the central and store server directly. Opening http sessions and logging in on both servers.
- The backoffice client will access only one server (the one shown in the address bar).
- Different browser tabs share the same cookie (and http session) when visiting the same host.
When you have both the WebPOS client (accessing the central server) open in one tab and the central server backoffice open in another tab then they will share the same cookie/session.
Sharing the same session/cookie to the same Openbravo server on different chrome tabs can confuse the WebPOS client. It will show messages related to context changed and force to relogin. This happens for example when:
- you switch organization or role in the backoffice-tab
- the default organization of the logged in user is different from the POS terminal organization
- you log in with a different user in the backoffice tab and WebPOS client.
The solution for this is to access WebPOS in the main browser window and then open an incognito window separately to access the backoffice ERP. Note that it seems that all incognito windows also share the cookies/session between them!
Openbravo Commerce supports doing requests from one WebPOS client to multiple servers in the architecture. The WebPOS client has a url pointing to one host from which it obtains the source code (and puts it in the appcache). Requests to other servers are therefore so-called cross domain requests. Cross domain requests are handled specifically in web environments requiring extra request and response headers.
In the configuration of the mobile servers it is important to set the Allowed Origin Domains field in the Mobile Servers Definition. A WebPOS client is only allowed to call the other servers in the environment if the domain (including protocol and port) of the original url of the WebPOS client (from where it loads the webpage itself) is:
- defined as an Allowed Origin Domain in any of the Mobile Server Definitions
- is the domain of the url of any of the Mobile Server Definitions
- if you define the store server with an url: http://store1.openbravo.com/openbravo and there is a central server with url: http://central.openbravo.com/openbravo.
- let's say that there is an alias host mystore.openbravo.com pointing to the same server as store1.openbravo.com.
- then a WebPOS client loaded from http://store1.openbravo.com can do requests to central.openbravo.com, this is allowed and supported.
- however a WebPOS client loaded from http://mystore.openbravo.com can not do requests to central.openbravo.com.
- to also allow mystore.openbravo.com to call central.openbravo.com you have to add: http://mystore.openbravo.com to the Allowed Origin Domains field of any Mobile Server Definition.
Apart from the configuration, Openbravo Commerce takes care of the implementation details, provided you extend existing Openbravo classes and make use of the standard approach of sending requests to the server.
Some links which might be of interest for background information:
Just as with CORS, Openbravo Commerce also takes care of automatic multi-server authentication on all the Openbravo Commerce servers in your architecture. For multi-server authentication Openbravo will generate authentication tokens with a limited live-time-span.
Multi-server authentication requires the use of a specific authentication manager, setup in Openbravo.properties (see also an earlier subsection in this wiki page):
You can see the authentication tokens being appended to the requests when looking in the Chrome Dev console:
When you work with multiple instances in your dev environment and the databases are not synced using Symmetric DS then both instances need to use the same pre-shared key. You can set this up by adding this Openbravo.properties (in all the instances):
Recreate mobile server authentication key
The Recreate Mobile Server Authentication Key process allows to recreate the mobile server authentication key for the current client of the user.