aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/com')
-rw-r--r--server/src/com/vaadin/data/Container.java54
-rw-r--r--server/src/com/vaadin/data/util/AbstractBeanContainer.java20
-rw-r--r--server/src/com/vaadin/data/util/AbstractInMemoryContainer.java151
-rw-r--r--server/src/com/vaadin/data/util/IndexedContainer.java7
-rw-r--r--server/src/com/vaadin/event/ConnectorActionManager.java88
-rw-r--r--server/src/com/vaadin/event/UIEvents.java116
-rw-r--r--server/src/com/vaadin/server/ClientMethodInvocation.java54
-rw-r--r--server/src/com/vaadin/server/Constants.java4
-rw-r--r--server/src/com/vaadin/server/ErrorHandlingRunnable.java38
-rw-r--r--server/src/com/vaadin/server/VaadinPortlet.java29
-rw-r--r--server/src/com/vaadin/server/VaadinService.java7
-rw-r--r--server/src/com/vaadin/server/VaadinServlet.java2
-rw-r--r--server/src/com/vaadin/server/VaadinServletService.java4
-rw-r--r--server/src/com/vaadin/server/VaadinSession.java60
-rw-r--r--server/src/com/vaadin/server/communication/PortletBootstrapHandler.java11
-rw-r--r--server/src/com/vaadin/server/communication/PushHandler.java64
-rw-r--r--server/src/com/vaadin/server/communication/ServerRpcHandler.java33
-rw-r--r--server/src/com/vaadin/ui/AbstractComponent.java5
-rw-r--r--server/src/com/vaadin/ui/Link.java84
-rw-r--r--server/src/com/vaadin/ui/Table.java32
-rw-r--r--server/src/com/vaadin/ui/TreeTable.java4
-rw-r--r--server/src/com/vaadin/ui/UI.java60
-rw-r--r--server/src/com/vaadin/ui/Window.java10
23 files changed, 804 insertions, 133 deletions
diff --git a/server/src/com/vaadin/data/Container.java b/server/src/com/vaadin/data/Container.java
index e93db52a35..bf553f31d2 100644
--- a/server/src/com/vaadin/data/Container.java
+++ b/server/src/com/vaadin/data/Container.java
@@ -582,6 +582,60 @@ public interface Container extends Serializable {
public Item addItemAt(int index, Object newItemId)
throws UnsupportedOperationException;
+ /**
+ * An <code>Event</code> object specifying information about the added
+ * items.
+ */
+ public interface ItemAddEvent extends ItemSetChangeEvent {
+
+ /**
+ * Gets the item id of the first added item.
+ *
+ * @return item id of the first added item
+ */
+ public Object getFirstItemId();
+
+ /**
+ * Gets the index of the first added item.
+ *
+ * @return index of the first added item
+ */
+ public int getFirstIndex();
+
+ /**
+ * Gets the number of the added items.
+ *
+ * @return the number of added items.
+ */
+ public int getAddedItemsCount();
+ }
+
+ /**
+ * An <code>Event</code> object specifying information about the removed
+ * items.
+ */
+ public interface ItemRemoveEvent extends ItemSetChangeEvent {
+ /**
+ * Gets the item id of the first removed item.
+ *
+ * @return item id of the first removed item
+ */
+ public Object getFirstItemId();
+
+ /**
+ * Gets the index of the first removed item.
+ *
+ * @return index of the first removed item
+ */
+ public int getFirstIndex();
+
+ /**
+ * Gets the number of the removed items.
+ *
+ * @return the number of removed items
+ */
+ public int getRemovedItemsCount();
+ }
}
/**
diff --git a/server/src/com/vaadin/data/util/AbstractBeanContainer.java b/server/src/com/vaadin/data/util/AbstractBeanContainer.java
index cd5c0c809d..67239996a2 100644
--- a/server/src/com/vaadin/data/util/AbstractBeanContainer.java
+++ b/server/src/com/vaadin/data/util/AbstractBeanContainer.java
@@ -222,6 +222,7 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
@Override
public boolean removeAllItems() {
int origSize = size();
+ IDTYPE firstItem = getFirstVisibleItem();
internalRemoveAllItems();
@@ -234,7 +235,7 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
// fire event only if the visible view changed, regardless of whether
// filtered out items were removed or not
if (origSize != 0) {
- fireItemSetChange();
+ fireItemsRemoved(0, firstItem, origSize);
}
return true;
@@ -679,6 +680,8 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
protected void addAll(Collection<? extends BEANTYPE> collection)
throws IllegalStateException, IllegalArgumentException {
boolean modified = false;
+ int origSize = size();
+
for (BEANTYPE bean : collection) {
// TODO skipping invalid beans - should not allow them in javadoc?
if (bean == null
@@ -699,13 +702,22 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
if (modified) {
// Filter the contents when all items have been added
if (isFiltered()) {
- filterAll();
- } else {
- fireItemSetChange();
+ doFilterContainer(!getFilters().isEmpty());
+ }
+ if (visibleNewItemsWasAdded(origSize)) {
+ // fire event about added items
+ int firstPosition = origSize;
+ IDTYPE firstItemId = getVisibleItemIds().get(firstPosition);
+ int affectedItems = size() - origSize;
+ fireItemsAdded(firstPosition, firstItemId, affectedItems);
}
}
}
+ private boolean visibleNewItemsWasAdded(int origSize) {
+ return size() > origSize;
+ }
+
/**
* Use the bean resolver to get the identifier for a bean.
*
diff --git a/server/src/com/vaadin/data/util/AbstractInMemoryContainer.java b/server/src/com/vaadin/data/util/AbstractInMemoryContainer.java
index 84304431bc..9a7922b928 100644
--- a/server/src/com/vaadin/data/util/AbstractInMemoryContainer.java
+++ b/server/src/com/vaadin/data/util/AbstractInMemoryContainer.java
@@ -15,8 +15,10 @@
*/
package com.vaadin.data.util;
+import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
+import java.util.EventObject;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
@@ -146,6 +148,85 @@ public abstract class AbstractInMemoryContainer<ITEMIDTYPE, PROPERTYIDCLASS, ITE
}
}
+ private static abstract class BaseItemAddOrRemoveEvent extends
+ EventObject implements Serializable {
+ protected Object itemId;
+ protected int index;
+ protected int count;
+
+ public BaseItemAddOrRemoveEvent(Container source, Object itemId,
+ int index, int count) {
+ super(source);
+ this.itemId = itemId;
+ this.index = index;
+ this.count = count;
+ }
+
+ public Container getContainer() {
+ return (Container) getSource();
+ }
+
+ public Object getFirstItemId() {
+ return itemId;
+ }
+
+ public int getFirstIndex() {
+ return index;
+ }
+
+ public int getAffectedItemsCount() {
+ return count;
+ }
+ }
+
+ /**
+ * An <code>Event</code> object specifying information about the added
+ * items.
+ *
+ * <p>
+ * This class provides information about the first added item and the number
+ * of added items.
+ * </p>
+ */
+ protected static class BaseItemAddEvent extends
+ BaseItemAddOrRemoveEvent implements
+ Container.Indexed.ItemAddEvent {
+
+ public BaseItemAddEvent(Container source, Object itemId, int index,
+ int count) {
+ super(source, itemId, index, count);
+ }
+
+ @Override
+ public int getAddedItemsCount() {
+ return getAffectedItemsCount();
+ }
+ }
+
+ /**
+ * An <code>Event</code> object specifying information about the removed
+ * items.
+ *
+ * <p>
+ * This class provides information about the first removed item and the
+ * number of removed items.
+ * </p>
+ */
+ protected static class BaseItemRemoveEvent extends
+ BaseItemAddOrRemoveEvent implements
+ Container.Indexed.ItemRemoveEvent {
+
+ public BaseItemRemoveEvent(Container source, Object itemId,
+ int index, int count) {
+ super(source, itemId, index, count);
+ }
+
+ @Override
+ public int getRemovedItemsCount() {
+ return getAffectedItemsCount();
+ }
+ }
+
/**
* Get an item even if filtered out.
*
@@ -898,36 +979,69 @@ public abstract class AbstractInMemoryContainer<ITEMIDTYPE, PROPERTYIDCLASS, ITE
* Notify item set change listeners that an item has been added to the
* container.
*
- * Unless subclasses specify otherwise, the default notification indicates a
- * full refresh.
- *
* @param postion
- * position of the added item in the view (if visible)
+ * position of the added item in the view
* @param itemId
* id of the added item
* @param item
* the added item
*/
protected void fireItemAdded(int position, ITEMIDTYPE itemId, ITEMCLASS item) {
- fireItemSetChange();
+ fireItemsAdded(position, itemId, 1);
+ }
+
+ /**
+ * Notify item set change listeners that items has been added to the
+ * container.
+ *
+ * @param firstPosition
+ * position of the first visible added item in the view
+ * @param firstItemId
+ * id of the first visible added item
+ * @param numberOfItems
+ * the number of visible added items
+ */
+ protected void fireItemsAdded(int firstPosition, ITEMIDTYPE firstItemId,
+ int numberOfItems) {
+ BaseItemAddEvent addEvent = new BaseItemAddEvent(this,
+ firstItemId, firstPosition, numberOfItems);
+ fireItemSetChange(addEvent);
}
/**
* Notify item set change listeners that an item has been removed from the
* container.
*
- * Unless subclasses specify otherwise, the default notification indicates a
- * full refresh.
+ * @param position
+ * position of the removed item in the view prior to removal
*
- * @param postion
- * position of the removed item in the view prior to removal (if
- * was visible)
* @param itemId
* id of the removed item, of type {@link Object} to satisfy
* {@link Container#removeItem(Object)} API
*/
protected void fireItemRemoved(int position, Object itemId) {
- fireItemSetChange();
+ fireItemsRemoved(position, itemId, 1);
+ }
+
+ /**
+ * Notify item set change listeners that items has been removed from the
+ * container.
+ *
+ * @param firstPosition
+ * position of the first visible removed item in the view prior
+ * to removal
+ * @param firstItemId
+ * id of the first visible removed item, of type {@link Object}
+ * to satisfy {@link Container#removeItem(Object)} API
+ * @param numberOfItems
+ * the number of removed visible items
+ *
+ */
+ protected void fireItemsRemoved(int firstPosition, Object firstItemId,
+ int numberOfItems) {
+ BaseItemRemoveEvent removeEvent = new BaseItemRemoveEvent(this,
+ firstItemId, firstPosition, numberOfItems);
+ fireItemSetChange(removeEvent);
}
// visible and filtered item identifier lists
@@ -946,6 +1060,21 @@ public abstract class AbstractInMemoryContainer<ITEMIDTYPE, PROPERTYIDCLASS, ITE
}
/**
+ * Returns the item id of the first visible item after filtering. 'Null' is
+ * returned if there is no visible items.
+ *
+ * For internal use only.
+ *
+ * @return item id of the first visible item
+ */
+ protected ITEMIDTYPE getFirstVisibleItem() {
+ if (!getVisibleItemIds().isEmpty()) {
+ return getVisibleItemIds().get(0);
+ }
+ return null;
+ }
+
+ /**
* Returns true is the container has active filters.
*
* @return true if the container is currently filtered
diff --git a/server/src/com/vaadin/data/util/IndexedContainer.java b/server/src/com/vaadin/data/util/IndexedContainer.java
index d7bf70caf6..5d20919208 100644
--- a/server/src/com/vaadin/data/util/IndexedContainer.java
+++ b/server/src/com/vaadin/data/util/IndexedContainer.java
@@ -226,6 +226,7 @@ public class IndexedContainer extends
@Override
public boolean removeAllItems() {
int origSize = size();
+ Object firstItem = getFirstVisibleItem();
internalRemoveAllItems();
@@ -235,7 +236,7 @@ public class IndexedContainer extends
// filtered out items were removed or not
if (origSize != 0) {
// Sends a change event
- fireItemSetChange();
+ fireItemsRemoved(0, firstItem, origSize);
}
return true;
@@ -620,8 +621,7 @@ public class IndexedContainer extends
@Override
protected void fireItemAdded(int position, Object itemId, Item item) {
if (position >= 0) {
- fireItemSetChange(new IndexedContainer.ItemSetChangeEvent(this,
- position));
+ super.fireItemAdded(position, itemId, item);
}
}
@@ -1211,4 +1211,5 @@ public class IndexedContainer extends
public Collection<Filter> getContainerFilters() {
return super.getContainerFilters();
}
+
}
diff --git a/server/src/com/vaadin/event/ConnectorActionManager.java b/server/src/com/vaadin/event/ConnectorActionManager.java
new file mode 100644
index 0000000000..297f78f179
--- /dev/null
+++ b/server/src/com/vaadin/event/ConnectorActionManager.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.event;
+
+import java.util.logging.Logger;
+
+import com.vaadin.event.Action.Container;
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.VariableOwner;
+import com.vaadin.server.communication.ServerRpcHandler;
+import com.vaadin.ui.Component;
+
+/**
+ * An ActionManager connected to a connector. Takes care of verifying that the
+ * connector can receive events before triggering an action.
+ * <p>
+ * This is mostly a workaround until shortcut actions are re-implemented in a
+ * more sensible way.
+ *
+ * @since 7.1.8
+ * @author Vaadin Ltd
+ */
+public class ConnectorActionManager extends ActionManager {
+
+ private ClientConnector connector;
+
+ /**
+ * Initialize an action manager for the given connector.
+ *
+ * @param connector
+ * the owner of this action manager
+ */
+ public ConnectorActionManager(ClientConnector connector) {
+ super();
+ this.connector = connector;
+ }
+
+ /**
+ * Initialize an action manager for the given connector using the given
+ * viewer.
+ *
+ * @param connector
+ * the owner of this action manager
+ * @param viewer
+ * the viewer connected
+ */
+ public <T extends Component & Container & VariableOwner> ConnectorActionManager(
+ ClientConnector connector, T viewer) {
+ super(viewer);
+ this.connector = connector;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.event.ActionManager#handleAction(com.vaadin.event.Action,
+ * java.lang.Object, java.lang.Object)
+ */
+ @Override
+ public void handleAction(Action action, Object sender, Object target) {
+ if (!connector.isConnectorEnabled()) {
+ getLogger().warning(
+ ServerRpcHandler.getIgnoredDisabledError("action",
+ connector));
+ return;
+ }
+
+ super.handleAction(action, sender, target);
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(ConnectorActionManager.class.getName());
+ }
+
+}
diff --git a/server/src/com/vaadin/event/UIEvents.java b/server/src/com/vaadin/event/UIEvents.java
new file mode 100644
index 0000000000..321bfc9251
--- /dev/null
+++ b/server/src/com/vaadin/event/UIEvents.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.event;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+import com.vaadin.ui.Component;
+import com.vaadin.ui.UI;
+import com.vaadin.util.ReflectTools;
+
+/**
+ * A class that contains events, listeners and handlers specific to the
+ * {@link UI} class.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public interface UIEvents {
+
+ /**
+ * A {@link PollListener} receives and handles {@link PollEvent PollEvents}
+ * fired by {@link PollNotifier PollNotifiers}.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+ public interface PollListener extends Serializable {
+ public static final Method POLL_METHOD = ReflectTools.findMethod(
+ PollListener.class, "poll", PollEvent.class);
+
+ /**
+ * A poll request has been received by the server.
+ *
+ * @param event
+ * poll event
+ */
+ public void poll(PollEvent event);
+ }
+
+ /**
+ * An event that is fired whenever a client polls the server for
+ * asynchronous UI updates.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+ public static class PollEvent extends Component.Event {
+ public PollEvent(UI ui) {
+ super(ui);
+ }
+
+ /**
+ * Get the {@link UI} instance that received the poll request.
+ *
+ * @return the {@link UI} that received the poll request. Never
+ * <code>null</code>.
+ */
+ public UI getUI() {
+ /*
+ * This cast is safe to make, since this class' constructor
+ * constrains the source to be a UI instance.
+ */
+ return (UI) getComponent();
+ }
+ }
+
+ /**
+ * The interface for adding and removing {@link PollEvent} listeners.
+ * <p>
+ * By implementing this interface, a class publicly announces that it is
+ * able to send {@link PollEvent PollEvents} whenever the client sends a
+ * periodic poll message to the client, to check for asynchronous
+ * server-side modifications.
+ *
+ * @since 7.2
+ * @see UI#setPollInterval(int)
+ */
+ public interface PollNotifier extends Serializable {
+ /**
+ * Add a poll listener.
+ * <p>
+ * The listener is called whenever the client polls the server for
+ * asynchronous UI updates.
+ *
+ * @see UI#setPollInterval(int)
+ * @see #removePollListener(PollListener)
+ * @param listener
+ * the {@link PollListener} to add
+ */
+ public void addPollListener(PollListener listener);
+
+ /**
+ * Remove a poll listener.
+ *
+ * @see #addPollListener(PollListener)
+ * @param listener
+ * the listener to be removed
+ */
+ public void removePollListener(PollListener listener);
+ }
+
+}
diff --git a/server/src/com/vaadin/server/ClientMethodInvocation.java b/server/src/com/vaadin/server/ClientMethodInvocation.java
index 9c8318b064..3a6a87a53c 100644
--- a/server/src/com/vaadin/server/ClientMethodInvocation.java
+++ b/server/src/com/vaadin/server/ClientMethodInvocation.java
@@ -16,10 +16,16 @@
package com.vaadin.server;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
+import org.json.JSONArray;
+import org.json.JSONException;
+
/**
* Internal class for keeping track of pending server to client method
* invocations for a Connector.
@@ -80,4 +86,52 @@ public class ClientMethodInvocation implements Serializable,
}
return Long.signum(getSequenceNumber() - o.getSequenceNumber());
}
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ // Need to have custom serialization and deserialization because the
+ // constructor allows parameters of any type with Object[]. Thus, having
+ // parameters that are not Serializable will lead to
+ // NotSerializableException when trying to serialize this class.
+ // An example case of this is in #12532 (JavaScriptCallbackHelper ->
+ // JSONArray as parameter and not Serializable), for which this
+ // hac..workaround is implemented.
+
+ // Goes through the parameter types, and apply "custom serialization" to
+ // the ones that are not Serializable by changing them into something
+ // that is Serializable. On deserialization (readObject-method below)
+ // the process should be reversed.
+
+ // Easy way for implementing serialization & deserialization is by
+ // writing/parsing the object's content as string.
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Type type = parameterTypes[i];
+ if (type instanceof Class<?>) {
+ Class<?> clazz = (Class<?>) type;
+ if (JSONArray.class.isAssignableFrom(clazz)) {
+ parameters[i] = ((JSONArray) parameters[i]).toString();
+ }
+ }
+ }
+ stream.defaultWriteObject();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+ // Reverses the serialization done in writeObject. Basically just
+ // parsing the serialized type back to the non-serializable type.
+ stream.defaultReadObject();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Type type = parameterTypes[i];
+ if (type instanceof Class<?>) {
+ Class<?> clazz = (Class<?>) type;
+ if (JSONArray.class.isAssignableFrom(clazz)) {
+ try {
+ parameters[i] = new JSONArray(((String) parameters[i]));
+ } catch (JSONException e) {
+ throw new IOException(e);
+ }
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java
index 8c379abe06..b0841da314 100644
--- a/server/src/com/vaadin/server/Constants.java
+++ b/server/src/com/vaadin/server/Constants.java
@@ -67,7 +67,7 @@ public interface Constants {
// Keep the version number in sync with push/build.xml and other locations
// listed in that file
- static final String REQUIRED_ATMOSPHERE_VERSION = "1.0.14.vaadin4";
+ static final String REQUIRED_ATMOSPHERE_RUNTIME_VERSION = "1.0.18.vaadin1";
static final String INVALID_ATMOSPHERE_VERSION_WARNING = "\n"
+ "=================================================================\n"
@@ -82,7 +82,7 @@ public interface Constants {
+ "If using a dependency management system, please add a dependency\n"
+ "to vaadin-push.\n"
+ "If managing dependencies manually, please make sure Atmosphere\n"
- + REQUIRED_ATMOSPHERE_VERSION
+ + REQUIRED_ATMOSPHERE_RUNTIME_VERSION
+ " is included on the classpath.\n"
+ "Will fall back to using "
+ PushMode.class.getSimpleName()
diff --git a/server/src/com/vaadin/server/ErrorHandlingRunnable.java b/server/src/com/vaadin/server/ErrorHandlingRunnable.java
new file mode 100644
index 0000000000..3970a14ee8
--- /dev/null
+++ b/server/src/com/vaadin/server/ErrorHandlingRunnable.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server;
+
+import java.io.Serializable;
+
+/**
+ * Defines the interface to handle exceptions thrown during the execution of a
+ * FutureAccess.
+ *
+ * @since 7.1.8
+ * @author Vaadin Ltd
+ */
+public interface ErrorHandlingRunnable extends Runnable, Serializable {
+
+ /**
+ * Handles exceptions thrown during the execution of a FutureAccess.
+ *
+ * @since 7.1.8
+ * @param exception
+ * the thrown exception.
+ */
+ public void handleError(Exception exception);
+
+}
diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java
index adef90c45f..a41f301219 100644
--- a/server/src/com/vaadin/server/VaadinPortlet.java
+++ b/server/src/com/vaadin/server/VaadinPortlet.java
@@ -422,16 +422,37 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
* @return A wrapped version of the PorletRequest
*/
protected VaadinPortletRequest createVaadinRequest(PortletRequest request) {
- String portalInfo = request.getPortalContext().getPortalInfo()
- .toLowerCase();
- if (portalInfo.contains("liferay")) {
+ if (isLiferay(request)) {
return new VaadinLiferayRequest(request, getService());
- } else if (portalInfo.contains("gatein")) {
+ } else if (isGateIn(request)) {
return new VaadinGateinRequest(request, getService());
} else {
return new VaadinPortletRequest(request, getService());
}
+ }
+ /**
+ * Returns true if the portlet request is from Liferay.
+ *
+ * @param request
+ * @return True if Liferay, false otherwise
+ */
+ private static boolean isLiferay(PortletRequest request) {
+ String portalInfo = request.getPortalContext().getPortalInfo()
+ .toLowerCase();
+ return portalInfo.contains("liferay");
+ }
+
+ /**
+ * Returns true if the portlet request if from GateIn
+ *
+ * @param request
+ * @return True if GateIn, false otherwise
+ */
+ private static boolean isGateIn(PortletRequest request) {
+ String portalInfo = request.getPortalContext().getPortalInfo()
+ .toLowerCase();
+ return portalInfo.contains("gatein");
}
private VaadinPortletResponse createVaadinResponse(PortletResponse response) {
diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java
index cf6c806ead..aff0124d16 100644
--- a/server/src/com/vaadin/server/VaadinService.java
+++ b/server/src/com/vaadin/server/VaadinService.java
@@ -1736,6 +1736,13 @@ public abstract class VaadinService implements Serializable {
.getCurrentInstances());
CurrentInstance.setCurrent(session);
pendingAccess.run();
+
+ try {
+ pendingAccess.get();
+
+ } catch (Exception exception) {
+ pendingAccess.handleError(exception);
+ }
}
}
} finally {
diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java
index d34cd3bf0e..baf97d23d9 100644
--- a/server/src/com/vaadin/server/VaadinServlet.java
+++ b/server/src/com/vaadin/server/VaadinServlet.java
@@ -426,8 +426,6 @@ public class VaadinServlet extends HttpServlet implements Constants {
outWriter.print(output);
outWriter.flush();
outWriter.close();
- out.flush();
-
}
/**
diff --git a/server/src/com/vaadin/server/VaadinServletService.java b/server/src/com/vaadin/server/VaadinServletService.java
index 3b39f17849..818f2e87c6 100644
--- a/server/src/com/vaadin/server/VaadinServletService.java
+++ b/server/src/com/vaadin/server/VaadinServletService.java
@@ -66,11 +66,11 @@ public class VaadinServletService extends VaadinService {
private static boolean checkAtmosphereSupport() {
try {
String rawVersion = Version.getRawVersion();
- if (!Constants.REQUIRED_ATMOSPHERE_VERSION.equals(rawVersion)) {
+ if (!Constants.REQUIRED_ATMOSPHERE_RUNTIME_VERSION.equals(rawVersion)) {
getLogger().log(
Level.WARNING,
Constants.INVALID_ATMOSPHERE_VERSION_WARNING,
- new Object[] { Constants.REQUIRED_ATMOSPHERE_VERSION,
+ new Object[] { Constants.REQUIRED_ATMOSPHERE_RUNTIME_VERSION,
rawVersion });
}
return true;
diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java
index 8f15dacc98..f34721944a 100644
--- a/server/src/com/vaadin/server/VaadinSession.java
+++ b/server/src/com/vaadin/server/VaadinSession.java
@@ -16,6 +16,8 @@
package com.vaadin.server;
+import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collection;
@@ -33,6 +35,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.logging.Level;
import java.util.logging.Logger;
import javax.portlet.PortletSession;
@@ -83,6 +86,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
private final Map<Class<?>, CurrentInstance> instances = CurrentInstance
.getInstances(true);
private final VaadinSession session;
+ private Runnable runnable;
/**
* Creates an instance for the given runnable
@@ -97,6 +101,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
public FutureAccess(VaadinSession session, Runnable runnable) {
super(runnable, null);
this.session = session;
+ this.runnable = runnable;
}
@Override
@@ -126,6 +131,36 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
public Map<Class<?>, CurrentInstance> getCurrentInstances() {
return instances;
}
+
+ /**
+ * Handles exceptions thrown during the execution of this task.
+ *
+ * @since 7.1.8
+ * @param exception
+ * the thrown exception.
+ */
+ public void handleError(Exception exception) {
+ try {
+ if (runnable instanceof ErrorHandlingRunnable) {
+ ErrorHandlingRunnable errorHandlingRunnable = (ErrorHandlingRunnable) runnable;
+
+ errorHandlingRunnable.handleError(exception);
+ } else {
+ ErrorEvent errorEvent = new ErrorEvent(exception);
+
+ ErrorHandler errorHandler = ErrorEvent
+ .findErrorHandler(session);
+
+ if (errorHandler == null) {
+ errorHandler = new DefaultErrorHandler();
+ }
+
+ errorHandler.error(errorEvent);
+ }
+ } catch (Exception e) {
+ getLogger().log(Level.SEVERE, e.getMessage(), e);
+ }
+ }
}
/**
@@ -202,10 +237,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* session is serialized as long as it doesn't happen while some other
* thread has the lock.
*/
- private transient ConcurrentLinkedQueue<FutureAccess> pendingAccessQueue;
+ private transient ConcurrentLinkedQueue<FutureAccess> pendingAccessQueue = new ConcurrentLinkedQueue<FutureAccess>();
/**
- * Create a new service session tied to a Vaadin service
+ * Creates a new VaadinSession tied to a VaadinService.
*
* @param service
* the Vaadin service for the new session
@@ -1260,18 +1295,15 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
}
/**
- * Gets the queue of tasks submitted using {@link #access(Runnable)}.
+ * Gets the queue of tasks submitted using {@link #access(Runnable)}. It is
+ * safe to call this method and access the returned queue without holding
+ * the {@link #lock() session lock}.
*
* @since 7.1
*
- * @return the pending access queue
+ * @return the queue of pending access tasks
*/
public Queue<FutureAccess> getPendingAccessQueue() {
- if (pendingAccessQueue == null) {
- // pendingAccessQueue is transient, so will be null after
- // deserialization
- pendingAccessQueue = new ConcurrentLinkedQueue<FutureAccess>();
- }
return pendingAccessQueue;
}
@@ -1288,6 +1320,16 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
}
/**
+ * Override default deserialization logic to account for transient
+ * {@link #pendingAccessQueue}.
+ */
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+ stream.defaultReadObject();
+ pendingAccessQueue = new ConcurrentLinkedQueue<FutureAccess>();
+ }
+
+ /**
* Finds the UI with the corresponding embed id.
*
* @since 7.2
diff --git a/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java b/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java
index 2458951ada..dd6d3c9283 100644
--- a/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java
+++ b/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java
@@ -31,6 +31,7 @@ import org.json.JSONObject;
import com.vaadin.server.BootstrapHandler;
import com.vaadin.server.PaintException;
import com.vaadin.server.VaadinPortlet;
+import com.vaadin.server.VaadinPortlet.VaadinLiferayRequest;
import com.vaadin.server.VaadinPortletRequest;
import com.vaadin.server.VaadinPortletResponse;
import com.vaadin.server.VaadinRequest;
@@ -98,6 +99,8 @@ public class PortletBootstrapHandler extends BootstrapHandler {
JSONObject parameters = super.getApplicationParameters(context);
VaadinPortletResponse response = (VaadinPortletResponse) context
.getResponse();
+ VaadinPortletRequest request = (VaadinPortletRequest) context
+ .getRequest();
MimeResponse portletResponse = (MimeResponse) response
.getPortletResponse();
ResourceURL resourceURL = portletResponse.createResourceURL();
@@ -108,6 +111,14 @@ public class PortletBootstrapHandler extends BootstrapHandler {
parameters
.put(ApplicationConstants.SERVICE_URL_PATH_AS_PARAMETER, true);
+ // If we are running in Liferay then we need to prefix all parameters
+ // with the portlet namespace
+ if (request instanceof VaadinLiferayRequest) {
+ parameters.put(
+ ApplicationConstants.SERVICE_URL_PARAMETER_NAMESPACE,
+ response.getPortletResponse().getNamespace());
+ }
+
return parameters;
}
} \ No newline at end of file
diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java
index 81dd00084d..09428e47a9 100644
--- a/server/src/com/vaadin/server/communication/PushHandler.java
+++ b/server/src/com/vaadin/server/communication/PushHandler.java
@@ -31,6 +31,8 @@ import org.atmosphere.cpr.AtmosphereResourceEvent;
import org.atmosphere.cpr.AtmosphereResourceEventListenerAdapter;
import org.json.JSONException;
+import com.vaadin.server.ErrorEvent;
+import com.vaadin.server.ErrorHandler;
import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException;
import com.vaadin.server.ServiceException;
import com.vaadin.server.ServletPortletHelper;
@@ -262,11 +264,12 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
return;
}
+ UI ui = null;
session.lock();
try {
VaadinSession.setCurrent(session);
// Sets UI.currentInstance
- final UI ui = service.findUI(vaadinRequest);
+ ui = service.findUI(vaadinRequest);
if (ui == null) {
sendNotificationAndDisconnect(resource,
UidlRequestHandler.getUINotFoundErrorJSON(service,
@@ -274,14 +277,63 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
} else {
callback.run(resource, ui);
}
- } catch (IOException e) {
- getLogger().log(Level.WARNING, "Error writing a push response",
- e);
+ } catch (final IOException e) {
+ callErrorHandler(session, e);
+ } catch (final Exception e) {
+ SystemMessages msg = service.getSystemMessages(
+ ServletPortletHelper.findLocale(null, null,
+ vaadinRequest), vaadinRequest);
+
+ AtmosphereResource errorResource = resource;
+ if (ui != null && ui.getPushConnection() != null) {
+ // We MUST use the opened push connection if there is one.
+ // Otherwise we will write the response to the wrong request
+ // when using streaming (the client -> server request
+ // instead of the opened push channel)
+ errorResource = ((AtmospherePushConnection) ui
+ .getPushConnection()).getResource();
+ }
+
+ sendNotificationAndDisconnect(
+ errorResource,
+ VaadinService.createCriticalNotificationJSON(
+ msg.getInternalErrorCaption(),
+ msg.getInternalErrorMessage(), null,
+ msg.getInternalErrorURL()));
+ callErrorHandler(session, e);
} finally {
- session.unlock();
+ try {
+ session.unlock();
+ } catch (Exception e) {
+ getLogger().log(Level.WARNING,
+ "Error while unlocking session", e);
+ // can't call ErrorHandler, we (hopefully) don't have a lock
+ }
}
} finally {
- service.requestEnd(vaadinRequest, null, session);
+ try {
+ service.requestEnd(vaadinRequest, null, session);
+ } catch (Exception e) {
+ getLogger().log(Level.WARNING, "Error while ending request", e);
+
+ // can't call ErrorHandler, we don't have a lock
+ }
+ }
+ }
+
+ /**
+ * Call the session's {@link ErrorHandler}, if it has one, with the given
+ * exception wrapped in an {@link ErrorEvent}.
+ */
+ private void callErrorHandler(VaadinSession session, Exception e) {
+ try {
+ ErrorHandler errorHandler = ErrorEvent.findErrorHandler(session);
+ if (errorHandler != null) {
+ errorHandler.error(new ErrorEvent(e));
+ }
+ } catch (Exception ex) {
+ // Let's not allow error handling to cause trouble; log fails
+ getLogger().log(Level.WARNING, "ErrorHandler call failed", ex);
}
}
diff --git a/server/src/com/vaadin/server/communication/ServerRpcHandler.java b/server/src/com/vaadin/server/communication/ServerRpcHandler.java
index eff9ceebf4..432a9ea893 100644
--- a/server/src/com/vaadin/server/communication/ServerRpcHandler.java
+++ b/server/src/com/vaadin/server/communication/ServerRpcHandler.java
@@ -248,15 +248,8 @@ public class ServerRpcHandler implements Serializable {
}
// Connector is disabled, log a warning and move to the next
- String msg = "Ignoring RPC call for disabled connector "
- + connector.getClass().getName();
- if (connector instanceof Component) {
- String caption = ((Component) connector).getCaption();
- if (caption != null) {
- msg += ", caption=" + caption;
- }
- }
- getLogger().warning(msg);
+ getLogger().warning(
+ getIgnoredDisabledError("RPC call", connector));
continue;
}
// DragAndDropService has null UI
@@ -495,4 +488,26 @@ public class ServerRpcHandler implements Serializable {
private static final Logger getLogger() {
return Logger.getLogger(ServerRpcHandler.class.getName());
}
+
+ /**
+ * Generates an error message when the client is trying to to something
+ * ('what') with a connector which is disabled or invisible.
+ *
+ * @since 7.1.8
+ * @param connector
+ * the connector which is disabled (or invisible)
+ * @return an error message
+ */
+ public static String getIgnoredDisabledError(String what,
+ ClientConnector connector) {
+ String msg = "Ignoring " + what + " for disabled connector "
+ + connector.getClass().getName();
+ if (connector instanceof Component) {
+ String caption = ((Component) connector).getCaption();
+ if (caption != null) {
+ msg += ", caption=" + caption;
+ }
+ }
+ return msg;
+ }
}
diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java
index 262d47af18..61bcf00ad8 100644
--- a/server/src/com/vaadin/ui/AbstractComponent.java
+++ b/server/src/com/vaadin/ui/AbstractComponent.java
@@ -27,6 +27,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.vaadin.event.ActionManager;
+import com.vaadin.event.ConnectorActionManager;
import com.vaadin.event.ShortcutListener;
import com.vaadin.server.AbstractClientConnector;
import com.vaadin.server.ComponentSizeValidator;
@@ -90,7 +91,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
* Keeps track of the Actions added to this component; the actual
* handling/notifying is delegated, usually to the containing window.
*/
- private ActionManager actionManager;
+ private ConnectorActionManager actionManager;
private boolean visible = true;
@@ -929,7 +930,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
*/
protected ActionManager getActionManager() {
if (actionManager == null) {
- actionManager = new ActionManager();
+ actionManager = new ConnectorActionManager(this);
setActionManagerViewer();
}
return actionManager;
diff --git a/server/src/com/vaadin/ui/Link.java b/server/src/com/vaadin/ui/Link.java
index cf8e1a9693..e1a47777bd 100644
--- a/server/src/com/vaadin/ui/Link.java
+++ b/server/src/com/vaadin/ui/Link.java
@@ -16,13 +16,10 @@
package com.vaadin.ui;
-import java.util.Map;
-
-import com.vaadin.server.PaintException;
-import com.vaadin.server.PaintTarget;
import com.vaadin.server.Resource;
import com.vaadin.shared.ui.BorderStyle;
import com.vaadin.shared.ui.link.LinkConstants;
+import com.vaadin.shared.ui.link.LinkState;
/**
* Link is used to create external or internal URL links.
@@ -31,7 +28,7 @@ import com.vaadin.shared.ui.link.LinkConstants;
* @since 3.0
*/
@SuppressWarnings("serial")
-public class Link extends AbstractComponent implements LegacyComponent {
+public class Link extends AbstractComponent {
/**
* @deprecated As of 7.0, use {@link BorderStyle#NONE} instead
@@ -51,14 +48,6 @@ public class Link extends AbstractComponent implements LegacyComponent {
@Deprecated
public static final BorderStyle TARGET_BORDER_DEFAULT = BorderStyle.DEFAULT;
- private String targetName;
-
- private BorderStyle targetBorder = BorderStyle.DEFAULT;
-
- private int targetWidth = -1;
-
- private int targetHeight = -1;
-
/**
* Creates a new link.
*/
@@ -105,43 +94,14 @@ public class Link extends AbstractComponent implements LegacyComponent {
setTargetBorder(border);
}
- /**
- * Paints the content of this component.
- *
- * @param target
- * the Paint Event.
- * @throws PaintException
- * if the paint operation failed.
- */
@Override
- public void paintContent(PaintTarget target) throws PaintException {
- if (getResource() == null) {
- return;
- }
-
- // Target window name
- final String name = getTargetName();
- if (name != null && name.length() > 0) {
- target.addAttribute("name", name);
- }
-
- // Target window size
- if (getTargetWidth() >= 0) {
- target.addAttribute("targetWidth", getTargetWidth());
- }
- if (getTargetHeight() >= 0) {
- target.addAttribute("targetHeight", getTargetHeight());
- }
-
- // Target window border
- switch (getTargetBorder()) {
- case MINIMAL:
- target.addAttribute("border", "minimal");
- break;
- case NONE:
- target.addAttribute("border", "none");
- break;
- }
+ protected LinkState getState() {
+ return (LinkState) super.getState();
+ }
+
+ @Override
+ protected LinkState getState(boolean markAsDirty) {
+ return (LinkState) super.getState(markAsDirty);
}
/**
@@ -150,7 +110,7 @@ public class Link extends AbstractComponent implements LegacyComponent {
* @return the target window border.
*/
public BorderStyle getTargetBorder() {
- return targetBorder;
+ return getState(false).targetBorder;
}
/**
@@ -159,7 +119,8 @@ public class Link extends AbstractComponent implements LegacyComponent {
* @return the target window height.
*/
public int getTargetHeight() {
- return targetHeight < 0 ? -1 : targetHeight;
+ return getState(false).targetHeight < 0 ? -1
+ : getState(false).targetHeight;
}
/**
@@ -169,7 +130,7 @@ public class Link extends AbstractComponent implements LegacyComponent {
* @return the target window name.
*/
public String getTargetName() {
- return targetName;
+ return getState(false).target;
}
/**
@@ -178,7 +139,8 @@ public class Link extends AbstractComponent implements LegacyComponent {
* @return the target window width.
*/
public int getTargetWidth() {
- return targetWidth < 0 ? -1 : targetWidth;
+ return getState(false).targetWidth < 0 ? -1
+ : getState(false).targetWidth;
}
/**
@@ -188,8 +150,7 @@ public class Link extends AbstractComponent implements LegacyComponent {
* the targetBorder to set.
*/
public void setTargetBorder(BorderStyle targetBorder) {
- this.targetBorder = targetBorder;
- markAsDirty();
+ getState().targetBorder = targetBorder;
}
/**
@@ -199,8 +160,7 @@ public class Link extends AbstractComponent implements LegacyComponent {
* the targetHeight to set.
*/
public void setTargetHeight(int targetHeight) {
- this.targetHeight = targetHeight;
- markAsDirty();
+ getState().targetHeight = targetHeight;
}
/**
@@ -210,8 +170,7 @@ public class Link extends AbstractComponent implements LegacyComponent {
* the targetName to set.
*/
public void setTargetName(String targetName) {
- this.targetName = targetName;
- markAsDirty();
+ getState().target = targetName;
}
/**
@@ -221,8 +180,7 @@ public class Link extends AbstractComponent implements LegacyComponent {
* the targetWidth to set.
*/
public void setTargetWidth(int targetWidth) {
- this.targetWidth = targetWidth;
- markAsDirty();
+ getState().targetWidth = targetWidth;
}
/**
@@ -244,8 +202,4 @@ public class Link extends AbstractComponent implements LegacyComponent {
setResource(LinkConstants.HREF_RESOURCE, resource);
}
- @Override
- public void changeVariables(Object source, Map<String, Object> variables) {
- // TODO Remove once LegacyComponent is no longer implemented
- }
}
diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java
index bd2b7828de..32ed738697 100644
--- a/server/src/com/vaadin/ui/Table.java
+++ b/server/src/com/vaadin/ui/Table.java
@@ -427,6 +427,12 @@ public class Table extends AbstractSelect implements Action.Container,
private int currentPageFirstItemIndex = 0;
/**
+ * Index of the "first" item on the last page if a user has used
+ * setCurrentPageFirstItemIndex to scroll down. -1 if not set.
+ */
+ private int currentPageFirstItemIndexOnLastPage = -1;
+
+ /**
* Holds value of property selectable.
*/
private boolean selectable = false;
@@ -1477,12 +1483,14 @@ public class Table extends AbstractSelect implements Action.Container,
}
/*
- * FIXME #7607 Take somehow into account the case where we want to
- * scroll to the bottom so that the last row is completely visible even
- * if (table height) / (row height) is not an integer. Reverted the
- * original fix because of #8662 regression.
+ * If the new index is on the last page we set the index to be the first
+ * item on that last page and make a note of the real index for the
+ * client side to be able to move the scroll position to the correct
+ * position.
*/
+ int indexOnLastPage = -1;
if (newIndex > maxIndex) {
+ indexOnLastPage = newIndex;
newIndex = maxIndex;
}
@@ -1494,6 +1502,20 @@ public class Table extends AbstractSelect implements Action.Container,
currentPageFirstItemId = null;
}
currentPageFirstItemIndex = newIndex;
+
+ if (needsPageBufferReset) {
+ /*
+ * The flag currentPageFirstItemIndexOnLastPage denotes a user
+ * set scrolling position on the last page via
+ * setCurrentPageFirstItemIndex() and shouldn't be changed by
+ * the table component internally changing the firstvisible item
+ * on lazy row fetching. Doing so would make the scrolling
+ * position not be updated correctly when the lazy rows are
+ * finally rendered.
+ */
+ currentPageFirstItemIndexOnLastPage = indexOnLastPage;
+ }
+
} else {
// For containers not supporting indexes, we must iterate the
@@ -3447,6 +3469,8 @@ public class Table extends AbstractSelect implements Action.Container,
if (getCurrentPageFirstItemIndex() != 0 || getPageLength() > 0) {
target.addVariable(this, "firstvisible",
getCurrentPageFirstItemIndex());
+ target.addVariable(this, "firstvisibleonlastpage",
+ currentPageFirstItemIndexOnLastPage);
}
}
diff --git a/server/src/com/vaadin/ui/TreeTable.java b/server/src/com/vaadin/ui/TreeTable.java
index e150db9423..1c13eae8d9 100644
--- a/server/src/com/vaadin/ui/TreeTable.java
+++ b/server/src/com/vaadin/ui/TreeTable.java
@@ -590,11 +590,11 @@ public class TreeTable extends Table implements Hierarchical {
// does not change component hierarchy during paint
containerSupportsPartialUpdates = (newDataSource instanceof ItemSetChangeNotifier) && false;
- if (!(newDataSource instanceof Hierarchical)) {
+ if (newDataSource != null && !(newDataSource instanceof Hierarchical)) {
newDataSource = new ContainerHierarchicalWrapper(newDataSource);
}
- if (!(newDataSource instanceof Ordered)) {
+ if (newDataSource != null && !(newDataSource instanceof Ordered)) {
newDataSource = new HierarchicalContainerOrderedWrapper(
(Hierarchical) newDataSource);
}
diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java
index 8beebb0f1e..a292e6b829 100644
--- a/server/src/com/vaadin/ui/UI.java
+++ b/server/src/com/vaadin/ui/UI.java
@@ -24,6 +24,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
+import java.util.logging.Level;
import java.util.logging.Logger;
import com.vaadin.event.Action;
@@ -31,10 +32,16 @@ import com.vaadin.event.Action.Handler;
import com.vaadin.event.ActionManager;
import com.vaadin.event.MouseEvents.ClickEvent;
import com.vaadin.event.MouseEvents.ClickListener;
+import com.vaadin.event.UIEvents.PollEvent;
+import com.vaadin.event.UIEvents.PollListener;
+import com.vaadin.event.UIEvents.PollNotifier;
import com.vaadin.navigator.Navigator;
import com.vaadin.server.ClientConnector;
import com.vaadin.server.ComponentSizeValidator;
import com.vaadin.server.ComponentSizeValidator.InvalidLayout;
+import com.vaadin.server.DefaultErrorHandler;
+import com.vaadin.server.ErrorHandler;
+import com.vaadin.server.ErrorHandlingRunnable;
import com.vaadin.server.LocaleService;
import com.vaadin.server.Page;
import com.vaadin.server.PaintException;
@@ -91,7 +98,8 @@ import com.vaadin.util.CurrentInstance;
* @since 7.0
*/
public abstract class UI extends AbstractSingleComponentContainer implements
- Action.Container, Action.Notifier, LegacyComponent, Focusable {
+ Action.Container, Action.Notifier, PollNotifier, LegacyComponent,
+ Focusable {
/**
* The application to which this UI belongs
@@ -163,10 +171,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements
@Override
public void poll() {
- /*
- * No-op. This is only called to cause a server visit to check for
- * changes.
- */
+ fireEvent(new PollEvent(UI.this));
}
};
private DebugWindowServerRpc debugRpc = new DebugWindowServerRpc() {
@@ -405,9 +410,12 @@ public abstract class UI extends AbstractSingleComponentContainer implements
* @see #getSession()
*/
public void setSession(VaadinSession session) {
- if ((session == null) == (this.session == null)) {
+ if (session == null && this.session == null) {
+ throw new IllegalStateException(
+ "Session should never be set to null when UI.session is already null");
+ } else if (session != null && this.session != null) {
throw new IllegalStateException(
- "VaadinServiceSession has already been set. Old session: "
+ "Session has already been set. Old session: "
+ getSessionDetails(this.session)
+ ". New session: " + getSessionDetails(session)
+ ".");
@@ -1296,11 +1304,36 @@ public abstract class UI extends AbstractSingleComponentContainer implements
throw new UIDetachedException();
}
- return session.access(new Runnable() {
+ return session.access(new ErrorHandlingRunnable() {
@Override
public void run() {
accessSynchronously(runnable);
}
+
+ @Override
+ public void handleError(Exception exception) {
+ try {
+ if (runnable instanceof ErrorHandlingRunnable) {
+ ErrorHandlingRunnable errorHandlingRunnable = (ErrorHandlingRunnable) runnable;
+
+ errorHandlingRunnable.handleError(exception);
+ } else {
+ ConnectorErrorEvent errorEvent = new ConnectorErrorEvent(
+ UI.this, exception);
+
+ ErrorHandler errorHandler = com.vaadin.server.ErrorEvent
+ .findErrorHandler(UI.this);
+
+ if (errorHandler == null) {
+ errorHandler = new DefaultErrorHandler();
+ }
+
+ errorHandler.error(errorEvent);
+ }
+ } catch (Exception e) {
+ getLogger().log(Level.SEVERE, e.getMessage(), e);
+ }
+ }
});
}
@@ -1458,6 +1491,17 @@ public abstract class UI extends AbstractSingleComponentContainer implements
return getState(false).pollInterval;
}
+ @Override
+ public void addPollListener(PollListener listener) {
+ addListener(EventId.POLL, PollEvent.class, listener,
+ PollListener.POLL_METHOD);
+ }
+
+ @Override
+ public void removePollListener(PollListener listener) {
+ removeListener(EventId.POLL, PollEvent.class, listener);
+ }
+
/**
* Retrieves the object used for configuring the push channel.
*
diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java
index 8e7c6dbc80..d3afdaacf1 100644
--- a/server/src/com/vaadin/ui/Window.java
+++ b/server/src/com/vaadin/ui/Window.java
@@ -82,6 +82,16 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
public void windowModeChanged(WindowMode newState) {
setWindowMode(newState);
}
+
+ @Override
+ public void windowMoved(int x, int y) {
+ if (x != getState(false).positionX) {
+ setPositionX(x);
+ }
+ if (y != getState(false).positionY) {
+ setPositionY(y);
+ }
+ }
};
/**