Skip to content

Commit

Permalink
Merge branch 'main' into fix/flush-logic-v2
Browse files Browse the repository at this point in the history
  • Loading branch information
tepi authored Nov 7, 2024
2 parents 044c8be + 4a08a10 commit 3d3a434
Show file tree
Hide file tree
Showing 41 changed files with 866 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,7 @@ protected final native AtmosphereConfiguration createConfig()
fallbackTransport: 'long-polling',
contentType: 'application/json; charset=UTF-8',
reconnectInterval: 5000,
maxWebsocketErrorRetries: 12,
timeout: -1,
maxReconnectOnClose: 10000000,
trackMessageLength: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,18 @@ public void pushOk(PushConnection pushConnection) {
debug("pushOk()");
if (isReconnecting()) {
resolveTemporaryError(Type.PUSH);
if (registry.getRequestResponseTracker().hasActiveRequest()) {
debug("pushOk() Reset active request state when reconnecting PUSH because of a network error.");
endRequest();
// for bidirectional transport, the pending message is not sent
// as reconnection payload, so immediately push the pending
// changes on reconnect
if (pushConnection.isBidirectional()) {
Console.debug(
"Flush pending messages after PUSH reconnection.");
registry.getMessageSender().sendInvocationsToServer();
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ public enum ResynchronizationState {

private ResynchronizationState resynchronizationState = ResynchronizationState.NOT_ACTIVE;

private JsonObject pushPendingMessage;

/**
* Creates a new instance connected to the given registry.
*
Expand Down Expand Up @@ -104,6 +106,17 @@ public void sendInvocationsToServer() {
*
*/
private void doSendInvocationsToServer() {
// If there's a stored message, resend it and postpone processing the
// rest of the queued messages to prevent resynchronization issues.
if (pushPendingMessage != null) {
Console.log("Sending pending push message "
+ pushPendingMessage.toJson());
JsonObject payload = pushPendingMessage;
pushPendingMessage = null;
registry.getRequestResponseTracker().startRequest();
send(payload);
return;
}

ServerRpcQueue serverRpcQueue = registry.getServerRpcQueue();
if (serverRpcQueue.isEmpty()
Expand Down Expand Up @@ -181,6 +194,13 @@ private JsonObject preparePayload(final JsonArray reqInvocations,
*/
public void send(final JsonObject payload) {
if (push != null && push.isBidirectional()) {
// When using bidirectional transport, the payload is not resent
// to the server during reconnection attempts.
// Keep a copy of the message, so that it could be resent to the
// server after a reconnection.
// Reference will be cleaned up once the server confirms it has
// seen this message
pushPendingMessage = payload;
push.push(payload);
} else {
registry.getXhrConnection().send(payload);
Expand Down Expand Up @@ -260,7 +280,14 @@ public void resynchronize() {
*/
public void setClientToServerMessageId(int nextExpectedId, boolean force) {
if (nextExpectedId == clientToServerMessageId) {
// No op as everything matches they way it should
// Everything matches they way it should
// Remove potential pending PUSH message if it has already been seen
// by the server.
if (pushPendingMessage != null
&& (int) pushPendingMessage.getNumber(
ApplicationConstants.CLIENT_TO_SERVER_ID) < nextExpectedId) {
pushPendingMessage = null;
}
return;
}
if (force) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ public class BuildDevBundleMojo extends AbstractMojo
@Parameter(defaultValue = "${project.basedir}/src/main/" + FRONTEND)
private File frontendDirectory;

@Parameter(property = InitParameters.NPM_EXCLUDE_WEB_COMPONENTS, defaultValue = "false")
private boolean npmExcludeWebComponents;

@Override
public void execute() throws MojoFailureException {
long start = System.nanoTime();
Expand Down Expand Up @@ -469,4 +472,9 @@ public boolean checkRuntimeDependency(String groupId, String artifactId,
Consumer<String> missingDependencyMessageConsumer) {
return false;
}

@Override
public boolean isNpmExcludeWebComponents() {
return npmExcludeWebComponents;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ internal class GradlePluginAdapter(

override fun applicationIdentifier(): String = config.applicationIdentifier.get()

override fun isNpmExcludeWebComponents(): Boolean = config.npmExcludeWebComponents.get()

override fun checkRuntimeDependency(
groupId: String,
artifactId: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ internal class PrepareFrontendInputProperties(private val config: PluginEffectiv
@Input
public fun getApplicationIdentifier(): Provider<String> = config.applicationIdentifier

@Input
public fun getNpmExcludeWebComponents(): Provider<Boolean> = config.npmExcludeWebComponents

@Input
@Optional
public fun getNodeExecutablePath(): Provider<String> = tools
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ public abstract class VaadinFlowPluginExtension @Inject constructor(private val

public abstract val applicationIdentifier: Property<String>

public abstract val npmExcludeWebComponents: Property<Boolean>

public fun filterClasspath(@DelegatesTo(value = ClasspathFilter::class, strategy = Closure.DELEGATE_FIRST) block: Closure<*>) {
block.delegate = classpathFilter
block.resolveStrategy = Closure.DELEGATE_FIRST
Expand Down Expand Up @@ -439,6 +441,9 @@ public class PluginEffectiveConfiguration(
))
.overrideWithSystemProperty("vaadin.${InitParameters.APPLICATION_IDENTIFIER}")

public val npmExcludeWebComponents: Provider<Boolean> = extension
.npmExcludeWebComponents.convention(false)

/**
* Finds the value of a boolean property. It searches in gradle and system properties.
*
Expand Down Expand Up @@ -499,7 +504,8 @@ public class PluginEffectiveConfiguration(
"alwaysExecutePrepareFrontend=${alwaysExecutePrepareFrontend.get()}, " +
"frontendHotdeploy=${frontendHotdeploy.get()}," +
"reactEnable=${reactEnable.get()}," +
"cleanFrontendFiles=${cleanFrontendFiles.get()}" +
"cleanFrontendFiles=${cleanFrontendFiles.get()}," +
"npmExcludeWebComponents=${npmExcludeWebComponents.get()}" +
")"
public companion object {
public fun get(project: Project): PluginEffectiveConfiguration =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ public abstract class FlowModeAbstractMojo extends AbstractMojo
@Parameter(property = InitParameters.REACT_ENABLE, defaultValue = "${null}")
private Boolean reactEnable;

@Parameter(property = InitParameters.NPM_EXCLUDE_WEB_COMPONENTS, defaultValue = "false")
private boolean npmExcludeWebComponents;

/**
* Identifier for the application.
* <p>
Expand Down Expand Up @@ -570,4 +573,9 @@ public String applicationIdentifier() {
project.getGroupId() + ":" + project.getArtifactId(),
StandardCharsets.UTF_8);
}

@Override
public boolean isNpmExcludeWebComponents() {
return npmExcludeWebComponents;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,9 @@ public void execute() throws MojoExecutionException, MojoFailureException {
.withHomeNodeExecRequired(requireHomeNodeExec())
.setJavaResourceFolder(javaResourceFolder())
.withProductionMode(productionMode)
.withReact(isReactEnabled());
.withReact(isReactEnabled())
.withNpmExcludeWebComponents(
isNpmExcludeWebComponents());
new NodeTasks(options).execute();
logInfo("SBOM generation created node_modules and all needed metadata. "
+ "If you don't need it, please run mvn vaadin:clean-frontend");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
import static com.vaadin.flow.server.InitParameters.FRONTEND_HOTDEPLOY;
import static com.vaadin.flow.server.InitParameters.NODE_DOWNLOAD_ROOT;
import static com.vaadin.flow.server.InitParameters.NODE_VERSION;
import static com.vaadin.flow.server.InitParameters.NPM_EXCLUDE_WEB_COMPONENTS;
import static com.vaadin.flow.server.InitParameters.REACT_ENABLE;
import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_INITIAL_UIDL;
import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE;
Expand Down Expand Up @@ -165,7 +166,9 @@ public static void prepareFrontend(PluginAdapterBase adapter)
.setNodeAutoUpdate(adapter.nodeAutoUpdate())
.withHomeNodeExecRequired(adapter.requireHomeNodeExec())
.setJavaResourceFolder(adapter.javaResourceFolder())
.withProductionMode(false).withReact(adapter.isReactEnabled());
.withProductionMode(false).withReact(adapter.isReactEnabled())
.withNpmExcludeWebComponents(
adapter.isNpmExcludeWebComponents());

// Copy jar artifact contents in TaskCopyFrontendFiles
options.copyResources(adapter.getJarFiles());
Expand Down Expand Up @@ -263,6 +266,10 @@ public static File propagateBuildInfo(PluginAdapterBase adapter) {
}

buildInfo.put(REACT_ENABLE, adapter.isReactEnabled());
if (adapter.isNpmExcludeWebComponents()) {
buildInfo.put(NPM_EXCLUDE_WEB_COMPONENTS,
adapter.isNpmExcludeWebComponents());
}

try {
FileUtils.forceMkdir(token.getParentFile());
Expand Down Expand Up @@ -339,7 +346,9 @@ public static void runNodeUpdater(PluginAdapterBuild adapter)
.withPostinstallPackages(adapter.postinstallPackages())
.withCiBuild(adapter.ciBuild())
.withForceProductionBuild(adapter.forceProductionBuild())
.withReact(adapter.isReactEnabled());
.withReact(adapter.isReactEnabled())
.withNpmExcludeWebComponents(
adapter.isNpmExcludeWebComponents());
new NodeTasks(options).execute();
} catch (ExecutionFailedException exception) {
throw exception;
Expand Down Expand Up @@ -405,7 +414,9 @@ public static void runDevBuildNodeUpdater(PluginAdapterBuild adapter)
.withBundleBuild(true)
.skipDevBundleBuild(adapter.skipDevBundleBuild())
.withCompressBundle(adapter.compressBundle())
.withReact(adapter.isReactEnabled());
.withReact(adapter.isReactEnabled())
.withNpmExcludeWebComponents(
adapter.isNpmExcludeWebComponents());
new NodeTasks(options).execute();
} catch (ExecutionFailedException exception) {
throw exception;
Expand Down Expand Up @@ -751,6 +762,7 @@ public static void updateBuildFile(PluginAdapterBuild adapter,
buildInfo.remove(Constants.CONNECT_OPEN_API_FILE_TOKEN);
buildInfo.remove(Constants.PROJECT_FRONTEND_GENERATED_DIR_TOKEN);
buildInfo.remove(InitParameters.BUILD_FOLDER);
buildInfo.remove(InitParameters.NPM_EXCLUDE_WEB_COMPONENTS);
// Premium features flag is always true, because Vaadin CI server
// uses Enterprise sub, thus it's always true.
// Thus, resets the premium feature flag and DAU flag before asking
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,4 +337,11 @@ default Lookup createLookup(ClassFinder classFinder) {
* {@literal blank}.
*/
String applicationIdentifier();

/**
* Whether to include web component npm packages in packages.json.
*
* @return {@code true} to include web component npm packages.
*/
boolean isNpmExcludeWebComponents();
}
40 changes: 40 additions & 0 deletions flow-server/src/main/java/com/vaadin/flow/component/Component.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@
*/
package com.vaadin.flow.component;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serial;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import java.util.stream.Stream.Builder;
Expand All @@ -32,6 +37,7 @@
import com.vaadin.flow.dom.ShadowRoot;
import com.vaadin.flow.i18n.I18NProvider;
import com.vaadin.flow.internal.AnnotationReader;
import com.vaadin.flow.internal.CurrentInstance;
import com.vaadin.flow.internal.LocaleUtil;
import com.vaadin.flow.internal.nodefeature.ElementData;
import com.vaadin.flow.server.Attributes;
Expand Down Expand Up @@ -820,4 +826,38 @@ public void removeFromParent() {
getElement().removeFromParent();
}

@Serial
private void writeObject(ObjectOutputStream out) throws IOException {
if (this instanceof UI ui) {
Map<Class<?>, CurrentInstance> instances = CurrentInstance
.setCurrent(ui);
try {
out.defaultWriteObject();
} finally {
CurrentInstance.restoreInstances(instances);
}
} else {
out.defaultWriteObject();
}
}

@Serial
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
if (this instanceof UI ui) {
Map<Class<?>, CurrentInstance> instances = CurrentInstance
.getInstances();
// Cannot use CurrentInstance.setCurrent(this) because it will try
// to get VaadinSession from UI.internals that is not yet available
CurrentInstance.set(UI.class, ui);
try {
in.defaultReadObject();
} finally {
CurrentInstance.restoreInstances(instances);
}
} else {
in.defaultReadObject();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -285,4 +285,9 @@ public class InitParameters implements Serializable {
*/
public static final String APPLICATION_IDENTIFIER = "applicationIdentifier";

/**
* Configuration name for excluding npm packages for web components.
*/
public static final String NPM_EXCLUDE_WEB_COMPONENTS = "npm.excludeWebComponents";

}
Loading

0 comments on commit 3d3a434

Please sign in to comment.