Java tutorial
/** * 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) 1999-2006 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <p> */ package org.olat.core.util; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.net.URLEncoder; import java.text.DateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringEscapeUtils; import org.olat.core.commons.chiefcontrollers.BaseChiefController; import org.olat.core.logging.LogDelegator; import org.radeox.api.engine.RenderEngine; import org.radeox.api.engine.context.InitialRenderContext; import org.radeox.api.engine.context.RenderContext; import org.radeox.engine.BaseRenderEngine; import org.radeox.engine.context.BaseInitialRenderContext; import org.radeox.engine.context.BaseRenderContext; /** * enclosing_type Description: <br> * A formatter to format locale-specific things (mainly dates and times) * * @author Felix Jost */ public class Formatter extends LogDelegator { private Locale locale; private static RenderEngine engineWithContext; private static BaseRenderContext baseRenderContext; static { InitialRenderContext initialContext = new BaseInitialRenderContext(); Locale loc = new Locale("olat", "olat"); initialContext.set(RenderContext.INPUT_LOCALE, loc); initialContext.set(RenderContext.OUTPUT_LOCALE, loc); initialContext.set(RenderContext.INPUT_BUNDLE_NAME, "radeox_markup_olat"); initialContext.set(RenderContext.OUTPUT_BUNDLE_NAME, "radeox_markup_olat"); engineWithContext = new BaseRenderEngine(initialContext); baseRenderContext = new BaseRenderContext(); } /** * Constructor for Formatter. */ private Formatter(Locale locale) { this.locale = locale; } /** * get an instance of the Formatter given the locale * * @param locale the locale which the formatter should use in its operations * @return the instance of the Formatter */ public static Formatter getInstance(Locale locale) { return new Formatter(locale); } /** * formats the given date so it is friendly to read * * @param d the date * @return a String with the formatted date */ public String formatDate(Date d) { DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); df.setLenient(false); String da = df.format(d); return da; } /** * formats the given time period so it is friendly to read * * @param d the date * @return a String with the formatted time */ public String formatTime(Date d) { DateFormat df = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale); df.setLenient(false); String da = df.format(d); return da; } /** * formats the given date so it is friendly to read * * @param d the date * @return a String with the formatted date and time */ public String formatDateAndTime(Date d) { if (d == null) return null; DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale); df.setLenient(false); String da = df.format(d); return da; } /** * Generate a simple date pattern that formats a date using the locale of the formatter * * @return */ public String getSimpleDatePatternForDate() { Calendar cal = new GregorianCalendar(); cal.set(1999, Calendar.MARCH, 1, 0, 0, 0); Date testDate = cal.getTime(); String formattedDate = formatDate(testDate); formattedDate = formattedDate.replace("1999", "%Y"); formattedDate = formattedDate.replace("99", "%Y"); formattedDate = formattedDate.replace("03", "%m"); formattedDate = formattedDate.replace("3", "%m"); formattedDate = formattedDate.replace("01", "%d"); formattedDate = formattedDate.replace("1", "%d"); return formattedDate; } /** * Generate a simple date pattern that formats a date with time using the locale of the formatter * * @return */ public String getSimpleDatePatternForDateAndTime() { Calendar cal = new GregorianCalendar(); cal.set(1999, Calendar.MARCH, 1, 4, 5, 0); Date testDate = cal.getTime(); String formattedDate = formatDateAndTime(testDate); formattedDate = formattedDate.replace("1999", "%Y"); formattedDate = formattedDate.replace("99", "%Y"); formattedDate = formattedDate.replace("03", "%m"); formattedDate = formattedDate.replace("3", "%m"); formattedDate = formattedDate.replace("01", "%d"); formattedDate = formattedDate.replace("1", "%d"); formattedDate = formattedDate.replace("04", "%H"); formattedDate = formattedDate.replace("4", "%H"); formattedDate = formattedDate.replace("05", "%M"); formattedDate = formattedDate.replace("5", "%M"); if (formattedDate.endsWith("AM")) { formattedDate = formattedDate.replace("%H", "%I").replace("AM", "%p"); } return formattedDate; } /** * Formats the given date with the ISO 8601 standard also known as 'datetime' See http://www.w3.org/TR/NOTE-datetime.html for more info. * * @param d the date to be formatted * @return a String with the formatted date and time */ public static String formatDatetime(Date d) { java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); return formatter.format(d); } /** * Use this for naming files or directories with a timestamp. As windows does not like ":" in filenames formatDateAndTime(d) does not work * * @param d the date to be formatted * @return a String with the formatted date and time */ public static String formatDatetimeFilesystemSave(Date d) { java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss_SSS"); return formatter.format(d); } /** * formats the given time period so it is friendly to read * * @param d the date * @return a String with the formatted time */ public String formatTimeShort(Date d) { DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT, locale); df.setLenient(false); String da = df.format(d); return da; } /** * Formats a duration in millis to "XXh YYm ZZs" * * @param millis * @return formatted string */ public static String formatDuration(long millis) { long h = millis / (1000 * 60 * 60); long hmins = h * 1000 * 60 * 60; long m = (millis - hmins) / (1000 * 60); long s = (millis - hmins - m * 1000 * 60) / 1000; return h + "h " + m + "m " + s + "s"; } /** * Escape " with \" in strings * * @param source * @return escaped string */ public static StringBuilder escapeDoubleQuotes(String source) { if (source == null) return null; StringBuilder sb = new StringBuilder(300); int len = source.length(); char[] cs = source.toCharArray(); for (int i = 0; i < len; i++) { char c = cs[i]; switch (c) { case '"': sb.append("""); break; default: sb.append(c); } } return sb; } /** * Escape " with \" and ' with \' in strings * * @param source * @return escaped string * @deprecated use org.apache.commons.lang.StringEscapeUtils.escapeJavaScript() instead. */ public static StringBuilder escapeSingleAndDoubleQuotes(String source) { if (source == null) return null; StringBuilder sb = new StringBuilder(300); int len = source.length(); char[] cs = source.toCharArray(); for (int i = 0; i < len; i++) { char c = cs[i]; switch (c) { case '"': sb.append("\\\""); break; case '\'': sb.append("\\\'"); break; default: sb.append(c); } } return sb; } /** * replace a given String with a different String * * @param source the source * @param delim the String to replace * @param replacement the replacement String * @return StringBuilder */ public StringBuilder replace(String source, String delim, String replacement) { if (source == null) return null; StringBuilder sb = new StringBuilder(300); StringTokenizer st = new StringTokenizer(source, delim); while (st.hasMoreTokens()) { String tok = st.nextToken(); sb.append(tok); sb.append(replacement); } return sb; } /** * truncates the supplied string to len-3 and replaces the last three positions with ... * * @param source * @param len * @return truncated string */ public static String truncate(String source, int len) { if (source == null) return null; if (source.length() > len && len > 3) return truncate(source, len - 3, "..."); else return source; } /** * This returns a substring of a len length from the input string, as opposite to the <code> truncate </code> method. This should be used for processing strings * before writing. * * @param source * @param len * @return */ public static String truncateOnly(String source, int len) { if (source == null) return null; if (source.length() > len) return source.substring(0, len); else return source; } /** * replaces all non ASCII characters in a string and also the most common special characters like by urlencode it "/" "\" ":" "*" "?" """ ' "<" ">" "|" * * @param source * @return a string which is OS independant and save for using on any filesystem */ public static String makeStringFilesystemSave(String source) { try { source = removeUndesirableSubstrings(source); return URLEncoder.encode(source, "utf-8"); } catch (UnsupportedEncodingException e) { // utf-8 should be supported } return ""; } /** * @param source * @return */ private static String removeUndesirableSubstrings(String source) { String returnString = source; // replace successive dots with only one, for now. while (returnString != null && returnString.indexOf("..") > -1) { returnString = returnString.replaceAll("\\.\\.", "."); // replace recursive 2 dots with one } return returnString; } /** * truncates a String: useful to limit in GUI * * @param source * @param len length of the returned string; if negative, return n chars from the end of the string, otherwise from the beginning of the string * @param delim * @return truncated string */ public static String truncate(String source, int len, String delim) { if (source == null) return null; int start, stop; int alen = source.length(); if (len > 0) { if (alen <= len) return source; start = 0; // TODO effizienter stop = (len > alen ? alen : len); StringBuilder sb = new StringBuilder(source.substring(start, stop)); if (alen > len) sb.append(delim); return sb.toString(); } start = (len < -alen ? 0 : alen + len); stop = alen; StringBuilder sb = new StringBuilder(source.substring(start, stop)); if (-alen <= len) sb.insert(0, delim); return sb.toString(); } /** * some old testing * * @param args */ public static void main(String[] args) { System.out.println("hello"); // log.debug(linePrepend("asdfsdf. bla and. \n2.line\n3.third",">")); // log.debug(escape("bla<>and so on &&\nsecond line").toString()); System.out.println(":" + StringEscapeUtils.escapeHtml("abcdef&<>") + ":"); System.out.println(":" + StringEscapeUtils.escapeHtml("Ā<ba>abcdef&<>") + ":"); System.out.println(":" + StringEscapeUtils.escapeHtml("Ā\n<ba>\nabcdef&<>") + ":"); System.out.println(":" + Formatter.truncate("abcdef", 0) + ":"); System.out.println(":" + Formatter.truncate("abcdef", 2) + ":"); System.out.println(":" + Formatter.truncate("abcdef", 4) + ":"); System.out.println(":" + Formatter.truncate("abcdef", 6) + ":"); System.out.println(":" + Formatter.truncate("abcdef", 7) + ":"); System.out.println(":" + Formatter.truncate("abcdef", 8) + ":"); System.out.println(":" + Formatter.truncate("abcdef", -2) + ":"); System.out.println(":" + Formatter.truncate("abcdef", -4) + ":"); System.out.println(":" + Formatter.truncate("abcdef", -6) + ":"); System.out.println(":" + Formatter.truncate("abcdef", -7) + ":"); System.out.println(":" + Formatter.truncate("abcdef", -8) + ":"); Locale loc = new Locale("de"); Formatter f2 = new Formatter(loc); Date d = new Date(); Calendar cal = Calendar.getInstance(loc); cal.setTime(d); cal.add(Calendar.HOUR_OF_DAY, 7); // so ists 16:36 nachmittags d = cal.getTime(); System.out.println(f2.formatDate(d)); System.out.println(f2.formatTime(d)); System.out.println(f2.formatDateAndTime(d)); System.out.println("Now make String filesystem save"); // String ugly = "\"/asdf/?._||\"bla"; String ugly = "guido/\\:? .|*\"\"<><guido"; System.out.println("input: " + ugly); System.out.println("output: " + Formatter.makeStringFilesystemSave(ugly)); } /** * @return locale of this formatter */ public Locale getLocale() { return locale; } /** * @param source * @return escaped string */ public static StringBuilder escWithBR(String source) { if (source == null) return null; StringBuilder sb = new StringBuilder(300); int len = source.length(); char[] cs = source.toCharArray(); for (int i = 0; i < len; i++) { char c = cs[i]; switch (c) { case '"': sb.append("""); break; case '<': sb.append("<"); break; case '>': sb.append(">"); break; case '&': // check on &# first (entities -> don't escape) if (i < len - 1 && cs[i + 1] == '#') { // we have # as next char sb.append("&"); } else { sb.append("&"); } break; // case '\r':sb.append("<br />"); break; case '\n': sb.append("<br />"); break; default: sb.append(c); } } return sb; } /** * @param source * @return stripped string */ public static StringBuilder stripTabsAndReturns(String source) { if (source == null) return null; StringBuilder sb = new StringBuilder(300); int len = source.length(); char[] cs = source.toCharArray(); for (int i = 0; i < len; i++) { char c = cs[i]; switch (c) { case '\t': sb.append(" "); break; case '\n': sb.append("<br />"); break; case '\r': sb.append("<br />"); break; case '\u2028': // unicode linebreak sb.append("<br />"); break; default: sb.append(c); } } return sb; } /** * renders wiki markup like _italic_ to XHTML see also www.radeox.org * * @Deprecated The wiki markup area is no longer supported. In the legacy form infrastructure it's still there, but it won't be available in the new flexi forms. In * flexi forms use the RichTextElement instead. tested during migration and expanded to prevent radeox failures * @param originalText * @return result (rendered originalText) or null if originalText was null */ @Deprecated public static String formatWikiMarkup(String oldValue) { if (oldValue != null) { String newValue = ""; // oldValue = oldValue.replaceAll("<>", "<>"); // oldValue = oldValue.replaceAll(Pattern.quote("[]"), // "[]"); // prevent error with {$} interpreted as regexp String marker1 = "piYie6Eigh0phafeiTuk4dahwahvoh7eedoegee2egh8xuj9phah8eop8iuk"; oldValue = oldValue.replaceAll(Pattern.quote("{$}"), marker1); // \{code} will result in an error => convert String marker2 = "RohbaeW7xahbohk8iewoo7thocaemaech2pahS8oe1UVohkohJiugaagaeco"; oldValue = oldValue.replaceAll(Pattern.quote("\\{code}"), marker2); // radeox gets an error, if {code} is not a closed tag. prevent at // least the case with one single statement. int nrOfCodeStatements = countOccurrences(oldValue, "{code}"); String marker3 = "shagheiph6enieNo0theph9aique0EihoChae6ve2edie4Pohwaok8thaoda"; if (nrOfCodeStatements == 1) { oldValue = oldValue.replaceAll(Pattern.quote("{code}"), marker3); } if (nrOfCodeStatements % 2 != 0 && nrOfCodeStatements != 1) { Formatter fInst = Formatter.getInstance(new Locale("olat")); fInst.log( "There will be a Warning/NPE from Radeox soon, as there are not enough {code} statements in a text."); fInst.log("Old value of text will be kept! " + oldValue); } // added for compatibility with wikimedia syntax used in the new wiki component. org.olat.core.gui.components.wiki.WikiMarkupComponent // filters " ''' " for bold and " ''''' " for bold/italic oldValue = oldValue.replaceAll( "(^|>|[\\p{Punct}\\p{Space}]+)'{3}(.*?)'{3}([\\p{Punct}\\p{Space}]+|<|$)", "$1*$2*$3"); oldValue = oldValue.replaceAll( "(^|>|[\\p{Punct}\\p{Space}]+)'{5}(.*?)'{5}([\\p{Punct}\\p{Space}]+|<|$)", "$1_*$2*_$3"); // try-catch not usable, as Radeox doesn't throw an exception, // it just prints warnings and returns unconverted value! newValue = engineWithContext.render(oldValue, baseRenderContext); // convert back newValue = newValue.replaceAll(marker1, Matcher.quoteReplacement("{$}")); newValue = newValue.replaceAll(marker2, Matcher.quoteReplacement("\\{code}")); newValue = newValue.replaceAll(marker3, Matcher.quoteReplacement("{code}")); return newValue; } else return null; } private static int countOccurrences(String arg1, String arg2) { int count = 0; int index = 0; while ((index = arg1.indexOf(arg2, index)) != -1) { ++index; ++count; } return count; } private void log(String msg) { logWarn(msg, null); } /** * Wrapp given html code with a wrapper an add code to transform latex formulas to nice visual characters on the client side. The latex formulas must be within an * HTML element that has the class 'math' attached. * * @param htmlFragment A html element that might contain an element that has a class 'math' with latex formulas * @return */ public static String formatLatexFormulas(String htmlFragment) { if (htmlFragment == null) return ""; // optimize, reduce jsmath calls on client if (BaseChiefController.isJsMathEnabled() && (htmlFragment.contains("class='math'") || htmlFragment.contains("class=\"math\""))) { // add math wrapper String domid = "mw_" + CodeHelper.getRAMUniqueID(); String elem = htmlFragment.contains("<div") ? "div" : "span"; StringBuffer sb = new StringBuffer(); sb.append("<").append(elem).append(" id=\"").append(domid).append("\">"); sb.append(htmlFragment); sb.append("</").append(elem).append(">"); sb.append("<script type='text/javascript'>/* <![CDATA[ */ BFormatter.formatLatexFormulas('") .append(domid).append("');/* ]]> */</script>"); return sb.toString(); } return htmlFragment; } /** * Round a double value to a double value with given number of figures after comma * * @param value * @param decimalPlace * @return rounded double value */ public static double round(double value, int decimalPlace) { BigDecimal bd = new BigDecimal(value); bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP); value = bd.doubleValue(); return value; } /** * Round a float value to a float value with given number of figures after comma * * @param value * @param decimalPlace * @return rounded float value */ public static float round(float value, int decimalPlace) { BigDecimal bd = new BigDecimal(value); bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP); value = bd.floatValue(); return value; } /** * Format a float as string with given number of figures after comma * * @param value * @param decimalPlace * @return formatted string */ public static String roundToString(float value, int decimalPlace) { BigDecimal bd = new BigDecimal(value); bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP); return bd.toString(); } }