All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.base.devserver.DebugWindowConnection Maven / Gradle / Ivy

/**
 * Copyright (C) 2000-2023 Vaadin Ltd
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See  for the full
 * license.
 */
package com.vaadin.base.devserver;

import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.vaadin.base.devserver.stats.DevModeUsageStatistics;
import com.vaadin.experimental.FeatureFlags;
import com.vaadin.flow.internal.BrowserLiveReload;
import com.vaadin.flow.server.VaadinContext;

import org.atmosphere.cpr.AtmosphereResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import elemental.json.Json;
import elemental.json.JsonObject;

/**
 * {@link BrowserLiveReload} implementation class.
 * 

* For internal use only. May be renamed or removed in a future release. * * @author Vaadin Ltd * */ public class DebugWindowConnection implements BrowserLiveReload { private final ClassLoader classLoader; private VaadinContext context; private final ConcurrentLinkedQueue> atmosphereResources = new ConcurrentLinkedQueue<>(); private Backend backend = null; private static final EnumMap> IDENTIFIER_CLASSES = new EnumMap<>( Backend.class); private final ObjectMapper objectMapper = new ObjectMapper(); static { IDENTIFIER_CLASSES.put(Backend.JREBEL, Collections.singletonList( "org.zeroturnaround.jrebel.vaadin.JRebelClassEventListener")); IDENTIFIER_CLASSES.put(Backend.HOTSWAP_AGENT, Collections.singletonList( "org.hotswap.agent.plugin.vaadin.VaadinIntegration")); IDENTIFIER_CLASSES.put(Backend.SPRING_BOOT_DEVTOOLS, Arrays.asList( "com.vaadin.flow.spring.SpringServlet", "org.springframework.boot.devtools.livereload.LiveReloadServer")); } DebugWindowConnection(VaadinContext context) { this(DebugWindowConnection.class.getClassLoader(), context); } DebugWindowConnection(ClassLoader classLoader, VaadinContext context) { this.classLoader = classLoader; this.context = context; } @Override public Backend getBackend() { if (backend != null) { return backend; } for (Map.Entry> entry : IDENTIFIER_CLASSES .entrySet()) { Backend backendCandidate = entry.getKey(); boolean found = true; for (String clazz : entry.getValue()) { try { classLoader.loadClass(clazz); } catch (ClassNotFoundException e) { // NOSONAR getLogger().debug("Class {} not found, excluding {}", clazz, backendCandidate); found = false; break; } } if (found) { backend = backendCandidate; break; } } return backend; } @Override public void setBackend(Backend backend) { assert (backend != null); this.backend = backend; } @Override public void onConnect(AtmosphereResource resource) { resource.suspend(-1); atmosphereResources.add(new WeakReference<>(resource)); resource.getBroadcaster().broadcast("{\"command\": \"hello\"}", resource); send(resource, "serverInfo", new ServerInfo()); send(resource, "featureFlags", new FeatureFlagMessage(FeatureFlags .get(context).getFeatures().stream() .filter(feature -> !feature.equals(FeatureFlags.EXAMPLE)) .collect(Collectors.toList()))); } private void send(AtmosphereResource resource, String command, Object data) { try { resource.getBroadcaster().broadcast(objectMapper.writeValueAsString( new DebugWindowMessage(command, data)), resource); } catch (Exception e) { getLogger().error("Error sending message", e); } } @Override public void onDisconnect(AtmosphereResource resource) { if (!atmosphereResources .removeIf(resourceRef -> resource.equals(resourceRef.get()))) { String uuid = resource.uuid(); getLogger().warn( "Push connection {} is not a live-reload connection or already closed", uuid); } } @Override public boolean isLiveReload(AtmosphereResource resource) { return atmosphereResources.stream() .anyMatch(resourceRef -> resource.equals(resourceRef.get())); } @Override public void reload() { atmosphereResources.forEach(resourceRef -> { AtmosphereResource resource = resourceRef.get(); if (resource != null) { resource.getBroadcaster().broadcast("{\"command\": \"reload\"}", resource); } }); } @Override public void onMessage(String message) { if (message.isEmpty()) { getLogger().debug("Received live reload heartbeat"); return; } JsonObject json = Json.parse(message); String command = json.getString("command"); if ("setFeature".equals(command)) { JsonObject data = json.getObject("data"); FeatureFlags.get(context).setEnabled(data.getString("featureId"), data.getBoolean("enabled")); } else if ("reportTelemetry".equals(command)) { JsonObject data = json.getObject("data"); DevModeUsageStatistics.handleBrowserData(data); } } private static Logger getLogger() { return LoggerFactory.getLogger(DebugWindowConnection.class.getName()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy