You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2008/11/12 13:49:56 UTC

svn commit: r713358 - /cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/

Author: sergeyb
Date: Wed Nov 12 04:49:56 2008
New Revision: 713358

URL: http://svn.apache.org/viewvc?rev=713358&view=rev
Log:
Adding code bits dealing with continuations for wider audience to comment

Added:
    cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/
    cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/AbstractPhaseInterceptor.java   (with props)
    cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/Phase.java   (with props)
    cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseChainCache.java   (with props)
    cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseComparator.java   (with props)
    cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptor.java   (with props)
    cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java   (with props)
    cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseManager.java   (with props)
    cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/package.html   (with props)

Added: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/AbstractPhaseInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/AbstractPhaseInterceptor.java?rev=713358&view=auto
==============================================================================
--- cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/AbstractPhaseInterceptor.java (added)
+++ cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/AbstractPhaseInterceptor.java Wed Nov 12 04:49:56 2008
@@ -0,0 +1,110 @@
+/**
+ * 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.cxf.phase;
+
+import java.util.Collection;
+import java.util.Set;
+
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.cxf.common.util.SortedArraySet;
+import org.apache.cxf.message.Message;
+
+public abstract class AbstractPhaseInterceptor<T extends Message> implements PhaseInterceptor<T> {
+    private final String id;
+    private final String phase;
+    private final Set<String> before = new SortedArraySet<String>();
+    private final Set<String> after = new SortedArraySet<String>();
+
+    public AbstractPhaseInterceptor(String phase) {
+        this(null, phase, false);
+    }
+    public AbstractPhaseInterceptor(String i, String p) {
+        this(i, p, false);
+    }
+    public AbstractPhaseInterceptor(String phase, boolean uniqueId) {
+        this(null, phase, uniqueId);
+    }
+    public AbstractPhaseInterceptor(String i, String p, boolean uniqueId) {
+        if (i == null) {
+            i = getClass().getName();
+        }
+        if (uniqueId) {
+            i += System.identityHashCode(this);
+        }
+        id = i;
+        phase = p;
+    }
+    
+    public void setBefore(Collection<String> i) {
+        before.clear();
+        before.addAll(i);
+    }
+    public void setAfter(Collection<String> i) {
+        after.clear();
+        after.addAll(i);
+    }
+    public void addBefore(Collection<String> i) {
+        before.addAll(i);
+    }
+    public void addAfter(Collection<String> i) {
+        after.addAll(i);
+    }
+    
+    public void addBefore(String i) {
+        before.add(i);
+    }
+
+    public void addAfter(String i) {
+        after.add(i);
+    }
+
+
+    public final Set<String> getAfter() {
+        return after;
+    }
+
+    public final Set<String> getBefore() {
+        return before;
+    }
+
+    public final String getId() {
+        return id;
+    }
+
+    public final String getPhase() {
+        return phase;
+    }
+
+
+    public void handleFault(T message) {
+    }
+
+    public boolean isGET(T message) {
+        String method = (String)message.get(Message.HTTP_REQUEST_METHOD);
+        return "GET".equals(method) && message.getContent(XMLStreamReader.class) == null;
+    }
+    
+    protected boolean isRequestor(T message) {
+        return Boolean.TRUE.equals(message.containsKey(
+            org.apache.cxf.message.Message.REQUESTOR_ROLE));
+    }  
+
+}

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/AbstractPhaseInterceptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/AbstractPhaseInterceptor.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/Phase.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/Phase.java?rev=713358&view=auto
==============================================================================
--- cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/Phase.java (added)
+++ cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/Phase.java Wed Nov 12 04:49:56 2008
@@ -0,0 +1,112 @@
+/**
+ * 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.cxf.phase;
+
+public class Phase implements Comparable {
+    
+    // can be removed from once defined as default value in configuration metadata for bus
+  
+    public static final String SETUP = "setup";
+    public static final String SETUP_ENDING = "setup-ending";
+    public static final String PRE_LOGICAL = "pre-logical";
+    public static final String PRE_LOGICAL_ENDING = "pre-logical-ending";
+    public static final String USER_LOGICAL = "user-logical";
+    public static final String USER_LOGICAL_ENDING = "user-logical-ending";
+    public static final String POST_LOGICAL = "post-logical";
+    public static final String POST_LOGICAL_ENDING = "post-logical-ending";
+    public static final String PRE_MARSHAL = "pre-marshal";
+    public static final String MARSHAL = "marshal";
+    public static final String POST_MARSHAL = "post-marshal";
+    public static final String MARSHAL_ENDING = "marshal-ending";
+    public static final String PRE_PROTOCOL = "pre-protocol";
+    public static final String PRE_PROTOCOL_ENDING = "pre-protocol-ending";
+    public static final String USER_PROTOCOL = "user-protocol";
+    public static final String USER_PROTOCOL_ENDING = "user-protocol-ending";
+    public static final String POST_PROTOCOL = "post-protocol";
+    public static final String POST_PROTOCOL_ENDING = "post-protocol-ending";
+    public static final String PREPARE_SEND = "prepare-send";
+    public static final String PREPARE_SEND_ENDING = "prepare-send-ending";
+    public static final String PRE_STREAM = "pre-stream";
+    public static final String PRE_STREAM_ENDING = "pre-stream-ending";
+    public static final String USER_STREAM = "user-stream";
+    public static final String USER_STREAM_ENDING = "user-stream-ending";
+    public static final String POST_STREAM = "post-stream";
+    public static final String POST_STREAM_ENDING = "post-stream-ending";
+    public static final String WRITE = "write";
+    public static final String WRITE_ENDING = "write-ending";
+    public static final String SEND = "send";
+    public static final String SEND_ENDING = "send-ending";
+   
+    public static final String RECEIVE = "receive";
+    public static final String READ = "read";
+    public static final String PROTOCOL = "protocol";
+    public static final String UNMARSHAL = "unmarshal";
+    public static final String PRE_INVOKE = "pre-invoke";
+    public static final String INVOKE = "invoke";
+    public static final String POST_INVOKE = "post-invoke";
+    
+    
+    private String name;
+    private int priority;
+    
+    public Phase() {
+    }
+    
+    public Phase(String n, int p) {
+        this.name = n;
+        this.priority = p;
+    }
+    
+    public String getName() {
+        return name;
+    }
+    public void setName(String n) {
+        this.name = n;
+    }
+    public int getPriority() {
+        return priority;
+    }
+    public void setPriority(int p) {
+        this.priority = p;
+    }
+    
+    public int hashCode() {
+        return priority;
+    }
+    public boolean equals(Object o) {
+        Phase p = (Phase)o;
+        
+        return p.priority == priority
+            && p.name.equals(name);
+    }
+
+    public int compareTo(Object o) {
+        Phase p = (Phase)o;
+        
+        if (priority == p.priority) {
+            return name.compareTo(p.name); 
+        }
+        return priority - p.priority;
+    }
+    
+    public String toString() {
+        return "Phase(" + getName() + ")";
+    }
+}

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/Phase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/Phase.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseChainCache.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseChainCache.java?rev=713358&view=auto
==============================================================================
--- cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseChainCache.java (added)
+++ cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseChainCache.java Wed Nov 12 04:49:56 2008
@@ -0,0 +1,137 @@
+/**
+ * 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.cxf.phase;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.SortedSet;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.cxf.common.util.ModCountCopyOnWriteArrayList;
+import org.apache.cxf.interceptor.Interceptor;
+
+/**
+ * The PhaseChainCache provides default interceptor chains for SOAP requests
+ * and responses, both from the client and web service side.  The list of
+ * phases supplied in the get() methods of this class are defined by default
+ * within org.apache.cxf.phase.PhaseManagerImpl.  For an example of this class 
+ * in use, check the sourcecode of org.apache.cxf.endpoint.ClientImpl.
+ */
+public final class PhaseChainCache {
+    AtomicReference<ChainHolder> lastData = new AtomicReference<ChainHolder>();
+    
+    
+    @SuppressWarnings("unchecked")
+    public PhaseInterceptorChain get(SortedSet<Phase> phaseList,
+                                     List<Interceptor> p1) {
+        return getChain(phaseList, p1);
+    }
+
+    @SuppressWarnings("unchecked")
+    public PhaseInterceptorChain get(SortedSet<Phase> phaseList,
+                                     List<Interceptor> p1,
+                                     List<Interceptor> p2) {
+        return getChain(phaseList, p1, p2);
+    }
+    @SuppressWarnings("unchecked")
+    public PhaseInterceptorChain get(SortedSet<Phase> phaseList,
+                                     List<Interceptor> p1,
+                                     List<Interceptor> p2,
+                                     List<Interceptor> p3) {
+        return getChain(phaseList, p1, p2, p3);
+    }
+    @SuppressWarnings("unchecked")
+    public PhaseInterceptorChain get(SortedSet<Phase> phaseList,
+                                     List<Interceptor> p1,
+                                     List<Interceptor> p2,
+                                     List<Interceptor> p3,
+                                     List<Interceptor> p4) {
+        return getChain(phaseList, p1, p2, p3, p4);
+    }
+    @SuppressWarnings("unchecked")
+    public PhaseInterceptorChain get(SortedSet<Phase> phaseList,
+                                     List<Interceptor> p1,
+                                     List<Interceptor> p2,
+                                     List<Interceptor> p3,
+                                     List<Interceptor> p4,
+                                     List<Interceptor> p5) {
+        return getChain(phaseList, p1, p2, p3, p4, p5);
+    }
+    
+    private PhaseInterceptorChain getChain(SortedSet<Phase> phaseList, List<Interceptor> ... providers) {
+        ChainHolder last = lastData.get();
+        
+        if (last == null 
+            || !last.matches(providers)) {
+            
+            PhaseInterceptorChain chain = new PhaseInterceptorChain(phaseList);
+            List<ModCountCopyOnWriteArrayList<Interceptor>> copy 
+                = new ArrayList<ModCountCopyOnWriteArrayList<Interceptor>>(providers.length);
+            for (List<Interceptor> p : providers) {
+                copy.add(new ModCountCopyOnWriteArrayList<Interceptor>(p));
+                chain.add(p);
+            }
+            last = new ChainHolder(chain, copy);
+            lastData.set(last);
+        }
+        
+        
+        return last.chain.cloneChain();
+    }
+    
+    private static class ChainHolder {
+        List<ModCountCopyOnWriteArrayList<Interceptor>> lists;
+        PhaseInterceptorChain chain;
+        
+        ChainHolder(PhaseInterceptorChain c, List<ModCountCopyOnWriteArrayList<Interceptor>> l) {
+            lists = l;
+            chain = c;
+        }
+        
+        boolean matches(List<Interceptor> ... providers) {
+            if (lists.size() == providers.length) {
+                for (int x = 0; x < providers.length; x++) {
+                    if (lists.get(x).size() != providers[x].size()) {
+                        return false;
+                    }
+                    
+                    if (providers[x].getClass() == ModCountCopyOnWriteArrayList.class) {
+                        if (((ModCountCopyOnWriteArrayList)providers[x]).getModCount()
+                            != lists.get(x).getModCount()) {
+                            return false;
+                        }
+                    } else {
+                        ListIterator<Interceptor> i1 = lists.get(x).listIterator();
+                        ListIterator<Interceptor> i2 = providers[x].listIterator();
+                        
+                        while (i1.hasNext()) {
+                            if (i1.next() != i2.next()) {
+                                return false;
+                            }
+                        }
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+    }
+}

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseChainCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseChainCache.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseComparator.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseComparator.java?rev=713358&view=auto
==============================================================================
--- cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseComparator.java (added)
+++ cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseComparator.java Wed Nov 12 04:49:56 2008
@@ -0,0 +1,30 @@
+/**
+ * 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.cxf.phase;
+
+import java.util.Comparator;
+
+public class PhaseComparator implements Comparator<Phase> {
+
+    public int compare(Phase o1, Phase o2) {
+        return o1.getPriority() - o2.getPriority();
+    }
+    
+}

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseComparator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseComparator.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptor.java?rev=713358&view=auto
==============================================================================
--- cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptor.java (added)
+++ cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptor.java Wed Nov 12 04:49:56 2008
@@ -0,0 +1,64 @@
+/**
+ * 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.cxf.phase;
+
+import java.util.Set;
+
+import org.apache.cxf.interceptor.Interceptor;
+import org.apache.cxf.message.Message;
+
+/**
+ * A phase interceptor participates in a PhaseInterceptorChain.
+ * <pre>
+ * The before and after properties contain a list of Ids that can control 
+ * where in the chain the interceptor is placed relative to other interceptors
+ * </pre> 
+ * @see org.apache.cxf.phase.PhaseInterceptorChain
+ * @author Dan Diephouse
+ */
+public interface PhaseInterceptor<T extends Message> extends Interceptor<T> {
+
+    /**
+     * Returns a set of IDs specifying the interceptors that this interceptor should 
+     * be placed after in the interceptor chain
+     * @return the ids of the interceptors
+     */
+    Set<String> getAfter();
+
+    /**
+     * Returns a set of IDs specifying the interceptors that this interceptor needs 
+     * to be before in the inteceptor chain.
+     * @return the ids of the interceptors 
+     */
+    Set<String> getBefore();
+
+    /**
+     * The ID of this interceptor.
+     * @return the id
+     */
+    String getId();
+
+    /**
+     * The phase of this interceptor.
+     * @return the phase
+     */
+    String getPhase();
+
+}

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptor.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java?rev=713358&view=auto
==============================================================================
--- cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java (added)
+++ cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java Wed Nov 12 04:49:56 2008
@@ -0,0 +1,687 @@
+/**
+ * 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.cxf.phase;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.continuations.SuspendedInvocationException;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.interceptor.Interceptor;
+import org.apache.cxf.interceptor.InterceptorChain;
+import org.apache.cxf.message.FaultMode;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.transport.MessageObserver;
+
+/**
+ * A PhaseInterceptorChain orders Interceptors according to the phase they
+ * participate in and also according to the before & after properties on an
+ * Interceptor.
+ * <p>
+ * A List of phases is supplied to the PhaseInterceptorChain in the constructor.
+ * This class is typically instantiated from the PhaseChainCache class in this
+ * package. Interceptors that are added to the chain are ordered by phase.
+ * Within a phase, interceptors can order themselves. Each PhaseInterceptor 
+ * has an ID. PhaseInterceptors can supply a Collection of IDs which they 
+ * should run before or after, supplying fine grained ordering.
+ * <p>
+ *  
+ */
+public class PhaseInterceptorChain implements InterceptorChain {
+
+    private static final Logger LOG = LogUtils.getL7dLogger(PhaseInterceptorChain.class); 
+
+    
+    private final Map<String, Integer> nameMap;
+    private final Phase phases[];
+
+    // heads[phase] refers to the first interceptor of the given phase
+    private InterceptorHolder heads[];
+    // tails[phase] refers to the last interceptor of the given phase
+    private InterceptorHolder tails[];
+    // hasAfters[phase] indicates that the given phase has already inserted
+    // interceptors that may need to be placed after future to-be-inserted
+    // interceptors.  This flag is used to activate ordering of interceptors
+    // when new ones are added to the list for this phase.
+    // Note no hasBefores[] is needed because implementation adds subsequent
+    // interceptors to the end of the list by default.
+    private boolean hasAfters[];
+
+    
+    private State state;
+    private Message pausedMessage;
+    private MessageObserver faultObserver;
+    private PhaseInterceptorIterator iterator;
+    
+    // currently one chain for one request/response, use below as signal 
+    // to avoid duplicate fault processing on nested calling of
+    // doIntercept(), which will throw same fault multi-times
+    private boolean faultOccurred;
+    
+    
+    private PhaseInterceptorChain(PhaseInterceptorChain src) {
+        //only used for clone
+        state = State.EXECUTING;
+        
+        //immutable, just repoint
+        nameMap = src.nameMap;
+        phases = src.phases;
+        
+        int length = phases.length;
+        hasAfters = new boolean[length];
+        System.arraycopy(src.hasAfters, 0, hasAfters, 0, length);
+        
+        heads = new InterceptorHolder[length];
+        tails = new InterceptorHolder[length];
+        
+        InterceptorHolder last = null;
+        for (int x = 0; x < length; x++) {
+            InterceptorHolder ih = src.heads[x];
+            while (ih != null
+                && ih.phaseIdx == x) {
+                InterceptorHolder ih2 = new InterceptorHolder(ih);
+                ih2.prev = last;
+                if (last != null) {
+                    last.next = ih2;
+                }
+                if (heads[x] == null) {
+                    heads[x] = ih2;
+                }
+                tails[x] = ih2;
+                last = ih2;
+                ih = ih.next;
+            }
+        }
+    }
+    
+    public PhaseInterceptorChain(SortedSet<Phase> ps) {
+        state = State.EXECUTING;
+        
+        int numPhases = ps.size();
+        phases = new Phase[numPhases];
+        nameMap = new HashMap<String, Integer>();
+
+        heads = new InterceptorHolder[numPhases];
+        tails = new InterceptorHolder[numPhases];
+        hasAfters = new boolean[numPhases];
+        
+        int idx = 0;
+        for (Phase phase : ps) {
+            phases[idx] = phase; 
+            nameMap.put(phase.getName(), idx);
+            ++idx;
+        }
+    }
+    
+    // this method should really be on the InterceptorChain interface
+    public State getState() {
+        return state;
+    }
+    
+    public PhaseInterceptorChain cloneChain() {
+        return new PhaseInterceptorChain(this);
+    }
+    
+    private void updateIterator() {
+        if (iterator == null) {
+            iterator = new PhaseInterceptorIterator(heads);
+            outputChainToLog(false);
+            //System.out.println(toString());
+        }
+    }
+    
+    public void add(Collection<Interceptor> newhandlers) {
+        add(newhandlers, false);
+    }
+
+    public void add(Collection<Interceptor> newhandlers, boolean force) {
+        if (newhandlers == null) {
+            return;
+        }
+
+        for (Interceptor handler : newhandlers) {
+            add(handler, force);
+        }
+    }
+
+    public void add(Interceptor i) {
+        add(i, false);
+    }
+    
+    public void add(Interceptor i, boolean force) {
+        PhaseInterceptor pi = (PhaseInterceptor)i;
+
+        String phaseName = pi.getPhase();        
+        Integer phase = nameMap.get(phaseName);
+        
+        if (phase == null) {
+            LOG.fine("Skipping interceptor " + i.getClass().getName() 
+                + ((phaseName == null) ? ": Phase declaration is missing." 
+                : ": Phase " + phaseName + " specified does not exist."));
+        } else {            
+            if (LOG.isLoggable(Level.FINE)) {
+                LOG.fine("Adding interceptor " + i + " to phase " + phaseName);
+            }
+
+            insertInterceptor(phase, pi, force);
+        }
+    }
+
+
+    public synchronized void pause() {
+        state = State.PAUSED;
+    }
+
+    public synchronized void resume() {
+        if (state == State.PAUSED) {
+            state = State.EXECUTING;
+            doIntercept(pausedMessage);
+        }
+    }
+
+    /**
+     * Intercept a message, invoking each phase's handlers in turn.
+     * 
+     * @param message the message 
+     * @throws Exception
+     */
+    @SuppressWarnings("unchecked")
+    public synchronized boolean doIntercept(Message message) {
+        updateIterator();
+        boolean isFineLogging = LOG.isLoggable(Level.FINE);
+        pausedMessage = message;
+        while (state == State.EXECUTING && iterator.hasNext()) {
+            try {
+                Interceptor currentInterceptor = iterator.next();
+                if (isFineLogging) {
+                    LOG.fine("Invoking handleMessage on interceptor " + currentInterceptor);
+                }
+                //System.out.println("-----------" + currentInterceptor);
+                currentInterceptor.handleMessage(message);
+            } catch (SuspendedInvocationException ex) {
+                // we need to resume from the same interceptor the exception got originated from
+                if (iterator.hasPrevious()) {
+                    iterator.previous();
+                }
+                pause();
+                throw ex;
+            } catch (RuntimeException ex) {
+                if (!faultOccurred) {
+ 
+                    faultOccurred = true;
+                                        
+                    FaultMode mode = message.get(FaultMode.class);
+                    if (mode == FaultMode.CHECKED_APPLICATION_FAULT) {
+                        if (LOG.isLoggable(Level.FINE)) { 
+                            LogUtils.log(LOG, Level.FINE,
+                                         "Application has thrown exception, unwinding now", ex);
+                        } else if (LOG.isLoggable(Level.INFO)) {
+                            Throwable t = ex;
+                            if (ex instanceof Fault
+                                && ex.getCause() != null) {
+                                t = ex.getCause();
+                            }                            
+                            
+                            LogUtils.log(LOG, Level.INFO,
+                                         "Application has thrown exception, unwinding now: "
+                                         + t.getClass().getName() 
+                                         + ": " + ex.getMessage());
+                        }
+                    } else if (LOG.isLoggable(Level.INFO)) {
+                        if (mode == FaultMode.UNCHECKED_APPLICATION_FAULT) {
+                            LogUtils.log(LOG, Level.INFO,
+                                         "Application has thrown exception, unwinding now", ex);
+                        } else {
+                            LogUtils.log(LOG, Level.INFO,
+                                         "Interceptor has thrown exception, unwinding now", ex);
+                        }
+                    }
+
+                    message.setContent(Exception.class, ex);
+                    if (message.getExchange() != null) {
+                        message.getExchange().put(Exception.class, ex);
+                    }                    
+                    unwind(message);
+                    
+                    if (faultObserver != null) {
+                        faultObserver.onMessage(message);
+                    }
+                }
+                state = State.ABORTED;
+            } 
+        }
+        if (state == State.EXECUTING) {
+            state = State.COMPLETE;
+            pausedMessage = null;
+        }
+        return state == State.COMPLETE;
+    }
+    
+    /**
+     * Intercept a message, invoking each phase's handlers in turn,
+     * starting after the specified interceptor.
+     * 
+     * @param message the message
+     * @param startingAfterInterceptorID the id of the interceptor 
+     * @throws Exception
+     */
+    public synchronized boolean doInterceptStartingAfter(Message message,
+                                                         String startingAfterInterceptorID) {
+        updateIterator();
+        while (state == State.EXECUTING && iterator.hasNext()) {
+            PhaseInterceptor currentInterceptor = (PhaseInterceptor)iterator.next();
+            if (currentInterceptor.getId().equals(startingAfterInterceptorID)) {
+                break;
+            }
+        }
+        return doIntercept(message);
+    }
+
+    /**
+     * Intercept a message, invoking each phase's handlers in turn,
+     * starting at the specified interceptor.
+     * 
+     * @param message the message
+     * @param startingAtInterceptorID the id of the interceptor 
+     * @throws Exception
+     */
+    public synchronized boolean doInterceptStartingAt(Message message,
+                                                         String startingAtInterceptorID) {
+        updateIterator();
+        while (state == State.EXECUTING && iterator.hasNext()) {
+            PhaseInterceptor currentInterceptor = (PhaseInterceptor)iterator.next();
+            if (currentInterceptor.getId().equals(startingAtInterceptorID)) {
+                iterator.previous();
+                break;
+            }
+        }
+        return doIntercept(message);
+    }
+
+    public synchronized void reset() {
+        updateIterator();
+        if (state == State.COMPLETE) {
+            state = State.EXECUTING;
+            iterator.reset();
+        } else {
+            iterator.reset();
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    private void unwind(Message message) {
+        boolean isFineLogging = LOG.isLoggable(Level.FINE);
+        while (iterator.hasPrevious()) {
+            Interceptor currentInterceptor = iterator.previous();
+            if (isFineLogging) {
+                LOG.fine("Invoking handleFault on interceptor " + currentInterceptor);
+            }
+            currentInterceptor.handleFault(message);
+        }
+    }
+
+    public void remove(Interceptor i) {
+        PhaseInterceptorIterator it = new PhaseInterceptorIterator(heads);
+        while (it.hasNext()) {
+            InterceptorHolder holder = it.nextInterceptorHolder();
+            if (holder.interceptor == i) {
+                remove(holder);
+                return;
+            }
+        }
+    }
+
+    public synchronized void abort() {
+        this.state = InterceptorChain.State.ABORTED;
+    }
+
+    public Iterator<Interceptor<? extends Message>> iterator() {
+        return getIterator();
+    }
+    public ListIterator<Interceptor<? extends Message>> getIterator() {
+        return new PhaseInterceptorIterator(heads);
+    }
+
+    private void remove(InterceptorHolder i) {
+        if (i.prev != null) {
+            i.prev.next = i.next;
+        }
+        if (i.next != null) {
+            i.next.prev = i.prev;
+        }
+        int ph = i.phaseIdx;
+        if (heads[ph] == i) {
+            if (i.next != null
+                && i.next.phaseIdx == ph) {
+                heads[ph] = i.next;
+            } else {
+                heads[ph] = null;
+                tails[ph] = null;
+            }
+        }
+        if (tails[ph] == i) {
+            if (i.prev != null
+                && i.prev.phaseIdx == ph) {
+                tails[ph] = i.prev;
+            } else {
+                heads[ph] = null;
+                tails[ph] = null;
+            }
+        }
+    }
+    
+    private void insertInterceptor(int phase, PhaseInterceptor interc, boolean force) {
+        InterceptorHolder ih = new InterceptorHolder(interc, phase);
+        if (heads[phase] == null) {
+            // no interceptors yet in this phase
+            heads[phase] = ih;
+            tails[phase] = ih;
+            hasAfters[phase] = !interc.getAfter().isEmpty();
+            
+            int idx = phase - 1;
+            while (idx >= 0) {
+                if (tails[idx] != null) {
+                    break;
+                }
+                --idx;
+            }
+            if (idx >= 0) {
+                //found something before us, in an earlier phase
+                ih.prev = tails[idx];
+                ih.next = tails[idx].next;
+                if (ih.next != null) {
+                    ih.next.prev = ih;
+                }
+                tails[idx].next = ih;
+            } else {
+                //did not find something before us, try after
+                idx = phase + 1;
+                while (idx < heads.length) {
+                    if (heads[idx] != null) {
+                        break;
+                    }
+                    ++idx;
+                }
+                
+                if (idx != heads.length) {
+                    //found something after us
+                    ih.next = heads[idx];
+                    heads[idx].prev = ih;
+                }
+            }
+        } else { // this phase already has interceptors attached
+        
+            // list of interceptors that the new interceptor should precede
+            Set beforeList = interc.getBefore();
+
+            // list of interceptors that the new interceptor should be after
+            Set afterList = interc.getAfter();
+            
+            // firstBefore will hold the first interceptor of a given phase
+            // that the interceptor to be added must precede
+            InterceptorHolder firstBefore = null;
+
+            // lastAfter will hold the last interceptor of a given phase
+            // that the interceptor to be added must come after
+            InterceptorHolder lastAfter = null;
+            
+            String id = interc.getId();
+            if (hasAfters[phase] || !beforeList.isEmpty()) {
+            
+                InterceptorHolder ih2 = heads[phase];
+                while (ih2 != tails[phase].next) {
+                    PhaseInterceptor cmp = ih2.interceptor;
+                    String cmpId = cmp.getId();
+                    if (cmpId != null && firstBefore == null
+                        && (beforeList.contains(cmpId)
+                            || cmp.getAfter().contains(id))) {
+                        firstBefore = ih2;
+                    } 
+                    if (cmpId != null && afterList.contains(cmpId)) {
+                        lastAfter = ih2;
+                    }
+                    if (!force && cmpId.equals(id)) {
+                        // interceptor is already in chain
+                        return;
+                    }
+                    ih2 = ih2.next;
+                }
+                if (lastAfter == null && beforeList.contains("*")) {
+                    firstBefore = heads[phase];
+                }
+                //System.out.print("Didn't skip: " + phase.toString());
+                //System.out.println("             " + interc.getId());
+            } else if (!force) {
+                // skip interceptor if already in chain
+                InterceptorHolder ih2 = heads[phase];
+                while (ih2 != tails[phase].next) {
+                    if (ih2.interceptor.getId().equals(id)) {
+                        return;
+                    }
+                    ih2 = ih2.next;
+                }
+                
+                //System.out.print("Skipped: " + phase.toString());
+                //System.out.println("         " + interc.getId());
+            }
+            hasAfters[phase] |= !afterList.isEmpty();
+            
+            if (firstBefore == null) {
+                //just add new interceptor at the end
+                ih.prev = tails[phase];
+                ih.next = tails[phase].next;
+                tails[phase].next = ih;
+                
+                if (ih.next != null) {
+                    ih.next.prev = ih;
+                }
+                tails[phase] = ih;
+            } else {
+                ih.prev = firstBefore.prev;
+                if (ih.prev != null) {
+                    ih.prev.next = ih;
+                }
+                ih.next = firstBefore;
+                firstBefore.prev = ih;
+                
+                if (heads[phase] == firstBefore) {
+                    heads[phase] = ih;
+                }
+            }
+        }
+        if (iterator != null) {
+            outputChainToLog(true);
+        }
+    }
+
+    public String toString() {
+        return toString(""); 
+    }
+    private String toString(String message) {
+        StringBuilder chain = new StringBuilder();
+        
+        chain.append("Chain ")
+            .append(super.toString())
+            .append(message)
+            .append(". Current flow:\n");
+        
+        for (int x = 0; x < phases.length; x++) {
+            if (heads[x] != null) {
+                chain.append("  ");
+                printPhase(x, chain);
+            }            
+        }
+        return chain.toString();
+    }
+    private void printPhase(int ph, StringBuilder chain) {
+        
+        chain.append(phases[ph].getName())
+            .append(" [");
+        InterceptorHolder i = heads[ph];
+        boolean first = true;
+        while (i != tails[ph].next) {
+            if (first) {
+                first = false;
+            } else {
+                chain.append(", ");
+            }
+            chain.append(i.interceptor.getClass().getSimpleName());
+            i = i.next;
+        }
+        chain.append("]\n");
+    }
+    
+    private void outputChainToLog(boolean modified) {
+        if (LOG.isLoggable(Level.FINE)) {
+            if (modified) {
+                LOG.fine(toString(" was modified"));
+            } else {
+                LOG.fine(toString(" was created"));
+            }
+        }
+    }
+    
+    public MessageObserver getFaultObserver() {
+        return faultObserver;
+    }
+    
+    public void setFaultObserver(MessageObserver faultObserver) {
+        this.faultObserver = faultObserver;
+    }
+    
+    static final class PhaseInterceptorIterator implements ListIterator<Interceptor<? extends Message>> {
+        InterceptorHolder heads[];
+        InterceptorHolder prev;
+        InterceptorHolder first;
+        
+        public PhaseInterceptorIterator(InterceptorHolder h[]) {
+            heads = h;
+            first = findFirst();
+        }
+        
+        public void reset() {
+            prev = null;
+            first = findFirst();
+        }
+        
+        private InterceptorHolder findFirst() {
+            for (int x = 0; x < heads.length; x++) {
+                if (heads[x] != null) {
+                    return heads[x];
+                }
+            }
+            return null;
+        }
+        
+        
+        public boolean hasNext() {
+            if (prev == null) {
+                return first != null;
+            }
+            return prev.next != null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Interceptor<? extends Message> next() {
+            if (prev == null) {
+                if (first == null) {
+                    throw new NoSuchElementException();
+                }
+                prev = first;
+            } else {
+                if (prev.next == null) {
+                    throw new NoSuchElementException();
+                }
+                prev = prev.next;
+            }
+            return prev.interceptor;
+        }
+        public InterceptorHolder nextInterceptorHolder() {
+            if (prev == null) {
+                if (first == null) {
+                    throw new NoSuchElementException();
+                }
+                prev = first;
+            } else {
+                if (prev.next == null) {
+                    throw new NoSuchElementException();
+                }
+                prev = prev.next;
+            }
+            return prev;
+        }
+        
+        public boolean hasPrevious() {
+            return prev != null;
+        }
+        @SuppressWarnings("unchecked")
+        public Interceptor<? extends Message> previous() {
+            if (prev == null) {
+                throw new NoSuchElementException();
+            }
+            InterceptorHolder tmp = prev;
+            prev = prev.prev;
+            return tmp.interceptor;
+        }
+        
+        public int nextIndex() {
+            throw new UnsupportedOperationException();
+        }
+        public int previousIndex() {
+            throw new UnsupportedOperationException();
+        }
+        public void add(Interceptor o) {
+            throw new UnsupportedOperationException();
+        }
+        public void set(Interceptor o) {
+            throw new UnsupportedOperationException();
+        }
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    
+    static final class InterceptorHolder {
+        PhaseInterceptor interceptor;
+        InterceptorHolder next;
+        InterceptorHolder prev;
+        int phaseIdx;
+        
+        InterceptorHolder(PhaseInterceptor i, int p) {
+            interceptor = i;
+            phaseIdx = p;
+        }
+        InterceptorHolder(InterceptorHolder p) {
+            interceptor = p.interceptor;
+            phaseIdx = p.phaseIdx;
+        }
+    }
+
+}

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseInterceptorChain.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseManager.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseManager.java?rev=713358&view=auto
==============================================================================
--- cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseManager.java (added)
+++ cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseManager.java Wed Nov 12 04:49:56 2008
@@ -0,0 +1,28 @@
+/**
+ * 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.cxf.phase;
+
+import java.util.SortedSet;
+
+public interface PhaseManager {
+    SortedSet<Phase> getInPhases();
+
+    SortedSet<Phase> getOutPhases();
+}

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/PhaseManager.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/package.html
URL: http://svn.apache.org/viewvc/cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/package.html?rev=713358&view=auto
==============================================================================
--- cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/package.html (added)
+++ cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/package.html Wed Nov 12 04:49:56 2008
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+  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.
+-->
+</head>
+<body bgcolor="white">
+
+An InterceptorChain implementation which uses the concept of 
+Phases to order message chains.
+
+</body>
+</html>

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/package.html
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Propchange: cxf/sandbox/2.2.x-continuations/api/src/main/java/org/apache/cxf/phase/package.html
------------------------------------------------------------------------------
    svn:mime-type = text/html