Change-Id: I50c2e4a95b492a42c4291e8dcbede3de87f1be6ftags/7.7.0.alpha1
@@ -109,6 +109,15 @@ | |||
</init-param> | |||
<async-supported>true</async-supported> | |||
</servlet> | |||
<servlet> | |||
<servlet-name>RPCLogger</servlet-name> | |||
<servlet-class>com.vaadin.tests.rpclogger.RPCLoggerServlet</servlet-class> | |||
<init-param> | |||
<param-name>ui</param-name> | |||
<param-value>com.vaadin.tests.rpclogger.RPCLoggerUI</param-value> | |||
</init-param> | |||
<async-supported>true</async-supported> | |||
</servlet> | |||
<servlet> | |||
<!-- This servlet is a separate instance for the sole purpose of | |||
@@ -202,6 +211,11 @@ | |||
<url-pattern>/commerror/*</url-pattern> | |||
</servlet-mapping> | |||
<servlet-mapping> | |||
<servlet-name>RPCLogger</servlet-name> | |||
<url-pattern>/rpclogger/*</url-pattern> | |||
</servlet-mapping> | |||
<servlet-mapping> | |||
<servlet-name>VaadinStaticFiles</servlet-name> | |||
<url-pattern>/VAADIN/*</url-pattern> |
@@ -316,7 +316,7 @@ public class ServerRpcHandler implements Serializable { | |||
* 6 semantics for components and add-ons that do not use Vaadin 7 RPC | |||
* directly. | |||
* | |||
* @param uI | |||
* @param ui | |||
* the UI receiving the invocations data | |||
* @param lastSyncIdSeenByClient | |||
* the most recent sync id the client has seen at the time the | |||
@@ -324,20 +324,21 @@ public class ServerRpcHandler implements Serializable { | |||
* @param invocationsData | |||
* JSON containing all information needed to execute all | |||
* requested RPC calls. | |||
* @since | |||
*/ | |||
private void handleInvocations(UI uI, int lastSyncIdSeenByClient, | |||
protected void handleInvocations(UI ui, int lastSyncIdSeenByClient, | |||
JsonArray invocationsData) { | |||
// TODO PUSH Refactor so that this is not needed | |||
LegacyCommunicationManager manager = uI.getSession() | |||
LegacyCommunicationManager manager = ui.getSession() | |||
.getCommunicationManager(); | |||
try { | |||
ConnectorTracker connectorTracker = uI.getConnectorTracker(); | |||
ConnectorTracker connectorTracker = ui.getConnectorTracker(); | |||
Set<Connector> enabledConnectors = new HashSet<Connector>(); | |||
List<MethodInvocation> invocations = parseInvocations( | |||
uI.getConnectorTracker(), invocationsData, | |||
ui.getConnectorTracker(), invocationsData, | |||
lastSyncIdSeenByClient); | |||
for (MethodInvocation invocation : invocations) { | |||
final ClientConnector connector = connectorTracker | |||
@@ -404,35 +405,11 @@ public class ServerRpcHandler implements Serializable { | |||
} | |||
if (invocation instanceof ServerRpcMethodInvocation) { | |||
try { | |||
ServerRpcManager.applyInvocation(connector, | |||
(ServerRpcMethodInvocation) invocation); | |||
} catch (RpcInvocationException e) { | |||
manager.handleConnectorRelatedException(connector, e); | |||
} | |||
handleInvocation(ui, connector, | |||
(ServerRpcMethodInvocation) invocation); | |||
} else { | |||
// All code below is for legacy variable changes | |||
LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation; | |||
Map<String, Object> changes = legacyInvocation | |||
.getVariableChanges(); | |||
try { | |||
if (connector instanceof VariableOwner) { | |||
// The source parameter is never used anywhere | |||
changeVariables(null, (VariableOwner) connector, | |||
changes); | |||
} else { | |||
throw new IllegalStateException( | |||
"Received legacy variable change for " | |||
+ connector.getClass().getName() | |||
+ " (" | |||
+ connector.getConnectorId() | |||
+ ") which is not a VariableOwner. The client-side connector sent these legacy varaibles: " | |||
+ changes.keySet()); | |||
} | |||
} catch (Exception e) { | |||
manager.handleConnectorRelatedException(connector, e); | |||
} | |||
handleInvocation(ui, connector, legacyInvocation); | |||
} | |||
} | |||
} catch (JsonException e) { | |||
@@ -443,6 +420,63 @@ public class ServerRpcHandler implements Serializable { | |||
} | |||
} | |||
/** | |||
* Handles the given RPC method invocation for the given connector | |||
* | |||
* @since | |||
* @param ui | |||
* the UI containing the connector | |||
* @param connector | |||
* the connector the RPC is targeted to | |||
* @param invocation | |||
* information about the rpc to invoke | |||
*/ | |||
protected void handleInvocation(UI ui, ClientConnector connector, | |||
ServerRpcMethodInvocation invocation) { | |||
try { | |||
ServerRpcManager.applyInvocation(connector, invocation); | |||
} catch (RpcInvocationException e) { | |||
ui.getSession().getCommunicationManager() | |||
.handleConnectorRelatedException(connector, e); | |||
} | |||
} | |||
/** | |||
* Handles the given Legacy variable change RPC method invocation for the | |||
* given connector | |||
* | |||
* @since | |||
* @param ui | |||
* the UI containing the connector | |||
* @param connector | |||
* the connector the RPC is targeted to | |||
* @param invocation | |||
* information about the rpc to invoke | |||
*/ | |||
protected void handleInvocation(UI ui, ClientConnector connector, | |||
LegacyChangeVariablesInvocation legacyInvocation) { | |||
Map<String, Object> changes = legacyInvocation.getVariableChanges(); | |||
try { | |||
if (connector instanceof VariableOwner) { | |||
// The source parameter is never used anywhere | |||
changeVariables(null, (VariableOwner) connector, changes); | |||
} else { | |||
throw new IllegalStateException( | |||
"Received legacy variable change for " | |||
+ connector.getClass().getName() | |||
+ " (" | |||
+ connector.getConnectorId() | |||
+ ") which is not a VariableOwner. The client-side connector sent these legacy varaibles: " | |||
+ changes.keySet()); | |||
} | |||
} catch (Exception e) { | |||
ui.getSession().getCommunicationManager() | |||
.handleConnectorRelatedException(connector, e); | |||
} | |||
} | |||
/** | |||
* Parse JSON from the client into a list of MethodInvocation instances. | |||
* |
@@ -51,9 +51,20 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements | |||
public static final String UIDL_PATH = "UIDL/"; | |||
private ServerRpcHandler rpcHandler = new ServerRpcHandler(); | |||
private ServerRpcHandler rpcHandler; | |||
public UidlRequestHandler() { | |||
rpcHandler = createRpcHandler(); | |||
} | |||
/** | |||
* Creates the ServerRpcHandler to use | |||
* | |||
* @since | |||
* @return the ServerRpcHandler to use | |||
*/ | |||
protected ServerRpcHandler createRpcHandler() { | |||
return new ServerRpcHandler(); | |||
} | |||
@Override |
@@ -0,0 +1,40 @@ | |||
/* | |||
* Copyright 2000-2014 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.tests.rpclogger; | |||
import com.vaadin.server.ClientConnector; | |||
import com.vaadin.server.ServerRpcMethodInvocation; | |||
import com.vaadin.server.communication.ServerRpcHandler; | |||
import com.vaadin.shared.communication.LegacyChangeVariablesInvocation; | |||
import com.vaadin.ui.UI; | |||
public class LoggingServerRpcHandler extends ServerRpcHandler { | |||
@Override | |||
protected void handleInvocation(UI ui, ClientConnector connector, | |||
LegacyChangeVariablesInvocation legacyInvocation) { | |||
((RPCLoggerUI) ui).recordInvocation(connector, legacyInvocation); | |||
super.handleInvocation(ui, connector, legacyInvocation); | |||
} | |||
@Override | |||
protected void handleInvocation(UI ui, ClientConnector connector, | |||
ServerRpcMethodInvocation invocation) { | |||
((RPCLoggerUI) ui).recordInvocation(connector, invocation); | |||
super.handleInvocation(ui, connector, invocation); | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
/* | |||
* Copyright 2000-2014 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.tests.rpclogger; | |||
import com.vaadin.server.communication.ServerRpcHandler; | |||
import com.vaadin.server.communication.UidlRequestHandler; | |||
public class LoggingUidlRequestHandler extends UidlRequestHandler { | |||
@Override | |||
protected ServerRpcHandler createRpcHandler() { | |||
return new LoggingServerRpcHandler(); | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
/* | |||
* Copyright 2000-2014 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.tests.rpclogger; | |||
import java.util.List; | |||
import com.vaadin.server.DeploymentConfiguration; | |||
import com.vaadin.server.RequestHandler; | |||
import com.vaadin.server.ServiceException; | |||
import com.vaadin.server.VaadinServlet; | |||
import com.vaadin.server.VaadinServletService; | |||
public class RPCLoggerService extends VaadinServletService { | |||
public RPCLoggerService(VaadinServlet servlet, | |||
DeploymentConfiguration deploymentConfiguration) | |||
throws ServiceException { | |||
super(servlet, deploymentConfiguration); | |||
} | |||
@Override | |||
protected List<RequestHandler> createRequestHandlers() | |||
throws ServiceException { | |||
List<RequestHandler> handlers = super.createRequestHandlers(); | |||
handlers.add(new LoggingUidlRequestHandler()); | |||
return handlers; | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
/* | |||
* Copyright 2000-2014 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.tests.rpclogger; | |||
import com.vaadin.server.DeploymentConfiguration; | |||
import com.vaadin.server.ServiceException; | |||
import com.vaadin.server.VaadinServlet; | |||
import com.vaadin.server.VaadinServletService; | |||
public class RPCLoggerServlet extends VaadinServlet { | |||
@Override | |||
protected VaadinServletService createServletService( | |||
DeploymentConfiguration deploymentConfiguration) | |||
throws ServiceException { | |||
RPCLoggerService service = new RPCLoggerService(this, | |||
deploymentConfiguration); | |||
service.init(); | |||
return service; | |||
} | |||
} |
@@ -0,0 +1,177 @@ | |||
/* | |||
* Copyright 2000-2014 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.tests.rpclogger; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Map; | |||
import com.vaadin.server.ClientConnector; | |||
import com.vaadin.server.ErrorHandler; | |||
import com.vaadin.server.ServerRpcMethodInvocation; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.shared.communication.LegacyChangeVariablesInvocation; | |||
import com.vaadin.shared.communication.MethodInvocation; | |||
import com.vaadin.tests.components.AbstractTestUIWithLog; | |||
import com.vaadin.ui.AbstractComponent; | |||
import com.vaadin.ui.Button; | |||
import com.vaadin.ui.Button.ClickEvent; | |||
import com.vaadin.ui.Button.ClickListener; | |||
import com.vaadin.ui.ListSelect; | |||
import com.vaadin.ui.Notification; | |||
import com.vaadin.ui.Notification.Type; | |||
public class RPCLoggerUI extends AbstractTestUIWithLog implements ErrorHandler { | |||
private List<Action> lastActions = new ArrayList<Action>(); | |||
public static class Action { | |||
public Action(ClientConnector connector, MethodInvocation invocation) { | |||
target = connector; | |||
this.invocation = invocation; | |||
} | |||
private MethodInvocation invocation; | |||
private ClientConnector target; | |||
} | |||
@Override | |||
protected int getLogSize() { | |||
return 10; | |||
} | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
setErrorHandler(this); | |||
addComponent(new Button("Do something")); | |||
ListSelect s = new ListSelect(); | |||
s.setMultiSelect(true); | |||
s.addItem("foo"); | |||
s.addItem("bar"); | |||
addComponent(s); | |||
addComponent(new Button("Action, which will fail", new ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
throw new RuntimeException("Something went wrong"); | |||
} | |||
})); | |||
} | |||
public void recordInvocation(ClientConnector connector, | |||
LegacyChangeVariablesInvocation legacyInvocation) { | |||
addAction(new Action(connector, legacyInvocation)); | |||
} | |||
public void recordInvocation(ClientConnector connector, | |||
ServerRpcMethodInvocation invocation) { | |||
addAction(new Action(connector, invocation)); | |||
} | |||
private void addAction(Action action) { | |||
while (lastActions.size() >= 5) { | |||
lastActions.remove(0); | |||
} | |||
lastActions.add(action); | |||
} | |||
public String formatAction(ClientConnector connector, | |||
LegacyChangeVariablesInvocation legacyInvocation) { | |||
String connectorIdentifier = getConnectorIdentifier(connector); | |||
Map<String, Object> changes = legacyInvocation.getVariableChanges(); | |||
String rpcInfo = ""; | |||
for (String key : changes.keySet()) { | |||
Object value = changes.get(key); | |||
rpcInfo += key + ": " + formatValue(value); | |||
} | |||
return "Legacy RPC " + rpcInfo + " for " + connectorIdentifier; | |||
} | |||
public String formatAction(ClientConnector connector, | |||
ServerRpcMethodInvocation invocation) { | |||
String connectorIdentifier = getConnectorIdentifier(connector); | |||
String rpcInfo = invocation.getInterfaceName() + "." | |||
+ invocation.getMethodName() + " ("; | |||
for (Object o : invocation.getParameters()) { | |||
rpcInfo += formatValue(o); | |||
rpcInfo += ","; | |||
} | |||
rpcInfo = rpcInfo.substring(0, rpcInfo.length() - 2) + ")"; | |||
return "RPC " + rpcInfo + " for " + connectorIdentifier; | |||
} | |||
private String formatValue(Object value) { | |||
if (value == null) { | |||
return "null"; | |||
} | |||
if (value instanceof String) { | |||
return (String) value; | |||
} else if (value instanceof Object[]) { | |||
String formatted = ""; | |||
for (Object o : ((Object[]) value)) { | |||
formatted += formatValue(o) + ","; | |||
} | |||
return formatted; | |||
} else { | |||
return value.toString(); | |||
} | |||
} | |||
private String getConnectorIdentifier(ClientConnector connector) { | |||
String connectorIdentifier = connector.getClass().getSimpleName(); | |||
if (connector instanceof AbstractComponent) { | |||
String caption = ((AbstractComponent) connector).getCaption(); | |||
if (caption != null) { | |||
connectorIdentifier += " - " + caption; | |||
} | |||
} | |||
return "'" + connectorIdentifier + "'"; | |||
} | |||
@Override | |||
public void error(com.vaadin.server.ErrorEvent event) { | |||
String msg = ""; | |||
for (int i = 0; i < lastActions.size(); i++) { | |||
Action action = lastActions.get(i); | |||
if (action.invocation instanceof ServerRpcMethodInvocation) { | |||
msg += "\n" | |||
+ (i + 1) | |||
+ " " | |||
+ formatAction(action.target, | |||
(ServerRpcMethodInvocation) action.invocation); | |||
} else { | |||
msg += "\n" | |||
+ (i + 1) | |||
+ " " | |||
+ formatAction( | |||
action.target, | |||
(LegacyChangeVariablesInvocation) action.invocation); | |||
} | |||
} | |||
msg += "\n"; | |||
msg += "\n"; | |||
msg += "This error should not really be shown but logged for later analysis."; | |||
Notification.show( | |||
"Something went wrong. Actions leading up to this error were:", | |||
msg, Type.ERROR_MESSAGE); | |||
// log(msg); | |||
} | |||
} |