/* * Copyright 2000-2016 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.Serializable; import java.io.Writer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.logging.Logger; import com.vaadin.server.ClientConnector; import com.vaadin.server.LegacyPaint; import com.vaadin.server.PaintTarget; import com.vaadin.ui.Component; import com.vaadin.ui.LegacyComponent; import com.vaadin.ui.UI; /** * Serializes legacy UIDL changes to JSON. * * @author Vaadin Ltd * @since 7.1 */ public class LegacyUidlWriter implements Serializable { /** * Writes a JSON array containing the changes of all dirty * {@link LegacyComponent}s in the given UI. * * @param ui * The {@link UI} whose legacy changes to write * @param writer * The {@link Writer} to write the JSON with * @param target * The {@link PaintTarget} to use * @throws IOException * If the serialization fails. */ public void write(UI ui, Writer writer, PaintTarget target) throws IOException { Collection<ClientConnector> dirtyVisibleConnectors = ui .getConnectorTracker().getDirtyVisibleConnectors(); List<Component> legacyComponents = new ArrayList<>( dirtyVisibleConnectors.size()); for (ClientConnector connector : dirtyVisibleConnectors) { // All Components that want to use paintContent must implement // LegacyComponent if (connector instanceof LegacyComponent) { legacyComponents.add((Component) connector); } } sortByHierarchy(legacyComponents); writer.write("["); for (Component c : legacyComponents) { getLogger() .fine("Painting LegacyComponent " + c.getClass().getName() + "@" + Integer.toHexString(c.hashCode())); target.startTag("change"); final String pid = c.getConnectorId(); target.addAttribute("pid", pid); LegacyPaint.paint(c, target); target.endTag("change"); } writer.write("]"); } private void sortByHierarchy(List<Component> paintables) { // Vaadin 6 requires parents to be painted before children as component // containers rely on that their updateFromUIDL method has been called // before children start calling e.g. updateCaption Collections.sort(paintables, (Component c1, Component c2) -> { int depth1 = 0; while (c1.getParent() != null) { depth1++; c1 = c1.getParent(); } int depth2 = 0; while (c2.getParent() != null) { depth2++; c2 = c2.getParent(); } if (depth1 < depth2) { return -1; } if (depth1 > depth2) { return 1; } return 0; }); } private static final Logger getLogger() { return Logger.getLogger(LegacyUidlWriter.class.getName()); } }