diff options
author | Leif Åstrand <leif@vaadin.com> | 2013-10-22 09:12:59 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2013-10-22 09:12:59 +0300 |
commit | d70961ff2539aabe99eea22683a8ae77efdc81e5 (patch) | |
tree | c3876e2266ace7e90d8dc82e35f22631e2ce29e5 /server | |
parent | a48370a761a6d0b6c54196da0defdb30b47a5bb1 (diff) | |
parent | ee809e5985d7a438e031c40bed160ac78ae8d0bc (diff) | |
download | vaadin-framework-d70961ff2539aabe99eea22683a8ae77efdc81e5.tar.gz vaadin-framework-d70961ff2539aabe99eea22683a8ae77efdc81e5.zip |
Merge changes from origin/7.1
c7ae45c Validate that the connector is enabled before triggering actions for it (#12743)
ce89a75 Created constants for tested browser versions (#12786)
f9ea9b3 Allow running tests locally by overriding runLocally() (#12786)
e70ba25 Added liferay module for building liferay.zip #12748
7c12694 Add sub directory support to sass test scanner (#12790)
39fdf66 Handle numbers in the same way if they do not have a unit (#12732)
6155d61 Disable fallback in a way compatible with Atmosphere JS 2.0.3 (#12241)
f401595 Test for pushing large chunks of data (#12567)
d41967d Skip compilation of TB2 tests if tests.tb2.skip is set
6c1ba81 Reverted button click() logic check (#12743)
779c8a0 Disable automated testing on Opera until issues are resolved (#12487, #12367, #12800)
962c1c3 Fix compilation error
7ee11a7 Remove unused test super class (#12786)
a4211dc Resolve concurrency issue in running TB3 tests
20c28aa Fixed javadoc
0d36896 Add more hax to make test work with new Atmosphere JS (#12241)
ed50200 Fix serialization issue (#12703)
dd51b7f Added more exception handling to PushHandler (#12578, #11882)
6f76840 Sass variables can now start with underscore (#12716)
ab5b20c Ticket #12727 - Panels get unnecessary scroll bars in WebKit when content is 100% wide.
361ad17 Fixed focus issue in TableMoveFocusWithSelectionTest (#12540)
ee809e5 Revert broken fix and test (#12446)
Change-Id: I71b6e3c2dc6b02845794df0934ba807d7ccac784
Diffstat (limited to 'server')
8 files changed, 177 insertions, 165 deletions
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/server/ErrorHandlingRunnable.java b/server/src/com/vaadin/server/ErrorHandlingRunnable.java index 8ae6ce3d5d..3970a14ee8 100644 --- a/server/src/com/vaadin/server/ErrorHandlingRunnable.java +++ b/server/src/com/vaadin/server/ErrorHandlingRunnable.java @@ -15,6 +15,8 @@ */ package com.vaadin.server; +import java.io.Serializable; + /** * Defines the interface to handle exceptions thrown during the execution of a * FutureAccess. @@ -22,7 +24,7 @@ package com.vaadin.server; * @since 7.1.8 * @author Vaadin Ltd */ -public interface ErrorHandlingRunnable extends Runnable { +public interface ErrorHandlingRunnable extends Runnable, Serializable { /** * Handles exceptions thrown during the execution of a FutureAccess. diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java index 81dd00084d..b7cc628856 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; @@ -274,14 +276,52 @@ 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); + sendNotificationAndDisconnect( + resource, + 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/server/communication/UidlRequestHandler.java b/server/src/com/vaadin/server/communication/UidlRequestHandler.java index 2277e1c76f..cf25910fa4 100644 --- a/server/src/com/vaadin/server/communication/UidlRequestHandler.java +++ b/server/src/com/vaadin/server/communication/UidlRequestHandler.java @@ -56,7 +56,8 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements private ServerRpcHandler rpcHandler = new ServerRpcHandler(); - private UidlWriter uidlWriter = new UidlWriter(); + public UidlRequestHandler() { + } @Override protected boolean canHandleRequest(VaadinRequest request) { @@ -147,7 +148,7 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements JSONException { openJsonMessage(writer, response); - uidlWriter.write(ui, writer, repaintAll, false); + new UidlWriter().write(ui, writer, repaintAll, false); closeJsonMessage(writer); } diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java index a290eb4846..b46fbbf58a 100644 --- a/server/src/com/vaadin/server/communication/UidlWriter.java +++ b/server/src/com/vaadin/server/communication/UidlWriter.java @@ -52,14 +52,6 @@ import com.vaadin.ui.UI; */ public class UidlWriter implements Serializable { - private LegacyUidlWriter legacyUidlWriter = new LegacyUidlWriter(); - private SharedStateWriter sharedStateWriter = new SharedStateWriter(); - private ConnectorTypeWriter connectorTypeWriter = new ConnectorTypeWriter(); - private ConnectorHierarchyWriter connectorHierarchyWriter = new ConnectorHierarchyWriter(); - private ClientRpcWriter clientRpcWriter = new ClientRpcWriter(); - private MetadataWriter metadataWriter = new MetadataWriter(); - private ResourceWriter resourceWriter = new ResourceWriter(); - /** * Writes a JSON object containing all pending changes to the given UI. * @@ -88,12 +80,13 @@ public class UidlWriter implements Serializable { // to write out session.getService().runPendingAccessTasks(session); + ArrayList<ClientConnector> dirtyVisibleConnectors = ui + .getConnectorTracker().getDirtyVisibleConnectors(); + LegacyCommunicationManager manager = session.getCommunicationManager(); // Paints components + ConnectorTracker uiConnectorTracker = ui.getConnectorTracker(); getLogger().log(Level.FINE, "* Creating response to client"); - ConnectorTracker uiConnectorTracker = ui.getConnectorTracker(); - ArrayList<ClientConnector> dirtyVisibleConnectors = uiConnectorTracker - .getDirtyVisibleConnectors(); getLogger().log( Level.FINE, "Found " + dirtyVisibleConnectors.size() @@ -111,13 +104,10 @@ public class UidlWriter implements Serializable { writer.write("\"changes\" : "); - LegacyCommunicationManager manager = session - .getCommunicationManager(); - JsonPaintTarget paintTarget = new JsonPaintTarget(manager, writer, !repaintAll); - legacyUidlWriter.write(ui, writer, paintTarget); + new LegacyUidlWriter().write(ui, writer, paintTarget); paintTarget.close(); writer.write(", "); // close changes @@ -134,7 +124,7 @@ public class UidlWriter implements Serializable { // processing. writer.write("\"state\":"); - sharedStateWriter.write(ui, writer); + new SharedStateWriter().write(ui, writer); writer.write(", "); // close states // TODO This should be optimized. The type only needs to be @@ -143,7 +133,7 @@ public class UidlWriter implements Serializable { // widget mapping writer.write("\"types\":"); - connectorTypeWriter.write(ui, writer, paintTarget); + new ConnectorTypeWriter().write(ui, writer, paintTarget); writer.write(", "); // close states // Send update hierarchy information to the client. @@ -154,7 +144,7 @@ public class UidlWriter implements Serializable { // child to 0 children) writer.write("\"hierarchy\":"); - connectorHierarchyWriter.write(ui, writer); + new ConnectorHierarchyWriter().write(ui, writer); writer.write(", "); // close hierarchy // send server to client RPC calls for components in the UI, in call @@ -164,7 +154,7 @@ public class UidlWriter implements Serializable { // which they were performed, remove the calls from components writer.write("\"rpc\" : "); - clientRpcWriter.write(ui, writer); + new ClientRpcWriter().write(ui, writer); writer.write(", "); // close rpc uiConnectorTracker.markAllConnectorsClean(); @@ -174,11 +164,11 @@ public class UidlWriter implements Serializable { SystemMessages messages = ui.getSession().getService() .getSystemMessages(ui.getLocale(), null); // TODO hilightedConnector - metadataWriter.write(ui, writer, repaintAll, async, messages); + new MetadataWriter().write(ui, writer, repaintAll, async, messages); writer.write(", "); writer.write("\"resources\" : "); - resourceWriter.write(ui, writer, paintTarget); + new ResourceWriter().write(ui, writer, paintTarget); Collection<Class<? extends ClientConnector>> usedClientConnectors = paintTarget .getUsedClientConnectors(); 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/tests/src/com/vaadin/server/communication/UidlWriterTest.java b/server/tests/src/com/vaadin/server/communication/UidlWriterTest.java deleted file mode 100644 index 8dcd6cbdf4..0000000000 --- a/server/tests/src/com/vaadin/server/communication/UidlWriterTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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.io.IOException; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Locale; - -import org.easymock.EasyMock; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.vaadin.server.ClientConnector; -import com.vaadin.server.LegacyCommunicationManager; -import com.vaadin.server.SystemMessages; -import com.vaadin.server.VaadinRequest; -import com.vaadin.server.VaadinService; -import com.vaadin.server.VaadinSession; -import com.vaadin.server.WrappedSession; -import com.vaadin.ui.ConnectorTracker; -import com.vaadin.ui.UI; - -/** - * - * @since - * @author Vaadin Ltd - */ -public class UidlWriterTest { - - private UI ui; - private UidlWriter uidlWriter; - - @Before - public void setUp() { - SystemMessages messages = EasyMock.createNiceMock(SystemMessages.class); - EasyMock.expect(messages.isSessionExpiredNotificationEnabled()) - .andReturn(true).anyTimes(); - EasyMock.replay(messages); - - VaadinService service = EasyMock.createNiceMock(VaadinService.class); - EasyMock.expect( - service.getSystemMessages(EasyMock.anyObject(Locale.class), - EasyMock.anyObject(VaadinRequest.class))) - .andReturn(messages).anyTimes(); - EasyMock.replay(service); - - LegacyCommunicationManager manager = EasyMock - .createNiceMock(LegacyCommunicationManager.class); - EasyMock.replay(manager); - - WrappedSession wrappedSession = EasyMock - .createNiceMock(WrappedSession.class); - EasyMock.expect(wrappedSession.getMaxInactiveInterval()).andReturn(100) - .times(3).andReturn(200); - - EasyMock.replay(wrappedSession); - - VaadinSession session = EasyMock.createNiceMock(VaadinSession.class); - EasyMock.expect(session.getService()).andReturn(service).anyTimes(); - EasyMock.expect(session.getCommunicationManager()).andReturn(manager) - .anyTimes(); - EasyMock.expect(session.getSession()).andReturn(wrappedSession) - .anyTimes(); - EasyMock.replay(session); - - ConnectorTracker tracker = EasyMock - .createNiceMock(ConnectorTracker.class); - EasyMock.expect(tracker.getDirtyVisibleConnectors()) - .andReturn(new ArrayList<ClientConnector>()).anyTimes(); - EasyMock.replay(tracker); - - ui = EasyMock.createNiceMock(UI.class); - EasyMock.expect(ui.getSession()).andReturn(session).anyTimes(); - EasyMock.expect(ui.getConnectorTracker()).andReturn(tracker).anyTimes(); - EasyMock.replay(ui); - - uidlWriter = new UidlWriter(); - } - - @Test - public void testMetadataWriterState() throws IOException, JSONException { - - Assert.assertEquals( - "Metadata should contain redirect interval on first write", - 115, getRedirect(uidl(false, false)).optInt("interval")); - Assert.assertNull( - "Metadata should not contain redirect interval on second write", - getRedirect(uidl(false, false))); - Assert.assertEquals( - "Metadata should contain redirect interval on repaintAll", 115, - getRedirect(uidl(true, false)).optInt("interval")); - Assert.assertEquals( - "Metadata should contain redirect interval when changed in session", - 215, getRedirect(uidl(false, false)).optInt("interval")); - } - - private JSONObject uidl(boolean repaintAll, boolean async) - throws IOException, JSONException { - StringWriter writer = new StringWriter(); - uidlWriter.write(ui, writer, repaintAll, async); - return new JSONObject("{" + writer.toString() + "}"); - } - - private JSONObject getRedirect(JSONObject json) throws JSONException { - return json.getJSONObject("meta").optJSONObject("timedRedirect"); - - } -} |