├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── github │ └── jneat │ └── jsf │ ├── SpringScopeRequest.java │ ├── SpringScopeSession.java │ ├── SpringScopeView.java │ ├── ViewScope.java │ └── ViewScopeViewMapListener.java └── resources └── com └── github └── jneat └── jsf └── jsfSpringScope.xml /.gitignore: -------------------------------------------------------------------------------- 1 | #Java specific 2 | *.class 3 | .gradle 4 | 5 | #Build and cache dirs 6 | /private 7 | /build 8 | 9 | #IDE 10 | nbproject 11 | nb-configuration.xml 12 | nbactions.xml 13 | .nb-gradle 14 | .nb-gradle-properties 15 | .settings 16 | .idea 17 | *.iml 18 | *.ipr 19 | *.iws 20 | .project 21 | .classpath 22 | 23 | #Generic files to ignore 24 | *~ 25 | *.lock 26 | *.DS_Store 27 | *.swp 28 | *.out 29 | /target/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 by rumatoest at github.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Implementation of JSF view scope for Spring 2 | 3 | [![Release](https://jitpack.io/v/jneat/spring-jsf.svg)](https://jitpack.io/#jneat/spring-jsf) 4 | 5 | The main idea is to put spring bean into JSF view scope, 6 | that you can access from ```FacesContext.getCurrentInstance().getViewRoot().getViewMap()``` 7 | 8 | This module provides appropriate Spring annotations for related JSF scopes: 9 | 10 | - @SpringScopeRequest - for request scope 11 | - @SpringScopeSession - for session scope 12 | - @SpringScopeView - for view scope 13 | 14 | ## Add to your project 15 | 16 | You can add this artifact to your project using [JitPack](https://jitpack.io/#jneat/spring-jsf). 17 | All versions list, instructions for gradle, maven, ivy etc. can be found by link above. 18 | 19 | To get latest commit use -SNAPSHOT instead version number. 20 | 21 | ## Configuration 22 | 23 | Just add next line to your applicationContext.xml 24 | ``` 25 | 26 | ``` 27 | 28 | 29 | ## Usage 30 | 31 | ### XML configuration 32 | ``` 33 | 34 | 35 | 36 | ``` 37 | 38 | ### Java configuration 39 | ``` 40 | import java.util.HashMap; 41 | import java.util.Map; 42 | 43 | import com.github.jneat.jsf.ViewScope; 44 | import org.springframework.beans.factory.config.CustomScopeConfigurer; 45 | import org.springframework.context.annotation.Configuration; 46 | 47 | @Configuration 48 | public class MyViewScope extends CustomScopeConfigurer { 49 | 50 | public InitViewScope() { 51 | log.info("Init ViewScope"); 52 | Map map = new HashMap<>(); 53 | map.put("view", new ViewScope()); 54 | super.setScopes(map); 55 | } 56 | } 57 | ``` 58 | 59 | 60 | ### In your code 61 | ``` 62 | import com.github.jneat.jsf.SpringScopeView; 63 | 64 | @SpringScopeView 65 | @Component 66 | class WhateverBean { 67 | // Implementation 68 | } 69 | ``` -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.github.jneat 6 | spring-jsf 7 | 0.2.1 8 | jar 9 | 10 | spring-jsf 11 | Spring integration with JSF 12 | https://github.com/jneat/spring-jsf 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 20 | 21 | 22 | javax.faces 23 | javax.faces-api 24 | 2.1 25 | provided 26 | 27 | 28 | javax.servlet 29 | javax.servlet-api 30 | 3.0.1 31 | provided 32 | 33 | 34 | commons-logging 35 | commons-logging 36 | 1.2 37 | provided 38 | 39 | 40 | org.springframework 41 | spring-context 42 | [3.+,4.+] 43 | provided 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-compiler-plugin 52 | 3.7.0 53 | 54 | 1.8 55 | 1.8 56 | 57 | 58 | 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-source-plugin 63 | 3.0.1 64 | 65 | 66 | attach-sources 67 | 68 | jar 69 | 70 | 71 | 72 | 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-javadoc-plugin 77 | 3.0.0 78 | 79 | 80 | attach-javadocs 81 | 82 | jar 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/jsf/SpringScopeRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by rumatoest at github.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.jneat.jsf; 23 | 24 | import org.springframework.beans.factory.annotation.Qualifier; 25 | import org.springframework.context.annotation.Scope; 26 | 27 | import java.lang.annotation.ElementType; 28 | import java.lang.annotation.Retention; 29 | import java.lang.annotation.RetentionPolicy; 30 | import java.lang.annotation.Target; 31 | 32 | /** 33 | * Indicates that spring bean instance will be in JSF like request scope. 34 | */ 35 | @Qualifier 36 | @Scope("request") 37 | @Target({ElementType.TYPE, ElementType.METHOD}) 38 | @Retention(RetentionPolicy.RUNTIME) 39 | public @interface SpringScopeRequest { 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/jsf/SpringScopeSession.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by rumatoest at github.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.jneat.jsf; 23 | 24 | import org.springframework.beans.factory.annotation.Qualifier; 25 | import org.springframework.context.annotation.Scope; 26 | 27 | import java.lang.annotation.ElementType; 28 | import java.lang.annotation.Retention; 29 | import java.lang.annotation.RetentionPolicy; 30 | import java.lang.annotation.Target; 31 | 32 | /** 33 | * Indicates that spring bean instance will be in JSF like session scope. 34 | */ 35 | @Qualifier 36 | @Scope("session") 37 | @Target({ElementType.TYPE, ElementType.METHOD}) 38 | @Retention(RetentionPolicy.RUNTIME) 39 | public @interface SpringScopeSession { 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/jsf/SpringScopeView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by rumatoest at github.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.jneat.jsf; 23 | 24 | import org.springframework.beans.factory.annotation.Qualifier; 25 | import org.springframework.context.annotation.Scope; 26 | 27 | import java.lang.annotation.ElementType; 28 | import java.lang.annotation.Retention; 29 | import java.lang.annotation.RetentionPolicy; 30 | import java.lang.annotation.Target; 31 | 32 | /** 33 | * Indicates that spring bean instance will be in JSF like view scope. 34 | */ 35 | @Qualifier 36 | @Scope("view") 37 | @Target({ElementType.TYPE, ElementType.METHOD}) 38 | @Retention(RetentionPolicy.RUNTIME) 39 | public @interface SpringScopeView { 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/jsf/ViewScope.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by rumatoest at github.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.jneat.jsf; 23 | 24 | import org.springframework.beans.factory.ObjectFactory; 25 | import org.springframework.beans.factory.config.Scope; 26 | 27 | import org.apache.commons.logging.Log; 28 | import org.apache.commons.logging.LogFactory; 29 | 30 | import javax.faces.component.UIViewRoot; 31 | import javax.faces.context.FacesContext; 32 | import javax.faces.event.PreDestroyViewMapEvent; 33 | import javax.servlet.http.HttpSession; 34 | import javax.servlet.http.HttpSessionBindingEvent; 35 | import javax.servlet.http.HttpSessionBindingListener; 36 | import java.util.HashSet; 37 | import java.util.Map; 38 | import java.util.Set; 39 | import java.util.WeakHashMap; 40 | 41 | /** 42 | * Implementation of JSF view scope for spring beans. 43 | * The core idea is to put spring bean into JSF view scope, that you can access from 44 | * FacesContext.getCurrentInstance().getViewRoot().getViewMap() 45 | * 46 | * @author Vladislav Zablotsky 47 | * @author Michail Nikolaev (original codebase author) 48 | */ 49 | public class ViewScope implements Scope, HttpSessionBindingListener { 50 | 51 | private static final long serialVersionUID = 1L; 52 | 53 | private static final Log logger = LogFactory.getLog(ViewScope.class); 54 | 55 | private final WeakHashMap> sessionToListeners = new WeakHashMap<>(); 56 | 57 | @Override 58 | public Object get(String name, ObjectFactory objectFactory) { 59 | Map viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 60 | //noinspection SynchronizationOnLocalVariableOrMethodParameter 61 | if (viewMap.containsKey(name)) { 62 | return viewMap.get(name); 63 | } else { 64 | synchronized (viewMap) { 65 | if (viewMap.containsKey(name)) { 66 | return viewMap.get(name); 67 | } else { 68 | logger.trace("Creating bean " + name); 69 | Object object = objectFactory.getObject(); 70 | viewMap.put(name, object); 71 | return object; 72 | } 73 | } 74 | } 75 | } 76 | 77 | @Override 78 | public String getConversationId() { 79 | return null; 80 | } 81 | 82 | /** 83 | * Removing bean from scope and unregister it destruction callback without executing them. 84 | * 85 | * @see Scope for more details 86 | */ 87 | @Override 88 | public Object remove(String name) { 89 | Map viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 90 | if (viewMap.containsKey(name)) { 91 | Object removed; 92 | synchronized (viewMap) { 93 | if (viewMap.containsKey(name)) { 94 | removed = FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name); 95 | } else { 96 | return null; 97 | } 98 | } 99 | 100 | HttpSession httpSession = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(true); 101 | Set sessionListeners; 102 | sessionListeners = sessionToListeners.get(httpSession); 103 | if (sessionListeners != null) { 104 | Set toRemove = new HashSet<>(); 105 | for (ViewScopeViewMapListener listener : sessionListeners) { 106 | if (listener.getName().equals(name)) { 107 | toRemove.add(listener); 108 | FacesContext.getCurrentInstance().getViewRoot().unsubscribeFromViewEvent(PreDestroyViewMapEvent.class, listener); 109 | } 110 | } 111 | synchronized (sessionListeners) { 112 | sessionListeners.removeAll(toRemove); 113 | } 114 | } 115 | 116 | return removed; 117 | } 118 | return null; 119 | } 120 | 121 | /** 122 | * Register callback to be executed only on whole scope destroying (not single object). 123 | * 124 | * @see Scope for more details 125 | */ 126 | @Override 127 | public void registerDestructionCallback(String name, Runnable callback) { 128 | logger.trace("registerDestructionCallback for bean " + name); 129 | 130 | UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot(); 131 | ViewScopeViewMapListener listener = new ViewScopeViewMapListener(viewRoot, name, callback, this); 132 | 133 | viewRoot.subscribeToViewEvent(PreDestroyViewMapEvent.class, listener); 134 | 135 | HttpSession httpSession = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(true); 136 | 137 | final Set sessionListeners; 138 | 139 | if (sessionToListeners.containsKey(httpSession)) { 140 | sessionListeners = sessionToListeners.get(httpSession); 141 | } else { 142 | synchronized (sessionToListeners) { 143 | if (sessionToListeners.containsKey(httpSession)) { 144 | sessionListeners = sessionToListeners.get(httpSession); 145 | } else { 146 | sessionListeners = new HashSet<>(); 147 | sessionToListeners.put(httpSession, sessionListeners); 148 | } 149 | } 150 | } 151 | 152 | synchronized (sessionListeners) { 153 | sessionListeners.add(listener); 154 | } 155 | 156 | if (!FacesContext.getCurrentInstance().getExternalContext().getSessionMap().containsKey("sessionBindingListener")) { 157 | FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("sessionBindingListener", this); 158 | } 159 | 160 | } 161 | 162 | @Override 163 | public Object resolveContextualObject(String key) { 164 | return null; 165 | } 166 | 167 | @Override 168 | public void valueBound(HttpSessionBindingEvent event) { 169 | logger.trace("Session event bound " + event.getName()); 170 | } 171 | 172 | /** 173 | * Seems like it called after our listeners was unbounded from http session. 174 | * Looks like view scope it destroyed. But should we call callback or not is a big question. 175 | * 176 | * @see HttpSessionBindingListener for more details 177 | */ 178 | @Override 179 | public void valueUnbound(HttpSessionBindingEvent event) { 180 | logger.trace("Session event unbound " + event.getName()); 181 | final Set listeners; 182 | synchronized (sessionToListeners) { 183 | if (sessionToListeners.containsKey(event.getSession())) { 184 | listeners = sessionToListeners.get(event.getSession()); 185 | sessionToListeners.remove(event.getSession()); 186 | } else { 187 | listeners = null; 188 | } 189 | } 190 | if (listeners != null) { 191 | // I just hope that JSF context already done this job 192 | for (ViewScopeViewMapListener listener : listeners) { 193 | // As long as our callbacks can run only once - this is not such big deal 194 | listener.doCallback(); 195 | } 196 | } 197 | } 198 | 199 | /** 200 | * Will remove listener from session set and unregister it from UIViewRoot. 201 | */ 202 | public void unregisterListener(ViewScopeViewMapListener listener) { 203 | logger.debug("Removing listener from map"); 204 | HttpSession httpSession = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false); 205 | FacesContext.getCurrentInstance().getViewRoot().unsubscribeFromViewEvent(PreDestroyViewMapEvent.class, listener); 206 | if (httpSession != null) { 207 | synchronized (sessionToListeners) { 208 | if (sessionToListeners.containsKey(httpSession)) { 209 | sessionToListeners.get(httpSession).remove(listener); 210 | } 211 | } 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/jsf/ViewScopeViewMapListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by rumatoest at github.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.jneat.jsf; 23 | 24 | import org.apache.commons.logging.Log; 25 | import org.apache.commons.logging.LogFactory; 26 | 27 | import javax.faces.component.UIViewRoot; 28 | import javax.faces.event.AbortProcessingException; 29 | import javax.faces.event.PreDestroyViewMapEvent; 30 | import javax.faces.event.SystemEvent; 31 | import javax.faces.event.ViewMapListener; 32 | import java.lang.ref.WeakReference; 33 | 34 | /** 35 | * Listener for processing ViewMapDestroydEvent 36 | * that indicates the argument root just had its associated view map destroyed. 37 | * 38 | * @see javax.faces.event.PreDestroyViewMapEvent 39 | * 40 | * @author Vladislav Zablotsky 41 | * @author Michail Nikolaev (original codebase author) 42 | */ 43 | public class ViewScopeViewMapListener implements ViewMapListener { 44 | 45 | private static final Log logger = LogFactory.getLog(ViewScope.class); 46 | 47 | private final String name; 48 | 49 | private final Runnable callback; 50 | 51 | private boolean callbackCalled = false; 52 | 53 | private final WeakReference uiViewRootWeakReference; 54 | 55 | private final ViewScope viewScope; 56 | 57 | public ViewScopeViewMapListener(UIViewRoot root, String name, Runnable callback, ViewScope viewScope) { 58 | this.name = name; 59 | this.callback = callback; 60 | this.uiViewRootWeakReference = new WeakReference<>(root); 61 | this.viewScope = viewScope; 62 | } 63 | 64 | public synchronized void doCallback() { 65 | logger.trace("Going call callback for bean " + name); 66 | if (!callbackCalled) { 67 | try { 68 | callback.run(); 69 | } finally { 70 | callbackCalled = true; 71 | } 72 | } 73 | } 74 | 75 | public String getName() { 76 | return name; 77 | } 78 | 79 | @Override 80 | public boolean isListenerForSource(Object source) { 81 | return (source == uiViewRootWeakReference.get()); 82 | } 83 | 84 | @Override 85 | public void processEvent(SystemEvent event) throws AbortProcessingException { 86 | if (event instanceof PreDestroyViewMapEvent) { 87 | logger.trace("Going call callback for bean " + name); 88 | doCallback(); 89 | viewScope.unregisterListener(this); 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/resources/com/github/jneat/jsf/jsfSpringScope.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | --------------------------------------------------------------------------------