All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.wicket.request.mapper.MountedMapper Maven / Gradle / Ivy

Go to download

Pax Wicket Service is an OSGi extension of the Wicket framework, allowing for dynamic loading and unloading of Wicket components and pageSources.

There is a newer version: 5.0.0
Show newest version
/*
 * 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.request.mapper;

import java.util.ArrayList;
import java.util.List;

import org.apache.wicket.Application;
import org.apache.wicket.RequestListenerInterface;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.component.IRequestablePage;
import org.apache.wicket.request.handler.ListenerInterfaceRequestHandler;
import org.apache.wicket.request.mapper.info.ComponentInfo;
import org.apache.wicket.request.mapper.info.PageComponentInfo;
import org.apache.wicket.request.mapper.info.PageInfo;
import org.apache.wicket.request.mapper.parameter.IPageParametersEncoder;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.mapper.parameter.PageParametersEncoder;
import org.apache.wicket.util.ClassProvider;
import org.apache.wicket.util.lang.Args;
import org.apache.wicket.util.string.Strings;

/**
 * Encoder for mounted URL. The mount path can contain parameter placeholders, i.e.
 * /mount/${foo}/path. In that case the appropriate segment from the URL will be
 * accessible as named parameter "foo" in the {@link PageParameters}. Similarly when the URL is
 * constructed, the second segment will contain the value of the "foo" named page parameter.
 * Optional parameters are denoted by using a # instead of $: /mount/#{foo}/path/${bar}
 * has an optional {@code foo} parameter, a fixed {@code /path/} part and a required {@code bar}
 * parameter. When in doubt, parameters are matched from left to right, where required parameters
 * are matched before optional parameters, and optional parameters eager (from left to right).
 * 

* Decodes and encodes the following URLs: * *

 *  Page Class - Render (BookmarkablePageRequestHandler for mounted pages)
 *  /mount/point
 *  (these will redirect to hybrid alternative if page is not stateless)
 * 
 *  IPage Instance - Render Hybrid (RenderPageRequestHandler for mounted pages) 
 *  /mount/point?2
 * 
 *  IPage Instance - Bookmarkable Listener (BookmarkableListenerInterfaceRequestHandler for mounted pages) 
 *  /mount/point?2-click-foo-bar-baz
 *  /mount/point?2-5.click.1-foo-bar-baz (1 is behavior index, 5 is render count)
 *  (these will redirect to hybrid if page is not stateless)
 * 
* * @author Matej Knopp */ public class MountedMapper extends AbstractBookmarkableMapper { private final IPageParametersEncoder pageParametersEncoder; private static class MountPathSegment { private int segmentIndex; private String fixedPart; private int minParameters; private int optionalParameters; public MountPathSegment(int segmentIndex) { this.segmentIndex = segmentIndex; } public void setFixedPart(String fixedPart) { this.fixedPart = fixedPart; } public void addRequiredParameter() { minParameters++; } public void addOptionalParameter() { optionalParameters++; } public int getSegmentIndex() { return segmentIndex; } public String getFixedPart() { return fixedPart; } public int getMinParameters() { return minParameters; } public int getOptionalParameters() { return optionalParameters; } public int getMaxParameters() { return getOptionalParameters() + getMinParameters(); } public int getFixedPartSize() { return getFixedPart() == null ? 0 : 1; } @Override public String toString() { return "(" + getSegmentIndex() + ") " + getMinParameters() + "-" + getMaxParameters() + " " + (getFixedPart() == null ? "(end)" : getFixedPart()); } } private final List pathSegments; private final String[] mountSegments; /** bookmarkable page class. */ private final ClassProvider pageClassProvider; /** * Construct. * * @param mountPath * @param pageClass */ public MountedMapper(String mountPath, Class pageClass) { this(mountPath, pageClass, new PageParametersEncoder()); } /** * Construct. * * @param mountPath * @param pageClassProvider */ public MountedMapper(String mountPath, ClassProvider pageClassProvider) { this(mountPath, pageClassProvider, new PageParametersEncoder()); } /** * Construct. * * @param mountPath * @param pageClass * @param pageParametersEncoder */ public MountedMapper(String mountPath, Class pageClass, IPageParametersEncoder pageParametersEncoder) { this(mountPath, ClassProvider.of(pageClass), pageParametersEncoder); } /** * Construct. * * @param mountPath * @param pageClassProvider * @param pageParametersEncoder */ public MountedMapper(String mountPath, ClassProvider pageClassProvider, IPageParametersEncoder pageParametersEncoder) { Args.notEmpty(mountPath, "mountPath"); Args.notNull(pageClassProvider, "pageClassProvider"); Args.notNull(pageParametersEncoder, "pageParametersEncoder"); this.pageParametersEncoder = pageParametersEncoder; this.pageClassProvider = pageClassProvider; mountSegments = getMountSegments(mountPath); pathSegments = getPathSegments(mountSegments); } private List getPathSegments(String[] segments) { List ret = new ArrayList(); int segmentIndex = 0; MountPathSegment curPathSegment = new MountPathSegment(segmentIndex); ret.add(curPathSegment); for (String curSegment : segments) { if (isFixedSegment(curSegment)) { curPathSegment.setFixedPart(curSegment); curPathSegment = new MountPathSegment(segmentIndex + 1); ret.add(curPathSegment); } else if (getPlaceholder(curSegment) != null) { curPathSegment.addRequiredParameter(); } else { curPathSegment.addOptionalParameter(); } segmentIndex++; } return ret; } private boolean isFixedSegment(String segment) { return getOptionalPlaceholder(segment) == null && getPlaceholder(segment) == null; } /** * @see org.apache.wicket.request.mapper.AbstractBookmarkableMapper#parseRequest(org.apache.wicket.request.Request) */ @Override protected UrlInfo parseRequest(Request request) { Url url = request.getUrl(); // when redirect to buffer/render is active and redirectFromHomePage returns true // check mounted class against the home page class. if it matches let wicket redirect // to the mounted URL if (redirectFromHomePage() && checkHomePage(url)) { return new UrlInfo(null, getContext().getHomePageClass(), newPageParameters()); } // check if the URL starts with the proper segments else if (urlStartsWith(url, mountSegments)) { // try to extract page and component information from URL PageComponentInfo info = getPageComponentInfo(url); Class pageClass = getPageClass(); PageParameters pageParameters = extractPageParameters(request, url); return new UrlInfo(info, pageClass, pageParameters); } else { return null; } } /* * extract the PageParameters from URL if there are any */ private PageParameters extractPageParameters(Request request, Url url) { int[] matchedParameters = getMatchedSegmentSizes(url); int total = 0; for (int curMatchSize : matchedParameters) total += curMatchSize; PageParameters pageParameters = extractPageParameters(request, total, pageParametersEncoder); int skippedParameters = 0; for (int pathSegmentIndex = 0; pathSegmentIndex < pathSegments.size(); pathSegmentIndex++) { MountPathSegment curPathSegment = pathSegments.get(pathSegmentIndex); int matchSize = matchedParameters[pathSegmentIndex] - curPathSegment.getFixedPartSize(); int optionalParameterMatch = matchSize - curPathSegment.getMinParameters(); for (int matchSegment = 0; matchSegment < matchSize; matchSegment++) { if (pageParameters == null) { pageParameters = new PageParameters(); } int curSegmentIndex = matchSegment + curPathSegment.getSegmentIndex(); String curSegment = mountSegments[curSegmentIndex]; String placeholder = getPlaceholder(curSegment); String optionalPlaceholder = getOptionalPlaceholder(curSegment); // extract the parameter from URL if (placeholder != null) { pageParameters.add(placeholder, url.getSegments().get(curSegmentIndex - skippedParameters)); } else if (optionalPlaceholder != null && optionalParameterMatch > 0) { pageParameters.add(optionalPlaceholder, url.getSegments().get(curSegmentIndex - skippedParameters)); optionalParameterMatch--; } } skippedParameters += curPathSegment.getMaxParameters() - matchSize; } return pageParameters; } @Override protected boolean urlStartsWith(Url url, String... segments) { if (url == null) { return false; } else { return getMatchedSegmentSizes(url) != null; } } private int[] getMatchedSegmentSizes(Url url) { int[] ret = new int[pathSegments.size()]; int segmentIndex = 0; int pathSegmentIndex = 0; for (MountPathSegment curPathSegment : pathSegments.subList(0, pathSegments.size() - 1)) { boolean foundFixedPart = false; segmentIndex += curPathSegment.getMinParameters(); int max = Math.min(curPathSegment.getOptionalParameters() + 1, url.getSegments().size() - segmentIndex); for (int count = max - 1; count >= 0; count--) { if (url.getSegments() .get(segmentIndex + count) .equals(curPathSegment.getFixedPart())) { foundFixedPart = true; segmentIndex += count + 1; ret[pathSegmentIndex] = count + curPathSegment.getMinParameters() + 1; break; } } if (!foundFixedPart) return null; pathSegmentIndex++; } MountPathSegment lastSegment = pathSegments.get(pathSegments.size() - 1); segmentIndex += lastSegment.getMinParameters(); if (segmentIndex > url.getSegments().size()) return null; ret[pathSegmentIndex] = Math.min(lastSegment.getMaxParameters(), url.getSegments().size() - segmentIndex + lastSegment.getMinParameters()); return ret; } protected PageParameters newPageParameters() { return new PageParameters(); } @Override public Url mapHandler(IRequestHandler requestHandler) { Url url = super.mapHandler(requestHandler); if (url == null && requestHandler instanceof ListenerInterfaceRequestHandler && getRecreateMountedPagesAfterExpiry()) { ListenerInterfaceRequestHandler handler = (ListenerInterfaceRequestHandler)requestHandler; IRequestablePage page = handler.getPage(); if (checkPageInstance(page)) { String componentPath = handler.getComponentPath(); RequestListenerInterface listenerInterface = handler.getListenerInterface(); Integer renderCount = null; if (listenerInterface.isIncludeRenderCount()) { renderCount = page.getRenderCount(); } PageInfo pageInfo = new PageInfo(page.getPageId()); ComponentInfo componentInfo = new ComponentInfo(renderCount, requestListenerInterfaceToString(listenerInterface), componentPath, handler.getBehaviorIndex()); PageComponentInfo pageComponentInfo = new PageComponentInfo(pageInfo, componentInfo); PageParameters parameters = new PageParameters(page.getPageParameters()); UrlInfo urlInfo = new UrlInfo(pageComponentInfo, page.getClass(), parameters.mergeWith(handler.getPageParameters())); url = buildUrl(urlInfo); } } return url; } boolean getRecreateMountedPagesAfterExpiry() { return Application.get().getPageSettings().getRecreateMountedPagesAfterExpiry(); } /** * @see org.apache.wicket.request.mapper.AbstractBookmarkableMapper#buildUrl(org.apache.wicket.request.mapper.AbstractBookmarkableMapper.UrlInfo) */ @Override protected Url buildUrl(UrlInfo info) { Url url = new Url(); for (String s : mountSegments) { url.getSegments().add(s); } encodePageComponentInfo(url, info.getPageComponentInfo()); PageParameters copy = new PageParameters(info.getPageParameters()); int dropped = 0; for (int i = 0; i < mountSegments.length; ++i) { String placeholder = getPlaceholder(mountSegments[i]); String optionalPlaceholder = getOptionalPlaceholder(mountSegments[i]); if (placeholder != null) { url.getSegments().set(i - dropped, copy.get(placeholder).toString("")); copy.remove(placeholder); } else if (optionalPlaceholder != null) { if (copy.getNamedKeys().contains(optionalPlaceholder)) { url.getSegments().set(i - dropped, copy.get(optionalPlaceholder).toString("")); copy.remove(optionalPlaceholder); } else { url.getSegments().remove(i - dropped); dropped++; } } } return encodePageParameters(url, copy, pageParametersEncoder); } /** * Check if the URL is for home page and the home page class match mounted class. If so, * redirect to mounted URL. * * @param url * @return request handler or null */ private boolean checkHomePage(Url url) { if (url.getSegments().isEmpty() && url.getQueryParameters().isEmpty()) { // this is home page if (getPageClass().equals(getContext().getHomePageClass()) && redirectFromHomePage()) { return true; } } return false; } /** * If this method returns true and application home page class is same as the class * mounted with this encoder, request to home page will result in a redirect to the mounted * path. * * @return whether this encode should respond to home page request when home page class is same * as mounted class. */ protected boolean redirectFromHomePage() { return true; } /** * @see org.apache.wicket.request.mapper.AbstractBookmarkableMapper#pageMustHaveBeenCreatedBookmarkable() */ @Override protected boolean pageMustHaveBeenCreatedBookmarkable() { return false; } /** * @see org.apache.wicket.request.mapper.AbstractBookmarkableMapper#getCompatibilityScore(org.apache.wicket.request.Request) */ @Override public int getCompatibilityScore(Request request) { if (urlStartsWith(request.getUrl(), mountSegments)) { return mountSegments.length; } else { return 0; } } /** * @see org.apache.wicket.request.mapper.AbstractBookmarkableMapper#checkPageClass(java.lang.Class) */ @Override protected boolean checkPageClass(Class pageClass) { return pageClass.equals(this.getPageClass()); } private Class getPageClass() { return pageClassProvider.get(); } @Override public String toString() { return "MountedMapper [mountSegments=" + Strings.join("/", mountSegments) + "]"; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy