This document is referring to a past Scout release. Please click here for the recent version. Looking for something else? Visit https://eclipsescout.github.io for all Scout related documentation. |
About This Document
This document describes all relevant changes from Eclipse Scout 9.0 to Eclipse Scout 10.0. If existing code has to be migrated, instructions are provided here.
New Web Tool Stack
Scout updated the web tool stack from a custom implementation to a standard Node.js, Webpack and Babel based setup.
Thanks to the power of these tools it is now possible to write modern JavaScript code which will be transpiled at build time so that old browsers can execute the code.
To run the JavaScript build a JavaScript runtime is required. This can be downloaded from Node.js. It is recommended to use a Node.js version 12 because this is a LTS release.
After downloading run the installer and add the installation directory to the PATH environment variable. This allows to use commands like node
or npm
from the command line.
These commands will be required later.
Automatic Migration
In order to reduce the time needed for migrating your code to Scout 10 there is a migration application available which will migrate most of the code automatically.
This application migrates a single Maven module. For a standard Scout application it has to be executed for the .ui module. If your project contains more modules containing JavaScript, CSS or HTML code, the migration application has to be executed for each of these (e.g. .app module). To launch the migration application follow these steps:
-
Clone the following git repository and import it into an empty eclipse workspace: https://github.com/bsi-software/scout-10-migration-template. The workspace and git repository are only necessary temporarily and can be deleted again after the migration.
-
The migration app requires at least Java 8. Also make sure the migration project uses the same encoding as your source code files (a regular scout project uses UTF-8 by default). If you use a different encoding, adjust the property in the pom.xml and press Alt+F5 to reimport the changes:
<properties> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>
-
The migration requires api files to properly generate the import statements. The api files for Scout are already placed in the folder
api
of the project. If your JavaScript code depends on other libraries built with Scout and not only org.eclipse.scout.rt.ui.html, then you need to include the api files from these libraries as well. -
Adjust the methods in the
Config
class to configure the migration application to your local setup. Make sure to read theJavaDoc
to understand what exactly you need to configure. -
The migration application has some prerequisites that the code can be migrated. Ensure that these are met before launching:
-
The source must be properly formatted.
-
One file must only contain one JavaScript class.
-
All files should be committed to VCS (not really a precondition but makes it easier to restart again if the migration fails).
-
-
If the above conditions are fulfilled the migration can be started using the launch config
migrate.launch
. -
The migration is executed in two steps (which will result in two separate VCS commits):
-
First: all existing files are overwritten with the migrated content.
-
Second: the files are moved to theirs new locations.
-
-
Having two steps is necessary to preserve the VCS history. When the first step is finished, the migration app asks you to commit the changes and confirm. Do NOT commit and confirm yet.
-
Have a look at the output. If there is an error you should revise your configuration (maybe you didn’t copy all api files?) and your code (did you extract all JS classes into a separate file?, etc.). To fix the errors abort the migration, reset all files (e.g. use git reset --hard), fix the configuration and run the migration again.
-
If there are no errors anymore have a look at the the migrated files. You will notice that the files are not properly formatted yet. You can do it now, if you like to have a clean git history, or do it later after the migration.
-
If you are pleased with the files commit them. Make sure all files are committed.
-
Now it is time to proceed with the second step. Confirm the message.
-
The migrated files are now moved to theirs new location. When it’s done, commit all the files.
After the migration execution there are some manual post processing tasks that must be executed, see next chapter.
Build Stack Migration
Dependencies to other JS modules are defined in a package.json file and can be installed using NPM. You will notice that sometimes the tool PNPM will be mentioned. This is a different package manager also used by Scout itself to build the Scout modules. This results in slightly different tasks. If you don’t know what to use yet we suggest starting with npm, you can always upgrade to pnpm (or maybe even Yarn) later. |
Depending on the type of application, you either have a *.ui.html module or a *.ui and an *.app module. The ui module typically contains the JS code and the app module the static resources (WebContent folder). If you only have one module it contains both. So if the guide tells you to do something in the .app module and you don’t have one, do it in the .ui.html module instead. |
-
Please do the Automatic Migration first even if you don’t have any JS or CSS files in your project because it will also migrate your HTML files (e.g. index.html etc.).
-
In the pom.xml of your parent project change the version of the parent maven_rt_plugin_config-master to 3.12.7. Ensure that the values of all
relativePath
attributes in theparent
group do not end withpom.xml
. Additionally, update your Scout dependencies to the most recent Scout 10 version. -
If you use Git, create a file (or open the existing one) named
.gitignore
in the .ui module and the .app module (if available) and add the following content:node_modules dist test-results
-
If you only have a .ui module without an .app module (typical Scout Classic app), follow these steps. Otherwise skip this section and continue with the next step.
-
Copy the following file to the root of your .ui.html module (replace the placeholder ${simpleArtifactName} with your application name and ${version} with your application version): package.json
-
Copy the following file to the root of the .ui.hml module: webpack.config.js
-
-
If you have a separate .app module you should have skipped the previous step. Instead do the following steps.
-
Copy the following file to the root of the .ui module (replace the placeholders ${simpleArtifactName} with your application name and ${version} with your application version): package.json
-
Copy the following file to the root of the .ui module: webpack.config.js
-
Copy the following file to the root of the .app module (replace the placeholders ${simpleArtifactName} with your application name, ${version} with your application version and ${rootArtifactId} with the root module name): package.json
If you use pnpm, referencing other npm modules in the same workspace is easier. In that case you should replace "file:../${rootArtifactId}.ui/" with the version of your .ui module (e.g. 1.0.0-snapshot). -
Copy the following file to the root of the .app module (replace the placeholder ${simpleArtifactName} with your application name): webpack.config.js. If you have JavaScript tests, copy the following file to the root of the .ui module: karma.conf.js
-
-
Copy the following file to the directory src/test/js of the .ui module: test-index.js
-
The migrator should have renamed
yourapp-module.js
toindex.js
,yourapp-module.less
toindex.less
and migrated theirs contents. Check these files for TODOS and resolve them, maybe you need to adjust an import. Also, if you have multiple themes, there should be an additional index file for each theme (e.g. index-dark.less). Check these files too. -
The migrator should also have renamed
yourapp-macro.js
toyourapp.js
,yourapp-macro.less
toyourapp-theme.less
and moved them to the src folder. The former index.js is now included into yourapp.js. There should be a theme file for each theme (e.g. yourapp-theme-dark.less). If not, create them manually. Make sure that the theme files properly import the according index files (e.g. yourapp-theme-dark.less should include index-dark.less files if available). -
Open your app file (the one that contains something like
new App().init
, e.g. src/main/js/yourapp.js) and remove the modelsUrl, if present. -
Check your html files. The migrator should have removed obsolete style and script tags and added references to
yourapp.js
andyourapp-theme.js
. If you had multiple custom*-macro.js
or*-macro.less files
there may still be references to an old*-macro.less
file → Use the new matching*-theme.css
file instead or maybe merge it with the regularyourapp-theme.css
file. -
If you have other html files than the migrated index.html, login.html etc. migrate them manually in the same way index.html has been migrated (adjust script, style and include tags).
-
Move all files and folders in src/main/resources/WebContent/res one folder up directly into WebContent and delete the empty res folder.
-
Search for all occurrences of
/res
within the .ui and .app modules and remove the res folder. -
In the file src/main/webapp/WEB-INF/web.xml files of the .ui.html.app.dev and .ui.html.app.war modules change the
filter-exclude
list of theAuthFilter
declaration to the following and replace ${simpleArtifactName} with your application name (if your application uses the Scout LoginApp). TheAuthFilter
may also be calledUiServletFilter
orYourAppNameUiServletFilter
./favicon/* /fonts/* /logo.png /jquery*.js /login*.js /logout*.js /${simpleArtifactName}-theme*.css /eclipse-scout*.js
-
If you have a Repository.js change the global object holding the repositories from
${yourAppNamespace}.repositories = {};
tostatic repositories = {};
and change all references in this file from${yourAppNamespace}.repositories
toRepository.repositories
. -
If you have Jasmine specs, follow these steps. Otherwise you can skip it and continue with the next step.
-
Remove any Jasmine server test launch configurations (jasmine.launch files).
-
Remove any Spec runner HTML files (Spec*Runner*.html files).
-
Remove all entries of the Maven plugins
jasmine-maven-plugin
andphantomjs-maven-plugin
from the pom.xml files. -
In all pom.xml files remove the entries of the Maven plugin
maven-dependency-plugin
that runs in phasegenerate-test-sources
and unpacks files fromorg.eclipse.scout.rt.ui.html
ororg.eclipse.scout.rt.ui.html.test
. -
Move all Specs from src/test/js/${yourAppNamespace} to src/test/js (one folder up)
-
-
If your .ui and .app modules are separated, in the pom.xml of the .ui module add the .following properties:
-
master_skip_npm_build_dev=true
-
master_skip_npm_build_prod=true
-
master_skip_copy_webpack_build_output=true
-
-
Remove the following properties from all your config.properties files:
scout.ui.prebuild
,scout.ui.prebuild.files
,scout.dev.scriptfile.rebuild
,scout.dev.scriptfile.persist.key
. -
If you use pnpm, create a file called
pnpm-workspace.yaml
in the parent folder of your modules (which is most likely the root of your git repository) and include your npm modules (.ui, .app). -
Open a terminal in the folder of the .ui module and run the command
npm install
(orpnpm install
, if you use pnpm). This installs all dependencies that are required by the .ui module. -
Open a terminal in the folder of the .app module and run the command
npm install
(orpnpm install
, if you use pnpm). This installs all dependencies that are required by the .app module (including the .ui module of your project). -
In the terminal of the .app module run the following command:
npm run build:dev
. This triggers the transpiler that creates the JavaScript build output in the dist folder of the .app module. Only after this command has been executed the server can find the web resources to deliver them to the browser. -
If there are any build errors, fix them manually. The migration application might not fix every possible code correctly.
-
In the terminal of the .ui module run the following command:
npm run testserver:start
. This executes the Jasmine Specs in a Chrome browser (Chrome must be installed locally, the same applies to ChromeHeadless if running the build in a CI environment, see Build / Continuous Integration). -
Now it is time to start your app!
Since you already rannpm run build:dev
all the required JS and CSS files should be created and you can start the UI server using your existing launch file. If you now use IntelliJ you need to create a run configuration that usesJettyServer
as main class (have a look at your Eclipse launch file for details). -
If you like, you can create a launch group that start the JS build and the UI server together. Have a look at the Scout archetype for an example (the new Scout Project wizard in Eclipse uses the archetype).
-
Test all your html files (index.html, login.html, logout.html etc.) and all your themes (dark, custom). If everything looks fine, you are done. If not, have a look at the Troubleshooting section.
Instead of npm run build:dev you can also use npm run build:dev:watch which will watch your JS and CSS files. This means you do not need to restart the task when you change JS or CSS files. This does not include the webpack.config.js, changing that file requires running the npm task again.
|
Troubleshooting
-
After starting the server the page in the browser stays blank.
This most likely happens when your created bundles don’t match the bundles required by the HTML files. Check the Network tab in your browser’s DevTools. Which files are being loaded? Are there 404 requests? Check your dist folder. What files are there? To fix it, adjust your HTML files or the entrypoints and chunks inwebpack.config.js
. -
I am not sure if I missed something.
You can always create a new Scout app based on the arche type and compare it with your code. The easiest way is to use Eclipse and create a new Scout Project. Make sure you choose the correct application type (Java for Scout Classic apps, JavaScript for Scout JS apps). -
I don’t understand why I had to do this and what it is for.
Have a look at the Build Stack chapter in the Technical Guide. -
I did everything you said but it still does not work.
Ask at Stack Overflow or the Forum, we are happy to help you out.
Build / Continuous Integration
With the new web tool stack the build of the JS and CSS code does not happen at runtime anymore but during build time. In order to make your life easier most of the npm tasks are automatically started by maven when running mvn install. But there are still a few adjustments you need to make on your CI jobs in order to build your application.
-
Node is installed automatically during maven build when the module contains a package.json. So there is no need to install node on the build server. Nothing to do here for you.
-
To run JavaScript specs Scout now uses ChromeHeadless instead of PhantomJS. If you have JS specs you need to make sure there is a Chrome installed on your build server. The following installation guide worked for our linux servers: https://gist.github.com/ipepe/94389528e2263486e53645fa0e65578b#gistcomment-2379515.
-
In order to display the test results you need to add the new test-results dir in your job configuration (e.g.
*/test-results/*/test-*.xml
) -
You only have to do this step if you want to share your npm packages between different applications.
If you want to deploy npm artifacts to a custom npm repository (e.g. Artifactory), you need to add.npmrc
file to the home directory of your build user on the build server (similar to the.settings.xml
of maven). In order to deploy the artifacts you can use the official npm cli interface (npm publish). If you want to publish snapshots you can use the following command.cd your.app.ui ./target/node/node ./target/node/node_modules/npm/bin/npm-cli.js publish --tag=snapshot
API Changes (Java)
StrictSimpleDateFormat
org.eclipse.scout.rt.jackson.dataobject.StrictSimpleDateFormat
was removed. Use org.eclipse.scout.rt.platform.util.date.StrictSimpleDateFormat
instead.
Data Objects
The Scout data object support was moved from the Scout platform to the module org.eclipse.scout.rt.dataobject
.
The package imports of all data object related classes therefore changed:
From org.eclipse.scout.rt.platform.dataobject
to org.eclipse.scout.rt.dataobject
IDoEntity raw list access
The following methods to access a raw list attribute where changed semantically. The getter now always return a non-null value. If the attribute is not available, an empty list is added as attribute value into the entity and the new created empty list is returned.
-
List<Object> getList(String attributeName)
-
<T> List<T> getList(String attributeName, Class<T> type)
-
<T> List<T> getList(String attributeName, Function<Object, T> mapper)
Additionally two new methods were added, which allows to access an optionally available list attribute, without adding a new attribute value to the entity, if the attribute is not available:
-
Optional<List<Object>> optList(String attributeName)
-
<T> Optional<List<T>> optList(String attributeName, Class<T> type)
Renamings
org.eclipse.scout.rt.client.ui.desktop.datachange.DoChangeEvent
→ org.eclipse.scout.rt.client.ui.desktop.datachange.ItemDataChangeEvent
CacheBuilder
The following methods on CacheBuilder
where removed, since they were unused and covered unused, old functionality:
-
Method
org.eclipse.scout.rt.shared.cache.CacheBuilder.addCacheInstance(ICache<K, V>)
-
Method
org.eclipse.scout.rt.shared.cache.CacheBuilder.getCacheInstances()
Move ICache and transactional Map
AbstractTransactionalMap
and its concrete implementations ConcurrentTransactionalMap
and CopyOnWriteTransactionalMap
have been moved to org.eclipse.scout.rt.platform.util.collection
.
ICache
, its implementations and cache wrappers have been moved to org.eclipse.scout.rt.platform.cache
.
Remove SessionStore Properties
The following properties are no longer used and can be deleted without replacement:
* scout.ui.sessionStore.maxWaitForAllShutdown
* scout.ui.sessionStore.valueUnboundMaxWaitForWriteLock
* scout.ui.sessionstore.housekeepingMaxWaitForShutdown
Authorization API
The authorization API of scout was extended and moved from org.eclipse.scout.rt.shared
into its own module.
You may check the technical guide for further details.
-
Introduced
IPermissionCollection
andIPermission
interfaces -
Let all current scout permission (e.g.
CopyToClipboardPermission
) implementIPermission
-
All scout permission names are now prefixed with
scout.
-
RemoteServiceAccessPermission#getName
returns a stable name instead of the service operation pattern -
Deleted
BasicHierarchyPermission
. If required, you may copy from an older version of scout. -
org.eclipse.scout.rt.shared.services.common.security.IAccessControlService
moved toorg.eclipse.scout.rt.security
-
IAccessControlService#getPermissionLevel
removed; use insteadACCESS#getGrantedPermissionLevel
-
IAccessControlService#checkPermission
removed; use insteadACCESS#check
-
IAccessControlService#getPermissions
must now never returnnull
. InsteadNonePermissionCollection
orAllPermissionCollection
may be returned. -
org.eclipse.scout.rt.shared.services.common.security.ACCESS
moved toorg.eclipse.scout.rt.security.ACCESS
-
ACCESS#check
now fails if argument isnull
(before succeeds). -
org.eclipse.scout.rt.shared.services.common.security.AbstractAccessControlService
moved toorg.eclipse.scout.rt.security
-
AbstractAccessControlService#getUserIdOfCurrentUser
moved toSessions#getCurrentUserId()
Load Permissions
With the new IPermissionCollection
, loading of permissions in AbstractAccessControlService#execLoadPermissions
has changed.
-
Create a new instance by calling
BEANS.get(DefaultPermissionCollection.class)
instead ofnew java.security.Permissions()
. -
Add permissions with a permission level:
permissions.add(new ReadUsersPermission(), PermissionLevel.ALL);
-
Do not forget to set permission collection as read only:
permissions.setReadOnly();
There is also a AllPermissionCollection
which may be used instead of DefaultPermissionCollection
.
TestingUtility → BeanTestingHelper
The following methods are deprecated. Use the corresponding methods on BeanTestingHelper
via BeanTestingHelper.get()
instead:
-
registerBeans
-
registerBean
-
unregisterBean
-
unregisterBeans
-
mockConfigProperty
The following replacement regex can be applied on all Java files:
\bTestingUtility\.(registerBeans|registerBean|unregisterBean|unregisterBeans|mockConfigProperty)
to BeanTestingHelper.get().$1
The following methods are deprecated and will be removed in a future release without a replacement:
-
registerWithReplace
-
registerWithTestingOrder
-
clearHttpAuthenticationCache
API Changes (JavaScript)
WidgetTile
The Widget’s main property tileWidget
is now a fully fledged property.
Up until now the property could only be set on initialization and couldn’t be changed during runtime.
Now the tileWidget
property can be set dynamically during runtime.
This required a change within the div-structure with which the widget is rendered. The tile and the wrapped widget used to share the same container div. Now they both have their own container div as shown in the example below:
<div class="form-field tile">
<div class="field"></div>
</div>
<div class="tile">
<div class="form-field">
<div class="field"></div>
</div>
</div>
AjaxCall (since 10.0.10)
Instances of AjaxCall
now return a single object of type AjaxError
when rejecting the promise.
For historical reasons, jQuery’s AJAX function rejects the promise with three arguments: jqXHR
, textStatus
and errorThrown
. The Promise specification only allows for one "reason" argument. To bring AjaxCall in line with this definition and to make rethrowing the error easier, it now wraps the three arguments into one object of type AjaxError
. It provides the following properties:
jqXHR
-
HTTP request object (jQuery argument #1)
textStatus
-
A string describing the type of error that occurred (jQuery argument #2)
errorThrown
-
The textual portion of the HTTP status (jQuery argument #3)
requestOptions
-
The options object that was passed to the
$.ajax
call. Can be used to retrieve the original URL for debugging or logging purposes.
Migration:
Check your code for any uses of AjaxCall
and change the signature of any fail() or catch() function.
// Old:
var ajaxCall = scout.create('AjaxCall', ajaxOptions);
ajaxCall.call()
.then(function(data) {
processData(data);
})
.catch(function(jqXHR, textStatus, errorThrown) {
handleError(jqXHR, textStatus, errorThrown);
});
// New:
var ajaxCall = scout.create('AjaxCall', ajaxOptions);
ajaxCall.call()
.then(function(data) {
processData(data);
})
.catch(function(ajaxError) {
handleError(ajaxError.jqXHR, ajaxError.textStatus, ajaxError.errorThrown);
});
REST Service Changes
Any changes which may change how REST consumer or provider behave.
Renamings in ErrorDo
org.eclipse.scout.rt.rest.error.ErrorDo
used by org.eclipse.scout.rt.rest.client.proxy.ErrorDoRestClientExceptionTransformer
and some org.eclipse.scout.rt.rest.exception.AbstractExceptionMapper<E>
was slightly changed:
-
ErrorDo#status
→ErrorDo#httpStatus
-
ErrorDo#code
→ErrorDo#errorCode
Different HTTP status codes
A REST service client using ErrorDoRestClientExceptionTransformer
will now transform
-
any client request error (HTTP
4xx
status codes) into aVetoException
-
403 - Forbidden
into aorg.eclipse.scout.rt.dataobject.exception.AccessForbiddenException
-
404 - Not Found
into aorg.eclipse.scout.rt.dataobject.exception.ResourceNotFoundException
The org.eclipse.scout.rt.rest.exception.VetoExceptionMapper
used by a REST service provide will now create an error response with status 400 - Bad Request
(this was formerly a 403
).
Cookies disabled by default
By default, a REST service client will no longer use cookies.
If required, cookies can be enabled by using
clientBuilder.property(RestClientProperties.ENABLE_COOKIES, true);
in configureClientBuilder
of AbstractRestClientHelper
.
StreamUtility.toMap
The default re-map function for duplicated keys used by StreamUtility.toMap
was changed from a throwing merger to a replacing merger mapper.
E.g. if a stream containing duplicated keys is collected into a map, the value of the latest key within the stream is collected into the target map.
Do you want to improve this document? Have a look at the sources on GitHub. |