Buscar este blog

Imágenes del tema: MichaelJay. Con la tecnología de Blogger.

Author Info

Labels

Video Of Day

Flickr

martes, 23 de abril de 2019

Lazy, Filtered and Sorted Vaadin Grid using External Data Source

In large enterprise application development projects, it's usual to code use cases that, as the main requirement, define to show the user huge amounts of data in a tabular way. For this kind of scenarios, there is a particular web component that comes really handy: a Grid. Given that we like Vaadin's framework, we are going to describe how to configure it in such a way that doesn't restrict you about performance issues when doing that. 
This post assumes that you have some knowledge of web application development using the Vaadin Framework and the Java Platform. But we’ll try to explain everything as much as possible. The version that we used to write this application is Vaadin 13, but this part of the API is almost the same since Vaadin 8, so it should be possible to use the same approach in older versions.
Setting up a Vaadin Grid, is really easy, just create an instance and then customize the columns, or even skip that part if your Pojo is sufficiently self-descriptive.
As an example, let’s assume that we want to show a grid with data for a person, which we can define as a simplified entity like this:

public class Person {



 private String name;

 private String lastName;

 private Integer age;

 

 public Person(String name, String lastName, Integer age) {

  super();

  this.name = name;

  this.lastName = lastName;

  this.age = age;

 }

 public String getName() {

  return name;

 }

 public void setName(String name) {

  this.name = name;

 }

 public String getLastName() {

  return lastName;

 }

 public void setLastName(String lastName) {

  this.lastName = lastName;

 }

 public Integer getAge() {

  return age;

 }

 public void setAge(Integer age) {

  this.age = age;

 }

}

And then we have a service that will have the responsibility of retrieving this information from a backend, like a database or a remote API. Let’s call it PersonService.
Suppose we want to show those entities in a Vaadin Grid, we would do this:


     List<Person> persons = getPersonService().fetchPersons();

     Grid<Person> personsGrid = new Grid<>(Person.class);

     personsGrid.setItems(persons);

This is fine for small amounts of data, but when dealing with large data sets some features, such as lazy loading, filtering and sorting, must be left to the backend, implementing that all at once can be a complex task, so let's review them.

Lazy Loading

First let’s define what we are talking about when we use this term. Usually when we are handling a list of items, we can choose to obtain  all of them, or just the ones that we want to display or handle in some way. Obviously it depends on the amount. If we are obtaining one hundred of them, it is something that we can manage directly in memory, but if we are handling millions, we have to deal with them in a different way.
This is the case when a mechanism such as lazy loading makes things easier.
Vaadin components, like Grid or ComboBox, already support this kind of behavior, without the need of doing something special, but it only will take care of retrieving what is needed in a lazy loading fashion between the web browser and your web application.
Given that Vaadin only takes care of the presentation layer of your application, you need to do something to apply this behavior from your underlying data source (database, REST API, etc.).


According to the official documentation, you need to ask to your backend two questions:
Can you tell me the total amount of items that we are dealing with?
Of those, can you only give me the first N items, skipping the previous M items?
You don’t need to calculate N and M, those numbers are provided by the framework. They are basically the limit (N) and offset (M). You answer those two questions by providing two lambda expressions to the method DataProvider.fromCallbacks(), something like this:


DataProvider<Person, Void> dataProvider = DataProvider.fromCallbacks(

        // First callback fetches items based on a query

        query -> {

            // The index of the first item to load

            int offset = query.getOffset();

            // The number of items to load

            int limit = query.getLimit();

            List<Person> persons = getPersonService()

                    .fetchPersons(offset, limit);

            return persons.stream();

        },

        // Second callback fetches the number of items for a query

        query -> getPersonService().getPersonCount());

);

Grid<Person> grid = new Grid<>();

grid.setDataProvider(dataProvider);

Now we added two new different methods to our service class.
But let’s continue with another relevant requirement.

Filtering

It’s a rather common request to narrow down the size of the queried items, and one typical way of doing that is to make grids filterable.
But before digging into this, we need to define what is a Filter. For us it’s just a class that will contain values that we want to be taken into account when deciding if a given item will be returned or not.
In our case, let’s assume that we only want to filter people by their name and last name:


public class PersonFilter {

 

 private String nameFilter = null;

 private String lastNameFilter = null;



 public PersonFilter() { 

 }

 

 public PersonFilter(String nameFilter, String lastNameFilter) {

  this.setNameFilter(nameFilter);

  this.setLastNameFilter(lastNameFilter);

 }



 public String getNameFilter() {

  return nameFilter;

 }



 public String getLastNameFilter() {

  return lastNameFilter;

 }



 public void setNameFilter(String nameFilter) {

  this.nameFilter = nameFilter;

 }



 public void setLastNameFilter(String lastNameFilter) {

  this.lastNameFilter = lastNameFilter;

 }

}

Now that we have our filter, how to do the actual filtering?
Instead of calling DataProvider.fromCallbacks(), we are going to use DataProvider.fromFilteringCallbacks(), makes sense, right?


        DataProvider<Person, PersonFilter> dataProvider =

            DataProvider.fromFilteringCallbacks(

            query -> {

              Optional<PersonFilter> filter = query.getFilter();

              return getPersonService().fetchPersons(

                query.getOffset(),

                query.getLimit(),

                filter.map(f -> f.getNameFilter()).orElse(null),

                filter.map(f -> f.getLastNameFilter()).orElse(null)

              );

            },

            query -> {

              Optional<PersonFilter> filter = query.getFilter();

              return getPersonService().getPersonCount(

                filter.map(f -> f.getNameFilter()).orElse(null),

                filter.map(f -> f.getLastNameFilter()).orElse(null)

              );

            }

          );

In this case, what we are doing, is just to obtain the filter from the query, and send the filter values to the backend class. We cannot do the filtering by ourselves because if the underlying backend is a database, then those filters have to be taken into account when building the SQL queries. If we do the filtering by ourselves, then it’s impossible to calculate the final count of the items, without retrieving all of the entities from the backend, causing our lazy loading mechanism to fail its goal (not to retrieve everything). The same applies when calling a remote API.
But let’s continue, if we want to change the filters dynamically, then we need to be able to configure the filters, for that we need to call the method withConfigurableFilter(), that will return an enhanced DataProvider with a method that will allow us to set a given Filter instance:


        PersonFilter gridFilter = new PersonFilter();

        ConfigurableFilterDataProvider<Person,Void,PersonFilter> dp = dataProvider.withConfigurableFilter();

        dp.setFilter(gridFilter);

We can change the filter later, or just save a reference to this instance and modify it’s values. After doing that a call to the method refreshAll() in the DataProvider will trigger the loading of the data with the new filter values.
Now, what about the visual part? … let’s see:

        HeaderRow hr = personsGrid.prependHeaderRow();

        TextField nameFilterTF = new TextField();

        nameFilterTF.addValueChangeListener(ev->{

         gridFilter.setNameFilter(ev.getValue());

         dp.refreshAll();

        });

        hr.getCell(personsGrid.getColumnByKey("name")).setComponent(nameFilterTF);

        TextField lastNameFilterTF = new TextField();

        lastNameFilterTF.addValueChangeListener(ev->{

         gridFilter.setLastNameFilter(ev.getValue());

         dp.refreshAll();

        });

        hr.getCell(personsGrid.getColumnByKey("lastName")).setComponent(lastNameFilterTF);     

First we are creating a HeaderRow, that is a row that will show at the top of our fancy grid, that will contain components that will filter our data.
Then we are creating a TextField for holding the strings to filter the name and last name of our people.
Finally we are adding some value change listeners that will actually apply the filters when changing the value.
That’s great! … now we are loading filtered data in a lazy way using multiple filters.
But what if we need to sort the data? … let’s continue.

Sorting

Similarly to our filtering case, we need a class to store each sorting information that we need:


public class PersonSort {



 private String propertyName;

 private boolean descending;

 

 public String getPropertyName() {

  return propertyName;

 }

 public void setPropertyName(String propertyName) {

  this.propertyName = propertyName;

 }

 public boolean isDescending() {

  return descending;

 }

 public void setDescending(boolean descending) {

  this.descending = descending;

 }

  

}

The class is pretty self-explained. Just holding the property that is currently being sorted, and a boolean for specifying if we sort up or down.
You might think why we are constructing these classes (PersonFilter and PersonSort), given that we could just pass the values directly to the service. The main reason is to have framework agnostic classes to hold these kind of information and then pass them to the backend, making a cleaner separation of layers.
In our example, we are going to provide a new parameter to our PersonService: a list of PersonSort (sort orders). This is a list, because the order of the sort criteria is important, you can establish this order in the Grid component, by calling personsGrid.setMultiSort(true). Let’s review the changes in our code:


        DataProvider<Person, PersonFilter> dataProvider =

          DataProvider.fromFilteringCallbacks(

          query -> {

            Optional<PersonFilter> filter = query.getFilter();

            List<PersonSort> sortOrders = query.getSortOrders().stream().map(sortOrder->new PersonSort(sortOrder.getSorted(),sortOrder.getDirection().equals(SortDirection.ASCENDING))).collect(Collectors.toList());

            return getPersonService().fetchPersons(

              query.getOffset(),

              query.getLimit(),

              filter.map(f -> f.getNameFilter()).orElse(null),

              filter.map(f -> f.getLastNameFilter()).orElse(null),

              sortOrders

            );

          },

          query -> {

            Optional<PersonFilter> filter = query.getFilter();

            return getPersonService().getPersonCount(

              filter.map(f -> f.getNameFilter()).orElse(null),

              filter.map(f -> f.getLastNameFilter()).orElse(null)

            );

          }

        );

Now we are assembling this list of PersonSort, using query.getSortOrders().
The implementation of PersonService is irrelevant, because it's up to the backend to provide the data requested using the information provided:

  • Lazy loading information: offset and limit
  • Filtering information: name and last name filters
  • Sorting information: list of PersonSort

If the backend obtains the data from a relational database, then a SQL clause has to be created dynamically based on that information. For example:


SELECT *

FROM PERSONS P

WHERE P.NAME LIKE %FILTERNAME% AND P.LASTNAME LIKE %LASTNAME%

ORDER BY P.NAME DESC, P.LASTNAME ASC

LIMIT OFFSET,LIMIT

Here's a small animation showing our grid in action:


You can play around with this example, by checking this GitHub project with the sources.
Have fun!

lunes, 17 de diciembre de 2018

Planning your SCM strategy

We have been frequently asked by companies that are planning or are developing a software product about the common issues found trying to achieve a good production workflow, good teamwork and the security of properly handling the code base.
During our years of expertise we developed a strong vision about the most important tools that you need to use if you want to build software in a controlled way.
These tools encourage the implementation of a Software Configuration Management (SCM) strategy within your organization. In turn, this will have a great positive impact in many aspects, some of them technical, but also in many functional and workflow oriented ones.
Today most of software engineers take these tools for granted. But there are cases where companies with small development teams or organizational debts need some help figuring out these stuff. In that spirit we are writing an overview of this topic.
Most of the important problems that could come up are solved by properly installing, configuring and using this tools.
One key fact is that these tools are important regardless of the language or platform that you're using.

First step: Secure your code

You have invested a lot of resources in building your product and you have a few customers using it. The source code is the most important part of that product, so the first issue you have to consider is how to store your code in a secure manner while helping improve the way your team work together without conflicts.
The solution to this is using a Version Control Software. In the beginning there were many different options to choose from, but these days almost everyone is using Git. It's one of the most advanced tools for handling code for large teams and it's easy to find candidates with experience using it.
Of course there are others: SubVersionMercurialTeam Foundation ServerBazaaretc.

Second step: What about the packages?

It's almost impossible to find an organization that builds software without a VCS, but the same cannot be said about handling the binaries or artifacts that you create to distribute your software. Most engineers don't even know there are tools that can be used for this. And why should they consider using such a tool?
In order to answer this, first we need to think about what are the steps involved in writing software:
  1. We begin by writing the code. You can use a minimal tool for doing this, like a simple notepad application, or you could use a heavy IDE with modern code generation techniques, but you almost always end up in tons of text files.
  2. Then, depending on your platform you might need to compile the code into a binary or intermediate format. That is a process that takes a source code as an input, and produces binary files as the output. This step might not be required if you're using an interpreted language as Javascript or PHP. But even in those cases, there are usually a transpilation process that creates new forms of code optimized to run in different browsers, and environments.
  3. Next you test the application in your local environment.
  4. If everything is ok, and you're ready for the production deployment phase. This involves taking the artifact that you tested locally or in a test environment and placing it in the server that is going to expose your application.
To be completely sure that there are no problems with the generated artifact, the best is to always perform the build in a clean environment (we'll explain this later), and in order to avoid repeating this process unnecessarily, the best is to store it in a safe place. This is when the binary repository shows its strength. This tool will store the artifacts in an organized and reliable way so you can download them when you need to deploy, but also when you need to build another software based on a library, for example.
There are many options available: NexusArtifactoryArchiva, etc.

Final step: Continuous Integration

Having the source code and the produced artifacts in place is only the beginning. Automating the construction of the applications and libraries will give you many advantages:
  • Having a clean and centralized place where the software is going to be built. Usually in many companies, the senior developer or the technical leader is the one that builds the artifacts that are going to production. But what if he or she forgets some work in progress or experiment, and then some unwanted behavior is accidentally introduced in the production ready artifact?
  • The building pipeline can be triggered upon changes on the code. This can help in finding possible issues earlier, thus reducing time spent following up on them when found in production, and of course it finally produces better quality deliverables. 
  • The building recipes can be standardized, so no wheels are going to be reinvented in that matter.
  • You can control who triggers builds and deployments, and have logs about those actions. That at the end means better control of the changes that have some impact in important environments, such as staging, testing, etc.
There are many alternatives for this kind of software, but one of the most well known is Jenkins CI. This open source project stands out due to its very large and active community, a vast list of plugins and extensions, addressing almost all of the problems that can arise when configuring this important part of the SCM strategy.
But there are other good choices as well: TeamCityTravisBambooetc.

Bonus track: Versioning scheme

But that is not all, you also need to define how to version your software and libraries, how to handle the release of your artifacts, how to manage dependencies, etc.
For that there are many tools, depending on the platform. For Java developers, Maven is almost a de facto standard, but you can also count with Gradle and Ivy. For .NET platform, you have NuGet, and for Javascript world, you have NPM, Bower and Yarn. All of them can be configured to be used with the binaries repositories, and the CI servers available.
Given the difficulty that can emerge when defining this process in your company, the best is to have the advice of experts.
We have years of experience in this subject, and helped many customers in defining and implementing their SCM strategy, so feel free to contact us and get more information.
See you all in the next post.

viernes, 21 de septiembre de 2018

Developing modern web-apps with Vaadin @ UNL

Last Wednesday we gave a presentation in Universidad Nacional del Litoral, where we explained some concepts related to developing web applications using the latest version of the Finnish framework.
We started explaining what it means to develop a client-server application nowadays, and then some key features of the platform, like the lack of need of browser plugins and the fact that it is completely open-source.
Then we introduced Web Components, a key technology, that is the ground base for the good looking components that are built-in in the platform. Also some introduction for Polymer Project. For more information about these technologies, we recommend reading about it in the WebComponents official site, the Polymer Project official site, and also at Vaadin's site.
Then we started talking about Flow, the Java API for creating modern web-apps using Vaadin's components in the client side. We showed some small examples covering the most significant features like server side DOM manipulation, routing, data binding and synchronization.
If you want to learn more about Flow, the official documentation site is a good place to start.

Students at Universidad Nacional del Litoral

Finally we developed a small application using Flow, showing how easy is to create a good looking web application that can edit data from a back end using Grid, one of the most advanced components.
After the speech, the students were interested in knowing more about the framework and some real life examples. So we decided to upload to GitHub the application that we developed in front of the audience. We added some tags that show each step in the process, feel free to download the sources and try modifying it to cover other use cases!

Lot of questions!

We also recommended another article that we wrote, telling the main steps for developing a complete application that covers how to invoke external REST APIs from the server side.
The experience was great and we found a lot of interest in the framework, so probably we are going to repeat the experience again soon.
Keep in touch with us for updates!

Javier explaining Flow basics

martes, 3 de julio de 2018

Vaadin 10 + Spring Demo application: World Cup Rusia 2018 stats

To test out some new interesting web technologies, we decided to go ahead and build a small demo application that will point out ideas that could potentially help a developer when trying to decide which ones to use in a new project. We decided to create a small application with responsiveness in mind, that would show real time and aggregated data about the current Football World Cup event that is taking place in Russia.

Technologies

The chosen technologies where:
  • Vaadin 10: The brand new version of the popular framework, that is powered by the new standards being pushed by the most popular browsers.
  • SpringFramework: The almost de-facto standard dependency injection framework, that stands as the backbone of almost every java project that are currently being built.
  • REST API: Our project uses the API available here. That API exposes data as a REST API with information being delivered in JSON format.

Features

This is a short list of currently supported features:
  • The application is responsive, it will correctly display information regardless the device being used. This feature is achieved by using Vaadin & Polymer technologies.
  • Depending on the device that you're browsing the site (especially mobile phones), you can add the application to the home screen, so it will look like a native application. The only catch is that it will not function in offline mode (yet, maybe sooner).
  • You can follow the matches in realtime. Using WebSockets, the application maintains an opened communication pipe between the browser and the server, so the updates can be informed to the client as soon as they are received from the API

Construction

You need to have a good starting point to start any new project. For us it was the Vaadin Base Project with String starter. By choosing this option, we could benefit of the fact that it already has a tested and working Spring configuration, so it was an easy decision. 

Responsiveness

We achieved this goal, by starting also a parallel development: a new Addon for the Vaadin platform that helps you to build new applications using a simple skeleton that takes care of building the usual visual elements present in a responsive application: hamburger menu, paper-cards and more.
Besides that, we also used some CSS techniques as media queries to make the final touches.

PWA

To allow the application to be added to the home screen of your device, and then showing it as a native application, we generated a PWA manifest, with some properties that you can easily mimic, by using a tool like the App Manifest Generator.

Realtime updates

This feature is really easy to implement, given Vaadin's @Push tecnology, based on websockets. Just adding a simple annotation to your main layout will give life to your bubbling screen.
You can learn more about this technology in Vaadin's official documentation.

Roadmap

These are the things we would like to implement in the near future:
  • Support for offline message that tells you that you need connectivity to use the app
  • Support for notifications
  • Localization
You can reach the demo online, by accessing: http://worldcup.flowingcode.com/ ... Try adding it to the home screen of your mobile device!
If you want to give us feedback, feel free to create issues in the GithHub page.
Finally some interesting links regarding these technologies:

Interested for our works and services?
Get more of our update !