use of com.vaadin.flow.internal.StateTree in project flow by vaadin.
the class AttachTemplateChildRpcHandler method handleNode.
@Override
protected Optional<Runnable> handleNode(StateNode node, JsonObject invocationJson) {
assert invocationJson.hasKey(JsonConstants.RPC_ATTACH_REQUESTED_ID);
assert invocationJson.hasKey(JsonConstants.RPC_ATTACH_ASSIGNED_ID);
assert invocationJson.hasKey(JsonConstants.RPC_ATTACH_ID);
int requestedId = (int) invocationJson.getNumber(JsonConstants.RPC_ATTACH_REQUESTED_ID);
int assignedId = (int) invocationJson.getNumber(JsonConstants.RPC_ATTACH_ASSIGNED_ID);
StateTree tree = (StateTree) node.getOwner();
StateNode requestedNode = tree.getNodeById(requestedId);
StateNode parent = tree.getNodeById(requestedId).getParent();
JsonValue id = invocationJson.get(JsonConstants.RPC_ATTACH_ID);
String tag = requestedNode.getFeature(ElementData.class).getTag();
Logger logger = LoggerFactory.getLogger(AttachTemplateChildRpcHandler.class.getName());
if (assignedId == -1) {
logger.error("Attach existing element has failed because " + "the client-side element is not found");
if (id instanceof JsonNull) {
throw new IllegalStateException(String.format("The element with the tag name '%s' was " + "not found in the parent with id='%d'", tag, parent.getId()));
} else {
throw new IllegalStateException(String.format("The element with the tag name '%s' and id '%s' was " + "not found in the parent with id='%d'", tag, id.asString(), parent.getId()));
}
} else if (requestedId != assignedId) {
logger.error("Attach existing element has failed because " + "the element has been already attached from the server side");
if (id instanceof JsonNull) {
throw new IllegalStateException(String.format("The element with the tag name '%s' is already " + "attached to the parent with id='%d'", tag, parent.getId()));
} else {
throw new IllegalStateException(String.format("The element with the tag name '%s' and id '%s' is " + "already attached to the parent with id='%d'", tag, id.asString(), parent.getId()));
}
} else {
logger.error("Attach existing element request succeded. " + "But the response about this is unexpected");
// side should not respond
throw new IllegalArgumentException("Unexpected successful attachment " + "response is received from the client-side. " + "Client side should not respond if everything is fine");
}
}
use of com.vaadin.flow.internal.StateTree in project flow by vaadin.
the class MapSyncRpcHandler method tryConvert.
private Serializable tryConvert(Serializable value, StateNode context) {
if (value instanceof JsonObject) {
JsonObject json = (JsonObject) value;
if (json.hasKey("nodeId")) {
StateTree tree = (StateTree) context.getOwner();
double id = json.getNumber("nodeId");
StateNode stateNode = tree.getNodeById((int) id);
return tryCopyStateNode(stateNode, json);
}
}
return value;
}
use of com.vaadin.flow.internal.StateTree in project flow by vaadin.
the class AttachExistingElementRpcHandlerTest method handleNode_error.
@Test
public void handleNode_error() {
AttachExistingElementRpcHandler handler = new AttachExistingElementRpcHandler();
int requestedId = 1;
JsonObject object = Json.createObject();
object.put(JsonConstants.RPC_ATTACH_REQUESTED_ID, requestedId);
object.put(JsonConstants.RPC_ATTACH_ASSIGNED_ID, -1);
object.put(JsonConstants.RPC_ATTACH_TAG_NAME, "div");
object.put(JsonConstants.RPC_ATTACH_INDEX, -1);
StateNode node = Mockito.mock(StateNode.class);
StateNode requested = Mockito.mock(StateNode.class);
StateTree tree = Mockito.mock(StateTree.class);
Mockito.when(node.getOwner()).thenReturn(tree);
Mockito.when(tree.getNodeById(requestedId)).thenReturn(requested);
AttachExistingElementFeature feature = new AttachExistingElementFeature(node);
Node<?> parentNode = Mockito.mock(Node.class);
ChildElementConsumer consumer = Mockito.mock(ChildElementConsumer.class);
Element sibling = Mockito.mock(Element.class);
feature.register(parentNode, sibling, requested, consumer);
Mockito.when(node.getFeature(AttachExistingElementFeature.class)).thenReturn(feature);
handler.handleNode(node, object);
Mockito.verify(consumer).onError(parentNode, "div", sibling);
assertNodeIsUnregistered(node, requested, feature);
}
use of com.vaadin.flow.internal.StateTree in project flow by vaadin.
the class AttachExistingElementRpcHandlerTest method handleNode_requestedIdEqualsAssignedId.
@Test
public void handleNode_requestedIdEqualsAssignedId() {
AttachExistingElementRpcHandler handler = new AttachExistingElementRpcHandler();
int requestedId = 1;
int index = 2;
JsonObject object = Json.createObject();
object.put(JsonConstants.RPC_ATTACH_REQUESTED_ID, requestedId);
object.put(JsonConstants.RPC_ATTACH_ASSIGNED_ID, requestedId);
object.put(JsonConstants.RPC_ATTACH_TAG_NAME, "div");
object.put(JsonConstants.RPC_ATTACH_INDEX, index);
StateNode node = Mockito.mock(StateNode.class);
StateNode requested = Mockito.mock(StateNode.class);
StateTree tree = Mockito.mock(StateTree.class);
Mockito.when(node.getOwner()).thenReturn(tree);
Mockito.when(tree.getNodeById(requestedId)).thenReturn(requested);
Mockito.when(requested.hasFeature(Mockito.any())).thenReturn(true);
AttachExistingElementFeature feature = new AttachExistingElementFeature(node);
Node<?> parentNode = Mockito.mock(Node.class);
ChildElementConsumer consumer = Mockito.mock(ChildElementConsumer.class);
Element sibling = Mockito.mock(Element.class);
feature.register(parentNode, sibling, requested, consumer);
Mockito.when(node.getFeature(AttachExistingElementFeature.class)).thenReturn(feature);
handler.handleNode(node, object);
assertNodeIsUnregistered(node, requested, feature);
Mockito.verify(parentNode).insertChild(index, Element.get(requested));
Mockito.verify(consumer).accept(Element.get(requested));
}
use of com.vaadin.flow.internal.StateTree in project flow by vaadin.
the class UidlWriter method encodeChanges.
/**
* Encodes the state tree changes of the given UI. The executions registered
* at
* {@link StateTree#beforeClientResponse(com.vaadin.flow.internal.StateNode, com.vaadin.flow.function.SerializableConsumer)}
* at evaluated before the changes are encoded.
*
* @param ui
* the UI
* @param stateChanges
* a JSON array to put state changes into
* @param templates
* a JSON object to put new template nodes into
* @see StateTree#runExecutionsBeforeClientResponse()
*/
private void encodeChanges(UI ui, JsonArray stateChanges, JsonObject templates) {
UIInternals uiInternals = ui.getInternals();
StateTree stateTree = uiInternals.getStateTree();
stateTree.runExecutionsBeforeClientResponse();
Consumer<TemplateNode> templateEncoder = new Consumer<TemplateNode>() {
@Override
public void accept(TemplateNode templateNode) {
// Send to client if it's a new template
if (!uiInternals.isTemplateSent(templateNode)) {
uiInternals.setTemplateSent(templateNode);
templates.put(Integer.toString(templateNode.getId()), templateNode.toJson(this));
}
}
};
Set<Class<? extends Component>> componentsWithDependencies = new LinkedHashSet<>();
stateTree.collectChanges(change -> {
// Ensure new templates are sent to the client
runIfNewTemplateChange(change, templateEncoder);
if (attachesComponent(change)) {
change.getNode().getFeature(ComponentMapping.class).getComponent().ifPresent(component -> addComponentHierarchy(ui, componentsWithDependencies, component));
}
// Encode the actual change
stateChanges.set(stateChanges.length(), change.toJson(uiInternals.getConstantPool()));
});
componentsWithDependencies.forEach(uiInternals::addComponentDependencies);
}
Aggregations