Browse Source

Migrate Vaadin 7 wiki articles to documentation (#9993)

tags/7.7.11
Henri Sara 6 years ago
parent
commit
15a76bbdca
69 changed files with 8733 additions and 0 deletions
  1. 790
    0
      documentation/articles/AddingJPAToTheAddressBookDemo.asciidoc
  2. 45
    0
      documentation/articles/AutoGeneratingAFormBasedOnABeanVaadin6StyleForm.asciidoc
  3. 584
    0
      documentation/articles/BuildingVaadinApplicationsOnTopOfActiviti.asciidoc
  4. 76
    0
      documentation/articles/ChangingTheDefaultConvertersForAnApplication.asciidoc
  5. 72
    0
      documentation/articles/ConfiguringGridColumnWidths.asciidoc
  6. 74
    0
      documentation/articles/CreatingABasicApplication.asciidoc
  7. 266
    0
      documentation/articles/CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc
  8. 382
    0
      documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc
  9. 135
    0
      documentation/articles/CreatingAReusableVaadinThemeInEclipse.asciidoc
  10. 63
    0
      documentation/articles/CreatingATextFieldForIntegerOnlyInputUsingADataSource.asciidoc
  11. 44
    0
      documentation/articles/CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource.asciidoc
  12. 71
    0
      documentation/articles/CreatingAnApplicationWithDifferentFeaturesForDifferentClients.asciidoc
  13. 103
    0
      documentation/articles/CreatingYourOwnConverterForString.asciidoc
  14. 44
    0
      documentation/articles/FindingTheCurrentRootAndApplication.asciidoc
  15. 177
    0
      documentation/articles/FormattingDataInGrid.asciidoc
  16. 405
    0
      documentation/articles/JMeterTesting.asciidoc
  17. 185
    0
      documentation/articles/JasperReportsOnVaadinSample.asciidoc
  18. 462
    0
      documentation/articles/LazyQueryContainer.asciidoc
  19. 648
    0
      documentation/articles/MigratingFromVaadin6ToVaadin7.asciidoc
  20. 169
    0
      documentation/articles/MigratingFromVaadin7.0ToVaadin7.1.asciidoc
  21. 568
    0
      documentation/articles/OfflineModeForTouchKit4MobileApps.asciidoc
  22. 187
    0
      documentation/articles/ScalaAndVaadinHOWTO.asciidoc
  23. 106
    0
      documentation/articles/ShowingDataInGrid.asciidoc
  24. 163
    0
      documentation/articles/ShowingExtraDataForGridRows.asciidoc
  25. 99
    0
      documentation/articles/SimplifiedRPCusingJavaScript.asciidoc
  26. 107
    0
      documentation/articles/UsingGridWithAContainer.asciidoc
  27. 91
    0
      documentation/articles/UsingGridWithInlineData.asciidoc
  28. 433
    0
      documentation/articles/UsingHibernateWithVaadin.asciidoc
  29. 413
    0
      documentation/articles/UsingJDBCwithLazyQueryContainerAndFilteringTable.asciidoc
  30. 272
    0
      documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc
  31. 437
    0
      documentation/articles/UsingPython.asciidoc
  32. 129
    0
      documentation/articles/UsingVaadinInAnExistingGWTProject.asciidoc
  33. 396
    0
      documentation/articles/VAccessControl.asciidoc
  34. 161
    0
      documentation/articles/Vaadin7HierarchicalContainerAndTreeComponentExampleWithLiferayOrganizationService.asciidoc
  35. 38
    0
      documentation/articles/contents.asciidoc
  36. 338
    0
      documentation/articles/img/DmoOrgTreeUI.java
  37. BIN
      documentation/articles/img/JAR Export (1).png
  38. BIN
      documentation/articles/img/JAR Export (2).png
  39. BIN
      documentation/articles/img/New Java Project.png
  40. BIN
      documentation/articles/img/New Vaadin project (1).png
  41. BIN
      documentation/articles/img/New Vaadin project (2).png
  42. BIN
      documentation/articles/img/Theme to build path.png
  43. BIN
      documentation/articles/img/Theme to deployment assembly.png
  44. BIN
      documentation/articles/img/VAADIN to deployment assembly.png
  45. BIN
      documentation/articles/img/Vaadin to build path.png
  46. BIN
      documentation/articles/img/VaadinJasperReportsSample_small.jpg
  47. BIN
      documentation/articles/img/ab-with-vaadin-scrshot.png
  48. BIN
      documentation/articles/img/address editor.png
  49. BIN
      documentation/articles/img/architecture.png
  50. BIN
      documentation/articles/img/architecture2.png
  51. BIN
      documentation/articles/img/buttons added.png
  52. BIN
      documentation/articles/img/complexdomain.png
  53. BIN
      documentation/articles/img/complexdomain_saving.png
  54. BIN
      documentation/articles/img/complexdomain_saving2.png
  55. BIN
      documentation/articles/img/customForms.png
  56. BIN
      documentation/articles/img/database connected.png
  57. BIN
      documentation/articles/img/deployartifact.png
  58. BIN
      documentation/articles/img/jm1B.png
  59. BIN
      documentation/articles/img/jm2B.png
  60. BIN
      documentation/articles/img/jm3B.png
  61. BIN
      documentation/articles/img/jm4.png
  62. BIN
      documentation/articles/img/jm5.png
  63. BIN
      documentation/articles/img/master detail wireframe.jpg
  64. BIN
      documentation/articles/img/person editor.png
  65. BIN
      documentation/articles/img/process.png
  66. BIN
      documentation/articles/img/screenshot.png
  67. BIN
      documentation/articles/img/sd_s_per_r.gif
  68. BIN
      documentation/articles/img/table and form.png
  69. BIN
      documentation/articles/img/views.png

+ 790
- 0
documentation/articles/AddingJPAToTheAddressBookDemo.asciidoc View File

@@ -0,0 +1,790 @@
[[adding-jpa-to-the-address-book-demo]]
Adding JPA to the address book demo
-----------------------------------

Petter Holmström

[[introduction]]
Introduction
~~~~~~~~~~~~

The https://github.com/vaadin/addressbook/tree/v7[Vaading address book] tutorial (the one
hour version, that is) does a very good job introducing the different
parts of Vaadin. However, it only uses an in-memory data source with
randomly generated data. This may be sufficient for demonstration
purposes, but not for any real world applications that manage data.
Therefore, in this article, we are going to replace the tutorial's
in-memory data source with the Java Persistence API (JPA) and also
utilize some of the new JEE 6 features of
https://glassfish.dev.java.net/[GlassFish] 3.

[[prerequisites]]
Prerequisites
^^^^^^^^^^^^^

In order to fully understand this article, you should be familiar with
JEE and JPA development and you should also have read through the Vaadin
tutorial.

If you want to try out the code in this article you should get the
latest version of GlassFish 3 (build 67 was used for this article) and
http://ant.apache.org[Apache Ant 1.7]. You also need to download the
https://github.com/eriklumme/doc-attachments/blob/master/attachments/addressbook.tar.gz[source code]. *Note, that you have to edit the
_build.xml_ file to point to the correct location of the GlassFish
installation directory before you can use it!*

[[the-system-architecture]]
The System Architecture
~~~~~~~~~~~~~~~~~~~~~~~

The architecture of the application is presented in the following
diagram:

image:img/architecture2.png[System architecture diagram]

In addition to the Vaadin UI created in the tutorial, we will add a
stateless Enterprise Java Bean (EJB) to act as a facade to the database.
The EJB will in turn use JPA to communicate with a JDBC data source (in
this example, the built-in `jdbc/sample` data source).

[[refactoring-the-domain-model]]
Refactoring the Domain Model
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Before doing anything else, we have to modify the domain model of the
Address Book example.

[[the-person-class]]
The Person class
^^^^^^^^^^^^^^^^

In order to use JPA, we have to add JPA annotations to the `Person`
class:

[source,java]
....
// Imports omitted
@Entity
public class Person implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Version
@Column(name = "OPTLOCK")
private Long version;
private String firstName = "";
private String lastName = "";
private String email = "";
private String phoneNumber = "";
private String streetAddress = "";
private Integer postalCode = null;
private String city = "";

public Long getId() {
return id;
}

public Long getVersion() {
return version;
}
// The rest of the methods omitted
}
....

As we do not need to fit the domain model onto an existing database, the
annotations become very simple. We have only marked the class as being
an entity and added an ID and a version field.

[[the-personreference-class]]
The PersonReference class
^^^^^^^^^^^^^^^^^^^^^^^^^

There are many advantages with using JPA or any other Object Persistence
Framework (OPF). The underlying database gets completely abstracted away
and we can work with the domain objects themselves instead of query
results and records. We can detach domain objects, send them to a client
using a remote invocation protocol, then reattach them again.

However, there are a few use cases where using an OPF is not such a good
idea: reporting and listing. When a report is generated or a list of
entities is presented to the user, normally only a small part of the
data is actually required. When the number of objects to fetch is large
and the domain model is complex, constructing the object graphs from the
database can be a very lengthy process that puts the users' patience to
the test – especially if they are only trying to select a person's name
from a list.

Many OPFs support lazy loading of some form, where references and
collections are fetched on demand. However, this rarely works outside
the container, e.g. on the other side of a remoting connection.

One way of working around this problem is to let reports and lists
access the database directly using SQL. This is a fast approach, but it
also couples the code to a particular SQL dialect and therefore to a
particular database vendor.

In this article, we are going to select the road in the middle – we will
only fetch the property values we need instead of the entire object, but
we will use PQL and JPA to do so. In this example, this is a slight
overkill as we have a very simple domain model. However, we do this for
two reasons: Firstly, as Vaadin is used extensively in business
applications where the domain models are complex, we want to introduce
this pattern in an early stage. Secondly, it makes it easier to plug
into Vaadin's data model.

In order to implement this pattern, we need to introduce a new class,
namely `PersonReference`:

[source,java]
....
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.ObjectProperty;
// Some imports omitted

public class PersonReference implements Serializable, Item {
private Long personId;
private Map<Object, Property> propertyMap;

public PersonReference(Long personId, Map<String, Object> propertyMap) {
this.personId = personId;
this.propertyMap = new HashMap<Object, Property>();
for (Map.Entry<Object, Property> entry : propertyMap.entrySet()) {
this.propertyMap.put(entry.getKey(), new ObjectProperty(entry.getValue()));
}
}

public Long getPersonId() {
return personId;
}

public Property getItemProperty(Object id) {
return propertyMap.get(id);
}

public Collection<?> getItemPropertyIds() {
return Collections.unmodifiableSet(propertyMap.keySet());
}

public boolean addItemProperty(Object id, Property property) {
throw new UnsupportedOperationException("Item is read-only.");
}

public boolean removeItemProperty(Object id) {
throw new UnsupportedOperationException("Item is read-only.");
}
}
....

The class contains the ID of the actual `Person` object and a `Map` of
property values. It also implements the `com.vaadin.data.Item`
interface, which makes it directly usable in Vaadin's data containers.

[[the-querymetadata-class]]
The QueryMetaData class
^^^^^^^^^^^^^^^^^^^^^^^

Before moving on to the EJB, we have to introduce yet another class,
namely `QueryMetaData`:

[source,java]
....
// Imports omitted
public class QueryMetaData implements Serializable {

private boolean[] ascending;
private String[] orderBy;
private String searchTerm;
private String propertyName;

public QueryMetaData(String propertyName, String searchTerm, String[] orderBy, boolean[] ascending) {
this.propertyName = propertyName;
this.searchTerm = searchTerm;
this.ascending = ascending;
this.orderBy = orderBy;
}

public QueryMetaData(String[] orderBy, boolean[] ascending) {
this(null, null, orderBy, ascending);
}

public boolean[] getAscending() {
return ascending;
}

public String[] getOrderBy() {
return orderBy;
}

public String getSearchTerm() {
return searchTerm;
}

public String getPropertyName() {
return propertyName;
}
}
....

As the class name suggests, this class contains query meta data such as
ordering and filtering information. We are going to look at how it is
used in the next section.

[[the-stateless-ejb]]
The Stateless EJB
~~~~~~~~~~~~~~~~~

We are now ready to begin designing the EJB. As of JEE 6, an EJB is no
longer required to have an interface. However, as it is a good idea to
use interfaces at the boundaries of system components, we will create
one nonetheless:

[source,java]
....
// Imports omitted
@TransactionAttribute
@Local
public interface PersonManager {

public List<PersonReference> getPersonReferences(QueryMetaData queryMetaData, String... propertyNames);

public Person getPerson(Long id);

public Person savePerson(Person person);
}
....

Please note the `@TransactionAttribute` and `@Local` annotations that
instruct GlassFish to use container managed transaction handling, and to
use local references, respectively. Next, we create the implementation:

[source,java]
....
// Imports omitted
@Stateless
public class PersonManagerBean implements PersonManager {

@PersistenceContext
protected EntityManager entityManager;

public Person getPerson(Long id) {
// Implementation omitted
}

public List<PersonReference> getPersonReferences(QueryMetaData queryMetaData, String... propertyNames) {
// Implementation omitted
}

public Person savePerson(Person person) {
// Implementation omitted
}
}
....

We use the `@Stateless` annotation to mark the implementation as a
stateless session EJB. We also use the `@PersistenceContext` annotation
to instruct the container to automatically inject the entity manager
dependency. Thus, we do not have to do any lookups using e.g. JNDI.

Now we can move on to the method implementations.

[source,java]
....
public Person getPerson(Long id) {
return entityManager.find(Person.class, id);
}
....

This implementation is very straight-forward: given the unique ID, we
ask the entity manager to look up the corresponding `Person` instance
and return it. If no such instance is found, `null` is returned.

[source,java]
....
public List<PersonReference> getPersonReferences(QueryMetaData queryMetaData, String... propertyNames) {
StringBuffer pqlBuf = new StringBuffer();
pqlBuf.append("SELECT p.id");
for (int i = 0; i < propertyNames.length; i++) {
pqlBuf.append(",");
pqlBuf.append("p.");
pqlBuf.append(propertyNames[i]);
}
pqlBuf.append(" FROM Person p");

if (queryMetaData.getPropertyName() != null) {
pqlBuf.append(" WHERE p.");
pqlBuf.append(queryMetaData.getPropertyName());
if (queryMetaData.getSearchTerm() == null) {
pqlBuf.append(" IS NULL");
} else {
pqlBuf.append(" = :searchTerm");
}
}

if (queryMetaData != null && queryMetaData.getAscending().length > 0) {
pqlBuf.append(" ORDER BY ");
for (int i = 0; i < queryMetaData.getAscending().length; i++) {
if (i > 0) {
pqlBuf.append(",");
}
pqlBuf.append("p.");
pqlBuf.append(queryMetaData.getOrderBy()[i]);
if (!queryMetaData.getAscending()[i]) {
pqlBuf.append(" DESC");
}
}
}

String pql = pqlBuf.toString();
Query query = entityManager.createQuery(pql);
if (queryMetaData.getPropertyName() != null && queryMetaData.getSearchTerm() != null) {
query.setParameter("searchTerm", queryMetaData.getSearchTerm());
}

List<Object[]> result = query.getResultList();
List<PersonReference> referenceList = new ArrayList<PersonReference>(result.size());

HashMap<String, Object> valueMap;
for (Object[] row : result) {
valueMap = new HashMap<String, Object>();
for (int i = 1; i < row.length; i++) {
valueMap.put(propertyNames[i - 1], row[i]);
}
referenceList.add(new PersonReference((Long) row[0], valueMap));
}
return referenceList;
}
....

This method is a little more complicated and also demonstrates the usage
of the `QueryMetaData` class. What this method does is that it
constructs a PQL query that fetches the values of the properties
provided in the `propertyNames` array from the database. It then uses
the `QueryMetaData` instance to add information about ordering and
filtering. Finally, it executes the query and returns the result as a
list of `PersonReference` instances.

The advantage with using `QueryMetaData` is that additional query
options can be added without having to change the interface. We could
e.g. create a subclass named `AdvancedQueryMetaData` with information
about wildcards, result size limitations, etc.

[source,java]
....
public Person savePerson(Person person) {
if (person.getId() == null)
entityManager.persist(person);
else
entityManager.merge(person);
return person;
}
....

This method checks if `person` is persistent or transient, merges or
persists it, respectively, and finally returns it. The reason why
`person` is returned is that this makes the method usable for remote
method calls. However, as this example does not need any remoting, we
are not going to discuss this matter any further in this article.

[[plugging-into-the-ui]]
Plugging Into the UI
~~~~~~~~~~~~~~~~~~~~

The persistence component of our Address Book application is now
completed. Now we just have to plug it into the existing user interface
component. In this article, we are only going to look at some of the
changes that have to be made to the code. That is, if you try to deploy
the application with the changes presented in this article only, it will
not work. For all the changes, please check the source code archive
attached to this article.

[[creating-a-new-container]]
Creating a New Container
^^^^^^^^^^^^^^^^^^^^^^^^

First of all, we have to create a Vaadin container that knows how to
read data from a `PersonManager`:

[source,java]
....
// Imports omitted
public class PersonReferenceContainer implements Container, Container.ItemSetChangeNotifier {

public static final Object[] NATURAL_COL_ORDER = new String[] {"firstName", "lastName", "email",
"phoneNumber", "streetAddress", "postalCode", "city"};
protected static final Collection<Object> NATURAL_COL_ORDER_COLL = Collections.unmodifiableList(
Arrays.asList(NATURAL_COL_ORDER)
);
protected final PersonManager personManager;
protected List<PersonReference> personReferences;
protected Map<Object, PersonReference> idIndex;
public static QueryMetaData defaultQueryMetaData = new QueryMetaData(
new String[]{"firstName", "lastName"}, new boolean[]{true, true});
protected QueryMetaData queryMetaData = defaultQueryMetaData;
// Some fields omitted

public PersonReferenceContainer(PersonManager personManager) {
this.personManager = personManager;
}

public void refresh() {
refresh(queryMetaData);
}

public void refresh(QueryMetaData queryMetaData) {
this.queryMetaData = queryMetaData;
personReferences = personManager.getPersonReferences(queryMetaData, (String[]) NATURAL_COL_ORDER);
idIndex = new HashMap<Object, PersonReference>(personReferences.size());
for (PersonReference pf : personReferences) {
idIndex.put(pf.getPersonId(), pf);
}
notifyListeners();
}

public QueryMetaData getQueryMetaData() {
return queryMetaData;
}

public void close() {
if (personReferences != null) {
personReferences.clear();
personReferences = null;
}
}

public boolean isOpen() {
return personReferences != null;
}

public int size() {
return personReferences == null ? 0 : personReferences.size();
}

public Item getItem(Object itemId) {
return idIndex.get(itemId);
}

public Collection<?> getContainerPropertyIds() {
return NATURAL_COL_ORDER_COLL;
}

public Collection<?> getItemIds() {
return Collections.unmodifiableSet(idIndex.keySet());
}

public List<PersonReference> getItems() {
return Collections.unmodifiableList(personReferences);
}

public Property getContainerProperty(Object itemId, Object propertyId) {
Item item = idIndex.get(itemId);
if (item != null) {
return item.getItemProperty(propertyId);
}
return null;
}

public Class<?> getType(Object propertyId) {
try {
PropertyDescriptor pd = new PropertyDescriptor((String) propertyId, Person.class);
return pd.getPropertyType();
} catch (Exception e) {
return null;
}
}

public boolean containsId(Object itemId) {
return idIndex.containsKey(itemId);
}

// Unsupported methods omitted
// addListener(..) and removeListener(..) omitted

protected void notifyListeners() {
ArrayList<ItemSetChangeListener> cl = (ArrayList<ItemSetChangeListener>) listeners.clone();
ItemSetChangeEvent event = new ItemSetChangeEvent() {
public Container getContainer() {
return PersonReferenceContainer.this;
}
};

for (ItemSetChangeListener listener : cl) {
listener.containerItemSetChange(event);
}
}
}
....

Upon creation, this container is empty. When one of the `refresh(..)`
methods is called, a list of `PersonReference`s are fetched from the
`PersonManager` and cached locally. Even though the database is updated,
e.g. by another user, the container contents will not change before the
next call to `refresh(..)`.

To keep things simple, the container is read only, meaning that all
methods that are designed to alter the contents of the container throw
an exception. Sorting, optimization and lazy loading has also been left
out (if you like, you can try to implement these yourself).

[[modifying-the-personform-class]]
Modifying the PersonForm class
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

We now have to refactor the code to use our new container, starting with
the `PersonForm` class. We begin with the part of the constructor that
creates a list of all the cities currently in the container:

[source,java]
....
PersonReferenceContainer ds = app.getDataSource();
for (PersonReference pf : ds.getItems()) {
String city = (String) pf.getItemProperty("city").getValue();
cities.addItem(city);
}
....

We have changed the code to iterate a collection of `PersonReference`
instances instead of `Person` instances.

Then, we will continue with the part of the `buttonClick(..)` method
that saves the contact:

[source,java]
....
if (source == save) {
if (!isValid()) {
return;
}
commit();
person = app.getPersonManager().savePerson(person);
setItemDataSource(new BeanItem(person));
newContactMode = false;
app.getDataSource().refresh();
setReadOnly(true);
}
....

The code has actually become simpler, as the same method is used to save
both new and existing contacts. When the contact is saved, the container
is refreshed so that the new information is displayed in the table.

Finally, we will add a new method, `editContact(..)` for displaying and
editing existing contacts:

[source,java]
....
public void editContact(Person person) {
this.person = person;
setItemDataSource(new BeanItem(person))
newContactMode = false;
setReadOnly(true);
}
....

This method is almost equal to `addContact()` but uses an existing
`Person` instance instead of a newly created one. It also makes the form
read only, as the user is expected to click an Edit button to make the
form editable.

[[modifying-the-addressbookapplication-class]]
Modifying the AddressBookApplication class
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Finally, we are going to replace the old container with the new one in
the main application class. We will start by adding a constructor:

[source,java]
....
public AddressBookApplication(PersonManager personManager) {
this.personManager = personManager;
}
....

This constructor will be used by a custom application servlet to inject
a reference to the `PersonManager` EJB. When this is done, we move on to
the `init()` method:

[source,java]
....
public void init() {
dataSource = new PersonReferenceContainer(personManager);
dataSource.refresh(); // Load initial data
buildMainLayout();
setMainComponent(getListView());
}
....

The method creates a container and refreshes it in order to load the
existing data from the database – otherwise, the user would be presented
with an empty table upon application startup.

Next, we modify the code that is used to select contacts:

[source,java]
....
public void valueChange(ValueChangeEvent event) {
Property property = event.getProperty();
if (property == personList) {
Person person = personManager.getPerson((Long) personList.getValue());
personForm.editContact(person);
}
}
....

The method gets the ID of the currently selected person and uses it to
lookup the `Person` instance from the database, which is then passed to
the person form using the newly created `editContact(..)` method.

Next, we modify the code that handles searches:

[source,java]
....
public void search(SearchFilter searchFilter) {
QueryMetaData qmd = new QueryMetaData((String) searchFilter.getPropertyId(), searchFilter.getTerm(),
getDataSource().getQueryMetaData().getOrderBy(),
getDataSource().getQueryMetaData().getAscending());
getDataSource().refresh(qmd);
showListView();
// Visual notification omitted
}
....

Instead of filtering the container, this method constructs a new
`QueryMetaData` instance and refreshes the data source. Thus, the search
operation is performed in the database and not in the container itself.

As we have removed container filtering, we also have to change the code
that is used to show all contacts:

[source,java]
....
public void itemClick(ItemClickEvent event) {
if (event.getSource() == tree) {
Object itemId = event.getItemId();
if (itemId != null) {
if (itemId == NavigationTree.SHOW_ALL) {
getDataSource().refresh(PersonReferenceContainer.defaultQueryMetaData);
showListView();
} else if (itemId == NavigationTree.SEARCH) {
showSearchView();
} else if (itemId instanceof SearchFilter) {
search((SearchFilter) itemId);
}
}
}
}
....

Instead of removing the filters, this method refreshes the data source
using the default query meta data.

[[creating-a-custom-servlet]]
Creating a Custom Servlet
~~~~~~~~~~~~~~~~~~~~~~~~~

The original tutorial used an `ApplicationServlet` configured in
_web.xml_ to start the application. In this version, however, we are
going to create our own custom servlet. By doing this, we can let
GlassFish inject the reference to the `PersonManager` EJB using
annotations, which means that we do not need any JDNI look ups at all.
As a bonus, we get rid of the _web.xml_ file as well thanks to the new
JEE 6 `@WebServlet` annotation. The servlet class can be added as an
inner class to the main application class:

[source,java]
....
@WebServlet(urlPatterns = "/*")
public static class Servlet extends AbstractApplicationServlet {

@EJB
PersonManager personManager;

@Override
protected Application getNewApplication(HttpServletRequest request) throws ServletException {
return new AddressBookApplication(personManager);
}

@Override
protected Class<? extends Application> getApplicationClass() throws ClassNotFoundException {
return AddressBookApplication.class;
}
}
....

When the servlet is initialized by the web container, the
`PersonManager` EJB will be automatically injected into the
`personManager` field thanks to the `@EJB` annotation. This reference
can then be passed to the main application class in the
`getNewApplication(..)` method.

[[classical-deployment]]
Classical Deployment
~~~~~~~~~~~~~~~~~~~~

Packaging this application into a WAR is no different from the Hello
World example. We just have to remember to include the _persistence.xml_
file (we are not going to cover the contents of this file in this
article), otherwise JPA will not work. Note, that as of JEE 6, we do not
need to split up the application into a different bundle for the EJB and
another for the UI. We also do not need any other configuration files
than the persistence unit configuration file.

The actual packaging can be done using the following Ant target:

[source,xml]
....
<target name="package-with-vaadin" depends="compile">
<mkdir dir="${dist.dir}"/>
<war destfile="${dist.dir}/${ant.project.name}-with-vaadin.war" needxmlfile="false">
<lib file="${vaadin.jar}"/>
<classes dir="${build.dir}"/>
<fileset dir="${web.dir}" includes="**"/>
</war>
</target>
....

Once the application has been packaged, it can be deployed like so,
using the *asadmin* tool that comes with GlassFish:

[source,bash]
....
$ asadmin deploy /path/to/addressbook-with-vaadin.war
....

Note, that the Java DB database bundled with GlassFish must be started
prior to deploying the application. Now we can test the application by
opening a web browser and navigating to
http://localhost:8080/addressbook-with-vaadin. The running application
should look something like this:

image:img/ab-with-vaadin-scrshot.png[Running application screenshot]

[[osgi-deployment-options]]
OSGi Deployment Options
~~~~~~~~~~~~~~~~~~~~~~~

The OSGi support of GlassFish 3 introduces some new possibilities for
Vaadin development. If the Vaadin library is deployed as an OSGi bundle, we can package and
deploy the address book application without the Vaadin library. The
following Ant target can be used to create the WAR:

[source,xml]
....
<target name="package-without-vaadin" depends="compile">
<mkdir dir="${dist.dir}"/>
<war destfile="${dist.dir}/${ant.project.name}-without-vaadin.war" needxmlfile="false">
<classes dir="${build.dir}"/>
<fileset dir="${web.dir}" includes="**"/>
</war>
</target>
....

[[summary]]
Summary
~~~~~~~

In this article, we have extended the Address Book demo to use JPA
instead of the in-memory container, with an EJB acting as the facade to
the database. Thanks to annotations, the application does not contain a
single JNDI lookup, and thanks to JEE 6, the application can be deployed
as a single WAR.

+ 45
- 0
documentation/articles/AutoGeneratingAFormBasedOnABeanVaadin6StyleForm.asciidoc View File

@@ -0,0 +1,45 @@
[[auto-generating-a-form-based-on-a-bean-vaadin-6-style-form]]
Auto-generating a form based on a bean - Vaadin 6 style Form
------------------------------------------------------------

In Vaadin 6 it is easy to get a completely auto generated form based on
a bean instance by creating a `BeanItem` and passing that to a Form. Using
`FieldGroup` this requires a few extra lines as `FieldGroup` never adds
fields automatically to any layout but instead gives that control to the
developer.

Given a bean such as this `Person`:

[source,java]
....
public class Person {
private String firstName,lastName;
private int age;
// + setters and getters
}
....

You can auto create a form using FieldGroup as follows:

[source,java]
....
public class AutoGeneratedFormUI extends UI {
@Override
public void init(VaadinRequest request) {
VerticalLayout layout = new VerticalLayout();
setContent(layout);

FieldGroup fieldGroup = new BeanFieldGroup<Person>(Person.class);

// We need an item data source before we create the fields to be able to
// find the properties, otherwise we have to specify them by hand
fieldGroup.setItemDataSource(new BeanItem<Person>(new Person("John", "Doe", 34)));

// Loop through the properties, build fields for them and add the fields
// to this UI
for (Object propertyId : fieldGroup.getUnboundPropertyIds()) {
layout.addComponent(fieldGroup.buildAndBind(propertyId));
}
}
}
....

+ 584
- 0
documentation/articles/BuildingVaadinApplicationsOnTopOfActiviti.asciidoc View File

@@ -0,0 +1,584 @@
[[building-vaadin-applications-on-top-of-activiti]]
Building Vaadin applications on top of Activiti
-----------------------------------------------

by Petter Holmström

[[introduction]]
Introduction
~~~~~~~~~~~~

In this article, we are going to look at how the
http://www.activiti.org[Activiti] BPM engine can be used together with
Vaadin. We are going to do this in the form of a case study of a demo
application that is available on
https://github.com/peholmst/VaadinActivitiDemo[GitHub]. The code is
licensed under Apache License 2.0 and can freely be used as a foundation
for your own applications.

[[the-example-process]]
The Example Process
^^^^^^^^^^^^^^^^^^^

The following process is used in the demo application:

image:img/process.png[Example process]

Compared to the capabilities of Activiti and BPMN 2.0, the above process
is almost ridiculously simple. However, it allows us to test the
following things:

* *Process start forms*, i.e. forms that need to be filled in before a
process instance is created.
* *User task forms*, i.e. forms that need to be filled in before a task
can be marked as completed.
* Parallell tasks
* Different candidate groups (i.e. groups whose users are potential
assignees of a certain task)

Here is a short walk-through of the process:

1. Before a new process instance is created, the reporter has to fill
in a _Submit bug report form_.
2. Once the instance has been created, two tasks are created:
* *Update bug report*: a manager assigns priority and target version to
the report. Potential assignees are members of the *managers* group.
* *Accept bug report*: a developer accepts the bug report. Potential
assignees are members of the *developers* group.
3. Both of these tasks require the assignee to fill in a form before
they can be completed: the _Update bug report form_ and _Accept bug
report form_, respectively.
4. Once the tasks have been completed, a new task is created, namely
_Resolve bug report_. Potential assignees are members of the
*developers* group. Ideally, this task should automatically be assigned
to whoever claimed the *Accept bug report* task, but currently this is
not implemented.
5. Before the task can be completed, the assignee has to fill in the
_Resolve bug report form_.
6. All tasks have been completed and the process instance ends.

[[prerequisites]]
Prerequisites
^^^^^^^^^^^^^

In order to get the most out of this article, you should already be
familiar with both Vaadin and Activiti. If not, there is enough free
material available on both products' web sites to get you started.

The demo application is a standard Java EE 6 web application and can be
deployed to any JEE 6 web container, such as
http://tomcat.apache.org[Tomcat 7]. It uses an embedded in-memory
http://www.h2database.com[H2 database] for storing data, which means
that all your data will be lost when the server is restarted.

http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/heliossr2[Eclipse
3.6] and the http://vaadin.com/eclipse[Vaadin plugin] was used to create
the application. Both the project files and the third-party libraries
are included in the source code repository. At this point, I recommend
you to download the source code before continuing.

Once you have Eclipse, Tomcat and Git properly installed and configured,
you can follow the following instructions to get the demo application up
and running:

1. Open a command line and clone the Git repository:
`git clone git://github.com/peholmst/VaadinActivitiDemo.git`
2. Start up Eclipse.
3. From the *File* menu, select *Import*.
4. Select *Existing Projects into Workspace* and click *Next*.
5. In the *Select root directory* field, click the *Browse* button and
locate the cloned Git repository directory.
6. In the list of projects, check *VaadinActivitiDemo* and click
*Finish*.
7. In the *Project Explorer*, right-click on *VaadinActivitiDemo*,
point to *Run As* and select *Run on Server*.
8. Select the Tomcat 7 server and click *Finish*.
9. Open a web browser and point it to
_http://localhost:8080/VaadinActivitiDemo_.

[[scope]]
Scope
^^^^^

As Activiti has a huge amount of features, we are only going to look at
a small subset of them in order to keep the scope of this article under
control. More specifically, we are going to look at the following two
questions:

1. How easy (or hard) is it to create custom-built forms using Vaadin
and plug these into Activiti?
2. How easy (or hard) is it to combine process data from Activiti with
other domain data from e.g. JPA?

[[application-architecture]]
Application Architecture
~~~~~~~~~~~~~~~~~~~~~~~~

In this section, we are going to briefly discuss the architecture of the
demo application on a general level and show how it has been implemented
on more technical level. A simplified version of the architecture is
illustrated here:

image:img/architecture.png[Application architecture]

[[the-h2-database]]
The H2 Database
^^^^^^^^^^^^^^^

The H2 database is used in in-memory mode and will start when the
process engine is initialized and stop when the engine is destroyed. All
you have to do is specify some connection parameters when you
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/activiti.cfg.xml[configure
Activiti] and the rest will be handled automatically.

[[the-activiti-engine-and-process-definitions]]
The Activiti Engine and Process Definitions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The Activiti engine is initialized and destroyed by a servlet context
listener, like so:

[source,java]
....
@WebListener
public class ProcessEngineServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
ProcessEngines.init();
deployProcesses();
}

@Override
public void contextDestroyed(ServletContextEvent event) {
ProcessEngines.destroy();
}

private void deployProcesses() {
RepositoryService repositoryService = ProcessEngines.getDefaultProcessEngine().getRepositoryService();
repositoryService.createDeployment()
.addClasspathResource("path/to/bpmn-document.bpmn20.xml")
.deploy();
}
}
....

Once the process engine has been initialized, the context listener
deploys the BPMN 2.0 process definitions to it. In other words, the
Activiti process engine becomes available as soon as the web application
starts and remains up and running until the application is stopped. All
the Vaadin application instances use the same Activiti engine.

[[the-vaadin-application]]
The Vaadin Application
^^^^^^^^^^^^^^^^^^^^^^

The Vaadin application is designed according to the
http://en.wikipedia.org/wiki/Model-view-presenter[Model-View-Presenter]
(MVP) pattern and is implemented using
https://github.com/peholmst/MVP4Vaadin[MVP4Vaadin]. This gives us the
following benefits:

* Clear separation between logic and UI (makes unit testing easier).
* View navigation becomes easier (e.g. the breadcrumb bar shown in the
demo screencast is a built-in part of MVP4Vaadin).

The following diagram illustrates the different views and potential
navigation paths between them:

image:img/views.png[Application views and navigation]

When the application is first started, the
https://github.com/peholmst/VaadinActivitiDemo/tree/master/src/com/github/peholmst/vaadinactivitidemo/ui/login[Login
View] is displayed in the main window. Once the user has logged on, the
main window is replaced with the
https://github.com/peholmst/VaadinActivitiDemo/tree/master/src/com/github/peholmst/vaadinactivitidemo/ui/main[Main
View]:

[source,java]
....
public class DemoApplication extends Application implements ViewListener {
// Field declarations omitted

@Override
public void init() {
createAndShowLoginWindow();
}

private void createAndShowLoginWindow() {
// Implementation omitted
}

private void createAndShowMainWindow() {
// Implementation omitted
}

@Override
public void handleViewEvent(ViewEvent event) {
if (event instanceof UserLoggedInEvent) {
// Some code omitted
createAndShowMainWindow();
} // Other event handlers omitted
}
// Additional methods omitted.
}
....

The main view acts as a controller and container for a number of
embedded views:

* The
https://github.com/peholmst/VaadinActivitiDemo/tree/master/src/com/github/peholmst/vaadinactivitidemo/ui/home[Home
View] is the main menu. From here, you can navigate to the _Process
Browser View_ and the _Identity Management View_.
* The
https://github.com/peholmst/VaadinActivitiDemo/tree/master/src/com/github/peholmst/vaadinactivitidemo/ui/processes[Process
Browser View] contains a list of all the available process definitions.
From this view, you can start new process instances. If a process has a
start form, you can also navigate to the _User Form View_.
* The
https://github.com/peholmst/VaadinActivitiDemo/tree/master/src/com/github/peholmst/vaadinactivitidemo/ui/identity[Identity
Management View] allows you to manage users and user groups.
* The
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/com/github/peholmst/vaadinactivitidemo/ui/tasks/UnassignedTasksViewImpl.java[Unassigned
Tasks View] contains a list of all unassigned tasks. You can navigate to
this view from any other view. From this view, you can assign tasks to
yourself.
* The
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/com/github/peholmst/vaadinactivitidemo/ui/tasks/MyTasksViewImpl.java[My
Tasks View] contains a list of all tasks currently assigned to you. You
can navigate to this view from any other view. From this view, you can
complete tasks. If a task has a form, you can also navigate to the _User
Form View_.
* The
https://github.com/peholmst/VaadinActivitiDemo/tree/master/src/com/github/peholmst/vaadinactivitidemo/ui/forms[User
Form View] is responsible for displaying the _User Task Forms_, e.g.
before a new process instance is created or before a task is completed.
The information about which form to show (if any) is specified in the
BPMN process definition. *Please note that when we are talking about
forms in this article, we are referring to the Acticiti form concept. Do
not confuse this with Vaadin forms.*

These views (or technically speaking their corresponding presenters)
communicate directly with the Activiti engine. For example, the
following snippet is taken from the
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/com/github/peholmst/vaadinactivitidemo/ui/processes/ProcessPresenter.java[`ProcessPresenter`]
class:

[source,java]
....
@Override
public void init() {
getView().setProcessDefinitions(getAllProcessDefinitions());
}

public void startNewInstance(ProcessDefinition processDefinition) {
try {
if (processDefinitionHasForm(processDefinition)) {
openFormForProcessDefinition(processDefinition);
} else {
getRuntimeService().startProcessInstanceById(processDefinition.getId());
getView().showProcessStartSuccess(processDefinition);
}
} catch (RuntimeException e) {
getView().showProcessStartFailure(processDefinition);
}
}

private List<ProcessDefinition> getAllProcessDefinitions() {
ProcessDefinitionQuery query = getRepositoryService().createProcessDefinitionQuery();
return query.orderByProcessDefinitionName().asc().list();
}

private RepositoryService getRepositoryService() {
return ProcessEngines.getDefaultProcessEngine().getRepositoryService();
}

private RuntimeService getRuntimeService() {
return ProcessEngines.getDefaultProcessEngine().getRuntimeService();
}
....

The Main View also regularly checks if there are new tasks available and
notifies the user if that is the case. The
http://vaadin.com/addon/refresher[Refresher] add-on is used to handle
the polling.

[[some-notes-on-mvp4vaadin]]
Some Notes on MVP4Vaadin
^^^^^^^^^^^^^^^^^^^^^^^^

Thanks to MVP4Vaadin, navigation between views is very simple. For
example, the following code snippet is taken from the
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/com/github/peholmst/vaadinactivitidemo/ui/main/components/WindowHeader.java[`WindowHeader`]
component, a part of the Main View implementation:

[source,java]
....
@SuppressWarnings("serial")
private Button createMyTasksButton() {
Button button = new Button();
button.addListener(new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
mainPresenter.showMyTasks();
}
});
button.addStyleName(Reindeer.BUTTON_SMALL);
return button;
}

@SuppressWarnings("serial")
private Button createUnassignedTasksButton() {
Button button = new Button();
button.addListener(new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
mainPresenter.showUnassignedTasks();
}
});
button.addStyleName(Reindeer.BUTTON_SMALL);
return button;
}
....

The corresponding snippets from the
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/com/github/peholmst/vaadinactivitidemo/ui/main/MainPresenter.java[`MainPresenter`]
class are as follows:

[source,java]
....
public void showUnassignedTasks() {
getViewController().goToView(UnassignedTasksView.VIEW_ID);
}

public void showMyTasks() {
getViewController().goToView(MyTasksView.VIEW_ID);
}
....

[[custom-forms]]
Custom Forms
~~~~~~~~~~~~

As you may already know, it is possible to use automatic form generation
with Activiti, but the generated forms are not Vaadin based. In this
article, we are going to use custom-built Vaadin forms instead. Even
though this forces us to write Java code for each form we want to use,
it gives us some advantages:

* It is possible to have more complex forms with differnt kinds of
components.
* It is possible to tailor the appearance and look and feel of the forms
to the user's needs.
* It is easy to plug in other infrastructure services such as EJBs and
JPA entities.

The following approach is used to implement custom forms in the demo
application:

image:img/customForms.png[Custom forms]

Here is a short walk-through of the most important classes:

* The
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/com/github/peholmst/vaadinactivitidemo/ui/util/UserTaskForm.java[`UserTaskForm`]
interface is implemented by all custom forms. This interface defines
several methods, the most interesting of which are the following:
** `populateForm(...)`: This method populates the form with initial data
retrieved from the Activiti form service.
** `getFormProperties()`: This method creates a map of the form data
that will be sent to the Activiti form service when the form is
submitted.
* The
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/com/github/peholmst/vaadinactivitidemo/ui/util/UserTaskFormContainer.java[`UserTaskFormContainer`]
is a class that contains user task forms. Each form can be accessed by a
unique form key, which in turn is used in BPMN-documents to refer to
forms. The main Vaadin application class is responsible for creating and
populating this container. *Please note, that this container class has
nothing to do with Vaadin Data Containers.*
* The
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/com/github/peholmst/vaadinactivitidemo/ui/forms/UserFormViewImpl.java[`UserFormViewImpl`]
class (and its corresponding presenter) is responsible for looking up
the correct form (by its form key), populating it, displaying it to the
user and finally submitting it.

[[some-code-examples]]
Some Code Examples
^^^^^^^^^^^^^^^^^^

We are now going to look at some snippets from the demo application
source code.

First up is a method from the
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/com/github/peholmst/vaadinactivitidemo/ui/tasks/MyTasksPresenter.java[`MyTasksPresenter`]
class that is invoked when the user wants to open the form for a
specific task:

[source,java]
....
public void openFormForTask(Task task) {
String formKey = getFormKey(task);
if (formKey != null) {
HashMap<String, Object> params = new HashMap<String, Object>();
params.put(UserFormView.KEY_FORM_KEY, formKey);
params.put(UserFormView.KEY_TASK_ID, task.getId());
getViewController().goToView(UserFormView.VIEW_ID, params);
}
}
....

The method checks if the task has a form and asks the view controller (a
part of MVP4Vaadin) to navigate to the User Form View if that is the
case. The task ID and form key is passed to the view as a map of
parameters.

The next code example is a method of the
https://github.com/peholmst/VaadinActivitiDemo/blob/master/src/com/github/peholmst/vaadinactivitidemo/ui/forms/UserFormPresenter.java[`UserFormPresenter`]
class that is invoked when the view controller has navigated to the User
Form View:

[source,java]
....
@Override
protected void viewShown(ViewController viewController,
Map<String, Object> userData, ControllableView oldView,
Direction direction) {
if (userData != null) {
String formKey = (String) userData.get(UserFormView.KEY_FORM_KEY);
if (userData.containsKey(UserFormView.KEY_TASK_ID)) {
String taskId = (String) userData.get(UserFormView.KEY_TASK_ID);
showTaskForm(formKey, taskId);
}
// The rest of the implementation is omitted
}
}

private void showTaskForm(String formKey, String taskId) {
UserTaskForm form = userTaskFormContainer.getForm(formKey);
TaskFormData formData = getFormService().getTaskFormData(taskId);
form.populateForm(formData, taskId);
getView().setForm(form);
}
....

The method first extracts the task ID and form key from the parameter
map. It then invokes a helper method that looks up the corresponding
form data and form from the Activiti form service and the
`UserTaskFormContainer`, respectively. Finally, the form is populated
and shown to the user.

The final example is a method (also from `UserFormPresenter`) that is
invoked when the user submits the form:

[source,java]
....
public void submitForm(UserTaskForm form) {
if (form.getFormType().equals(UserTaskForm.Type.START_FORM)) {
getFormService().submitStartFormData(form.getProcessDefinitionId(), form.getFormProperties());
} else if (form.getFormType().equals(UserTaskForm.Type.TASK_FORM)) {
getFormService().submitTaskFormData(form.getTaskId(), form.getFormProperties());
}
getViewController().goBack();
}
....

As there are two different kinds of forms (process start forms and user
task forms, respectively), the method has to start by checking which
kind it is currently processing. Then, the information is submitted to
the Activiti form service. Finally, the view controller is asked to
navigate back to what ever page it was on before the User Form View
became visible.

[[complex-domain-objects]]
Complex Domain Objects
~~~~~~~~~~~~~~~~~~~~~~

The demo application does not use any domain objects as all the
information can be represented as Activiti process variables. However,
in most real-world applications you probably want to use a dedicated
domain model.

We are now going to look at a potential design for combining Activiti
with a complex domain model. *Please note that the design has not been
tested in practice* - feel free to test it if you feel like it (and
remember to tell me the results)!

Here is a sketch of a process that involves a more complicated domain
model than just a few strings:

image:img/complexdomain.png[Complex domain]

The idea is that although many different entities need to be created and
stored throughout the process, only some small parts of the information
is actually required to drive the process forward. For example, the
*Send invoice* task does not necessarily need the entire invoice object;
only the invoice number, order number and due date should be sufficient.
Likewise, the *Receive payment* task needs only the invoice number to be
able to check that the invoice has been paid, the timer needs the due
date to be able to send out a new invoice, etc.

[[implementation-ideas]]
Implementation Ideas
^^^^^^^^^^^^^^^^^^^^

The actual forms that the users fill in could be implemented in Vaadin,
as described previously in this article. When the form is submitted, the
entities are saved to some data store (e.g. a relational database).
After this, the necessary form properties are submitted to the Activiti
form service, completing the task in question. In other words, Activiti
is used to drive the process forward (i.e. define the business logic),
whereas JPA or any other object persistence solution is used to store
data.

There are a few things to keep in mind, though:

* How are transactions handled?
* How is data validation performed?
* How is security enforced?
* Is versioning of the domain data required? How should it be
implemented if so? (Activiti already maintains a history log of the
process operations.)

In smaller applications, the following design could be sufficient:

image:img/complexdomain_saving.png[Complex domain saving]

Here, the Presenter (in the MVP-pattern) is responsible for extracting
the needed form properties from the domain data, saving the entity and
submitting the form. This moves some of the logic to the UI layer, but
for small applications this is not a big problem as the presenter is
itself decoupled from the actual UI code.

For larger applications, the following design could be a better
approach:

image:img/complexdomain_saving2.png[Complex domain saving 2]

Here, both the repository and the form service engine is hidden behind a
facade. A Data Transfer Object (DTO) is used to convey the data from the
Presenter to the facade. This approach requires more code, but decouples
the business layer from the UI layer even more. Security enforcement and
transaction handling also become easier.

[[summary]]
Summary
~~~~~~~

In this article, we have looked at how the Activiti BPM engine and
Vaadin fit together. We have covered how the engine is initialized and
accessed by Vaadin application instances. We have also covered how
custom-made Vaadin forms can be used instead of Activiti's own form
generation. Finally, we have discussed a way of combining Activiti
processes with a more complex domain model.

The Activiti API is clear and does not force adopters to use a specific
GUI technology. Therefore, it plays really well with Vaadin and should
be concidered a serious alternative for process centric enterprise
applications.

Likewise, Vaadin should be considered a serious alternative as a front
end technology for applications based on Activiti.

If you have any comments or questions, for example if something in the
article is unclear or confusing, feel free to either post them below or
send them to me directly by e-mail.

+ 76
- 0
documentation/articles/ChangingTheDefaultConvertersForAnApplication.asciidoc View File

@@ -0,0 +1,76 @@
[[changing-the-default-converters-for-an-application]]
Changing the default converters for an application
--------------------------------------------------

Each Vaadin session instance has a `ConverterFactory` that provides
converters to Fields and Table. The defaults might not be ideal for your
case so it is possible for you to change the defaults by providing your
own ConverterFactory. If you, for instance, want to format all (or most)
doubles from your data model with 3 decimals and no thousand separator
(but still allow the user to input with any number of decimals) you can
do this by first creating your own Converter:

[source,java]
....
public class MyStringToDoubleConverter extends StringToDoubleConverter {

@Override
protected NumberFormat getFormat(Locale locale) {
NumberFormat format = super.getFormat(locale);
format.setGroupingUsed(false);
format.setMaximumFractionDigits(3);
format.setMinimumFractionDigits(3);
return format;
}
}
....

and then extending the default converter factory to use your converter
for all `Double` &lt;-&gt; `String` conversions.

[source,java]
....
public class MyConverterFactory extends DefaultConverterFactory {
@Override
protected <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> findConverter(
Class<PRESENTATION> presentationType, Class<MODEL> modelType) {
// Handle String <-> Double
if (presentationType == String.class && modelType == Double.class) {
return (Converter<PRESENTATION, MODEL>) new MyStringToDoubleConverter();
}
// Let default factory handle the rest
return super.findConverter(presentationType, modelType);
}
}
....

You still need to tell your application to always use
`MyConverterFactory`:

[source,java]
....
VaadinSession.getCurrent().setConverterFactory(new MyConverterFactory());
....

Now we can test it using

[source,java]
....
public class MyUI extends UI {
public void init(VaadinRequest request) {
TextField tf = new TextField("This is my double field");
tf.setImmediate(true);
tf.setConverter(Double.class);
setContent(tf);
tf.setConvertedValue(50.1);
}
}
....

This will not enforce the contents of the field to the format specified
by the converter. Only data from the data source is formatted to adhere
to the format set in the converter.

If you want to force the user to enter data with a given number of
decimals you need to create your own converter instead of only
overriding the format for `StringToDoubleConverter`.

+ 72
- 0
documentation/articles/ConfiguringGridColumnWidths.asciidoc View File

@@ -0,0 +1,72 @@
[[configuring-grid-column-widths]]
Configuring Grid column widths
------------------------------

To try out how the widths of Grid columns work in different situations,
we'll use the same base implementation as in the
link:UsingGridWithAContainer.asciidoc[Using Grid with a Container]
example.

Grid does by default check the widths of all cells on the first pageful
of data and allocate column widths based on that. If there's room to
spare, each column gets and equal share of the extra pixels.

There is usually one or maybe two columns that would most benefit from
some additional breathing room, but Grid can't know which columns that
is unless you tell it. You can do so using the `setExpandRatio(int)`
method for a column.

[source,java]
....
grid.getColumn("name").setExpandRatio(1);
....

When setting one column to expand, all the extra space gets allocated to
that column. This might instead cause the other columns to be too
tightly spaced. One easy way of avoiding this is to use `setWidth(double)`
to set a pixel size for columns that are not expanded.

[source,java]
....
grid.getColumn("name").setExpandRatio(1);
grid.getColumn("amount").setWidth(100);
grid.getColumn("count").setWidth(100);
....

Reducing the width of Grid does now cause the `Name` column to shrink
while the two other columns keep their defined original sizes. We might,
however, want to prevent the `Name` column from becoming too narrow by
giving it a minimum width. Without any defined minimum width, the widths
of the cell contents of the first pageful of data will define the
minimum width. If there's not enough room for all columns, Grid will
automatically enable horizontal scrolling so that all columns can still
be accessed.

[source,java]
....
grid.setWidth("400px");
grid.getColumn("name").setMinimumWidth(250);
grid.getColumn("amount").setWidth(100);
grid.getColumn("count").setWidth(100);
....

With horizontal scrolling, it might be desirable to still keep columns
identifying each row visible all the time so that it's easier for the
user to interpret the data. This can be done by freezing a number of
columns, counted from the left, using the `setFrozenColumnCount(int)`
method. By default, only the column showing selection state in
multiselect mode is frozen. This column can also be unfrozen by setting
the count to -1.

[source,java]
....
grid.setWidth("400px");
grid.setFrozenColumnCount(1);
grid.getColumn("name").setMinimumWidth(250);
grid.getColumn("amount").setWidth(100);
grid.getColumn("count").setWidth(100);
....

If the width of Grid is again increased so that all columns can fit
without scrolling, the frozen columns will behave just as any other
column.

+ 74
- 0
documentation/articles/CreatingABasicApplication.asciidoc View File

@@ -0,0 +1,74 @@
[[creating-a-basic-application]]
Creating a basic application
----------------------------

To create a Vaadin application you need two files. A class that extends
UI which is your main view and entry point to the application as well as
a web.xml referring to the UI.

With Eclipse and the Vaadin plugin you will get all of this
automatically by opening the New wizard (File -> New -> Other) and
choosing Vaadin -> Vaadin Project. From there you can give the new
project a name and the wizard takes care of the rest.

In other environments you can create the standard java web application
project. Create one file which extends UI into the source folder. Let's
call it MyApplicationUI:

[source,java]
....
package com.example.myexampleproject;

import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Label;

public class MyApplicationUI extends UI {

@Override
protected void init(VaadinRequest request) {
VerticalLayout view = new VerticalLayout();
view.addComponent(new Label("Hello Vaadin!"));
setContent(view);
}
}
....

This application creates a new main layout to the UI and adds the text
"Hello Vaadin!" into it.

Your web deployment descriptor, web.xml, has to point at your UI as
well. This is done with an defining a Vaadin servlet and giving the UI
as a parameter to it:

[source,xml]
....
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>MyApplication</display-name>
<context-param>
<description>Vaadin production mode</description>
<param-name>productionMode</param-name>
<param-value>false</param-value>
</context-param>
<servlet>
<servlet-name>My Vaadin App</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<description>Vaadin UI</description>
<param-name>UI</param-name>
<param-value>com.example.myexampleproject.MyApplicationUI</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>My Vaadin App</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
....

Now you're able to package your application into a war and deploy it on
a servlet container.

+ 266
- 0
documentation/articles/CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc View File

@@ -0,0 +1,266 @@
[[creating-a-customfield-for-editing-the-address-of-a-person]]
Creating a CustomField for editing the address of a person
----------------------------------------------------------

A normal use case is that you want to create a form out a bean that the
user can edit. Often these beans contain references to other beans as
well, and you have to create a separate editor for those. This tutorial
goes through on how to edit an `Address` bean which is inside a `Person`
bean with the use of `CustomField` and `FieldGroup`.

Here are the `Person` and `Address` beans

[source,java]
....
public class Person {
private String firstName;
private String lastName;
private Address address;
private String phoneNumber;
private String email;
private Date dateOfBirth;
private String comments;

//Getters and setters
}
....

[source,java]
....
public class Address {
private String street;
private String zip;
private String city;
private String country;

// Getters and setters
}
....

[[creating-a-new-field]]
Creating a new field
~~~~~~~~~~~~~~~~~~~~

The first step is to create a new field which represents the editor for
the address. In this case the field itself will be a button. The button
will open a window where you have all the address fields. The address
will be stored back when the user closes the window.

[source,java]
....
public class AddressPopup extends CustomField<Address> {
@Override
protected Component initContent() {
return null;
}

@Override
public Class<Address> getType() {
return Address.class;
}
}
....

CustomField requires that you implement two methods, `initContent()` and
`getType()`. `initContent()` creates the actual visual representation of
your field. `getType()` tells the field which type of data will be handled
by the field. In our case it is an `Address` object so we return
`Address.class` in the method.

[[creating-the-content]]
Creating the content
~~~~~~~~~~~~~~~~~~~~

Next up we create the actual button that will be visible in the person
editor when the CustomField is rendered. This button should open up a
new window where the user can edit the address.

[source,java]
....
@Override
protected Component initContent() {
final Window window = new Window("Edit address");
final Button button = new Button("Open address editor", new ClickListener() {
public void buttonClick(ClickEvent event) {
getUI().addWindow(window);
}
});
return button;
}
....

This is enough to attach the field to the person editor, but the window
will be empty and it won't modify the data in any way.

[[creating-the-editable-fields]]
Creating the editable fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The address object contains four strings - street, zip, city and
country. For the three latter a `TextField` is good for editing, but the
street address can contain multiple row so a `TextArea` is better here.
All the fields have to be put into a layout and the layout has to be set
as the content of the window. `FormLayout` is a good choice here to nicely
align up the captions and fields of the window.

[source,java]
....
FormLayout layout = new FormLayout();
TextArea street = new TextArea("Street address:");
TextField zip = new TextField("Zip code:");
TextField city = new TextField("City:");
TextField country = new TextField("Country:");
layout.addComponent(street);
layout.addComponent(zip);
layout.addComponent(city);
layout.addComponent(country);
window.setContent(layout);
....

The field is now visually ready but it doesn't contain or affect any
data. You want to also modify the sizes as well to make it look a bit
nicer:

[source,java]
....
window.center();
window.setWidth(null);
layout.setWidth(null);
layout.setMargin(true);
....

[[binding-the-address-to-the-field]]
Binding the address to the field
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A FieldGroup can be used to bind the data of an Address bean into the
fields. We create a member variable for a FieldGroup and initialize it
within the createContent() -method:

[source,java]
....
fieldGroup = new BeanFieldGroup<Address>(Address.class);
fieldGroup.bind(street, "street");
fieldGroup.bind(zip, "zip");
fieldGroup.bind(city, "city");
fieldGroup.bind(country, "country");
....

The `FieldGroup` of the person editor will call
`AddressPopup.setValue(person.getAddress())` when we start to edit our
person. We need to override `setInternalValue(Address)` to get the `Address`
object and pass it to the `FieldGroup` of the address editor.

[source,java]
....
@Override
protected void setInternalValue(Address address) {
super.setInternalValue(address);
fieldGroup.setItemDataSource(new BeanItem<Address>(address));
}
....

The last thing that has to be done is save the modifications made by the
user back into the `Address` bean. This is done with a `commit()` call to
the `FieldGroup`, which can be made for example when the window is closed:

[source,java]
....
window.addCloseListener(new CloseListener() {
public void windowClose(CloseEvent e) {
try {
fieldGroup.commit();
} catch (CommitException ex) {
ex.printStackTrace();
}
}
});
....

Now you need to attach the `AddressPopup` custom field into the person
editor through it's `FieldGroup` and you have a working editor.

[[complete-code]]
Complete code
~~~~~~~~~~~~~

[source,java]
....
package com.example.addressforms.fields;

import com.example.addressforms.data.Address;
import com.vaadin.data.fieldgroup.BeanFieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.util.BeanItem;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.CustomField;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.CloseEvent;
import com.vaadin.ui.Window.CloseListener;

public class AddressPopup extends CustomField<Address> {
private FieldGroup fieldGroup;

@Override
protected Component initContent() {
FormLayout layout = new FormLayout();
final Window window = new Window("Edit address", layout);
TextArea street = new TextArea("Street address:");
TextField zip = new TextField("Zip code:");
TextField city = new TextField("City:");
TextField country = new TextField("Country:");
layout.addComponent(street);
layout.addComponent(zip);
layout.addComponent(city);
layout.addComponent(country);

fieldGroup = new BeanFieldGroup<Address>(Address.class);
fieldGroup.bind(street, "street");
fieldGroup.bind(zip, "zip");
fieldGroup.bind(city, "city");
fieldGroup.bind(country, "country");
Button button = new Button("Open address editor", new ClickListener() {
public void buttonClick(ClickEvent event) {
getUI().addWindow(window);
}
});
window.addCloseListener(new CloseListener() {
public void windowClose(CloseEvent e) {
try {
fieldGroup.commit();
} catch (CommitException ex) {
ex.printStackTrace();
}
}
});

window.center();
window.setWidth(null);
layout.setWidth(null);
layout.setMargin(true);
return button;
}

@Override
public Class<Address> getType() {
return Address.class;
}

@Override
protected void setInternalValue(Address address) {
super.setInternalValue(address);
fieldGroup.setItemDataSource(new BeanItem<Address>(address));
}
}
....

image:img/person%20editor.png[Address editor]

image:img/address%20editor.png[Address editor window]

+ 382
- 0
documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc View File

@@ -0,0 +1,382 @@
[[creating-a-master-details-view-for-editing-persons]]
Creating a master details view for editing persons
--------------------------------------------------

[[set-up]]
Set-up
~~~~~~

In this tutorial we go through a standard use case where you have a bean
and a backend ready with create, read, update and delete capabilities on
that bean. You want to create a view where you can view all the beans
and edit them. This example is an address book where you edit person
information. The bean and the backend that we're going to use looks like
this:

[[person]]
Person
^^^^^^

[source,java]
....
public class Person {
private int id = -1;
private String firstName = "";
private String lastName = "";
private Address address = new Address();
private String phoneNumber = "";
private String email = "";
private Date dateOfBirth = null;
private String comments = "";
....

[[ibackend]]
IBackend
^^^^^^^^

[source,java]
....
public interface IBackend {
public List<Person> getPersons();
public void storePerson(Person person);
public void deletePerson(Person person);
}
....

The view will contain a table, with all the persons in it, and a form
for editing a single person. Additionally the table will have buttons
too add or remove persons and the form will have buttons to save and
discard changes. The UI wireframe looks like this:

image:img/master%20detail%20wireframe.jpg[Master detail UI wireframe]

[[building-the-basic-ui]]
Building the basic UI
~~~~~~~~~~~~~~~~~~~~~

We start off with creating a basic UIfor our application

[source,java]
....
public class AddressFormsUI extends UI {
@Override
protected void init(VaadinRequest request) {
VerticalLayout mainLayout = new VerticalLayout();
mainLayout.setSpacing(true);
mainLayout.setMargin(true);
mainLayout.addComponent(new Label("Hello Vaadiners!"));
setContent(mainLayout);
}
}
....

The first things that we want to add to it is the table and the form.
The table should be selectable and immediate so that we're able to pass
person objects from it to the form. I will create all the fields for our
person editor by hand to get more flexibility in how the fields will be
built and laid out. You could also let Vaadin `FieldGroup` take care of
creating the standard fields with the `buildAndBind` -methods if you don't
need to customize them.

[source,java]
....
package com.example.addressforms;

import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Component;
import com.vaadin.ui.DateField;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.UI;
import com.vaadin.ui.Table;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;

public class AddressFormsUI extends UI {

private GridLayout form;
private Table table;

@Override
protected void init(VaadinRequest request) {
VerticalLayout mainLayout = new VerticalLayout();
mainLayout.setSpacing(true);
mainLayout.setMargin(true);

mainLayout.addComponent(buildTable());
mainLayout.addComponent(buildForm());

setContent(mainLayout);
}

private Component buildTable() {
table = new Table(null);
table.setWidth("500px");
table.setSelectable(true);
table.setImmediate(true);
return table;
}

private Component buildForm() {
form = new GridLayout(2, 3);

TextField firstName = new TextField("First name:");
TextField lastName = new TextField("Last name:");
TextField phoneNumber = new TextField("Phone Number:");
TextField email = new TextField("E-mail address:");
DateField dateOfBirth = new DateField("Date of birth:");
TextArea comments = new TextArea("Comments:");

form.addComponent(firstName);
form.addComponent(lastName);
form.addComponent(phoneNumber);
form.addComponent(email);
form.addComponent(dateOfBirth);
form.addComponent(comments);
return form;
}
}
....

image:img/table%20and%20form.png[Address form]

We also want the add, remove, save and discard buttons so let's create
them as well. I've positioned the add and remove above the table and
save and discard below the form.

[source,java]
....
private GridLayout form;
private HorizontalLayout tableControls;
private Table table;
private HorizontalLayout formControls;

@Override
protected void init(VaadinRequest request) {
VerticalLayout mainLayout = new VerticalLayout();
mainLayout.setSpacing(true);
mainLayout.setMargin(true);

mainLayout.addComponent(buildTableControls());
mainLayout.addComponent(buildTable());
mainLayout.addComponent(buildForm());
mainLayout.addComponent(buildFormControls());

setContent(mainLayout);
}

...

private Component buildTableControls() {
tableControls = new HorizontalLayout();
Button add = new Button("Add");
Button delete = new Button("Delete");
tableControls.addComponent(add);
tableControls.addComponent(delete);
return tableControls;
}

private Component buildFormControls() {
formControls = new HorizontalLayout();
Button save = new Button("Save");
Button discard = new Button("Discard");
formControls.addComponent(save);
formControls.addComponent(discard);
return formControls;
}
....

The buttons doesn't do anything yet but we have all the components that
we need in the view now.

image:img/buttons%20added.png[Address form with add, delete, save and discard buttons]

[[connecting-the-backend-to-the-view]]
Connecting the backend to the view
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The backend reference is store as a field so that all methods have
access to it.

[source,java]
....
...
private IBackend backend;

@Override
protected void init(VaadinRequest request) {
backend = new Backend();
...
....

Then we have to build a container for the table. I will do it in a
separate method from the table building so that it can be rebuilt for
refreshing the table after the initial rendering. We call this method
once in the initial rendering as well on every button click that
modifies the list of persons. A good choice of container in this case is
the `BeanItemContainer` where we specify to the table which columns we
want to show, and sort the table based on the name.

[source,java]
....
...
private Component buildTable() {
table = new Table(null);
table.setSelectable(true);
table.setImmediate(true);
updateTableData();
return table;
}

...

private void updateTableData() {
List<Person> persons = backend.getPersons();
BeanItemContainer<Person> container = new BeanItemContainer<Person>(
Person.class, persons);
table.setContainerDataSource(container);

table.setVisibleColumns(new String[] { "firstName", "lastName",
"phoneNumber", "email", "dateOfBirth" });
table.setColumnHeaders(new String[] { "First name", "Last name",
"Phone number", "E-mail address", "Date of birth" });
table.sort(new Object[] { "firstName", "lastName" }, new boolean[] {
true, true });
}
...
....

To get the data from the selected person's data into the fields, and the
changes back into the bean, we will use a FieldGroup. The `FieldGroup`
should be defined as class variable and it should bind the fields that
is initialized in `buildForm()`.

[source,java]
....
...
private FieldGroup fieldGroup = new FieldGroup();

...

private Component buildForm() {
form = new GridLayout(2, 3);

TextField firstName = new TextField("First name:");
TextField lastName = new TextField("Last name:");
TextField phoneNumber = new TextField("Phone Number:");
TextField email = new TextField("E-mail address:");
DateField dateOfBirth = new DateField("Date of birth:");
TextArea comments = new TextArea("Comments:");

fieldGroup.bind(firstName, "firstName");
fieldGroup.bind(lastName, "lastName");
fieldGroup.bind(phoneNumber, "phoneNumber");
fieldGroup.bind(email, "email");
fieldGroup.bind(dateOfBirth, "dateOfBirth");
fieldGroup.bind(comments, "comments");

form.addComponent(firstName);
form.addComponent(lastName);
form.addComponent(phoneNumber);
form.addComponent(email);
form.addComponent(dateOfBirth);
form.addComponent(comments);
return form;
}
....

Additionally the table requires a value change listener and the
currently selected person in the table has to be passed to the
`FieldGroup`.

[source,java]
....
private Component buildTable() {
...
table.addValueChangeListener(new ValueChangeListener() {
public void valueChange(ValueChangeEvent event) {
editPerson((Person) table.getValue());
}
});
...
}

...

private void editPerson(Person person) {
if (person == null) {
person = new Person();
}
BeanItem<Person> item = new BeanItem<Person>(person);
fieldGroup.setItemDataSource(item);
}
....

[[putting-the-buttons-in-use]]
Putting the buttons in use
~~~~~~~~~~~~~~~~~~~~~~~~~~

Last thing we have to do is implement all the buttons that we have in
the application. Add should create a new Person object and give it to
the form. Delete should tell the backend to remove the selected person
and update the table. Save should store the changes into the bean and
the bean into the backend and update the table. Discard should reset the
form.

[source,java]
....
private Component buildTableControls() {
tableControls = new HorizontalLayout();
Button add = new Button("Add", new ClickListener() {
public void buttonClick(ClickEvent event) {
editPerson(new Person());
}
});
Button delete = new Button("Delete", new ClickListener() {
public void buttonClick(ClickEvent event) {
backend.deletePerson((Person) table.getValue());
updateTableData();
}
});
tableControls.addComponent(add);
tableControls.addComponent(delete);
return tableControls;
}

private Component buildFormControls() {
formControls = new HorizontalLayout();
Button save = new Button("Save", new ClickListener() {
public void buttonClick(ClickEvent event) {
try {
fieldGroup.commit();
backend.storePerson(((BeanItem<Person>) fieldGroup
.getItemDataSource()).getBean());
updateTableData();
editPerson(null);
} catch (CommitException e) {
e.printStackTrace();
}
}
});
Button discard = new Button("Discard", new ClickListener() {
public void buttonClick(ClickEvent event) {
fieldGroup.discard();
}
});
formControls.addComponent(save);
formControls.addComponent(discard);
return formControls;
}
....

image:img/database%20connected.png[Form with database connected]

That's it! Now you have a full working CRUD view with total control over
the components and layouts. A little theming and layout adjustments and
it is ready for production.

You might have noticed that the person bean contains a reference to
another bean, a address, which is not editable here. The tutorial
link:CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc[Creating a custom field for editing the address of a person] goes
through on how to edit beans within beans with a `CustomField`, which can
be used directly as a field for the `FieldGroup`.

+ 135
- 0
documentation/articles/CreatingAReusableVaadinThemeInEclipse.asciidoc View File

@@ -0,0 +1,135 @@
[[creating-a-reusable-vaadin-theme-in-eclipse]]
Creating a reusable Vaadin theme in Eclipse
-------------------------------------------

This tutorial teaches you how to create a standalone Vaadin theme that
can be reused in other Vaadin projects as an add-on.

*Requirements:*

* https://www.eclipse.org/downloads/[Eclipse IDE for Java EE developers]
* https://vaadin.com/eclipse/[Vaadin plug-in for Eclipse]

[[create-a-project-for-your-theme]]
Create a project for your theme
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Create a new Java project.

image:img/New%20Java%20Project.png[Create a new Java project]

https://vaadin.com/download[Download a Vaadin JAR] and add it to your
project’s build path.

image:img/Vaadin%20to%20build%20path.png[Add Vaadin to build path]

In the src folder, create a class for your theme:

[source,java]
....
package com.example.mytheme;

import com.vaadin.ui.themes.BaseTheme;

public class MyTheme extends BaseTheme {
public static final String THEME_NAME = "my-theme";
}
....

This makes your theme extend Vaadin’s
https://vaadin.com/api/com/vaadin/ui/themes/BaseTheme.html[BaseTheme],
which will let you fully customize your theme from scratch. On the other
hand, if you don't have very specific theming needs and just want
good-looking results quickly, try extending
https://vaadin.com/api/com/vaadin/ui/themes/ChameleonTheme.html[ChameleonTheme]
instead. In any case, both of these themes are designed for extension
and therefore your best choices to start with.

In the root of your project, create the following folder and files:

* META-INF
** MANIFEST.MF
* VAADIN
** themes
*** my-theme
**** addons.scss
**** my-theme.scss
**** styles.scss

The MANIFEST.MF file should contain the following:

....
Manifest-Version: 1.0
Implementation-Title: My Theme
Implementation-Version: 1.0.0
Vaadin-Package-Version: 1
Class-Path:
....

Your `Implementation-Title` and `Implementation-Version` should reflect
how you want your theme to be visible in the
https://vaadin.com/directory[Vaadin directory].

[[create-a-demo-app-for-your-theme]]
Create a demo app for your theme
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Create a new Vaadin project.

image:img/New%20Vaadin%20project%20(1).png[Create a new Vaadin project]

image:img/New%20Vaadin%20project%20(2).png[Create a new Vaadin project 2]

Add your *theme* project to your *demo* project’s Java build path.

image:img/Theme%20to%20build%20path.png[Add theme to build path]

Add your *theme* project to your *demo* project’s _deployment assembly_.
This will automatically convert your theme project to a Java EE Utility
project.

image:img/Theme%20to%20deployment%20assembly.png[Add theme to Deployment Assembly]

Now that your theme project is a Java EE Utility project, it will also
have a deployment assembly. Add your *theme project*’s VAADIN folder to
there and make sure you specify its deploy path as `VAADIN`.

image:img/VAADIN%20to%20deployment%20assembly.png[Add theme to Deployment Assembly 2]

In your *demo* application class, add the following line to your
`init()` method:

[source,java]
....
setTheme(MyTheme.THEME_NAME);
....

To try if it works, right-click on your *demo* project and choose _Run
As > Run on Server_.

[[develop-your-theme]]
Develop your theme
~~~~~~~~~~~~~~~~~~

Create a new style name constant in your theme class for each new CSS
class name you add to your stylesheets. These can then be passed to the
`Component.addStyleName(String)` method. This will make it easier for
other developers to use your theme!

Changes to your stylesheets will be visible in your demo app almost
instantly. All you need to do is save the file, wait for the server to
automatically pick up the changes, then refresh your browser.

[[export-your-theme-as-a-vaadin-add-on]]
Export your theme as a Vaadin add-on
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Right-click on your *theme* project, choose _Export… > Java > Jar file_
and make sure your settings match those in the following two images.

image:img/JAR%20Export%20(1).png[Export as JAR]

image:img/JAR%20Export%20(2).png[Export as JAR 2]

Finally, upload your theme add-on Jar to the
https://vaadin.com/directory[Vaadin directory]!

+ 63
- 0
documentation/articles/CreatingATextFieldForIntegerOnlyInputUsingADataSource.asciidoc View File

@@ -0,0 +1,63 @@
[[creating-a-textfield-for-integer-only-input-using-a-data-source]]
Creating a TextField for integer only input using a data source
---------------------------------------------------------------

A `TextField` is a component that always has a value of type `String`. When
binding a property of another type to a text field, the value is
automatically converted if the conversion between the two types is
supported.

[source,java]
....
public class MyBean {
private int value;

public int getValue() {
return value;
}

public void setValue(int integer) {
value = integer;
}
}
....

The property named "value" from a `BeanItem` constructed from `MyBean` will
be of type `Integer`. Binding the property to a `TextField` will
automatically make validation fail for texts that can not be converted
to an `Integer`.

[source,java]
....
final MyBean myBean = new MyBean();
BeanItem<MyBean> beanItem = new BeanItem<MyBean>(myBean);

final Property<Integer> integerProperty = (Property<Integer>) beanItem
.getItemProperty("value");
final TextField textField = new TextField("Text field", integerProperty);

Button submitButton = new Button("Submit value", new ClickListener() {
public void buttonClick(ClickEvent event) {
String uiValue = textField.getValue();
Integer propertyValue = integerProperty.getValue();
int dataModelValue = myBean.getValue();

Notification.show("UI value (String): " + uiValue
+ "\nProperty value (Integer): " + propertyValue
+ "\nData model value (int): " + dataModelValue);
}
});

addComponent(new Label("Text field type: " + textField.getType()));
addComponent(new Label("Text field type: " + integerProperty.getType()));
addComponent(textField);
addComponent(submitButton);
....

With this example, entering a number and pressing the button causes the
value of the `TextField` to be a `String`, the property value will be an
`Integer` representing the same value and the value in the bean will be
the same int. If e.g. a letter is entered to the field and the button is
pressed, the validation will fail. This causes a notice to be displayed
for the field. The field value is still updated, but the property value
and the bean value are kept at their previous values.

+ 44
- 0
documentation/articles/CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource.asciidoc View File

@@ -0,0 +1,44 @@
[[creating-a-textfield-for-integer-only-input-when-not-using-a-data-source]]
Creating a TextField for integer only input when not using a data source
------------------------------------------------------------------------

A `TextField` is a component that always has a value of type `String`. By
adding a converter to a field, the field will automatically validate
that the entered value can be converted and it will provide the
converted value using the `getConvertedValue()` method.

[source,java]
....
final TextField textField = new TextField("Text field");
textField.setConverter(Integer.class);

Button submitButton = new Button("Submit value", new ClickListener() {
public void buttonClick(ClickEvent event) {
String uiValue = textField.getValue();
try {
Integer convertedValue = (Integer) textField
.getConvertedValue();
Notification.show(
"UI value (String): " + uiValue
+ "<br />Converted value (Integer): "
+ convertedValue);
} catch (ConversionException e) {
Notification.show(
"Could not convert value: " + uiValue);
}
}
});

addComponent(new Label("Text field type: " + textField.getType()));
addComponent(new Label("Converted text field type: "
+ textField.getConverter().getModelType()));
addComponent(textField);
addComponent(submitButton);
....

With this example, entering a number and pressing the button causes the
value of the `TextField` to be a `String` while the converted value will be
an `Integer` representing the same value. If e.g. a letter is entered to
the field and the button is pressed, the validation will fail. This
causes a notice to be displayed for the field and an exception to be
thrown from `getConvertedValue()`.

+ 71
- 0
documentation/articles/CreatingAnApplicationWithDifferentFeaturesForDifferentClients.asciidoc View File

@@ -0,0 +1,71 @@
[[creating-an-application-with-different-features-for-different-clients]]
Creating an application with different features for different clients
---------------------------------------------------------------------

Providing different features for different clients can be done by
creating a specialized UIProvider for the application.

We start by creating the specialized UI's

[source,java]
....
public class DefaultUI extends UI {
@Override
protected void init(VaadinRequest request) {
setContent(
new Label("This browser does not support touch events"));
}
}
....

[source,java]
....
public class TouchUI extends UI {
@Override
protected void init(VaadinRequest request) {
WebBrowser webBrowser = getPage().getWebBrowser();
String screenSize = "" + webBrowser.getScreenWidth() + "x"
+ webBrowser.getScreenHeight();
setContent(new Label("Using a touch enabled device with screen size"
+ screenSize));
}
}
....

We then define an UIProvider which knows what UI the application should
return.

[source,java]
....
public class DifferentFeaturesForDifferentClients extends UIProvider {

@Override
public Class<? extends UI> getUIClass(UIClassSelectionEvent event) {
// could also use browser version etc.
if (event.getRequest().getHeader("user-agent").contains("mobile")) {
return TouchUI.class;
} else {
return DefaultUI.class;
}
}
}
....

Now that we have an `UIProvider` we need to tell Vaadin to use it. This is
most easily done by defining the `UIProvider` class in web.xml instead of
defining a UI class.

[source,xml]
....
<servlet>
<servlet-name>My Vaadin App</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<description>Vaadin UI</description>
<param-name>UIProvider</param-name>
<param-value>com.example.myexampleproject.DifferentFeaturesForDifferentClients</param-value>
</init-param>
</servlet>
....

Each UI can have its own feature set, layout and theme.

+ 103
- 0
documentation/articles/CreatingYourOwnConverterForString.asciidoc View File

@@ -0,0 +1,103 @@
[[creating-your-own-converter-for-string-mytype-conversion]]
Creating your own converter for String - MyType conversion
----------------------------------------------------------

If you have custom types that you want to represent using the built in
field components, you can easily create your own converter to take care
of converting between your own type and the native data type of the
field.

A sample custom type, in this case a Name object with separate fields
for first and last name.

[source,java]
....
public class Name {
private String firstName;
private String lastName;

public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}
}
....

A converter for the name, assuming the parts are separated with a space
and that there are only two parts of a name.

[source,java]
....
public class StringToNameConverter implements Converter<String, Name> {
public Name convertToModel(String text, Locale locale)
throws ConversionException {
if (text == null) {
return null;
}
String[] parts = text.split(" ");
if (parts.length != 2) {
throw new ConversionException("Can not convert text to a name: " + text);
}
return new Name(parts[0], parts[1]);
}

public String convertToPresentation(Name name, Locale locale)
throws ConversionException {
if (name == null) {
return null;
} else {
return name.getFirstName() + " " + name.getLastName();
}
}

public Class<Name> getModelType() {
return Name.class;
}

public Class<String> getPresentationType() {
return String.class;
}
}
....

Hooking up the Name type and its Converter to a TextField can then be
done like this

[source,java]
....
Name name = new Name("Rudolph", "Reindeer");

final TextField textField = new TextField("Name");
textField.setConverter(new StringToNameConverter());
textField.setConvertedValue(name);

addComponent(textField);
addComponent(new Button("Submit value", new ClickListener() {
public void buttonClick(ClickEvent event) {
try {
Name name = (Name) textField.getConvertedValue();
Notification.show(
"First name: " + name.getFirstName() +
"<br />Last name: " + name.getLastName());
} catch (ConversionException e) {
Notification.show(e.getCause().getMessage());
}
}
}));
....

+ 44
- 0
documentation/articles/FindingTheCurrentRootAndApplication.asciidoc View File

@@ -0,0 +1,44 @@
[[finding-the-current-root-and-application]]
Finding the current root and application
----------------------------------------

There are many cases where you need a reference to the active
`Application` or `Root`, for instance for showing notifications in a click
listener. It is possible to get a reference to the component from the
event and then a reference from the component to the `Root` but Vaadin
also offers an easier way through two static methods:

[source,java]
....
Root.getCurrent()
Application.getCurrent()
....

For example when you want to show the name of the current Root class:

[source,java]
....
Button helloButton = new Button("Say Hello");
helloButton.addListener(new ClickListener() {
public void buttonClick(ClickEvent event) {
Notification.show("This Root is " + Root.getCurrent().getClass().getSimpleName());
}
});
....

Similarly for `Application`, for instance to find out if the application
is running in production mode:

[source,java]
....
public void buttonClick(ClickEvent event) {
String msg = "Running in ";
msg += Application.getCurrent().isProductionMode() ?
"production" : "debug";
msg += " mode";
Notification.show(msg);
}
....

*Note* that these are based on `ThreadLocal` so they won't work in a
background thread (or otherwise outside the standard request scope).

+ 177
- 0
documentation/articles/FormattingDataInGrid.asciidoc View File

@@ -0,0 +1,177 @@
[[formatting-data-in-grid]]
Formatting data in grid
-----------------------

Without any special configuration, Grid tries to find a `Converter` for
converting the property value into a String that can be shown in the
browser. The `ConverterFactory` configured for the session is used for
this purpose. If no compatible converter is found, Grid will instead
fall back to using `toString()` on the property value.

[[cellstylegenerator]]
CellStyleGenerator
^^^^^^^^^^^^^^^^^^

Grid does also provide a couple of mechanisms for fine-tuning how the
data is displayed. The simplest way of controlling the data output is to
use a `CellStyleGenerator` to add custom stylenames to individual cells,
thus affecting which CSS rules from the theme are applied to each cell.

[source,java]
....
grid.setCellStyleGenerator(new CellStyleGenerator() {
@Override
public String getStyle(CellReference cellReference) {
if ("amount".equals(cellReference.getPropertyId())) {
Double value = (Double) cellReference.getValue();
if (value.doubleValue() == Math.round(value.doubleValue())) {
return "integer";
}
}
return null;
}
});

getPage().getStyles().add(".integer { color: blue; }");
....

We have not yet defined any `Converter` or `Renderer` in this example. This
means that Grid will use a `StringToDoubleConverter` to convert the Double
values from the data source into Strings that are sent to the browser
and displayed in each cell.

To keep this example as simple as possible, we are dynamically injecting
new CSS styles into the page. In a real application, it's recommended to
instead add the styles to the theme since that helps with separation of
concerns.

[[renderer]]
Renderer
^^^^^^^^

The next thing you can do to control how the data is displayed is to use
a `Renderer`. The `Renderer` will receive the value from the data source
property, possibly after it has been converted to the `Renderer`{empty}'s input
type using a `Converter`. The `Renderer` is will then make sure the value
gets show in an appropriate way in the browser. A simple renderer might
just show the data as text, but there are also more complex `Renderer`{empty}s
that e.g. show a numerical value as a progress bar.

Will will use a `NumberRenderer` using a currency format to render the
cell values for the `Amount` column. To do this, we simply create and
configure it and then set it as the `Renderer` for the designated column.
No `Converter` will be used in this case since `NumberRenderer` already
knows ho to handle values of the type Double.

[source,java]
....
NumberFormat poundformat = NumberFormat.getCurrencyInstance(Locale.UK);
NumberRenderer poundRenderer = new NumberRenderer(poundformat);
grid.getColumn("amount").setRenderer(poundRenderer);
....

[[converter]]
Converter
^^^^^^^^^

The last way of controlling how data is displayed is to use a `Converter`.
The framework will in most cases find and use a suitable `Converter`, but
you can also supply your own if the default conversion is not what you
need. The following example uses a custom `Converter` for the `Count` column
to change the value into HTML strings with different HTML for even and
odd counts. Grid will by default protect you from cross-site scripting
vulnerabilities by not interpreting HTML in cell values. This can be
overridden by setting the column to use a `HtmlRenderer` instead of the
default `TextRenderer`. Both those renderers expect String values. Since
we will not be editing any values, the Converter doesn't need to support
changing the HTML strings back into integers.

[source,java]
....
grid.getColumn("count").setConverter(new StringToIntegerConverter() {
@Override
public String convertToPresentation(Integer value, Class<? extends String> targetType, Locale locale)
throws Converter.ConversionException {
String stringRepresentation = super.convertToPresentation(value, targetType, locale);
if (value.intValue() % 2 == 0) {
return "<strong>" + stringRepresentation + "</strong>";
} else {
return "<em>" + stringRepresentation + "</em>";
}
}
});

grid.getColumn("count").setRenderer(new HtmlRenderer());
....

[[full-example]]
Full example
^^^^^^^^^^^^

Putting all these pieces together, we end up with this class that uses
the same data as in the link:UsingGridWithAContainer.asciidoc[Using
Grid with a Container] example.

[source,java]
....
import java.text.NumberFormat;
import java.util.Locale;

import com.vaadin.annotations.Theme;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.StringToIntegerConverter;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.CellReference;
import com.vaadin.ui.Grid.CellStyleGenerator;
import com.vaadin.ui.UI;
import com.vaadin.ui.renderers.HtmlRenderer;
import com.vaadin.ui.renderers.NumberRenderer;

@Theme("valo")
public class FormattingDataInGrid extends UI {

@Override
protected void init(VaadinRequest request) {
Grid grid = new Grid(GridExampleHelper.createContainer());

setContent(grid);

grid.setCellStyleGenerator(new CellStyleGenerator() {
@Override
public String getStyle(CellReference cellReference) {
if ("amount".equals(cellReference.getPropertyId())) {
Double value = (Double) cellReference.getValue();
if (value.doubleValue() == Math.round(value.doubleValue())) {
return "integer";
}
}
return null;
}
});

getPage().getStyles().add(".integer { color: blue; }");

NumberFormat poundformat = NumberFormat.getCurrencyInstance(Locale.UK);
NumberRenderer poundRenderer = new NumberRenderer(poundformat);
grid.getColumn("amount").setRenderer(poundRenderer);

grid.getColumn("count").setConverter(new StringToIntegerConverter() {
@Override
public String convertToPresentation(Integer value,
Class<? extends String> targetType, Locale locale)
throws Converter.ConversionException {
String stringRepresentation = super.convertToPresentation(
value, targetType, locale);
if (value.intValue() % 2 == 0) {
return "<strong>" + stringRepresentation + "</strong>";
} else {
return "<em>" + stringRepresentation + "</em>";
}
}
});

grid.getColumn("count").setRenderer(new HtmlRenderer());
}
}
....

+ 405
- 0
documentation/articles/JMeterTesting.asciidoc View File

@@ -0,0 +1,405 @@
[[how-to-test-vaadin-web-application-performance-with-jmeter]]
How to test Vaadin web application performance with JMeter
----------------------------------------------------------

This article describes how to make load testing of your Vaadin web
application with http://jakarta.apache.org/jmeter/[JMeter].

[[get-the-latest-jmeter]]
Get the latest JMeter
~~~~~~~~~~~~~~~~~~~~~

Download JMeter from http://jmeter.apache.org/download_jmeter.cgi

[[configure-jmeter]]
Configure JMeter
~~~~~~~~~~~~~~~~

Unzip the apache-jmeter-x.x.x.zip file.

Edit `JMETERHOME/bin/jmeter.bat` (or `jmeter.sh`) and check that the JVM
memory parameters are ok (e.g. `set HEAP=-Xms512m -Xmx1500m -Xss128k`).
The maximum heap size (`-Xmx`) should be at least 1024m. I would also
recommend that the thread stack size is set to 512k or below if a large
number of threads is used in testing.

You should read this to ensure you follow best-practices:

* http://jmeter.apache.org/usermanual/best-practices.html +
* http://www.ubik-ingenierie.com/blog/jmeter_performance_tuning_tips/

[[start-jmeter]]
Start JMeter
~~~~~~~~~~~~

E.g. double clicking jmeter.bat

[[configure-your-test-plan-and-workbench]]
Configure your Test Plan and WorkBench
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Right click the WorkBench icon and select 'Add' -> 'Non-Test Elements'
-> 'HTTP(S) Test Script Recorder'. Edit the Recorder parameters and set
Port: to e.g. 9999 (you could leave it to 8080 if your web application
servers do not use the port 8080). Typically requests related to loading
static web content like css files and images are excluded from the load
test. You can use 'Url Patterns to Exclude' section of the recorder to
define what content is excluded. For instance to exclude css files add
following pattern: `.*\.css`

image:img/jm1B.png[JMeter patterns to exclude]

Right click the Recorder icon and select 'Add' -> 'Timer' -> 'Uniform
random timer'. Configure timer by setting the *Constant Delays Offset
into $\{T}*. This setting means that JMeter records also the delays
between the http requests. You could also test without the timer but
with the timer your test is more realistic.

image:img/jm3B.png[JMeter uniform random timer]

Optionally you could also add 'View Result Tree' listener under the
Recorder. With 'View Result Tree' listener it is possible to inspect
every recorded request and response.

*Note since JMeter you can do this in one step using menu item
"Templates..." and selecting "Recording" template.*

image:img/jm2B.png[JMeter View Results Tree]

Next, configure the Test Plan.
Add a 'Thread Group' to it and then add a 'Config Element' -> 'HTTP
Cookie Manager' to the thread group. Set Cookie policy of the cookie
manager to be 'compatibility'. *Remember also to set the "Clear cookies
each iteration" setting to 'checked'*. Add also a 'Config Element' ->
'HTTP Request Defaults' into Thread group.

You could also add a 'Config Element' -> 'User Defined Variables' and a
'Logic Controller' -> 'Recording Controller' into Thread Group.

Your JMeter should now looks something like the screenshot below:

image:img/jm4.png[JMeter User Defined Variables]

[[configure-your-vaadin-application]]
Configure your Vaadin application
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[[disable-the-xsrf-protection]]
Disable the xsrf-protection
^^^^^^^^^^^^^^^^^^^^^^^^^^^

In Vaadin you have to disable the xsrf-protection of your application or
otherwise the JMeter test may fail. The way how xsrf protection is
disabled differs in Vaadin 6 and Vaadin 7.

*In Vaadin 7*

If you use web.xml in your Vaadin 7 project, add the following
context-parameter in the web.xml or optionally add it as an init
parameter just like in the Vaadin 6 project below.

[source,xml]
....
<context-param>
<param-name>disable-xsrf-protection</param-name>
<param-value>true</param-value>
</context-param>
....

If you use annotation based (Servlet 3.0) Vaadin servlet configuration,
you can currently (in Vaadin 7.1.11) either fall back to Servlet 2.4
web.xml configuration or set the parameter value for
'disable-xsrf-protection' as a `java.lang.System property` before the
Vaadin's `DefaultDeploymentConfiguration` is loaded. This can be done for
example by extending `VaadinServlet` class. At the end of this Wiki
article there is an example servlet (`JMeterServlet`) that implements this
functionality. See the example code below for how to replace the default
`VaadinServlet` with your custom `VaadinServlet` in the UI class.

[source,java]
....
public class YourUI extends UI {

@WebServlet(value = "/*", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = YourUI.class)
public static class Servlet extends JMeterServlet {
}

@Override
protected void init(VaadinRequest request) {
//...
}
....

*In Vaadin 6*

See the example below for how to disable the protection from the web.xml
file:

[source,xml]
....
<servlet>
<servlet-name>FeatureBrowser</servlet-name>
<servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
<init-param>
<param-name>application</param-name>
<param-value>com.vaadin.demo.featurebrowser.FeatureBrowser</param-value>
</init-param>

<init-param>
<param-name>disable-xsrf-protection</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
....

*Important! Remember to enable the protection after the testing is
done!*

[[disabling-syncid-happens-with-similar-parameter]]
Disabling syncId happens with similar parameter
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

[source,xml]
....
<context-param>
<param-name>syncId</param-name>
<param-value>false</param-value>
</context-param>
....

If you want to do the above with Java Servlet 3.0 annotations, use the
following:

[source,java]
....
initParams = {
@WebInitParam(name = "disable-xsrf-protection", value = "true"),
@WebInitParam(name = "syncIdCheck", value = "false")}
....

[[use-debug-ids-within-your-vaadin-application]]
Use debug id:s within your Vaadin application
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Normally a Vaadin application sets a sequential id for each user
interface component of the application. These ids are used in the
ajax-requests when the component state is synchronized between the
server and the client side. The aforementioned id sequence is likely the
same between different runs of the application, but this is not
guaranteed. *In Vaadin 6* these ids can be manually set by calling
http://vaadin.com/api/com/vaadin/ui/AbstractComponent.html#setDebugId%28java.lang.String%29[`setDebugId()`]
method.

*In Vaadin 7* there no more exists a `setDebugId()` method; instead there
is
https://vaadin.com/api/com/vaadin/ui/Component.html#setId(java.lang.String)[`setId()`]
method. Unfortunately this method won't set component ids used in the
ajax-request. Therefore, by default, JMeter tests of a Vaadin 7
application are not stable to UI changes. To overcome this problem you
can use our `JMeterServlet` (see the end of this article) instead of the
default `VaadinServlet`. When using the `JMeterServlet` component ids are
again used in the ajax requests. See example above for how to replace
default `VaadinServlet` with JMeterServlet. For additional information,
see the Vaadin ticket http://dev.vaadin.com/ticket/13396[#13396].

[[use-named-windows-in-your-application]]
Use named windows in your application
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Setting the name for the Windows *in the Vaadin (< 6.4.X)* application
is important since otherwise these names are randomly generated. Window
name could be set using the `setName()`{empty}-method.

[[configure-your-browser]]
Configure your browser
~~~~~~~~~~~~~~~~~~~~~~

Since JMeter is used as a proxy server, you have to configure the proxy
settings of your browser. You can find the proxy settings of Firefox
from Tools -> Options -> Connections -> Settings: 'Manual proxy
configuration'. Set the correct IP of your computer (or 'localhost'
string) and the same port that you set into proxy server settings above.

[[start-recording]]
Start recording
~~~~~~~~~~~~~~~

Start your web application server. Start the proxy server from the
JMeter. Open the URL of your web application into the browser configured
above. You should append `?restartApplication` to the URL used when
recording the tests to make sure that the UI gets initialized properly.
Thus the URL becomes something like
(http://localhost:8080/test/TestApplication/?restartApplication). If
everything is ok your web application opens normally and you can see how
the different HTTP requests appear into JMeter's thread group (see
screenshot below). When you have done the recording, stop the proxy
server.

image:img/jm5.png[JMeter Thread Groups]

[[performance-testing]]
Performance testing
~~~~~~~~~~~~~~~~~~~

[[clean-up-the-recorded-request]]
Clean up the recorded request
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Before you start the test, you may have to delete the first timer object
which is located below the first HTTP request in the thread group since
its time delay may be unrealistically big (see the screenshot above).
*It is also very much recommended to check the recorded data and delete
all unessential requests.*

[[detecting-out-of-sync-errors]]
Detecting Out of Sync errors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If your test results in the application being in an Out of Sync error
state it is not by default detected by JMeter (because the response code
is still HTTP/1.1 200 OK). To make an assertion for detecting this kind
of error you should add a Response Assertion to your test plan.
Right-click on the thread group and select Add -> Assertions -> Response
Assertion. Configure the assertion to assert that the Text Response does
NOT contain a pattern "Out of sync".

[[optional-parameterization-of-the-request]]
Optional parameterization of the request
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Sometimes, it is useful to parameterize the recorded requests.
Parameterization of a request is easily done in JMeter:

1. add a "User Defined Variables"-element into the first place of your Test Plan.
2. Copy paste the whole parameter value of wanted UIDL-request into the
newly made variable (e.g. `PARAM1`).
3. Replace the value of the UIDL-request with the parameter reference (e.g. `${PARAM1}`).

[[start-testing]]
Start testing
^^^^^^^^^^^^^

Now, it is time to do the actual testing. Configure the thread group
with proper 'Number of Threads' (e.g. 100) and set also the 'Ramp-Up
Period' to some realistic value (e.g. 120). Then, add e.g. 'Listener' ->
'Graph Results' to monitor how your application is performing. Finally,
start the test from the Run -> Start.

[[stop-on-error]]
Stop on Error
^^^^^^^^^^^^^

When you are pushing your Vaadin application to the limits, you might
get into a situation where some of the UIDL requests fail. Because of
the server-driven nature of Vaadin, it's likely that subsequent requests
will cause errors like "_Warning: Ignoring variable change for
non-existent component_", as the state stored on the server-side is no
longer in sync with the JMeter test script. In these cases, it's often
best to configure your JMeter thread group to stop the thread on sampler
error. However, if you have configured your test to loop, you might want
to still continue (and ignore the errors), if the next iteration will
start all over again with fresh state.

[[continuous-integration]]
Continuous Integration
^^^^^^^^^^^^^^^^^^^^^^

If you want to integrate load testing in your CI, you can use this
http://jmeter.lazerycode.com/[plugin].

You can read this for full integration with Jenkins : 

* https://blog.codecentric.de/en/2014/01/automating-jmeter-tests-maven-jenkins/

[[jmeterservlet]]
JMeterServlet
^^^^^^^^^^^^^

In Vaadin 7 we recommend using the following or similar customized
`VaadinServlet`.

[source,java]
....
package com.example.vaadin7jmeterservlet;

import com.vaadin.server.ClientConnector;
import com.vaadin.server.DeploymentConfiguration;
import com.vaadin.server.ServiceException;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinServlet;
import com.vaadin.server.VaadinServletService;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.Component;

/**
* @author Marcus Hellberg (marcus@vaadin.com)
* Further modified by Johannes Tuikkala (johannes@vaadin.com)
*/
public class JMeterServlet extends VaadinServlet {
private static final long serialVersionUID = 898354532369443197L;

public JMeterServlet() {
System.setProperty(getPackageName() + "." + "disable-xsrf-protection",
"true");
}

@Override
protected VaadinServletService createServletService(
DeploymentConfiguration deploymentConfiguration)
throws ServiceException {
JMeterService service = new JMeterService(this, deploymentConfiguration);
service.init();

return service;
}

private String getPackageName() {
String pkgName;
final Package pkg = this.getClass().getPackage();
if (pkg != null) {
pkgName = pkg.getName();
} else {
final String className = this.getClass().getName();
pkgName = new String(className.toCharArray(), 0,
className.lastIndexOf('.'));
}
return pkgName;
}

public static class JMeterService extends VaadinServletService {
private static final long serialVersionUID = -5874716650679865909L;

public JMeterService(VaadinServlet servlet,
DeploymentConfiguration deploymentConfiguration)
throws ServiceException {
super(servlet, deploymentConfiguration);
}

@Override
protected VaadinSession createVaadinSession(VaadinRequest request)
throws ServiceException {
return new JMeterSession(this);
}
}

public static class JMeterSession extends VaadinSession {
private static final long serialVersionUID = 4596901275146146127L;

public JMeterSession(VaadinService service) {
super(service);
}

@Override
public String createConnectorId(ClientConnector connector) {
if (connector instanceof Component) {
Component component = (Component) connector;
return component.getId() == null ? super
.createConnectorId(connector) : component.getId();
}
return super.createConnectorId(connector);
}
}
}
....

+ 185
- 0
documentation/articles/JasperReportsOnVaadinSample.asciidoc View File

@@ -0,0 +1,185 @@
[[jasper-reports-on-vaadin-sample]]
Jasper reports on Vaadin sample
------------------------------

[[introduction]]
Introduction
~~~~~~~~~~~~

I meet JasperReports some years ago and I liked this report library;
this year I did need to implement a report on a personal project using
Vaadin, but surprisingly I was not able to found a sample of this, so I
did this little sample and article.

First, you will need a JDK Maven and Mysql in order to try the sample,
and you can download the code here:
http://sourceforge.net/projects/jrtutorial/files/VaadinJRSample/

There is a README.txt file you can follow in order to run the sample,
basically you need to:

1. Create database running resources/database.sql on Mysql or MariaDB
2. Compile the entire project: run "mvn install”.
3. Deploy the application in Jetty: run "mvn jetty:run"
4. Go to http://localhost:8080/  in your browser

[[implementation]]
Implementation
~~~~~~~~~~~~~~

Let’s see the sample code step by step. +
The data is only a _person_ table with some data. +
The main class _MyUI.java_ has two UI components (the report generating
button and a list component used to show current data in database.):

[source,java]
....
final Button reportGeneratorButton = new Button("Generate report");
layout.addComponent(reportGeneratorButton);
layout.addComponent(new PersonList());
....

The list is implemented on _PersonList.java_, I am using a
_FilteringTable_ (https://vaadin.com/directory/component/filteringtable),
that loads the data using a Vaadin _SQLContainer_:

[source,java]
....
SQLContainer container=null;
TableQuery tq = new TableQuery("person", new ConnectionUtil().getJDBCConnectionPool());
container = new SQLContainer(tq);
filterTable = buildPagedTable(container);
....

And the _SQLContainer_ is provided with a _JDBCConnectionPool_ created
from a properties file (_resources/database.properties_):

[source,java]
....
Properties prop=PropertiesUtil.getProperties();
public JDBCConnectionPool getJDBCConnectionPool(){
JDBCConnectionPool pool = null;
try {
pool = new SimpleJDBCConnectionPool(
prop.getProperty("database.driver"),
prop.getProperty("database.url"),
prop.getProperty("database.userName"),
prop.getProperty("database.password"));
} catch (SQLException e) {
e.printStackTrace();
}
return pool;
....

The report generation is implemented on _ReportGenerator_ class, this
class loads the report template:

[source,java]
....
File templateFile=new File(templatePath);       
JasperDesign jasperDesign = JRXmlLoader.load(templateFile);
....

Compile report template:

[source,java]
....
jasperReport = JasperCompileManager.compileReport(jasperDesign);
....

Fill report with data:

[source,java]
....
HashMap fillParameters=new HashMap();       
JasperPrint jasperPrint = JasperFillManager.fillReport(   
jasperReport,                   
fillParameters,                   
conn);
....

Export the _jasperPrint_ object to Pdf format:

[source,java]
....
JRPdfExporter exporter = new JRPdfExporter();
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));
exporter.exportReport();
....

And finally execute all the logic to generate the report and sent it to
an _OutputStream_:

[source,java]
....
JasperDesign jasperDesign=loadTemplate(templatePath);
setTempDirectory(templatePath);       
JasperReport jasperReport=compileReport(jasperDesign);       
JasperPrint jasperPrint=fillReport(jasperReport, conn);       
exportReportToPdf(jasperPrint, outputStream);
....

But all the logic at _ReportGenerator.java_ is called from the
_ReportUtil_ class, this class is the responsible to connect Vaadin
layer with _ReportGenerator_ layer. There are two methods: the first one
is _prepareForPdfReport_, this method creates a database connection,
generates the report as a StreamResource (calling the another method)
and finally extends the source button with a _FileDownloader_ component
in order to upload the generated report stream, so all the uploading
magic is done by _FileDownloader_ extension
(https://vaadin.com/api/com/vaadin/server/FileDownloader.html):

[source,java]
....
Connection conn=new ConnectionUtil().getSQLConnection();
reportOutputFilename+=("_"+getDateAsString()+".pdf");       
StreamResource myResource =createPdfResource(conn,reportTemplate,reportOutputFilename);       
FileDownloader fileDownloader = new FileDownloader(myResource);       
fileDownloader.extend(buttonToExtend);
....

The second method _createPdfResource_, uses _ReportGenerator_ class in
order to return the generated report as a _StreamResource_:

[source,java]
....
return new StreamResource(new StreamResource.StreamSource() {
@Override
public InputStream getStream () {
ByteArrayOutputStream pdfBuffer = new ByteArrayOutputStream();
ReportGenerator reportGenerator=new ReportGenerator();
try {
reportGenerator.executeReport(baseReportsPath+templatePath, conn, pdfBuffer);
} catch (JRException e) {
e.printStackTrace();
}
return new ByteArrayInputStream(
pdfBuffer.toByteArray());
}
}, reportFileName);
....

So, in order to call the report generator process when only need to call
ReportUtil like we did in ‘MyUI.java’:

[source,java]
....
final Button reportGeneratorButton = new Button("Generate report");
new ReportsUtil().prepareForPdfReport("/reports/PersonListReport.jrxml",               
"PersonList",               
reportGeneratorButton);
....

Finally, the jasper report design can be found in the
_WEB-INF/personListReport.jrxml_ file

This is a picture of the sample running and the generated report:

image:img/VaadinJasperReportsSample_small.jpg[Running sample]

And that’s all, I expect to help someone with this sample, thanks for
reading.

+ 462
- 0
documentation/articles/LazyQueryContainer.asciidoc View File

@@ -0,0 +1,462 @@
[[lazy-query-container]]
Lazy query container
--------------------

[[when-to-use-lazy-query-container]]
When to Use Lazy Query Container?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Typical usage scenario is browsing a large persistent data set in Vaadin
Table. LQC minimizes the complexity of the required custom
implementation while retaining all table features like sorting and lazy
loading. LQC delegates sorting of the data set to the backend data store
instead of sorting in memory. Sorting in memory would require entire
data set to be loaded to application server.

[[what-is-lazy-loading]]
What is Lazy Loading?
~~~~~~~~~~~~~~~~~~~~~

In this context lazy loading refers to loading items to table on demand
in batches instead of loading the entire data set to memory at once.
This is useful in most business applications as row counts often range
from thousands to millions. Loading more than few hundred rows to memory
often causes considerable delay in page response.

[[getting-started]]
Getting Started
~~~~~~~~~~~~~~~

To use LQC you need to get the add-on from add-ons page and drop it to
your projects WEB-INF/lib directory. After this you can use existing
query factory (`JpaQueryFactory`), extend `AbstractBeanQuery` or proceed to
implement custom `Query` and `QueryFactory`. Finally you need to instantiate
`LazyQueryContainer` and give your query factory as constructor parameter.

[[how-to-use-lazy-query-container-with-table]]
How to Use Lazy Query Container with Table?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

LQC is implementation of Vaadin Container interface. Please refer to
Book of Vaadin for usage details of Table and Container implementations
generally.

[[how-to-use-entitycontainer]]
How to Use EntityContainer
~~~~~~~~~~~~~~~~~~~~~~~~~~

`EntityContainer` is specialized version `LazyQueryContainer` allowing easy
use of JPA as persistence layer and supports defining where criteria and
corresponding parameter map in addition to normal `LazyQueryContainer`
features:

[source,java]
....
entityContainer = new EntityContainer<Task>(entityManager, true, Task.class, 100,
new Object[] { "name" }, new boolean[] { true });
entityContainer.addContainerProperty("name", String.class, "", true, true);
entityContainer.addContainerProperty("reporter", String.class, "", true, true);
entityContainer.addContainerProperty("assignee", String.class, "", true, true);
whereParameters = new HashMap<String, Object>();
whereParameters.put("name", nameFilter);
entityContainer.filter("e.name=:name", whereParameters);

table.setContainerDataSource(entityContainer);
....

[[how-to-use-beanqueryfactory]]
How to Use BeanQueryFactory
~~~~~~~~~~~~~~~~~~~~~~~~~~~

`BeanQueryFactory` and `AbstractBeanQuery` are used to implement queries
saving and loading JavaBeans.

The `BeanQueryFactory` is used as follows with the Vaadin table. Usage of
`queryConfiguration` is optional and enables passing objects to the
constructed queries:

[source,java]
....
Table table = new Table();
BeanQueryFactory<TaskBeanQuery> queryFactory = new
BeanQueryFactory<TaskBeanQuery>(TaskBeanQuery.class);

Map<String,Object> queryConfiguration = new HashMap<String,Object>();
queryConfiguration.put("taskService",new TaskService());
queryFactory.setQueryConfiguration(queryConfiguration);

LazyQueryContainer container = new LazyQueryContainer(queryFactory,50);
table.setContainerDataSource(container);
....

Here is a simple example of `AbstractBeanQuery` implementation:

[source,java]
....
public class TaskBeanQuery extends AbstractBeanQuery<Task> {

public TaskBeanQuery(QueryDefinition definition,
Map<String, Object> queryConfiguration, Object[] sortPropertyIds,
boolean[] sortStates) {
super(definition, queryConfiguration, sortPropertyIds, sortStates);
}

@Override
protected Task constructBean() {
return new Task();
}

@Override
public int size() {
TaskService taskService =
(TaskService)queryConfiguration.get("taskService");
return taskService.countTasks();
}

@Override
protected List<Task> loadBeans(int startIndex, int count) {
TaskService taskService =
(TaskService)queryConfiguration.get("taskService");
return taskService.loadTasks(startIndex, count, sortPropertyIds, sortStates);
}

@Override
protected void saveBeans(List<Task> addedTasks, List<Task> modifiedTasks,
List<Task> removedTasks) {
TaskService taskService =
(TaskService)queryConfiguration.get("taskService");
taskService.saveTasks(addedTasks, modifiedTasks, removedTasks);
}
}
....

[[how-to-implement-custom-query-and-queryfactory]]
How to Implement Custom Query and QueryFactory?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

`QueryFactory` instantiates new query whenever sort state changes or
refresh is requested. Query can construct for example named JPA query in
constructor. Data loading starts by invocation of `Query.size()` method
and after this data is loaded in batches by invocations of
`Query.loadItems()`.

Please remember that the idea is to load data in batches. You do not
need to load the entire data set to memory. If you do that you are
better of with some other container implementation like
`BeanItemContainer`. To be able to load database in batches you need your
storage to provide you with the result set size and ability to load rows
in batches as illustrated by the following pseudo code:

[source,java]
....
int countObjects(SearchCriteria searchCriteria);
List<Object> getObjects(SearchCriteria searchCriteria, int startIndex, int batchSize);
....

Here is simple read only JPA example to illustrate the idea. You can
find further examples from add-on page.

[source,java]
....
package com.logica.portlet.example;

import javax.persistence.EntityManager;

import org.vaadin.addons.lazyquerycontainer.Query;
import org.vaadin.addons.lazyquerycontainer.QueryDefinition;
import org.vaadin.addons.lazyquerycontainer.QueryFactory;

public class MovieQueryFactory implements QueryFactory {

private EntityManager entityManager;
private QueryDefinition definition;

public MovieQueryFactory(EntityManager entityManager) {
super();
this.entityManager = entityManager;
}

@Override
public void setQueryDefinition(QueryDefinition definition) {
this.definition = definition;
}

@Override
public Query constructQuery(Object[] sortPropertyIds, boolean[] sortStates) {
return new MovieQuery(entityManager,definition,sortPropertyIds,sortStates);
}
}
....

[source,java]
....
package com.logica.portlet.example;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;

import org.vaadin.addons.lazyquerycontainer.Query;
import org.vaadin.addons.lazyquerycontainer.QueryDefinition;

import com.logica.example.jpa.Movie;
import com.vaadin.data.Item;
import com.vaadin.data.util.BeanItem;

public class MovieQuery implements Query {

private EntityManager entityManager;
private QueryDefinition definition;
private String criteria = "";

public MovieQuery(EntityManager entityManager,
QueryDefinition definition,
Object[] sortPropertyIds,
boolean[] sortStates) {
super();
this.entityManager = entityManager;
this.definition = definition;

for(int i=0;i<sortPropertyIds.length;i++) {
if(i==0) {
criteria = " ORDER BY";
} else {
criteria+ = ",";
}
criteria += " m." + sortPropertyIds[i];
if(sortStates[i]) {
criteria += " ASC";
}
else {
criteria += " DESC";
}
}
}

@Override
public Item constructItem() {
return new BeanItem<Movie>(new Movie());
}

@Override
public int size() {
javax.persistence.Query query = entityManager.
createQuery("SELECT count(m) from Movie as m");
return (int)((Long) query.getSingleResult()).longValue();
}

@Override
public List<Item> loadItems(int startIndex, int count) {
javax.persistence.Query query = entityManager.
createQuery("SELECT m from Movie as m" + criteria);
query.setFirstResult(startIndex);
query.setMaxResults(count);

List<Movie> movies=query.getResultList();
List<Item> items=new ArrayList<Item>();
for(Movie movie : movies) {
items.add(new BeanItem<Movie>(movie));
}

return items;
}

@Override
public void saveItems(List<Item> addedItems, List<Item> modifiedItems,
List<Item> removedItems) {
throw new UnsupportedOperationException();
}

@Override
public boolean deleteAllItems() {
throw new UnsupportedOperationException();
}
}
....

[[how-to-implement-editable-table]]
How to Implement Editable Table?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

First you need to implement the `Query.saveItems()` method. After this you
need to set some of the properties editable in your items and set table
in editable mode as well. After user has made changes you need to call
`container.commit()` or `container.discard()` to commit or rollback
respectively. Please find complete examples of table handing and
editable JPA query from add-on page.

[[how-to-use-debug-properties]]
How to Use Debug Properties?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

LQC provides set of debug properties which give information about
response times, number of queries constructed and data batches loaded.
To use these properties the items used need to contain these properties
with correct ids and types. If you use dynamic items you can defined
them in the query definition and add them on demand in the query
implementation.

[source,java]
....
container.addContainerProperty(LazyQueryView.DEBUG_PROPERTY_ID_QUERY_INDEX, Integer.class, 0, true, false);
container.addContainerProperty(LazyQueryView.DEBUG_PROPERTY_ID_BATCH_INDEX, Integer.class, 0, true, false);
container.addContainerProperty(LazyQueryView.DEBUG_PROPERTY_ID_BATCH_QUERY_TIME, Integer.class, 0, true, false);
....

[[how-to-use-row-status-indicator-column-in-table]]
How to Use Row Status Indicator Column in Table?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When creating editable tables LCQ provides
`QueryItemStatusColumnGenerator` which can be used to generate the status
column cells to the table. In addition you need to have the status
property in your items. If your items respect the query definition you
can implement this as follows:

[source,java]
....
container.addContainerProperty(LazyQueryView.PROPERTY_ID_ITEM_STATUS,
QueryItemStatus.class, QueryItemStatus.None, true, false);
....

[[how-to-use-status-column-and-debug-columns-with-beans]]
How to Use Status Column and Debug Columns with Beans
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Here is example query implementation which shows how JPA and beans can
be used together with status and debug properties:

[source,java]
....
package org.vaadin.addons.lazyquerycontainer.example;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;

import org.vaadin.addons.lazyquerycontainer.CompositeItem;
import org.vaadin.addons.lazyquerycontainer.Query;
import org.vaadin.addons.lazyquerycontainer.QueryDefinition;

import com.vaadin.data.Item;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.ObjectProperty;

public class TaskQuery implements Query {

private EntityManager entityManager;
private QueryDefinition definition;
private String criteria=" ORDER BY t.name ASC";

public TaskQuery(EntityManager entityManager, QueryDefinition definition,
Object[] sortPropertyIds, boolean[] sortStates) {
super();
this.entityManager = entityManager;
this.definition = definition;

for(int i=0; i<sortPropertyIds.length; i++) {
if(i==0) {
criteria = " ORDER BY";
} else {
criteria+ = ",";
}
criteria += " t." + sortPropertyIds[i];
if(sortStates[i]) {
criteria += " ASC";
}
else {
criteria += " DESC";
}
}
}

@Override
public Item constructItem() {
Task task=new Task();
try {
BeanInfo info = Introspector.getBeanInfo( Task.class );
for ( PropertyDescriptor pd : info.getPropertyDescriptors() ) {
for(Object propertyId : definition.getPropertyIds()) {
if(pd.getName().equals(propertyId)) {
pd.getWriteMethod().invoke(task,
definition.getPropertyDefaultValue(propertyId));
}
}
}
} catch(Exception e) {
throw new RuntimeException("Error in bean property population");
}
return toItem(task);
}

@Override
public int size() {
javax.persistence.Query query = entityManager.createQuery(
"SELECT count(t) from Task as t");
return (int)((Long) query.getSingleResult()).longValue();
}

@Override
public List<Item> loadItems(int startIndex, int count) {
javax.persistence.Query query = entityManager.createQuery(
"SELECT t from Task as t" + criteria);
query.setFirstResult(startIndex);
query.setMaxResults(count);

List<Task> tasks=query.getResultList();
List<Item> items=new ArrayList<Item>();
for(Task task : tasks) {
items.add(toItem(task));
}
return items;
}

@Override
public void saveItems(List<Item> addedItems, List<Item> modifiedItems,
List<Item> removedItems) {
entityManager.getTransaction().begin();
for(Item item : addedItems) {
entityManager.persist(fromItem(item));
}
for(Item item : modifiedItems) {
entityManager.persist(fromItem(item));
}
for(Item item : removedItems) {
entityManager.remove(fromItem(item));
}
entityManager.getTransaction().commit();
}

@Override
public boolean deleteAllItems() {
throw new UnsupportedOperationException();
}

private Item toItem(Task task) {
BeanItem<Task> beanItem= new BeanItem<Task>(task);

CompositeItem compositeItem=new CompositeItem();

compositeItem.addItem("task", beanItem);

for(Object propertyId : definition.getPropertyIds()) {
if(compositeItem.getItemProperty(propertyId)==null) {
compositeItem.addItemProperty(propertyId, new ObjectProperty(
definition.getPropertyDefaultValue(propertyId),
definition.getPropertyType(propertyId),
definition.isPropertyReadOnly(propertyId)));
}
}
return compositeItem;
}

private Task fromItem(Item item) {
return (Task)((BeanItem)(((CompositeItem)item).getItem("task"))).getBean();
}
}
....

+ 648
- 0
documentation/articles/MigratingFromVaadin6ToVaadin7.asciidoc View File

@@ -0,0 +1,648 @@
[[migrating-from-vaadin-6-to-vaadin-7]]
Migrating from Vaadin 6 to Vaadin 7
-----------------------------------

For migration to Vaadin 7.1,  see
link:MigratingFromVaadin7.0ToVaadin7.1.asciidoc[Migrating
from Vaadin 7.0 to Vaadin 7.1]

[[getting-started]]
Getting Started
~~~~~~~~~~~~~~~

Most Vaadin 7 APIs are compatible with Vaadin 6, but there are some
changes that affect every application.

Moving to Vaadin 7 brings a number of features designed to make the
lives of developers easier. It is a major version where we could improve
(and break) some parts of the API that have been stagnant and in need of
improvement for years.

Fear not, though, as the vast majority of the API is unchanged or
practically so - many parts even for the last 10 years apart for some
package name changes. While every application requires some migration
steps, the minimal steps needed for many applications are simple enough,
although a few more changes can be useful to benefit from some of the
new features such as improvements to data binding.

The first step is to *update Vaadin libraries*. While Vaadin 6 had a
single JAR and separate GWT JARs, Vaadin 7 is packaged as multiple JARs
that also include GWT. The easiest way to get all you need is to use Ivy
(see below in the section on updating an existing Eclipse project) or
Maven (see below on updating a Maven project). If you are using the latest version of
the Vaadin Eclipse plug-in, upgrading the facet version creates an Ivy
configuration.

The first code change that applies to every Vaadin 6 application
concerns the *com.vaadin.Application* class - it *exists no more*. The
main entry point to your application is now a *com.vaadin.ui.UI*, which
replaces Application and its main window. When switching to UI, you also
get multi-window support out of the box, so bye bye to any old hacks to
make it work. On the flip side, a new UI is created on page reload. If
you prefer to keep the UI state over page reloads in the same way Vaadin
6 does, just add *@PreserveOnRefresh* annotation on your UI class.

For minimal migration, though, it is possible to replace Application
with *LegacyApplication* and its main Window with *LegacyWindow* and
postpone a little dealing with UIs, but when migrating to UIs, you get
more out of the box. The class *Window* is now only used for
"sub-windows" (windows floating inside the page) , not "browser level"
windows or tabs (the whole web page).

An example should clarify things better than lengthy explanations,
so:Vaadin 6:

[source,java]
....
package com.example.myexampleproject;

import com.vaadin.Application;
import com.vaadin.ui.*;

public class V6tm1Application extends Application {
@Override
public void init() {
Window mainWindow = new Window("V6tm1 Application");
Label label = new Label("Hello Vaadin!");
mainWindow.addComponent(label);
setMainWindow(mainWindow);
setTheme(“mytheme”);
}
}
....

Vaadin 7:

[source,java]
....
package com.example.myexampleproject;

import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.*;

@Theme("mytheme")
public class MyApplicationUI extends UI {

@Override
protected void init(VaadinRequest request) {
VerticalLayout view = new VerticalLayout();
view.addComponent(new Label("Hello Vaadin!"));
setContent(view);
}
}
....

In addition, replace `com.vaadin.terminal.gwt.server.ApplicationServlet`
with com.vaadin.server.*VaadinServlet* in web.xml and its parameter
"application" with "*UI*" pointing to your UI class, and the application
is ready to go. Likewise, *ApplicationPortlet* has become *VaadinPortlet*.

Some package names have also been changed, but a simple import
reorganization in your IDE should take care of this.

If you have a custom theme, import e.g.
"../reindeer/*legacy-styles.css*" instead of "../reindeer/styles.css".
The theme is now selected with an *@Theme* annotation on your UI class
rather than a call to *setTheme()*, the usage should be clear from the
example above.

Most remaining issues should show up as compilation errors and in most
cases should be easy to fix in your IDE.

Now you should be ready to compile your widgetset (if any) and take the
application for a first test drive. If you have customized themes, they
will probably also need other updates - see the section on themes below.

Note that support for some older browser versions - including IE6 and
IE7 - has been dropped in Vaadin 7. If you absolutely need them, Vaadin
6 will continue to support them until its planned end of life (June
2014, five years from release of 6.0).

If you have problems with specific topics, see the related sections of
the migration guide.

In case you need more help with the migration, the Vaadin team also
provides https://vaadin.com/services#professionalservices[professional
services].

[[converting-an-eclipse-project]]
Converting an Eclipse project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you have an existing Vaadin 6 Eclipse project, the easiest way to get
up and running with Vaadin 7 is to switch to *Ivy for dependency
management*. In the project properties, select Project Facets and change
the Vaadin plug-in version to 7.0. If necessary, upgrade also the Java
and Dynamic Web Module facets. _Make sure you use the latest version of
the *Eclipse plug-in* from the update site
https://vaadin.com/framework/get-started#eclipse for this, and note that currently
installing it also requires that the IvyDE update site is configured. We
will attempt to eliminate this additional complication soon._

Ivy dependency management can also be configured by hand by adding the
files ivy.xml and ivysettings.xml to the root of the project and using
them from Eclipse (with the IvyDE plug-in), Ant or other build system.
For examples of the two files, see e.g.
http://dev.vaadin.com/svn/integration/eclipse/plugins/com.vaadin.integration.eclipse/template/ivy/[here]
and update VAADIN_VERSION in the file ivy.xml.

Note that Vaadin 7 requires *Java version 6* or higher and *servlet
version 2.4* or higher (or portlet 2.0 or higher). If your project is
set up for older versions, update the corresponding facets.

[[converting-a-maven-project]]
Converting a Maven project
~~~~~~~~~~~~~~~~~~~~~~~~~~

Converting a *Maven* project is usually quite straightforward: replace
the Vaadin dependency with dependencies to the needed Vaadin artifacts,
remove any dependencies on GWT JARs, replace the GWT plug-in with the
Vaadin plug-in and recompile everything. The easiest way to get the
required sections and dependencies is to create a new project from the
vaadin-application-archetype and copy the relevant sections from it to
your project.

Note that Vaadin 7 requires Java version 6 or higher and servlet version
2.4 or higher (or portlet 2.0 or higher). If your project is set up for
older versions, update the corresponding dependencies and compiler
version.

[[content-for-windows-panels-and-more]]
Content for Windows, Panels and More
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In Vaadin 6, Window, Panel and some other components had a *default
layout* and addComponent() etc. As this often caused confusion and
caused layout problems when unaware of the implicit layout or forgetting
to set its layout parameters, Vaadin 7 now requires *explicitly setting
the content*. See See e.g.
link:CreatingABasicApplication.asciidoc[Creating
a basic application]

If you want to minimize the impact of this on the look and theme of an
old application, you can reproduce the *old structure* simply by setting
a `VerticalLayout` (with margins enabled) as the content and add your
components to it rather than the Panel/UI/Window.

Note that the class *Window* is now only used for sub-windows, not
browser level windows.

Information related to browser windows in now in *Page*, including
browser window size, URI fragment and page title. Setting the browser
location (redirecting to a URL) can also be performed via Page.

The API for *Notifications* has also changed, static methods
`Notification.show()` are now used instead of `Window.showNotification()`.

The current *UI*, *Page*, *VaadinService*, *VaadinRequest* and *VaadinResponse*
instances are easily accessible using *UI.getCurrent()*,
*Page.getCurrent()* etc. The session can be obtained using
*UI.getSession()* and the request and response are available from
*VaadinService.getCurrent()*. Thus, no more need for an explicit
*ThreadLocal* to keep track of them.

VaadinSession also provides the new entry point for *locking* access to
Vaadin components from *background threads*, replacing the old approach
of synchronizing to the Application instance - see the javadoc for
*VaadinSession.lock()* for more details.

To customize the creation of UIs - for instance to create different UIs
for mobile and desktop devices -
*link:CreatingAnApplicationWithDifferentFeaturesForDifferentClients.asciidoc[a
custom UIProvider]* can be used.

[[forms-and-data-binding]]
Forms and Data Binding
~~~~~~~~~~~~~~~~~~~~~~

What enterprise applications are all about is data, and the data entry
side in Vaadin 6 has been lacking in customizability. While it has been
possible to create arbitrary forms for data input, many situations have
required either bypassing the Form mechanism or using complicated tricks
to customize their layouts etc.

Although *Form* is still there in Vaadin 7 and a lot of old code for
data binding works mostly as is, version 7 brings something better:

* *FieldGroup* supporting *automated data binding*, whether for a hand-designed
form or
link:AutoGeneratingAFormBasedOnABeanVaadin6StyleForm.asciidoc[creating
the fields automatically]

* *link:CreatingATextFieldForIntegerOnlyInputUsingADataSource.asciidoc[typed
fields and properties]*

* *link:CreatingYourOwnConverterForString.asciidoc[converters]*,
both
link:ChangingTheDefaultConvertersForAnApplication.asciidoc[automatic
via ConverterFactory] and
link:CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource.asciidoc[explicitly set]

* improved *validation* (performed on data model values after
conversion) - see e.g.
link:UsingBeanValidationToValidateInput.asciidoc[bean validation example]

* and more

If you want to keep using the old mechanisms, just note that e.g.
*TextField* now has the type String, and automatic conversions are applied
as well as *validation* performed on values converted to the *data model
type*. You can migrate data entry views form by form.

The ancient *QueryContainer* has been removed, so it is time to switch
to *SQLContainer* or some other container implementation.

If you are using a custom implementation of *Container.Indexed*, there
is one more method to implement - see the javadoc of *getItemIds(int,
int)* for details and a utility making implementing it easy.

*Property.toString()* should not be used to try to get the value of the
property, use *Property.getValue()* instead.

[[add-ons]]
Add-ons
~~~~~~~

If your project relies on add-ons from Vaadin Directory, note that not
all of them have been updated for Vaadin 7, and a few might only be
compatible with older Vaadin 7 beta versions. *Check the add-ons* you
use before committing to migration.

You may need to click "*Available for 7*" on the add-on page to get the
correct add-on version.

You can see a list of add-ons with a version available for Vaadin 7 using https://vaadin.com/directory/search[the search],
although some of them might only be compatible with older alpha and beta
versions of Vaadin 7 at the moment.

Note also that a handful of add-ons you might have used are now obsolete
as e.g. *CustomField* is integrated in Vaadin 7.

[[widgetset]]
Widgetset
~~~~~~~~~

As long as you use the *correct version of* the Eclipse or Maven
*plug-in* to compile your widgetset and remove any old GWT libraries
from your classpath, not much changes for widgetsets.

The current default widgetset is *com.vaadin.DefaultWidgetSet* and
should be inherited by custom widgetsets, although
*com.vaadin.terminal.gwt.DefaultWidgetset* still exists for backwards
compatibility. *DefaultWidgetSet* is also used on portals, replacing
*PortalDefaultWidgetSet*.

If you are compiling your widgetset e.g. with Ant, there are some
changes to the class to execute and its parameters. The class and
parameters to use are now "com.google.gwt.dev.Compiler -workDir (working
directory) -war (output directory) (widgetset module name)" with
optional additional optional parameters before the module name.

If you have optimized your widgetset to limit what components to load
initially, see
link:OptimizingTheWidgetSet.asciidoc[this
tutorial] and the
https://vaadin.com/directory/component/widget-set-optimizer[WidgetSet
Optimizer add-on].

[[themes]]
Themes
~~~~~~

The *HTML5 DOCTYPE* is used by Vaadin 7, which can affect the behavior
of some CSS rules.Vaadin 7 brings a new option to create your themes,
with SCSS syntax of *SASS* supporting *variables, nested blocks and
mix-ins* for easier reuse of definitions etc.

To get your old application running without bigger changes, just import
e.g. "../reindeer/*legacy-styles.css*" instead of
"../reindeer/styles.css" and take the application for a spin. There will
most likely be some changes to be done in your theme, but the main parts
should be there.

The themes also support *mixing components from multiple themes* and
using multiple applications with *different themes on the same page*,
which can be especially useful for portlets. However, these depend on
fully migrating your themes to the SCSS format with a theme name
selector.

To take advantage of the new features, see
link:CreatingAThemeUsingSass.asciidoc[Creating
a theme using sass] and
link:CustomizingComponentThemeWithSass.asciidoc[Customizing
component theme with Sass].

Note that the SCSS theme needs to be *compiled* to CSS before use - in
development mode, this takes place automatically on the fly whenever the
theme is loaded, but when moving to production mode, you need to run the
theme compiler on it to produce a pre-compiled static theme.

link:WidgetStylingUsingOnlyCSS.asciidoc[CSS
can be used to style components] somewhat more freely than in Vaadin 6.

The DOM structure of several layouts has changed, which might require
changes to themes for layouts. See also the section on layouts below.

[[navigation]]
Navigation
~~~~~~~~~~

In addition to low-level support for handling URI fragments Vaadin 7
also provides a higher level *navigation* framework, allowing you to
focus on the content of your views rather than the mechanics of how to
navigate to them.

The best way to get acquainted with the new navigation features is to
check the tutorials on
link:CreatingABookmarkableApplicationWithBackButtonSupport.asciidoc[creating
a bookmarkable application],
link:UsingParametersWithViews.asciidoc[using
parameters with views],
link:AccessControlForViews.asciidoc[access
control for views] and
link:ViewChangeConfirmations.asciidoc[view
change confirmations].

When logging out a user, you can use *Page.setLocation()* to redirect
the user to a suitable page.

[[extending-the-servlet]]
Extending the Servlet
~~~~~~~~~~~~~~~~~~~~~

As ApplicationServlet moved to history and is replaced by
*VaadinServlet*, many customizations you have made to it need a rewrite.

The most common customizations:

* link:CustomizingTheStartupPageInAnApplication.asciidoc[Customizing
the bootstrap page]: JavaScript, headers, ...
* Add-ons using customized servlets for other purposes (e.g. customizing
communication between client and server) probably need more extensive
rework

Note also that *TransactionListener*, *ServletRequestListener* and
*PortletRequestListener* have been removed.

Many things that used to be taken care of by *ApplicationServlet* are now
distributed among *VaadinServletService*, *VaadinSession*, *VaadinService*
etc. You can get a *VaadinSession* with *Component.getSession()* and
*VaadinService* e.g. with *VaadinSession.getService()*.

System messages that used to be configured by "overriding" a static
method *Application.getSystemMessages()* are now set in *VaadinService*
using a *SystemMessagesProvider*.

[[client-side-widgets]]
Client side widgets
~~~~~~~~~~~~~~~~~~~

For add-on authors and creators of custom widgets, the biggest changes
in Vaadin 7 have perhaps taken place on the client side and in
client-server communication.

The first big change is a separation of the client side UI *widgets* and
the code handling communication with the server (*Connector*). The
familiar VLabel is still the client side widget corresponding to the
server side component Label, but the communication part has been split
off into LabelConnector. The annotations linking the client side and the
server side have also changed, now the LabelConnector has an *@Connect*
annotation linking it to the server side component Label.
https://vaadin.com/book/vaadin7/-/page/architecture.client-side.html[the
book] provides some background and the tutorial on
link:CreatingASimpleComponent.asciidoc[creating
a simple component] shows an example.

The connector communicates with the server primarily via shared
state from the server to the client and **RPC
calls **link:SendingEventsFromTheClientToTheServerUsingRPC.asciidoc[from
client to server] and
link:UsingRPCToSendEventsToTheClient.asciidoc[from
server to client], with a larger set of supported data types. For
component containers,
link:CreatingASimpleComponentContainer.asciidoc[the
hierarchy of the contained components is sent separately].

The old mechanism with UIDL, *paintContent()* and *changeVariables()* is
still there for a while to ease migration, but it is recommended to
update your components to the new mechanisms, which also tend to result
in much cleaner code. Using the old mechanisms requires implementing
*LegacyComponent*.

There are also new features such as support for *Extensions* (components
which
link:CreatingAUIExtension.asciidoc[extend
the UI] or
link:CreatingAComponentExtension.asciidoc[other
components] without having a widget in a layout) and
link:UsingAJavaScriptLibraryOrAStyleSheetInAnAddOn.asciidoc[support
for JavaScript], also for
link:IntegratingAJavaScriptComponent.asciidoc[implementing
components] and
link:IntegratingAJavaScriptLibraryAsAnExtension.asciidoc[extensions],
which might simplify the implementation of some components. Shared state
and RPC can also be used from JavaScript, and there are other techniques
for client-server communication.

*Package names* for the client side have changed but a simple import
reorganization by the IDE should be able to take care of that, the new
packages are under *com.vaadin.client.ui*.

If you have implemented a *component that contains other components*
(HasComponents, ComponentContainer) or have client side widgets which do
size calculations etc, see the layouts chapter - these should now be
much simpler to implement than previously, although much of custom
layout widgets will probably need to be rewritten.

A final note about client side development:
*https://vaadin.com/blog/vaadin-and-superdevmode[SuperDevMode]*
has been integrated to Vaadin 7, eliminating the need for browser
plug-ins in many cases when debugging client side code.

[[migration-steps-quick-and-dirty]]
Migration steps (quick and dirty)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* Create a connector class for the add-on
* Extend *LegacyConnector*, override the *getWidget()* method, change its
signature to return *VMyWidget* and implement it as return *(VMyWidget)
super.getWidget();*
* Replace the *@ClientWidget(VMyWidget.class)* annotation (on the
server-side component) with *@Connect(MyServerSideComponent.class)* on the
connector class
* Remove the call to *super.updateFromUIDL(...)* in
*VMyWidget.updateFromUIDL(...)* if no such method exists in the
superclass.
* If the widget has implemented *setHeight* and *setWidth*, make the
connector implement *SimpleManagedLayout* and move the layout logic to the
*layout()* method.
* The actual sizes of the widget is available through
*getLayoutManager().getOuterHeight(getWidget().getElement())* and similar
for the width.
* If the widget implements *ContainerResizedListener*, make the connector
implement *SimpleManagedLayout* and call *getWidget().iLayout()* from the
*layout()* method.
* Be prepared for problems if you are doing layouting in *updateFromUIDL*
as the actual size of a relatively sized widget will most likely change
during the layout phase, i.e. after *updateFromUIDL*

The connector class should look like

[source,java]
....
@Connect(MyComponent.class)
public class MyConnector extends LegacyConnector {
@Override
public VMyWidget getWidget() {
return (VMyWidget) super.getWidget();
}
}
....

* Implement the interface *LegacyComponent* in the server side class
* If your widget has not delegated caption handling to the framework
(i.e. used *ApplicationConnection.updateComponent(..., ..., false)* you
should override *delegateCaptionHandling()* in your connector and return
false. Please note, however, that this is not recommended for most
widgets.

[[basic-widget-add-on-using-vaadin-7-apis]]
Basic widget add-on using Vaadin 7 APIs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Note: migration to new communication mechanisms etc. should be performed
step by step.These instructions continue from where the quick and dirty
migration ended.

* Intermediate step: move *updateFromUIDL(...)* implementation from the
widget to the connector
* Change the visibility of any methods and fields it accesses in the
widget to "package"
* Intermediate step: design an API for the widget that does not access
Vaadin communication mechanisms directly
* Use listeners for events from the widget to the server
* Use setters and action methods for server to client modifications
* Convert state variables and their transmission in
*paintContent()*/*updateFromUIDL()* to use shared state
* Convert one-time actions (events etc.) to use RPC
* Remove "implements LegacyComponent" from the server-side class and the
methods *paintContent()* and *changeVariables()*
* Remove "implements Paintable" or "extends LegacyConnector" and
*updateFromUIDL()* from the client-side connector class (extend
*AbstractComponentConnector* instead of *LegacyConnector*)

[[layouts-and-component-containers]]
Layouts and Component Containers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

While the server side API of various layouts has not changed much, the
implementations on the client side have. With the currently supported
browsers, much more can now be calculated by the browser, so Vaadin
layouts often do not need to measure and calculate sizes.

Most of the differences are only relevant to those who develop client
side component containers, but a few can also affect other developers.

Among the changes affecting others than layout developers, *CssLayout*
now consists of a single DIV instead of three nested elements, and
link:WidgetStylingUsingOnlyCSS.asciidoc[CSS
can be used to do more customization] than in previous Vaadin versions.
Also other layouts have changed in terms of their *DOM structure* on the
client, which might require changes to themes. The interface
*MarginHandler* is now only implemented by layouts that actually support
it, not in *AbstractLayout*, and *margins* should be set in CSS for
*CssLayout*.

When implementing components that are not full-blown layouts (with
*addComponent()*, *removeComponent()* etc.) but should contain other
components, the simpler interface *HasComponents* should be used instead
of *ComponentContainer*.

For those implementing new component containers or layouts, see the
related tutorials
link:CreatingASimpleComponentContainer.asciidoc[Creating
a simple component container] and
link:WidgetStylingUsingOnlyCSS.asciidoc[Widget
styling using only CSS].

[[migration-steps-for-componentcontainers]]
Migration steps for ComponentContainers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

These continue from where the add-on migration steps above left off

* Component containers (e.g. layouts) require more changes as the
underlying layout mechanisms and updates have changed
* Client-side child connectors are now created by the framework
* Hierarchy change events. Guaranteed to run before child calls
*updateCaption*. Create any child slots here and attach the widget.
* Don't paint children
* Don't call *child.updateFromUidl*
* Update caption management (called before *updateFromUidl*, from state
change event listener)

[[miscellaneous-changes]]
Miscellaneous Changes
~~~~~~~~~~~~~~~~~~~~~

Many overloaded *addListener()* methods have been deprecated. Use
*addClickListener()*, *addValueChangeListener()* etc. instead of them,
reducing ambiguity and the need for explicit casts.

Many *constants* have been replaced with enums, although in most cases
the old names refer to enum values to ease migration.

If using *background threads, locking* has changed: there is no longer
an *Application* class to synchronize to, but *getSession().lock()* etc.
should be used - see the javadoc for details on its correct use, using a
correct try-finally is crucial for building reliable multi-threaded
Vaadin applications.

*ApplicationResource* has been replaced with *ConnectorResource*, taking
different parameters.

*URIHandler* has been replaced with *RequestHandler*. See also the related
class *DownloadStream*.

*JavaScript* can now be executed using *JavaScript.execute()*.

Various methods that were *deprecated* until 6.8 etc. have been removed,
and some classes and methods have been deprecated. In most of those
cases, the deprecation comment or javadoc indicates what to use as a
replacement.

AbstractComponent.*isEnabled()* and *isVisible()* do not take the state
of the parent component into account, but only inquire the state set for
the component itself. A component inside a disabled component still is
disabled, and one inside an invisible component is not rendered on the
browser.

No information is sent to the browser about components marked as
*invisible* - they simply do not exist from the point of view of the
client.

[[components]]
Components
~~~~~~~~~~

*Button* is no longer a Field and does not have a constructor that takes
a method name to call, use anonymous inner class instead. Because of
this, *CheckBox* is no longer a Button and uses a *ValueChangeListener*
instead of a *ClickListener*.

*DateField* no longer supports milliseconds and its default resolution
is day.

*Label* now supports converters.

*RichTextArea* custom formatting methods removed, use a
*PropertyFormatter* or a *Converter* instead of overriding formatting
methods.

[[need-help]]
Need help?
----------

If you need any advice, training or hands on help in migrating your app
to Vaadin 7, please be in touch with sales@vaadin.com. Vaadin team would
be happy to be at your service.

+ 169
- 0
documentation/articles/MigratingFromVaadin7.0ToVaadin7.1.asciidoc View File

@@ -0,0 +1,169 @@
[[migrating-from-vaadin-7.0-to-vaadin-7.1]]
Migrating from Vaadin 7.0 to Vaadin 7.1
---------------------------------------

This guide describes how to migrate from earlier versions to Vaadin 7.1.

[[migrating-from-vaadin-6]]
Migrating from Vaadin 6
~~~~~~~~~~~~~~~~~~~~~~~

When migrating from Vaadin 6, first review
link:MigratingFromVaadin6ToVaadin7.asciidoc[Migrating
from Vaadin 6 to Vaadin 7], then continue with the rest of this guide.

[[migrating-from-vaadin-7.0]]
Migrating from Vaadin 7.0
~~~~~~~~~~~~~~~~~~~~~~~~~

As always with minor releases, we have tried hard to minimize the number
and extent of changes that could affect existing applications you want
to upgrade. However, there are a few points that must be considered, and
some other changes and improvements that might be beneficial to know.

[[property-legacypropertytostring]]
Property legacyPropertyToString
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The old convention where `Property` `toString()` was used to get the value
of the `Property` continues to cause problems. Changing this behaviour
could potentially cause severe bugs that are hard to find, so instead we
continue our quest to phase out this behaviour.

The behaviour can now be configured via the `legacyPropertyToString`
(either as an init-parameter or using `@VaadinServletConfiguration`). The
settings are:

* “warning” = as 7.0, `toString()` logs warning, default when using
web.xml
* “disabled” = `toString()` is just `toString()`, does not log, default when
using `@VaadinServletConfiguration`
* “enabled” = legacy `toString()` behaviour, does not log, compatible with
Vaadin 6

By default, if you are not using `@VaadinServletConfiguration` to
configure your servlet, the functionality is the same as in 7.0, and
compatible with 6; a warning is logged.

If you are using the new `@VaadinServletConfiguration` to configure your
servlet, it is assumed that you’re creating a new project, and using
`getValue()` instead of `toString()`, and no warning of `toString()` usage is
logged.

This change will not break your application, but you should consider the
options.

1. Consider switching `legacyPropertyToString` mode to
1. “enabled” if you are using `toString()` improperly, and do not want
warnings
2. “disabled” if you are absolutely sure you are not using `toString()`
improperly, and do not want warnings

[[converter-targettype]]
Converter targetType
^^^^^^^^^^^^^^^^^^^^

The conversion methods in `Converter` now have an additional `targetType`
parameter, used by the caller to indicate what return type is expected.
This enables `Converter`{empty}s to support multiple types, which can be handy in
some cases.

This change will cause compile errors if you implement or call
`Converter.convertToModel()` and/or `Converter.convertToPresentation()`.

1. Add the `targetType` parameter if needed

[[ui-access-outside-its-requestresponse]]
UI access() outside it’s request/response
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If you have background threads/processes that update the ui (e.g long
running process updating a `ProgressBar`), or if you otherwise update a ui
from outside its request/response (e.g updating one UI from another),
you should use the new `UI.access()` method. This ensures proper locking
is done, and failing to do so might result in hard to debug concurrency
problems.

To debug possible concurrency problems, it is recommended to enable
assertions with the "-ea" parameter to the JVM.

This change will not break your application, but your application might
already be broken; you should ensure that all ui access dome outside the
request handling thread uses this new API.

[[calendar-included]]
Calendar included
^^^^^^^^^^^^^^^^^

The `Calendar` component, which was previously an add-on, is now included
in the core framework. However, the package is new, and there are minor
API changes.

This change will not break your application, but you might want to
switch to the core framework version of the component.

1. Remove the Calendar add-on
2. Update imports to the new package
3. Adjust for API changes

[[progressbar-is-the-new-progressindicator]]
ProgressBar is the new ProgressIndicator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The `ProgressIndicator` component had integrated support for polling - a
feature that was a bit strange, especially now with built-in polling and
push support. `ProgressBar` is a pure visual component that is intended to
replace `ProgressIndicator`. If you have been relying on the polling
capability of `ProgressIndicator`, you should look at `UI.setPollInterval()`
or enable server push.

This change does not break your application, but is deprecated, and
should particularly not be used if push or `UI.setPollInterval()` is used.

1. Replace `ProgressIndicator` with `ProgressBar`
2. If you are using the polling feature use `UI.setPollInterval()` or enable push

[[isattached-replaces-sessionnull]]
isAttached() replaces session!=null
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Previously you had to do an awkward `getSession() != null` to figure out
whether or not the component (or `ClientConnector` to be precise) actually
was attached to the UI hierarchy (attached to a session, to be precise).
There is now a `isAttached()` method that does that. Note that the old way
still works, the new way is just more explicit, clean and findable.

This change will not break your application, but if you want to clean up
your code, you can look for `getSession()` null-checking and replace as
appropriate with `isAttached()`.

[[vconsole-is-now-java.util.logging]]
VConsole is now java.util.logging
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

For client-side logging and debug messages, the proprietary `VConsole` has
been deprecated and replaced with the standard `java.util.logging`
framework, and the messages are (by default) displayed in the completely
renewed debug window.

This change will not break your application, but the old API is
deprecated, and the new one has additional features (e.g log levels). To
update, look for references to `VConsole` and replace with standard
`java.util.logging` calls, e.g
`Logger.getLogger(getClass().getName()).log(“A message”)`.

[[call-init-for-custom-vaadinservice-instances]]
Call init() for custom VaadinService instances
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If overriding `VaadinServlet.createServletService()` or
`VaadinPortlet.createPortletService()`, the new `init` method must be
invoked for the newly-created `VaadinService` instance.

[[new-features]]
New features
~~~~~~~~~~~~

In addition to the changes, there are a number of new features that you
probably want to familiarize yourself with, such as `Push` and the
redesigned `DebugWindow`.

+ 568
- 0
documentation/articles/OfflineModeForTouchKit4MobileApps.asciidoc View File

@@ -0,0 +1,568 @@
[[offline-mode-for-touchkit-4-mobile-apps]]
Offline mode for TouchKit 4 mobile apps
---------------------------------------

[.underline]#*_Note:_* _Vaadin Touchkit has been discontinued. A community-supported version is
available https://github.com/parttio/touchkit[on GitHub]._#

[[background]]
Background
~~~~~~~~~~

Vaadin is primarily a server-side framework. What happens with the
application when the server is not available? Although this is possible
on desktop computers, more often it happens when using a mobile device.
This is why Vaadin TouchKit allows
you to define offline behavior. In this article I will tell you all the
details you need to know about offline mode and how to use it. It is
written based on Vaadin 7.3 and TouchKit 4.0.0.

Touchkit is a Vaadin
addon that helps in developing mobile applications. I assume that you
have some knowledge in Vaadin and how to develop client-side Vaadin
(GWT) code. I will mention the http://demo.vaadin.com/parking/[Parking
demo] here a few times and you can find its sources
https://github.com/vaadin/parking-demo[here]. I suggest that you read
this article before you try to understand the Parking demo source code,
it will help you grasp the concepts demonstrated in the demo.

[[demystifying-offline-mode]]
Demystifying offline mode
~~~~~~~~~~~~~~~~~~~~~~~~~

As said before, Vaadin is a server-side framework and that implies that
when an application is running, there is a lot of communication going on
between the server and the client. Thus server-side views are not
accessible when there is no connection. On the other hand, offline
enabled applications run pure client-side Vaadin (GWT) code without
connecting the server.

There are a couple of approaches you might take to specify offline
behavior on the client-side.

1. Write a fully client-side application for the user to interact with
when the server is offline.
2. Write some views as client-side widgets and, in case the connection
is lost, disable all the components that might need a server connection.

Let’s take a look at the technical details you need to know.

[[client-side-offline-mode-handling---method-1-checking-the-status]]
Client-side offline mode handling - method 1: checking the status
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The simplest way to know if the application is online or offline is to
use this code:

[source,java]
....
OfflineModeEntrypoint.get().getNetworkStatus().isAppOnline()
....

You might use it before sending something to the server or calling an
RPC, for example. However, the network status might change at any time.
Method 2 helps you react to those changes.

[[client-side-offline-mode-handling---method-2-handling-events]]
Client-side offline mode handling - method 2: handling events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In order to use this method you need an `ApplicationConnection` instance.
We are going to use its event bus to handle online/offline events.
Usually you get an `ApplicationConnection` instance from a component
connector. Here is an example:

[source,java]
....
@Connect(MyComponent.class)
public class MyConnector extends AbstractComponentConnector {
@Override
protected void init() {
super.init();

getConnection().addHandler(OnlineEvent.TYPE, new OnlineEvent.OnlineHandler() {
@Override
public void onOnline(final OnlineEvent event) {
// do some stuff
}
});

getConnection().addHandler(OfflineEvent.TYPE, new OfflineEvent.OfflineHandler() {
@Override
public void onOffline(final OfflineEvent event) {
// do some stuff
}
});
}
}
....

Note that this connector will only be created if an instance of
`MyComponent` is created on the server side and attached to the UI. As an
option, it might be a `UI` or `Component` extension connector. Otherwise
your connector will never be instantiated and you will never receive
these events, so you can rely on them only if you want to show some
changes in the view or disable some functionality of a view when
offline. In order to get true offline capabilities, use method 3.

[[client-side-offline-mode-handling---method-3-implementing-offlinemode-interface]]
Client-side offline mode handling - method 3: implementing OfflineMode interface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Implementing client-side OfflineMode interface allows you to specify
true offline-mode behavior: you will receive events also in case the
page is loaded from cache without network connection at all.

Fortunately, there is a default implementation and you don’t need to
worry about the implementation details. `DefaultOfflineMode` provides an
OfflineMode implementation for any TouchKit application. It shows a
loading indicator and a sad face when the network is down. In most cases
all you want to do is replace this sad face with something more useful
(for example Minesweeper or Sudoku), here’s a sample:

[source,java]
....
public class MyOfflineMode extends DefaultOfflineMode {
@Override
protected void buildDefaultContent() {
getPanel().clear();
getPanel().add(createOfflineApplication()); // might be a full blown GWT UI
}
}
....

Then you need to specify the implementation in your widgetset definition
file (*.gwt.xml):

[source,xml]
....
<replace-with class="com.mybestapp.widgetset.client.MyOfflineMode">
<when-type-is class="com.vaadin.addon.touchkit.gwt.client.offlinemode.OfflineMode" />
</replace-with>
....

This is enough for showing an offline UI, it will be shown and hidden
automatically, `DefaultOfflineMode` will take care of this. If you need a
more complex functionality, like doing something when going
offline/online, you might want to override additional methods from
`DefaultOfflineMode` or implement OfflineMode from scratch. I briefly
sketch what you need to know about it.

The OfflineMode interface has three methods:

[source,java]
....
void activate(ActivationReason);
boolean deactivate();
boolean isActive();
....

Pretty clear, but there are some pitfalls.

Counterintuitively, not all `ActivationReason`{empty}(s) actually require
activating the offline application view. On
`ActivationReason.APP_STARTING` you can just show a loading indicator and
on `ActivationReason.ONLINE_APP_NOT_STARTED` you might want to display a
reload button or actually hide the offline view. Take a look at the
`DefaultOfflineMode` implementation and the `TicketViewWidget` in the
Parking demo.

Second thing to note: `deactivate()` will never be called if i`sActive()`
returns `false`. So you must track whether the offline mode is active or
just take a shortcut like this:

[source,java]
....
boolean isActive() {
return true;
}
....

And the last one: regardless of what JavaDoc says, the return value of
the `deactivate()` method is ignored. You might want to check if this
changes in future versions.

Note that this client-side
http://demo.vaadin.com/javadoc/com.vaadin.addon/vaadin-touchkit-agpl/4.0.0/com/vaadin/addon/touchkit/gwt/client/offlinemode/OfflineMode.html[com.vaadin.addon.touchkit.gwt.client.offlinemode.OfflineMode]
interface has nothing to do with server-side extension
http://demo.vaadin.com/javadoc/com.vaadin.addon/vaadin-touchkit-agpl/4.0.0/com/vaadin/addon/touchkit/extensions/OfflineMode.html[com.vaadin.addon.touchkit.extensions.OfflineMode]
class (unfortunate naming).

[[setting-up-the-offline-mode]]
Setting up the offline mode
~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can turn a Vaadin application into an offline-enabled TouchKit
application by using an extension of `TouchKitServlet` as your servlet
class. For example, the following might be your servlet declaration in
your UI class:

[source,java]
....
@WebServlet(value = "/*")
public static class Servlet extends TouchKitServlet /* instead of VaadinServlet */ {}
....

Below are some details that you might need at some point (or have read
about in other places and are wondering what they are). You may skip to
the “Synchronizing data between server and client” section if you just
want a quick start.

You can check network status (method 1) in any TouchKit application
(i.e. any application using `TouchKitServlet`), nothing special is
required.

In order to use the application connection event bus (method 2), offline
mode must be enabled or no events will be sent. As of TouchKit 4, it is
enabled by default whenever you use TouchKit. If for some reason you
want offline mode disabled, annotate your UI class with
`@OfflineModeEnabled(false)`. Although this is not recommended in TouchKit
applications, because no message will be shown if the app goes offline,
not even the standard Vaadin message.

For method 3 (implementing the OfflineMode interface), besides enabling
offline mode, the
http://en.wikipedia.org/wiki/Cache_manifest_in_HTML5[HTML5 cache
manifest] should be enabled. The cache manifest tells the browser to
cache some files, so that they can be used without a network connection.
As with the offline mode, it is enabled by default. If you want it
disabled, annotate your UI class with  `@CacheManifestEnabled(false)`.
That way your application might be fully functional once starting online
and then going offline (if it does not need any additional files when
offline), but will not be able to start when there is no connection.

[[caching-additional-files-for-example-a-custom-theme]]
Caching additional files, for example a custom theme
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If you need some additional files to be cached for offline loading (most
likely your custom theme), you can add this property to your *.gwt.xml
file:

[source,xml]
....
<set-configuration-property
name='touchkit.manifestlinker.additionalCacheRoot'
value='path/relative/to/project/root:path/on/the/server' />
....

Only files having these extensions will be added to the cache manifest:
.html, .js, .css, .png, .jpg, .gif, .ico, .woff);

If this is a directory, it will be scanned recursively and all the files
with these extensions will be added to the manifest.

[[offlinemode-extension]]
OfflineMode extension
^^^^^^^^^^^^^^^^^^^^^

In addition, you can slightly tweak the offline mode through the
OfflineMode UI extension.

You can set offline mode timeout (if there’s no response from the server
during this time, offline mode will be activated), or manually set
application mode to offline/online (useful for development). There’s
also a less useful parameter: enable/disable persistent session cookie
(enabled by default if you use `@PreserveOnRefresh`, which you should do
for offline mode anyways). That’s all there is in this extension. Usage:

[source,java]
....
// somewhere among UI initializaion
OfflineMode offline = new OfflineMode();
offline.extend(this);
offlineModeSettings.setOfflineModeTimeout(5);
....

Note: it is not compulsory to use this extension, but it helps the
client side of the Touchkit add-on to find the application connection.
Without it, it tries to get an application connection for 5 seconds. If
you suspect that your connection is too slow or the server is very slow
to respond, you might add a new `OfflineMode().extend(this);` to your UI
just in case. That should be very rarely needed.

This extension is usually used for synchronizing data between the server
and the client (covered in the next section), but it can be done through
any other extension/component -- there is no special support for it in
OfflineMode extension.

[[synchronizing-data-between-server-and-client]]
Synchronizing data between server and client
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In a sense, the client is always in “offline mode” between requests from
the server point of view. Therefore the regular Vaadin way of
synchronizing data between the client-side widget and the server-side
(https://vaadin.com/book/-/page/gwt.rpc.html[Vaadin RPC mechanism] and
https://vaadin.com/book/-/page/gwt.shared-state.html[shared state]) is
still valid, the difference being that the offline widget is probably
more complex and the amount of data is greater than that of an average
component.

As mentioned, the server is not necessarily aware that the client went
offline for some time, therefore the synchronization should be initiated
from the client side. So using method 2 or 3, the client side gets an
event that the connection is online and it sends an RPC call to the
server. New data might be sent with the notification or asked
separately, e.g. using
http://demo.vaadin.com/javadoc/com.vaadin.addon/vaadin-touchkit-agpl/4.0.0/index.html?com/vaadin/addon/touchkit/extensions/LocalStorage.html[LocalStorage]
(TouchKit provides easy access to
http://www.w3schools.com/html/html5_webstorage.asp[HTML5 LocalStorage]
from the server side). The server might send new data through shared
state.

If we reuse OfflineMode (mentioned in the end of the last section), the
code might look like this:

[source,java]
....
public class MyOfflineModeExtension extends OfflineMode {
public MyOfflineModeExtension() {
registerRpc(serverRpc);
}

private final SyncDataServerRpc serverRpc = new SyncDataServerRpc() {
@Override
public void syncData(final Object newData) {
doSmth(newData); // update data
getState().someProperty = newServerData; // new data from the server to the client
}
};
}

@Connect(MyOfflineModeExtension.class)
public class MyOfflineConnector extends OfflineModeConnector {
private final SyncDataServerRpc rpc = RpcProxy.create(SyncDataServerRpc.class, this);

@Override
protected void init() {
super.init();

getConnection().addHandler(OnlineEvent.TYPE, new OnlineEvent.OnlineHandler() {
@Override
public void onOnline(final OnlineEvent event) {
Object new Data = … // get updated data
rpc.syncData(newData);
}
});
}
}
....

As already said, this does not necessarily have to be done through the
OfflineMode extension, it can be done using any component connector,
there is nothing special about OfflineMode.

Another option, a less wordy and more decoupled one, could be done by
using JavaScript function call.

On the server side:

[source,java]
....
JavaScript.getCurrent().addFunction("myapp.syncData",
(args) -> { /*sync data, e.g. get it from LocalStorage */});
....

On the client side:

[source,java]
....
// in any connector
getConnection().addHandler(OnlineEvent.TYPE, new OnlineEvent.OnlineHandler() {
@Override
public native void onOnline(final OnlineEvent event) /*-{
myapp.syncData();
}-*/;
});
....

Or similar code in client-side OfflineMode implementation:

[source,java]
....
MyOfflineMode extends DefaultOfflineMode {
@Override
public native boolean deactivate() /*-{
myapp.syncData();
}-*/;
}
....

This option is less “the Vaadin way”, but in some cases might be useful.

[[creating-efficient-offline-views]]
Creating efficient offline views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

There are two main concerns with offline-enabled applications:

1. Maximizing code sharing between online and offline mode.
2. Seamlessly switching between offline and online mode.

To share the code for a view that is used both in online and offline,
you will probably need to create the view as a custom widget, including
connector and a server-side component class. If you know how to do this
and understand why it is needed, you can skip to the “Switching between
online and offline” subsection .

As Vaadin is a server-side framework, the views and the logic are
usually implemented using server-side Java code. During application
lifetime, a lot of traffic is sent between the server and the client
even in a single view. Thus server-side implemented views are not usable
when there is no connection between server and client.

For very simple views (e.g. providing a list, no data input) it might be
appropriate to have two separate implementations, one client-side and
one server-side, as it is quick and easy to build these and you avoid
the development and code overhead of using client-side views online,
keeping the server-side advantages for the online version.

For more complex functionality you will need to implement a fully
client-side view for both online and offline operation and then
synchronize the data as described in the previous section. Using it
during a completely offline operation is straightforward: just show the
view on the screen by an OfflineMode interface implementation in an
overlay. For server-side usage you will probably need to create a
https://vaadin.com/book/-/page/gwt.html[server-side component and a
connector].

[[switching-between-online-and-offline]]
Switching between online and offline
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

What we want to achieve is that the user doesn’t feel that the
application went offline or online if he doesn’t need to know that. We
might show an indicator so that the user is aware, but he should be able
to do what he did before the switch happened, if this is possible. Also,
no data should be lost during switching.

[[a-navigatormanager-issue-and-workaround]]
A NavigatorManager issue and workaround
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Before we go to some deeper details, note that there is an annoying
`NavigatorManager` behavior related to offline mode: when you click a
`NagivationButton` while the connection is down (but before offline mode
was activated) and the target view is not in the DOM yet, the server
does not respond the system switches to offline mode and then when
coming back from offline mode, we’re stuck in an empty view.

A workaround for this is to call `NavigatorManagerConnector` to redraw on
an online event, so this might be put in some connector (you might use
deferred binding to put this in `NavigatorManagerConnector` itself):

[source,java]
....
getConnection().addHandler(OnlineEvent.TYPE, new OnlineEvent.OnlineHandler() {
@Override
public void onOnline(final OnlineEvent event) {
final JsArrayObject<ComponentConnector> jsArray =
ConnectorMap.get(getConnection()).getComponentConnectorsAsJsArray();

for (int i = 0; jsArray.size() > i; i++) {
if (jsArray.get(i) instanceof NavigationManagerConnector) {
final NavigationManagerConnector connector =
(NavigationManagerConnector) jsArray.get(i);
connector.forceStateChange();
}
}
}
});
....

[[user-experience-considerations-related-to-switching]]
User experience considerations related to switching
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Here’s an example of what we want to achieve: if the user is filling a
form, which by design can be filled offline or online, and the network
suddenly goes down, he should be able to continue filling the form
without much interference. That means, if we’re using method 3 by
implementing OfflineMode and showing an overlay on the screen (which is
done in the Parking demo), the offline overlay will be hiding the real
online form. At that point the data from the online form is copied to
the offline form and the user barely notices that something happened.
That means there are two instances of the form, online one and offline
one. Another option would be that you have only one instance of the form
and instead of copying the data, you attach the whole form to a
different view (thanks to Tomi Virkku for the tip).

In the Parking demo, the ticket view jumps, because the scroll position
changes and an indicator is added. If the user was in the middle of
something, he is suddenly interrupted, although no data is lost.

If we want to improve user experience, we could implement it in a better
way. In case the network goes offline when the user is filling a form,
we disable all the elements that might fire a request to the server and
let the user continue filling the form. Of course, the form should be
implemented completely client-side, and all the suspicious elements
would be around it, probably navigation/toolbar buttons. Another option
would be to have all the elements client-side and on click they would be
checking if there is a connection, before sending anything to the
server. After the user submits or cancels the form, we can show the
“true” offline view. Alternatively, it will be the only offline view in
the application, depending on the specific case.

For example, if you are using a navigator manager, the trick would be to
keep or find the `VNavigatorManager` and disable its widgets (left and
right widgets, the ones that are used to navigate):

[source,java]
....
getConnection().addHandler(OfflineEvent.TYPE, new OfflineEvent.OfflineHandler() {
@Override
public void onOffline(final OfflineEvent event) {
setWidgetEnabled(getWidget().getNavigationBar().getWidget(0), false);
}
});

void setWidgetEnabled(final Widget widget, final boolean enabled) {
widget.setStyleName(ApplicationConnection.DISABLED_CLASSNAME, !enabled);

if (widget instanceof HasEnabled)
((HasEnabled) widget).setEnabled(enabled);

// this is just because for some reason VNavigatorButton does not implement HasEnabled, although it has such methods...
if (widget instanceof VNavigationButton)
((VNavigationButton) widget).setEnabled(enabled);
}
....

Known issues: `HasEnabled` declaration should be fixed soon, but I should
warn you that for some reason a disabled `NavigationButton` still responds
to mouse click events, although correctly ignoring touch events.

Same works in the other direction as well, so when an offline form is
shown and the connection goes up, you just keep the offline form until
the user submits/cancels, then show the online view again.

This is how you can give the user experience the best experience.

[[phonegap-integration]]
PhoneGap integration
~~~~~~~~~~~~~~~~~~~~

As this is not directly related to the topic I will not explain the
basics here, just a couple of pitfalls that someone familiar with
PhoneGap might encounter.

http://dev.vaadin.com/ticket/13250[An issue with offline mode on
PhoneGap] was reported recently and because of that, a new solution was
found that puts the Vaadin application into an iframe. You can get the
files for PhoneGap from TouchKit maven archetype (_link no longer available_). However, this solution has its
drawbacks and you might want
to disable the iframe. If you do that, you need to copy some files (like
widgetset) to your PhoneGap project. There is still ongoing discussion
of how to improve this. No more details here, this was just to warn you.

Another pitfall is that when you specify the URL in archetype’s
index.html do put the final slash:

[source,java]
....
window.vaadinAppUrl = 'http://youraddress.com/path/'; // <--- slash is compulsory!
....

Without it the application will not load from cache when there’s no
connection.

+ 187
- 0
documentation/articles/ScalaAndVaadinHOWTO.asciidoc View File

@@ -0,0 +1,187 @@
[[scala-and-vaadin-how-to]]
Scala and Vaadin how-to
-----------------------

[[introduction]]
Introduction
~~~~~~~~~~~~

Since Vaadin is a server-side library it works very well with all JVM
languages, including Scala. This article provides instructions on how to
get started with Vaadin using Scala. First, we'll go through setting up
a new project. After that we'll introduce the Scaladin add-on and see
how it enhances Vaadin components by adding features that leverage the
power of Scala.

[[creating-a-new-eclipse-vaadin-project-with-scala]]
Creating a new Eclipse Vaadin project with Scala
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

[[installing-the-required-software-components]]
Installing the required software components
+++++++++++++++++++++++++++++++++++++++++++

* Download and install http://eclipse.org/[Eclipse] Helios or Indigo by
unpacking it to a location of your choice. Please note that only Eclipse
Helios is officially supported by Scala IDE but also Indigo can be used.
* Start Eclipse, and install the http://vaadin.com/eclipse[Vaadin
Eclipse Plug-in] and http://www.scala-ide.org[Scala IDE Eclipse Plug-in]
using the plug-in installation feature of Eclipse (available under
`Help -> Install New Software...`).

You also need a servlet container to run your application. In this
example we use Tomcat, but any standard container (Jetty, JBoss,
Glassfish, Oracle WebLogic, IBM WebSphere etc.) should be fine.

* Download and install http://tomcat.apache.org/[Tomcat] by unpacking it
to a location of your choice.
* Add the server to Eclipse
* Open the Servers view
* Right click in the Servers view and choose `New -> Server`
* Choose the type of your server, in this case `Apache -> Tomcat`
* Choose the server runtime environment in the dialog by selecting the
folder you unpacked Tomcat to.

[[creating-a-new-project]]
Creating a new project
++++++++++++++++++++++

* Create a new Vaadin project in Eclipse:
* Choose `File -> New...`
* Choose `Other...`
* Choose `Vaadin -> Vaadin Project` from the list. You can use the
filter to narrow down the list.
* Choose a name for your project, eg. "ScalaTest"

The New Vaadin Project Wizard allows you to configure different aspects
your project, but the defaults are fine.

At this point you have a ready-to-go Vaadin Java project. To start doing
Scala we need to do a few more things:

* Add the Scala nature to your project: right click your project root,
and choose `Configure -> Add Scala Nature` from the menu.
* Navigate to the `src` folder, and delete the generated Java file under
the default package (eg. `com.example.scalatest`)

Next up, some Scala!

* Add a new Scala class in your project: right click the default
package, and choose `New -> Scala Class`
* Choose a name for the class, eg. "ScalaApp"
* Our new class should extend the `com.vaadin.Application`, so in the
wizard, click the `Browse...` button next to the "Superclass" field, and
choose that from the list.
* Click "Finish" to let Eclipse generate the class.

Now we need to write some code in the method of our new Vaadin
application.

* Open the `ScalaApp.scala`
* Add the following lines in the `init()`
method: `setMainWindow(new Window("Scala Rocks!"))` `getMainWindow.addComponent(new Label("Hello World!"))`

You can let Eclipse add the imports as you go, or just import the Vaadin
components `(import com.vaadin.ui._)` yourself. The resulting file
should look like this:

[source,javascript]
....
import com.vaadin.Application
import com.vaadin.ui._

class ScalaApp extends Application {
def init(): Unit = {
setMainWindow(new Window("Scala Rocks!"))
getMainWindow.addComponent(new Label("Hello World!"))
}
}
....

Next we make sure the servlet container knows which class it should
load.

* Open `WebContent/WEB-INF/web.xml`
* Under the `<web-app><servlet>` branch change the `param-value` of the
`application` init-param to contain to your application class, including
the package name. Eg. "com.example.scalatest.ScalaApp"

[[additional-configuration]]
Additional configuration
++++++++++++++++++++++++

We're almost done. The last thing we need to do is make sure that the
`scala-library.jar` is available at runtime. We do this by adding the
JAR into the classpath of our servlet container.

First, we need the JAR file itself. You already have this in the Scala
IDE installation folder under Eclipse, or you can download the Scala
distribution from http://www.scala-lang.org/downloads.

We have a few options how to make sure the JAR is available at runtime.

* Put the file in the `WEB-INF/lib` folder under your project.
* Put the file directly in the lib folder of your servlet container.
* Add the Scala library to the deployment assembly:
`project properties -> Deployment assembly -> Add... -> Java build path entries`

After you have done this we can fire up our application!

[[running-the-application]]
Running the application
+++++++++++++++++++++++

Running the application is simple

* Right click your project, and choose `Run As -> Run On Server`
* Choose the previously created Tomcat instance as the target. You might
also want to check the "Always use this server when running this
project" checkbox.

Eclipse should then start the server and open the UI in a internal
browser window.

[[creating-a-new-project-using-a-giter8-template]]
Creating a new project using a Giter8 template
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

https://github.com/n8han/giter8[Giter8] is a command-line tool that
generates project skeletons from templates that are published on GitHub.
The Vaadin-Scala template creates the basic structure for a
http://www.scala-sbt.org/[SBT]-project that has Vaadin, Scala
and Scaladin included.

First, install Giter8 following the instructions
https://github.com/n8han/giter8#readme[on their readme]. Then just

....
g8 ripla/vaadin-scala
....

And answer the questions, or press enter for defaults. After that launch
the server (jetty):

....
cd <project dir>
sbt
container:start
....

You can then browse to
__[[http://localhost:8080__|http://localhost:8080_]] for the app. The
created project is a standard SBT-project that uses the normal maven
style layout, so you'll find the application source from_
src/main/scala__.__

To create Eclipse project files, type _eclipse_ in the sbt prompt. After
this, the project can be imported as an Eclipse project.

[[scaladin]]
Scaladin
~~~~~~~~

Scaladin is a library that extends Vaadin and adds Scala-like features
to Vaadin classes. It's just a single add-on (one JAR) and is highly
recommended for any Scala Vaadin development. See the
http://github.com/henrikerola/scaladin/wiki[GitHub wiki] and the
https://vaadin.com/directory/component/scaladin[Directory page] for more information.

+ 106
- 0
documentation/articles/ShowingDataInGrid.asciidoc View File

@@ -0,0 +1,106 @@
[[showing-data-in-grid]]
Showing data in Grid
--------------------

Grid lazy-loads data from a `Container` instance. There are different
container implementations that e.g. fetch data from a database or use a
list of Java objects. Assuming you already have code that initializes a
`Container`, this is all that is needed for showing a Grid with the data
from your container.

[source,java]
....
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Grid;
import com.vaadin.ui.UI;

public class UsingGridWithAContainer extends UI {
@Override
protected void init(VaadinRequest request) {
Grid grid = new Grid();
grid.setContainerDataSource(GridExampleHelper.createContainer());

setContent(grid);
}
}
....

The container in this example contains three properties; name, count and
amount. You can configure the columns in Grid using the property ids to
do things like setting the column caption, removing a column or changing
the order of the visible columns.

[source,java]
....
protected void init(VaadinRequest request) {
Grid grid = new Grid();
grid.setContainerDataSource(GridExampleHelper.createContainer());

grid.getColumn("name").setHeaderCaption("Bean name");
grid.removeColumn("count");
grid.setColumnOrder("name", "amount");

setContent(grid);
}
....

This is really all that is needed to get started with Grid.

For reference, this is how the example container is implemented.

[source,java]
....
public class GridExampleBean {
private String name;
private int count;
private double amount;

public GridExampleBean() {
}

public GridExampleBean(String name, int count, double amount) {
this.name = name;
this.count = count;
this.amount = amount;
}

public String getName() {
return name;
}

public int getCount() {
return count;
}

public double getAmount() {
return amount;
}

public void setName(String name) {
this.name = name;
}

public void setCount(int count) {
this.count = count;
}

public void setAmount(double amount) {
this.amount = amount;
}
}
....

[source,java]
....
import com.vaadin.data.util.BeanItemContainer;

public class GridExampleHelper {
public static BeanItemContainer<GridExampleBean> createContainer() {
BeanItemContainer<GridExampleBean> container = new BeanItemContainer<GridExampleBean>(GridExampleBean.class);
for (int i = 0; i < 1000; i++) {
container.addItem(new GridExampleBean("Bean " + i, i * i, i / 10d));
}
return container;
}
}
....

+ 163
- 0
documentation/articles/ShowingExtraDataForGridRows.asciidoc View File

@@ -0,0 +1,163 @@
[[showing-extra-data-for-grid-rows]]
Showing extra data for Grid rows
--------------------------------

Some data might not be suitable to be shown as part of a regular Grid,
e.g. because it's too large to fit into a Grid cell or because it's
secondary information that should only be shown on demand. This kind of
situation is covered with the row details functionality that shows a
Vaadin Component in an area expanded below a specific row. Using this
functionality is a two step process: first you need to implement a
generator that lazily creates the `Component` for a row if it has been
expanded, and then you need to hook up the events for actually expanding
a row.

This example uses the same data as in the
link:UsingGridWithAContainer.asciidoc[Using Grid with a Container]
example.

[[detailsgenerator]]
DetailsGenerator
^^^^^^^^^^^^^^^^

A details generator is a callback interface that Grid calls to create
the Vaadin `Component` that is used for showing the details for a specific
row. In this example, we create a layout that contains a label, an image
and a button that all use data from the row.

[source,java]
....
grid.setDetailsGenerator(new DetailsGenerator() {
@Override
public Component getDetails(RowReference rowReference) {
// Find the bean to generate details for
final GridExampleBean bean = (GridExampleBean) rowReference.getItemId();

// A basic label with bean data
Label label = new Label("Extra data for " + bean.getName());

// An image with extra details about the bean
Image image = new Image();
image.setWidth("300px");
image.setHeight("150px");
image.setSource(new ExternalResource("http://dummyimage.com/300x150/000/fff&text=" + bean.getCount()));

// A button just for the sake of the example
Button button = new Button("Click me", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
Notification.show("Button clicked for " + bean.getName());
}
});

// Wrap up all the parts into a vertical layout
VerticalLayout layout = new VerticalLayout(label, image, button);
layout.setSpacing(true);
layout.setMargin(true);
return layout;
}
});
....

[[opening-the-details-for-a-row]]
Opening the details for a row
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Since there are multiple different UI patterns for how details should be
opened (e.g. clicking a button in a cell or double clicking anywhere on
the row), Grid does not have any action enabled by default. You can
instead implement your own listener that takes care of showing and
hiding the details for the rows. One easy way of doing this is to add an
item click listener that toggles the status whenever a row is double
clicked.

[source,java]
....
grid.addItemClickListener(new ItemClickListener() {
@Override
public void itemClick(ItemClickEvent event) {
if (event.isDoubleClick()) {
Object itemId = event.getItemId();
grid.setDetailsVisible(itemId, !grid.isDetailsVisible(itemId));
}
}
});
....

[[full-example]]
Full example
^^^^^^^^^^^^

Putting all these pieces together, we end up with this class that uses
the same data as in the link:UsingGridWithAContainer.asciidoc[Using
Grid with a Container] example.

[source,java]
....
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.server.ExternalResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Component;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.DetailsGenerator;
import com.vaadin.ui.Grid.RowReference;
import com.vaadin.ui.Image;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

public class ShowingExtraDataForRows extends UI {
@Override
protected void init(VaadinRequest request) {
final Grid grid = new Grid();
grid.setContainerDataSource(GridExampleHelper.createContainer());

grid.setDetailsGenerator(new DetailsGenerator() {
@Override
public Component getDetails(RowReference rowReference) {
// Find the bean to generate details for
final GridExampleBean bean = (GridExampleBean) rowReference.getItemId();

// A basic label with bean data
Label label = new Label("Extra data for " + bean.getName());

// An image with extra details about the bean
Image image = new Image();
image.setWidth("300px");
image.setHeight("150px");
image.setSource(new ExternalResource("http://dummyimage.com/300x150/000/fff&text=" + bean.getCount()));

// A button just for the sake of the example
Button button = new Button("Click me", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
Notification.show("Button clicked for " + bean.getName());
}
});

// Wrap up all the parts into a vertical layout
VerticalLayout layout = new VerticalLayout(label, image, button);
layout.setSpacing(true);
layout.setMargin(true);
return layout;
}
});

grid.addItemClickListener(new ItemClickListener() {
@Override
public void itemClick(ItemClickEvent event) {
if (event.isDoubleClick()) {
Object itemId = event.getItemId();
grid.setDetailsVisible(itemId, !grid.isDetailsVisible(itemId));
}
}
});

setContent(grid);
}
}
....

+ 99
- 0
documentation/articles/SimplifiedRPCusingJavaScript.asciidoc View File

@@ -0,0 +1,99 @@
[[simplified-rpc-using-javascript]]
Simplified RPC using JavaScript
-------------------------------

This tutorial continues where
link:IntegratingAJavaScriptComponent.asciidoc[Integrating a JavaScript
component] ended. We will now add RPC functionality to the JavaScript
Flot component. RPC can be used in the same way as with ordinary GWT
components as described in link:UsingRPCFromJavaScript.asciidoc[Using
RPC from JavaScript]. This tutorial describes a simplified way that is
based on the same concepts as in
link:ExposingServerSideAPIToJavaScript.asciidoc[Exposing server
side API to JavaScript]. This way of doing RPC is less rigorous and is
intended for simple cases and for developers appreciating the dynamic
nature of JavaScript.

The simplified way is based on single callback functions instead of
interfaces containing multiple methods. We will invoke a server-side
callback when the user clicks a data point in the graph and a
client-side callback for highlighting a data point in the graph. Each
callback takes a data series index and the index of a point in that
series.

In the constructor, we register the callback that will be called from
the client-side when a data point is clicked.

[source,java]
....
public Flot() {
addFunction("onPlotClick", new JavaScriptFunction() {
public void call(JsonArray arguments) throws JSONException {
int seriesIndex = arguments.getInt(0);
int dataIndex = arguments.getInt(1);
Notification.show("Clicked on [" + seriesIndex + ", "
+ dataIndex + "]");
}
});
}
....

Highlighting is implemented by invoking the client-side callback
function by name and passing the appropriate arguments.

[source,java]
....
public void highlight(int seriesIndex, int dataIndex) {
callFunction("highlight", seriesIndex, dataIndex);
}
....

The simplified RPC mechanism is based on JavaScript functions attached
directly to the connector wrapper object. Callbacks registered using the
server-side `registerCallback` method will be made available as a
similarly named function on the connector wrapper and functions in the
connector wrapper object matching the name used in a server-side
`callFunction` will be called. Because of the dynamic nature of
JavaScript, it's the developer's responsibility to avoid naming
conflicts.

We need to make some small adjustments to the connector JavaScript to
make it work with the way Flot processes events. Because a new Flot
object is created each time the onStateChange function is called, we
need to store a reference to the current object that we can use for
applying the highlight. We also need to pass a third parameter to
`$.plot` to make the graph area clickable. We are finally storing a
reference to `this` in the `self` variable because `this` will point to
a different object inside the click event handler. Aside from those
changes, we just call the callback in a click listener and add our own
callback function for highlighting a point.

[source,javascript]
....
window.com_example_Flot = function() {
var element = $(this.getElement());
var self = this;
var flot;

this.onStateChange = function() {
flot = $.plot(element, this.getState().series, {grid: {clickable: true}});
}

element.bind('plotclick', function(event, point, item) {
if (item) {
self.onPlotClick(item.seriesIndex, item.dataIndex);
}
});

this.highlight = function(seriesIndex, dataIndex) {
if (flot) {
flot.highlight(seriesIndex, dataIndex);
}
};
}
....

When the simplified RPC functionality designed for JavaScript
connectors, there's no need to define RPC interfaces for communication.
This fits the JavaScript world nicely and makes your server-side code
more dynamic - for better or for worse.

+ 107
- 0
documentation/articles/UsingGridWithAContainer.asciidoc View File

@@ -0,0 +1,107 @@
[[using-grid-with-a-container]]
Using Grid with a Container
---------------------------

Grid lazy-loads data from a `Container` instance. There are different
container implementations that e.g. fetch data from a database or use a
list of Java objects. Assuming you already have code that initializes a
`Container`, this is all that is needed for showing a Grid with the data
from your container.

[source,java]
....
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Grid;
import com.vaadin.ui.UI;

public class UsingGridWithAContainer extends UI {
@Override
protected void init(VaadinRequest request) {
Grid grid = new Grid();
grid.setContainerDataSource(GridExampleHelper.createContainer());

setContent(grid);
}
}
....

The container in this example contains three properties; name, count and
amount. You can configure the columns in Grid using the property ids to
do things like setting the column caption, removing a column or changing
the order of the visible columns.

[source,java]
....
protected void init(VaadinRequest request) {
Grid grid = new Grid();
grid.setContainerDataSource(GridExampleHelper.createContainer());

grid.getColumn("name").setHeaderCaption("Bean name");
grid.removeColumn("count");
grid.setColumnOrder("name", "amount");

setContent(grid);
}
....

This is really all that is needed to get started with Grid.

For reference, this is how the example container is implemented.

[source,java]
....
public class GridExampleBean {
private String name;
private int count;
private double amount;

public GridExampleBean() {
}

public GridExampleBean(String name, int count, double amount) {
this.name = name;
this.count = count;
this.amount = amount;
}

public String getName() {
return name;
}

public int getCount() {
return count;
}

public double getAmount() {
return amount;
}

public void setName(String name) {
this.name = name;
}

public void setCount(int count) {
this.count = count;
}

public void setAmount(double amount) {
this.amount = amount;
}
}
....

[source,java]
....
import com.vaadin.data.util.BeanItemContainer;

public class GridExampleHelper {
public static BeanItemContainer<GridExampleBean> createContainer() {
BeanItemContainer<GridExampleBean> container = new BeanItemContainer<GridExampleBean>(
GridExampleBean.class);
for (int i = 0; i < 1000; i++) {
container.addItem(new GridExampleBean("Bean " + i, i * i, i / 10d));
}
return container;
}
}
....

+ 91
- 0
documentation/articles/UsingGridWithInlineData.asciidoc View File

@@ -0,0 +1,91 @@
[[using-grid-with-inline-data]]
Using Grid with inline data
---------------------------

Instead of using a Vaadin Container as explained in
link:UsingGridWithAContainer.asciidoc[Using Grid with a Container],
you can also directly add simple inline data to Grid without directly
using a Container.

After creating a Grid instance, the first thing you need to do is to
define the columns that should be shown. You an also define the types of
the data in each column - Grid will expect String data in each column
unless you do this.

[source,java]
....
grid.addColumn("Name").setSortable(true);
grid.addColumn("Score", Integer.class);
....

The columns will be shown in the order they are added. The `addColumn`
method does also return the created `Column` instance, so you can go ahead
and configure the column right away if you want to.

When you have added all columns, you can add data using the
`addRow(Object...)` method.

[source,java]
....
grid.addRow("Alice", 15);
grid.addRow("Bob", -7);
grid.addRow("Carol", 8);
grid.addRow("Dan", 0);
grid.addRow("Eve", 20);
....

The order of the arguments to `addRow` should match the order in which the
columns are shown. It is recommended to only use `addRow` when
initializing Grid, since later on e.g. `setColumnOrder(Object...)` might
have been used to change the order, causing unintended behavior.

Grid will still manage a `Container` instance for you behind the scenes,
so you can still use Grid API that is based on `Property` or `Item` from the
`Container` API. One particularly useful feature is that each added row
will get an `Integer` item id, counting up starting from 1. This means
that you can e.g. select the second row in this way:

[source,java]
....
grid.select(2);
....

[[full-example]]
Full example
^^^^^^^^^^^^

Putting all these pieces together, we end up with this class.

[source,java]
....
import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.ui.grid.HeightMode;
import com.vaadin.ui.Grid;
import com.vaadin.ui.UI;

@Theme("valo")
public class ShowingInlineDataInGrid extends UI {

@Override
protected void init(VaadinRequest request) {
final Grid grid = new Grid();

grid.addColumn("Name").setSortable(true);
grid.addColumn("Score", Integer.class);

grid.addRow("Alice", 15);
grid.addRow("Bob", -7);
grid.addRow("Carol", 8);
grid.addRow("Dan", 0);
grid.addRow("Eve", 20);

grid.select(2);

grid.setHeightByRows(grid.getContainerDataSource().size());
grid.setHeightMode(HeightMode.ROW);

setContent(grid);
}
}
....

+ 433
- 0
documentation/articles/UsingHibernateWithVaadin.asciidoc View File

@@ -0,0 +1,433 @@
[[using-hibernate-with-vaadin]]
Using Hibernate with Vaadin
---------------------------

Using Hibernate in Toolkit application, Basic
http://en.wikipedia.org/wiki/Create,_read,_update_and_delete[CRUD]
actions for persistent POJO

image:img/screenshot.png[Example CRUD application]

Check out related source code with subversion (svn co
http://dev.vaadin.com/svn/incubator/hbncontainer/) or view it with trac
http://dev.vaadin.com/browser/incubator/hbncontainer/. Download the
latest version as a Vaadin add-on from the Vaadin Directory (https://vaadin.com/directory/component/hbncontainer)

_The project in incubator currently has a prototype of using
associations. The article is outdated on that part_.

Hibernate is the de facto standard when it comes to Java and Object
Relational Mapping. Since version 3 onwards one can actually drop the de
facto part as Hibernate 3 implements Java Persistency API with some
optional packages. Hibernate is backed by a strong support from both
commercial players and open source community. It is an important part of
popular JBoss Application Server.

As an open source project with an industry proven maturity, Hibernate
makes a perfect combo with IT Mill Toolkit. Hibernate is in a key role
in many projects built or supported by IT Mill. The way Hibernate is
used varies a lot due different kinds of architectures and requirements.
Largest questions are usually how to work with Hibernate session,
transactions and how to tie entity beans into toolkit components.

In this article and example application I'll show you how to implement
session-per-request pattern for Hibernate session handling and present
some patterns to do
http://en.wikipedia.org/wiki/Create,_read,_update_and_delete[CRUD]
actions of a simple entity bean. As I'm a sport fanatic, instead of
storing cats and other mammals to DB we'll build a simple *WorkoutLog*
application to store the details of our jogging sessions. Download the
source package to see full source code.

Note that this is not trying to be a yet another Hibernate tutorial.
Although we'll stay in rather basic tricks, I expect the reader to have
some experience on ORM and IT Mill Toolkit. The purpose of this tutorial
is to show an example how to do simple Hibernate session handling in
Toolkit application and explain some patterns how to entity objects can
be tied into GUI.

[[preparing-the-project]]
Preparing the project
~~~~~~~~~~~~~~~~~~~~~

If you want want to learn by doing, it is time to put your hands on
dirt. Create a new web application project in your favorite IDE, throw
in latest `toolkit.jar` and all needed Hibernate related libraries.
Prepare your database and configure Hibernate. Combo I chose when
writing this article was Eclipse, WTP and MySQL 5, but any option should
be fine.

If you want to get started really easily, check out the Eclipse project
from svn repository. This is done simply with subclipse plugin or via
command line svn co http://dev.vaadin.com/svn/incubator/hbncontainer/.
The project containtains embedded database( http://hsqldb.org/[HSQLDB]
), all needed required libraries and the source code for the example
project itself. That is an easy way to start experimenting with Toolkit
and Hibernate. You will also need a servlet container, Tomcat is a good
option.

As I hate all xml configuration I created DB mappings with annotations.
Below is the one and only entity class we'll be using in this example.
Create it in and possibly test your Hibernate configuration with a
simple test application.

[source,java]
....
@Entity
public class Workout {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private Date date = new Date();
private String title = " -- new workout -- ";
private float kilometers;

public Workout() {}

public Long getId() {
return id;
}

private void setId(Long id) {
this.id = id;
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public float getKilometers() {
return kilometers;
}

public void setKilometers(float kilometers) {
this.kilometers = kilometers;
}
}
....

Also create a new Tookit application, configure it in web.xml.

[[using-session-per-request-pattern]]
Using session-per-request pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Proper session handling in Hibernate backed applications is often the
most difficult problem. Use cases vary from by architecture and load.
Hibernate is known to be quite strict on session and transaction
handling, so to save yourself from a headache, I'd suggest you to make
it right. There is a lot's of good documentation about different session
handling patterns in hibernate.org.

Using session-per-request pattern is often a safe bet for Toolkit
application. It is maybe the most common pattern among all Servlet based
applications. When doing data manipulation we'll use the same session
during the whole request and in the end of the request make sure that
session and transaction is properly finalized. When implemented
properly, session-per-request pattern guarantees that number of
Hibernate sessions is in control, sessions are properly closed and
sessions are flushed regularly. A good combo of characteristics for a
multi-user web application.

By Toolkits nature, session-per-request pattern is actually kind of
wrong. Toolkit is a general purpose GUI framework and programmer does
not need to think about requests and responses at all. Actually Toolkit
applications and components don't know nothing about requests. It its
the web terminal that does all the web magic. Another option is to use
session-per-application or even session-per-transaction like one would
do with SWING or other destop application. Always evaluate your
requirements, use cases and available computing resources to have the
optimal session handling pattern.

To ensure that we are using only one Hibernate session per http request
is the easy part. We can use Hibernates `getCurrentSession()` to retrieve
thread local session instance. As we always want to actually use the
session I build a helper method that will also begin a database
transaction. In our *WorkoutLog* we will always be using this method to
get session reference.

[source,java]
....
/**
* Used to get current Hibernate session. Also ensures an open Hibernate
* transaction.
*/
public Session getSession() {
Session currentSession = HibernateUtil.getSessionFactory()
.getCurrentSession();
if(!currentSession.getTransaction().isActive()) {
currentSession.beginTransaction();
}
return currentSession;
}
....

Closing is bit more tricky. One way around would be to use a servlet
filter. You can find examples of this from hibernate.org. But we'll keep
toolkits terminal independence in mind and don't pollute our program
with servlet specific code. To properly implement session-per-request
pattern we'll need to familiarize ourselves to a feature in Toolkits
terminal. Ideally toolkit programmer don't need to care about terminal
at all, but now we need to hook some logic into the end of (http)
request that don't exist for the application. For the pattern it is
essential that session finalization is done always and and after all
hibernate related stuff is done. With event based programming model
there is no way we can detect the last database action in the actual
program code.

The feature we need is `TransactionListeners`. `TransactionListeners` are
attached to `ApplicationContext` which corresponds to http session in our
current web terminal. `TransactionListeners` are notified right before
and right after the clients state is synchronized with server. The
transaction end is what we need here. I'll attach the transaction
listener in the applications `init()` like this:

[source,java]
....
getContext().addTransactionListener(new TransactionListener() {
public void transactionEnd(Application application,
Object transactionData) {
// Transaction listener gets fired for all contexts
// (HttpSessions) toolkit applications, checking to be this one.
if (application == WorkoutLog.this) {
closeSession();
}
}

public void transactionStart(Application application, Object transactionData) {
}
});
....

In `closeSession()` the usual Hibernate sessions finalization is done.

[source,java]
....
private void closeSession() {
Session sess = HibernateUtil.getSessionFactory().getCurrentSession();
if(sess.getTransaction().isActive()) {
sess.getTransaction().commit();
}
sess.flush();
sess.close();
}
....

The sequence diagram below shows how Session handling works with this
pattern during one (http) request. It is an imaginary server visit that
fires to event listeners. The first one does some listing and the latter
re-attaches detached pojo. Note that the second database/Hibernate
action uses the same Session object as the first one. Note that function
names are not real ones, but trying to describe the process better.

image:img/sd_s_per_r.gif[Session handling sequence diagram]

Due Toolkit applications do have state, pattern can be defined more
strictly as a session-per-request-with-detached-objects pattern. As the
session closes quite often, our entity objects are most likely detached
by the time we are updating them. So when we have our changes to entity
object done, it is time to re-attach it to current session to persist
changes into database. An example of that is below:

[source,java]
....
run.setDate((Date) date.getValue());
run.setKilometers(Float.parseFloat(kilomiters.getValue().toString()));
run.setTitle((String) title.getValue());
getSession().merge(run);
....

[[attaching-pojos-ui]]
Attaching POJO's UI
~~~~~~~~~~~~~~~~~~~

In this chapter I'll discuss briefly some options to implement basic
CRUD (Create, Read, Update, Delete) actions for our DB backed Workout
objects.

[[listing-objects]]
Listing Objects
^^^^^^^^^^^^^^^

If you are learning by doing, I'd suggest that you manually insert some
rows to your db at this point. Listing an empty database will be quite
boring.

The most natural way to list our simple Workout object is to put them
into Table component. To do this there is an easy way and an the right
way. We'll start with the easy one, but I suggest to use the latter in
real applications. The code below (the "easy" way) is not in the
*WorkoutLog* app at all, but you can try it if you want.

[source,java]
....
// prepare tables container
table.addContainerProperty("date", Date.class, null);
table.addContainerProperty("kilometers", Float.class, null);
table.addContainerProperty("title", String.class, null);

// list all Workouts
List workouts = getSession().createCriteria(Workout.class).list();
for (Iterator iterator = workouts.iterator(); iterator.hasNext();) {
Workout wo = (Workout) iterator.next();
// add item to table and set properties from POJO
Item woItem = table.addItem(wo.getId());
woItem.getItemProperty("date").setValue(wo.getDate());
woItem.getItemProperty("kilometers").setValue(wo.getKilometers());
woItem.getItemProperty("title").setValue(wo.getTitle());
}
....

In the above example we are using Table's default container,
`IndexedContainer`. It is a good general purpose container, but using it
always is not a good option. You have to load the data into it by
yourself and configure properties etc. It also stores everything in
memory. In our example it may start to be a problem if you
do three workouts everyday, live 100 years old and memory chips don't
get cheaper in the future. But in real application we might really have
millions of records in DB. I really wouldn't suggest to load that table
into memory anymore.

As you may guess the way is to build our own container for Workouts.
Building good containers is one of the most difficult tasks in Toolkit
programming. There are number of different sub interfaces one might want
to implement and a whole bunch of methods code. Luckily one can't safely
throw `UnsupportedOperationExeception` for many of those. It is a boring
tasks, but it often pays it back later. When you have your container
ready, it hides lots of DB access from program logic and can be used for
many components (Selects, Trees, Tables etc). With your own customized
container you can also tune it to work as you want (memory-consumption
versus speed etc).

As building a full-featured is not in the scope of this article, it is
time to throw in a nice helper class called `HbnContainer`. It takes a
Hibernate entity class and a strategy to get Hibernate session in its
constructor. It is indexed, ordered, sortable, had a limited supports
adding/removing items and even ought to be fairly well scalable (by
number of rows in DB). It is not part of Toolkit as we don't consider it
ready for framework yet, but we hope to have something similar in the
core Toolkit in later releases. But feel free to use it in you own
projects.

With `HbnContainer` loading table with Workouts simplifies quite a bit.
We need to implement `HbnContainer`.`SessionManager` interface, but it is
rather easy task as we already have getSession named function in our
*WorkoutLog*. Create and add table to your application, load its content
with following code snippet and you should have a Workout listing on
your screen.

[source,java]
....
table.setContainerDataSource(new HbnContainer(Workout.class, this));
....

[[creating-workouts]]
Creating workouts
^^^^^^^^^^^^^^^^^

Now that we have listing we might want to add some rows via our web
interface. To create a new Workout instance and store it in to DB we
have to do the usual Hibernate stuff: instantiate POJO and attach it to
session. But as I hinted earlier, having a good container will help us
to do it even simpler. `HbnContainer` supports adding items with the most
simplest method `addItem()`.

If you look into the implementation, it does all the usual Hibernates
stuff and returns items generated identifier. In addition this it also
notifies appropriate listeners that the content of table has changed. So
by using containers `addItem()` method instead of doing DB persist
ourselves we don't need to worry about UI updates. Table listens to its
container changes and changes gets sent to web browsers.

[[updates-and-deletes]]
Updates and deletes
^^^^^^^^^^^^^^^^^^^

Building an editor for our Workout object is a straight forwarded coding
task. You may organize your code just like you want. `WorkoutEditor`
class is a simple example implementation that shows and editor in
floating window. It has fields for workouts properties and it can be
loaded with Workout instance or with an identifier. In `WorkoutLog` I
attached a `ValueChangeListener` into table to open editor when user
clicks a row in table. Save and delete buttons in `WorkoutEditor`
delegates work back to methods in main application. Delete uses
containers method and behind the scenes a normal Hibernate object
deletion. When saving we just reattach detached object using `merge()`.

To avoid "monkey-coding" I'll show one can to use toolkits advanced
features to automatically create editable fields for items. The
`WorkoutEditor` class could have created its fields automatically by
using appropriate Item and a Form component. Also Table supports
automatic field generation, so why not edit workouts directly in our
main object listing?

All we need to do is to use `setEditable()` method. In `WorkoutLog` there
is a button that toggles this feature. Clicking it make table editable,
clicking it again shows data only. Can't imagine any simpler way to do
the 'U' part of CRUD.

Both Form and Table components use `FieldFactory` interface to
automatically create fields for Items properties. There is a simple
default factory that you almost certainly want to modify for your needs.
As an example I extended it to set proper resolution for date field and
also did some other fine tuning.

If you investigate the code a bit you might wonder how the database is
updated now as we don't seem to call `merge()` or any other method to
re-attached POJO. When field is updated it knows only about its
underlaying Property. In this case it is `EntityItemProperty` built by
`HbnContainer`. Field calls its `setValue()` method and that is where the
underlaying POJO is re-attached into Hibernate session.

[[adding-custom-columns-to-hbncontainer]]
Adding custom columns to HbnContainer
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This last bonus chapter is bit out of scope of the article. But as
updating is so easy in Table we could ditch our `WorkoutEditor`. But then
arises a question how to implement deletion. An option is to use Tables
selection feature and "Delete selected" button. Another one is to use
context menu option. This is also done in `WorkoutLog`. Both are good
options, but someday someone will be asking how to add delete button on
each row. So lets discuss that right away.

Ideologically this is adding a new property to our items. We definitely
don't want to pollute our entity object by adding `public Button
getDelete()` to our Workout object. The right place to implement this is
in custom Container and Item. I implemented an example of this by
extending `HbnContainer` to `WorkoutListingWithSteroids`. It adds a column
"actions" (or container property if we are talking "Toolkit") which is a
layout containing two buttons.

Another possibly little bit easier method is to use recently introduced
feature in Table component called `ColumnGenerator`. *WorkoutLog* (in svn)
has an example of this method too.

Check out the example code if you want this kind of behavior.

[[summary]]
Summary
~~~~~~~

Popular open source ORM tool Hibernate is a perfect companion for IT
Mill Toolkit. Finding the right way to handle session in your
application is a often the most critical task. Session-per-request
pattern is a safe choice for Toolkit application, but not the only
option. DB backed entity objects are used in a usual manner. To use more
advanced features of toolkit, you'll want to use a custom built
container-item-property set. ORM is never easy, but it is not a rocket
science if you use tested industry proven patterns. And if your
application is going to be a big or old, I can guarantee that you will
have a nice ROI for hours you spend on it (ORM).

+ 413
- 0
documentation/articles/UsingJDBCwithLazyQueryContainerAndFilteringTable.asciidoc View File

@@ -0,0 +1,413 @@
[[using-jdbc-with-lazy-query-container-and-filteringtable]]
Using JDBC with Lazy Query Container and FilteringTable
-------------------------------------------------------

Introduction

Populating display tables from a database is a deceptively complicated
operation, especially when mixing multiple techniques together. This
page provides an example of one way to efficiently load data from a SQL
database table into a filterable UI, using the _Lazy Query Container_ and
_FilteringTable_ add-ons.

Note: Do not use the SQLContainer package. This is buggy and will have
your database and garbage collector crunching in loops.

`Query` and `QueryFactory` implementation

The place to start is the Lazy Query Container's (LQC) Query interface.
This is where the interface with your database happens. This example
access a database table with computer statistics. It's read-only. How to
log and access your JDBC connection differs in each environment; they
are treated generically here. Only select imports are included.

[source,java]
....
import org.vaadin.addons.lazyquerycontainer.Query;
import org.vaadin.addons.lazyquerycontainer.QueryDefinition;
import org.vaadin.addons.lazyquerycontainer.QueryFactory;

import com.vaadin.data.Container.Filter;
import com.vaadin.data.Item;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.data.util.PropertysetItem;
import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper;
import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder;

/**
* Query for using the database's device-status table as a data source
* for a Vaadin container (table).
*/
public class DeviceStatusQuery implements Query {
private static final Logger log = LoggerFactory.getLogger(DeviceStatusQuery.class);

/**
* The table column names. Use these instead of typo-prone magic strings.
*/
public static enum Column {
hostname, loc_id, update_when, net_ip, lan_ip, lan_mac, hardware,
opsys, image, sw_ver, cpu_load, proc_count, mem_usage, disk_usage;

public boolean is(Object other) {
if (other instanceof String)
return this.toString().equals(other);
else
return (this == other);
}
};

public static class Factory implements QueryFactory {
private int locId;

/**
* Constructor
* @param locId - location ID
*/
public Factory(int locId) {
this.locId = locId;
}

@Override
public Query constructQuery(QueryDefinition def) {
return new DeviceStatusQuery(def, locId);
}
}//class Factory

/////// INSTANCE ///////

private String countQuery;
private String fetchQuery;
/** Borrow from SQLContainer to build filter queries */
private StatementHelper stmtHelper = new StatementHelper();

/**
* Constructor
* @param locId - location ID
* @param userId - ID of user viewing the data
*/
private DeviceStatusQuery(QueryDefinition def, int locId) {
Build filters block List<Filter> filters = def.getFilters();
String filterStr = null;
if (filters != null && !filters.isEmpty())
filterStr = QueryBuilder.getJoinedFilterString(filters, "AND", stmtHelper);

// Count query
StringBuilder query = new StringBuilder( "SELECT COUNT(*) FROM device_status");
query.append(" WHERE loc_id=").append(locId);

if (filterStr != null)
query.append(" AND ").append(filterStr);

this.countQuery = query.toString();

// Fetch query
query = new StringBuilder(
"SELECT hostname, loc_id, update_when, net_ip, lan_ip, " +
"lan_mac, hardware, opsys, image, sw_ver, cpu_load, " +
"proc_count, mem_usage, disk_usage FROM device_status");
query.append(" WHERE loc_id=").append(locId);

if (filterStr != null)
query.append(" AND ").append(filterStr);

// Build Order by
Object[] sortIds = def.getSortPropertyIds();
if (sortIds != null && sortIds.length > 0) {
query.append(" ORDER BY ");
boolean[] sortAsc = def.getSortPropertyAscendingStates();
assert sortIds.length == sortAsc.length;

for (int si = 0; si < sortIds.length; ++si) {
if (si > 0) query.append(',');

query.append(sortIds[si]);
if (sortAsc[si]) query.append(" ASC");
else query.append(" DESC");
}
}
else query.append(" ORDER BY hostname");

this.fetchQuery = query.toString();

log.trace("DeviceStatusQuery count: {}", this.countQuery);
log.trace("DeviceStatusQuery fetch: {}", this.fetchQuery);
}//constructor

@Override
public int size() {
int result = 0;
try (Connection conn = Database.getConnection()) {
PreparedStatement stmt = conn.prepareStatement(this.countQuery);
stmtHelper.setParameterValuesToStatement(stmt);
ResultSet rs = stmt.executeQuery();
if (rs.next()) result = rs.getInt(1);

stmt.close();
}
catch (SQLException ex) {
log.error("DB access failure", ex);
}

log.trace("DeviceStatusQuery size=\{}", result);
return result;
}

@Override
public List<Item> loadItems(int startIndex, int count) {
List<Item> items = new ArrayList<Item>();
try (Connection conn = Database.getConnection()) {
String q = this.fetchQuery + " LIMIT " + count + " OFFSET " + startIndex;
PreparedStatement stmt = conn.prepareStatement(q);
stmtHelper.setParameterValuesToStatement(stmt);

ResultSet rs = stmt.executeQuery();
while (rs.next()) {
PropertysetItem item = new PropertysetItem();
// Include the data type parameter on ObjectProperty any time the value could be null
item.addItemProperty(Column.hostname,
new ObjectProperty<String>(rs.getString(1), String.class));
item.addItemProperty(Column.loc_id,
new ObjectProperty<Integer>(rs.getInt(2), Integer.class));
item.addItemProperty(Column.update_when,
new ObjectProperty<Timestamp>(rs.getTimestamp(3), Timestamp.class));
item.addItemProperty(Column.net_ip,
new ObjectProperty<String>(rs.getString(4)));
item.addItemProperty(Column.lan_ip,
new ObjectProperty<String>(rs.getString(5)));
item.addItemProperty(Column.lan_mac,
new ObjectProperty<String>(rs.getString(6)));
item.addItemProperty(Column.hardware,
new ObjectProperty<String>(rs.getString(7)));
item.addItemProperty(Column.opsys,
new ObjectProperty<String>(rs.getString(8)));
item.addItemProperty(Column.image,
new ObjectProperty<String>(rs.getString(9)));
item.addItemProperty(Column.sw_ver,
new ObjectProperty<String>(rs.getString(10)));
item.addItemProperty(Column.cpu_load,
new ObjectProperty<String>(rs.getString(11)));
item.addItemProperty(Column.proc_count,
new ObjectProperty<Integer>(rs.getInt(12)));
item.addItemProperty(Column.mem_usage,
new ObjectProperty<Integer>(rs.getInt(13)));
item.addItemProperty(Column.disk_usage,
new ObjectProperty<Integer>(rs.getInt(14)));

items.add(item);
}
rs.close();
stmt.close();
}
catch (SQLException ex) {
log.error("DB access failure", ex);
}

log.trace("DeviceStatusQuery load {} items from {}={} found", count,
startIndex, items.size());
return items;
} //loadItems()

/**
* Only gets here if loadItems() fails, so return an empty state.
* Throwing from here causes an infinite loop.
*/
@Override
public Item constructItem() {
PropertysetItem item = new PropertysetItem();
item.addItemProperty(Column.hostname, new ObjectProperty<String>(""));
item.addItemProperty(Column.loc_id, new ObjectProperty<Integer>(-1));
item.addItemProperty(Column.update_when,
new ObjectProperty<Timestamp>(new Timestamp(System.currentTimeMillis())));
item.addItemProperty(Column.net_ip, new ObjectProperty<String>(""));
item.addItemProperty(Column.lan_ip, new ObjectProperty<String>(""));
item.addItemProperty(Column.lan_mac, new ObjectProperty<String>(""));
item.addItemProperty(Column.hardware, new ObjectProperty<String>(""));
item.addItemProperty(Column.opsys, new ObjectProperty<String>(""));
item.addItemProperty(Column.image, new ObjectProperty<String>(""));
item.addItemProperty(Column.sw_ver, new ObjectProperty<String>(""));
item.addItemProperty(Column.cpu_load, new ObjectProperty<String>(""));
item.addItemProperty(Column.proc_count, new ObjectProperty<Integer>(0));
item.addItemProperty(Column.mem_usage, new ObjectProperty<Integer>(0));
item.addItemProperty(Column.disk_usage, new ObjectProperty<Integer>(0));

log.warn("Shouldn't be calling DeviceStatusQuery.constructItem()");
return item;
}

@Override
public boolean deleteAllItems() {
throw new UnsupportedOperationException();
}

@Override
public void saveItems(List<Item> arg0, List<Item> arg1, List<Item> arg2) {
throw new UnsupportedOperationException();
}
}
....

Using the Query with FilteringTable

Now that we have our Query, we need to create a table to hold it. Here's
one of many ways to do it with FilteringTable.

[source,java]
....

import org.tepi.filtertable.FilterDecorator;
import org.tepi.filtertable.numberfilter.NumberFilterPopupConfig;
import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;

import com.vaadin.data.Property;
import com.vaadin.server.Resource;
import com.vaadin.shared.ui.datefield.Resolution;
import com.vaadin.ui.DateField;
import com.vaadin.ui.AbstractTextField.TextChangeEventMode;

/**
* Filterable table of device statuses.
*/
public class DeviceStatusTable extends FilterTable {
private final
String[] columnHeaders = {"Device", "Site", "Last Report", "Report IP",
"LAN IP", "MAC Adrs", "Hardware", "O/S", "Image", "Software", "CPU"
"Load", "Processes", "Memory Use", "Disk Use"};

/**
* Configuration this table for displaying of DeviceStatusQuery data.
*/
public void configure(LazyQueryContainer dataSource) {
super.setFilterGenerator(new LQCFilterGenerator(dataSource));
super.setFilterBarVisible(true);
super.setSelectable(true);
super.setImmediate(true);
super.setColumnReorderingAllowed(true);
super.setColumnCollapsingAllowed(true);
super.setSortEnabled(true);

dataSource.addContainerProperty(Column.hostname, String.class, null, true, true);
dataSource.addContainerProperty(Column.loc_id, Integer.class, null, true, false);
dataSource.addContainerProperty(Column.update_when, Timestamp.class, null, true, true);
dataSource.addContainerProperty(Column.net_ip, String.class, null, true, true);
dataSource.addContainerProperty(Column.lan_ip, String.class, null, true, true);
dataSource.addContainerProperty(Column.lan_mac, String.class, null, true, true);
dataSource.addContainerProperty(Column.hardware, String.class, null, true, true);
dataSource.addContainerProperty(Column.opsys, String.class, null, true, true);
dataSource.addContainerProperty(Column.image, String.class, null, true, true);
dataSource.addContainerProperty(Column.sw_ver, String.class, null, true, true);
dataSource.addContainerProperty(Column.cpu_load, String.class, null, true, true);
dataSource.addContainerProperty(Column.proc_count, Integer.class, null, true, true);
dataSource.addContainerProperty(Column.mem_usage, Integer.class, null, true, true);
dataSource.addContainerProperty(Column.disk_usage, Integer.class, null, true, true);

super.setContainerDataSource(dataSource);
super.setColumnHeaders(columnHeaders);
super.setColumnCollapsed(Column.lan_mac, true);
super.setColumnCollapsed(Column.opsys, true);
super.setColumnCollapsed(Column.image, true);
super.setFilterFieldVisible(Column.loc_id, false);
}

@Override
protected String formatPropertyValue(Object rowId, Object colId, Property<?> property) {
if (Column.loc_id.is(colId)) {
// Example of how to translate a column value
return Hierarchy.getLocation(((Integer) property.getValue())).getShortName();
} else if (Column.update_when.is(colId)) {
// Example of how to format a value.
return ((java.sql.Timestamp) property.getValue()).toString().substring(0, 19);
}

return super.formatPropertyValue(rowId, colId, property);
}

/**
* Filter generator that triggers a refresh of a LazyQueryContainer
* whenever the filters change.
*/
public class LQCFilterGenerator implements FilterGenerator {
private final LazyQueryContainer lqc;

public LQCFilterGenerator(LazyQueryContainer lqc) {
this.lqc = lqc;
}

@Override
public Filter generateFilter(Object propertyId, Object value) {
return null;
}

@Override
public Filter generateFilter(Object propertyId, Field<?> originatingField) {
return null;
}

@Override
public AbstractField<?> getCustomFilterComponent(Object propertyId) {
return null;
}

@Override
public void filterRemoved(Object propertyId) {
this.lqc.refresh();
}

@Override
public void filterAdded(Object propertyId, Class<? extends Filter> filterType, Object value) {
this.lqc.refresh();
}

@Override
public Filter filterGeneratorFailed(Exception reason, Object propertyId, Object value) {
return null;
}
}
}
....
Put them together on the UI

Now we have our Container that reads from the database, and a Table for
displaying them, lets put the final pieces together somewhere in some UI
code:

[source,java]
....
final DeviceStatusTable table = new DeviceStatusTable();
table.setSizeFull();

DeviceStatusQuery.Factory factory = new DeviceStatusQuery.Factory(locationID);
final LazyQueryContainer statusDataContainer = new LazyQueryContainer(factory,
/*index*/ null, /*batchSize*/ 50, false);
statusDataContainer.getQueryView().setMaxCacheSize(300);
table.configure(statusDataContainer);

layout.addComponent(table);
layout.setHeight(100f, Unit.PERCENTAGE); // no scrollbar

// Respond to row click
table.addValueChangeListener(new Property.ValueChangeListener() {
@Override
public void valueChange(ValueChangeEvent event) {
Object index = event.getProperty().getValue();
if (index != nulll) {
int locId = (Integer) statusDataContainer.getItem(index)
.getItemProperty(DeviceStatusQuery.Column.loc_id).getValue();
doSomething(locId);
table.setValue(null); //visually deselect
}
}
});
....

And finally, since we're using `SQLContainer`{empty}'s `QueryBuilder`, depending on
your database you may need to include something like this once during
your application startup:

[source,java]
....
import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder;
import com.vaadin.data.util.sqlcontainer.query.generator.filter.StringDecorator;

// Configure Vaadin SQLContainer to work with MySQL
QueryBuilder.setStringDecorator(new StringDecorator("`","`"));
....

+ 272
- 0
documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc View File

@@ -0,0 +1,272 @@
[[using-phonegap-build-with-vaadin-touchkit]]
Using PhoneGap Build with Vaadin TouchKit
-----------------------------------------

[.underline]#*_Note:_* _Vaadin Touchkit has been discontinued. A community-supported version is
available https://github.com/parttio/touchkit[on GitHub]._#

At first, using https://build.phonegap.com/[PhoneGap Build] to point to
your Vaadin TouchKit apps seems like a breeze. Just create a simple
`config.xml` and an `index.html` that redirects to your web site, and you
have an app! Unfortunately, simply doing this is not robust. Mobile
devices lose connectivity, and when they do your app not only stops
working, it may appear to freeze up and have to be killed and restarted
to get working again.

With the release of TouchKit v3.0.2 though, there is a solution! This
article summarizes this solution, which was worked out over months of
trial and error on http://dev.vaadin.com/ticket/13250[Vaadin ticket
13250].

'''''

First, server side you need TouchKit v3.0.2. (The needed enhancements
and fixes should roll into _v4.0_ at some point, but as of _beta1_ it isn't
there.) You also need to ensure that your VAADIN directory resources are
being served up by a servlet extending `TouchKitServlet`. If you have a
main application extending `VaadinServlet`, this needs to be changed to
`TouchKitServlet`.

'''''

When your PhoneGap app runs, it loads your provided `index.html` file into
an embedded WebKit browser. Only this file has access to the PhoneGap
Javascript library, so it handles things like offline-mode detection,
and passes this via messages to the iframe containing your
server-provided application.

[source,html]
....
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="user-scalable=no,initial-scale=1.0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<title>My Application Name</title>
<style type="text/css">
html, body {height:100%;margin:0;}
.spinner {-webkit-animation: spin 6s infinite linear;}
@-webkit-keyframes spin {
0% {-webkit-transform: rotate(0deg);}
100% {-webkit-transform: rotate(360deg);}
}
</style>
</head>
<body style='margin: 0px'>
<script type="text/javascript" src="cordova.js"></script>
<script>
function failedIframe() {
document.getElementById('offline').style.display = 'none';
document.getElementById('spinner').className = '';
document.getElementById('retry').style.display = 'block';
}
function retryIframe() {
document.getElementById('offline').style.display = 'block';
document.getElementById('spinner').className = 'spinner';
document.getElementById('retry').style.display = 'none';
setTimeout(failedIframe, 20000);
document.getElementById('app').src = document.getElementById('app').src;
}
// Use cordova network plugin to inform the iframe about the connection
document.addEventListener('deviceready', function() {
if (!navigator.network || !navigator.network.connection || !Connection) {
console.log(">>> ERROR, it seems cordova network connection plugin has not been loaded.");
return;
}

var iframe = document.getElementById('app');
var loading = document.getElementById('loading');
var offline = document.getElementById('offline');

function sendMessage(msg) {
iframe.contentWindow.postMessage("cordova-" + msg, "*");
}

function check() {
var sts = navigator.network.connection.type == Connection.NONE ? 'offline' : 'online';
sendMessage(sts);
}
function showIframe(ev) {
if (loading.parentNode) {
loading.parentNode.removeChild(loading);
document.getElementById('app').style.width = iframe.style.height = "100%";
sendMessage('resume');
}
navigator.splashscreen.hide();
}
function showOffline() {
document.getElementById('offline').style.display = 'block';
navigator.splashscreen.hide();

// if after a while we have not received any notification we show the retry link
setTimeout(failedIframe, 20000);
}

// Listen for offline/online events
document.addEventListener('offline', check, false);
document.addEventListener('online', check, false);
document.addEventListener('resume', function(){sendMessage('resume')}, false);
document.addEventListener('pause', function(){sendMessage('pause')}, false);
// check the connection periodically
setInterval(check, 30000);

// when vaadin app is loaded, it sends to the parent window a ready message
window.addEventListener('message', showIframe, false);

// If the app takes more than 3 secs to start, proly .manifest stuff is being loaded.
setTimeout(showOffline, 3000);

// Ignore back button in android
// document.addEventListener('backbutton', function() {}, false);
}, false);
</script>
<!-- A div to show in the meanwhile the app is loaded -->
<div id='loading' style='font-size: 120%; font-weight: bold; font-family: helvetica; width: 100%; height: 100%; position: absolute; text-align: center;'>
<div id='spinner' class='spinner'><img src="spinner.png"></div>
<div id='offline' style='display: block; padding: 15px;'>Downloading application files,<br/>Please be patient...</div>
<div id="retry" style="display: none;">
<p>Failed to contact the server.</p>
<p>
Please ensure you have a stable Internet connection, and then
<a href="javascript:void(0)" onclick="retryIframe();">touch here</a> to retry.
</p>
</div>
</div>
<!-- Load the app in an iframe so as we can pass messages, instead of using redirect -->
<iframe id='app' style='width: 0px; height: 0px; position: absolute; border: none' src='http://www.example.com/touch/'></iframe>
</body>
</html>
....

Change the `<title>` and URL in the iframe at the end to match your app.
This also expects a file named `spinner.png` along side `index.html`, which
will be displayed and spin while loading application files from the
server.

This Javascript handles detecting when the app goes offline and back
online (and passes that to TouchKit), provides user feedback during a
long initial load, and provides a friendly retry mechanism if the app is
initially run without network access. It also hides the initial
splashscreen.

'''''

PhoneGap Build requires a config.xml file to tell it how to behave.
Below is a working example that works to create Android 4.0+ and iOS 6 &
7 apps.

[source,xml]
....
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE widget>
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:gap="http://phonegap.com/ns/1.0"
id="com.example.myapp" version="{VERSION}" versionCode="{RELEASE}">
<name>My App Name</name>
<description xml:lang="en"><![CDATA[
Describe your app. This only shows on PhoneGap - each app store has you enter descriptions on their systems.
]]>
</description>
<author href="http://www.example.com">
Example Corp, LLC
</author>
<license>
Copyright 2014, Example Corp, LLC
</license>

<gap:platform name="android"/>
<gap:platform name="ios"/>

<gap:plugin name="com.phonegap.plugin.statusbar" />
<gap:plugin name="org.apache.cordova.network-information" />
<gap:plugin name="org.apache.cordova.splashscreen" />
<feature name="org.apache.cordova.network-information" />

<icon src="res/ios/icon-57.png" gap:platform="ios" width="57" height="57" />
<icon src="res/ios/icon-57_at_2x.png" gap:platform="ios" width="114" height="114" />
<icon src="res/ios/icon-72.png" gap:platform="ios" width="72" height="72" />
<icon src="res/ios/icon-72_at_2x.png" gap:platform="ios" width="144" height="144" />
<icon src="res/ios/icon-76.png" gap:platform="ios" width="76" height="76" />
<icon src="res/ios/icon-76_at_2x.png" gap:platform="ios" width="152" height="152" />
<icon src="res/ios/icon-120.png" gap:platform="ios" width="120" height="120" />

<icon src="res/android/icon-36-ldpi.png" gap:platform="android" width="36" height="36" gap:density="ldpi"/>
<icon src="res/android/icon-48-mdpi.png" gap:platform="android" width="48" height="48" gap:density="mdpi"/>
<icon src="res/android/icon-72-hdpi.png" gap:platform="android" width="72" height="72" gap:density="hdpi"/>
<icon src="res/android/icon-96-xhdpi.png" gap:platform="android" width="96" height="96" gap:density="xhdpi"/>
<icon src="res/android/icon-96-xxhdpi.png" gap:platform="android" width="96" height="96" gap:density="xxhdpi"/>

<gap:splash src="res/ios/Default.png" gap:platform="ios" width="320" height="480" />
<gap:splash src="res/ios/Default@2x.png" gap:platform="ios" width="640" height="960" />
<gap:splash src="res/ios/Default_iphone5.png" gap:platform="ios" width="640" height="1136"/>
<gap:splash src="res/ios/Default-Landscape.png" gap:platform="ios" width="1024" height="768" />
<gap:splash src="res/ios/Default-Portrait.png" gap:platform="ios" width="768" height="1004"/>
<gap:splash src="res/ios/Default-568h.png" gap:platform="ios" width="320" height="568" />
<gap:splash src="res/ios/Default-568@2x.png" gap:platform="ios" width="640" height="1136"/>
<gap:splash src="res/ios/Default-Landscape@2x.png" gap:platform="ios" width="2048" height="1496"/>
<gap:splash src="res/ios/Default-Portrait@2x.png" gap:platform="ios" width="1536" height="2008"/>

<gap:splash src="res/android/splash-ldpi.9.png" gap:platform="android" gap:density="ldpi" />
<gap:splash src="res/android/splash-mdpi.9.png" gap:platform="android" gap:density="mdpi" />
<gap:splash src="res/android/splash-hdpi.9.png" gap:platform="android" gap:density="hdpi" />
<gap:splash src="res/android/splash-xhdpi.9.png" gap:platform="android" gap:density="xhdpi"/>

<!-- PhoneGap version to use -->
<preference name="phonegap-version" value="3.4.0" />

<!-- Allow landscape and portrait orientations -->
<preference name="Orientation" value="default" />

<!-- Don't allow overscroll effects (bounce-back on iOS, glow on Android.
Not useful since app doesn't scroll. -->
<preference name="DisallowOverscroll" value="true"/>

<!-- Don't hide the O/S's status bar -->
<preference name="fullscreen" value="false" />

<!-- iOS: Obey the app's viewport meta tag -->
<preference name="EnableViewportScale" value="true"/>

<!-- iOS: if set to true, app will terminate when home button is pressed -->
<preference name="exit-on-suspend" value="false" />

<!-- iOS: If icon is prerendered, iOS will not apply it's gloss to the app's icon on the user's home screen -->
<preference name="prerendered-icon" value="false" />

<!-- iOS: if set to false, the splash screen must be hidden using a JavaScript API -->
<preference name="AutoHideSplashScreen" value="false" />

<!-- iOS: MinimumOSVersion -->
<preference name="deployment-target" value="6.0" />

<!-- Android: Keep running in the background -->
<preference name="KeepRunning" value="true"/>

<!-- Android: Web resource load timeout, ms -->
<preference name="LoadUrlTimeoutValue" value="30000"/>

<!-- Android: The amount of time the splash screen image displays (if not hidden by app) -->
<preference name="SplashScreenDelay" value="3000"/>

<!-- Android: Minimum (4.0) and target (4.4) API versions -->
<preference name="android-minSdkVersion" value="14"/>
<preference name="android-targetSdkVersion" value="19"/>
</widget>
....

The listed plugins are all required to make the splash screen and
offline-mode work properly. The slew of icons and splash screen .png
file are required by the app stores, so be sure to include all of them
in the source .zip that you upload to PhoneGap Build. Placing these
files in a subdirectory allows you to also put an empty file named
".pgbomit" in that folder, which ensures that *extra* copies of each of
these file are not included in the file app package produced by PhoneGap
Build.

'''''

Special thanks to "manolo" from Vaadin for working with me for over a
month to make all of this work by creating enhancements to TouchKit and
the index.html file that the above one is based on.

+ 437
- 0
documentation/articles/UsingPython.asciidoc View File

@@ -0,0 +1,437 @@
[[developing-vaadin-apps-with-python]]
Developing Vaadin apps with Python
----------------------------------

[[to-accomplish-exactly-what]]
To accomplish exactly what?
^^^^^^^^^^^^^^^^^^^^^^^^^^^

This article describes how to start developing Vaadin apps with Python
programming language. Goal is that programmer could use Python instead
of Java with smallest amount of boilerplate code necessary to get the
environment working.

Luckily Python can make use of Java classes and vice versa. For detailed
tutorial how to accomplish this in general please see
http://www.jython.org/jythonbook/en/1.0/JythonAndJavaIntegration.html
and http://wiki.python.org/jython/UserGuide.

[[requirements]]
Requirements
^^^^^^^^^^^^

For setup used in this article you will need to install PyDev plugin to
your Eclipse and Jython. See http://pydev.org/ and
http://www.jython.org/ for more details.

[[lets-get-started]]
Let's get started
^^^^^^^^^^^^^^^^^

To get started create a new Vaadin project or open existing as you would
normally do. As you have PyDev installed as Eclipse plugin you can start
developing after few steps.

* Add Python nature to your project by right clicking the project and
selecting PyDev -> Set as PyDev Project. After this the project
properties has PyDev specific sections.

* Go to PyDev - Interpreter/Grammar and select Jython as your Python
interpreter.

* Add a source folder where your Python source code will reside. Go to
section PyDev - PYTHONPATH and add source folder. Also add
vaadin-x.x.x.jar to PYTHONPATH in external libraries tab.

* Add jython.jar to your project's classpath and into deployment
artifact.

* Map your python source folder into WEB-INF/classes in deployment
artifact. Go to Deployment Assembly -> Add -> Folder.

image:img/deployartifact.png[Deploy artifact]

[[modify-web.xml-and-applicationservlet]]
Modify web.xml and ApplicationServlet
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

First of all to build a basic Vaadin app you need to define your app in
web.xml. You have something like this in your web.xml:

[source,xml]
....
<servlet>
<servlet-name>Vaadin Application</servlet-name>
<servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
<init-param>
<description>Vaadin application class to start</description>
<param-name>application</param-name>
<param-value>com.vaadin.example.ExampleApplication</param-value>
</init-param>
</servlet>
....

This will have to be modified a bit. Servlet init parameter application
is a Java class name which will be instantiated for each user session.
Default implementation of
`com.vaadin.terminal.gwt.server.ApplicationServlet` can only instantiate
Java classes so therefore you must override that class so that it is
able to instantiate Python objects. Of course if you want the main
Application object to be a Java class there is no need to modify the
web.xml.

Here's the modified section of web.xml. Implementation of PythonServlet
is explained later. Init parameter application is now actually Python
class.

[source,xml]
....
<servlet>
<servlet-name>Python Application</servlet-name>
<servlet-class>com.vaadin.example.pythonapp.PythonServlet</servlet-class>
<init-param>
<description>Vaadin application class to start</description>
<param-name>application</param-name>
<param-value>python.vaadin.pythonapp.PyApplication</param-value>
</init-param>
</servlet>
....

And here's the PythonServlet. This is altered version of original Vaadin
ApplicationServlet.

[source,java]
....
package com.vaadin.example.pythonapp;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import org.python.core.PyObject;
import org.python.util.PythonInterpreter;

import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.AbstractApplicationServlet;

public class PythonServlet extends AbstractApplicationServlet {
// Private fields
private Class<? extends Application> applicationClass;

/**
* Called by the servlet container to indicate to a servlet that the servlet
* is being placed into service.
*
* @param servletConfig
* the object containing the servlet's configuration and
* initialization parameters
* @throws javax.servlet.ServletException
* if an exception has occurred that interferes with the
* servlet's normal operation.
*/
@Override
public void init(javax.servlet.ServletConfig servletConfig)
throws javax.servlet.ServletException {
super.init(servletConfig);

final String applicationModuleName = servletConfig
.getInitParameter("application");
if (applicationModuleName == null) {
throw new ServletException(
"Application not specified in servlet parameters");
}

String[] appModuleSplitted = applicationModuleName.split("\\.");
if(appModuleSplitted.length < 1) {
throw new ServletException("Cannot parse class name");
}

final String applicationClassName = appModuleSplitted[appModuleSplitted.length-1];

try {
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("from "+applicationModuleName+" import "+applicationClassName);
PyObject pyObj = interpreter.get(applicationClassName).__call__();
Application pyApp = (Application)pyObj.__tojava__(Application.class);
applicationClass = pyApp.getClass();
} catch (Exception e) {
e.printStackTrace();
throw new ServletException("Failed to load application class: "
+ applicationModuleName, e);
}
}

@Override
protected Application getNewApplication(HttpServletRequest request)
throws ServletException {

// Creates a new application instance
try {
final Application application = getApplicationClass().newInstance();

return application;
} catch (final IllegalAccessException e) {
throw new ServletException("getNewApplication failed", e);
} catch (final InstantiationException e) {
throw new ServletException("getNewApplication failed", e);
} catch (ClassNotFoundException e) {
throw new ServletException("getNewApplication failed", e);
}
}

@Override
protected Class<? extends Application> getApplicationClass()
throws ClassNotFoundException {
return applicationClass;
}
}
....

The most important part is the following. It uses Jython's
PythonInterpreter to instantiate and convert Python classes into Java
classes. Then Class object is stored for later use of creating new
instances of it on demand.

[source,java]
....
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("from "+applicationModuleName+" import "+applicationClassName);
PyObject pyObj = interpreter.get(applicationClassName).__call__();
Application pyApp = (Application)pyObj.__tojava__(Application.class);
....

Now the Python application for Vaadin is good to go. No more effort is
needed to get it running. So next we see how the application itself can
be written in Python.

[[python-style-application-object]]
Python style Application object
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Creating an Application is pretty straightforward. You would write class
that is identical to the Java counterpart except it's syntax is Python.
Basic hello world application would look like this

[source,python]
....
from com.vaadin import Application
from com.vaadin.ui import Label
from com.vaadin.ui import Window

class PyApplication(Application):
def __init__(self):
pass

def init(self):
mainWindow = Window("Vaadin with Python")
label = Label("Vaadin with Python")
mainWindow.addComponent(label)
self.setMainWindow(mainWindow)
....

[[event-listeners]]
Event listeners
^^^^^^^^^^^^^^^

Python does not have anonymous classes like Java and Vaadin's event
listeners rely heavily on implementing listener interfaces which are
very often done as anonymous classes. So therefore the closest
equivalent of

[source,java]
....
Button button = new Button("java button");
button.addListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
//Do something for the click
}
});
....

is

[source,python]
....
button = Button("python button")
class listener(Button.ClickListener):
def buttonClick(self, event):
#do something for the click
button.addListener(listener())
....

Jython supports for some extend AWT/Swing-style event listeners but
however that mechanism is not compatible with Vaadin. Same problem
applies to just about anything else event listening interface in Java
libraries like Runnable or Callable. To reduce the resulted verbosity
some decorator code can be introduced like here
https://gist.github.com/sunng87/947926.

[[creating-custom-components]]
Creating custom components
^^^^^^^^^^^^^^^^^^^^^^^^^^

Creating custom Vaadin components is pretty much as straightforward as
the creation of Vaadin main application. Override the CustomComponent
class in similar manner as would be done with Java.

[source,python]
....
from com.vaadin.ui import CustomComponent
from com.vaadin.ui import VerticalLayout
from com.vaadin.ui import Label
from com.vaadin.ui import Button
from com.vaadin.terminal import ThemeResource

class PyComponent(CustomComponent, Button.ClickListener):
def __init__(self):
mainLayout = VerticalLayout()
button = Button("click me to toggle the icon")
self.label = Label()
button.addListener(self)
mainLayout.addComponent(self.label)
mainLayout.addComponent(button)
self.super__setCompositionRoot(mainLayout)

def buttonClick(self, event):
if self.label.getIcon() == None:
self.label.setIcon(ThemeResource("../runo/icons/16/lock.png"));
else:
self.label.setIcon(None)
....

[[containers-and-pythonbeans]]
Containers and PythonBeans
^^^^^^^^^^^^^^^^^^^^^^^^^^

Although not Python style of doing things there are some occasions that
require use of beans.

Let's say that you would like to have a table which has it's content
retrieved from a set of beans. Content would be one row with two columns
where cells would contain strings "first" and "second" respectively. You
would write this code to create and fill the table.

[source,python]
....
table = Table()
container = BeanItemContainer(Bean().getClass())
bean = Bean()
bean.setFirst("first")
bean.setSecond("second")
container.addItem(bean)
table.setContainerDataSource(container)
....

and the Bean object would look like this

[source,python]
....
class Bean(JavaBean):
def __init__(self):
self.__first = None
self.__second = None

def getFirst(self):
return self.__first

def getSecond(self):
return self.__second

def setFirst(self, val):
self.__first = val

def setSecond(self, val):
self.__second = val
....

and JavaBean

[source,java]
....
public interface JavaBean {
String getFirst();
void setFirst(String first);
String getSecond();
void setSecond(String second);
}
....

Note that in this example there is Java interface mixed into Python
code. That is because Jython in it's current (2.5.2) version does not
fully implement reflection API for python objects. Result without would
be a table that has no columns.

Implementing a Java interface adds necessary piece of information of
accessor methods so that bean item container can handle it.

[[filtering-container]]
Filtering container
^^^^^^^^^^^^^^^^^^^

Let's add filtering to previous example. Implement custom filter that
allows only bean that 'first' property is set to 'first'

[source,python]
....
container.addContainerFilter(PyFilter())

class PyFilter(Container.Filter):
def appliesToProperty(self, propertyId):
return True

def passesFilter(self, itemId, item):
prop = item.getItemProperty("first")
if prop.getValue() == "first":
return True
else:
return False
....

Again pretty straightforward.

[[debugging]]
Debugging
^^^^^^^^^

Debugging works as you would debug any Jython app remotely in a servlet
engine. See PyDev's manual for remote debugging at
http://pydev.org/manual_adv_remote_debugger.html.

Setting breakpoints directly via Eclipse IDE however does not work.
Application is started as a Java application and the debugger therefore
does not understand Python code.

[[final-thoughts]]
Final thoughts
^^^^^^^^^^^^^^

By using Jython it allows easy access from Python code to Java code
which makes it really straightforward to develop Vaadin apps with
Python.

Some corners are bit rough as they require mixing Java code or are not
possible to implement with Python as easily or efficiently than with
Java.

[[how-this-differs-from-muntjac]]
How this differs from Muntjac?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


https://pypi.python.org/pypi/Muntjac[Muntjac project]
is a python translation of Vaadin and it's goal is pretty much same as
this article's: To enable development of Vaadin apps with Python.

Muntjac's approach was to take Vaadin's Java source code and translate
it to Python while keeping the API intact or at least similar as
possible. While in this article the Vaadin itself is left as is.

Simple Python applications like shown above can be executed with Vaadin
or Muntjac. Application code should be compatible with both with small
package/namespace differences.

Muntjac requires no Jython but it also lacks the possibility to use Java
classes directly.

The problems we encountered above with requiring the use of mixed Java
code are currently present in Muntjac (v1.0.4) as well. For example the
BeanItemContainer is missing from the Muntjac at the moment.

+ 129
- 0
documentation/articles/UsingVaadinInAnExistingGWTProject.asciidoc View File

@@ -0,0 +1,129 @@
[[using-vaadin-in-an-existing-gwt-project]]
Using Vaadin in an existing GWT project
---------------------------------------

[[using-vaadin-jar-with-google-eclipse-plugin-in-a-gwt-project]]
Using Vaadin JAR with Google Eclipse plugin in a GWT project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

With GWT development and run-time classes now included in Vaadin, it is
easy to move from Google's build of GWT to Vaadin.

By switching to the GWT integrated in Vaadin 7, you immediately get
easier integration of SuperDevMode in your application. Many future GWT
bugfixes will be available in Vaadin before they get integrated to the
official version and more and more Vaadin widgets ready to use in your
application. You risk nothing and can easily switch back to stand-alone
GWT if you don't use features from `com.vaadin` packages.

You also have the option to easily move to a hybrid application
development model integrating business logic on the server with custom
components and other parts of your UI implemented using GWT. You can
easily combine the productivity and security benefits of a server side
framework with the flexibility of client side development where needed.

[[using-google-eclipse-plugin]]
Using Google Eclipse Plugin
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Google Plugin for Eclipse assumes the use of GWT SDK. Nevertheless, the
plugin can easily be used to develop client side applications with
Vaadin, by following the steps described below.

For lighter deployment, a minimal run-time version of Vaadin JAR will be
available in the future.

1. You need to have the IvyDE plugin for Eclipse installed
2. Disable some error messages by setting *Preferences... → Google →
Errors/Warnings → Missing SDK → Ignore*. Note that you may still get an
error message about missing `gwt-servlet.jar` when modifying project
build path.
3. If you don't already have a client side application project, you can
create one with "New Web Application Project...", selecting any recent
version of the GWT SDK. If you don't have any version of GWT installed,
download one
https://code.google.com/p/google-web-toolkit/downloads/list[here] - the
next steps will switch to using Vaadin JAR.
4. Open project properties, select *Java Build Path → Libraries* and
remove the GWT SDK from the project class path
5. In the project properties, make sure the project JRE version in
*Project Facets* is 1.6 or later
6. Copy the `ivy.xml` and `ivy-settings.xml` from an existing Vaadin
project created with the Vaadin Plugin for Eclipse
7. Set the Vaadin version in `ivy.xml` to your preferred version
8. Add the following dependency in the `ivy.xml`:
`<dependency org="javax.servlet" name="jsp-api" rev="2.0" />`
9. Right-click the `ivy.xml` and select *Add Ivy library...* and click
*Finish*
10. Right-click project, select *Ivy → Resolve*

That's it - you are now ready to debug the application using GWT
development mode server:

* *Debug as... → Web Application*

To avoid the need to install and update browser plug-ins, use SuperDevMode.

[[using-maven]]
Using Maven
~~~~~~~~~~~

Also the Maven plug-in for GWT makes some assumptions but it is easy to
switch to the combined Vaadin JAR.

As the Vaadin JAR now includes GWT, Maven projects should not depend
directly on GWT JARs (gwt-user, gwt-dev, gwt-servlet).

To convert an existing Maven project, perform the following
modifications in your pom.xml

* update compiler source and target Java version to 1.6
* remove dependencies to GWT (`com.google.gwt:gwt-user`,
`com.google.gwt:gwt-servlet`, `com.google.gwt:gwt-dev`)
* add dependencies to
Vaadin

[source,xml]
....
<!-- this replaces gwt-user.jar -->
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-client</artifactId>
<version>7.0.0.beta9</version>
<scope>provided</scope>
</dependency>
<!-- this replaces gwt-dev.jar -->
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-client-compiler</artifactId>
<version>7.0.0.beta9</version>
<scope>provided</scope>
</dependency>
<!-- optional - this replaces gwt-servlet.jar etc. and is deployed on the server -->
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-server</artifactId>
<version>7.0.0.beta9</version>
</dependency>
....
* if not included e.g. via Jetty/Tomcat/other, add a "provided"
dependency to the servlet
API

[source,xml]
....
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
....
* replace the `gwt-maven-plugin` with `com.vaadin:vaadin-maven-plugin`,
comment out `<dependencies>` in its configuration (if exists) and use
plug-in version that matches the Vaadin version
* use goal `vaadin:compile` instead of `gwt:compile` etc.

The vaadin-client, vaadin-client-compiler and their dependencies only
need to be deployed on the server for debugging with
SuperDevMode.

+ 396
- 0
documentation/articles/VAccessControl.asciidoc View File

@@ -0,0 +1,396 @@
[[v-access-control]]
V - Access control
------------------

In this tutorial we will look into access control.

[[basic-access-control]]
Basic access control
~~~~~~~~~~~~~~~~~~~~

The application we've been building will inevitably need some
administrative tools. Creation and deletion of users, for example, is
generally something that we'd like to do during runtime. Let's create a
simple View for creating a new user:

[source,java]
....
package com.vaadin.cdi.tutorial;

import java.util.concurrent.atomic.AtomicLong;

import javax.inject.Inject;

import com.vaadin.cdi.CDIView;
import com.vaadin.data.Validator;
import com.vaadin.data.fieldgroup.BeanFieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup.CommitEvent;
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.fieldgroup.FieldGroup.CommitHandler;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;

@CDIView
public class CreateUserView extends CustomComponent implements View {

@Inject
UserDAO userDAO;

private static final AtomicLong ID_FACTORY = new AtomicLong(3);

@Override
public void enter(ViewChangeEvent event) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
layout.setSpacing(true);
layout.addComponent(new Label("Create new user"));

final BeanFieldGroup<User> fieldGroup = new BeanFieldGroup<User>(
User.class);
layout.addComponent(fieldGroup.buildAndBind("firstName"));
layout.addComponent(fieldGroup.buildAndBind("lastName"));
layout.addComponent(fieldGroup.buildAndBind("username"));
layout.addComponent(fieldGroup.buildAndBind("password"));
layout.addComponent(fieldGroup.buildAndBind("email"));

fieldGroup.getField("username").addValidator(new Validator() {
@Override
public void validate(Object value) throws InvalidValueException {
String username = (String) value;
if (username.isEmpty()) {
throw new InvalidValueException("Username cannot be empty");
}

if (userDAO.getUserBy(username) != null) {
throw new InvalidValueException("Username is taken");
}
}
});

fieldGroup.setItemDataSource(new User(ID_FACTORY.incrementAndGet(), "",
"", "", "", "", false));

final Label messageLabel = new Label();
layout.addComponent(messageLabel);

fieldGroup.addCommitHandler(new CommitHandler() {
@Override
public void preCommit(CommitEvent commitEvent) throws CommitException {
}

@Override
public void postCommit(CommitEvent commitEvent) throws CommitException {
userDAO.saveUser(fieldGroup.getItemDataSource().getBean());
fieldGroup.setItemDataSource(new User(ID_FACTORY
.incrementAndGet(), "", "", "", "", "", false));
}
});
Button commitButton = new Button("Create");
commitButton.addClickListener(new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
try {
fieldGroup.commit();
messageLabel.setValue("User created");
} catch (CommitException e) {
messageLabel.setValue(e.getMessage());
}
}
});

layout.addComponent(commitButton);
setCompositionRoot(layout);
}
}
....

`CDIViewProvider` checks the Views for a specific annotation,
`javax.annotation.security.RolesAllowed`. You can get access to it by
adding the following dependency to your pom.xml:

[source,xml]
....
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.2-b01</version>
</dependency>
....

[source,java]
....
@CDIView
@RolesAllowed({ "admin" })
public class CreateUserView extends CustomComponent implements View {
....

To add access control to our application we'll need to have a concrete
implementation of the AccessControl abstract class. Vaadin CDI comes
bundled with a simple JAAS implementation, but configuring a JAAS
security domain is outside the scope of this tutorial. Instead we'll opt
for a simpler implementation.

We'll go ahead and alter our UserInfo class to include hold roles.

[source,java]
....
private List<String> roles = new LinkedList<String>();
public void setUser(User user) {
this.user = user;
roles.clear();
if (user != null) {
roles.add("user");
if (user.isAdmin()) {
roles.add("admin");
}
}
}

public List<String> getRoles() {
return roles;
}
....

Let's extend `AccessControl` and use our freshly modified `UserInfo` in it.

[source,java]
....
package com.vaadin.cdi.tutorial;

import javax.enterprise.inject.Alternative;
import javax.inject.Inject;

import com.vaadin.cdi.access.AccessControl;

@Alternative
public class CustomAccessControl extends AccessControl {

@Inject
private UserInfo userInfo;

@Override
public boolean isUserSignedIn() {
return userInfo.getUser() != null;
}

@Override
public boolean isUserInRole(String role) {
if (isUserSignedIn()) {
for (String userRole : userInfo.getRoles()) {
if (role.equals(userRole)) {
return true;
}
}
}
return false;
}

@Override
public String getPrincipalName() {
if (isUserSignedIn()) {
return userInfo.getUser().getUsername();
}
return null;
}
}
....

Note the `@Alternative` annotation. The JAAS implementation is set as the
default, and we can't have multiple default implementations. We'll have
to add our custom implementation to the beans.xml:

[source,xml]
....
<beans>
<alternatives>
<class>com.vaadin.cdi.tutorial.UserGreetingImpl</class>
<class>com.vaadin.cdi.tutorial.CustomAccessControl</class>
</alternatives>
<decorators>
<class>com.vaadin.cdi.tutorial.NavigationLogDecorator</class>
</decorators>
</beans>
....

Now let's add a button to navigate to this view.

ChatView:

[source,java]
....
private Layout buildUserSelectionLayout() {
VerticalLayout layout = new VerticalLayout();
layout.setWidth("100%");
layout.setMargin(true);
layout.setSpacing(true);
layout.addComponent(new Label("Select user to talk to:"));
for (User user : userDAO.getUsers()) {
if (user.equals(userInfo.getUser())) {
continue;
}
layout.addComponent(generateUserSelectionButton(user));
}
layout.addComponent(new Label("Admin:"));
Button createUserButton = new Button("Create user");
createUserButton.addClickListener(new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
navigationEvent.fire(new NavigationEvent("create-user"));
}
});
layout.addComponent(createUserButton);
return layout;
}
....

Everything seems to work fine, the admin is able to use this new feature
to create a new user and the view is inaccessible to non-admins. An
attempt to access the view without the proper authorization will
currently cause an `IllegalArgumentException`. A better approach would be
to create an error view and display that instead.

[source,java]
....
package com.vaadin.cdi.tutorial;

import javax.inject.Inject;

import com.vaadin.cdi.access.AccessControl;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;

public class ErrorView extends CustomComponent implements View {

@Inject
private AccessControl accessControl;

@Inject
private javax.enterprise.event.Event<NavigationEvent> navigationEvent;

@Override
public void enter(ViewChangeEvent event) {
VerticalLayout layout = new VerticalLayout();
layout.setSizeFull();
layout.setMargin(true);
layout.setSpacing(true);

layout.addComponent(new Label(
"Unfortunately, the page you've requested does not exists."));
if (accessControl.isUserSignedIn()) {
layout.addComponent(createChatButton());
} else {
layout.addComponent(createLoginButton());
}
setCompositionRoot(layout);
}

private Button createLoginButton() {
Button button = new Button("To login page");
button.addClickListener(new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
navigationEvent.fire(new NavigationEvent("login"));
}
});
return button;
}

private Button createChatButton() {
Button button = new Button("Back to the main page");
button.addClickListener(new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
navigationEvent.fire(new NavigationEvent("chat"));
}
});
return button;
}
}
....

To use this we'll modify our `NavigationService` to add the error view to
the `Navigator`.

NavigationServiceImpl:

[source,java]
....
@Inject
private ErrorView errorView;

@PostConstruct
public void initialize() {
if (ui.getNavigator() == null) {
Navigator navigator = new Navigator(ui, ui);
navigator.addProvider(viewProvider);
navigator.setErrorView(errorView);
}
}
....

We don't really want the admin-only buttons to be visible to non-admin
users. To programmatically hide them we can inject `AccessControl` to our
view.

ChatView:

[source,java]
....
@Inject
private AccessControl accessControl;

private Layout buildUserSelectionLayout() {
VerticalLayout layout = new VerticalLayout();
layout.setWidth("100%");
layout.setMargin(true);
layout.setSpacing(true);
layout.addComponent(new Label("Select user to talk to:"));
for (User user : userDAO.getUsers()) {
if (user.equals(userInfo.getUser())) {
continue;
}
layout.addComponent(generateUserSelectionButton(user));
}
if(accessControl.isUserInRole("admin")) {
layout.addComponent(new Label("Admin:"));
Button createUserButton = new Button("Create user");
createUserButton.addClickListener(new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
navigationEvent.fire(new NavigationEvent("create-user"));
}
});
layout.addComponent(createUserButton);
}
return layout;
}
....

[[some-further-topics]]
Some further topics
~~~~~~~~~~~~~~~~~~~

In the previous section we pruned the layout programmatically to prevent
non-admins from even seeing the admin buttons. That was one way to do
it. Another would be to create a custom component representing the
layout, then create a producer for that component which would determine
at runtime which version to create.

Sometimes there's a need for a more complex custom access control
implementations. You may need to use something more than Java Strings to
indicate user roles, you may want to alter access rights during runtime.
For those purposes we could extend the `CDIViewProvider` (with either the
`@Specializes` annotation or `@Alternative` with a beans.xml entry) and
override `isUserHavingAccessToView(Bean<?> viewBean)`.

+ 161
- 0
documentation/articles/Vaadin7HierarchicalContainerAndTreeComponentExampleWithLiferayOrganizationService.asciidoc View File

@@ -0,0 +1,161 @@
[[vaadin-7-hierarchical-container-and-treecomponent-example-with-liferay-organizationservice]]
Vaadin 7 hierarchical container and TreeComponent example with Liferay OrganizationService
------------------------------------------------------------------------------------------

I recently needed a portlet to display the Organizations/Locations a
user belongs to in a Hierarchical Tree.  I used Vaadin's tree and
hierarchical container components along with information from Vaadin's
book of examples to create the code below (http://demo.vaadin.com/book-examples-vaadin7/book#component.tree.itemstylegenerator).

See link:img/DmoOrgTreeUI.java[DmoOrgTreeUI.java] for full source code.

[source,java]
....
private void buildMainLayout() throws SystemException, PortalException {
if (viewContent.getComponentCount() > 0) {
viewContent.removeAllComponents();
}

viewContent.setMargin(true);
viewContent.addStyleName("view");

List orgList = new ArrayList();
orgList = OrganizationLocalServiceUtil.getUserOrganizations(user.getUserId());
final HierarchicalContainer container = createTreeContent(orgList);

tree = new Tree("My Organizations", container);
tree.addStyleName("checkboxed");
tree.setSelectable(false);
tree.setItemCaptionMode(ItemCaptionMode.PROPERTY);
tree.setItemCaptionPropertyId("name");
tree.addItemClickListener(new ItemClickEvent.ItemClickListener() {
public void itemClick(ItemClickEvent event) {
if (event.getItemId().getClass() == Long.class) {
long itemId = (Long) event.getItemId();
if (checked.contains(itemId)) {
checkboxChildren(container, itemId, false);
}
else {
checkboxChildren(container, itemId, true);
tree.expandItemsRecursively(itemId);
}
}
tree.markAsDirty();
}
});

Tree.ItemStyleGenerator itemStyleGenerator = new Tree.ItemStyleGenerator() {
@Override
public String getStyle(Tree source, Object itemId) {
if (checked.contains(itemId))
return "checked";
else
return "unchecked";
}
};
tree.setItemStyleGenerator(itemStyleGenerator);

viewContent.addComponent(tree);
viewContent.setVisible(true);
setContent(viewContent);
}

public void checkboxChildren(HierarchicalContainer hc, long itemId, boolean bAdd) {
try {
if (bAdd) {
checked.add(itemId);
}
else {
checked.remove(itemId);
Object iParendId = hc.getParent(itemId);
while (iParendId != null) {
checked.remove(iParendId);
iParendId = hc.getParent(iParendId);
}
}

if (hc.hasChildren(itemId)) {
Collection children = hc.getChildren(itemId);
for (Object o : children) {
if (o.getClass() == Long.class) {
itemId = (Long) o;
checkboxChildren(hc, itemId, bAdd);
}
}
}
}
catch (Exception e) {
Notification.show("Unable to build Organization tree. Contact Administrator.", Type.ERROR_MESSAGE);
}
}

public static HierarchicalContainer createTreeContent(List oTrees)
throws SystemException, PortalException {

HierarchicalContainer container = new HierarchicalContainer();
container.addContainerProperty("name", String.class, "");

new Object() {
@SuppressWarnings("unchecked")
public void put(List data, HierarchicalContainer container)
throws SystemException, PortalException {

for (Organization o : data) {
long orgId = o.getOrganizationId();

if (!container.containsId(orgId)) {
container.addItem(orgId);
container.getItem(orgId).getItemProperty("name").setValue(o.getName());

if (!o.hasSuborganizations()) {
container.setChildrenAllowed(orgId, false);
}
else {
container.setChildrenAllowed(orgId, true);
}

if (o.isRoot()) {
container.setParent(orgId, null);
}
else {
if (!container.containsId(o.getParentOrganizationId())) {
List sub = new ArrayList();
sub.add(o.getParentOrganization());
put(sub, container);
}
container.setParent(orgId, (Object) o.getParentOrganizationId());
}
}
}
}
}.put(oTrees, container);

return container;
}
....

Below is the css used

[source,scss]
....
.v-tree-node-caption-disabled {
color: black;
font-style: italic;
//border-style:solid;
//border-width:1px;
}

.v-tree-checkboxed .v-tree-node-caption-unchecked div span {
background: url("images/unchecked.png") no-repeat;
padding-left: 24px;
//border-style:solid;
//border-width:1px;
}

.v-tree-checkboxed .v-tree-node-caption-checked div span {
background: url("images/checked.png") no-repeat;
padding-left: 24px;
//border-style:solid;
//border-width:1px;
}
....

+ 38
- 0
documentation/articles/contents.asciidoc View File

@@ -0,0 +1,38 @@
= Community articles for Vaadin 7

[discrete]
== Articles
- link:LazyQueryContainer.asciidoc[Lazy query container]
- link:UsingJDBCwithLazyQueryContainerAndFilteringTable.asciidoc[Using JDBC with Lazy Query Container and FilteringTable]
- link:OfflineModeForTouchKit4MobileApps.asciidoc[Offline mode for TouchKit 4 mobile apps]
- link:CreatingYourOwnConverterForString.asciidoc[Creating your own converter for String]
- link:ChangingTheDefaultConvertersForAnApplication.asciidoc[Changing the default converters for an application]
- link:CreatingAnApplicationWithDifferentFeaturesForDifferentClients.asciidoc[Creating an application with different features for different clients]
- link:VAccessControl.asciidoc[V - Access control]
- link:FindingTheCurrentRootAndApplication.asciidoc[Finding the current root and application]
- link:CreatingABasicApplication.asciidoc[Creating a basic application]
- link:JasperReportsOnVaadinSample.asciidoc[Jasper reports on Vaadin sample]
- link:BuildingVaadinApplicationsOnTopOfActiviti.asciidoc[Building Vaadin applications on top of Activiti]
- link:UsingVaadinInAnExistingGWTProject.asciidoc[Using Vaadin in an existing GWT project]
- link:UsingPython.asciidoc[Using Python]
- link:UsingPhoneGapBuildWithVaadinTouchKit.asciidoc[Using PhoneGap Build with Vaadin TouchKit]
- link:ScalaAndVaadinHOWTO.asciidoc[Scala and Vaadin how-to]
- link:UsingHibernateWithVaadin.asciidoc[Using Hibernate with Vaadin]
- link:AddingJPAToTheAddressBookDemo.asciidoc[Adding JPA to the address book demo]
- link:SimplifiedRPCusingJavaScript.asciidoc[Simplified RPC using JavaScript]
- link:JMeterTesting.asciidoc[JMeter testing]
- link:AutoGeneratingAFormBasedOnABeanVaadin6StyleForm.asciidoc[Auto-generating a form based on a bean - Vaadin 6 style Form]
- link:CreatingAReusableVaadinThemeInEclipse.asciidoc[Creating a reusable Vaadin theme in Eclipse]
- link:CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource.asciidoc[Creating a TextField for integer only input when not using a data source]
- link:FormattingDataInGrid.asciidoc[Formatting data in grid]
- link:ConfiguringGridColumnWidths.asciidoc[Configuring Grid column widths]
- link:Vaadin7HierarchicalContainerAndTreeComponentExampleWithLiferayOrganizationService.asciidoc[Vaadin 7 hierarchical container and TreeComponent example with Liferay OrganizationService]
- link:CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc[Creating a CustomField for editing the address of a person]
- link:CreatingAMasterDetailsViewForEditingPersons.asciidoc[Creating a master details view for editing persons]
- link:ShowingExtraDataForGridRows.asciidoc[Showing extra data for Grid rows]
- link:CreatingATextFieldForIntegerOnlyInputUsingADataSource.asciidoc[Creating a TextField for integer only input using a data source]
- link:UsingGridWithAContainer.asciidoc[Using Grid with a Container]
- link:ShowingDataInGrid.asciidoc[Showing data in Grid]
- link:UsingGridWithInlineData.asciidoc[Using Grid with inline data]
- link:MigratingFromVaadin6ToVaadin7.asciidoc[Migrating from Vaadin 6 to Vaadin 7]
- link:MigratingFromVaadin7.0ToVaadin7.1.asciidoc[Migrating from Vaadin 7.0 to Vaadin 7.1]

+ 338
- 0
documentation/articles/img/DmoOrgTreeUI.java View File

@@ -0,0 +1,338 @@

package com.dmo.util.ui;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.servlet.annotation.WebServlet;

import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.model.Organization;
import com.liferay.portal.model.User;
import com.liferay.portal.service.OrganizationLocalServiceUtil;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.portal.theme.ThemeDisplay;
import com.liferay.portal.util.PortalUtil;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.data.util.HierarchicalContainer;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.server.VaadinPortletSession;
import com.vaadin.server.VaadinPortletSession.PortletListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.AbstractSelect.ItemCaptionMode;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.Tree;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

@SuppressWarnings({
"serial", "deprecation"
})
@Theme("dmoprojectview")
public class DmoOrgTreeUI extends UI implements PortletListener {

private PortletMode previousMode = null;
private PortletRequest portletRequest;
private PortletSession portletSession;
private User user;
private ThemeDisplay themeDisplay;
private VerticalLayout viewContent = new VerticalLayout();
private Tree tree = new Tree("Organization Tree");
private HashSet<Long> checked = new HashSet<Long>();

@WebServlet(value = "/*", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = DmoOrgTreeUI.class)
public static class Servlet extends VaadinServlet {
}

@Override
protected void init(VaadinRequest request) {

viewContent = new VerticalLayout();
viewContent.setMargin(true);
setContent(viewContent);

if (VaadinSession.getCurrent() instanceof VaadinPortletSession) {
final VaadinPortletSession portletsession = (VaadinPortletSession) VaadinSession.getCurrent();
portletsession.addPortletListener(this);

try {
setPortletRequestUI((PortletRequest) request);
setPortletSessionUI(portletsession.getPortletSession());
user = UserLocalServiceUtil.getUser(PortalUtil.getUser((PortletRequest) request).getUserId());
setThemeDisplayUI((ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY));
//System.out.println("DEBUG=>" + this.getClass() + "\n ==>themeDisplay getLayout=" + themeDisplay.getLayout().toString());
doView();
}
catch (PortalException e) {
e.printStackTrace();
}
catch (com.liferay.portal.kernel.exception.SystemException e) {
e.printStackTrace();
}
}
else {
Notification.show("Not initialized in a Portal!", Notification.Type.ERROR_MESSAGE);
}

}

@Override
public void handleRenderRequest(RenderRequest request, RenderResponse response, UI root) {

PortletMode portletMode = request.getPortletMode();
try {
setPortletRequestUI((PortletRequest) request);
setPortletSessionUI(request.getPortletSession());

setThemeDisplayUI((ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY));
user = UserLocalServiceUtil.getUser(PortalUtil.getUser((PortletRequest) request).getUserId());
if (request.getPortletMode() == PortletMode.VIEW) {
doView();
}
}
catch (PortalException e) {
Notification.show(e.getMessage(), Type.ERROR_MESSAGE);
}
catch (com.liferay.portal.kernel.exception.SystemException e) {
Notification.show(e.getMessage(), Type.ERROR_MESSAGE);
}

setPreviousModeUI(portletMode);

}

@Override
public void handleActionRequest(ActionRequest request, ActionResponse response, UI root) {

}

@Override
public void handleEventRequest(EventRequest request, EventResponse response, UI root) {

}

@Override
public void handleResourceRequest(ResourceRequest request, ResourceResponse response, UI root) {

this.setThemeDisplayUI((ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY));

setPortletRequestUI((PortletRequest) request);
setPortletSessionUI(request.getPortletSession());
setThemeDisplayUI((ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY));
try {
user = UserLocalServiceUtil.getUser(PortalUtil.getUser((PortletRequest) request).getUserId());
}
catch (PortalException e) {
Notification.show(e.getMessage(), Type.ERROR_MESSAGE);
}
catch (com.liferay.portal.kernel.exception.SystemException e) {
Notification.show(e.getMessage(), Type.ERROR_MESSAGE);
}
}

public void doView() {

try {
buildMainLayout();
}
catch (SystemException e) {
Notification.show("System error occurred. Contact administrator.", Type.WARNING_MESSAGE);
}
catch (PortalException e) {
Notification.show("System error occurred. Contact administrator.", Type.WARNING_MESSAGE);
}
catch (Exception e) {
Notification.show("System error occurred. Contact administrator.", Type.WARNING_MESSAGE);
}
}

private void buildMainLayout()
throws SystemException, PortalException {

if (viewContent.getComponentCount() > 0) {
viewContent.removeAllComponents();
}

viewContent.setMargin(true);
viewContent.addStyleName("view");

List<Organization> orgList = new ArrayList<Organization>();
orgList = OrganizationLocalServiceUtil.getUserOrganizations(user.getUserId());
final HierarchicalContainer container = createTreeContent(orgList);

tree = new Tree("My Organizations", container);
tree.addStyleName("checkboxed");
tree.setSelectable(false);
tree.setItemCaptionMode(ItemCaptionMode.PROPERTY);
tree.setItemCaptionPropertyId("name");
tree.addItemClickListener(new ItemClickEvent.ItemClickListener() {

public void itemClick(ItemClickEvent event) {

if (event.getItemId().getClass() == Long.class) {
long itemId = (Long) event.getItemId();
if (checked.contains(itemId)) {
checkboxChildren(container, itemId, false);
}
else {
checkboxChildren(container, itemId, true);
tree.expandItemsRecursively(itemId);
}
}
tree.markAsDirty();
}
});

Tree.ItemStyleGenerator itemStyleGenerator = new Tree.ItemStyleGenerator() {

@Override
public String getStyle(Tree source, Object itemId) {

if (checked.contains(itemId))
return "checked";
else
return "unchecked";
}
};
tree.setItemStyleGenerator(itemStyleGenerator);

viewContent.addComponent(tree);
viewContent.setVisible(true);
setContent(viewContent);
}

public void checkboxChildren(HierarchicalContainer hc, long itemId, boolean bAdd) {

try {

if (bAdd) {
checked.add(itemId);
}
else {
checked.remove(itemId);
}

if (hc.hasChildren(itemId)) {
Collection<?> children = hc.getChildren(itemId);
for (Object o : children) {
if (o.getClass() == Long.class) {
itemId = (Long) o;
checkboxChildren(hc, itemId, bAdd);
}
}
}
}
catch (Exception e) {
Notification.show("Unable to build Organization tree. Contact Administrator.", Type.ERROR_MESSAGE);
}
}

public static HierarchicalContainer createTreeContent(List<Organization> oTrees)
throws SystemException, PortalException {

HierarchicalContainer container = new HierarchicalContainer();
container.addContainerProperty("name", String.class, "");

new Object() {

@SuppressWarnings("unchecked")
public void put(List<Organization> data, HierarchicalContainer container)
throws SystemException, PortalException {

for (Organization o : data) {
long orgId = o.getOrganizationId();

if (!container.containsId(orgId)) {

container.addItem(orgId);
container.getItem(orgId).getItemProperty("name").setValue(o.getName());

if (!o.hasSuborganizations()) {
container.setChildrenAllowed(orgId, false);
}
else {
container.setChildrenAllowed(orgId, true);
}

if (o.isRoot()) {
container.setParent(orgId, null);
}
else {
if (!container.containsId(o.getParentOrganizationId())) {
List<Organization> sub = new ArrayList<Organization>();
sub.add(o.getParentOrganization());
put(sub, container);
}

container.setParent(orgId, (Object) o.getParentOrganizationId());
}
}
}
}
}.put(oTrees, container);

return container;
}

public PortletRequest getPortletRequestUI() {

return portletRequest;
}

public void setPortletRequestUI(PortletRequest portletRequest) {

this.portletRequest = portletRequest;
}

public PortletSession getPortletSessionUI() {

return portletSession;
}

public void setPortletSessionUI(PortletSession portletSession) {

this.portletSession = portletSession;
}

public ThemeDisplay getThemeDisplayUI() {

return themeDisplay;
}

public void setThemeDisplayUI(ThemeDisplay themeDisplay) {

this.themeDisplay = themeDisplay;
}

public PortletMode getPreviousModeUI() {

return previousMode;
}

public void setPreviousModeUI(PortletMode previousMode) {

this.previousMode = previousMode;
}

}

BIN
documentation/articles/img/JAR Export (1).png View File


BIN
documentation/articles/img/JAR Export (2).png View File


BIN
documentation/articles/img/New Java Project.png View File


BIN
documentation/articles/img/New Vaadin project (1).png View File


BIN
documentation/articles/img/New Vaadin project (2).png View File


BIN
documentation/articles/img/Theme to build path.png View File


BIN
documentation/articles/img/Theme to deployment assembly.png View File


BIN
documentation/articles/img/VAADIN to deployment assembly.png View File


BIN
documentation/articles/img/Vaadin to build path.png View File


BIN
documentation/articles/img/VaadinJasperReportsSample_small.jpg View File


BIN
documentation/articles/img/ab-with-vaadin-scrshot.png View File


BIN
documentation/articles/img/address editor.png View File


BIN
documentation/articles/img/architecture.png View File


BIN
documentation/articles/img/architecture2.png View File


BIN
documentation/articles/img/buttons added.png View File


BIN
documentation/articles/img/complexdomain.png View File


BIN
documentation/articles/img/complexdomain_saving.png View File


BIN
documentation/articles/img/complexdomain_saving2.png View File


BIN
documentation/articles/img/customForms.png View File


BIN
documentation/articles/img/database connected.png View File


BIN
documentation/articles/img/deployartifact.png View File


BIN
documentation/articles/img/jm1B.png View File


BIN
documentation/articles/img/jm2B.png View File


BIN
documentation/articles/img/jm3B.png View File


BIN
documentation/articles/img/jm4.png View File


BIN
documentation/articles/img/jm5.png View File


BIN
documentation/articles/img/master detail wireframe.jpg View File


BIN
documentation/articles/img/person editor.png View File


BIN
documentation/articles/img/process.png View File


BIN
documentation/articles/img/screenshot.png View File


BIN
documentation/articles/img/sd_s_per_r.gif View File


BIN
documentation/articles/img/table and form.png View File


BIN
documentation/articles/img/views.png View File


Loading…
Cancel
Save