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

org.imsglobal.lti.BasicLTIUtil Maven / Gradle / Ivy

Go to download

BasicLTI Utilities are a set of utility classes to aid in the development of BasicLTI consumers and providers. They deal with much of the heavy lifting and make the process more opaque to the developer.

The newest version!
/*
 * $URL: https://source.sakaiproject.org/svn/basiclti/trunk/basiclti-util/src/java/org/imsglobal/basiclti/BasicLTIUtil.java $
 * $Id: BasicLTIUtil.java 133995 2014-02-02 22:06:40Z [email protected] $
 *
 * Copyright (c) 2008 IMS GLobal Learning Consortium
 *
 * Licensed 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.imsglobal.lti;

import static org.imsglobal.lti.BasicLTIConstants.CUSTOM_PREFIX;
import static org.imsglobal.lti.BasicLTIConstants.EXTENSION_PREFIX;
import static org.imsglobal.lti.BasicLTIConstants.LTI_MESSAGE_TYPE;
import static org.imsglobal.lti.BasicLTIConstants.LTI_VERSION;
import static org.imsglobal.lti.BasicLTIConstants.OAUTH_PREFIX;
import static org.imsglobal.lti.BasicLTIConstants.TOOL_CONSUMER_INSTANCE_CONTACT_EMAIL;
import static org.imsglobal.lti.BasicLTIConstants.TOOL_CONSUMER_INSTANCE_DESCRIPTION;
import static org.imsglobal.lti.BasicLTIConstants.TOOL_CONSUMER_INSTANCE_GUID;
import static org.imsglobal.lti.BasicLTIConstants.TOOL_CONSUMER_INSTANCE_NAME;
import static org.imsglobal.lti.BasicLTIConstants.TOOL_CONSUMER_INSTANCE_URL;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.TreeMap;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthMessage;
import net.oauth.OAuthValidator;
import net.oauth.SimpleOAuthValidator;
import net.oauth.server.OAuthServlet;
import net.oauth.signature.OAuthSignatureMethod;
import org.apache.commons.lang3.StringUtils;
import org.imsglobal.lti.launch.LtiError;
import org.imsglobal.lti.launch.LtiLaunch;
import org.imsglobal.lti.launch.LtiVerificationResult;

/* Leave out until we have JTidy 0.8 in the repository 
 import org.w3c.tidy.Tidy;
 import java.io.ByteArrayOutputStream;
 */
/**
 * Some Utility code for IMS LTI http://www.anyexample.com/programming/java
 * /java_simple_class_to_compute_sha_1_hash.xml
 * 

* Sample Descriptor * *

 * <?xml version="1.0" encoding="UTF-8"?>
 * <basic_lti_link xmlns="http://www.imsglobal.org/xsd/imsbasiclti_v1p0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 *   <title>generated by tp+user</title>
 *   <description>generated by tp+user</description>
 *   <custom>
 *	 <parameter key="keyname">value</parameter>
 *   </custom>
 *   <extensions platform="www.lms.com">
 *	 <parameter key="keyname">value</parameter>
 *   </extensions>
 *   <launch_url>url to the lti launch URL</launch_url>
 *   <secure_launch_url>url to the lti launch URL</secure_launch_url>
 *   <icon>url to an icon for this tool (optional)</icon>
 *   <secure_icon>url to an icon for this tool (optional)</secure_icon>
 *   <cartridge_icon identifierref="BLTI001_Icon"/>
 *   <vendor>
 *	 <code>vendor.com</code>
 *	 <name>Vendor Name</name>
 *	 <description>
 *            This is a Grade Book that supports many column types.
 *          </description>
 *	 <contact>
 *	   <email>[email protected]</email>
 *	 </contact>
 *	 <url>http://www.vendor.com/product</url>
 *   </vendor>
 * </basic_lti_link>
 * 
*/ public class BasicLTIUtil { // We use the built-in Java logger because this code needs to be very generic private static Logger M_log = Logger.getLogger(BasicLTIUtil.class.toString()); /** * To turn on really verbose debugging */ private static boolean verbosePrint = false; public static final String BASICLTI_SUBMIT = "ext_basiclti_submit"; private static final Pattern CUSTOM_REGEX = Pattern.compile("[^A-Za-z0-9]"); private static final String UNDERSCORE = "_"; // Simple Debug Print Mechanism public static void dPrint(String str) { if (verbosePrint) { System.out.println(str); } M_log.fine(str); } public static LtiVerificationResult validateMessage(HttpServletRequest request, String URL, String oauth_secret) { OAuthMessage oam = OAuthServlet.getMessage(request, URL); String oauth_consumer_key = null; try { oauth_consumer_key = oam.getConsumerKey(); } catch (Exception e) { return new LtiVerificationResult(false, LtiError.BAD_REQUEST, "Unable to find consumer key in message"); } OAuthValidator oav = new SimpleOAuthValidator(); OAuthConsumer cons = new OAuthConsumer("about:blank#OAuth+CallBack+NotUsed", oauth_consumer_key, oauth_secret, null); OAuthAccessor acc = new OAuthAccessor(cons); String base_string = null; try { base_string = OAuthSignatureMethod.getBaseString(oam); } catch (IOException|URISyntaxException e) { return new LtiVerificationResult(false, LtiError.BAD_REQUEST, "Unable to find base string"); } try { oav.validateMessage(oam, acc); } catch (Exception e) { if (base_string != null) { return new LtiVerificationResult(false, LtiError.BAD_REQUEST, "Failed to validate: " + e.getLocalizedMessage() + "\nBase String\n" + base_string); } else { return new LtiVerificationResult(false, LtiError.BAD_REQUEST, "Failed to validate: " + e.getLocalizedMessage()); } } return new LtiVerificationResult(true, new LtiLaunch(request)); } public static String validateDescriptor(String descriptor) { if (descriptor == null) { return null; } if (descriptor.indexOf(" tm = XMLMap.getFullMap(descriptor.trim()); if (tm == null) { return null; } // We demand at least an endpoint String ltiSecureLaunch = XMLMap.getString(tm, "/basic_lti_link/secure_launch_url"); // We demand at least an endpoint if (ltiSecureLaunch != null && ltiSecureLaunch.trim().length() > 0) { return ltiSecureLaunch; } String ltiLaunch = XMLMap.getString(tm, "/basic_lti_link/launch_url"); if (ltiLaunch != null && ltiLaunch.trim().length() > 0) { return ltiLaunch; } return null; } /** * Any properties which are not well known (i.e. in * {@link BasicLTIConstants#validPropertyNames}) will be mapped to custom * properties per the specified semantics. NOTE: no blacklisting of keys is * performed. * * @param rawProperties A set of properties that will be cleaned. * @return A cleansed version of rawProperties. */ public static Map cleanupProperties( final Map rawProperties) { return cleanupProperties(rawProperties, null); } /** * Any properties which are not well known (i.e. in * {@link BasicLTIConstants#validPropertyNames}) will be mapped to custom * properties per the specified semantics. * * @param rawProperties A set of properties that will be cleaned. * @param blackList An array of {@link String}s which are considered unsafe * to be included in launch data. Any matches will be removed from the * return. * @return A cleansed version of rawProperties. */ public static Map cleanupProperties( final Map rawProperties, final String[] blackList) { final Map newProp = new HashMap( rawProperties.size()); // roughly the same size for (String okey : rawProperties.keySet()) { final String key = okey.trim(); if (blackList != null) { boolean blackListed = false; for (String blackKey : blackList) { if (blackKey.equals(key)) { blackListed = true; break; } } if (blackListed) { continue; } } final String value = rawProperties.get(key); if (value == null || "".equals(value)) { // remove null or empty values continue; } if (isSpecifiedPropertyName(key)) { // a well known property name newProp.put(key, value); } else { // convert to a custom property name newProp.put(adaptToCustomPropertyName(key), value); } } return newProp; } /** * Any properties which are not well known (i.e. in * {@link BasicLTIConstants#validPropertyNames}) will be mapped to custom * properties per the specified semantics. * * @deprecated See {@link #cleanupProperties(Map)} * @param rawProperties A set of {@link Properties} that will be cleaned. * Keys must be of type {@link String}. * @return A cleansed version of {@link Properties}. */ public static Properties cleanupProperties(final Properties rawProperties) { final Map map = cleanupProperties( convertToMap(rawProperties), null); return convertToProperties(map); } /** * Checks to see if the passed propertyName is equal to one of the Strings * contained in {@link BasicLTIConstants#validPropertyNames}. String * matching is case sensitive. * * @param propertyName * @return true if propertyName is equal to one of the Strings contained in * {@link BasicLTIConstants#validPropertyNames} or is a custom parameter oe * extension parameter ; else return false. */ public static boolean isSpecifiedPropertyName(final String propertyName) { boolean found = false; if (propertyName.startsWith(CUSTOM_PREFIX)) { return true; } if (propertyName.startsWith(EXTENSION_PREFIX)) { return true; } if (propertyName.startsWith(OAUTH_PREFIX)) { return true; } for (String key : BasicLTIConstants.validPropertyNames) { if (key.equals(propertyName)) { found = true; break; } } return found; } /** * A simple utility method which implements the specified semantics of * custom properties. *

* i.e. The parameter names are mapped to lower case and any character that * is neither a number nor letter in a parameter name is replaced with an * "underscore". *

* e.g. Review:Chapter=1.2.56 would map to custom_review_chapter=1.2.56. * * @param propertyName * @return */ public static String adaptToCustomPropertyName(final String propertyName) { if (propertyName == null || "".equals(propertyName)) { throw new IllegalArgumentException("propertyName cannot be null"); } String customName = propertyName.toLowerCase(); customName = CUSTOM_REGEX.matcher(customName).replaceAll(UNDERSCORE); if (!customName.startsWith(CUSTOM_PREFIX)) { customName = CUSTOM_PREFIX + customName; } return customName; } /** * Add the necessary fields and sign. * * @deprecated See: * {@link BasicLTIUtil#signProperties(Map, String, String, String, String, String, String, String, String, String)} * * @param postProp * @param url * @param method * @param oauth_consumer_key * @param oauth_consumer_secret * @param org_id See: {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_GUID} * @param org_desc See: * {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_DESCRIPTION} * @param org_url See: {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_URL} * @return */ public static Properties signProperties(Properties postProp, String url, String method, String oauth_consumer_key, String oauth_consumer_secret, String org_id, String org_desc, String org_url) { final Map signedMap = signProperties( convertToMap(postProp), url, method, oauth_consumer_key, oauth_consumer_secret, org_id, org_desc, org_url, null, null); return convertToProperties(signedMap); } /** * Add the necessary fields and sign. * * @param postProp * @param url * @param method * @param oauth_consumer_key * @param oauth_consumer_secret * @param tool_consumer_instance_guid See: * {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_GUID} * @param tool_consumer_instance_description See: * {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_DESCRIPTION} * @param tool_consumer_instance_url See: * {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_URL} * @param tool_consumer_instance_name See: * {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_NAME} * @param tool_consumer_instance_contact_email See: * {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_CONTACT_EMAIL} * @return */ public static Map signProperties( Map postProp, String url, String method, String oauth_consumer_key, String oauth_consumer_secret, String tool_consumer_instance_guid, String tool_consumer_instance_description, String tool_consumer_instance_url, String tool_consumer_instance_name, String tool_consumer_instance_contact_email) { postProp = BasicLTIUtil.cleanupProperties(postProp); if (postProp.get(LTI_VERSION) == null) { postProp.put(LTI_VERSION, "LTI-1p0"); } if (postProp.get(LTI_MESSAGE_TYPE) == null) { postProp.put(LTI_MESSAGE_TYPE, "basic-lti-launch-request"); } // Allow caller to internationalize this for us... if (postProp.get(BASICLTI_SUBMIT) == null) { postProp.put(BASICLTI_SUBMIT, "Launch Endpoint with BasicLTI Data"); } if (tool_consumer_instance_guid != null) { postProp.put(TOOL_CONSUMER_INSTANCE_GUID, tool_consumer_instance_guid); } if (tool_consumer_instance_description != null) { postProp.put(TOOL_CONSUMER_INSTANCE_DESCRIPTION, tool_consumer_instance_description); } if (tool_consumer_instance_url != null) { postProp.put(TOOL_CONSUMER_INSTANCE_URL, tool_consumer_instance_url); } if (tool_consumer_instance_name != null) { postProp.put(TOOL_CONSUMER_INSTANCE_NAME, tool_consumer_instance_name); } if (tool_consumer_instance_contact_email != null) { postProp.put(TOOL_CONSUMER_INSTANCE_CONTACT_EMAIL, tool_consumer_instance_contact_email); } if (postProp.get("oauth_callback") == null) { postProp.put("oauth_callback", "about:blank"); } if (oauth_consumer_key == null || oauth_consumer_secret == null) { dPrint("No signature generated in signProperties"); return postProp; } OAuthMessage oam = new OAuthMessage(method, url, postProp.entrySet()); OAuthConsumer cons = new OAuthConsumer("about:blank", oauth_consumer_key, oauth_consumer_secret, null); OAuthAccessor acc = new OAuthAccessor(cons); try { oam.addRequiredParameters(acc); // System.out.println("Base Message String\n"+OAuthSignatureMethod.getBaseString(oam)+"\n"); List> params = oam.getParameters(); Map nextProp = new HashMap(); // Convert to Map for (final Map.Entry entry : params) { nextProp.put(entry.getKey(), entry.getValue()); } return nextProp; } catch (net.oauth.OAuthException e) { M_log.warning("BasicLTIUtil.signProperties OAuth Exception " + e.getMessage()); throw new Error(e); } catch (java.io.IOException e) { M_log.warning("BasicLTIUtil.signProperties IO Exception " + e.getMessage()); throw new Error(e); } catch (java.net.URISyntaxException e) { M_log.warning("BasicLTIUtil.signProperties URI Syntax Exception " + e.getMessage()); throw new Error(e); } } /** * Check if the properties are properly signed * * @deprecated See: * {@link BasicLTIUtil#checkProperties(Map, String, String, String, String)} * * @param postProp * @param url * @param method * @param oauth_consumer_key * @param oauth_consumer_secret * @return */ public static boolean checkProperties(Properties postProp, String url, String method, String oauth_consumer_key, String oauth_consumer_secret) { return checkProperties(convertToMap(postProp), url, method, oauth_consumer_key, oauth_consumer_secret); } /** * Check if the fields are properly signed * * @param postProp * @param url * @param method * @param oauth_consumer_key * @param oauth_consumer_secret * * @return */ public static boolean checkProperties( Map postProp, String url, String method, String oauth_consumer_key, String oauth_consumer_secret) { OAuthMessage oam = new OAuthMessage(method, url, postProp.entrySet()); OAuthConsumer cons = new OAuthConsumer("about:blank", oauth_consumer_key, oauth_consumer_secret, null); OAuthValidator oav = new SimpleOAuthValidator(); OAuthAccessor acc = new OAuthAccessor(cons); String base_string = null; try { base_string = OAuthSignatureMethod.getBaseString(oam); } catch (Exception e) { M_log.warning(e.getLocalizedMessage()); base_string = null; return false; } try { oav.validateMessage(oam, acc); } catch (Exception e) { M_log.warning("Provider failed to validate message"); M_log.warning(e.getLocalizedMessage()); if (base_string != null) { M_log.warning(base_string); } return false; } return true; } /** * Create the HTML to render a POST form and then automatically submit it. * Make sure to call {@link #cleanupProperties(Properties)} before signing. * * @deprecated Moved to {@link #postLaunchHTML(Map, String, boolean)} * @param cleanProperties Assumes you have called * {@link #cleanupProperties(Properties)} beforehand. * @param endpoint The LTI launch url. * @param debug Useful for viewing the HTML before posting to end point. * @return the HTML ready for IFRAME src = inclusion. */ public static String postLaunchHTML(final Properties cleanProperties, String endpoint, boolean debug) { Map map = convertToMap(cleanProperties); return postLaunchHTML(map, endpoint, debug); } /** * Create the HTML to render a POST form and then automatically submit it. * Make sure to call {@link #cleanupProperties(Properties)} before signing. * * @param cleanProperties Assumes you have called * {@link #cleanupProperties(Properties)} beforehand. * @param endpoint The LTI launch url. * @param debug Useful for viewing the HTML before posting to end point. * @return the HTML ready for IFRAME src = inclusion. */ public static String postLaunchHTML( final Map cleanProperties, String endpoint, boolean debug) { if (cleanProperties == null || cleanProperties.isEmpty()) { throw new IllegalArgumentException( "cleanProperties == null || cleanProperties.isEmpty()"); } if (endpoint == null) { throw new IllegalArgumentException("endpoint == null"); } Map newMap = null; if (debug) { // sort the properties for readability newMap = new TreeMap(cleanProperties); } else { newMap = cleanProperties; } StringBuilder text = new StringBuilder(); // paint form text.append("

\n"); text.append("
\n"); for (Entry entry : newMap.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); if (value == null) { continue; } // This will escape the contents pretty much - at least // we will be safe and not generate dangerous HTML key = htmlspecialchars(key); value = htmlspecialchars(value); if (key.equals(BASICLTI_SUBMIT)) { text.append("\n"); } text.append("\n"); text.append("
\n"); // Paint the auto-pop up if we are transitioning from https: to http: // and are not already the top frame... text.append("\n"); // paint debug output if (debug) { text.append("
\n");
            text.append("BasicLTI Endpoint\n");
            text.append(endpoint);
            text.append("\n\n");
            text.append("BasicLTI Parameters:\n");
            for (Entry entry : newMap.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (value == null) {
                    continue;
                }
                text.append(htmlspecialchars(key));
                text.append("=");
                text.append(htmlspecialchars(value));
                text.append("\n");
            }
            text.append("
\n"); } else { // paint auto submit script text .append(" \n"); } String htmltext = text.toString(); return htmltext; } /** * @deprecated See: {@link #parseDescriptor(Map, Map, String)} * @param launch_info Variable is mutated by this method. * @param postProp Variable is mutated by this method. * @param descriptor * @return */ public static boolean parseDescriptor(Properties launch_info, Properties postProp, String descriptor) { // this is an ugly copy/paste of the non-@deprecated method // could not convert data types as they variables get mutated (ugh) Map tm = null; try { tm = XMLMap.getFullMap(descriptor.trim()); } catch (Exception e) { M_log.warning("BasicLTIUtil exception parsing BasicLTI descriptor: " + e.getMessage()); return false; } if (tm == null) { M_log.warning("Unable to parse XML in parseDescriptor"); return false; } String launch_url = StringUtils.stripToNull(XMLMap.getString(tm, "/basic_lti_link/launch_url")); String secure_launch_url = StringUtils.stripToNull(XMLMap.getString(tm, "/basic_lti_link/secure_launch_url")); if (launch_url == null && secure_launch_url == null) { return false; } setProperty(launch_info, "launch_url", launch_url); setProperty(launch_info, "secure_launch_url", secure_launch_url); // Extensions for hand-authored placements - The export process should scrub these setProperty(launch_info, "key", StringUtils.stripToNull(XMLMap.getString(tm, "/basic_lti_link/x-secure/launch_key"))); setProperty(launch_info, "secret", StringUtils.stripToNull(XMLMap.getString(tm, "/basic_lti_link/x-secure/launch_secret"))); List> theList = XMLMap.getList(tm, "/basic_lti_link/custom/parameter"); for (Map setting : theList) { dPrint("Setting=" + setting); String key = XMLMap.getString(setting, "/!key"); // Get the key attribute String value = XMLMap.getString(setting, "/"); // Get the value if (key == null || value == null) { continue; } key = "custom_" + mapKeyName(key); dPrint("key=" + key + " val=" + value); postProp.setProperty(key, value); } return true; } /** * * @param launch_info Variable is mutated by this method. * @param postProp Variable is mutated by this method. * @param descriptor * @return */ public static boolean parseDescriptor(Map launch_info, Map postProp, String descriptor) { Map tm = null; try { tm = XMLMap.getFullMap(descriptor.trim()); } catch (Exception e) { M_log.warning("BasicLTIUtil exception parsing BasicLTI descriptor: " + e.getMessage()); return false; } if (tm == null) { M_log.warning("Unable to parse XML in parseDescriptor"); return false; } String launch_url = StringUtils.stripToNull(XMLMap.getString(tm, "/basic_lti_link/launch_url")); String secure_launch_url = StringUtils.stripToNull(XMLMap.getString(tm, "/basic_lti_link/secure_launch_url")); if (launch_url == null && secure_launch_url == null) { return false; } setProperty(launch_info, "launch_url", launch_url); setProperty(launch_info, "secure_launch_url", secure_launch_url); // Extensions for hand-authored placements - The export process should scrub // these setProperty(launch_info, "key", StringUtils.stripToNull(XMLMap.getString(tm, "/basic_lti_link/x-secure/launch_key"))); setProperty(launch_info, "secret", StringUtils.stripToNull(XMLMap.getString(tm, "/basic_lti_link/x-secure/launch_secret"))); List> theList = XMLMap.getList(tm, "/basic_lti_link/custom/parameter"); for (Map setting : theList) { dPrint("Setting=" + setting); String key = XMLMap.getString(setting, "/!key"); // Get the key attribute String value = XMLMap.getString(setting, "/"); // Get the value if (key == null || value == null) { continue; } key = "custom_" + mapKeyName(key); dPrint("key=" + key + " val=" + value); postProp.put(key, value); } return true; } // Remove fields that should not be exported public static String prepareForExport(String descriptor) { Map tm = null; try { tm = XMLMap.getFullMap(descriptor.trim()); } catch (Exception e) { M_log.warning("BasicLTIUtil exception parsing BasicLTI descriptor" + e.getMessage()); return null; } if (tm == null) { M_log.warning("Unable to parse XML in prepareForExport"); return null; } XMLMap.removeSubMap(tm, "/basic_lti_link/x-secure"); String retval = XMLMap.getXML(tm, true); return retval; } /** * The parameter name is mapped to lower case and any character that is * neither a number or letter is replaced with an "underscore". So if a * custom entry was as follows: * * {@code 1.2.56} * * Would map to: custom_vendor_chapter=1.2.56 */ public static String mapKeyName(String keyname) { StringBuffer sb = new StringBuffer(); if (keyname == null) { return null; } keyname = keyname.trim(); if (keyname.length() < 1) { return null; } for (int i = 0; i < keyname.length(); i++) { Character ch = Character.toLowerCase(keyname.charAt(i)); if (Character.isLetter(ch) || Character.isDigit(ch)) { sb.append(ch); } else { sb.append('_'); } } return sb.toString(); } /** * Mutates the passed {@code Map map} variable. Puts the key,value * into the Map if the value is not null and is not empty. * * @param map Variable is mutated by this method. * @param key * @param value */ public static void setProperty(final Map map, final String key, final String value) { if (value != null && !"".equals(value)) { map.put(key, value); } } /** * Mutates the passed Properties props variable. Puts the key,value into the * Map if the value is not null and is not empty. * * @deprecated See: {@link #setProperty(Map, String, String)} * @param props Variable is mutated by this method. * @param key * @param value */ public static void setProperty(Properties props, String key, String value) { if (value == null) { return; } if (value.trim().length() < 1) { return; } props.setProperty(key, value); } // Basic utility to encode form text - handle the "safe cases" public static String htmlspecialchars(String input) { if (input == null) { return null; } String retval = input.replace("&", "&"); retval = retval.replace("\"", """); retval = retval.replace("<", "<"); retval = retval.replace(">", ">"); retval = retval.replace(">", ">"); retval = retval.replace("=", "="); return retval; } /** * Simple utility method deal with a request that has the wrong URL when * behind a proxy. * * @param extUrl The url that the external world sees us as responding to. * This needs to be up to but not including the last slash like and not * include any path information http://www.sakaiproject.org - although we do * compensate for extra stuff at the end. * @return The full path of the request with extUrl in place of whatever the * request thinks is the current URL. */ static public String getRealPath(String servletUrl, String extUrl) { Pattern pat = Pattern.compile("^https??://[^/]*"); // Deal with potential bad extUrl formats Matcher m = pat.matcher(extUrl); if (m.find()) { extUrl = m.group(0); } String retval = pat.matcher(servletUrl).replaceFirst(extUrl); return retval; } static public String getRealPath(HttpServletRequest request, String extUrl) { String URLstr = request.getRequestURL().toString(); String retval = getRealPath(URLstr, extUrl); return retval; } /** * Simple utility method to help with the migration from {@code Properties} to {@code Map}. * * @param properties * @return */ @SuppressWarnings({"unchecked", "rawtypes"}) public static Map convertToMap(final Properties properties) { final Map map = new HashMap(properties); return map; } /** * Simple utility method to help with the migration from {@code Map} * to {@code Properties}. * * @deprecated Should migrate to {@code Map} signatures. * @param map * @return */ public static Properties convertToProperties(final Map map) { final Properties properties = new Properties(); if (map != null) { for (Entry entry : map.entrySet()) { properties.setProperty(entry.getKey(), entry.getValue()); } } return properties; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy