Browse Source

Make it possible to intercept RPC calls without copy/paste

Change-Id: I50c2e4a95b492a42c4291e8dcbede3de87f1be6f
tags/7.7.0.alpha1
Artur Signell 8 years ago
parent
commit
39640d188b

+ 14
- 0
WebContent/WEB-INF/web.xml View File

@@ -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>

+ 66
- 32
server/src/com/vaadin/server/communication/ServerRpcHandler.java View File

@@ -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.
*

+ 12
- 1
server/src/com/vaadin/server/communication/UidlRequestHandler.java View File

@@ -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

+ 40
- 0
uitest/src/com/vaadin/tests/rpclogger/LoggingServerRpcHandler.java View File

@@ -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);
}

}

+ 28
- 0
uitest/src/com/vaadin/tests/rpclogger/LoggingUidlRequestHandler.java View File

@@ -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();
}

}

+ 41
- 0
uitest/src/com/vaadin/tests/rpclogger/RPCLoggerService.java View File

@@ -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;
}
}

+ 34
- 0
uitest/src/com/vaadin/tests/rpclogger/RPCLoggerServlet.java View File

@@ -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;
}
}

+ 177
- 0
uitest/src/com/vaadin/tests/rpclogger/RPCLoggerUI.java View File

@@ -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);
}
}

Loading…
Cancel
Save