Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

ServerRpcHandler.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.server.communication;
  17. import java.io.IOException;
  18. import java.io.Reader;
  19. import java.io.Serializable;
  20. import java.lang.reflect.Type;
  21. import java.util.ArrayList;
  22. import java.util.HashSet;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.Set;
  26. import java.util.logging.Level;
  27. import java.util.logging.Logger;
  28. import com.vaadin.server.ClientConnector;
  29. import com.vaadin.server.Constants;
  30. import com.vaadin.server.JsonCodec;
  31. import com.vaadin.server.LegacyCommunicationManager;
  32. import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException;
  33. import com.vaadin.server.ServerRpcManager;
  34. import com.vaadin.server.ServerRpcManager.RpcInvocationException;
  35. import com.vaadin.server.ServerRpcMethodInvocation;
  36. import com.vaadin.server.VaadinRequest;
  37. import com.vaadin.server.VaadinService;
  38. import com.vaadin.server.VariableOwner;
  39. import com.vaadin.shared.ApplicationConstants;
  40. import com.vaadin.shared.Connector;
  41. import com.vaadin.shared.Version;
  42. import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
  43. import com.vaadin.shared.communication.MethodInvocation;
  44. import com.vaadin.shared.communication.ServerRpc;
  45. import com.vaadin.shared.communication.UidlValue;
  46. import com.vaadin.shared.data.DataRequestRpc;
  47. import com.vaadin.ui.Component;
  48. import com.vaadin.ui.ConnectorTracker;
  49. import com.vaadin.ui.UI;
  50. import elemental.json.JsonArray;
  51. import elemental.json.JsonException;
  52. import elemental.json.JsonObject;
  53. import elemental.json.JsonValue;
  54. import elemental.json.impl.JsonUtil;
  55. /**
  56. * Handles a client-to-server message containing serialized {@link ServerRpc
  57. * server RPC} invocations.
  58. *
  59. * @author Vaadin Ltd
  60. * @since 7.1
  61. */
  62. public class ServerRpcHandler implements Serializable {
  63. /**
  64. * A data transfer object representing an RPC request sent by the client
  65. * side.
  66. *
  67. * @since 7.2
  68. * @author Vaadin Ltd
  69. */
  70. public static class RpcRequest implements Serializable {
  71. private final String csrfToken;
  72. private final JsonArray invocations;
  73. private final int syncId;
  74. private final JsonObject json;
  75. private final boolean resynchronize;
  76. private final int clientToServerMessageId;
  77. private String widgetsetVersion = null;
  78. public RpcRequest(String jsonString, VaadinRequest request) {
  79. json = JsonUtil.parse(jsonString);
  80. JsonValue token = json.get(ApplicationConstants.CSRF_TOKEN);
  81. if (token == null) {
  82. csrfToken = ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE;
  83. } else {
  84. String csrfToken = token.asString();
  85. if (csrfToken.isEmpty()) {
  86. csrfToken = ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE;
  87. }
  88. this.csrfToken = csrfToken;
  89. }
  90. if (request.getService().getDeploymentConfiguration()
  91. .isSyncIdCheckEnabled()) {
  92. syncId = (int) json
  93. .getNumber(ApplicationConstants.SERVER_SYNC_ID);
  94. } else {
  95. syncId = -1;
  96. }
  97. if (json.hasKey(ApplicationConstants.RESYNCHRONIZE_ID)) {
  98. resynchronize = json
  99. .getBoolean(ApplicationConstants.RESYNCHRONIZE_ID);
  100. } else {
  101. resynchronize = false;
  102. }
  103. if (json.hasKey(ApplicationConstants.WIDGETSET_VERSION_ID)) {
  104. widgetsetVersion = json
  105. .getString(ApplicationConstants.WIDGETSET_VERSION_ID);
  106. }
  107. if (json.hasKey(ApplicationConstants.CLIENT_TO_SERVER_ID)) {
  108. clientToServerMessageId = (int) json
  109. .getNumber(ApplicationConstants.CLIENT_TO_SERVER_ID);
  110. } else {
  111. getLogger()
  112. .warning("Server message without client id received");
  113. clientToServerMessageId = -1;
  114. }
  115. invocations = json.getArray(ApplicationConstants.RPC_INVOCATIONS);
  116. }
  117. /**
  118. * Gets the CSRF security token (double submit cookie) for this request.
  119. *
  120. * @return the CSRF security token for this current change request
  121. */
  122. public String getCsrfToken() {
  123. return csrfToken;
  124. }
  125. /**
  126. * Gets the data to recreate the RPC as requested by the client side.
  127. *
  128. * @return the data describing which RPC should be made, and all their
  129. * data
  130. */
  131. public JsonArray getRpcInvocationsData() {
  132. return invocations;
  133. }
  134. /**
  135. * Gets the sync id last seen by the client.
  136. *
  137. * @return the last sync id given by the server, according to the
  138. * client's request
  139. */
  140. public int getSyncId() {
  141. return syncId;
  142. }
  143. /**
  144. * Checks if this is a request to resynchronize the client side
  145. *
  146. * @return true if this is a resynchronization request, false otherwise
  147. */
  148. public boolean isResynchronize() {
  149. return resynchronize;
  150. }
  151. /**
  152. * Gets the id of the client to server message
  153. *
  154. * @since 7.6
  155. * @return the server message id
  156. */
  157. public int getClientToServerId() {
  158. return clientToServerMessageId;
  159. }
  160. /**
  161. * Gets the entire request in JSON format, as it was received from the
  162. * client.
  163. * <p>
  164. * <em>Note:</em> This is a shared reference - any modifications made
  165. * will be shared.
  166. *
  167. * @return the raw JSON object that was received from the client
  168. *
  169. */
  170. public JsonObject getRawJson() {
  171. return json;
  172. }
  173. /**
  174. * Gets the widget set version reported by the client
  175. *
  176. * @since 7.6
  177. * @return The widget set version reported by the client or null if the
  178. * message did not contain a widget set version
  179. */
  180. public String getWidgetsetVersion() {
  181. return widgetsetVersion;
  182. }
  183. }
  184. private static final int MAX_BUFFER_SIZE = 64 * 1024;
  185. /**
  186. * Reads JSON containing zero or more serialized RPC calls (including legacy
  187. * variable changes) and executes the calls.
  188. *
  189. * @param ui
  190. * The {@link UI} receiving the calls. Cannot be null.
  191. * @param reader
  192. * The {@link Reader} used to read the JSON.
  193. * @param request
  194. * @throws IOException
  195. * If reading the message fails.
  196. * @throws InvalidUIDLSecurityKeyException
  197. * If the received security key does not match the one stored in
  198. * the session.
  199. */
  200. public void handleRpc(UI ui, Reader reader, VaadinRequest request)
  201. throws IOException, InvalidUIDLSecurityKeyException {
  202. ui.getSession().setLastRequestTimestamp(System.currentTimeMillis());
  203. String changeMessage = getMessage(reader);
  204. if (changeMessage == null || changeMessage.isEmpty()) {
  205. // The client sometimes sends empty messages, this is probably a bug
  206. return;
  207. }
  208. RpcRequest rpcRequest = new RpcRequest(changeMessage, request);
  209. // Security: double cookie submission pattern unless disabled by
  210. // property
  211. if (!VaadinService.isCsrfTokenValid(ui.getSession(),
  212. rpcRequest.getCsrfToken())) {
  213. throw new InvalidUIDLSecurityKeyException("");
  214. }
  215. checkWidgetsetVersion(rpcRequest.getWidgetsetVersion());
  216. int expectedId = ui.getLastProcessedClientToServerId() + 1;
  217. if (rpcRequest.getClientToServerId() != -1
  218. && rpcRequest.getClientToServerId() != expectedId) {
  219. // Invalid message id, skip RPC processing but force a full
  220. // re-synchronization of the client as it might have not received
  221. // the previous response (e.g. due to a bad connection)
  222. // Must resync also for duplicate messages because the server might
  223. // have generated a response for the first message but the response
  224. // did not reach the client. When the client re-sends the message,
  225. // it would only get an empty response (because the dirty flags have
  226. // been cleared on the server) and would be out of sync
  227. ui.getSession().getCommunicationManager().repaintAll(ui);
  228. if (rpcRequest.getClientToServerId() < expectedId) {
  229. // Just a duplicate message due to a bad connection or similar
  230. // It has already been handled by the server so it is safe to
  231. // ignore
  232. getLogger()
  233. .fine("Ignoring old message from the client. Expected: "
  234. + expectedId + ", got: "
  235. + rpcRequest.getClientToServerId());
  236. } else {
  237. getLogger().warning(
  238. "Unexpected message id from the client. Expected: "
  239. + expectedId + ", got: "
  240. + rpcRequest.getClientToServerId());
  241. }
  242. } else {
  243. // Message id ok, process RPCs
  244. ui.setLastProcessedClientToServerId(expectedId);
  245. handleInvocations(ui, rpcRequest.getSyncId(),
  246. rpcRequest.getRpcInvocationsData());
  247. }
  248. ui.getConnectorTracker()
  249. .cleanConcurrentlyRemovedConnectorIds(rpcRequest.getSyncId());
  250. if (rpcRequest.isResynchronize()) {
  251. ui.getSession().getCommunicationManager().repaintAll(ui);
  252. }
  253. }
  254. /**
  255. * Checks that the version reported by the client (widgetset) matches that
  256. * of the server.
  257. *
  258. * @param widgetsetVersion
  259. * the widget set version reported by the client or null
  260. */
  261. private void checkWidgetsetVersion(String widgetsetVersion) {
  262. if (widgetsetVersion == null) {
  263. // Only check when the widgetset version is reported. It is reported
  264. // in the first UIDL request (not the initial request as it is a
  265. // plain GET /)
  266. return;
  267. }
  268. if (!Version.getFullVersion().equals(widgetsetVersion)) {
  269. getLogger().warning(String.format(Constants.WIDGETSET_MISMATCH_INFO,
  270. Version.getFullVersion(), widgetsetVersion));
  271. }
  272. }
  273. /**
  274. * Processes invocations data received from the client.
  275. * <p>
  276. * The invocations data can contain any number of RPC calls, including
  277. * legacy variable change calls that are processed separately.
  278. * <p>
  279. * Consecutive changes to the value of the same variable are combined and
  280. * changeVariables() is only called once for them. This preserves the Vaadin
  281. * 6 semantics for components and add-ons that do not use Vaadin 7 RPC
  282. * directly.
  283. *
  284. * @param ui
  285. * the UI receiving the invocations data
  286. * @param lastSyncIdSeenByClient
  287. * the most recent sync id the client has seen at the time the
  288. * request was sent
  289. * @param invocationsData
  290. * JSON containing all information needed to execute all
  291. * requested RPC calls.
  292. * @since 7.7
  293. */
  294. protected void handleInvocations(UI ui, int lastSyncIdSeenByClient,
  295. JsonArray invocationsData) {
  296. // TODO PUSH Refactor so that this is not needed
  297. LegacyCommunicationManager manager = ui.getSession()
  298. .getCommunicationManager();
  299. try {
  300. ConnectorTracker connectorTracker = ui.getConnectorTracker();
  301. Set<Connector> enabledConnectors = new HashSet<>();
  302. List<MethodInvocation> invocations = parseInvocations(
  303. ui.getConnectorTracker(), invocationsData,
  304. lastSyncIdSeenByClient);
  305. for (MethodInvocation invocation : invocations) {
  306. final ClientConnector connector = connectorTracker
  307. .getConnector(invocation.getConnectorId());
  308. if (connector != null && connector.isConnectorEnabled()) {
  309. enabledConnectors.add(connector);
  310. }
  311. }
  312. for (MethodInvocation invocation : invocations) {
  313. final ClientConnector connector = connectorTracker
  314. .getConnector(invocation.getConnectorId());
  315. if (connector == null) {
  316. getLogger().log(Level.WARNING,
  317. "Received RPC call for unknown connector with id {0} (tried to invoke {1}.{2})",
  318. new Object[] { invocation.getConnectorId(),
  319. invocation.getInterfaceName(),
  320. invocation.getMethodName() });
  321. continue;
  322. }
  323. if (!enabledConnectors.contains(connector)) {
  324. if (invocation instanceof LegacyChangeVariablesInvocation) {
  325. LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation;
  326. // TODO convert window close to a separate RPC call and
  327. // handle above - not a variable change
  328. // Handle special case where window-close is called
  329. // after the window has been removed from the
  330. // application or the application has closed
  331. Map<String, Object> changes = legacyInvocation
  332. .getVariableChanges();
  333. if (changes.size() == 1 && changes.containsKey("close")
  334. && Boolean.TRUE.equals(changes.get("close"))) {
  335. // Silently ignore this
  336. continue;
  337. }
  338. } else if (invocation instanceof ServerRpcMethodInvocation) {
  339. ServerRpcMethodInvocation rpc = (ServerRpcMethodInvocation) invocation;
  340. // special case for data communicator requesting more
  341. // data
  342. if (DataRequestRpc.class.getName()
  343. .equals(rpc.getInterfaceClass().getName())) {
  344. handleInvocation(ui, connector, rpc);
  345. }
  346. continue;
  347. }
  348. // Connector is disabled, log a warning and move to the next
  349. getLogger().warning(
  350. getIgnoredDisabledError("RPC call", connector));
  351. continue;
  352. }
  353. // DragAndDropService has null UI
  354. if (connector.getUI() != null
  355. && connector.getUI().isClosing()) {
  356. String msg = "Ignoring RPC call for connector "
  357. + connector.getClass().getName();
  358. if (connector instanceof Component) {
  359. String caption = ((Component) connector).getCaption();
  360. if (caption != null) {
  361. msg += ", caption=" + caption;
  362. }
  363. }
  364. msg += " in closed UI";
  365. getLogger().warning(msg);
  366. continue;
  367. }
  368. if (invocation instanceof ServerRpcMethodInvocation) {
  369. handleInvocation(ui, connector,
  370. (ServerRpcMethodInvocation) invocation);
  371. } else {
  372. LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation;
  373. handleInvocation(ui, connector, legacyInvocation);
  374. }
  375. }
  376. } catch (JsonException e) {
  377. getLogger().warning("Unable to parse RPC call from the client: "
  378. + e.getMessage());
  379. throw new RuntimeException(e);
  380. }
  381. }
  382. /**
  383. * Handles the given RPC method invocation for the given connector
  384. *
  385. * @since 7.7
  386. * @param ui
  387. * the UI containing the connector
  388. * @param connector
  389. * the connector the RPC is targeted to
  390. * @param invocation
  391. * information about the rpc to invoke
  392. */
  393. protected void handleInvocation(UI ui, ClientConnector connector,
  394. ServerRpcMethodInvocation invocation) {
  395. try {
  396. ServerRpcManager.applyInvocation(connector, invocation);
  397. } catch (RpcInvocationException e) {
  398. ui.getSession().getCommunicationManager()
  399. .handleConnectorRelatedException(connector, e);
  400. }
  401. }
  402. /**
  403. * Handles the given Legacy variable change RPC method invocation for the
  404. * given connector
  405. *
  406. * @since 7.7
  407. * @param ui
  408. * the UI containing the connector
  409. * @param connector
  410. * the connector the RPC is targeted to
  411. * @param invocation
  412. * information about the rpc to invoke
  413. */
  414. protected void handleInvocation(UI ui, ClientConnector connector,
  415. LegacyChangeVariablesInvocation legacyInvocation) {
  416. Map<String, Object> changes = legacyInvocation.getVariableChanges();
  417. try {
  418. if (connector instanceof VariableOwner) {
  419. // The source parameter is never used anywhere
  420. changeVariables(null, (VariableOwner) connector, changes);
  421. } else {
  422. throw new IllegalStateException(
  423. "Received a legacy variable change for "
  424. + connector.getClass().getName() + " ("
  425. + connector.getConnectorId()
  426. + ") which is not a VariableOwner. The client-side connector sent these legacy variables: "
  427. + changes.keySet());
  428. }
  429. } catch (Exception e) {
  430. ui.getSession().getCommunicationManager()
  431. .handleConnectorRelatedException(connector, e);
  432. }
  433. }
  434. /**
  435. * Parse JSON from the client into a list of MethodInvocation instances.
  436. *
  437. * @param connectorTracker
  438. * The ConnectorTracker used to lookup connectors
  439. * @param invocationsJson
  440. * JSON containing all information needed to execute all
  441. * requested RPC calls.
  442. * @param lastSyncIdSeenByClient
  443. * the most recent sync id the client has seen at the time the
  444. * request was sent
  445. * @return list of MethodInvocation to perform
  446. */
  447. private List<MethodInvocation> parseInvocations(
  448. ConnectorTracker connectorTracker, JsonArray invocationsJson,
  449. int lastSyncIdSeenByClient) {
  450. int invocationCount = invocationsJson.length();
  451. ArrayList<MethodInvocation> invocations = new ArrayList<>(
  452. invocationCount);
  453. MethodInvocation previousInvocation = null;
  454. // parse JSON to MethodInvocations
  455. for (int i = 0; i < invocationCount; ++i) {
  456. JsonArray invocationJson = invocationsJson.getArray(i);
  457. MethodInvocation invocation = parseInvocation(invocationJson,
  458. previousInvocation, connectorTracker,
  459. lastSyncIdSeenByClient);
  460. if (invocation != null) {
  461. // Can be null if the invocation was a legacy invocation and it
  462. // was merged with the previous one or if the invocation was
  463. // rejected because of an error.
  464. invocations.add(invocation);
  465. previousInvocation = invocation;
  466. }
  467. }
  468. return invocations;
  469. }
  470. private MethodInvocation parseInvocation(JsonArray invocationJson,
  471. MethodInvocation previousInvocation,
  472. ConnectorTracker connectorTracker, long lastSyncIdSeenByClient) {
  473. String connectorId = invocationJson.getString(0);
  474. String interfaceName = invocationJson.getString(1);
  475. String methodName = invocationJson.getString(2);
  476. if (connectorTracker.getConnector(connectorId) == null && !connectorId
  477. .equals(ApplicationConstants.DRAG_AND_DROP_CONNECTOR_ID)) {
  478. if (!connectorTracker.connectorWasPresentAsRequestWasSent(
  479. connectorId, lastSyncIdSeenByClient)) {
  480. getLogger().log(Level.WARNING, "RPC call to " + interfaceName
  481. + "." + methodName + " received for connector "
  482. + connectorId
  483. + " but no such connector could be found. Resynchronizing client.");
  484. // This is likely an out of sync issue (client tries to update a
  485. // connector which is not present). Force resync.
  486. connectorTracker.markAllConnectorsDirty();
  487. }
  488. return null;
  489. }
  490. JsonArray parametersJson = invocationJson.getArray(3);
  491. if (LegacyChangeVariablesInvocation
  492. .isLegacyVariableChange(interfaceName, methodName)) {
  493. if (!(previousInvocation instanceof LegacyChangeVariablesInvocation)) {
  494. previousInvocation = null;
  495. }
  496. return parseLegacyChangeVariablesInvocation(connectorId,
  497. interfaceName, methodName,
  498. (LegacyChangeVariablesInvocation) previousInvocation,
  499. parametersJson, connectorTracker);
  500. } else {
  501. return parseServerRpcInvocation(connectorId, interfaceName,
  502. methodName, parametersJson, connectorTracker);
  503. }
  504. }
  505. private LegacyChangeVariablesInvocation parseLegacyChangeVariablesInvocation(
  506. String connectorId, String interfaceName, String methodName,
  507. LegacyChangeVariablesInvocation previousInvocation,
  508. JsonArray parametersJson, ConnectorTracker connectorTracker) {
  509. if (parametersJson.length() != 2) {
  510. throw new JsonException(
  511. "Invalid parameters in legacy change variables call. Expected 2, was "
  512. + parametersJson.length());
  513. }
  514. String variableName = parametersJson.getString(0);
  515. UidlValue uidlValue = (UidlValue) JsonCodec.decodeInternalType(
  516. UidlValue.class, true, parametersJson.get(1), connectorTracker);
  517. Object value = uidlValue.getValue();
  518. if (previousInvocation != null
  519. && previousInvocation.getConnectorId().equals(connectorId)) {
  520. previousInvocation.setVariableChange(variableName, value);
  521. return null;
  522. } else {
  523. return new LegacyChangeVariablesInvocation(connectorId,
  524. variableName, value);
  525. }
  526. }
  527. private ServerRpcMethodInvocation parseServerRpcInvocation(
  528. String connectorId, String interfaceName, String methodName,
  529. JsonArray parametersJson, ConnectorTracker connectorTracker)
  530. throws JsonException {
  531. ClientConnector connector = connectorTracker.getConnector(connectorId);
  532. ServerRpcManager<?> rpcManager = connector.getRpcManager(interfaceName);
  533. if (rpcManager == null) {
  534. /*
  535. * Security: Don't even decode the json parameters if no RpcManager
  536. * corresponding to the received method invocation has been
  537. * registered.
  538. */
  539. getLogger().warning("Ignoring RPC call to " + interfaceName + "."
  540. + methodName + " in connector "
  541. + connector.getClass().getName() + "(" + connectorId
  542. + ") as no RPC implementation is registered");
  543. return null;
  544. }
  545. // Use interface from RpcManager instead of loading the class based on
  546. // the string name to avoid problems with OSGi
  547. Class<? extends ServerRpc> rpcInterface = rpcManager.getRpcInterface();
  548. ServerRpcMethodInvocation invocation = new ServerRpcMethodInvocation(
  549. connectorId, rpcInterface, methodName, parametersJson.length());
  550. Object[] parameters = new Object[parametersJson.length()];
  551. Type[] declaredRpcMethodParameterTypes = invocation.getMethod()
  552. .getGenericParameterTypes();
  553. for (int j = 0; j < parametersJson.length(); ++j) {
  554. JsonValue parameterValue = parametersJson.get(j);
  555. Type parameterType = declaredRpcMethodParameterTypes[j];
  556. parameters[j] = JsonCodec.decodeInternalOrCustomType(parameterType,
  557. parameterValue, connectorTracker);
  558. }
  559. invocation.setParameters(parameters);
  560. return invocation;
  561. }
  562. protected void changeVariables(Object source, VariableOwner owner,
  563. Map<String, Object> m) {
  564. owner.changeVariables(source, m);
  565. }
  566. protected String getMessage(Reader reader) throws IOException {
  567. StringBuilder sb = new StringBuilder(MAX_BUFFER_SIZE);
  568. char[] buffer = new char[MAX_BUFFER_SIZE];
  569. while (true) {
  570. int read = reader.read(buffer);
  571. if (read == -1) {
  572. break;
  573. }
  574. sb.append(buffer, 0, read);
  575. }
  576. return sb.toString();
  577. }
  578. private static final Logger getLogger() {
  579. return Logger.getLogger(ServerRpcHandler.class.getName());
  580. }
  581. /**
  582. * Generates an error message when the client is trying to to something
  583. * ('what') with a connector which is disabled or invisible.
  584. *
  585. * @since 7.1.8
  586. * @param connector
  587. * the connector which is disabled (or invisible)
  588. * @return an error message
  589. */
  590. public static String getIgnoredDisabledError(String what,
  591. ClientConnector connector) {
  592. String msg = "Ignoring " + what + " for disabled connector "
  593. + connector.getClass().getName();
  594. if (connector instanceof Component) {
  595. String caption = ((Component) connector).getCaption();
  596. if (caption != null) {
  597. msg += ", caption=" + caption;
  598. }
  599. }
  600. return msg;
  601. }
  602. }