Thanks, Jacques and Mathieu.

Verified the fix on the local machine, the system is working fine now.


Thanks & Regards
--
Deepak Nigam
HotWax Systems Pvt. Ltd.

On Tue, Aug 28, 2018 at 9:51 PM Jacques Le Roux <
[email protected]> wrote:

> Hi,
>
> I confirm this issue which can easily be reproduced in trunk and locally.
>
> The problem is r1838081 prevents to serialise requests.
>
> Like in ordermgr/control/updateCheckoutOptions/quickcheckout where
> updateCheckoutOptions and quickcheckout are serialised to update the check
> out with
> updateCheckoutOptions and then get back to the screen with quickcheckout
>
> It's fixed at r1839451 using last Mathieu's patch in OFBIZ-10438
>
> Jacques
>
>
> Le 20/08/2018 à 06:25, deepak nigam a écrit :
> > Hi Shi/Rishi,
> >
> > I was using the trunk downloaded from GitHub (
> > https://github.com/apache/ofbiz-framework). I will reverify this issue
> on
> > SVN trunk and will let you know the details.
> >
> > On Mon, Aug 20, 2018 at 1:37 AM Shi Jinghai <[email protected]>
> wrote:
> >
> >> Hi Deepak,
> >>
> >> As Rishi suggested, could you please reopen OFBIZ-10438 or create a new
> >> jira for the bug you mentioned here?
> >>
> >> I cannot reproduce it in my local and online trunk demo environments, I
> >> guess my test case is not the same as yours.
> >>
> >> Thanks,
> >>
> >> Shi Jinghai
> >>
> >> -----邮件原件-----
> >> 发件人: Rishi Solanki [mailto:[email protected]]
> >> 发送时间: 2018年8月17日 21:24
> >> 收件人: [email protected]
> >> 抄送: [email protected]
> >> 主题: Re: svn commit: r1838081 - in
> /ofbiz/ofbiz-framework/trunk/framework:
> >> base/src/main/java/org/apache/ofbiz/base/util/collections/
> >> base/src/test/java/org/apache/ofbiz/base/collections/ webapp/config/
> >> webapp/dtd/ webapp/src/main/java/org/apache/ofbiz/weba...
> >>
> >> Deepak,
> >>
> >> Thanks for reporting the issue, can you please create Jira ticket and
> add
> >> details (images are not coming at mailing list) with logs if possible?
> >>
> >>
> >>
> >> Rishi Solanki
> >> Sr Manager, Enterprise Software Development
> >> HotWax Systems Pvt. Ltd.
> >> Direct: +91-9893287847
> >> http://www.hotwaxsystems.com
> >> www.hotwax.co
> >>
> >> On Fri, Aug 17, 2018 at 6:32 PM, deepak nigam <
> [email protected]>
> >> wrote:
> >>
> >>> I am using OFBiz trunk and on creating an order from backend and
> getting
> >>> error screens while adding an item to cart and selecting shipping
> >> methods.
> >>> Please find the attached images for your reference.
> >>>
> >>> On further investigation, I found that on reverting this commit things
> >> are
> >>> working fine. Can we verify this commit once more?
> >>>
> >>> On Wed, Aug 15, 2018 at 5:15 PM <[email protected]> wrote:
> >>>
> >>>> Author: shijh
> >>>> Date: Wed Aug 15 11:45:45 2018
> >>>> New Revision: 1838081
> >>>>
> >>>> URL: http://svn.apache.org/viewvc?rev=1838081&view=rev
> >>>> Log:
> >>>> Implemented: Add method attribute to request-map to controll a uri can
> >> be
> >>>> called GET or POST only
> >>>> OFBIZ-10438
> >>>>
> >>>> Thanks: Mathieu Lirzin for the contribution.
> >>>>
> >>>> Added:
> >>>>      ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>> org/apache/ofbiz/base/util/collections/MultivaluedMapContext.java
> >>>>   (with props)
> >>>>      ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>>
> org/apache/ofbiz/base/util/collections/MultivaluedMapContextAdapter.java
> >>>>   (with props)
> >>>>      ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>> org/apache/ofbiz/base/collections/
> >>>>      ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>>
> org/apache/ofbiz/base/collections/MultivaluedMapContextAdapterTests.java
> >>>>   (with props)
> >>>>      ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>> org/apache/ofbiz/base/collections/MultivaluedMapContextTests.java
> >>>>   (with props)
> >>>>      ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/MethodNotAllowedException.java
> >>>>   (with props)
> >>>>      ofbiz/ofbiz-framework/trunk/framework/webapp/src/test/
> >>>> java/org/apache/ofbiz/webapp/control/RequestHandlerTests.java   (with
> >>>> props)
> >>>> Modified:
> >>>>      ofbiz/ofbiz-framework/trunk/framework/webapp/config/
> >>>> WebappUiLabels.xml
> >>>>      ofbiz/ofbiz-framework/trunk/framework/webapp/dtd/site-conf.xsd
> >>>>      ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java
> >>>>      ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/ControlServlet.java
> >>>>      ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/RequestHandler.java
> >>>>
> >>>> Added: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>> org/apache/ofbiz/base/util/collections/MultivaluedMapContext.java
> >>>> URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/
> >>>> framework/base/src/main/java/org/apache/ofbiz/base/util/collections/
> >>>> MultivaluedMapContext.java?rev=1838081&view=auto
> >>>> ============================================================
> >>>> ==================
> >>>> --- ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>> org/apache/ofbiz/base/util/collections/MultivaluedMapContext.java
> >> (added)
> >>>> +++ ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>> org/apache/ofbiz/base/util/collections/MultivaluedMapContext.java Wed
> >>>> Aug 15 11:45:45 2018
> >>>> @@ -0,0 +1,87 @@
> >>>> +/**********************************************************
> >>>> *********************
> >>>> + * 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.ofbiz.base.util.collections;
> >>>> +
> >>>> +import java.util.LinkedList;
> >>>> +import java.util.List;
> >>>> +
> >>>> +/**
> >>>> + * MultivaluedMap Context
> >>>> + *
> >>>> + * A MapContext which handles multiple values for the same key.
> >>>> + */
> >>>> +public class MultivaluedMapContext<K, V> extends MapContext<K,
> >> List<V>> {
> >>>> +
> >>>> +    public static final String module = MultivaluedMapContext.class.
> >>>> getName();
> >>>> +
> >>>> +    /**
> >>>> +     * Create a multi-value map initialized with one context
> >>>> +     */
> >>>> +    public MultivaluedMapContext() {
> >>>> +        push();
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Associate {@code key} with the single value {@code value}.
> >>>> +     * If other values are already associated with {@code key} then
> >>>> override them.
> >>>> +     *
> >>>> +     * @param key the key to associate {@code value} with
> >>>> +     * @param value the value to add to the context
> >>>> +     */
> >>>> +    public void putSingle(K key, V value) {
> >>>> +        List<V> box = new LinkedList<>();
> >>>> +        box.add(value);
> >>>> +        put(key, box);
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Associate {@code key} with the single value {@code value}.
> >>>> +     * If other values are already associated with {@code key},
> >>>> +     * then add {@code value} to them.
> >>>> +     *
> >>>> +     * @param key the key to associate {@code value} with
> >>>> +     * @param value the value to add to the context
> >>>> +     */
> >>>> +    public void add(K key, V value) {
> >>>> +        List<V> cur = contexts.getFirst().get(key);
> >>>> +        if (cur == null) {
> >>>> +            cur = new LinkedList<>();
> >>>> +            /* if this method is called after a context switch, copy
> >> the
> >>>> previous values
> >>>> +               in current context to not mask them. */
> >>>> +            List<V> old = get(key);
> >>>> +            if (old != null) {
> >>>> +                cur.addAll(old);
> >>>> +            }
> >>>> +        }
> >>>> +        cur.add(value);
> >>>> +        put(key, cur);
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Get the first value contained in the list of values associated
> >>>> with {@code key}.
> >>>> +     *
> >>>> +     * @param key a candidate key
> >>>> +     * @return the first value associated with {@code key} or null if
> >> no
> >>>> value
> >>>> +     * is associated with it.
> >>>> +     */
> >>>> +    public V getFirst(Object key) {
> >>>> +        List<V> res = get(key);
> >>>> +        return res == null ? null : res.get(0);
> >>>> +    }
> >>>> +}
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>> org/apache/ofbiz/base/util/collections/MultivaluedMapContext.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:eol-style = native
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>> org/apache/ofbiz/base/util/collections/MultivaluedMapContext.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:keywords = Date Rev Author URL Id
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>> org/apache/ofbiz/base/util/collections/MultivaluedMapContext.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:mime-type = text/plain
> >>>>
> >>>> Added: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>>
> org/apache/ofbiz/base/util/collections/MultivaluedMapContextAdapter.java
> >>>> URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/
> >>>> framework/base/src/main/java/org/apache/ofbiz/base/util/collections/
> >>>> MultivaluedMapContextAdapter.java?rev=1838081&view=auto
> >>>> ============================================================
> >>>> ==================
> >>>> --- ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>>
> org/apache/ofbiz/base/util/collections/MultivaluedMapContextAdapter.java
> >>>> (added)
> >>>> +++ ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>>
> org/apache/ofbiz/base/util/collections/MultivaluedMapContextAdapter.java
> >>>> Wed Aug 15 11:45:45 2018
> >>>> @@ -0,0 +1,103 @@
> >>>> +/**********************************************************
> >>>> *********************
> >>>> + * 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.ofbiz.base.util.collections;
> >>>> +
> >>>> +import java.util.Collection;
> >>>> +import java.util.Map;
> >>>> +import java.util.Set;
> >>>> +import java.util.stream.Collectors;
> >>>> +
> >>>> +// Adapter which allows viewing a multi-value map as a single-value
> >> map.
> >>>> +public class MultivaluedMapContextAdapter<K, V> implements Map<K, V>
> {
> >>>> +    private MultivaluedMapContext<K, V> adaptee;
> >>>> +
> >>>> +    public MultivaluedMapContextAdapter(MultivaluedMapContext<K, V>
> >>>> adaptee) {
> >>>> +        this.adaptee = adaptee;
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public int size() {
> >>>> +        return adaptee.size();
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public boolean isEmpty() {
> >>>> +        return adaptee.isEmpty();
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public boolean containsKey(Object key) {
> >>>> +        return adaptee.containsKey(key);
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public boolean containsValue(Object value) {
> >>>> +        return adaptee.values().stream()
> >>>> +                .map(l -> l.get(0))
> >>>> +                .anyMatch(value::equals);
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public V get(Object key) {
> >>>> +        return adaptee.getFirst(key);
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public V put(K key, V value) {
> >>>> +        V prev = get(key);
> >>>> +        adaptee.putSingle(key, value);
> >>>> +        return prev;
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public V remove(Object key) {
> >>>> +        V prev = get(key);
> >>>> +        adaptee.remove(key);
> >>>> +        return prev;
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public void putAll(Map<? extends K, ? extends V> m) {
> >>>> +        m.forEach(adaptee::putSingle);
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public void clear() {
> >>>> +        adaptee.clear();
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public Set<K> keySet() {
> >>>> +        return adaptee.keySet();
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public Collection<V> values() {
> >>>> +        return adaptee.values().stream()
> >>>> +                .map(l -> l.get(0))
> >>>> +                .collect(Collectors.toList());
> >>>> +    }
> >>>> +
> >>>> +    @Override
> >>>> +    public Set<Entry<K, V>> entrySet() {
> >>>> +        return adaptee.keySet().stream()
> >>>> +                .collect(Collectors.toMap(k -> k, k -> get(k)))
> >>>> +                .entrySet();
> >>>> +    }
> >>>> +}
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>>
> org/apache/ofbiz/base/util/collections/MultivaluedMapContextAdapter.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:eol-style = native
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>>
> org/apache/ofbiz/base/util/collections/MultivaluedMapContextAdapter.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:keywords = Date Rev Author URL Id
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/
> >>>>
> org/apache/ofbiz/base/util/collections/MultivaluedMapContextAdapter.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:mime-type = text/plain
> >>>>
> >>>> Added: ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>>
> org/apache/ofbiz/base/collections/MultivaluedMapContextAdapterTests.java
> >>>> URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/
> >>>> framework/base/src/test/java/org/apache/ofbiz/base/collections/
> >>>> MultivaluedMapContextAdapterTests.java?rev=1838081&view=auto
> >>>> ============================================================
> >>>> ==================
> >>>> --- ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>>
> org/apache/ofbiz/base/collections/MultivaluedMapContextAdapterTests.java
> >>>> (added)
> >>>> +++ ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>>
> org/apache/ofbiz/base/collections/MultivaluedMapContextAdapterTests.java
> >>>> Wed Aug 15 11:45:45 2018
> >>>> @@ -0,0 +1,70 @@
> >>>> +/**********************************************************
> >>>> *********************
> >>>> + * 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.ofbiz.base.collections;
> >>>> +
> >>>> +import static org.hamcrest.CoreMatchers.hasItems;
> >>>> +import static org.hamcrest.CoreMatchers.is;
> >>>> +import static org.junit.Assert.assertEquals;
> >>>> +import static org.junit.Assert.assertFalse;
> >>>> +import static org.junit.Assert.assertThat;
> >>>> +import static org.junit.Assert.assertTrue;
> >>>> +
> >>>> +import java.util.HashMap;
> >>>> +
> >>>> +import org.apache.ofbiz.base.util.collections.MultivaluedMapContext;
> >>>> +import org.apache.ofbiz.base.util.collections.
> >>>> MultivaluedMapContextAdapter;
> >>>> +import org.junit.Before;
> >>>> +import org.junit.Test;
> >>>> +
> >>>> +public class MultivaluedMapContextAdapterTests {
> >>>> +    private MultivaluedMapContext<String, Integer> adaptee;
> >>>> +    private MultivaluedMapContextAdapter<String, Integer> adapter;
> >>>> +
> >>>> +    @Before
> >>>> +    public void setUp() throws Exception {
> >>>> +        adaptee = new MultivaluedMapContext<>();
> >>>> +        adaptee.add("foo", 0);
> >>>> +        adaptee.add("foo", 1);
> >>>> +        adaptee.add("foo", 2);
> >>>> +        adaptee.add("bar", 3);
> >>>> +        adapter = new MultivaluedMapContextAdapter<>(adaptee);
> >>>> +    }
> >>>> +
> >>>> +    @Test
> >>>> +    public void containsValueBasic() {
> >>>> +        assertTrue(adapter.containsValue(0));
> >>>> +        assertFalse(adapter.containsValue(1));
> >>>> +        assertFalse(adapter.containsValue(2));
> >>>> +        assertTrue(adapter.containsValue(3));
> >>>> +    }
> >>>> +
> >>>> +    @Test
> >>>> +    public void valuesBasic() {
> >>>> +        assertThat(adapter.values(), hasItems(0, 3));
> >>>> +        assertThat(adapter.values().size(), is(2));
> >>>> +    }
> >>>> +
> >>>> +    @Test
> >>>> +    public void entrySetBasic() {
> >>>> +        HashMap<String, Integer> expected = new HashMap<>();
> >>>> +        expected.put("foo", 0);
> >>>> +        expected.put("bar", 3);
> >>>> +        assertEquals(expected.entrySet(), adapter.entrySet());
> >>>> +    }
> >>>> +}
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>>
> org/apache/ofbiz/base/collections/MultivaluedMapContextAdapterTests.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:eol-style = native
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>>
> org/apache/ofbiz/base/collections/MultivaluedMapContextAdapterTests.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:keywords = Date Rev Author URL Id
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>>
> org/apache/ofbiz/base/collections/MultivaluedMapContextAdapterTests.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:mime-type = text/plain
> >>>>
> >>>> Added: ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>> org/apache/ofbiz/base/collections/MultivaluedMapContextTests.java
> >>>> URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/
> >>>> framework/base/src/test/java/org/apache/ofbiz/base/collections/
> >>>> MultivaluedMapContextTests.java?rev=1838081&view=auto
> >>>> ============================================================
> >>>> ==================
> >>>> --- ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>> org/apache/ofbiz/base/collections/MultivaluedMapContextTests.java
> >> (added)
> >>>> +++ ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>> org/apache/ofbiz/base/collections/MultivaluedMapContextTests.java Wed
> >>>> Aug 15 11:45:45 2018
> >>>> @@ -0,0 +1,82 @@
> >>>> +/**********************************************************
> >>>> *********************
> >>>> + * 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.ofbiz.base.collections;
> >>>> +
> >>>> +import static org.hamcrest.CoreMatchers.both;
> >>>> +import static org.hamcrest.CoreMatchers.hasItem;
> >>>> +import static org.hamcrest.CoreMatchers.hasItems;
> >>>> +import static org.hamcrest.CoreMatchers.is;
> >>>> +import static org.hamcrest.CoreMatchers.not;
> >>>> +import static org.hamcrest.CoreMatchers.nullValue;
> >>>> +import static org.junit.Assert.assertThat;
> >>>> +
> >>>> +import org.apache.ofbiz.base.util.collections.MultivaluedMapContext;
> >>>> +import org.junit.Before;
> >>>> +import org.junit.Test;
> >>>> +
> >>>> +public class MultivaluedMapContextTests {
> >>>> +    private MultivaluedMapContext<String, Integer> m;
> >>>> +
> >>>> +    @Before
> >>>> +    public void setUp() throws Exception {
> >>>> +        m = new MultivaluedMapContext<>();
> >>>> +    }
> >>>> +
> >>>> +    @Test
> >>>> +    public void getEmpty() {
> >>>> +        assertThat(m.get("foo"), is(nullValue()));
> >>>> +    }
> >>>> +
> >>>> +    @Test
> >>>> +    public void putSingleBasic() {
> >>>> +        m.putSingle("foo", 0);
> >>>> +        assertThat(m.get("foo"), hasItem(0));
> >>>> +        m.putSingle("foo", 1);
> >>>> +        assertThat(m.get("foo"),
> >> both(hasItem(1)).and(not(hasItem(0))));
> >>>> +    }
> >>>> +
> >>>> +    @Test
> >>>> +    public void addBasic() {
> >>>> +        m.add("foo", 0);
> >>>> +        assertThat(m.get("foo"), hasItem(0));
> >>>> +        m.add("foo", 1);
> >>>> +        assertThat(m.get("foo"), hasItems(0, 1));
> >>>> +    }
> >>>> +
> >>>> +    @Test
> >>>> +    public void addWithPreviousContext() {
> >>>> +        m.add("foo", 0);
> >>>> +        m.push();
> >>>> +        assertThat(m.get("foo"), hasItem(0));
> >>>> +        m.add("foo", 1);
> >>>> +        assertThat(m.get("foo"), hasItems(0, 1));
> >>>> +    }
> >>>> +
> >>>> +    @Test
> >>>> +    public void getFirstBasic() {
> >>>> +        m.add("foo", 0);
> >>>> +        m.add("foo", 1);
> >>>> +        assertThat(m.getFirst("foo"), is(0));
> >>>> +    }
> >>>> +
> >>>> +    @Test
> >>>> +    public void getFirstEmpty() {
> >>>> +        assertThat(m.getFirst("foo"), is(nullValue()));
> >>>> +    }
> >>>> +}
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>> org/apache/ofbiz/base/collections/MultivaluedMapContextTests.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:eol-style = native
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>> org/apache/ofbiz/base/collections/MultivaluedMapContextTests.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:keywords = Date Rev Author URL Id
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/base/src/test/java/
> >>>> org/apache/ofbiz/base/collections/MultivaluedMapContextTests.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:mime-type = text/plain
> >>>>
> >>>> Modified: ofbiz/ofbiz-framework/trunk/framework/webapp/config/
> >>>> WebappUiLabels.xml
> >>>> URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/
> >>>> framework/webapp/config/WebappUiLabels.xml?rev=
> >>>> 1838081&r1=1838080&r2=1838081&view=diff
> >>>> ============================================================
> >>>> ==================
> >>>> ---
> >> ofbiz/ofbiz-framework/trunk/framework/webapp/config/WebappUiLabels.xml
> >>>> (original)
> >>>> +++
> >> ofbiz/ofbiz-framework/trunk/framework/webapp/config/WebappUiLabels.xml
> >>>> Wed Aug 15 11:45:45 2018
> >>>> @@ -339,4 +339,8 @@
> >>>>           <value xml:lang="zh">æ²¡æœ‰å®Œæˆ äº‹ä»¶</value>
> >>>>           <value xml:lang="zh-TW">æ²’æœ‰å®Œæˆ äº‹ä»¶</value>
> >>>>       </property>
> >>>> +    <property key="RequestMethodNotMatchConfig">
> >>>> +        <value xml:lang="en">[{0}] cannot be called by [{1}]
> >>>> method.</value>
> >>>> +        <value xml:lang="zh">[{0}]ä¸
> 能用[{1}]方法请求。</value>
> >>>> +    </property>
> >>>>   </resource>
> >>>>
> >>>> Modified:
> ofbiz/ofbiz-framework/trunk/framework/webapp/dtd/site-conf.xsd
> >>>> URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/
> >>>> framework/webapp/dtd/site-conf.xsd?rev=1838081&r1=
> >>>> 1838080&r2=1838081&view=diff
> >>>> ============================================================
> >>>> ==================
> >>>> --- ofbiz/ofbiz-framework/trunk/framework/webapp/dtd/site-conf.xsd
> >>>> (original)
> >>>> +++ ofbiz/ofbiz-framework/trunk/framework/webapp/dtd/site-conf.xsd Wed
> >>>> Aug 15 11:45:45 2018
> >>>> @@ -216,6 +216,24 @@ under the License.
> >>>>                   </xs:documentation>
> >>>>               </xs:annotation>
> >>>>           </xs:attribute>
> >>>> +        <xs:attribute name="method" use="optional" default="all">
> >>>> +            <xs:annotation>
> >>>> +                <xs:documentation>
> >>>> +                    The HTTP of this request. This will be the HTTP
> >>>> method used to access the request.
> >>>> +                </xs:documentation>
> >>>> +            </xs:annotation>
> >>>> +            <xs:simpleType>
> >>>> +                <xs:restriction base="xs:token">
> >>>> +                    <xs:enumeration value="get"/>
> >>>> +                    <xs:enumeration value="post"/>
> >>>> +                    <xs:enumeration value="put"/>
> >>>> +                    <xs:enumeration value="delete"/>
> >>>> +                    <xs:enumeration value="patch"/>
> >>>> +                    <xs:enumeration value="options"/>
> >>>> +                    <xs:enumeration value="all"/>
> >>>> +                </xs:restriction>
> >>>> +            </xs:simpleType>
> >>>> +        </xs:attribute>
> >>>>           <xs:attribute type="xs:boolean" name="edit" default="true">
> >>>>               <xs:annotation>
> >>>>                   <xs:documentation>
> >>>>
> >>>> Modified: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java
> >>>> URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/
> >>>> framework/webapp/src/main/java/org/apache/ofbiz/webapp/
> >>>>
> control/ConfigXMLReader.java?rev=1838081&r1=1838080&r2=1838081&view=diff
> >>>> ============================================================
> >>>> ==================
> >>>> --- ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java (original)
> >>>> +++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java Wed Aug 15
> >>>> 11:45:45 2018
> >>>> @@ -49,6 +49,8 @@ import org.apache.ofbiz.base.util.UtilVa
> >>>>   import org.apache.ofbiz.base.util.UtilXml;
> >>>>   import org.apache.ofbiz.base.util.cache.UtilCache;
> >>>>   import org.apache.ofbiz.base.util.collections.MapContext;
> >>>> +import org.apache.ofbiz.base.util.collections.MultivaluedMapContext;
> >>>> +import org.apache.ofbiz.base.util.collections.
> >>>> MultivaluedMapContextAdapter;
> >>>>   import org.w3c.dom.Document;
> >>>>   import org.w3c.dom.Element;
> >>>>
> >>>> @@ -192,7 +194,7 @@ public class ConfigXMLReader {
> >>>>           private Map<String, Event> beforeLogoutEventList = new
> >>>> LinkedHashMap<String, Event>();
> >>>>           private Map<String, String> eventHandlerMap = new
> >>>> HashMap<String, String>();
> >>>>           private Map<String, String> viewHandlerMap = new
> >> HashMap<String,
> >>>> String>();
> >>>> -        private Map<String, RequestMap> requestMapMap = new
> >>>> HashMap<String, RequestMap>();
> >>>> +        private MultivaluedMapContext<String, RequestMap>
> requestMapMap
> >>>> = new MultivaluedMapContext<>();
> >>>>           private Map<String, ViewMap> viewMapMap = new
> HashMap<String,
> >>>> ViewMap>();
> >>>>
> >>>>           public ControllerConfig(URL url) throws
> >>>> WebAppConfigurationException {
> >>>> @@ -276,11 +278,16 @@ public class ConfigXMLReader {
> >>>>               return getIncludes(ccfg -> ccfg.protectView);
> >>>>           }
> >>>>
> >>>> +        // XXX: Keep it for backward compatibility until moving
> >>>> everything to 鈥榞etRequestMapMultiMap鈥�.
> >>>>           public Map<String, RequestMap> getRequestMapMap() throws
> >>>> WebAppConfigurationException {
> >>>> -            MapContext<String, RequestMap> result = new
> MapContext<>();
> >>>> +            return new MultivaluedMapContextAdapter<>
> >>>> (getRequestMapMultiMap());
> >>>> +        }
> >>>> +
> >>>> +        public MultivaluedMapContext<String, RequestMap>
> >>>> getRequestMapMultiMap() throws WebAppConfigurationException {
> >>>> +            MultivaluedMapContext<String, RequestMap> result = new
> >>>> MultivaluedMapContext<>();
> >>>>               for (URL includeLocation : includes) {
> >>>>                   ControllerConfig controllerConfig =
> >> getControllerConfig(
> >>>> includeLocation);
> >>>> -                result.push(controllerConfig.getRequestMapMap());
> >>>> +
> result.push(controllerConfig.getRequestMapMultiMap());
> >>>>               }
> >>>>               result.push(requestMapMap);
> >>>>               return result;
> >>>> @@ -403,7 +410,7 @@ public class ConfigXMLReader {
> >>>>           private void loadRequestMap(Element root) {
> >>>>               for (Element requestMapElement :
> >>>> UtilXml.childElementList(root, "request-map")) {
> >>>>                   RequestMap requestMap = new
> >>>> RequestMap(requestMapElement);
> >>>> -                this.requestMapMap.put(requestMap.uri, requestMap);
> >>>> +                this.requestMapMap.add(requestMap.uri, requestMap);
> >>>>               }
> >>>>           }
> >>>>
> >>>> @@ -450,6 +457,7 @@ public class ConfigXMLReader {
> >>>>
> >>>>       public static class RequestMap {
> >>>>           public String uri;
> >>>> +        public String method;
> >>>>           public boolean edit = true;
> >>>>           public boolean trackVisit = true;
> >>>>           public boolean trackServerHit = true;
> >>>> @@ -466,6 +474,7 @@ public class ConfigXMLReader {
> >>>>           public RequestMap(Element requestMapElement) {
> >>>>               // Get the URI info
> >>>>               this.uri = requestMapElement.getAttribute("uri");
> >>>> +            this.method = requestMapElement.getAttribute("method");
> >>>>               this.edit = !"false".equals(requestMapElement.
> >>>> getAttribute("edit"));
> >>>>               this.trackServerHit = !"false".equals(requestMapElement.
> >>>> getAttribute("track-serverhit"));
> >>>>               this.trackVisit = !"false".equals(requestMapElement.
> >>>> getAttribute("track-visit"));
> >>>>
> >>>> Modified: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/ControlServlet.java
> >>>> URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/
> >>>> framework/webapp/src/main/java/org/apache/ofbiz/webapp/
> >>>>
> control/ControlServlet.java?rev=1838081&r1=1838080&r2=1838081&view=diff
> >>>> ============================================================
> >>>> ==================
> >>>> --- ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/ControlServlet.java (original)
> >>>> +++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/ControlServlet.java Wed Aug 15
> >>>> 11:45:45 2018
> >>>> @@ -211,6 +211,12 @@ public class ControlServlet extends Http
> >>>>           try {
> >>>>               // the ServerHitBin call for the event is done inside
> the
> >>>> doRequest method
> >>>>               requestHandler.doRequest(request, response, null,
> >>>> userLogin, delegator);
> >>>> +        } catch (MethodNotAllowedException e) {
> >>>> +            response.setContentType("text/plain");
> >>>> +
> >> response.setCharacterEncoding(request.getCharacterEncoding()
> >>>> );
> >>>> +            response.setStatus(HttpServletResponse.SC_METHOD_
> >>>> NOT_ALLOWED);
> >>>> +            response.getWriter().print(e.getMessage());
> >>>> +            Debug.logError(e.getMessage(), module);
> >>>>           } catch (RequestHandlerException e) {
> >>>>               Throwable throwable = e.getNested() != null ?
> e.getNested()
> >>>> : e;
> >>>>               if (throwable instanceof IOException) {
> >>>>
> >>>> Added: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/MethodNotAllowedException.java
> >>>> URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/
> >>>> framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/
> >>>> MethodNotAllowedException.java?rev=1838081&view=auto
> >>>> ============================================================
> >>>> ==================
> >>>> --- ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/MethodNotAllowedException.java
> >>>> (added)
> >>>> +++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/MethodNotAllowedException.java
> Wed
> >>>> Aug 15 11:45:45 2018
> >>>> @@ -0,0 +1,26 @@
> >>>> +/**********************************************************
> >>>> *********************
> >>>> + * 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.ofbiz.webapp.control;
> >>>> +
> >>>> +@SuppressWarnings("serial")
> >>>> +public class MethodNotAllowedException extends
> RequestHandlerException
> >> {
> >>>> +    MethodNotAllowedException(String str) {
> >>>> +        super(str);
> >>>> +    }
> >>>> +}
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/MethodNotAllowedException.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:eol-style = native
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/MethodNotAllowedException.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:keywords = Date Rev Author URL Id
> >>>>
> >>>> Propchange: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/MethodNotAllowedException.java
> >>>> ------------------------------------------------------------
> >>>> ------------------
> >>>>      svn:mime-type = text/plain
> >>>>
> >>>> Modified: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/RequestHandler.java
> >>>> URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/
> >>>> framework/webapp/src/main/java/org/apache/ofbiz/webapp/
> >>>>
> control/RequestHandler.java?rev=1838081&r1=1838080&r2=1838081&view=diff
> >>>> ============================================================
> >>>> ==================
> >>>> --- ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/RequestHandler.java (original)
> >>>> +++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/
> >>>> java/org/apache/ofbiz/webapp/control/RequestHandler.java Wed Aug 15
> >>>> 11:45:45 2018
> >>>> @@ -24,11 +24,15 @@ import java.io.IOException;
> >>>>   import java.io.Serializable;
> >>>>   import java.net.URL;
> >>>>   import java.security.cert.X509Certificate;
> >>>> +
> >>>> +import java.util.Collection;
> >>>> +import java.util.Collections;
> >>>>   import java.util.Enumeration;
> >>>>   import java.util.HashMap;
> >>>>   import java.util.List;
> >>>>   import java.util.Locale;
> >>>>   import java.util.Map;
> >>>> +import java.util.Optional;
> >>>>
> >>>>   import javax.servlet.ServletContext;
> >>>>   import javax.servlet.http.HttpServletRequest;
> >>>> @@ -45,12 +49,14 @@ import org.apache.ofbiz.base.util.UtilMi
> >>>>   import org.apache.ofbiz.base.util.UtilObject;
> >>>>   import org.apache.ofbiz.base.util.UtilProperties;
> >>>>   import org.apache.ofbiz.base.util.UtilValidate;
> >>>> +import org.apache.ofbiz.base.util.collections.MultivaluedMapContext;
> >>>>   import org.apache.ofbiz.entity.Delegator;
> >>>>   import org.apache.ofbiz.entity.GenericEntityException;
> >>>>   import org.apache.ofbiz.entity.GenericValue;
> >>>>   import org.apache.ofbiz.entity.util.EntityQuery;
> >>>>   import org.apache.ofbiz.entity.util.EntityUtilProperties;
> >>>>   import org.apache.ofbiz.webapp.OfbizUrlBuilder;
> >>>> +import org.apache.ofbiz.webapp.control.ConfigXMLReader.RequestMap;
> >>>>   import org.apache.ofbiz.webapp.event.EventFactory;
> >>>>   import org.apache.ofbiz.webapp.event.EventHandler;
> >>>>   import org.apache.ofbiz.webapp.event.EventHandlerException;
> >>>> @@ -68,12 +74,74 @@ import org.apache.ofbiz.widget.model.The
> >>>>   public class RequestHandler {
> >>>>
> >>>>       public static final String module =
> RequestHandler.class.getName();
> >>>> -    private final String defaultStatusCodeString = UtilProperties.
> >>>> getPropertyValue("requestHandler", "status-code", "302");
> >>>> +    private final static String defaultStatusCodeString =
> >>>> +            UtilProperties.getPropertyValue("requestHandler",
> >>>> "status-code", "302");
> >>>>       private final ViewFactory viewFactory;
> >>>>       private final EventFactory eventFactory;
> >>>>       private final URL controllerConfigURL;
> >>>>       private final boolean trackServerHit;
> >>>>       private final boolean trackVisit;
> >>>> +    private ControllerConfig ccfg;
> >>>> +
> >>>> +    static class ControllerConfig {
> >>>> +        private final MultivaluedMapContext<String, RequestMap>
> >>>> requestMapMap;
> >>>> +        private final Map<String, ConfigXMLReader.ViewMap>
> viewMapMap;
> >>>> +        private String statusCodeString;
> >>>> +        private final String defaultRequest;
> >>>> +        private final Map<String, ConfigXMLReader.Event>
> >>>> firstVisitEventList;
> >>>> +        private final Map<String, ConfigXMLReader.Event>
> >>>> preprocessorEventList;
> >>>> +        private final Map<String, ConfigXMLReader.Event>
> >>>> postprocessorEventList;
> >>>> +        private final String protectView;
> >>>> +
> >>>> +        ControllerConfig(ConfigXMLReader.ControllerConfig ccfg)
> throws
> >>>> WebAppConfigurationException {
> >>>> +            preprocessorEventList = ccfg.getPreprocessorEventList();
> >>>> +            postprocessorEventList =
> ccfg.getPostprocessorEventList();
> >>>> +            requestMapMap = ccfg.getRequestMapMultiMap();
> >>>> +            viewMapMap = ccfg.getViewMapMap();
> >>>> +            defaultRequest = ccfg.getDefaultRequest();
> >>>> +            firstVisitEventList = ccfg.getFirstVisitEventList();
> >>>> +            protectView = ccfg.getProtectView();
> >>>> +
> >>>> +            String status = ccfg.getStatusCode();
> >>>> +            statusCodeString = UtilValidate.isEmpty(status) ?
> >>>> defaultStatusCodeString : status;
> >>>> +        }
> >>>> +
> >>>> +        public MultivaluedMapContext<String, RequestMap>
> >>>> getRequestMapMap() {
> >>>> +            return requestMapMap;
> >>>> +        }
> >>>> +
> >>>> +        public Map<String, ConfigXMLReader.ViewMap> getViewMapMap() {
> >>>> +            return viewMapMap;
> >>>> +        }
> >>>> +
> >>>> +        public String getStatusCodeString() {
> >>>> +            return statusCodeString;
> >>>> +        }
> >>>> +
> >>>> +        public String getDefaultRequest() {
> >>>> +            return defaultRequest;
> >>>> +        }
> >>>> +
> >>>> +        public void setStatusCodeString(String statusCodeString) {
> >>>> +            this.statusCodeString = statusCodeString;
> >>>> +        }
> >>>> +
> >>>> +        public Map<String, ConfigXMLReader.Event>
> >>>> getFirstVisitEventList() {
> >>>> +            return firstVisitEventList;
> >>>> +        }
> >>>> +
> >>>> +        public Map<String, ConfigXMLReader.Event>
> >>>> getPreprocessorEventList() {
> >>>> +            return preprocessorEventList;
> >>>> +        }
> >>>> +
> >>>> +        public Map<String, ConfigXMLReader.Event>
> >>>> getPostprocessorEventList() {
> >>>> +            return postprocessorEventList;
> >>>> +        }
> >>>> +
> >>>> +        public String getProtectView() {
> >>>> +            return protectView;
> >>>> +        }
> >>>> +    }
> >>>>
> >>>>       public static RequestHandler getRequestHandler(ServletContext
> >>>> servletContext) {
> >>>>           RequestHandler rh = (RequestHandler)
> >>>> servletContext.getAttribute("_REQUEST_HANDLER_");
> >>>> @@ -110,6 +178,56 @@ public class RequestHandler {
> >>>>           return null;
> >>>>       }
> >>>>
> >>>> +    /**
> >>>> +     * Find a collection of request maps in {@code ccfg} matching
> >> {@code
> >>>> req}.
> >>>> +     * Otherwise fall back to matching the {@code defaultReq} field
> in
> >>>> {@code ccfg}.
> >>>> +     *
> >>>> +     * @param ccfg The controller containing the current
> configuration
> >>>> +     * @param req The HTTP request to match
> >>>> +     * @return a collection of request maps which might be empty
> >>>> +     */
> >>>> +    static Collection<RequestMap> resolveURI(ControllerConfig ccfg,
> >>>> HttpServletRequest req) {
> >>>> +        Map<String, List<RequestMap>> requestMapMap =
> >>>> ccfg.getRequestMapMap();
> >>>> +        Map<String, ConfigXMLReader.ViewMap> viewMapMap =
> >>>> ccfg.getViewMapMap();
> >>>> +        String defaultRequest = ccfg.getDefaultRequest();
> >>>> +        String path = req.getPathInfo();
> >>>> +        String requestUri = getRequestUri(path);
> >>>> +        String viewUri = getOverrideViewUri(path);
> >>>> +        Collection<RequestMap> rmaps;
> >>>> +        if (requestMapMap.containsKey(requestUri) &&
> >>>> !viewMapMap.containsKey(viewUri)) {
> >>>> +            rmaps = requestMapMap.get(requestUri);
> >>>> +        } else if (defaultRequest != null) {
> >>>> +            rmaps = requestMapMap.get(defaultRequest);
> >>>> +        } else {
> >>>> +            rmaps = null;
> >>>> +        }
> >>>> +        return rmaps != null ? rmaps : Collections.emptyList();
> >>>> +    }
> >>>> +
> >>>> +    /**
> >>>> +     * Find the request map matching {@code method}.
> >>>> +     * Otherwise fall back to the one matching the "all" and ""
> special
> >>>> methods
> >>>> +     * in that respective order.
> >>>> +     *
> >>>> +     * @param method the HTTP method to match
> >>>> +     * @param rmaps the collection of request map candidates
> >>>> +     * @return a request map {@code Optional}
> >>>> +     */
> >>>> +    static Optional<RequestMap> resolveMethod(String method,
> >>>> Collection<RequestMap> rmaps) {
> >>>> +        for (RequestMap map : rmaps) {
> >>>> +            if (map.method.equalsIgnoreCase(method)) {
> >>>> +                return Optional.of(map);
> >>>> +            }
> >>>> +        }
> >>>> +        if (method.isEmpty()) {
> >>>> +            return Optional.empty();
> >>>> +        } else if (method.equals("all")) {
> >>>> +            return resolveMethod("", rmaps);
> >>>> +        } else {
> >>>> +            return resolveMethod("all", rmaps);
> >>>> +        }
> >>>> +    }
> >>>> +
> >>>>       public void doRequest(HttpServletRequest request,
> >>>> HttpServletResponse response, String requestUri) throws
> >>>> RequestHandlerException, RequestHandlerExceptionAllowExternalRequests
> {
> >>>>           HttpSession session = request.getSession();
> >>>>           Delegator delegator = (Delegator) request.getAttribute("
> >>>> delegator");
> >>>> @@ -125,20 +243,13 @@ public class RequestHandler {
> >>>>           long startTime = System.currentTimeMillis();
> >>>>           HttpSession session = request.getSession();
> >>>>
> >>>> -        // get the controllerConfig once for this method so we don't
> >>>> have to get it over and over inside the method
> >>>> -        ConfigXMLReader.ControllerConfig controllerConfig =
> >>>> this.getControllerConfig();
> >>>> -        Map<String, ConfigXMLReader.RequestMap> requestMapMap = null;
> >>>> -        String statusCodeString = null;
> >>>> +        // Parse controller config.
> >>>>           try {
> >>>> -            requestMapMap = controllerConfig.getRequestMapMap();
> >>>> -            statusCodeString = controllerConfig.getStatusCode();
> >>>> +            ccfg = new ControllerConfig(getControllerConfig());
> >>>>           } catch (WebAppConfigurationException e) {
> >>>>               Debug.logError(e, "Exception thrown while parsing
> >>>> controller.xml file: ", module);
> >>>>               throw new RequestHandlerException(e);
> >>>>           }
> >>>> -        if (UtilValidate.isEmpty(statusCodeString)) {
> >>>> -            statusCodeString = defaultStatusCodeString;
> >>>> -        }
> >>>>
> >>>>           // workaround if we are in the root webapp
> >>>>           String cname = UtilHttp.getApplicationName(request);
> >>>> @@ -153,50 +264,29 @@ public class RequestHandler {
> >>>>               }
> >>>>           }
> >>>>
> >>>> -        String overrideViewUri = RequestHandler.
> >>>> getOverrideViewUri(request.getPathInfo());
> >>>> -
> >>>> -        String requestMissingErrorMessage = "Unknown request [" +
> >>>> defaultRequestUri + "]; this request does not exist or cannot be
> called
> >>>> directly.";
> >>>> -        ConfigXMLReader.RequestMap requestMap = null;
> >>>> -        if (defaultRequestUri != null) {
> >>>> -            requestMap = requestMapMap.get(defaultRequestUri);
> >>>> -        }
> >>>> -        // check for default request
> >>>> -        if (requestMap == null) {
> >>>> -            String defaultRequest;
> >>>> -            try {
> >>>> -                defaultRequest =
> controllerConfig.getDefaultRequest();
> >>>> -            } catch (WebAppConfigurationException e) {
> >>>> -                Debug.logError(e, "Exception thrown while parsing
> >>>> controller.xml file: ", module);
> >>>> -                throw new RequestHandlerException(e);
> >>>> -            }
> >>>> -            if (defaultRequest != null) { // required! to avoid a
> null
> >>>> pointer exception and generate a requesthandler exception if default
> >>>> request not found.
> >>>> -                requestMap = requestMapMap.get(defaultRequest);
> >>>> -            }
> >>>> -        }
> >>>> -
> >>>> -        // check for override view
> >>>> -        if (overrideViewUri != null) {
> >>>> -            ConfigXMLReader.ViewMap viewMap;
> >>>> -            try {
> >>>> -                viewMap = getControllerConfig().getViewMapMap().get(
> >>>> overrideViewUri);
> >>>> -                if (viewMap == null) {
> >>>> -                    String defaultRequest = controllerConfig.
> >>>> getDefaultRequest();
> >>>> -                    if (defaultRequest != null) { // required! to
> avoid
> >>>> a null pointer exception and generate a requesthandler exception if
> >> default
> >>>> request not found.
> >>>> -                        requestMap =
> requestMapMap.get(defaultRequest);
> >>>> -                    }
> >>>> -                }
> >>>> -            } catch (WebAppConfigurationException e) {
> >>>> -                Debug.logError(e, "Exception thrown while parsing
> >>>> controller.xml file: ", module);
> >>>> -                throw new RequestHandlerException(e);
> >>>> +        String requestMissingErrorMessage = "Unknown request ["
> >>>> +                + defaultRequestUri
> >>>> +                + "]; this request does not exist or cannot be called
> >>>> directly.";
> >>>> +
> >>>> +        String path = request.getPathInfo();
> >>>> +        String requestUri = getRequestUri(path);
> >>>> +        String overrideViewUri = getOverrideViewUri(path);
> >>>> +
> >>>> +        Collection<RequestMap> rmaps = resolveURI(ccfg, request);
> >>>> +        if (rmaps.isEmpty()) {
> >>>> +            if (throwRequestHandlerExceptionOnMissingLocalRequest) {
> >>>> +              throw new RequestHandlerException(
> >>>> requestMissingErrorMessage);
> >>>> +            } else {
> >>>> +              throw new
> RequestHandlerExceptionAllowExternalRequests();
> >>>>               }
> >>>>           }
> >>>>
> >>>> -        // if no matching request is found in the controller,
> depending
> >>>> on throwRequestHandlerExceptionOnMissingLocalRequest
> >>>> -        //  we throw a RequestHandlerException or
> >>>> RequestHandlerExceptionAllowExternalRequests
> >>>> -        if (requestMap == null) {
> >>>> -            if (throwRequestHandlerExceptionOnMissingLocalRequest)
> >>>> throw new RequestHandlerException(requestMissingErrorMessage);
> >>>> -            else throw new RequestHandlerExceptionAllowEx
> >>>> ternalRequests();
> >>>> -         }
> >>>> +        String method = request.getMethod();
> >>>> +        RequestMap requestMap = resolveMethod(method,
> >>>> rmaps).orElseThrow(() -> {
> >>>> +            String msg = UtilProperties.getMessage("WebappUiLabels",
> >>>> "RequestMethodNotMatchConfig",
> >>>> +                    UtilMisc.toList(requestUri, method),
> >>>> UtilHttp.getLocale(request));
> >>>> +            return new MethodNotAllowedException(msg);
> >>>> +        });
> >>>>
> >>>>           String eventReturn = null;
> >>>>           if (requestMap.metrics != null &&
> >> requestMap.metrics.getThreshold()
> >>>> != 0.0 && requestMap.metrics.getTotalEvents() > 3 &&
> >> requestMap.metrics.getThreshold()
> >>>> < requestMap.metrics.getServiceRate()) {
> >>>> @@ -210,7 +300,7 @@ public class RequestHandler {
> >>>>           // Check for chained request.
> >>>>           if (chain != null) {
> >>>>               String chainRequestUri = RequestHandler.getRequestUri(
> >>>> chain);
> >>>> -            requestMap = requestMapMap.get(chainRequestUri);
> >>>> +            requestMap = ccfg.getRequestMapMap().
> >>>> getFirst(chainRequestUri);
> >>>>               if (requestMap == null) {
> >>>>                   throw new RequestHandlerException("Unknown chained
> >>>> request [" + chainRequestUri + "]; this request does not exist");
> >>>>               }
> >>>> @@ -234,18 +324,11 @@ public class RequestHandler {
> >>>>               // Check to make sure we are allowed to access this
> request
> >>>> directly. (Also checks if this request is defined.)
> >>>>               // If the request cannot be called, or is not defined,
> >> check
> >>>> and see if there is a default-request we can process
> >>>>               if (!requestMap.securityDirectRequest) {
> >>>> -                String defaultRequest;
> >>>> -                try {
> >>>> -                    defaultRequest = controllerConfig.
> >>>> getDefaultRequest();
> >>>> -                } catch (WebAppConfigurationException e) {
> >>>> -                    Debug.logError(e, "Exception thrown while parsing
> >>>> controller.xml file: ", module);
> >>>> -                    throw new RequestHandlerException(e);
> >>>> -                }
> >>>> -                if (defaultRequest == null || !requestMapMap.get(
> >>>> defaultRequest).securityDirectRequest) {
> >>>> +                if (ccfg.getDefaultRequest() == null ||
> >>>>
> >>
> !ccfg.getRequestMapMap().getFirst(ccfg.getDefaultRequest()).securityDirectRequest)
> >>>> {
> >>>>                       // use the same message as if it was missing for
> >>>> security reasons, ie so can't tell if it is missing or direct request
> is
> >>>> not allowed
> >>>>                       throw new RequestHandlerException(
> >>>> requestMissingErrorMessage);
> >>>>                   } else {
> >>>> -                    requestMap = requestMapMap.get(defaultRequest);
> >>>> +                    requestMap =
> ccfg.getRequestMapMap().getFirst(ccfg.
> >>>> getDefaultRequest());
> >>>>                   }
> >>>>               }
> >>>>               // Check if we SHOULD be secure and are not.
> >>>> @@ -288,7 +371,7 @@ public class RequestHandler {
> >>>>                       String newUrl = RequestHandler.makeUrl(request,
> >>>> response, urlBuf.toString());
> >>>>                       if (newUrl.toUpperCase().startsWith("HTTPS")) {
> >>>>                           // if we are supposed to be secure, redirect
> >>>> secure.
> >>>> -                        callRedirect(newUrl, response, request,
> >>>> statusCodeString);
> >>>> +                        callRedirect(newUrl, response, request,
> >>>> ccfg.getStatusCodeString());
> >>>>                           return;
> >>>>                       }
> >>>>                   }
> >>>> @@ -333,63 +416,52 @@ public class RequestHandler {
> >>>>                   if (Debug.infoOn())
> >>>>                       Debug.logInfo("This is the first request in this
> >>>> visit." + showSessionId(request), module);
> >>>>                   session.setAttribute("_FIRST_VISIT_EVENTS_",
> >>>> "complete");
> >>>> -                try {
> >>>> -                    for (ConfigXMLReader.Event event:
> controllerConfig.
> >>>> getFirstVisitEventList().values()) {
> >>>> -                        try {
> >>>> -                            String returnString =
> >> this.runEvent(request,
> >>>> response, event, null, "firstvisit");
> >>>> -                            if (returnString == null ||
> >>>> "none".equalsIgnoreCase(returnString)) {
> >>>> -                                interruptRequest = true;
> >>>> -                            } else if
> >> (!"success".equalsIgnoreCase(returnString))
> >>>> {
> >>>> -                                throw new
> >> EventHandlerException("First-Visit
> >>>> event did not return 'success'.");
> >>>> -                            }
> >>>> -                        } catch (EventHandlerException e) {
> >>>> -                            Debug.logError(e, module);
> >>>> +                for (ConfigXMLReader.Event event:
> >>>> ccfg.getFirstVisitEventList().values()) {
> >>>> +                    try {
> >>>> +                        String returnString = this.runEvent(request,
> >>>> response, event, null, "firstvisit");
> >>>> +                        if (returnString == null ||
> >>>> "none".equalsIgnoreCase(returnString)) {
> >>>> +                            interruptRequest = true;
> >>>> +                        } else if
> >> (!"success".equalsIgnoreCase(returnString))
> >>>> {
> >>>> +                            throw new
> >> EventHandlerException("First-Visit
> >>>> event did not return 'success'.");
> >>>>                           }
> >>>> +                    } catch (EventHandlerException e) {
> >>>> +                        Debug.logError(e, module);
> >>>>                       }
> >>>> -                } catch (WebAppConfigurationException e) {
> >>>> -                    Debug.logError(e, "Exception thrown while parsing
> >>>> controller.xml file: ", module);
> >>>> -                    throw new RequestHandlerException(e);
> >>>>                   }
> >>>>               }
> >>>>
> >>>>               // Invoke the pre-processor (but NOT in a chain)
> >>>> -            try {
> >>>> -                for (ConfigXMLReader.Event event: controllerConfig.
> >>>> getPreprocessorEventList().values()) {
> >>>> -                    try {
> >>>> -                        String returnString = this.runEvent(request,
> >>>> response, event, null, "preprocessor");
> >>>> -                        if (returnString == null ||
> >>>> "none".equalsIgnoreCase(returnString)) {
> >>>> -                            interruptRequest = true;
> >>>> -                        } else if
> >> (!"success".equalsIgnoreCase(returnString))
> >>>> {
> >>>> -                            if
> (!returnString.contains(":_protect_:"))
> >> {
> >>>> -                                throw new
> >> EventHandlerException("Pre-Processor
> >>>> event [" + event.invoke + "] did not return 'success'.");
> >>>> -                            } else { // protect the view normally
> >>>> rendered and redirec

Reply via email to