summaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'server/src')
-rw-r--r--server/src/com/vaadin/data/Buffered.java58
-rw-r--r--server/src/com/vaadin/data/fieldgroup/FieldGroup.java6
-rw-r--r--server/src/com/vaadin/data/util/filter/Between.java4
-rw-r--r--server/src/com/vaadin/data/util/filter/Compare.java3
-rw-r--r--server/src/com/vaadin/data/util/filter/IsNull.java4
-rw-r--r--server/src/com/vaadin/data/util/filter/Like.java4
-rw-r--r--server/src/com/vaadin/data/util/filter/SimpleStringFilter.java3
-rw-r--r--server/src/com/vaadin/event/EventRouter.java39
-rw-r--r--server/src/com/vaadin/server/Constants.java2
-rw-r--r--server/src/com/vaadin/server/JsonCodec.java15
-rw-r--r--server/src/com/vaadin/server/LegacyCommunicationManager.java2
-rw-r--r--server/src/com/vaadin/server/VaadinPortlet.java1
-rw-r--r--server/src/com/vaadin/server/VaadinService.java15
-rw-r--r--server/src/com/vaadin/server/VaadinSession.java29
-rw-r--r--server/src/com/vaadin/server/communication/AtmospherePushConnection.java146
-rw-r--r--server/src/com/vaadin/server/communication/DateSerializer.java42
-rw-r--r--server/src/com/vaadin/server/communication/JSONSerializer.java72
-rw-r--r--server/src/com/vaadin/server/communication/PushConnection.java14
-rw-r--r--server/src/com/vaadin/server/communication/PushHandler.java52
-rw-r--r--server/src/com/vaadin/server/communication/PushRequestHandler.java14
-rw-r--r--server/src/com/vaadin/server/communication/ServerRpcHandler.java4
-rw-r--r--server/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java75
-rw-r--r--server/src/com/vaadin/ui/AbstractComponent.java30
-rw-r--r--server/src/com/vaadin/ui/AbstractField.java21
-rw-r--r--server/src/com/vaadin/ui/AbstractSelect.java31
-rw-r--r--server/src/com/vaadin/ui/Calendar.java4
-rw-r--r--server/src/com/vaadin/ui/ComboBox.java2
-rw-r--r--server/src/com/vaadin/ui/FormLayout.java19
-rw-r--r--server/src/com/vaadin/ui/Label.java4
-rw-r--r--server/src/com/vaadin/ui/PushConfiguration.java42
-rw-r--r--server/src/com/vaadin/ui/Table.java1
-rw-r--r--server/src/com/vaadin/ui/UI.java83
-rw-r--r--server/src/com/vaadin/ui/Upload.java14
33 files changed, 569 insertions, 286 deletions
diff --git a/server/src/com/vaadin/data/Buffered.java b/server/src/com/vaadin/data/Buffered.java
index 0d6722f71f..c4c79ae13f 100644
--- a/server/src/com/vaadin/data/Buffered.java
+++ b/server/src/com/vaadin/data/Buffered.java
@@ -23,29 +23,20 @@ import com.vaadin.data.Validator.InvalidValueException;
/**
* <p>
* Defines the interface to commit and discard changes to an object, supporting
- * read-through and write-through modes.
- * </p>
+ * buffering.
*
* <p>
- * <i>Read-through mode</i> means that the value read from the buffered object
- * is constantly up to date with the data source. <i>Write-through</i> mode
- * means that all changes to the object are immediately updated to the data
- * source.
- * </p>
+ * In <i>buffered</i> mode the initial value is read from the data source and
+ * then buffered. Any subsequential writes or reads will be done on the buffered
+ * value. Calling {@link #commit()} will write the buffered value to the data
+ * source while calling {@link #discard()} while discard the buffered value and
+ * re-read the value from the data source.
*
* <p>
- * Since these modes are independent, their combinations may result in some
- * behaviour that may sound surprising.
- * </p>
- *
- * <p>
- * For example, if a <code>Buffered</code> object is in read-through mode but
- * not in write-through mode, the result is an object whose value is updated
- * directly from the data source only if it's not locally modified. If the value
- * is locally modified, retrieving the value from the object would result in a
- * value that is different than the one stored in the data source, even though
- * the object is in read-through mode.
- * </p>
+ * In <i>non-buffered</i> mode the value is always read directly from the data
+ * source. Any write is done directly to the data source with no buffering in
+ * between. Reads are also done directly from the data source. Calling
+ * {@link #commit()} or {@link #discard()} in this mode is efficiently a no-op.
*
* @author Vaadin Ltd.
* @since 3.0
@@ -77,25 +68,15 @@ public interface Buffered extends Serializable {
public void discard() throws SourceException;
/**
- * Sets the object's buffered mode to the specified status.
+ * Sets the buffered mode to the specified status.
* <p>
- * When the object is in buffered mode, an internal buffer will be used to
- * store changes until {@link #commit()} is called. Calling
- * {@link #discard()} will revert the internal buffer to the value of the
- * data source.
- * </p>
+ * When in buffered mode, an internal buffer will be used to store changes
+ * until {@link #commit()} is called. Calling {@link #discard()} will revert
+ * the internal buffer to the value of the data source.
* <p>
- * This is an easier way to use {@link #setReadThrough(boolean)} and
- * {@link #setWriteThrough(boolean)} and not as error prone. Changing
- * buffered mode will change both the read through and write through state
- * of the object.
- * </p>
- * <p>
- * Mixing calls to {@link #setBuffered(boolean)}/{@link #isBuffered()} and
- * {@link #setReadThrough(boolean)}/{@link #isReadThrough()} or
- * {@link #setWriteThrough(boolean)}/{@link #isWriteThrough()} is generally
- * a bad idea.
- * </p>
+ * When in non-buffered mode both read and write operations will be done
+ * directly on the data source. In this mode the {@link #commit()} and
+ * {@link #discard()} methods serve no purpose.
*
* @param buffered
* true if buffered mode should be turned on, false otherwise
@@ -104,10 +85,7 @@ public interface Buffered extends Serializable {
public void setBuffered(boolean buffered);
/**
- * Checks the buffered mode of this Object.
- * <p>
- * This method only returns true if both read and write buffering is used.
- * </p>
+ * Checks the buffered mode
*
* @return true if buffered mode is on, false otherwise
* @since 7.0
diff --git a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java
index 23f2da53ce..7edcc9719c 100644
--- a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java
+++ b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java
@@ -23,7 +23,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.logging.Logger;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
@@ -55,9 +54,6 @@ import com.vaadin.util.ReflectTools;
*/
public class FieldGroup implements Serializable {
- private static final Logger logger = Logger.getLogger(FieldGroup.class
- .getName());
-
private Item itemDataSource;
private boolean buffered = true;
@@ -1013,9 +1009,7 @@ public class FieldGroup implements Serializable {
*/
public Field<?> buildAndBind(String caption, Object propertyId)
throws BindException {
- Class<?> type = getPropertyType(propertyId);
return buildAndBind(caption, propertyId, Field.class);
-
}
/**
diff --git a/server/src/com/vaadin/data/util/filter/Between.java b/server/src/com/vaadin/data/util/filter/Between.java
index 8209f7b0a2..a76821981a 100644
--- a/server/src/com/vaadin/data/util/filter/Between.java
+++ b/server/src/com/vaadin/data/util/filter/Between.java
@@ -67,6 +67,10 @@ public class Between implements Filter {
@Override
public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
// Only objects of the same class can be equal
if (!getClass().equals(obj.getClass())) {
return false;
diff --git a/server/src/com/vaadin/data/util/filter/Compare.java b/server/src/com/vaadin/data/util/filter/Compare.java
index f9f19c6602..ac167673bd 100644
--- a/server/src/com/vaadin/data/util/filter/Compare.java
+++ b/server/src/com/vaadin/data/util/filter/Compare.java
@@ -307,6 +307,9 @@ public abstract class Compare implements Filter {
@Override
public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
// Only objects of the same class can be equal
if (!getClass().equals(obj.getClass())) {
diff --git a/server/src/com/vaadin/data/util/filter/IsNull.java b/server/src/com/vaadin/data/util/filter/IsNull.java
index 5c5bdfc0b1..6907a016a1 100644
--- a/server/src/com/vaadin/data/util/filter/IsNull.java
+++ b/server/src/com/vaadin/data/util/filter/IsNull.java
@@ -62,6 +62,10 @@ public final class IsNull implements Filter {
@Override
public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
// Only objects of the same class can be equal
if (!getClass().equals(obj.getClass())) {
return false;
diff --git a/server/src/com/vaadin/data/util/filter/Like.java b/server/src/com/vaadin/data/util/filter/Like.java
index 4c15564105..dc2e18363a 100644
--- a/server/src/com/vaadin/data/util/filter/Like.java
+++ b/server/src/com/vaadin/data/util/filter/Like.java
@@ -84,6 +84,10 @@ public class Like implements Filter {
@Override
public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
// Only objects of the same class can be equal
if (!getClass().equals(obj.getClass())) {
return false;
diff --git a/server/src/com/vaadin/data/util/filter/SimpleStringFilter.java b/server/src/com/vaadin/data/util/filter/SimpleStringFilter.java
index bc58999445..a214e69846 100644
--- a/server/src/com/vaadin/data/util/filter/SimpleStringFilter.java
+++ b/server/src/com/vaadin/data/util/filter/SimpleStringFilter.java
@@ -82,6 +82,9 @@ public final class SimpleStringFilter implements Filter {
@Override
public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
// Only ones of the objects of the same class can be equal
if (!(obj instanceof SimpleStringFilter)) {
diff --git a/server/src/com/vaadin/event/EventRouter.java b/server/src/com/vaadin/event/EventRouter.java
index 73bfa33881..fdc543143b 100644
--- a/server/src/com/vaadin/event/EventRouter.java
+++ b/server/src/com/vaadin/event/EventRouter.java
@@ -23,6 +23,10 @@ import java.util.EventObject;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.logging.Logger;
+
+import com.vaadin.server.ErrorEvent;
+import com.vaadin.server.ErrorHandler;
/**
* <code>EventRouter</code> class implementing the inheritable event listening
@@ -154,6 +158,25 @@ public class EventRouter implements MethodEventSource {
* the Event to be sent to all listeners.
*/
public void fireEvent(EventObject event) {
+ fireEvent(event, null);
+ }
+
+ /**
+ * Sends an event to all registered listeners. The listeners will decide if
+ * the activation method should be called or not.
+ * <p>
+ * If an error handler is set, the processing of other listeners will
+ * continue after the error handler method call unless the error handler
+ * itself throws an exception.
+ *
+ * @param event
+ * the Event to be sent to all listeners.
+ * @param errorHandler
+ * error handler to use to handle any exceptions thrown by
+ * listeners or null to let the exception propagate to the
+ * caller, preventing further listener calls
+ */
+ public void fireEvent(EventObject event, ErrorHandler errorHandler) {
// It is not necessary to send any events if there are no listeners
if (listenerList != null) {
@@ -164,7 +187,16 @@ public class EventRouter implements MethodEventSource {
// will filter out unwanted events.
final Object[] listeners = listenerList.toArray();
for (int i = 0; i < listeners.length; i++) {
- ((ListenerMethod) listeners[i]).receiveEvent(event);
+ ListenerMethod listenerMethod = (ListenerMethod) listeners[i];
+ if (null != errorHandler) {
+ try {
+ listenerMethod.receiveEvent(event);
+ } catch (Exception e) {
+ errorHandler.error(new ErrorEvent(e));
+ }
+ } else {
+ listenerMethod.receiveEvent(event);
+ }
}
}
@@ -208,4 +240,9 @@ public class EventRouter implements MethodEventSource {
}
return listeners;
}
+
+ private Logger getLogger() {
+ return Logger.getLogger(EventRouter.class.getName());
+ }
+
}
diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java
index b0841da314..a39c39fa72 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_RUNTIME_VERSION = "1.0.18.vaadin1";
+ static final String REQUIRED_ATMOSPHERE_RUNTIME_VERSION = "2.0.3.vaadin1";
static final String INVALID_ATMOSPHERE_VERSION_WARNING = "\n"
+ "=================================================================\n"
diff --git a/server/src/com/vaadin/server/JsonCodec.java b/server/src/com/vaadin/server/JsonCodec.java
index d533ed99f3..129307e5c1 100644
--- a/server/src/com/vaadin/server/JsonCodec.java
+++ b/server/src/com/vaadin/server/JsonCodec.java
@@ -31,6 +31,7 @@ import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -45,6 +46,8 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import com.vaadin.server.communication.DateSerializer;
+import com.vaadin.server.communication.JSONSerializer;
import com.vaadin.shared.Connector;
import com.vaadin.shared.JsonConstants;
import com.vaadin.shared.communication.UidlValue;
@@ -176,6 +179,11 @@ public class JsonCodec implements Serializable {
*/
private static Map<String, Class<?>> transportTypeToType = new HashMap<String, Class<?>>();
+ private static Map<Class<?>, JSONSerializer<?>> customSerializers = new HashMap<Class<?>, JSONSerializer<?>>();
+ static {
+ customSerializers.put(Date.class, new DateSerializer());
+ }
+
static {
registerType(String.class, JsonConstants.VTYPE_STRING);
registerType(Connector.class, JsonConstants.VTYPE_CONNECTOR);
@@ -283,6 +291,9 @@ public class JsonCodec implements Serializable {
Class<?> classForType = getClassForType(targetType);
return decodeEnum(classForType.asSubclass(Enum.class),
(String) value);
+ } else if (customSerializers.containsKey(getClassForType(targetType))) {
+ return customSerializers.get(getClassForType(targetType))
+ .deserialize(targetType, value, connectorTracker);
} else {
return decodeObject(targetType, (JSONObject) value,
connectorTracker);
@@ -676,6 +687,10 @@ public class JsonCodec implements Serializable {
return encodeEnum((Enum<?>) value, connectorTracker);
} else if (value instanceof JSONArray || value instanceof JSONObject) {
return new EncodeResult(value);
+ } else if (customSerializers.containsKey(value.getClass())) {
+ JSONSerializer serializer = customSerializers.get(value.getClass());
+ return new EncodeResult(serializer.serialize(value,
+ connectorTracker));
} else if (valueType instanceof Class<?>) {
// Any object that we do not know how to encode we encode by looping
// through fields
diff --git a/server/src/com/vaadin/server/LegacyCommunicationManager.java b/server/src/com/vaadin/server/LegacyCommunicationManager.java
index ad662cf6df..8d61968b47 100644
--- a/server/src/com/vaadin/server/LegacyCommunicationManager.java
+++ b/server/src/com/vaadin/server/LegacyCommunicationManager.java
@@ -316,8 +316,6 @@ public class LegacyCommunicationManager implements Serializable {
private final HashMap<Class<? extends ClientConnector>, Integer> typeToKey = new HashMap<Class<? extends ClientConnector>, Integer>();
private int nextTypeKey = 0;
- private BootstrapHandler bootstrapHandler;
-
/**
* @deprecated As of 7.1. Will be removed in the future.
*/
diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java
index a41f301219..6cf30e85e9 100644
--- a/server/src/com/vaadin/server/VaadinPortlet.java
+++ b/server/src/com/vaadin/server/VaadinPortlet.java
@@ -365,7 +365,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
if (request instanceof RenderRequest) {
return RequestType.RENDER;
} else if (request instanceof ResourceRequest) {
- ResourceRequest resourceRequest = (ResourceRequest) request;
if (ServletPortletHelper.isUIDLRequest(vaadinRequest)) {
return RequestType.UIDL;
} else if (PortletUIInitHandler.isUIInitRequest(vaadinRequest)) {
diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java
index aff0124d16..b457436b8f 100644
--- a/server/src/com/vaadin/server/VaadinService.java
+++ b/server/src/com/vaadin/server/VaadinService.java
@@ -420,6 +420,9 @@ public abstract class VaadinService implements Serializable {
/**
* Adds a listener that gets notified when a Vaadin service session that has
* been initialized for this service is destroyed.
+ * <p>
+ * The session being destroyed is locked and its UIs have been removed when
+ * the listeners are called.
*
* @see #addSessionInitListener(SessionInitListener)
*
@@ -461,8 +464,11 @@ public abstract class VaadinService implements Serializable {
}
});
}
+ // for now, use the session error handler; in the future, could
+ // have an API for using some other handler for session init and
+ // destroy listeners
eventRouter.fireEvent(new SessionDestroyEvent(
- VaadinService.this, session));
+ VaadinService.this, session), session.getErrorHandler());
}
});
}
@@ -776,7 +782,12 @@ public abstract class VaadinService implements Serializable {
private void onVaadinSessionStarted(VaadinRequest request,
VaadinSession session) throws ServiceException {
- eventRouter.fireEvent(new SessionInitEvent(this, session, request));
+ // for now, use the session error handler; in the future, could have an
+ // API for using some other handler for session init and destroy
+ // listeners
+
+ eventRouter.fireEvent(new SessionInitEvent(this, session, request),
+ session.getErrorHandler());
ServletPortletHelper.checkUiProviders(session, this);
}
diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java
index f34721944a..265d18b859 100644
--- a/server/src/com/vaadin/server/VaadinSession.java
+++ b/server/src/com/vaadin/server/VaadinSession.java
@@ -22,12 +22,15 @@ import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
+import java.util.Enumeration;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Queue;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
@@ -423,6 +426,32 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
}
/**
+ * Retrieves all {@link VaadinSession}s which are stored in the given HTTP
+ * session
+ *
+ * @since 7.2
+ * @param httpSession
+ * the HTTP session
+ * @return the found VaadinSessions
+ */
+ public static Collection<VaadinSession> getAllSessions(
+ HttpSession httpSession) {
+ Set<VaadinSession> sessions = new HashSet<VaadinSession>();
+ Enumeration<String> attributeNames = httpSession.getAttributeNames();
+
+ while (attributeNames.hasMoreElements()) {
+ String attributeName = attributeNames.nextElement();
+ if (attributeName.startsWith(VaadinSession.class.getName() + ".")) {
+ Object value = httpSession.getAttribute(attributeName);
+ if (value instanceof VaadinSession) {
+ sessions.add((VaadinSession) value);
+ }
+ }
+ }
+ return sessions;
+ }
+
+ /**
* Removes this VaadinSession from the HTTP session.
*
* @param service
diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java
index b9d4955b12..56dd576403 100644
--- a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java
+++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java
@@ -22,22 +22,16 @@ import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResource.TRANSPORT;
-import org.json.JSONException;
import com.vaadin.shared.communication.PushConstants;
import com.vaadin.ui.UI;
/**
- * {@link PushConnection} implementation using the Atmosphere push support that
- * is by default included in Vaadin.
+ * A {@link PushConnection} implementation using the Atmosphere push support
+ * that is by default included in Vaadin.
*
* @author Vaadin Ltd
* @since 7.1
@@ -92,55 +86,84 @@ public class AtmospherePushConnection implements PushConnection {
}
}
+ protected enum State {
+ /**
+ * Not connected. Trying to push will set the connection state to
+ * PUSH_PENDING or RESPONSE_PENDING and defer sending the message until
+ * a connection is established.
+ */
+ DISCONNECTED,
+
+ /**
+ * Not connected. An asynchronous push is pending the opening of the
+ * connection.
+ */
+ PUSH_PENDING,
+
+ /**
+ * Not connected. A response to a client request is pending the opening
+ * of the connection.
+ */
+ RESPONSE_PENDING,
+
+ /**
+ * Connected. Messages can be sent through the connection.
+ */
+ CONNECTED;
+ }
+
+ private State state = State.DISCONNECTED;
private UI ui;
private AtmosphereResource resource;
- private Future<String> outgoingMessage;
private FragmentedMessage incomingMessage;
- public AtmospherePushConnection(UI ui, AtmosphereResource resource) {
+ public AtmospherePushConnection(UI ui) {
this.ui = ui;
- this.resource = resource;
}
@Override
public void push() {
- assert isConnected();
- try {
- push(true);
- } catch (IOException e) {
- // TODO Error handling
- throw new RuntimeException("Push failed", e);
- }
+ push(true);
}
/**
- * Pushes pending state changes and client RPC calls to the client.
+ * Pushes pending state changes and client RPC calls to the client. If
+ * {@code isConnected()} is false, defers the push until a connection is
+ * established.
*
* @param async
* True if this push asynchronously originates from the server,
* false if it is a response to a client request.
- * @throws IOException
*/
- protected void push(boolean async) throws IOException {
- Writer writer = new StringWriter();
- try {
- new UidlWriter().write(getUI(), writer, false, async);
- } catch (JSONException e) {
- throw new IOException("Error writing UIDL", e);
+ public void push(boolean async) {
+ if (!isConnected()) {
+ if (async && state != State.RESPONSE_PENDING) {
+ state = State.PUSH_PENDING;
+ } else {
+ state = State.RESPONSE_PENDING;
+ }
+ } else {
+ try {
+ Writer writer = new StringWriter();
+ new UidlWriter().write(getUI(), writer, false, async);
+ sendMessage("for(;;);[{" + writer.toString() + "}]");
+ } catch (Exception e) {
+ throw new RuntimeException("Push failed", e);
+ }
}
- sendMessage("for(;;);[{" + writer.toString() + "}]");
}
/**
- * Sends the given message to the current client.
+ * Sends the given message to the current client. Cannot be called if
+ * {@isConnected()} is false.
*
* @param message
* The message to send
*/
void sendMessage(String message) {
+ assert (isConnected());
// "Broadcast" the changes to the single client only
- outgoingMessage = getResource().getBroadcaster().broadcast(message,
- getResource());
+ getResource().getBroadcaster().broadcast(message, getResource());
}
/**
@@ -157,7 +180,7 @@ public class AtmospherePushConnection implements PushConnection {
*/
protected Reader receiveMessage(Reader reader) throws IOException {
- if (resource.transport() != TRANSPORT.WEBSOCKET) {
+ if (resource == null || resource.transport() != TRANSPORT.WEBSOCKET) {
return reader;
}
@@ -179,9 +202,37 @@ public class AtmospherePushConnection implements PushConnection {
@Override
public boolean isConnected() {
- return resource != null
- && resource.getBroadcaster().getAtmosphereResources()
- .contains(resource);
+ assert (state == State.CONNECTED) ^ (resource == null);
+ return state == State.CONNECTED;
+ }
+
+ /**
+ * Associates this {@code AtmospherePushConnection} with the given
+ * {@AtmosphereResource} representing an established
+ * push connection. If already connected, calls {@link #disconnect()} first.
+ * If there is a deferred push, carries it out via the new connection.
+ *
+ * @since 7.2
+ */
+ public void connect(AtmosphereResource resource) {
+
+ assert resource != null;
+ assert resource != this.resource;
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ this.resource = resource;
+ State oldState = state;
+ state = State.CONNECTED;
+
+ if (oldState == State.PUSH_PENDING
+ || oldState == State.RESPONSE_PENDING) {
+ // Sending a "response" message (async=false) also takes care of a
+ // pending push, but not vice versa
+ push(oldState == State.PUSH_PENDING);
+ }
}
/**
@@ -202,33 +253,8 @@ public class AtmospherePushConnection implements PushConnection {
@Override
public void disconnect() {
assert isConnected();
-
- if (outgoingMessage != null) {
- // Wait for the last message to be sent before closing the
- // connection (assumes that futures are completed in order)
- try {
- outgoingMessage.get(1000, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- getLogger()
- .log(Level.INFO,
- "Timeout waiting for messages to be sent to client before disconnect");
- } catch (Exception e) {
- getLogger()
- .log(Level.INFO,
- "Error waiting for messages to be sent to client before disconnect");
- }
- outgoingMessage = null;
- }
-
resource.resume();
resource = null;
- }
-
- /**
- * @since
- * @return
- */
- private static Logger getLogger() {
- return Logger.getLogger(AtmospherePushConnection.class.getName());
+ state = State.DISCONNECTED;
}
}
diff --git a/server/src/com/vaadin/server/communication/DateSerializer.java b/server/src/com/vaadin/server/communication/DateSerializer.java
new file mode 100644
index 0000000000..9179eb922b
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/DateSerializer.java
@@ -0,0 +1,42 @@
+/*
+ * 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.communication;
+
+import java.lang.reflect.Type;
+import java.util.Date;
+
+import com.vaadin.ui.ConnectorTracker;
+
+/**
+ * Server side serializer/deserializer for java.util.Date
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public class DateSerializer implements JSONSerializer<Date> {
+
+ @Override
+ public Date deserialize(Type type, Object jsonValue,
+ ConnectorTracker connectorTracker) {
+ return new Date(Long.valueOf(String.valueOf(jsonValue)));
+ }
+
+ @Override
+ public Object serialize(Date value, ConnectorTracker connectorTracker) {
+ return value.getTime();
+ }
+
+}
diff --git a/server/src/com/vaadin/server/communication/JSONSerializer.java b/server/src/com/vaadin/server/communication/JSONSerializer.java
new file mode 100644
index 0000000000..fe609c70b6
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/JSONSerializer.java
@@ -0,0 +1,72 @@
+/*
+ * 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.communication;
+
+import java.lang.reflect.Type;
+
+import com.vaadin.ui.ConnectorTracker;
+
+/**
+ * Implementors of this interface knows how to serialize an Object of a given
+ * type to JSON and how to deserialize the JSON back into an object.
+ * <p>
+ * The {@link #serialize(Object, ConnectorTracker)} and
+ * {@link #deserialize(Type, Object, ConnectorTracker)} methods must be
+ * symmetric so they can be chained and produce the original result (or an equal
+ * result).
+ * <p>
+ * Each {@link JSONSerializer} implementation can handle an object of a single
+ * type.
+ * <p>
+ * This is the server side interface, see
+ * com.vaadin.client.communication.JSONSerializer for the client side interface.
+ *
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public interface JSONSerializer<T> {
+ /**
+ * Creates and deserializes an object received from the client. Must be
+ * compatible with {@link #serialize(Object, ConnectorTracker)} and also
+ * with the client side com.vaadin.client.communication.JSONSerializer.
+ * <p>
+ * The json parameter is of type Object as org.json JSON classes have no
+ * other common super class
+ *
+ * @param type
+ * The expected return type
+ * @param jsonValue
+ * the value from the JSON
+ * @param connectorTracker
+ * the connector tracker instance for the UI
+ * @return A deserialized object
+ */
+ T deserialize(Type type, Object jsonValue, ConnectorTracker connectorTracker);
+
+ /**
+ * Serialize the given object into JSON. Must be compatible with
+ * {@link #deserialize(Object, connectorTracker)} and the client side
+ * com.vaadin.client.communication.JSONSerializer
+ *
+ * @param value
+ * The object to serialize
+ * @param connectorTracker
+ * The connector tracker instance for the UI
+ * @return A JSON serialized version of the object
+ */
+ Object serialize(T value, ConnectorTracker connectorTracker);
+
+}
diff --git a/server/src/com/vaadin/server/communication/PushConnection.java b/server/src/com/vaadin/server/communication/PushConnection.java
index 7f78d1d48e..cab3c94824 100644
--- a/server/src/com/vaadin/server/communication/PushConnection.java
+++ b/server/src/com/vaadin/server/communication/PushConnection.java
@@ -20,7 +20,12 @@ import com.vaadin.ui.UI;
/**
* Represents a bidirectional ("push") connection between a single UI and its
- * client-side.
+ * client-side. A single {@code PushConnection} instance is bound to a UI as
+ * long as push is enabled in that UI, even if the actual connection is
+ * momentarily dropped either due to a network failure or as a normal part of
+ * the transport mechanism.
+ * <p>
+ * This interface is an internal API, only meant to be used by the framework.
*
* @author Vaadin Ltd
* @since 7.1
@@ -28,9 +33,10 @@ import com.vaadin.ui.UI;
public interface PushConnection {
/**
- * Pushes pending state changes and client RPC calls to the client. Cannot
- * be called if {@link #isConnected()} is false. It is NOT safe to invoke
- * this method if not holding the session lock.
+ * Pushes pending state changes and client RPC calls to the client. Can be
+ * called even if {@link #isConnected()} is false; the push will be deferred
+ * until a connection is available. It is NOT safe to invoke this method if
+ * not holding the session lock.
* <p>
* This is internal API; please use {@link UI#push()} instead.
*/
diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java
index 09428e47a9..99aff3780f 100644
--- a/server/src/com/vaadin/server/communication/PushHandler.java
+++ b/server/src/com/vaadin/server/communication/PushHandler.java
@@ -19,7 +19,6 @@ package com.vaadin.server.communication;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
-import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -43,7 +42,6 @@ import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinServletRequest;
import com.vaadin.server.VaadinServletService;
import com.vaadin.server.VaadinSession;
-import com.vaadin.server.WebBrowser;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.communication.PushMode;
import com.vaadin.ui.UI;
@@ -75,8 +73,8 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
@Override
public void run(AtmosphereResource resource, UI ui) throws IOException {
getLogger().log(Level.FINER,
- "New push connection with transport {0}",
- resource.transport());
+ "New push connection for resource {0} with transport {1}",
+ new Object[] { resource.uuid(), resource.transport() });
resource.addEventListener(PushHandler.this);
@@ -84,14 +82,6 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
VaadinSession session = ui.getSession();
if (resource.transport() == TRANSPORT.STREAMING) {
- // IE8 requires a longer padding to work properly if the
- // initial message is small (#11573). Chrome does not work
- // without the original padding...
- WebBrowser browser = session.getBrowser();
- if (browser.isIE() && browser.getBrowserMajorVersion() == 8) {
- resource.padding(LONG_PADDING);
- }
-
// Must ensure that the streaming response contains
// "Connection: close", otherwise iOS 6 will wait for the
// response to this request before sending another request to
@@ -115,10 +105,9 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
resource.suspend();
- AtmospherePushConnection connection = new AtmospherePushConnection(
- ui, resource);
-
- ui.setPushConnection(connection);
+ AtmospherePushConnection connection = getConnectionForUI(ui);
+ assert (connection != null);
+ connection.connect(resource);
}
};
@@ -182,11 +171,11 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
@Override
public void run(AtmosphereResource resource, UI ui) throws IOException {
PushMode pushMode = ui.getPushConfiguration().getPushMode();
- AtmospherePushConnection pushConnection = getConnectionForUI(ui);
+ AtmospherePushConnection connection = getConnectionForUI(ui);
String id = resource.uuid();
- if (pushConnection == null) {
+ if (connection == null) {
getLogger()
.log(Level.WARNING,
"Could not find push connection to close: {0} with transport {1}",
@@ -209,19 +198,11 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
"Connection unexpectedly closed for resource {0} with transport {1}",
new Object[] { id, resource.transport() });
}
- ui.setPushConnection(null);
+ connection.disconnect();
}
}
};
- private static final String LONG_PADDING;
-
- static {
- char[] array = new char[4096];
- Arrays.fill(array, '-');
- LONG_PADDING = String.copyValueOf(array);
-
- }
private VaadinServletService service;
public PushHandler(VaadinServletService service) {
@@ -351,10 +332,10 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
private static AtmospherePushConnection getConnectionForUI(UI ui) {
PushConnection pushConnection = ui.getPushConnection();
if (pushConnection instanceof AtmospherePushConnection) {
- assert pushConnection.isConnected();
return (AtmospherePushConnection) pushConnection;
+ } else {
+ return null;
}
- return null;
}
@Override
@@ -391,7 +372,7 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
break;
case JSONP:
case LONG_POLLING:
- resource.resume();
+ disconnect(event);
break;
default:
getLogger().log(Level.SEVERE, "Unknown transport {0}",
@@ -415,13 +396,6 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
}
@Override
- public void onResume(AtmosphereResourceEvent event) {
- // Log event on trace level
- super.onResume(event);
- disconnect(event);
- }
-
- @Override
public void destroy() {
}
@@ -444,8 +418,8 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter
*/
private static void sendRefreshAndDisconnect(AtmosphereResource resource)
throws IOException {
- AtmospherePushConnection connection = new AtmospherePushConnection(
- null, resource);
+ AtmospherePushConnection connection = new AtmospherePushConnection(null);
+ connection.connect(resource);
try {
connection.sendMessage(VaadinService
.createCriticalNotificationJSON(null, null, null, null));
diff --git a/server/src/com/vaadin/server/communication/PushRequestHandler.java b/server/src/com/vaadin/server/communication/PushRequestHandler.java
index 74595322a0..f3869a76f8 100644
--- a/server/src/com/vaadin/server/communication/PushRequestHandler.java
+++ b/server/src/com/vaadin/server/communication/PushRequestHandler.java
@@ -18,6 +18,7 @@ package com.vaadin.server.communication;
import java.io.IOException;
+import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import org.atmosphere.client.TrackMessageSizeInterceptor;
@@ -58,11 +59,22 @@ public class PushRequestHandler implements RequestHandler,
public PushRequestHandler(VaadinServletService service)
throws ServiceException {
+ final ServletConfig config = service.getServlet().getServletConfig();
+
atmosphere = new AtmosphereFramework() {
@Override
protected void analytics() {
// Overridden to disable version number check
}
+
+ @Override
+ public AtmosphereFramework addInitParameter(String name,
+ String value) {
+ if (config.getInitParameter(name) == null) {
+ super.addInitParameter(name, value);
+ }
+ return this;
+ }
};
service.addServiceDestroyListener(new ServiceDestroyListener() {
@@ -93,7 +105,7 @@ public class PushRequestHandler implements RequestHandler,
"false");
try {
- atmosphere.init(service.getServlet().getServletConfig());
+ atmosphere.init(config);
// Ensure the client-side knows how to split the message stream
// into individual messages when using certain transports
diff --git a/server/src/com/vaadin/server/communication/ServerRpcHandler.java b/server/src/com/vaadin/server/communication/ServerRpcHandler.java
index 432a9ea893..ce9cec5e2a 100644
--- a/server/src/com/vaadin/server/communication/ServerRpcHandler.java
+++ b/server/src/com/vaadin/server/communication/ServerRpcHandler.java
@@ -68,7 +68,7 @@ public class ServerRpcHandler implements Serializable {
* @since 7.2
* @author Vaadin Ltd
*/
- public static class RpcRequest {
+ public static class RpcRequest implements Serializable {
private final String csrfToken;
private final JSONArray invocations;
@@ -439,7 +439,7 @@ public class ServerRpcHandler implements Serializable {
"Ignoring RPC call to " + interfaceName + "." + methodName
+ " in connector " + connector.getClass().getName()
+ "(" + connectorId
- + ") as no RPC implementation is regsitered");
+ + ") as no RPC implementation is registered");
return null;
}
diff --git a/server/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java b/server/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java
index cc04e50b3c..3ad76794de 100644
--- a/server/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java
+++ b/server/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java
@@ -32,8 +32,6 @@ import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
-import java.util.logging.Level;
-import java.util.logging.Logger;
/**
* Utility class to collect widgetset related information from classpath.
@@ -111,6 +109,15 @@ public class ClassPathExplorer {
*/
private static Map<String, URL> classpathLocations = getClasspathLocations(rawClasspathEntries);
+ private static boolean debug = false;
+
+ static {
+ String debugProperty = System.getProperty("debug");
+ if (debugProperty != null && !debugProperty.equals("")) {
+ debug = true;
+ }
+ }
+
/**
* No instantiation from outside, callable methods are static.
*/
@@ -163,9 +170,8 @@ public class ClassPathExplorer {
sb.append("\n");
}
- final Logger logger = getLogger();
- logger.info(sb.toString());
- logger.info("Search took " + (end - start) + "ms");
+ log(sb.toString());
+ log("Search took " + (end - start) + "ms");
return new LocationInfo(widgetsets, themes);
}
@@ -226,8 +232,7 @@ public class ClassPathExplorer {
} catch (MalformedURLException e) {
// should never happen as based on an existing URL,
// only changing end of file name/path part
- getLogger().log(Level.SEVERE,
- "Error locating the widgetset " + classname, e);
+ error("Error locating the widgetset " + classname, e);
}
}
}
@@ -276,7 +281,7 @@ public class ClassPathExplorer {
}
}
} catch (IOException e) {
- getLogger().log(Level.WARNING, "Error parsing jar file", e);
+ error("Error parsing jar file", e);
}
}
@@ -304,7 +309,7 @@ public class ClassPathExplorer {
classpath = classpath.substring(0, classpath.length() - 1);
}
- getLogger().log(Level.FINE, "Classpath: {0}", classpath);
+ debug("Classpath: " + classpath);
String[] split = classpath.split(pathSep);
for (int i = 0; i < split.length; i++) {
@@ -338,9 +343,8 @@ public class ClassPathExplorer {
include(null, file, locations);
}
long end = System.currentTimeMillis();
- Logger logger = getLogger();
- if (logger.isLoggable(Level.FINE)) {
- logger.fine("getClassPathLocations took " + (end - start) + "ms");
+ if (debug) {
+ debug("getClassPathLocations took " + (end - start) + "ms");
}
return locations;
}
@@ -379,7 +383,8 @@ public class ClassPathExplorer {
url = new URL("jar:" + url.toExternalForm() + "!/");
JarURLConnection conn = (JarURLConnection) url
.openConnection();
- getLogger().fine(url.toString());
+ debug(url.toString());
+
JarFile jarFile = conn.getJarFile();
Manifest manifest = jarFile.getManifest();
if (manifest != null) {
@@ -393,11 +398,13 @@ public class ClassPathExplorer {
}
}
} catch (MalformedURLException e) {
- getLogger().log(Level.FINEST, "Failed to inspect JAR file",
- e);
+ if (debug) {
+ error("Failed to inspect JAR file", e);
+ }
} catch (IOException e) {
- getLogger().log(Level.FINEST, "Failed to inspect JAR file",
- e);
+ if (debug) {
+ error("Failed to inspect JAR file", e);
+ }
}
return false;
@@ -489,14 +496,12 @@ public class ClassPathExplorer {
*/
public static URL getDefaultSourceDirectory() {
- final Logger logger = getLogger();
-
- if (logger.isLoggable(Level.FINE)) {
- logger.fine("classpathLocations values:");
+ if (debug) {
+ debug("classpathLocations values:");
ArrayList<String> locations = new ArrayList<String>(
classpathLocations.keySet());
for (String location : locations) {
- logger.fine(String.valueOf(classpathLocations.get(location)));
+ debug(String.valueOf(classpathLocations.get(location)));
}
}
@@ -510,11 +515,15 @@ public class ClassPathExplorer {
try {
return new URL("file://" + directory.getCanonicalPath());
} catch (MalformedURLException e) {
- logger.log(Level.FINEST, "Ignoring exception", e);
// ignore: continue to the next classpath entry
+ if (debug) {
+ e.printStackTrace();
+ }
} catch (IOException e) {
- logger.log(Level.FINEST, "Ignoring exception", e);
// ignore: continue to the next classpath entry
+ if (debug) {
+ e.printStackTrace();
+ }
}
}
}
@@ -525,14 +534,24 @@ public class ClassPathExplorer {
* Test method for helper tool
*/
public static void main(String[] args) {
- getLogger().info(
- "Searching for available widgetsets and stylesheets...");
+ log("Searching for available widgetsets and stylesheets...");
ClassPathExplorer.getAvailableWidgetSetsAndStylesheets();
}
- private static final Logger getLogger() {
- return Logger.getLogger(ClassPathExplorer.class.getName());
+ private static void log(String message) {
+ System.out.println(message);
+ }
+
+ private static void error(String message, Exception e) {
+ System.err.println(message);
+ e.printStackTrace();
+ }
+
+ private static void debug(String message) {
+ if (debug) {
+ System.out.println(message);
+ }
}
}
diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java
index 61bcf00ad8..33aa689a88 100644
--- a/server/src/com/vaadin/ui/AbstractComponent.java
+++ b/server/src/com/vaadin/ui/AbstractComponent.java
@@ -31,13 +31,13 @@ import com.vaadin.event.ConnectorActionManager;
import com.vaadin.event.ShortcutListener;
import com.vaadin.server.AbstractClientConnector;
import com.vaadin.server.ComponentSizeValidator;
-import com.vaadin.server.ErrorHandler;
import com.vaadin.server.ErrorMessage;
import com.vaadin.server.Resource;
import com.vaadin.server.VaadinSession;
import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.ComponentConstants;
import com.vaadin.shared.ui.ComponentStateUtil;
+import com.vaadin.ui.Field.ValueChangeEvent;
import com.vaadin.util.ReflectTools;
/**
@@ -85,8 +85,6 @@ public abstract class AbstractComponent extends AbstractClientConnector
private static final Pattern sizePattern = Pattern
.compile("^(-?\\d+(\\.\\d+)?)(%|px|em|rem|ex|in|cm|mm|pt|pc)?$");
- private ErrorHandler errorHandler = null;
-
/**
* Keeps track of the Actions added to this component; the actual
* handling/notifying is delegated, usually to the containing window.
@@ -97,6 +95,8 @@ public abstract class AbstractComponent extends AbstractClientConnector
private HasComponents parent;
+ private Boolean explicitImmediateValue;
+
/* Constructor */
/**
@@ -360,25 +360,29 @@ public abstract class AbstractComponent extends AbstractClientConnector
}
}
- /*
- * Tests if the component is in the immediate mode. Don't add a JavaDoc
- * comment here, we use the default documentation from implemented
- * interface.
- */
public boolean isImmediate() {
- return getState(false).immediate;
+ if (explicitImmediateValue != null) {
+ return explicitImmediateValue;
+ } else if (hasListeners(ValueChangeEvent.class)) {
+ /*
+ * Automatic immediate for fields that developers are interested
+ * about.
+ */
+ return true;
+ } else {
+ return false;
+ }
}
/**
- * Sets the component's immediate mode to the specified status. This method
- * will trigger a {@link RepaintRequestEvent}.
+ * Sets the component's immediate mode to the specified status.
*
* @param immediate
* the boolean value specifying if the component should be in the
* immediate mode after the call.
- * @see Component#isImmediate()
*/
public void setImmediate(boolean immediate) {
+ explicitImmediateValue = immediate;
getState().immediate = immediate;
}
@@ -675,6 +679,8 @@ public abstract class AbstractComponent extends AbstractClientConnector
} else {
getState().errorMessage = null;
}
+
+ getState().immediate = isImmediate();
}
/* General event framework */
diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java
index 6a52d6b849..300e130c4e 100644
--- a/server/src/com/vaadin/ui/AbstractField.java
+++ b/server/src/com/vaadin/ui/AbstractField.java
@@ -783,15 +783,16 @@ public abstract class AbstractField<T> extends AbstractComponent implements
ConversionException e) {
String conversionError = getConversionError();
- if (dataSourceType != null) {
- conversionError = conversionError.replace("{0}",
- dataSourceType.getSimpleName());
- }
- if (e != null) {
- conversionError = conversionError.replace("{1}",
- e.getLocalizedMessage());
+ if (conversionError != null) {
+ if (dataSourceType != null) {
+ conversionError = conversionError.replace("{0}",
+ dataSourceType.getSimpleName());
+ }
+ if (e != null) {
+ conversionError = conversionError.replace("{1}",
+ e.getLocalizedMessage());
+ }
}
-
return conversionError;
}
@@ -1085,6 +1086,8 @@ public abstract class AbstractField<T> extends AbstractComponent implements
public void addValueChangeListener(Property.ValueChangeListener listener) {
addListener(AbstractField.ValueChangeEvent.class, listener,
VALUE_CHANGE_METHOD);
+ // ensure "automatic immediate handling" works
+ markAsDirty();
}
/**
@@ -1106,6 +1109,8 @@ public abstract class AbstractField<T> extends AbstractComponent implements
public void removeValueChangeListener(Property.ValueChangeListener listener) {
removeListener(AbstractField.ValueChangeEvent.class, listener,
VALUE_CHANGE_METHOD);
+ // ensure "automatic immediate handling" works
+ markAsDirty();
}
/**
diff --git a/server/src/com/vaadin/ui/AbstractSelect.java b/server/src/com/vaadin/ui/AbstractSelect.java
index 556b16943f..a32d40b11d 100644
--- a/server/src/com/vaadin/ui/AbstractSelect.java
+++ b/server/src/com/vaadin/ui/AbstractSelect.java
@@ -878,6 +878,37 @@ public abstract class AbstractSelect extends AbstractField<Object> implements
return retval;
}
+ /**
+ * Adds given items with given item ids to container.
+ *
+ * @since 7.2
+ * @param itemId
+ * item identifiers to be added to underlying container
+ * @throws UnsupportedOperationException
+ * if the underlying container don't support adding items with
+ * identifiers
+ */
+ public void addItems(Object... itemId) throws UnsupportedOperationException {
+ for (Object id : itemId) {
+ addItem(id);
+ }
+ }
+
+ /**
+ * Adds given items with given item ids to container.
+ *
+ * @since 7.2
+ * @param itemIds
+ * item identifiers to be added to underlying container
+ * @throws UnsupportedOperationException
+ * if the underlying container don't support adding items with
+ * identifiers
+ */
+ public void addItems(Collection<Object> itemIds)
+ throws UnsupportedOperationException {
+ addItems(itemIds.toArray());
+ }
+
/*
* (non-Javadoc)
*
diff --git a/server/src/com/vaadin/ui/Calendar.java b/server/src/com/vaadin/ui/Calendar.java
index 9ccc8ea2d9..b0999451c3 100644
--- a/server/src/com/vaadin/ui/Calendar.java
+++ b/server/src/com/vaadin/ui/Calendar.java
@@ -1824,7 +1824,7 @@ public class Calendar extends AbstractComponent implements
try {
Date start = formatter.parse(startDate);
for (Action.Handler ah : actionHandlers) {
- ah.handleAction(action, this, start);
+ ah.handleAction(action, Calendar.this, start);
}
} catch (ParseException e) {
@@ -1842,7 +1842,7 @@ public class Calendar extends AbstractComponent implements
DateConstants.ACTION_DATE_FORMAT_PATTERN);
formatter.setTimeZone(getTimeZone());
for (Action.Handler ah : actionHandlers) {
- ah.handleAction(action, this, events.get(eventIndex));
+ ah.handleAction(action, Calendar.this, events.get(eventIndex));
}
}
}
diff --git a/server/src/com/vaadin/ui/ComboBox.java b/server/src/com/vaadin/ui/ComboBox.java
index 88e895df82..5fb2f81011 100644
--- a/server/src/com/vaadin/ui/ComboBox.java
+++ b/server/src/com/vaadin/ui/ComboBox.java
@@ -56,8 +56,6 @@ public class ComboBox extends AbstractSelect implements
*/
protected int pageLength = 10;
- private int columns = 0;
-
// Current page when the user is 'paging' trough options
private int currentPage = -1;
diff --git a/server/src/com/vaadin/ui/FormLayout.java b/server/src/com/vaadin/ui/FormLayout.java
index 9d5e637068..9dc0b24cad 100644
--- a/server/src/com/vaadin/ui/FormLayout.java
+++ b/server/src/com/vaadin/ui/FormLayout.java
@@ -52,4 +52,23 @@ public class FormLayout extends AbstractOrderedLayout {
addComponents(children);
}
+ /**
+ * @deprecated This method currently has no effect as expand ratios are not
+ * implemented in FormLayout
+ */
+ @Override
+ @Deprecated
+ public void setExpandRatio(Component component, float ratio) {
+ super.setExpandRatio(component, ratio);
+ }
+
+ /**
+ * @deprecated This method currently has no effect as expand ratios are not
+ * implemented in FormLayout
+ */
+ @Override
+ @Deprecated
+ public float getExpandRatio(Component component) {
+ return super.getExpandRatio(component);
+ }
}
diff --git a/server/src/com/vaadin/ui/Label.java b/server/src/com/vaadin/ui/Label.java
index d7cee2a80d..3aa83de420 100644
--- a/server/src/com/vaadin/ui/Label.java
+++ b/server/src/com/vaadin/ui/Label.java
@@ -18,7 +18,6 @@ package com.vaadin.ui;
import java.lang.reflect.Method;
import java.util.Locale;
-import java.util.logging.Logger;
import com.vaadin.data.Property;
import com.vaadin.data.util.AbstractProperty;
@@ -56,9 +55,6 @@ public class Label extends AbstractComponent implements Property<String>,
Property.Viewer, Property.ValueChangeListener,
Property.ValueChangeNotifier, Comparable<Label> {
- private static final Logger logger = Logger
- .getLogger(Label.class.getName());
-
/**
* @deprecated As of 7.0, use {@link ContentMode#TEXT} instead
*/
diff --git a/server/src/com/vaadin/ui/PushConfiguration.java b/server/src/com/vaadin/ui/PushConfiguration.java
index a592b39bef..49738c5aff 100644
--- a/server/src/com/vaadin/ui/PushConfiguration.java
+++ b/server/src/com/vaadin/ui/PushConfiguration.java
@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.Collections;
import com.vaadin.server.VaadinSession;
+import com.vaadin.server.communication.AtmospherePushConnection;
import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.ui.Transport;
import com.vaadin.shared.ui.ui.UIState.PushConfigurationState;
@@ -170,20 +171,32 @@ class PushConfigurationImpl implements PushConfiguration {
throw new IllegalArgumentException("Push mode cannot be null");
}
- if (pushMode.isEnabled()) {
- VaadinSession session = ui.getSession();
- if (session != null && !session.getService().ensurePushAvailable()) {
- throw new IllegalStateException(
- "Push is not available. See previous log messages for more information.");
- }
+ VaadinSession session = ui.getSession();
+
+ if (session == null) {
+ throw new UIDetachedException(
+ "Cannot set the push mode for a detached UI");
+ }
+
+ assert session.hasLock();
+
+ if (pushMode.isEnabled() && !session.getService().ensurePushAvailable()) {
+ throw new IllegalStateException(
+ "Push is not available. See previous log messages for more information.");
}
- /*
- * Client-side will open a new connection or disconnect the old
- * connection, so there's nothing more to do on the server at this
- * point.
- */
- getState().mode = pushMode;
+ PushMode oldMode = getState().mode;
+ if (oldMode != pushMode) {
+ getState().mode = pushMode;
+
+ if (!oldMode.isEnabled() && pushMode.isEnabled()) {
+ // The push connection is initially in a disconnected state;
+ // the client will establish the connection
+ ui.setPushConnection(new AtmospherePushConnection(ui));
+ }
+ // Nothing to do here if disabling push;
+ // the client will close the connection
+ }
}
/*
@@ -274,9 +287,8 @@ class PushConfigurationImpl implements PushConfiguration {
@Override
public Collection<String> getParameterNames() {
- return Collections
- .unmodifiableCollection(ui.getState(false).pushConfiguration.parameters
- .keySet());
+ return Collections.unmodifiableCollection(getState(false).parameters
+ .keySet());
}
}
diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java
index 32ed738697..06e82dedcb 100644
--- a/server/src/com/vaadin/ui/Table.java
+++ b/server/src/com/vaadin/ui/Table.java
@@ -2165,7 +2165,6 @@ public class Table extends AbstractSelect implements Action.Container,
// more efficient implementation for containers supporting access by
// index
- Container.Indexed indexed = ((Container.Indexed) items);
List<?> itemIds = getItemIds(firstIndex, rows);
for (int i = 0; i < rows && i < itemIds.size(); i++) {
Object id = itemIds.get(i);
diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java
index a292e6b829..e688c06061 100644
--- a/server/src/com/vaadin/ui/UI.java
+++ b/server/src/com/vaadin/ui/UI.java
@@ -55,6 +55,7 @@ import com.vaadin.server.communication.PushConnection;
import com.vaadin.shared.Connector;
import com.vaadin.shared.EventId;
import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.ui.DebugWindowClientRpc;
import com.vaadin.shared.ui.ui.DebugWindowServerRpc;
import com.vaadin.shared.ui.ui.ScrollClientRpc;
@@ -422,8 +423,9 @@ public abstract class UI extends AbstractSingleComponentContainer implements
} else {
if (session == null) {
detach();
- // Close the push connection when UI is detached. Otherwise the
+ // Disable push when the UI is detached. Otherwise the
// push connection and possibly VaadinSession will live on.
+ getPushConfiguration().setPushMode(PushMode.DISABLED);
setPushConnection(null);
}
this.session = session;
@@ -550,8 +552,6 @@ public abstract class UI extends AbstractSingleComponentContainer implements
private transient PushConnection pushConnection = null;
- private boolean hasPendingPush = false;
-
private LocaleService localeService = new LocaleService(this,
getState(false).localeServiceState);
@@ -1368,6 +1368,9 @@ public abstract class UI extends AbstractSingleComponentContainer implements
* Pushes the pending changes and client RPC invocations of this UI to the
* client-side.
* <p>
+ * If push is enabled, but the push connection is not currently open, the
+ * push will be done when the connection is established.
+ * <p>
* As with all UI methods, the session must be locked when calling this
* method. It is also recommended that {@link UI#getCurrent()} is set up to
* return this UI since writing the response may invoke logic in any
@@ -1385,79 +1388,73 @@ public abstract class UI extends AbstractSingleComponentContainer implements
*/
public void push() {
VaadinSession session = getSession();
- if (session != null) {
- assert session.hasLock();
-
- /*
- * Purge the pending access queue as it might mark a connector as
- * dirty when the push would otherwise be ignored because there are
- * no changes to push.
- */
- session.getService().runPendingAccessTasks(session);
-
- if (!getConnectorTracker().hasDirtyConnectors()) {
- // Do not push if there is nothing to push
- return;
- }
- if (!getPushConfiguration().getPushMode().isEnabled()) {
- throw new IllegalStateException("Push not enabled");
- }
+ if (session == null) {
+ throw new UIDetachedException("Cannot push a detached UI");
+ }
+ assert session.hasLock();
- if (pushConnection == null) {
- hasPendingPush = true;
- } else {
- pushConnection.push();
- }
- } else {
- throw new UIDetachedException("Trying to push a detached UI");
+ if (!getPushConfiguration().getPushMode().isEnabled()) {
+ throw new IllegalStateException("Push not enabled");
+ }
+ assert pushConnection != null;
+
+ /*
+ * Purge the pending access queue as it might mark a connector as dirty
+ * when the push would otherwise be ignored because there are no changes
+ * to push.
+ */
+ session.getService().runPendingAccessTasks(session);
+
+ if (!getConnectorTracker().hasDirtyConnectors()) {
+ // Do not push if there is nothing to push
+ return;
}
+
+ pushConnection.push();
}
/**
* Returns the internal push connection object used by this UI. This method
- * should only be called by the framework. If the returned PushConnection is
- * not null, it is guaranteed to have {@code isConnected() == true}.
+ * should only be called by the framework.
* <p>
* This method is not intended to be overridden. If it is overridden, care
* should be taken since this method might be called in situations where
* {@link UI#getCurrent()} does not return this UI.
*
- * @return the push connection used by this UI, <code>null</code> if there
- * is no active push connection.
+ * @return the push connection used by this UI, or {@code null} if push is
+ * not available.
*/
public PushConnection getPushConnection() {
- assert (pushConnection == null || pushConnection.isConnected());
+ assert !(getPushConfiguration().getPushMode().isEnabled() && pushConnection == null);
return pushConnection;
}
/**
* Sets the internal push connection object used by this UI. This method
- * should only be called by the framework. If {@pushConnection} is not null,
- * its {@code isConnected()} must be true.
+ * should only be called by the framework.
+ * <p>
+ * The {@code pushConnection} argument must be non-null if and only if
+ * {@code getPushConfiguration().getPushMode().isEnabled()}.
*
* @param pushConnection
* the push connection to use for this UI
*/
public void setPushConnection(PushConnection pushConnection) {
- // If pushMode is disabled then there should never be a pushConnection
- assert (pushConnection == null || getPushConfiguration().getPushMode()
- .isEnabled());
- assert (pushConnection == null || pushConnection.isConnected());
+ // If pushMode is disabled then there should never be a pushConnection;
+ // if enabled there should always be
+ assert (pushConnection == null)
+ ^ getPushConfiguration().getPushMode().isEnabled();
if (pushConnection == this.pushConnection) {
return;
}
- if (this.pushConnection != null) {
+ if (this.pushConnection != null && this.pushConnection.isConnected()) {
this.pushConnection.disconnect();
}
this.pushConnection = pushConnection;
- if (pushConnection != null && hasPendingPush) {
- hasPendingPush = false;
- pushConnection.push();
- }
}
/**
diff --git a/server/src/com/vaadin/ui/Upload.java b/server/src/com/vaadin/ui/Upload.java
index 08cabf979a..98f5d2ded9 100644
--- a/server/src/com/vaadin/ui/Upload.java
+++ b/server/src/com/vaadin/ui/Upload.java
@@ -28,6 +28,7 @@ import com.vaadin.server.NoOutputStreamException;
import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.server.StreamVariable.StreamingProgressEvent;
+import com.vaadin.shared.ui.upload.UploadClientRpc;
/**
* Component for uploading files from client to server.
@@ -107,11 +108,6 @@ public class Upload extends AbstractComponent implements Component.Focusable,
private int nextid;
/**
- * Flag to indicate that submitting file has been requested.
- */
- private boolean forceSubmit;
-
- /**
* Creates a new instance of Upload.
*
* The receiver must be set before performing an upload.
@@ -157,11 +153,6 @@ public class Upload extends AbstractComponent implements Component.Focusable,
notStarted = false;
return;
}
- if (forceSubmit) {
- target.addAttribute("forceSubmit", true);
- forceSubmit = true;
- return;
- }
// The field should be focused
if (focus) {
target.addAttribute("focus", true);
@@ -1011,12 +1002,11 @@ public class Upload extends AbstractComponent implements Component.Focusable,
*/
public void submitUpload() {
markAsDirty();
- forceSubmit = true;
+ getRpcProxy(UploadClientRpc.class).submitUpload();
}
@Override
public void markAsDirty() {
- forceSubmit = false;
super.markAsDirty();
}