This is an automated email from the ASF dual-hosted git repository. reiern70 pushed a commit to branch reiern70/systemmapper in repository https://gitbox.apache.org/repos/asf/wicket.git
commit 9f8f5f099d8ad3afa36a2251547af65c375a5ea1 Author: reiern70 <[email protected]> AuthorDate: Sat Apr 12 13:35:30 2025 -0500 [WICKET-7153] 1) make system mapper more reusable by making newResourceReferenceMapper protected and 2) roll a hash code version of ResourceReferenceMapper that encodes class names by using their hash code. --- .../main/java/org/apache/wicket/SystemMapper.java | 6 +- .../mapper/HashBasedResourceReferenceMapper.java | 121 +++++++++++++++++++++ 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/wicket-core/src/main/java/org/apache/wicket/SystemMapper.java b/wicket-core/src/main/java/org/apache/wicket/SystemMapper.java index 6f0084ca93..2140372003 100644 --- a/wicket-core/src/main/java/org/apache/wicket/SystemMapper.java +++ b/wicket-core/src/main/java/org/apache/wicket/SystemMapper.java @@ -51,7 +51,7 @@ public class SystemMapper extends CompoundRequestMapper add(newBookmarkableMapper()); add(newHomePageMapper(new HomePageProvider(application))); add(newResourceReferenceMapper(new PageParametersEncoder(), - new ParentFolderPlaceholderProvider(application), getResourceCachingStrategy())); + new ParentFolderPlaceholderProvider(application), getResourceCachingStrategy(), application)); add(newUrlResourceReferenceMapper()); add(RestartResponseAtInterceptPageException.MAPPER); add(newBufferedResponseMapper()); @@ -67,9 +67,9 @@ public class SystemMapper extends CompoundRequestMapper return new UrlResourceReferenceMapper(); } - private IRequestMapper newResourceReferenceMapper(PageParametersEncoder pageParametersEncoder, + protected IRequestMapper newResourceReferenceMapper(PageParametersEncoder pageParametersEncoder, ParentFolderPlaceholderProvider parentFolderPlaceholderProvider, - Supplier<IResourceCachingStrategy> resourceCachingStrategy) + Supplier<IResourceCachingStrategy> resourceCachingStrategy, Application application) { return new ResourceReferenceMapper(pageParametersEncoder, parentFolderPlaceholderProvider,resourceCachingStrategy); } diff --git a/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/HashBasedResourceReferenceMapper.java b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/HashBasedResourceReferenceMapper.java new file mode 100644 index 0000000000..9e2bffa455 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/core/request/mapper/HashBasedResourceReferenceMapper.java @@ -0,0 +1,121 @@ +/* + * 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.wicket.core.request.mapper; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; +import org.apache.wicket.WicketRuntimeException; +import org.apache.wicket.request.mapper.ParentPathReferenceRewriter; +import org.apache.wicket.request.mapper.parameter.IPageParametersEncoder; +import org.apache.wicket.request.resource.caching.IResourceCachingStrategy; + +/** + * <p> + * Resource reference {@link org.apache.wicket.request.IRequestMapper} that encodes class names as hash codes. + * This allows hiding the class name from resource references. i.e., instead of <em>/wicket/resource/org.xxx.yyy.ZPanel/a.js</em> the + * URL will display <em>/wicket/resource/ddd/a.js</em>, where ddd = hash(org.xxx.yyy.ZPanel). This allows globally hiding + * class structure of your application (not displaying it via URLs). + * </p> + * + * <p> + * Caveat: we don't take into account has collisions. I.e. to to different class names having the same hash code. + * </p> + * <p> + * Note: if you want to hide the "wicket" part of URL for "xxx" you can do: + * <code> + * protected IMapperContext newMapperContext() { + * return new DefaultMapperContext(this) { + * public String getNamespace() { + * return "xxx"; + * } + * }; + * } + * </code> + * on your Application class. + * </p> + */ +public class HashBasedResourceReferenceMapper extends ParentPathReferenceRewriter +{ + + private static class HashBasedBasicResourceReferenceMapper extends BasicResourceReferenceMapper + { + + private final Map<Long, String> hashMap = new ConcurrentHashMap<>(); + + private final boolean checkHashCollision; + + /** + * Construct. + * + * @param pageParametersEncoder {@link IPageParametersEncoder} + * @param cachingStrategy {@link Supplier<IResourceCachingStrategy>} + */ + public HashBasedBasicResourceReferenceMapper(IPageParametersEncoder pageParametersEncoder, Supplier<? extends IResourceCachingStrategy> cachingStrategy, boolean checkHashCollision) + { + super(pageParametersEncoder, cachingStrategy); + this.checkHashCollision = checkHashCollision; + } + + @Override + protected Class<?> resolveClass(String name) + { + try + { + long hash = Long.parseLong(name); + String className = hashMap.get(hash); + if (className == null) + { + return super.getPageClass(name); + } + return super.resolveClass(className); + } + catch (NumberFormatException e) + { + return super.getPageClass(name); + } + } + + @Override + protected String getClassName(Class<?> scope) + { + String name = super.getClassName(scope); + long hash = scope.hashCode(); + if (checkHashCollision) { + String existing = hashMap.get(hash); + if (existing != null && !existing.equals(name)) { + throw new WicketRuntimeException("Class " + name + " has collision with " + existing); + } + } + hashMap.putIfAbsent(hash, name); + return Long.toString(hash); + } + } + + /** + * Construct. + * + * @param pageParametersEncoder {@link IPageParametersEncoder} + * @param parentPathPartEscapeSequence {@link Supplier<String>} + * @param cachingStrategy Supplier<IResourceCachingStrategy> + */ + public HashBasedResourceReferenceMapper(IPageParametersEncoder pageParametersEncoder, Supplier<String> parentPathPartEscapeSequence, Supplier<IResourceCachingStrategy> cachingStrategy, boolean checkHashCollision) + { + super(new HashBasedBasicResourceReferenceMapper(pageParametersEncoder, cachingStrategy, checkHashCollision), parentPathPartEscapeSequence); + } + +}
