/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. * <p> */ package org.olat.core.gui.render; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.regex.Pattern; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.Window; import org.olat.core.gui.components.form.flexible.impl.NameValuePair; import org.olat.core.gui.control.winmgr.AJAXFlags; import org.olat.core.logging.AssertException; import org.olat.core.util.StringHelper; /** * * @author Felix Jost */ public class URLBuilder { private static final Pattern p1 = Pattern.compile("\\+"); private static final Pattern p2 = Pattern.compile("%2F"); private final String uriPrefix; private final String windowID; private final String timestampID; private String componentID; private String componentTimestamp; /** * @param uriPrefix * @param windowID * @param timestampID * @param businessControlPath may be null */ public URLBuilder(String uriPrefix, String windowID, String timestampID) { this.uriPrefix = uriPrefix; // e.g. /olat/auth this.windowID = windowID; this.timestampID = timestampID; } /** * @return */ public URLBuilder createCopyFor(Component source) { URLBuilder n = new URLBuilder(uriPrefix, windowID, timestampID); // adjust the component id of the urlbuilder for the new component n.componentID = source.getDispatchID(); // for ajax-mode needed: (but we set it anyway) // we also provide the component's timestamp in addition to the window's timestamp to enabled component-based timestamp checking. // the window-based timestamp checking is still needed for link which are not in ajax-mode and for the asynmediaresponsible n.componentTimestamp = source.getTimestamp(); return n; } /** * builds an uri. neither key nor values may contain the character * UserRequest.PARAM_DELIM which is a ":" (colon). in case you think you * should transfer a filename using a param, then may be it is better to use a * model anyway to avoid having special characters in the url (even though it * is utf-8 encoded, but some browsers/webservers do not seem to handle * special chars in the url pathinfo part) * * @param buf the buffer to write to * @param keys the keys * @param values the values. * @param modURI * @param mode indicates what kind of link it is (0 normal, 1 into background-iframe, ...) */ public void buildURI(StringOutput buf, String[] keys, String[] values, String modURI, int mode) { StringOutput result = new StringOutput(100); result.append(uriPrefix); encodeParams(result, mode); if (keys != null) { for (int i = 0; i < keys.length; i++) { result.append(UserRequest.PARAM_DELIM); result.append(keys[i]); result.append(UserRequest.PARAM_DELIM); result.append(values[i]); } } result.append("/"); if (modURI != null) { result.append(modURI); } buf.append(encodeUrl(result.toString())); } /** * @param buf * @param keys * @param values */ public void buildURI(StringOutput buf, String[] keys, String[] values) { buildURI(buf, keys, values, null, 0); } /** * * @param buf * @param keys * @param values * @param mode */ public void buildURI(StringOutput buf, String[] keys, String[] values, int mode) { buildURI(buf, keys, values, null, mode); } public void buildURI(StringOutput buf, int mode, NameValuePair... pairs) { final String[] keys; final String[] values; if(pairs == null || pairs.length == 0) { keys = values = new String[0]; } else { keys = new String[pairs.length]; values = new String[pairs.length]; for(int i=pairs.length; i-->0; ) { keys[i] = pairs[i].getName(); values[i] = pairs[i].getValue(); } } buildURI(buf, keys, values, null, mode); } public StringOutput buildHrefAndOnclick(StringOutput sb, boolean ajaxEnabled, NameValuePair... commands) { return buildHrefAndOnclick(sb, null, ajaxEnabled, true, true, commands); } public StringOutput buildHrefAndOnclick(StringOutput sb, String urlEnding, boolean ajaxEnabled, boolean dirtyCheck, boolean pushState, NameValuePair... commands) { sb.append(" href=\""); buildURI(sb, ajaxEnabled? AJAXFlags.MODE_TOBGIFRAME : AJAXFlags.MODE_NORMAL, commands); sb.append("\" onclick=\""); if(ajaxEnabled) { String escapedUrlEnding = StringHelper.escapeJavaScript(urlEnding); buildXHREvent(sb, escapedUrlEnding, dirtyCheck, pushState, commands).append(" return false;"); } else if(dirtyCheck) { sb.append("return o2cl();"); } sb.append("\" "); return sb; } public StringOutput buildXHREvent(StringOutput sb, String urlEnding, boolean dirtyCheck, boolean pushState, NameValuePair... commands) { return openXHREvent(sb, urlEnding, dirtyCheck, pushState, commands).append(");"); } public StringOutput openXHREvent(StringOutput sb, String urlEnding, boolean dirtyCheck, boolean pushState, NameValuePair... commands) { sb.append("o_XHREvent('").append(uriPrefix); encodeParams(sb, AJAXFlags.MODE_TOBGIFRAME); sb.append("/"); if(StringHelper.containsNonWhitespace(urlEnding)) { sb.append(urlEnding); } sb.append("',").append(dirtyCheck).append(",").append(pushState); commandParameters(sb, commands); return sb; } public StringOutput getXHRNoResponseEvent(StringOutput sb, String urlEnding, NameValuePair... commands) { return openXHRNoResponseEvent(sb, urlEnding, commands).append(");"); } public StringOutput openXHRNoResponseEvent(StringOutput sb, String urlEnding, NameValuePair... commands) { sb.append("o_XHRNFEvent('").append(uriPrefix); encodeParams(sb, AJAXFlags.MODE_TOBGIFRAME); sb.append("/"); if(StringHelper.containsNonWhitespace(urlEnding)) { sb.append(urlEnding); } sb.append("'"); commandParameters(sb, commands); //no response marker commandParameters(sb, new NameValuePair(Window.NO_RESPONSE_PARAMETER_MARKER, Window.NO_RESPONSE_VALUE_MARKER)); return sb; } private final void commandParameters(StringOutput sb, NameValuePair... commands) { if(commands != null && commands.length > 0 && commands[0] != null) { for(NameValuePair command:commands) { sb.append(",'") .append(command.getName()).append("','").append(command.getValue()).append("'"); } } } /** * encodes the internal params (timestamp, window id, and component id) * * @return */ private StringOutput encodeParams(StringOutput result, int mode) { // encode framework parameters result.append(windowID == null ? "0" : windowID); result.append(UserRequest.PARAM_DELIM); result.append(timestampID == null ? "0" : timestampID); result.append(UserRequest.PARAM_DELIM); result.append(componentID == null ? "0" : componentID); result.append(UserRequest.PARAM_DELIM); result.append(componentTimestamp == null ? "0" : componentTimestamp); result.append(UserRequest.PARAM_DELIM); result.append(mode); return result; } /** * @param url * @return encoded string */ public String encodeUrl(String url) { String encodedURL; try { encodedURL = URLEncoder.encode(url, "UTF-8"); } catch (UnsupportedEncodingException e) { /* * from java.nio.Charset Standard charsets Every implementation of the * Java platform is required to support the following standard charsets... * ... UTF-8 Eight-bit UCS Transformation Format ... */ throw new AssertException("utf-8 encoding is needed for proper encoding, but not offered on this java platform????"); } encodedURL = p1.matcher(encodedURL).replaceAll("%20"); encodedURL = p2.matcher(encodedURL).replaceAll("/"); return encodedURL; } String getUriPrefix() { return uriPrefix; } }