[ 
https://issues.apache.org/jira/browse/EXTCDI-317?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14240781#comment-14240781
 ] 

Nuno G. de M commented on EXTCDI-317:
-------------------------------------

Hi, on this issue, we have the following information to add.

(1) We have identified that the reason why CODI appears not be tuning the 
request url's with the windowId request parameter is because it's JSF phase 
listeners appear not be enabled under weblogic 12.c

(2) Futher analysis on how the jsf phase listener extension works, and how it 
discovers and later enables the CODI phase listener annotated classes into the 
normal mojarra JSF life cycle is not working in weblogic, with two apprent 
problems.
(2.1) It does not look like it will always discover the phase listeners with 
every deployment, most of the times the phase listeners are discovered but once 
or twice it appear as if they were not

(2.2.) The main problem is that during the enabling phase of the phase 
listeners, the class loader of weblogic is not the same one as during the 
discovery phase of the phase listenrs.
When CODI tries to fetch phase listeners from an hasp map keyed by class 
loaders, it always comes out with an empty basked because the phase listener is 
not in the map.


To get the sample project to work, we had to modify the CODI JSF phase listener 
extension with what we could "call" a dirty patch - which we highly doubt is an 
adequate fix.

On the code posted bellow, please take a look at what we had to do to get the 
sample project to work on weblogic, namely starting at line:
  boolean workingOnWeblogicAndThereArePhaseListenersToUse = foundPhaseListeners 
== null && classLoader.toString().
                toLowerCase().contains("weblogic") && 
phaseListeners.keySet().size() > 0;

 



/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.myfaces.extensions.cdi.jsf.impl.listener.phase;

import 
org.apache.myfaces.extensions.cdi.core.api.activation.ProjectStageActivated;
import org.apache.myfaces.extensions.cdi.core.api.config.CodiCoreConfig;
import org.apache.myfaces.extensions.cdi.core.api.projectstage.ProjectStage;
import 
org.apache.myfaces.extensions.cdi.core.api.startup.CodiStartupBroadcaster;
import org.apache.myfaces.extensions.cdi.core.api.util.ClassUtils;
import 
org.apache.myfaces.extensions.cdi.core.api.tools.InvocationOrderComparator;
import 
org.apache.myfaces.extensions.cdi.core.impl.projectstage.ProjectStageProducer;
import org.apache.myfaces.extensions.cdi.core.impl.util.CodiUtils;
import 
org.apache.myfaces.extensions.cdi.jsf.api.listener.phase.JsfPhaseListener;

import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.faces.event.PhaseListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import static 
org.apache.myfaces.extensions.cdi.core.impl.util.ClassDeactivation.isClassActivated;
import static 
org.apache.myfaces.extensions.cdi.core.impl.util.CodiUtils.injectFields;

/**
 * The PhaseListenerExtension picks up all {@link JsfPhaseListener} annotated 
beans for later registration as
 * PhaseListeners. We have to maintain this separately for each 
ContextClassLoader since it is possible that multiple
 * WebApps start up in parallel.
 */
public class PhaseListenerExtension implements Extension {

    private static Map<ClassLoader, List<Class<? extends PhaseListener>>> 
phaseListeners
            = new ConcurrentHashMap<ClassLoader, List<Class<? extends 
PhaseListener>>>();

    /**
     * Filters beans annotated with {@link JsfPhaseListener}. The class will be 
stored for consuming it later (see
     * #consumePhaseListeners)
     *
     * @param processAnnotatedType current process-annotated-type
     */
    public void filterJsfPhaseListeners(@Observes ProcessAnnotatedType 
processAnnotatedType) {
        CodiStartupBroadcaster.broadcastStartup();

        if 
(processAnnotatedType.getAnnotatedType().isAnnotationPresent(JsfPhaseListener.class))
 {
            Class<? extends PhaseListener> phaseListenerClass
                    = processAnnotatedType.getAnnotatedType().getJavaClass();

            if (isClassActivated(phaseListenerClass)) {
                addPhaseListener(phaseListenerClass);
            }

            processAnnotatedType.veto();
        }
    }

    private void addPhaseListener(Class<? extends PhaseListener> 
newPhaseListener) {
        ClassLoader classLoader = getClassLoader();

        List<Class<? extends PhaseListener>> phaseListenerClass = 
phaseListeners.get(classLoader);

        if (phaseListenerClass == null) {
            phaseListenerClass = new CopyOnWriteArrayList<Class<? extends 
PhaseListener>>();
            phaseListeners.put(classLoader, phaseListenerClass);
        }

        // just add the Class of the PhaseListener and do not instantiate it 
now,
        // because there is no FacesContext available at this point and the
        // constructor of the PhaseListener could use it (possible in JSF 2.0)
        phaseListenerClass.add(newPhaseListener);
    }

    /**
     * Exposes the found phase-listeners for the invocation. Afterwards it will 
return an empty list.
     *
     * @return found phase-listeners for the first invocation, an empty list if 
there are no phase-listeners or if they
     * are consumed already.
     */
    public static List<PhaseListener> consumePhaseListeners() {
        //workaround for mojarra
        CodiStartupBroadcaster.broadcastStartup();

        ClassLoader classLoader = getClassLoader();

        // customized code for weblogic deployment.
        // PROBLEM 1: The class loader during the discovery process is not the 
same as the class loader during the execution phase of JSF
        // PROBLEM 2: The class loader of weblogic seems to disver multiple 
times the same phase listener class
        // therefore we project from it by making sure the same class is not 
added twice using a hackish map
        List<Class<? extends PhaseListener>> foundPhaseListeners = 
phaseListeners.get(classLoader);
        boolean workingOnWeblogicAndThereArePhaseListenersToUse = 
foundPhaseListeners == null && classLoader.toString().
                toLowerCase().contains("weblogic") && 
phaseListeners.keySet().size() > 0;
        if (workingOnWeblogicAndThereArePhaseListenersToUse) {
            // TACKING PROBLEM1:
            System.out.println("Drity hacking the CODI phase listener 
registration process");
            foundPhaseListeners = 
phaseListeners.get(phaseListeners.keySet().iterator().next());
        }

        // customized code for weblogic deployment.
        // TACKING PROBLEM 2:
        boolean advancedQualifierRequiredForDependencyInjection
                = CodiUtils.getContextualReferenceByClass(CodiCoreConfig.class)
                .isAdvancedQualifierRequiredForDependencyInjection();      
        Map<Class<? extends PhaseListener>, Boolean> addedPhaseListenersMap = 
new HashMap<Class<? extends PhaseListener>, Boolean>();

        if (foundPhaseListeners != null && !foundPhaseListeners.isEmpty()) {

            // init the map to all phase listeners are not added
            // TACKING PROBLEM 2:
            for (Class<? extends PhaseListener> phaseListenerClass : 
foundPhaseListeners) {
                addedPhaseListenersMap.put(phaseListenerClass, Boolean.FALSE);
            }

            List<PhaseListener> result = new 
ArrayList<PhaseListener>(foundPhaseListeners.size());

            Class<? extends ProjectStage> activeProjectStage
                    = 
ProjectStageProducer.getInstance().getProjectStage().getClass();

            for (Class<? extends PhaseListener> phaseListenerClass : 
foundPhaseListeners) {
                if 
(phaseListenerClass.isAnnotationPresent(ProjectStageActivated.class)) {
                    boolean projectStageFound = false;

                    for (Class<? extends ProjectStage> currentProjectStage
                            : 
phaseListenerClass.getAnnotation(ProjectStageActivated.class).value()) {
                        if 
(currentProjectStage.isAssignableFrom(activeProjectStage)) {
                            projectStageFound = true;
                        }
                    }

                    if (!projectStageFound) {
                        continue;
                    }
                }

                // make sure we only register one phase listener per class
                // TACKING PROBLEM 2:
                boolean isFirstTimeCurrentPhaseListenerClassIsAdded = 
Boolean.FALSE.equals(addedPhaseListenersMap.get(
                        phaseListenerClass));
                if (isFirstTimeCurrentPhaseListenerClassIsAdded) { // 
customized loop
                    PhaseListener phaseListener = 
createPhaseListenerInstance(phaseListenerClass);
                    result.add(injectFields(phaseListener, 
advancedQualifierRequiredForDependencyInjection));
                    //  customized code
                    addedPhaseListenersMap.put(phaseListenerClass, 
Boolean.TRUE);
                }
            }

            foundPhaseListeners.clear();

            Collections.sort(result, new 
InvocationOrderComparator<PhaseListener>());
            return result;
        }
        return Collections.emptyList();
    }

    private static PhaseListener createPhaseListenerInstance(Class<? extends 
PhaseListener> phaseListenerClass) {
        return ClassUtils.tryToInstantiateClass(phaseListenerClass);
    }

    private static ClassLoader getClassLoader() {
        return ClassUtils.getClassLoader(null);
    }
}


> @ViewAccessScope with faces-redirect=true
> -----------------------------------------
>
>                 Key: EXTCDI-317
>                 URL: https://issues.apache.org/jira/browse/EXTCDI-317
>             Project: MyFaces CODI
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: 1.0.6
>         Environment: Windows 7
> WebLogic 12.1.2.0
>            Reporter: Kua Yan Xu
>         Attachments: javaee-redirect.zip
>
>   Original Estimate: 168h
>  Remaining Estimate: 168h
>
> Hi,
> I had create a simple application which have a page bean with a variable.
> In index.xhtml page, I have a button to set the variable to some value, and 
> another button to redirect to a new xhtml page using faces-redirect=true.
> When in GlassFish, the newly set variable value is display in the new page, 
> but not in WebLogic server.
> I can provide the simple application for you to test with.
> Regards,
> Yanxu



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to