summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenri Sara <henri.sara@gmail.com>2017-09-19 09:50:11 +0300
committerGitHub <noreply@github.com>2017-09-19 09:50:11 +0300
commit15a76bbdcaa6cd551e85c9e1e3c681e912885e8a (patch)
tree6027d86bc9bf9afc7e0838eddabd1e4b29fc59dc
parent872d489506c1b1108c4e99134f0473c4b4b987fa (diff)
parent377695d75dee8ddfaef9b994b1c85b50672f2d25 (diff)
downloadvaadin-framework-15a76bbdcaa6cd551e85c9e1e3c681e912885e8a.tar.gz
vaadin-framework-15a76bbdcaa6cd551e85c9e1e3c681e912885e8a.zip
Migrate Vaadin 7 wiki articles to documentation (#9993)
-rw-r--r--documentation/articles/AddingJPAToTheAddressBookDemo.asciidoc790
-rw-r--r--documentation/articles/AutoGeneratingAFormBasedOnABeanVaadin6StyleForm.asciidoc45
-rw-r--r--documentation/articles/BuildingVaadinApplicationsOnTopOfActiviti.asciidoc584
-rw-r--r--documentation/articles/ChangingTheDefaultConvertersForAnApplication.asciidoc76
-rw-r--r--documentation/articles/ConfiguringGridColumnWidths.asciidoc72
-rw-r--r--documentation/articles/CreatingABasicApplication.asciidoc74
-rw-r--r--documentation/articles/CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc266
-rw-r--r--documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc382
-rw-r--r--documentation/articles/CreatingAReusableVaadinThemeInEclipse.asciidoc135
-rw-r--r--documentation/articles/CreatingATextFieldForIntegerOnlyInputUsingADataSource.asciidoc63
-rw-r--r--documentation/articles/CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource.asciidoc44
-rw-r--r--documentation/articles/CreatingAnApplicationWithDifferentFeaturesForDifferentClients.asciidoc71
-rw-r--r--documentation/articles/CreatingYourOwnConverterForString.asciidoc103
-rw-r--r--documentation/articles/FindingTheCurrentRootAndApplication.asciidoc44
-rw-r--r--documentation/articles/FormattingDataInGrid.asciidoc177
-rw-r--r--documentation/articles/JMeterTesting.asciidoc405
-rw-r--r--documentation/articles/JasperReportsOnVaadinSample.asciidoc185
-rw-r--r--documentation/articles/LazyQueryContainer.asciidoc462
-rw-r--r--documentation/articles/MigratingFromVaadin6ToVaadin7.asciidoc648
-rw-r--r--documentation/articles/MigratingFromVaadin7.0ToVaadin7.1.asciidoc169
-rw-r--r--documentation/articles/OfflineModeForTouchKit4MobileApps.asciidoc568
-rw-r--r--documentation/articles/ScalaAndVaadinHOWTO.asciidoc187
-rw-r--r--documentation/articles/ShowingDataInGrid.asciidoc106
-rw-r--r--documentation/articles/ShowingExtraDataForGridRows.asciidoc163
-rw-r--r--documentation/articles/SimplifiedRPCusingJavaScript.asciidoc99
-rw-r--r--documentation/articles/UsingGridWithAContainer.asciidoc107
-rw-r--r--documentation/articles/UsingGridWithInlineData.asciidoc91
-rw-r--r--documentation/articles/UsingHibernateWithVaadin.asciidoc433
-rw-r--r--documentation/articles/UsingJDBCwithLazyQueryContainerAndFilteringTable.asciidoc413
-rw-r--r--documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc272
-rw-r--r--documentation/articles/UsingPython.asciidoc437
-rw-r--r--documentation/articles/UsingVaadinInAnExistingGWTProject.asciidoc129
-rw-r--r--documentation/articles/VAccessControl.asciidoc396
-rw-r--r--documentation/articles/Vaadin7HierarchicalContainerAndTreeComponentExampleWithLiferayOrganizationService.asciidoc161
-rw-r--r--documentation/articles/contents.asciidoc38
-rw-r--r--documentation/articles/img/DmoOrgTreeUI.java338
-rw-r--r--documentation/articles/img/JAR Export (1).pngbin0 -> 71122 bytes
-rw-r--r--documentation/articles/img/JAR Export (2).pngbin0 -> 65400 bytes
-rw-r--r--documentation/articles/img/New Java Project.pngbin0 -> 78004 bytes
-rw-r--r--documentation/articles/img/New Vaadin project (1).pngbin0 -> 66748 bytes
-rw-r--r--documentation/articles/img/New Vaadin project (2).pngbin0 -> 56843 bytes
-rw-r--r--documentation/articles/img/Theme to build path.pngbin0 -> 70898 bytes
-rw-r--r--documentation/articles/img/Theme to deployment assembly.pngbin0 -> 67174 bytes
-rw-r--r--documentation/articles/img/VAADIN to deployment assembly.pngbin0 -> 53809 bytes
-rw-r--r--documentation/articles/img/Vaadin to build path.pngbin0 -> 71578 bytes
-rw-r--r--documentation/articles/img/VaadinJasperReportsSample_small.jpgbin0 -> 89358 bytes
-rw-r--r--documentation/articles/img/ab-with-vaadin-scrshot.pngbin0 -> 103760 bytes
-rw-r--r--documentation/articles/img/address editor.pngbin0 -> 56718 bytes
-rw-r--r--documentation/articles/img/architecture.pngbin0 -> 37636 bytes
-rw-r--r--documentation/articles/img/architecture2.pngbin0 -> 38972 bytes
-rw-r--r--documentation/articles/img/buttons added.pngbin0 -> 87049 bytes
-rw-r--r--documentation/articles/img/complexdomain.pngbin0 -> 64543 bytes
-rw-r--r--documentation/articles/img/complexdomain_saving.pngbin0 -> 10497 bytes
-rw-r--r--documentation/articles/img/complexdomain_saving2.pngbin0 -> 16057 bytes
-rw-r--r--documentation/articles/img/customForms.pngbin0 -> 46028 bytes
-rw-r--r--documentation/articles/img/database connected.pngbin0 -> 196481 bytes
-rw-r--r--documentation/articles/img/deployartifact.pngbin0 -> 71797 bytes
-rw-r--r--documentation/articles/img/jm1B.pngbin0 -> 86524 bytes
-rw-r--r--documentation/articles/img/jm2B.pngbin0 -> 40622 bytes
-rw-r--r--documentation/articles/img/jm3B.pngbin0 -> 13289 bytes
-rw-r--r--documentation/articles/img/jm4.pngbin0 -> 20036 bytes
-rw-r--r--documentation/articles/img/jm5.pngbin0 -> 32394 bytes
-rw-r--r--documentation/articles/img/master detail wireframe.jpgbin0 -> 37394 bytes
-rw-r--r--documentation/articles/img/person editor.pngbin0 -> 60580 bytes
-rw-r--r--documentation/articles/img/process.pngbin0 -> 34581 bytes
-rw-r--r--documentation/articles/img/screenshot.pngbin0 -> 91117 bytes
-rw-r--r--documentation/articles/img/sd_s_per_r.gifbin0 -> 33376 bytes
-rw-r--r--documentation/articles/img/table and form.pngbin0 -> 81518 bytes
-rw-r--r--documentation/articles/img/views.pngbin0 -> 20438 bytes
69 files changed, 8733 insertions, 0 deletions
diff --git a/documentation/articles/AddingJPAToTheAddressBookDemo.asciidoc b/documentation/articles/AddingJPAToTheAddressBookDemo.asciidoc
new file mode 100644
index 0000000000..73a2eb72f7
--- /dev/null
+++ b/documentation/articles/AddingJPAToTheAddressBookDemo.asciidoc
@@ -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.
diff --git a/documentation/articles/AutoGeneratingAFormBasedOnABeanVaadin6StyleForm.asciidoc b/documentation/articles/AutoGeneratingAFormBasedOnABeanVaadin6StyleForm.asciidoc
new file mode 100644
index 0000000000..8c4851bfe7
--- /dev/null
+++ b/documentation/articles/AutoGeneratingAFormBasedOnABeanVaadin6StyleForm.asciidoc
@@ -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));
+ }
+ }
+}
+....
diff --git a/documentation/articles/BuildingVaadinApplicationsOnTopOfActiviti.asciidoc b/documentation/articles/BuildingVaadinApplicationsOnTopOfActiviti.asciidoc
new file mode 100644
index 0000000000..d7c8fdba30
--- /dev/null
+++ b/documentation/articles/BuildingVaadinApplicationsOnTopOfActiviti.asciidoc
@@ -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.
diff --git a/documentation/articles/ChangingTheDefaultConvertersForAnApplication.asciidoc b/documentation/articles/ChangingTheDefaultConvertersForAnApplication.asciidoc
new file mode 100644
index 0000000000..1110a99eaa
--- /dev/null
+++ b/documentation/articles/ChangingTheDefaultConvertersForAnApplication.asciidoc
@@ -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`.
diff --git a/documentation/articles/ConfiguringGridColumnWidths.asciidoc b/documentation/articles/ConfiguringGridColumnWidths.asciidoc
new file mode 100644
index 0000000000..322780c422
--- /dev/null
+++ b/documentation/articles/ConfiguringGridColumnWidths.asciidoc
@@ -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.
diff --git a/documentation/articles/CreatingABasicApplication.asciidoc b/documentation/articles/CreatingABasicApplication.asciidoc
new file mode 100644
index 0000000000..e5dde4995f
--- /dev/null
+++ b/documentation/articles/CreatingABasicApplication.asciidoc
@@ -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.
diff --git a/documentation/articles/CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc b/documentation/articles/CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc
new file mode 100644
index 0000000000..a28b63150f
--- /dev/null
+++ b/documentation/articles/CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc
@@ -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]
diff --git a/documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc b/documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc
new file mode 100644
index 0000000000..7ad2e94967
--- /dev/null
+++ b/documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc
@@ -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`.
diff --git a/documentation/articles/CreatingAReusableVaadinThemeInEclipse.asciidoc b/documentation/articles/CreatingAReusableVaadinThemeInEclipse.asciidoc
new file mode 100644
index 0000000000..f4c8eced65
--- /dev/null
+++ b/documentation/articles/CreatingAReusableVaadinThemeInEclipse.asciidoc
@@ -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]!
diff --git a/documentation/articles/CreatingATextFieldForIntegerOnlyInputUsingADataSource.asciidoc b/documentation/articles/CreatingATextFieldForIntegerOnlyInputUsingADataSource.asciidoc
new file mode 100644
index 0000000000..980049e9e9
--- /dev/null
+++ b/documentation/articles/CreatingATextFieldForIntegerOnlyInputUsingADataSource.asciidoc
@@ -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.
diff --git a/documentation/articles/CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource.asciidoc b/documentation/articles/CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource.asciidoc
new file mode 100644
index 0000000000..62c8390a07
--- /dev/null
+++ b/documentation/articles/CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource.asciidoc
@@ -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()`.
diff --git a/documentation/articles/CreatingAnApplicationWithDifferentFeaturesForDifferentClients.asciidoc b/documentation/articles/CreatingAnApplicationWithDifferentFeaturesForDifferentClients.asciidoc
new file mode 100644
index 0000000000..c8b073868f
--- /dev/null
+++ b/documentation/articles/CreatingAnApplicationWithDifferentFeaturesForDifferentClients.asciidoc
@@ -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.
diff --git a/documentation/articles/CreatingYourOwnConverterForString.asciidoc b/documentation/articles/CreatingYourOwnConverterForString.asciidoc
new file mode 100644
index 0000000000..2c41f5caf5
--- /dev/null
+++ b/documentation/articles/CreatingYourOwnConverterForString.asciidoc
@@ -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());
+ }
+ }
+}));
+....
diff --git a/documentation/articles/FindingTheCurrentRootAndApplication.asciidoc b/documentation/articles/FindingTheCurrentRootAndApplication.asciidoc
new file mode 100644
index 0000000000..05b90308de
--- /dev/null
+++ b/documentation/articles/FindingTheCurrentRootAndApplication.asciidoc
@@ -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).
diff --git a/documentation/articles/FormattingDataInGrid.asciidoc b/documentation/articles/FormattingDataInGrid.asciidoc
new file mode 100644
index 0000000000..0562ee9823
--- /dev/null
+++ b/documentation/articles/FormattingDataInGrid.asciidoc
@@ -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());
+ }
+}
+....
diff --git a/documentation/articles/JMeterTesting.asciidoc b/documentation/articles/JMeterTesting.asciidoc
new file mode 100644
index 0000000000..76e02135ab
--- /dev/null
+++ b/documentation/articles/JMeterTesting.asciidoc
@@ -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);
+ }
+ }
+}
+....
diff --git a/documentation/articles/JasperReportsOnVaadinSample.asciidoc b/documentation/articles/JasperReportsOnVaadinSample.asciidoc
new file mode 100644
index 0000000000..cac8d261f2
--- /dev/null
+++ b/documentation/articles/JasperReportsOnVaadinSample.asciidoc
@@ -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.
diff --git a/documentation/articles/LazyQueryContainer.asciidoc b/documentation/articles/LazyQueryContainer.asciidoc
new file mode 100644
index 0000000000..54e561fa50
--- /dev/null
+++ b/documentation/articles/LazyQueryContainer.asciidoc
@@ -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();
+ }
+}
+....
diff --git a/documentation/articles/MigratingFromVaadin6ToVaadin7.asciidoc b/documentation/articles/MigratingFromVaadin6ToVaadin7.asciidoc
new file mode 100644
index 0000000000..6a10cacbde
--- /dev/null
+++ b/documentation/articles/MigratingFromVaadin6ToVaadin7.asciidoc
@@ -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.
diff --git a/documentation/articles/MigratingFromVaadin7.0ToVaadin7.1.asciidoc b/documentation/articles/MigratingFromVaadin7.0ToVaadin7.1.asciidoc
new file mode 100644
index 0000000000..2f65f0f74f
--- /dev/null
+++ b/documentation/articles/MigratingFromVaadin7.0ToVaadin7.1.asciidoc
@@ -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`.
diff --git a/documentation/articles/OfflineModeForTouchKit4MobileApps.asciidoc b/documentation/articles/OfflineModeForTouchKit4MobileApps.asciidoc
new file mode 100644
index 0000000000..e215c0921b
--- /dev/null
+++ b/documentation/articles/OfflineModeForTouchKit4MobileApps.asciidoc
@@ -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.
diff --git a/documentation/articles/ScalaAndVaadinHOWTO.asciidoc b/documentation/articles/ScalaAndVaadinHOWTO.asciidoc
new file mode 100644
index 0000000000..d0703aa58d
--- /dev/null
+++ b/documentation/articles/ScalaAndVaadinHOWTO.asciidoc
@@ -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.
diff --git a/documentation/articles/ShowingDataInGrid.asciidoc b/documentation/articles/ShowingDataInGrid.asciidoc
new file mode 100644
index 0000000000..8f84d0ab11
--- /dev/null
+++ b/documentation/articles/ShowingDataInGrid.asciidoc
@@ -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;
+ }
+}
+....
diff --git a/documentation/articles/ShowingExtraDataForGridRows.asciidoc b/documentation/articles/ShowingExtraDataForGridRows.asciidoc
new file mode 100644
index 0000000000..71cc69d7f7
--- /dev/null
+++ b/documentation/articles/ShowingExtraDataForGridRows.asciidoc
@@ -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);
+ }
+}
+....
diff --git a/documentation/articles/SimplifiedRPCusingJavaScript.asciidoc b/documentation/articles/SimplifiedRPCusingJavaScript.asciidoc
new file mode 100644
index 0000000000..31e69832e0
--- /dev/null
+++ b/documentation/articles/SimplifiedRPCusingJavaScript.asciidoc
@@ -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.
diff --git a/documentation/articles/UsingGridWithAContainer.asciidoc b/documentation/articles/UsingGridWithAContainer.asciidoc
new file mode 100644
index 0000000000..5782c698ed
--- /dev/null
+++ b/documentation/articles/UsingGridWithAContainer.asciidoc
@@ -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;
+ }
+}
+....
diff --git a/documentation/articles/UsingGridWithInlineData.asciidoc b/documentation/articles/UsingGridWithInlineData.asciidoc
new file mode 100644
index 0000000000..6a3640894a
--- /dev/null
+++ b/documentation/articles/UsingGridWithInlineData.asciidoc
@@ -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);
+ }
+}
+....
diff --git a/documentation/articles/UsingHibernateWithVaadin.asciidoc b/documentation/articles/UsingHibernateWithVaadin.asciidoc
new file mode 100644
index 0000000000..21416ebe98
--- /dev/null
+++ b/documentation/articles/UsingHibernateWithVaadin.asciidoc
@@ -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).
diff --git a/documentation/articles/UsingJDBCwithLazyQueryContainerAndFilteringTable.asciidoc b/documentation/articles/UsingJDBCwithLazyQueryContainerAndFilteringTable.asciidoc
new file mode 100644
index 0000000000..2f5e73e6ed
--- /dev/null
+++ b/documentation/articles/UsingJDBCwithLazyQueryContainerAndFilteringTable.asciidoc
@@ -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("`","`"));
+....
diff --git a/documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc b/documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc
new file mode 100644
index 0000000000..337b3a2905
--- /dev/null
+++ b/documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc
@@ -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.
diff --git a/documentation/articles/UsingPython.asciidoc b/documentation/articles/UsingPython.asciidoc
new file mode 100644
index 0000000000..8f1d433759
--- /dev/null
+++ b/documentation/articles/UsingPython.asciidoc
@@ -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.
diff --git a/documentation/articles/UsingVaadinInAnExistingGWTProject.asciidoc b/documentation/articles/UsingVaadinInAnExistingGWTProject.asciidoc
new file mode 100644
index 0000000000..00d7e10137
--- /dev/null
+++ b/documentation/articles/UsingVaadinInAnExistingGWTProject.asciidoc
@@ -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.
diff --git a/documentation/articles/VAccessControl.asciidoc b/documentation/articles/VAccessControl.asciidoc
new file mode 100644
index 0000000000..dce9c3a6c0
--- /dev/null
+++ b/documentation/articles/VAccessControl.asciidoc
@@ -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)`.
diff --git a/documentation/articles/Vaadin7HierarchicalContainerAndTreeComponentExampleWithLiferayOrganizationService.asciidoc b/documentation/articles/Vaadin7HierarchicalContainerAndTreeComponentExampleWithLiferayOrganizationService.asciidoc
new file mode 100644
index 0000000000..988f59f62f
--- /dev/null
+++ b/documentation/articles/Vaadin7HierarchicalContainerAndTreeComponentExampleWithLiferayOrganizationService.asciidoc
@@ -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;
+}
+....
diff --git a/documentation/articles/contents.asciidoc b/documentation/articles/contents.asciidoc
new file mode 100644
index 0000000000..c2e3743cb2
--- /dev/null
+++ b/documentation/articles/contents.asciidoc
@@ -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]
diff --git a/documentation/articles/img/DmoOrgTreeUI.java b/documentation/articles/img/DmoOrgTreeUI.java
new file mode 100644
index 0000000000..5e343cc347
--- /dev/null
+++ b/documentation/articles/img/DmoOrgTreeUI.java
@@ -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;
+ }
+
+}
diff --git a/documentation/articles/img/JAR Export (1).png b/documentation/articles/img/JAR Export (1).png
new file mode 100644
index 0000000000..a67ef892b6
--- /dev/null
+++ b/documentation/articles/img/JAR Export (1).png
Binary files differ
diff --git a/documentation/articles/img/JAR Export (2).png b/documentation/articles/img/JAR Export (2).png
new file mode 100644
index 0000000000..7a88f9be92
--- /dev/null
+++ b/documentation/articles/img/JAR Export (2).png
Binary files differ
diff --git a/documentation/articles/img/New Java Project.png b/documentation/articles/img/New Java Project.png
new file mode 100644
index 0000000000..b22895d183
--- /dev/null
+++ b/documentation/articles/img/New Java Project.png
Binary files differ
diff --git a/documentation/articles/img/New Vaadin project (1).png b/documentation/articles/img/New Vaadin project (1).png
new file mode 100644
index 0000000000..73799e80b6
--- /dev/null
+++ b/documentation/articles/img/New Vaadin project (1).png
Binary files differ
diff --git a/documentation/articles/img/New Vaadin project (2).png b/documentation/articles/img/New Vaadin project (2).png
new file mode 100644
index 0000000000..3bde1bef7a
--- /dev/null
+++ b/documentation/articles/img/New Vaadin project (2).png
Binary files differ
diff --git a/documentation/articles/img/Theme to build path.png b/documentation/articles/img/Theme to build path.png
new file mode 100644
index 0000000000..5641c4b987
--- /dev/null
+++ b/documentation/articles/img/Theme to build path.png
Binary files differ
diff --git a/documentation/articles/img/Theme to deployment assembly.png b/documentation/articles/img/Theme to deployment assembly.png
new file mode 100644
index 0000000000..d6b58bf898
--- /dev/null
+++ b/documentation/articles/img/Theme to deployment assembly.png
Binary files differ
diff --git a/documentation/articles/img/VAADIN to deployment assembly.png b/documentation/articles/img/VAADIN to deployment assembly.png
new file mode 100644
index 0000000000..44d3463ca5
--- /dev/null
+++ b/documentation/articles/img/VAADIN to deployment assembly.png
Binary files differ
diff --git a/documentation/articles/img/Vaadin to build path.png b/documentation/articles/img/Vaadin to build path.png
new file mode 100644
index 0000000000..a346c0ab15
--- /dev/null
+++ b/documentation/articles/img/Vaadin to build path.png
Binary files differ
diff --git a/documentation/articles/img/VaadinJasperReportsSample_small.jpg b/documentation/articles/img/VaadinJasperReportsSample_small.jpg
new file mode 100644
index 0000000000..47f14fa7a4
--- /dev/null
+++ b/documentation/articles/img/VaadinJasperReportsSample_small.jpg
Binary files differ
diff --git a/documentation/articles/img/ab-with-vaadin-scrshot.png b/documentation/articles/img/ab-with-vaadin-scrshot.png
new file mode 100644
index 0000000000..4da34e1b24
--- /dev/null
+++ b/documentation/articles/img/ab-with-vaadin-scrshot.png
Binary files differ
diff --git a/documentation/articles/img/address editor.png b/documentation/articles/img/address editor.png
new file mode 100644
index 0000000000..1dd60c3dc8
--- /dev/null
+++ b/documentation/articles/img/address editor.png
Binary files differ
diff --git a/documentation/articles/img/architecture.png b/documentation/articles/img/architecture.png
new file mode 100644
index 0000000000..fa0930179a
--- /dev/null
+++ b/documentation/articles/img/architecture.png
Binary files differ
diff --git a/documentation/articles/img/architecture2.png b/documentation/articles/img/architecture2.png
new file mode 100644
index 0000000000..c9631cc022
--- /dev/null
+++ b/documentation/articles/img/architecture2.png
Binary files differ
diff --git a/documentation/articles/img/buttons added.png b/documentation/articles/img/buttons added.png
new file mode 100644
index 0000000000..26ea5852f9
--- /dev/null
+++ b/documentation/articles/img/buttons added.png
Binary files differ
diff --git a/documentation/articles/img/complexdomain.png b/documentation/articles/img/complexdomain.png
new file mode 100644
index 0000000000..050049dff5
--- /dev/null
+++ b/documentation/articles/img/complexdomain.png
Binary files differ
diff --git a/documentation/articles/img/complexdomain_saving.png b/documentation/articles/img/complexdomain_saving.png
new file mode 100644
index 0000000000..97cf0cc790
--- /dev/null
+++ b/documentation/articles/img/complexdomain_saving.png
Binary files differ
diff --git a/documentation/articles/img/complexdomain_saving2.png b/documentation/articles/img/complexdomain_saving2.png
new file mode 100644
index 0000000000..af4d5d4f25
--- /dev/null
+++ b/documentation/articles/img/complexdomain_saving2.png
Binary files differ
diff --git a/documentation/articles/img/customForms.png b/documentation/articles/img/customForms.png
new file mode 100644
index 0000000000..0edb698b71
--- /dev/null
+++ b/documentation/articles/img/customForms.png
Binary files differ
diff --git a/documentation/articles/img/database connected.png b/documentation/articles/img/database connected.png
new file mode 100644
index 0000000000..80c3588224
--- /dev/null
+++ b/documentation/articles/img/database connected.png
Binary files differ
diff --git a/documentation/articles/img/deployartifact.png b/documentation/articles/img/deployartifact.png
new file mode 100644
index 0000000000..f3e89561db
--- /dev/null
+++ b/documentation/articles/img/deployartifact.png
Binary files differ
diff --git a/documentation/articles/img/jm1B.png b/documentation/articles/img/jm1B.png
new file mode 100644
index 0000000000..9d4bf9ecf1
--- /dev/null
+++ b/documentation/articles/img/jm1B.png
Binary files differ
diff --git a/documentation/articles/img/jm2B.png b/documentation/articles/img/jm2B.png
new file mode 100644
index 0000000000..dfcbd6d30a
--- /dev/null
+++ b/documentation/articles/img/jm2B.png
Binary files differ
diff --git a/documentation/articles/img/jm3B.png b/documentation/articles/img/jm3B.png
new file mode 100644
index 0000000000..da2cb86b65
--- /dev/null
+++ b/documentation/articles/img/jm3B.png
Binary files differ
diff --git a/documentation/articles/img/jm4.png b/documentation/articles/img/jm4.png
new file mode 100644
index 0000000000..4dedd80647
--- /dev/null
+++ b/documentation/articles/img/jm4.png
Binary files differ
diff --git a/documentation/articles/img/jm5.png b/documentation/articles/img/jm5.png
new file mode 100644
index 0000000000..058193fe4f
--- /dev/null
+++ b/documentation/articles/img/jm5.png
Binary files differ
diff --git a/documentation/articles/img/master detail wireframe.jpg b/documentation/articles/img/master detail wireframe.jpg
new file mode 100644
index 0000000000..4745b4831f
--- /dev/null
+++ b/documentation/articles/img/master detail wireframe.jpg
Binary files differ
diff --git a/documentation/articles/img/person editor.png b/documentation/articles/img/person editor.png
new file mode 100644
index 0000000000..71de0a3ebb
--- /dev/null
+++ b/documentation/articles/img/person editor.png
Binary files differ
diff --git a/documentation/articles/img/process.png b/documentation/articles/img/process.png
new file mode 100644
index 0000000000..f8b1b3e1ad
--- /dev/null
+++ b/documentation/articles/img/process.png
Binary files differ
diff --git a/documentation/articles/img/screenshot.png b/documentation/articles/img/screenshot.png
new file mode 100644
index 0000000000..13522d4c66
--- /dev/null
+++ b/documentation/articles/img/screenshot.png
Binary files differ
diff --git a/documentation/articles/img/sd_s_per_r.gif b/documentation/articles/img/sd_s_per_r.gif
new file mode 100644
index 0000000000..cccdddc43b
--- /dev/null
+++ b/documentation/articles/img/sd_s_per_r.gif
Binary files differ
diff --git a/documentation/articles/img/table and form.png b/documentation/articles/img/table and form.png
new file mode 100644
index 0000000000..d454da1fd9
--- /dev/null
+++ b/documentation/articles/img/table and form.png
Binary files differ
diff --git a/documentation/articles/img/views.png b/documentation/articles/img/views.png
new file mode 100644
index 0000000000..fd4bb48f64
--- /dev/null
+++ b/documentation/articles/img/views.png
Binary files differ