Overview

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

Platform

All Resolved Issue

Breaking Changes

  1. The authentication mechanism has been refactored to be more extensible. The LoginServiceBean and LoginWorkerBean classes are now deprecated and just delegate to the new mechanism. If you have overridden them in your project, you need to migrate your extension to using the new functionality. For example, you can use events to intercept login on the middle tier.

  2. Due to improvements in datatypes, a migration of custom datatypes is needed. Studio does it automatically when you switch to the new platform version. If you don’t use Studio and your project has custom datatypes registered in metadata.xml, add id attribute to the datatype element and set it to the value of the NAME constant of your datatype class. For example:

    <datatype id="year" class="com.company.sample.YearDatatype"/>

    The Datatypes class became a wrapper around the DatatypeRegistry bean, so now you cannot invoke its methods until the Spring container is fully initialized. If you have initialized datatype instances in fields of Spring beans like this:

    @Component
    public class MyBean {
        // will throw a NPE on start
        private Datatype<BigDecimal> decimalDatatype = Datatypes.getNN(BigDecimal.class);
        //...
    }

    you should move the initialization to a place where the Spring container is already initialized, for example:

    @Component
    public class MyBean {
    
        @Inject
        private DatatypeRegistry datatypeRegistry;
    
        public void myMethod(BigDecimal value) {
            Datatype<BigDecimal> decimalDatatype = datatypeRegistry.getNN(BigDecimal.class);
        //...
    }
  3. RemoveAction and BulkEditAction do not have remove and update constraint operation types by default anymore. The reason is as follows: constraint scripts are normally executed on middleware and expect entities in the managed state. But when you assign a constraint operation type on an action, the same scripts are executed also on the client with detached entities, which may result in unexpected "unfetched attribute" errors. So it should be a developer’s decision whether to assign constraint operation types to actions and hence execute constraint scripts on the client side.

  4. UserSessionEntity now contains user login in lower case for reliable identification.

  5. In the charts add-on, types of the following parameters have been changed:

    • plotAreaFillColors parameter of SerialChart, GanttChart, XYChart and StockPanel has List<Color> type.

    • fillColors and negativeFillColors parameters of SerialChart, GanttChart, XYChart, RadarChart and StockGraph have List<Color> type.

    • compareGraphFillColors parameter of StockGraph has List<Color> type.

    • startDuration parameter of HasStartEffect has Double type.

    • minorTickInterval parameter of GaugeAxis has Double type.

  6. The charts add-on does not provide artifact com.haulmont.charts:charts-web@web anymore. If you used it explicitly in your build.gradle then remove the following dependency:

    webcontent(group: 'com.haulmont.charts', name: 'charts-web', version: cubaVersion, classifier: 'web', ext: 'zip')
  7. The buildWar and buildUberJar tasks get Polymer UI from the es6-unbundled directory which is a default for the new Polymer build system. If you have Polymer UI in your project, and you build WAR or UberJAR, you should add the following parameter to the build task until you migrate to Polymer 2:

    task buildWar(type: CubaWarBuilding) {
        // ...
        polymerBuildDir = 'bundled'
    }

Data Model

Base Classes

Non-persistent entities should be inherited form the same base classes as persistent ones: BaseUuidEntity, BaseLongIdEntity, and so on. It allows you to have identifiers of any type, which is important when non-persistent entities represent data from some data store. The framework determines if the entity is persistent or not by the file where it is registered: persistence.xml or metadata.xml.

AbstractNotPersistentEntity has been deprecated, but can still be used for backward compatibility.

Number Format

Using the new @NumberFormat annotation, you can define a display format for numeric attributes right in the entity class. So if you need just a specific formatting of an attribute, and don’t need some custom conversion algorithm, then you don’t have to create a Datatype for the attribute. For example, here is an integer number without grouping separators:

@Column(name = "SIMPLE_NUMBER")
@NumberFormat(pattern = "#")
protected Integer simpleNumber;

Datatypes

The datatypes mechanism has been improved for better extensibility.

The getName() method of the Datatype interface is deprecated, and implementation classes do not need the NAME constant. Instead, the id XML attribute is used when the implementation class is registered.

The getJavaClass() method of the Datatype interface now has a default implementation that returns a value of the @JavaClass annotation if it is present on the class.

All datatypes are registered in metadata.xml files, but if old datatypes.xml exists, it is loaded for backward compatibility.

There is no hard-coded list of "standard datatypes" anymore. The default XML attribute in metadata.xml indicates that the datatype should be used by default for a Java class handled by this datatype, i.e. this datatype will be resolved automatically for entity attributes of appropriate type. Standard datatypes are defined in the cuba-metadata.xml of the cuba application component. Subsequent metadata.xml files can add and override any datatype including default ones.

The Datatypes class became a thin wrapper delegating to the DatatypeRegistry and FormatStringsRegistry beans. It is recommended to use DatatypeRegistry directly. Its getId*() methods are designed to get an id the datatype is registered with.

Base View

Sometimes _minimal view includes reference attributes that are not included to _local, so we have added one more predefined view which is available for all entities: _base (defined also in View.BASE constant). It includes all local non-system attributes and attributes defined by @NamePattern (effectively _minimal + _local).

Generic UI

Lookup Screen Customization

When a browse screen is opened as a lookup, it contains an automatically added panel with buttons and a special lookup action. Now you can customize all these parts: replace the frame with buttons for all lookup screens in your project, create your own selection buttons for a certain screen, or customize the lookup action. See details in the documentation.

Controller of Combined Screen

The framework now contains a base class for controllers of combined screens that are created by the Entity combined screen template in Studio. The base class encapsulates all logic of the screen, so concrete screens have no boilerplate code at all. Also, unlike the previous implementation, the base controller provides pessimistic locking in the same way as AbstractEditor does.

PopupButton

The PopupButton component can show not only actions but also custom popup content. For this, the popup nested XML element or the corresponding popupContent API property must contain a single Component or Container. See details in the documentation.

SuggestionPickerField

To simplify usage of the SuggestionPickerField component, we have added a declarative way of providing options for the current user input. It’s the query element, containing a JPQL query for loading options from the database.

BrowserFrame

The new BrowserFrame component is designed to display embedded web pages. It is an equivalent of the HTML iframe element.

The Embedded component has been deprecated. Use the Image component for displaying images or BrowserFrame for embedded web pages.

CurrencyField

The new CurrencyField component is a text field designed for displaying and entering currency values. It has a currency symbol inside the field and is aligned to the right by default.

FTS Conditions in Filter

Previously, the full-text search functionality in the Filter component could be used only by completely replacing the set of structured conditions, i.e. users had to choose whether they want to filter by conditions or by FTS. Now you can use full-text search together with structured conditions: see FTS condition item in the Add condition dialog. It can be particularly useful in predefined filters and application/search folders if you create a set of hidden structured conditions and leave only the FTS condition for users.

Outer Margin in GroupBox

The GroupBox container can have a margin outside its border. Sometimes it can save you from adding an extra container just to provide a margin.

Valo Styles

tiny, small, large, huge predefined styles from the Vaadin’s Valo theme can be used in the following UI components: Button, Label, TextField, TextArea, DateField (large are huge are not supported), LookupField, PickerField, LookupPickerField, SearchPickerField, SuggestionPickerField.

Maximized State

A dialog window or a message dialog can be maximized on opening or when they are already shown. It can be done declaratively in screen’s XML:

<dialogMode maximized="true"/>

Or programmatically:

openWindow("windowAlias", WindowManager.OpenType.DIALOG.setMaximized(true));

showMessageDialog("title", "message", MessageType.WARNING.setMaximized(true));

Return a maximized screen to the normal state:

button.setAction(new BaseAction("unmaximize"){
    @Override
    public void actionPerform(Component component) {
        getDialogOptions().setMaximized(false);
    }
});

Polymer UI

Polymer 2

Polymer Client and CUBA elements have been updated in order to be compatible with Polymer 2.0 which comes with the following major features:

  • compatibility with custom elements v1 and shadow DOM v1 standards which are agreed to be implemented in most modern browsers;

  • support ES6 class-based syntax for defining elements.

See more about new features on Polymer website.

Changes in Build Process

Dependency on Gulp and gulpfile.js were removed in favour of direct polymer-cli usage. By default, Polymer client is targeting browsers with ES6 support, however it’s possible to specify different build target. See details in the documentation.

Manual Migration

Studio does not provide automatic migration, however Polymer templates are compatible with both Polymer 1 and Polymer 2 based clients.

You can migrate your project to Polymer 2 manually by performing the following steps:

  1. Update component versions in bower.json. Here is the example of components which are used in Polymer 2.0 compatible client

       "dependencies": {
         "fetch": "github/fetch#^2.0.2",
         "polymer": "Polymer/polymer#^2.0.1",
         "app-route": "PolymerElements/app-route#^2.0.0",
         "app-layout": "PolymerElements/app-layout#^2.0.1",
         "iron-lazy-pages": "TimvdLippe/iron-lazy-pages#^2.0.2",
         "iron-icons": "PolymerElements/iron-icons#^2.0.1",
         "vaadin-combo-box": "vaadin/vaadin-combo-box#^2.0.0",
         "vaadin-date-picker": "vaadin/vaadin-date-picker#^2.0.0",
         "paper-button": "PolymerElements/paper-button#^2.0.0",
         "paper-input": "PolymerElements/paper-input#^2.0.0",
         "paper-checkbox": "PolymerElements/paper-checkbox#^2.0.0",
         "paper-radio-group": "PolymerElements/paper-radio-group#^2.0.0",
         "paper-radio-button": "PolymerElements/paper-radio-button#^2.0.0",
         "paper-icon-button": "PolymerElements/paper-icon-button#^2.0.0",
         "paper-card": "PolymerElements/paper-card#^2.0.0",
         "paper-toolbar": "PolymerElements/paper-toolbar#^2.0.0",
         "paper-spinner": "PolymerElements/paper-spinner#^2.0.0",
         "paper-toast": "PolymerElements/paper-toast#^2.0.0",
         "paper-listbox": "PolymerElements/paper-listbox#^2.0.0",
         "paper-item": "PolymerElements/paper-item#^2.0.0",
         "paper-drawer-panel": "PolymerElements/paper-drawer-panel#^2.0.0",
         "paper-header-panel": "PolymerElements/paper-header-panel#^2.0.0",
         "paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#^2.0.0",
         "cuba-app": "cuba-elements/cuba-app#^0.3.0",
         "cuba-data": "cuba-elements/cuba-data#^0.3.0",
         "cuba-form": "cuba-elements/cuba-form#^0.4.0",
         "cuba-login": "cuba-elements/cuba-login#^0.3.0",
         "cuba-styles": "cuba-elements/cuba-styles#^0.3.0",
         "cuba-ui": "cuba-elements/cuba-ui#^0.3.0",
         "cuba-file-field": "cuba-elements/cuba-file-field#^0.3.0",
         "webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0",
         "web-animations-js": "web-animations/web-animations-js#^2.3.1"
       }
  2. Change scripts and devDependencies in package.json:

      "scripts": {
        "build": "polymer build"
      },
      "devDependencies": {
        "bower": "^1.8.2",
        "polymer-cli": "^1.5.7"
      },
  3. Change extraDependencies and build properties in polymer.json:

      "extraDependencies": [
        "manifest.json",
        "service-worker.js",
        "bower_components/webcomponentsjs/*.js",
        "bower_components/fetch/fetch.js"
      ],
      "builds": [
        {
          "preset": "es6-unbundled",
          "basePath": "/app-front/",
          "addServiceWorker": false
        }
      ]
  4. Change assemble and deploy tasks in build.gradle:

    configure(polymerClientModule) {
        ...
    
        def frontAppDir = 'app-front'
        ...
    
        task assemble(type: NodeTask, dependsOn: installBowerPackages) {
            script = file("node_modules/polymer-cli/bin/polymer")
            args = ['build']
            inputs.dir "./"
            outputs.dir "build"
        }
    
        task deployUnbundled(type: Copy) {
            from file('./')
            include 'bower_components/**'
            include 'src/**'
            into "$cuba.tomcat.dir/webapps/$frontAppDir"
        }
    
        task deploy(type: Copy, dependsOn: [assemble, deployUnbundled]) {
            from file('build/es6-unbundled')
            into "$cuba.tomcat.dir/webapps/$frontAppDir"
        }
  5. Open index.html and delete webcomponents polyfill loading code:

          var onload = function() {
            // For native Imports, manually fire WebComponentsReady so user code
            // can use the same code path for native and polyfill'd imports.
            if (!window.HTMLImports) {
              document.dispatchEvent(
                new CustomEvent('WebComponentsReady', {bubbles: true})
              );
            }
          };
    
          var webComponentsSupported = (
            'registerElement' in document
            && 'import' in document.createElement('link')
            && 'content' in document.createElement('template')
          );
    
          if (!webComponentsSupported) {
            var script = document.createElement('script');
            script.async = true;
            script.src = 'bower_components/webcomponentsjs/webcomponents-lite.min.js';
            script.onload = onload;
            document.head.appendChild(script);
          } else {
            onload();
          }

    Instead of the code above webcomponents-loader should be used now. Paste the script below inside the head tag:

      <script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>
  6. There are no paper-elements bundle for Polymer 2.0 so it’s required to import each paper-* element used in app separately. Open app-shell.html and change

    <link rel="import" href="../bower_components/paper-elements/paper-elements.html">

    to

    <link rel="import" href="../bower_components/paper-button/paper-button.html">
    <link rel="import" href="../bower_components/paper-input/paper-input.html">
    <link rel="import" href="../bower_components/paper-checkbox/paper-checkbox.html">
    <link rel="import" href="../bower_components/paper-radio-group/paper-radio-group.html">
    <link rel="import" href="../bower_components/paper-radio-button/paper-radio-button.html">
    <link rel="import" href="../bower_components/paper-icon-button/paper-icon-button.html">
    <link rel="import" href="../bower_components/paper-card/paper-card.html">
    <link rel="import" href="../bower_components/paper-toolbar/paper-toolbar.html">
    <link rel="import" href="../bower_components/paper-spinner/paper-spinner.html">
    <link rel="import" href="../bower_components/paper-toast/paper-toast.html">
    <link rel="import" href="../bower_components/paper-listbox/paper-listbox.html">
    <link rel="import" href="../bower_components/paper-drawer-panel/paper-drawer-panel.html">
    <link rel="import" href="../bower_components/paper-header-panel/paper-header-panel.html">
    <link rel="import" href="../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
  7. One of the main breaking changes of Polymer 2 is using slot instead of content tags. So we need to explicitly specify slot for nested elements e.g.:

      <paper-drawer-panel id="drawerPanel">
        <paper-header-panel drawer>
          <paper-toolbar>
        ...
        <paper-header-panel main>
         <paper-toolbar class="main-toolbar">

    should be

      <paper-drawer-panel id="drawerPanel">
        <paper-header-panel slot="drawer">
          <paper-toolbar slot="header">
        ...
        <paper-header-panel slot="main">
         <paper-toolbar slot="header" class="main-toolbar">

    You may also want to use app-layout elements instead of deprecated paper-* layout elements.

  8. Pages included in iron-lazy-pages should not be wrapped with template anymore, change:

      <iron-lazy-pages selected="[[_computeSelectedPage(routeData.page)]]" attr-for-selected="data-route" class="content fit">
        <template is="iron-lazy-page" data-route="">
          <myapp-page></myapp-page>
        </template>
      </iron-lazy-pages>

    to

      <iron-lazy-pages selected="[[_computeSelectedPage(routeData.page)]]" attr-for-selected="data-route" selected-attribute="active" class="content fit">
        <myapp-page data-route=""></myapp-page>
      </iron-lazy-pages>

Also in order to migrate your own component see the full Polymer upgrade guide

Remove the following directories:

  • .gradle

  • modules/polymer-client/.gradle

  • modules/polymer-client/bower_components/

  • modules/polymer-client/node_modules/

and kill gradle daemon before running the upgraded application.

REST API

LDAP Authentication in REST API

REST API now supports external authentication via LDAP. See documentation for details.

Entities Search Filter

You apply filters when loading lists of entities using the entities operation. See documentation for details.

Reporting

New Templates and Output Types

CUBA report generator now supports the following new templates and output types:

  • JasperReports templates allow you to output reports in PDF, HTML and office formats using the open-source JasperReports library.

  • CSV templates allow you to output reports in the CSV format.

  • Table formatter allows you to output reports into tables right inside your application UI. You don’t need to create and upload any templates, just create the report structure and specify Table in the Output type field of the Template editor screen.

Input Parameters Validation

Before executing a report, its input parameters can be validated using Groovy scripts.

JSON Dataset

The new JSON dataset can be used in the report structure. It allows you to specify the set of records in JSON format. The JSON content can be received from a report parameter, an external URL, or generated by a Groovy script.

DOCX Conversion

Reports with DOCX templates can be output to PDF and HTML using LibreOffice, which provides better quality than default conversion using Docx4j. Use the reporting.openoffice.docx.useOfficeForDocumentConversion application property to specify the conversion mode.

Miscellaneous

Events

The new events mechanism is based on Spring application events and adds ability to send events to screens currently opened by the user.

Entity Log

The entity log mechanism now registers and shows old values of changed attributes.

Entity Attribute Access Control

The security subsystem allows you to set up access to entity attributes according to user permissions. But sometimes you may want to change the access to attributes dynamically depending also on the current state of the entity or its linked entities. The new mechanism allows you to create rules of what attributes should be hidden, read-only or required for a particular entity instance, and apply these rules automatically to Generic UI components and REST API. See details in the documentation.

Accordance With View

The EntityStates bean now contains a set of methods that allow you to check if an entity instance has attributes loaded according to a view: checkLoadedWithView() and isLoadedWithView(). You can use these methods to decide whether you need to reload an instance in some business logic.

The @RequiredView annotation can be added to service method definitions to ensure that entity instances are loaded with all the attributes specified in a view.

Support for Microsoft SQL Server 2005

Now you can connect to Microsoft SQL Server 2005 databases using the jTDS JDBC driver. It will be selected if you specify Microsoft SQL Server 2005 database type for your project’s main or additional data store in Studio.

If you don’t use Studio, specify the following parameters for the createDb and updateDb Gradle tasks:

dbms = 'mssql'
dbmsVersion = '2005'

and the following connection parameters in context.xml:

<Resource
  name="jdbc/CubaDS"
  type="javax.sql.DataSource"
  maxIdle="2"
  maxTotal="20"
  maxWaitMillis="5000"
  driverClassName="net.sourceforge.jtds.jdbc.Driver"
  username="sa"
  password="saPass1"
  url="jdbc:jtds:sqlserver://localhost/sample"/>

Updated Dependencies

Java libraries:

com.esotericsoftware/kryo-shaded = 4.0.1
com.fasterxml.jackson = 2.9.0
com.google.code.gson/gson = 2.8.1
com.haulmont.thirdparty/eclipselink = 2.6.2.cuba18
com.haulmont.yarg = 2.0.7
com.microsoft.sqlserver/mssql-jdbc = 6.2.1.jre8
com.vaadin = 7.7.10.cuba.9
com.vaadin.addon/vaadin-context-menu = 0.7.5
commons-cli/commons-cli = 1.4
commons-fileupload/commons-fileupload = 1.3.3
commons-io/commons-io = 2.5
org.apache.commons/commons-collections4 = 4.1
org.apache.commons/commons-compress = 1.14
org.codehaus.groovy/groovy-all = 2.4.12
org.javassist/javassist = 3.21.0-GA
org.springframework = 4.3.10.RELEASE
org.springframework.security = 4.2.3.RELEASE
org.springframework.security.oauth/spring-security-oauth2 = 2.1.1.RELEASE
org.thymeleaf = 3.0.7.RELEASE
org.vaadin.addons/popupbutton = 2.6.0-3
org.webjars/amcharts = 3.20.20
org.webjars/pivottable = 2.3.0

Studio

Settings

Most of the Studio settings were moved from the Studio Server window to the Settings tab of the web interface initial screen. So the Studio Server window now contains only settings that really need a restart:

studio settings 1

Other settings are available after the start on the Settings tab:

studio settings 2

Repository Configuration

Now Studio can manage multiple repositories used in your project. The repository configuration dialog is split into two sections:

studio repositories 1

The first section contains the list of repositories known to Studio, with their URLs and credentials. This list is stored in the ${user.home}/.haulmont/studio/cache/base-projects.xml file. Please note that repository passwords are saved in plain text. Initially the list contains only the CUBA public repositories, and you can add your own.

The second section contains repositories selected for the current project. You can add and remove items in this list using the Use in the project and Remove from the project buttons. The Up/Down buttons allow you to order the repositories in your build.gradle. The order of repositories affects the sequence of searching for platform versions, so we recommend placing a repository containing the platform artifacts on top.

Screen Layout Designer

The screen layout designer has acquired new functionality. First of all, it is Undo and Redo actions that can be invoked using the icon buttons at the top left corner:

studio screen designer 1

The designer now analyzes the screen layout on save and reports about possible issues. In case of a "false positive", you can switch off the analysis for a particular screen in the issue dialog. The icon button at the top right corner indicates whether the analysis is active for the screen, and you can switch it on and off.

Style names of visual components can be selected from the list of predefined styles, see the "plus" button in the stylename field:

studio screen designer 2

Entity Designer

  • Previously, the @OnDelete and @OnDeleteInverse annotations were used only at runtime when processing deletion of soft deleted entities. Now you can define the @OnDeleteInverse annotation also for a reference to a hard deleted entity, and Studio will create an appropriate on delete clause for the foreign key on the database level.

  • Using the Hide properties link at the top of the entity designer, you can collapse the entity properties panel and give more vertical space to the list of attributes. In the collapsed state, the link changes its title and shows the entity name:

    studio entity designer 1
  • If the entity class implements system interfaces like Creatable or Versioned itself (i.e. it does not extend StandardEntity), it contains appropriate fields: createTs, createdBy and so on. Now Studio shows them in the attributes table, and you can arrange them using the Up/Down buttons:

    studio entity designer 2
  • The Studio entity designer can create method-based non-persistent attributes. If you select Transient checkbox and deselect Create field, the attribute becomes read-only:

    studio entity designer 3

    The source code of the attribute will look as follows:

    @MetaProperty(related = {"name", "num"})
    public String getTitle() {
        return name + " - " + num; // written manually
    }
  • For reference attributes, the attribute type field contains a button that allows you to navigate to the linked entity:

    studio entity designer 4

    You can go back using the History dialog that is available via Ctrl-Shift-H or Alt-C shortcuts.

View Designer

Sometimes you need to edit large object graphs in the the view designer. The new search capability allows you to quickly find attributes by name:

studio view designer 1
. . .