-
Notifications
You must be signed in to change notification settings - Fork 166
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add a common API to intergrate with hotswap tools
Adds API to integrate with hotswap agents and to allow plugging class change reload plugins. The hotswapper also tries to refresh the views instead of reloading the page, if PUSH feature is enabled. Part of #19261 Part of #19262
- Loading branch information
1 parent
ba2400f
commit 30c624e
Showing
9 changed files
with
1,643 additions
and
2 deletions.
There are no files selected for viewing
416 changes: 416 additions & 0 deletions
416
flow-server/src/main/java/com/vaadin/flow/hotswap/Hotswapper.java
Large diffs are not rendered by default.
Oops, something went wrong.
101 changes: 101 additions & 0 deletions
101
flow-server/src/main/java/com/vaadin/flow/hotswap/VaadinHotswapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
* Copyright 2000-2024 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.flow.hotswap; | ||
|
||
import java.util.Set; | ||
|
||
import com.vaadin.flow.server.VaadinService; | ||
import com.vaadin.flow.server.VaadinSession; | ||
|
||
/** | ||
* Implementor ot this interface are responsible for update Vaadin components | ||
* when application classes change. | ||
* <p> | ||
* </p> | ||
* Listener instances are by default discovered using Flow | ||
* {@link com.vaadin.flow.di.Lookup} mechanisms. Implementors are usually | ||
* discovered and instantiated using {@link java.util.ServiceLoader}, meaning | ||
* that all implementations must have a zero-argument constructor and the fully | ||
* qualified name of the implementation class must be listed on a separate line | ||
* in a META-INF/services/com.vaadin.flow.hotswap.VaadinHotSwapper file present | ||
* in the jar file containing the implementation class. Integrations for | ||
* specific runtime environments, such as Spring and CDI, might also provide | ||
* other ways of discovering implementors. | ||
* <p> | ||
* </p> | ||
* For internal use only. May be renamed or removed in a future release. | ||
* | ||
* @author Vaadin Ltd | ||
* @since 24.5 | ||
*/ | ||
public interface VaadinHotswapper { | ||
|
||
/** | ||
* Called by Vaadin hotswap entry point when one or more application classes | ||
* have been updated. | ||
* <p> | ||
* </p> | ||
* This method is meant to perform application-wide updates. Operation | ||
* targeting Vaadin session should be implemented in | ||
* {@link #onClassLoadEvent(VaadinSession, Set, boolean)} method. | ||
* | ||
* @param vaadinService | ||
* active {@link VaadinService} instance. | ||
* @param classes | ||
* the set of changed classes. | ||
* @param redefined | ||
* {@literal true} if the classes have been redefined by hotswap | ||
* mechanism, {@literal false} if they have been loaded for the | ||
* first time by the ClassLoader. | ||
* @return {@literal true} if a browser page reload is required, | ||
* {@literal false} otherwise. | ||
* @see #onClassLoadEvent(VaadinSession, Set, boolean) | ||
*/ | ||
default boolean onClassLoadEvent(VaadinService vaadinService, | ||
Set<Class<?>> classes, boolean redefined) { | ||
// no-op by default | ||
return false; | ||
} | ||
|
||
/** | ||
* Called by Vaadin hotswap entry point when one or more application classes | ||
* have been updated. | ||
* <p> | ||
* </p> | ||
* This method is meant to perform updates at {@link VaadinSession} level. | ||
* Operation targeting the entire application should be implemented in | ||
* {@link #onClassLoadEvent(VaadinService, Set, boolean)} method. | ||
* | ||
* @param vaadinSession | ||
* the {@link VaadinSession} to be potentially updated. | ||
* @param classes | ||
* the set of changed classes. | ||
* @param redefined | ||
* {@literal true} if the classes have been redefined by hotswap | ||
* mechanism, {@literal false} if they have been loaded for the | ||
* first time by the ClassLoader. | ||
* @return {@literal true} if a browser page reload is required, | ||
* {@literal false} otherwise. | ||
* @see #onClassLoadEvent(VaadinService, Set, boolean) | ||
*/ | ||
default boolean onClassLoadEvent(VaadinSession vaadinSession, | ||
Set<Class<?>> classes, boolean redefined) { | ||
// no-op by default | ||
return false; | ||
} | ||
|
||
} |
36 changes: 36 additions & 0 deletions
36
flow-server/src/main/java/com/vaadin/flow/internal/ReflectionCacheHotswapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* Copyright 2000-2024 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.flow.internal; | ||
|
||
import java.util.Set; | ||
|
||
import com.vaadin.flow.hotswap.VaadinHotswapper; | ||
import com.vaadin.flow.server.VaadinService; | ||
|
||
/** | ||
* Clears all mappings from all reflection caches and related resources when one | ||
* or more classes has been changed. | ||
*/ | ||
public class ReflectionCacheHotswapper implements VaadinHotswapper { | ||
|
||
@Override | ||
public boolean onClassLoadEvent(VaadinService vaadinService, | ||
Set<Class<?>> classes, boolean redefined) { | ||
ReflectionCache.clearAll(); | ||
return false; | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
flow-server/src/main/java/com/vaadin/flow/router/internal/RouteRegistryHotswapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* Copyright 2000-2024 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.flow.router.internal; | ||
|
||
import java.util.Set; | ||
|
||
import com.vaadin.flow.component.Component; | ||
import com.vaadin.flow.hotswap.VaadinHotswapper; | ||
import com.vaadin.flow.router.Route; | ||
import com.vaadin.flow.server.SessionRouteRegistry; | ||
import com.vaadin.flow.server.VaadinService; | ||
import com.vaadin.flow.server.VaadinSession; | ||
import com.vaadin.flow.server.startup.ApplicationRouteRegistry; | ||
|
||
/** | ||
* A component that reacts on class changes to update route registries. | ||
* <p> | ||
* </p> | ||
* This class is meant to be used in combination wit Flow | ||
* {@link com.vaadin.flow.hotswap.Hotswapper} to immediately update routes | ||
* registries when classes have been added or modified. | ||
* <p> | ||
* </p> | ||
* For internal use only. May be renamed or removed in a future release. | ||
* | ||
* @since 24.4 | ||
*/ | ||
public class RouteRegistryHotswapper implements VaadinHotswapper { | ||
|
||
/** | ||
* Updates both application registry, to reflect provided class changes. | ||
* <p> | ||
* </p> | ||
* For modified route classes, the following changes are taken into account: | ||
* <ul> | ||
* <li>{@link Route} annotation removed: the previous route is removed from | ||
* the registry</li> | ||
* <li>{@link Route#value()} modified</li> | ||
* </ul> | ||
* | ||
*/ | ||
@Override | ||
public boolean onClassLoadEvent(VaadinService vaadinService, | ||
Set<Class<?>> classes, boolean redefined) { | ||
Set<Class<?>> addedClasses = redefined ? Set.of() : classes; | ||
Set<Class<?>> modifiedClasses = redefined ? classes : Set.of(); | ||
Set<Class<?>> removedClasses = Set.of(); | ||
|
||
if (hasNoComponentClasses(addedClasses) | ||
&& hasNoComponentClasses(modifiedClasses) | ||
&& hasNoComponentClasses(removedClasses)) { | ||
return false; | ||
} | ||
ApplicationRouteRegistry appRegistry = ApplicationRouteRegistry | ||
.getInstance(vaadinService.getContext()); | ||
RouteUtil.updateRouteRegistry(appRegistry, addedClasses, | ||
modifiedClasses, removedClasses); | ||
return false; | ||
} | ||
|
||
@Override | ||
public boolean onClassLoadEvent(VaadinSession session, | ||
Set<Class<?>> classes, boolean redefined) { | ||
Set<Class<?>> addedClasses = redefined ? Set.of() : classes; | ||
Set<Class<?>> modifiedClasses = redefined ? classes : Set.of(); | ||
Set<Class<?>> removedClasses = Set.of(); | ||
if (hasNoComponentClasses(addedClasses) | ||
&& hasNoComponentClasses(modifiedClasses) | ||
&& hasNoComponentClasses(removedClasses)) { | ||
return false; | ||
} | ||
if (session.getAttribute(SessionRouteRegistry.class) != null) { | ||
RouteUtil.updateRouteRegistry( | ||
SessionRouteRegistry.getSessionRegistry(session), Set.of(), | ||
modifiedClasses, removedClasses); | ||
} | ||
return false; | ||
} | ||
|
||
private boolean hasNoComponentClasses(Set<Class<?>> classes) { | ||
return classes == null || classes.isEmpty() || classes.stream() | ||
.noneMatch(Component.class::isAssignableFrom); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
flow-server/src/main/resources/META-INF/services/com.vaadin.flow.hotswap.VaadinHotswapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# | ||
# Copyright 2000-2024 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. | ||
# | ||
|
||
com.vaadin.flow.router.internal.RouteRegistryHotswapper | ||
com.vaadin.flow.internal.ReflectionCacheHotswapper |
Oops, something went wrong.