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 RequestHandlerExceptionAllowExternalRequests(); - } + 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 redirect to error response view - returnString = returnString.replace(":_protect_:", ""); - if (returnString.length() > 0) { - request.setAttribute("_ERROR_MESSAGE_", returnString); - } - eventReturn = null; - // check to see if there is a "protect" response, if so it's ok else show the default_error_response_view - if (!requestMap.requestResponseMap.containsKey("protect")) { - String protectView = controllerConfig.getProtectView(); - if (protectView != null) { - overrideViewUri = protectView; - } else { - overrideViewUri = EntityUtilProperties.getPropertyValue("security", "default.error.response.view", delegator); - overrideViewUri = overrideViewUri.replace("view:", ""); - if ("none:".equals(overrideViewUri)) { - interruptRequest = true; - } + for (ConfigXMLReader.Event event: ccfg.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 redirect to error response view + returnString = returnString.replace(":_protect_:", ""); + if (returnString.length() > 0) { + request.setAttribute("_ERROR_MESSAGE_", returnString); + } + eventReturn = null; + // check to see if there is a "protect" response, if so it's ok else show the default_error_response_view + if (!requestMap.requestResponseMap.containsKey("protect")) { + if (ccfg.getProtectView() != null) { + overrideViewUri = ccfg.getProtectView(); + } else { + overrideViewUri = EntityUtilProperties.getPropertyValue("security", "default.error.response.view", delegator); + overrideViewUri = overrideViewUri.replace("view:", ""); + if ("none:".equals(overrideViewUri)) { + interruptRequest = true; } } } } - } catch (EventHandlerException e) { - Debug.logError(e, module); } + } 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); } } @@ -409,7 +481,7 @@ public class RequestHandler { // Invoke the security handler // catch exceptions and throw RequestHandlerException if failed. if (Debug.verboseOn()) Debug.logVerbose("[RequestHandler]: AuthRequired. Running security check. " + showSessionId(request), module); - ConfigXMLReader.Event checkLoginEvent = requestMapMap.get("checkLogin").event; + ConfigXMLReader.Event checkLoginEvent = ccfg.getRequestMapMap().getFirst("checkLogin").event; String checkLoginReturnString = null; try { @@ -422,9 +494,9 @@ public class RequestHandler { eventReturn = checkLoginReturnString; // if the request is an ajax request we don't want to return the default login check if (!"XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) { - requestMap = requestMapMap.get("checkLogin"); + requestMap = ccfg.getRequestMapMap().getFirst("checkLogin"); } else { - requestMap = requestMapMap.get("ajaxCheckLogin"); + requestMap = ccfg.getRequestMapMap().getFirst("ajaxCheckLogin"); } } } @@ -556,7 +628,7 @@ public class RequestHandler { redirectTarget += "?" + queryString; } - callRedirect(makeLink(request, response, redirectTarget), response, request, statusCodeString); + callRedirect(makeLink(request, response, redirectTarget), response, request, ccfg.getStatusCodeString()); return; } } @@ -603,41 +675,35 @@ public class RequestHandler { // ======== handle views ======== // first invoke the post-processor events. - try { - for (ConfigXMLReader.Event event: controllerConfig.getPostprocessorEventList().values()) { - try { - String returnString = this.runEvent(request, response, event, requestMap, "postprocessor"); - if (returnString != null && !"success".equalsIgnoreCase(returnString)) { - throw new EventHandlerException("Post-Processor event did not return 'success'."); - } - } catch (EventHandlerException e) { - Debug.logError(e, module); + for (ConfigXMLReader.Event event: ccfg.getPostprocessorEventList().values()) { + try { + String returnString = this.runEvent(request, response, event, requestMap, "postprocessor"); + if (returnString != null && !"success".equalsIgnoreCase(returnString)) { + throw new EventHandlerException("Post-Processor 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); } String responseStatusCode = nextRequestResponse.statusCode; if(UtilValidate.isNotEmpty(responseStatusCode)) - statusCodeString = responseStatusCode; - + ccfg.setStatusCodeString(responseStatusCode); if ("url".equals(nextRequestResponse.type)) { if (Debug.verboseOn()) Debug.logVerbose("[RequestHandler.doRequest]: Response is a URL redirect." + showSessionId(request), module); - callRedirect(nextRequestResponse.value, response, request, statusCodeString); + callRedirect(nextRequestResponse.value, response, request, ccfg.getStatusCodeString()); } else if ("cross-redirect".equals(nextRequestResponse.type)) { // check for a cross-application redirect if (Debug.verboseOn()) Debug.logVerbose("[RequestHandler.doRequest]: Response is a Cross-Application redirect." + showSessionId(request), module); String url = nextRequestResponse.value.startsWith("/") ? nextRequestResponse.value : "/" + nextRequestResponse.value; - callRedirect(url + this.makeQueryString(request, nextRequestResponse), response, request, statusCodeString); + callRedirect(url + this.makeQueryString(request, nextRequestResponse), response, request, ccfg.getStatusCodeString()); } else if ("request-redirect".equals(nextRequestResponse.type)) { if (Debug.verboseOn()) Debug.logVerbose("[RequestHandler.doRequest]: Response is a Request redirect." + showSessionId(request), module); - callRedirect(makeLinkWithQueryString(request, response, "/" + nextRequestResponse.value, nextRequestResponse), response, request, statusCodeString); + callRedirect(makeLinkWithQueryString(request, response, "/" + nextRequestResponse.value, nextRequestResponse), response, request, ccfg.getStatusCodeString()); } else if ("request-redirect-noparam".equals(nextRequestResponse.type)) { if (Debug.verboseOn()) Debug.logVerbose("[RequestHandler.doRequest]: Response is a Request redirect with no parameters." + showSessionId(request), module); - callRedirect(makeLink(request, response, nextRequestResponse.value), response, request, statusCodeString); + callRedirect(makeLink(request, response, nextRequestResponse.value), response, request, ccfg.getStatusCodeString()); } else if ("view".equals(nextRequestResponse.type)) { if (Debug.verboseOn()) Debug.logVerbose("[RequestHandler.doRequest]: Response is a view." + showSessionId(request), module); Added: ofbiz/ofbiz-framework/trunk/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/RequestHandlerTests.java URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/RequestHandlerTests.java?rev=1838081&view=auto ============================================================================== --- ofbiz/ofbiz-framework/trunk/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/RequestHandlerTests.java (added) +++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/RequestHandlerTests.java Wed Aug 15 11:45:45 2018 @@ -0,0 +1,188 @@ +/******************************************************************************* + * 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; + +import static org.hamcrest.CoreMatchers.both; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.ofbiz.base.util.collections.MultivaluedMapContext; +import org.apache.ofbiz.webapp.control.ConfigXMLReader.RequestMap; +import org.apache.ofbiz.webapp.control.ConfigXMLReader.ViewMap; +import org.junit.Before; +import org.junit.Test; +import org.w3c.dom.Element; + +public class RequestHandlerTests { + public static class ResolveURITests { + private MultivaluedMapContext<String,RequestMap> reqMaps; + private Map<String, ViewMap> viewMaps; + private HttpServletRequest req; + private Element dummyElement; + private RequestHandler.ControllerConfig ccfg; + + @Before + public void setUp() { + ccfg = mock(RequestHandler.ControllerConfig.class); + reqMaps = new MultivaluedMapContext<>(); + viewMaps = new HashMap<>(); + when(ccfg.getDefaultRequest()).thenReturn(null); + when(ccfg.getRequestMapMap()).thenReturn(reqMaps); + when(ccfg.getViewMapMap()).thenReturn(viewMaps); + req = mock(HttpServletRequest.class); + dummyElement = mock(Element.class); + when(dummyElement.getAttribute("method")).thenReturn("all"); + when(req.getMethod()).thenReturn("get"); + } + + @Test + public void resolveURIBasic() throws RequestHandlerException { + RequestMap foo = new RequestMap(dummyElement); + RequestMap bar = new RequestMap(dummyElement); + reqMaps.putSingle("foo", foo); + reqMaps.putSingle("bar", bar); + when(req.getPathInfo()).thenReturn("/foo"); + assertThat(RequestHandler.resolveURI(ccfg, req), + both(hasItem(foo)).and(not(hasItem(bar)))); + assertThat(RequestHandler.resolveURI(ccfg, req).size(), is(1)); + } + + @Test + public void resolveURIBasicPut() throws RequestHandlerException { + when(dummyElement.getAttribute("method")).thenReturn("put"); + when(req.getPathInfo()).thenReturn("/foo"); + when(req.getMethod()).thenReturn("put"); + + RequestMap foo = new RequestMap(dummyElement); + + assertTrue(RequestHandler.resolveURI(ccfg, req).isEmpty()); + reqMaps.putSingle("foo", foo); + assertFalse(RequestHandler.resolveURI(ccfg, req).isEmpty()); + } + + @Test + public void resolveURIUpperCase() throws RequestHandlerException { + when(dummyElement.getAttribute("method")).thenReturn("get"); + RequestMap foo = new RequestMap(dummyElement); + when(dummyElement.getAttribute("method")).thenReturn("put"); + RequestMap bar = new RequestMap(dummyElement); + reqMaps.putSingle("foo", foo); + reqMaps.putSingle("bar", bar); + + when(req.getPathInfo()).thenReturn("/foo"); + when(req.getMethod()).thenReturn("GET"); + assertThat(RequestHandler.resolveURI(ccfg, req), hasItem(foo)); + + when(req.getPathInfo()).thenReturn("/bar"); + when(req.getMethod()).thenReturn("PUT"); + assertThat(RequestHandler.resolveURI(ccfg, req), hasItem(bar)); + } + + @Test + public void resolveURIDefault() throws Exception { + RequestMap foo = new RequestMap(dummyElement); + RequestMap bar = new RequestMap(dummyElement); + reqMaps.putSingle("foo", foo); + reqMaps.putSingle("bar", bar); + + when(req.getPathInfo()).thenReturn("/baz"); + when(ccfg.getDefaultRequest()).thenReturn("bar"); + assertThat(RequestHandler.resolveURI(ccfg, req), hasItem(bar)); + } + + @Test + public void resolveURIOverrideView() throws Exception { + RequestMap foo = new RequestMap(dummyElement); + RequestMap bar = new RequestMap(dummyElement); + reqMaps.putSingle("foo", foo); + reqMaps.putSingle("bar", bar); + + viewMaps.put("baz", new ViewMap(dummyElement)); + + when(req.getPathInfo()).thenReturn("/foo/baz"); + when(ccfg.getDefaultRequest()).thenReturn("bar"); + assertThat(RequestHandler.resolveURI(ccfg, req), hasItem(bar)); + } + + @Test + public void resolveURINoDefault() throws Exception { + RequestMap foo = new RequestMap(dummyElement); + RequestMap bar = new RequestMap(dummyElement); + reqMaps.putSingle("foo", foo); + reqMaps.putSingle("bar", bar); + + when(req.getPathInfo()).thenReturn("/baz"); + assertTrue(RequestHandler.resolveURI(ccfg, req).isEmpty()); + } + } + + public static class ResolveMethodTests { + private Element dummyElement; + private Collection<RequestMap> rmaps; + + @Before + public void setUp() { + dummyElement = mock(Element.class); + rmaps = new ArrayList<>(); + } + + @Test + public void resolveMethodBasic() throws RequestHandlerException { + RequestMap fooPut = new RequestMap(dummyElement); + fooPut.method = "put"; + rmaps.add(fooPut); + + RequestMap fooAll = new RequestMap(dummyElement); + fooAll.method = "all"; + rmaps.add(fooAll); + + assertThat(RequestHandler.resolveMethod("put", rmaps).get(), is(fooPut)); + assertThat(RequestHandler.resolveMethod("get", rmaps).get(), is(fooAll)); + } + + @Test + public void resolveMethodCatchAll() throws RequestHandlerException { + assertFalse(RequestHandler.resolveMethod("get", rmaps).isPresent()); + assertFalse(RequestHandler.resolveMethod("post", rmaps).isPresent()); + assertFalse(RequestHandler.resolveMethod("put", rmaps).isPresent()); + assertFalse(RequestHandler.resolveMethod("delete", rmaps).isPresent()); + + RequestMap foo = new RequestMap(dummyElement); + foo.method = "all"; + rmaps.add(foo); + assertTrue(RequestHandler.resolveMethod("get", rmaps).isPresent()); + assertTrue(RequestHandler.resolveMethod("post", rmaps).isPresent()); + assertTrue(RequestHandler.resolveMethod("put", rmaps).isPresent()); + assertTrue(RequestHandler.resolveMethod("delete", rmaps).isPresent()); + } + } +} Propchange: ofbiz/ofbiz-framework/trunk/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/RequestHandlerTests.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/ofbiz-framework/trunk/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/RequestHandlerTests.java ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/ofbiz-framework/trunk/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/RequestHandlerTests.java ------------------------------------------------------------------------------ svn:mime-type = text/plain |
Free forum by Nabble | Edit this page |