Skip to content

Commit

Permalink
#199: fix failing view scope unload when bean is constructed for first
Browse files Browse the repository at this point in the history
time during postback on same view (i.e. not on initial request; this is
unusual but not impossible). For this, added Ajax#load().
  • Loading branch information
Bauke Scholtz committed Mar 24, 2016
1 parent 625ed0d commit 8dbd495
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 6 deletions.
19 changes: 13 additions & 6 deletions src/main/java/org/omnifaces/cdi/viewscope/ViewScopeManager.java
Expand Up @@ -16,6 +16,7 @@
package org.omnifaces.cdi.viewscope;

import static java.lang.Boolean.TRUE;
import static org.omnifaces.util.Ajax.load;
import static org.omnifaces.util.Ajax.oncomplete;
import static org.omnifaces.util.Components.addScriptResourceToBody;
import static org.omnifaces.util.Components.addScriptResourceToHead;
Expand Down Expand Up @@ -233,17 +234,23 @@ private void createViewScope(UUID id) {
activeViewScopes.put(id, new BeanStorage(DEFAULT_BEANS_PER_VIEW_SCOPE));

FacesContext context = FacesContext.getCurrentInstance();
boolean ajaxRequestWithPartialRendering = isAjaxRequestWithPartialRendering(context);

if (context.getCurrentPhaseId() != PhaseId.RENDER_RESPONSE || TRUE.equals(context.getAttributes().get(StateManager.IS_BUILDING_INITIAL_STATE))) {
addScriptResourceToHead("omnifaces", "omnifaces.js");
}
else if (!Hacks.isScriptResourceRendered(context, new ResourceIdentifier("omnifaces", "omnifaces.js"))) {
addScriptResourceToBody("omnifaces", "unload.js");
if (!Hacks.isScriptResourceRendered(context, new ResourceIdentifier("omnifaces", "omnifaces.js"))) {
if (ajaxRequestWithPartialRendering) {
load("omnifaces", "unload.js");
}
else if (context.getCurrentPhaseId() != PhaseId.RENDER_RESPONSE || TRUE.equals(context.getAttributes().get(StateManager.IS_BUILDING_INITIAL_STATE))) {
addScriptResourceToHead("omnifaces", "omnifaces.js");
}
else {
addScriptResourceToBody("omnifaces", "unload.js");
}
}

String script = String.format(SCRIPT_INIT, id);

if (isAjaxRequestWithPartialRendering(context)) {
if (ajaxRequestWithPartialRendering) {
oncomplete(script);
}
else {
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/org/omnifaces/util/Ajax.java
Expand Up @@ -12,15 +12,22 @@
*/
package org.omnifaces.util;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.omnifaces.util.Components.getCurrentComponent;
import static org.omnifaces.util.Components.getCurrentForm;
import static org.omnifaces.util.Faces.getApplication;
import static org.omnifaces.util.Faces.isAjaxRequestWithPartialRendering;

import java.beans.Introspector;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;

import javax.faces.FacesException;
import javax.faces.application.Resource;
import javax.faces.component.UIColumn;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
Expand Down Expand Up @@ -59,6 +66,11 @@ public final class Ajax {

// Constants ------------------------------------------------------------------------------------------------------

private static final String ERROR_NO_SCRIPT_RESOURCE =
"";
private static final String ERROR_NO_PARTIAL_RENDERING =
"The current request is not an ajax request with partial rendering."
+ " Use Components#addScriptXxx() methods instead.";
private static final String ERROR_ARGUMENTS_LENGTH =
"The arguments length must be even. Encountered %d items.";
private static final String ERROR_ARGUMENT_TYPE =
Expand Down Expand Up @@ -229,12 +241,44 @@ private static void updateColumnCells(UIData table, int index, int rowCount) {
}
}

/**
* Load given script resource on complete of the current ajax response. Basically, it loads the script resource as
* a {@link String} and then delegates it to {@link #oncomplete(String...)}.
* @param libraryName Library name of the JavaScript resource.
* @param resourceName Resource name of the JavaScript resource.
* @throws IllegalArgumentException When given script resource cannot be found.
* @throws IllegalStateException When current request is not an ajax request with partial rendering. You should use
* either {@link Components#addScriptResourceToBody(String, String)}
* or {@link Components#addScriptResourceToHead(String, String)} instead.
* @since 2.3
*/
public static void load(String libraryName, String resourceName) {
Resource resource = getApplication().getResourceHandler().createResource(resourceName, libraryName);

if (resource == null) {
throw new IllegalArgumentException(ERROR_NO_SCRIPT_RESOURCE);
}

try (Scanner scanner = new Scanner(resource.getInputStream(), UTF_8.name())) {
oncomplete(scanner.useDelimiter("\\A").next());
}
catch (IOException e) {
throw new FacesException(e);
}
}

/**
* Execute the given scripts on complete of the current ajax response.
* @param scripts The scripts to be executed.
* @throws IllegalStateException When current request is not an ajax request with partial rendering. You should use
* {@link Components#addScriptToBody(String)} instead.
* @see OmniPartialViewContext#addCallbackScript(String)
*/
public static void oncomplete(String... scripts) {
if (!isAjaxRequestWithPartialRendering()) {
throw new IllegalStateException(ERROR_NO_PARTIAL_RENDERING);
}

OmniPartialViewContext context = OmniPartialViewContext.getCurrentInstance();

for (String script : scripts) {
Expand Down
Expand Up @@ -115,6 +115,7 @@ public UIViewRoot restoreView(FacesContext context, String viewId) {
private boolean restoreViewRootState(FacesContext context, ResponseStateManager manager, UIViewRoot view) {
Object state = manager.getState(context, view.getViewId());

// TODO: this assumes partial state saving not full state saving (thus doesn't work on full state saving).
if (state == null || !(state instanceof Object[]) || ((Object[]) state).length < 2 || !(((Object[]) state)[1] instanceof Map)) {
return false;
}
Expand Down

0 comments on commit 8dbd495

Please sign in to comment.