Overview

This document highlights major changes in CUBA Platform and Studio version 6.5.

Platform

Breaking Changes

  1. The structure of storing references to entities in Entity Log, Entity Snapshots and Dynamic Attributes has been changed. If you have accessed internals of these mechanisms from your application code, you may need to change it accordingly. PL-8461.

  2. Now we use default behavior of Vaadin’s Valo theme (PL-8267) :

    • HBox and VBox use overflow: auto CSS mode. If a HBox or VBox has a child with 0 height then the layout will have non-zero height.

    • Font size is inherited using normal CSS rules instead of explicit setting for components.

  3. The fileExists() method of FileStorageAPI now declares FileStorageException. If you invoke this method, add a catch block. PL-8866.

  4. Validation for input parameters of UniqueNumbersAPI methods has been added. A sequence name can contain only alphanumeric characters and underscores, otherwise IllegalArgumentException is thrown. PL-8724.

  5. Due to cluster improvements explained below, pay attention to the following:

    • If you don’t use Studio migration procedure, edit spring.xml files of all client modules used in your project, find the xyz_proxyCreator bean definitions and replace:

      <property name="clusterInvocationSupport" ref="cuba_clusterInvocationSupport"/>

      with

      <property name="serverSelector" ref="cuba_ServerSelector"/>
    • jgroups.xml has been split into two files: jgroups.xml (UDP stack) and jgroups_tcp.xml (TCP stack). Use cuba.cluster.jgroupsConfig application property to select the stack.

  6. Due to improvements in FieldGroup component explained below:

    • Class FieldGroup.FieldConfig has been refactored to interface. Now you cannot create FieldConfig instance using constructor as it became a Java interface. Use FieldGroup.createField(id) instead.

    • FieldConfig.setDatasource() now does not trigger creation of Field components. Use an additional FieldGroup.bind() call.

  7. Option dialogs opened with showOptionDialog() method of screen controllers are always closed after selecting an option, even if an exception occurs in actionPerform(). PL-8610.

  8. Microsoft’s JDBC driver is now used instead of jTDS if the project uses Microsoft SQLServer database. Studio performs automatic migration when upgrading the project to platform 6.5. PL-8826.

  9. Reporting. If no screens are specified for a report, it is not shown on pop-up window of screen reporting actions. PL-8618.

  10. Charts and Maps. Chart API has been reworked, see below. PL-7754.

  11. Charts and Maps. The GoogleMapViewer interface has been deprecated, use the MapViewer component directly. PL-8787.

Uber JAR

CUBA applications can now be deployed as executable JAR files containing the application code, all dependencies and embedded HTTP server. See UberJAR Deployment for details.

Cluster Improvements

Middleware Load Balancing

Previously, the web client blocks did not perform balancing when worked with multiple middleware blocks. They chose a middleware server from the list specified in the cuba.connectionUrlList at startup and didn’t change it until it became unavailable. So the load balancing was possible only between multiple web blocks (and if cuba.randomServerPriority was set to true): first web block works with first middleware, second web with another middleware and so on. If cuba.randomServerPriority was set to false, each client block selected a middleware block that was first in its cuba.connectionUrlList.

Now the balancing is much more granular - on the user session level. A middleware server is randomly determined on the first remote connection for a user session, and it is fixed for the whole session life time ("sticky session"). Requests from anonymous session and without session do not stick to a server and go to random servers.

The algorithm of selecting a middleware server is provided by the cuba_ServerSorter bean which is by default implemented by the RandomServerSorter class. You can provide your own implementation in the project or use NoopServerSorter to revert to the old behavior when client always selects the first available server from its cuba.connectionUrlList.

Coordination Using ZooKeeper

Application blocks interact in a cluster in two ways: middleware blocks interact with each other, web blocks send requests to middleware. These channels of communication are based on different mechanisms (JGroups for inter-middleware interaction, Spring HTTPInvoker for requesting middleware from clients), however they both require discovering of current cluster topology - what middleware servers are up now and how to connect to them. By default, the following approaches are used:

  • For communication between middleware blocks you set up UDP or TCP stack with some discovery methods. In case of UDP stack the discovery can be automatic as it is based on broadcasting UDP messages. However, broadcasting is often disabled in production environments, so the only reliable method of discovery is to specify the list of server addresses for TCPPING protocol in jgroups.xml. It means that the topology is static - you have to know it in advance when starting a middleware server.

  • For requesting middleware from client blocks, you have to specify addresses of the middleware blocks in the cuba.connectionUrlList application property. It also makes the configuration static - you have to know addresses of the middleware servers when starting a client block.

Now we provide an application component that enables dynamic discovery of middleware servers for both communication channels. It is based on integration with Apache ZooKeeper - a centralized service for maintaining configuration information. When this component is included in your project, you need to specify only one static address when running your application blocks - the address of ZooKeeper. Middleware servers will advertise themselves by publishing their addresses on the ZooKeeper directory and discovery mechanisms will request ZooKeeper for addresses of available servers. If a middleware server goes down, it will be automatically removed from the directory immediately or after a timeout.

The source code of application component is available on GitHub, the binary artifacts are published in the standard CUBA repositories. See README for information about including and configuring the component.

REST API Improvements

Model Versioning

REST API v2 now contains a mechanism that allows you to change your data model but keep compatibility with existing REST clients. If a request from a client contains the modelVersion parameter, REST will apply a set of JSON transformations defined in a special XML configuration file. There are predefined transformations like removing or replacing an attribute, and you can provide custom classes for arbitrary transformations of schema and values. See documentation for details.

Persistent Token Store

By default, REST API v2 OAuth tokens are stored in memory only, which means clients need to re-login if the middleware server is restarted. Now you can turn on persistent storage for authentication tokens: see documentation for details. You may also want to increase token expiration timeout using the cuba.rest.client.tokenExpirationTimeSec application property, which is 12 hours by default.

FileLoader Interface

The new FileLoader interface allows you to work with files contained in File Storage uniformly from the client and middle tier using input/output streams. It’s a managed bean that can be injected or obtained via AppBeans class and it provides openStream() and saveStream() methods to load and save files. Both client and middleware implementations of the interface do not keep the whole file in memory, so you can pass files of any size without the risk of reaching memory limits.

FieldGroup API

We have reworked API of the FieldGroup component, deprecated old procedural methods and added support for dynamic change of the set of fields.

Breaking changes

Class FieldGroup.FieldConfig has been refactored to interface. Now you cannot create FieldConfig instance using constructor as it became a Java interface. Use FieldGroup.createField(id) instead.

FieldConfig.setDatasource() now does not trigger creation of Field components. Use an additional FieldGroup.bind() call.

Deprecated

All methods setField<Something>(fieldId, value) and set<Something>(fieldId, value) have been deprecated. Use FieldConfig APIs instead:

fieldGroup.getFieldNN("login").setVisible(false);

Method FieldGroup.addCustomField has been deprecated. Now, it is recommended to obtain FieldConfig and call setComponent(Component):

LookupField languageLookup = factory.createComponent(LookupField.class);
...
fieldGroupRight.getFieldNN("language").setComponent(languageLookup);
New features

You can specify separate property XML attribute for data binding:

<fieldGroup id="fieldGroup" datasource="userDs" width="AUTO">
    <field id="position1x" property="position"/>
</fieldGroup>

We have introduced the FieldGroupFieldFactory bean that can be replaced globally or for a certain FieldGroup instance using fieldFactoryBean XML attribute or FieldGroup.setFieldFactory() method.

Now you can add/remove fields on the fly using methods: addField(FieldConfig), addField(FieldConfig, colIndex), addField(FieldConfig, colIndex, rowIndex), removeField(fieldId).

See PL-8776 for more details.

DataGrid

We have introduced inline editor for DataGrid component. DataGrid supports line-based editing, where double-clicking (or using Enter key) a row opens the row editor. In the editor, the input fields can be edited, as well as navigated with Tab and Shift+Tab keys. If validation fails, an error is displayed and the user can correct the inputs. It allows a user to edit rows inside of DataGrid using a special editable representation of a row.

gui dataGrid editor

SuggestionPickerField

The visual components library now contains a true autocomplete field with background loading of options: SuggestionPickerField. It is designed to search for entity instances according to a string entered by a user. It differs from SearchPickerField in that it refreshes the list of options on each entered symbol without the need to press Enter. The list of options is loaded in background according to the logic defined by the application developer on the server side.

gui suggestionPickerField

Managed TabSheet

New cuba.web.mainTabSheetMode application property defines which component will be used for Tabbed mode of main window:

  1. Default TabSheet component.

  2. Managed TabSheet component that doesn’t unload tab content from the browser when a user selects another tab.

This property can have one of the two string values: DEFAULT or MANAGED.

MANAGED option is useful when you integrate some thirdparty web UI to your application as HTML iframe using the Embedded component. In case of DEFAULT mode content of a tab and embedded iframe will be completely reloaded on each selected tab switch. If you use MANAGED option then content of a tab remains in a browser memory and will not be reloaded when user switches tabs.

See PL-8464 for more details.

Charts

Charts API has been simplified:

  • Introduced separate component interfaces for all charts: AngularGaugeChart, FunnelChart, GanttChart, PieChart, RadarChart, SerialChart, XYChart. They contain methods that are relevant for a concrete chart implementation.

  • Improved data binding. Now you can simply call addData() method to add items to a chart.

Note: charts XML markup fully compatible with the previous version.

New API usage example:

public class OrderBrowse extends AbstractLookup {
    @Inject
    private PieChart pieChart;  // we can inject typed Chart interface

    @Override
    public void init(Map<String, Object> params) {
        super.init(params);

        // no need to obtain configuration object and cast it to PieChart
        pieChart.setDepth3D(15)
                .setAngle(15)
                .setBalloon(
                        new Balloon()
                                .setColor(Color.AQUA)
                );

        // just add data, no need to create and set ListDataProvider
        pieChart.addData(MapDataItem.of("name", "Some String",
                                        "value", 75));
        pieChart.addData(MapDataItem.of("name", "Another String",
                                        "value", 12));
    }
}
Removed
  • Chart.setConfiguration() - now you have to use concrete Chart interface inheritor.

  • Chart.isByDate() and Chart.setByDate() - now you have to use SeriesBasedChart interface and assign value to CategoryAxis.parseDates property.

Moved
  • Chart.add<SomeEvent>Listener methods now are available only for concrete Chart interfaces.

  • Methods zoomOut, zoomToIndexes, zoomToDates have been moved to SeriesBasedChart interface.

  • Methods zoomOutValueAxes, zoomOutValueAxis, zoomOutValueAxis, zoomValueAxisToValues, zoomValueAxisToValues have been moved to CoordinateChart interface.

Deprecated
  • Constant Chart.NAME no more corresponds to concrete Component class.

  • Chart.getConfiguration() - now you can use concrete Chart inheritor instead, but you still can configure chart using old code based on configuration object.

If you declare charts in XML then concrete chart components will be created and you can inject them to your controller:

@Inject
private SerialChart columnChart;
@Inject
private GanttChart ganttChart;

To migrate old code that uses event listeners you have to add type casts (or use the new chart interface):

@Inject
private Chart pieChart;
...
((PieChart) pieChart).addSliceClickListener(event -> {
});
Simplified data binding API
  • Added convenient constructors to MapDataItem

  • New addData method is available from any Chart interface

pieChart.addData(MapDataItem.of("name", "Some String",
                                "value", 75));
pieChart.addData(MapDataItem.of("name:", "Another String",
                                "value", 12));

See PL-7754 for more details.

Polymer UI

Polymer templates have been adopted to use CUBA Studio’s snippets mechanism. All templates use the same snippets for entity -list and -edit components generation. Also properties and methods of -list and -edit components were extracted to the corresponding behaviors: CubaEntityEditViewBehavior and CubaEntityListViewBehavior which are available in cuba-ui package.

Routing

'Entity CRUD actions' templates were merged to a single 'Entity management' template however you still can choose between cards/simple list representation. The component generated by this template contains routing logic for switching between list and editor state. The state is bound to the URL using app-route components so it is possible to navigate directly to a particular entity editor.

Lookup Approach

cuba-lookup component provides an ability to specify entity -list component in order to select an entity instance for a reference attribute. The list component should be marked with .lookup-screen class.

<link rel="demo-manufacturers-by-country.html">

<cuba-lookup picked-entity="{{entity.manufacturer}}">
  <div class="dropdown">
    ... <!-- dropdown-->
  </div>
  <demo-manufacturers-by-country class="lookup-screen"></demo-manufacturers-by-country>
</cuba-lookup>
File Upload Field

cuba-file-field element provides an ability to upload file to the server. Uploaded file will be shown as clickable link.

<cuba-file-field file-descriptor="{{entity.photo}}"></cuba-file-field>

Studio

Known Issues

  • There is a bug in the Studio release 6.5.5 shell script that prevents launching if current directory is not studio/bin that contains the script. In order to start Studio on Linux, open your terminal, cd to the bin folder and execute studio from it.

Breaking Changes

Polymer Templates

Templates which are used for Polymer UI scaffolding were changed to support routing improvements. In order to adopt those changes and use new templates you have to perform manual upgrade on your Polymer client source code. The changes are listed below.

  1. Add cuba-ui dependency to the bower.json:

    {
      ...
      "dependencies": {
        ...
        "cuba-ui": "cuba-elements/cuba-ui#^0.1.0",
        ...
      }
      ...
    }
  2. Add cuba-ui import to the {namespace}-shell.html:

    <link rel="import" href="../bower_components/cuba-ui/cuba-ui.html">
  3. Make the following changes in {namespace}-shell.html:

    1. add tail property binding in the app-route component:

      <app-route route="{{route}}" pattern="/:page" data="{{routeData}}" tail="{{routeTail}}">
    2. set selected-attribute="active" in the iron-lazy-pages component:

      <iron-lazy-pages selected="[[_computeSelectedPage(routeData.page)]]" attr-for-selected="data-route" selected-attribute="active" class="content fit">
    3. add the following listener and handler:

      Polymer({
        is: 'namespace-shell',
        ...
        listeners: {
          'navigate': '_onNavigate'
        },
        ...
        _onNavigate: function(event, detail) {
          this.set("route.path", detail);
        }
      });

Screen Templates

The API of screen templates has been reworked, so if you have created your own templates, they most probably won’t work in Studio 6.5.

The following API methods have been removed: getEditorNestedDatasourceProperties(), getEditorNestedCollectionDatasourceProperties(), generateDescriptorFileName(), generateFiledGroupXml(), getEditorCollectionAttributesTablesXml(), getBrowseColumns(), generateControllerNameByDescriptorName().

The removed methods are replaced with two new methods: processSnippet() and evaluateScript(), and a number of "snippets" and "scripts". These reusable parts of templates are located in the snippet subdirectory of the templates folder. As a result, all the logic previously hidden inside Studio API is now available in the form of micro-templates.

See Studio context help on the templates editing page for details.

Bintray Repository

All binary artifacts of CUBA platform and Premium Add-ons are now published also on Bintray. Currently we are considering the usage of Bintray as experimental, but if you have any trouble accessing our repo.cuba-platform.com repository, you can easily switch to Bintray by selecting it in the Studio Server window:

https://dl.bintray.com/cuba-platform/main

Authentication for this repository is not needed. After reopening your project, Studio will automatically update the buildscript.repositories section of your build.gradle. There will be separate declarations of all needed repositories, such as mavenCentral, jcenter, etc.

If you use Premium Add-ons, build.gradle will contain additional repository:

maven {
    url 'https://cuba-platform.bintray.com/premium'
    credentials {
        username(rootProject.hasProperty('premiumRepoUser') ?
                    rootProject['premiumRepoUser'] : System.getenv('CUBA_PREMIUM_USER'))
        password(rootProject.hasProperty('premiumRepoPass') ?
                    rootProject['premiumRepoPass'] : System.getenv('CUBA_PREMIUM_PASSWORD'))
    }
}

Studio provides credentials automatically from your subscription information.

When you build your project with Bintray from the command line, there is a distinction from repo.cuba-platform.com repository in how to specify credentials. For Bintray, you should add @cuba-platform suffix to the user name, for example:

gradlew assemble -PpremiumRepoUser=123456123456@cuba-platform -PpremiumRepoPass=abcdefabcdef

Support for Bean Validation

Studio now contains UI for setting field-level bean validation annotations. It is available on the entity attribute panel, for example:

bean validation 2

Please note that you should enter annotation values exactly as they appear in Java code. This is especially important in regular expressions where you should escape \ symbols, for example:

bean validation 1

Groovy-based Entity Listeners

If you have selected Groovy support on the Project properties > Advanced tab,

groovy entity listener 1

you can select Groovy when creating an entity listener:

groovy entity listener 2

Scaffolding Custom Datasources

custom datasource 1

Localized Messages in UI Designer

Studio screen layout designer now displays localized messages (in default locale) instead of message keys. In the example below, the button has its caption attribute set to msg://myButton, but the layout display My Button caption that is set in a message pack for this key:

loc messages 1
. . .