/* * Copyright (C) 2003-2009 eXo Platform SAS. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see<http://www.gnu.org/licenses/>. */ package org.exoplatform.ks.common; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; import java.security.MessageDigest; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Properties; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.commons.lang.StringUtils; import org.exoplatform.container.ExoContainer; import org.exoplatform.container.ExoContainerContext; import org.exoplatform.container.PortalContainer; import org.exoplatform.ks.rendering.MarkupRenderingService; import org.exoplatform.ks.rendering.api.Renderer; import org.exoplatform.ks.rendering.core.SupportedSyntaxes; import org.exoplatform.services.jcr.RepositoryService; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.quartz.JobExecutionContext; import org.w3c.dom.Document; /** * @author <a href="mailto:patrice.lamarque@exoplatform.com">Patrice Lamarque</a> * @version $Revision$ */ public class Utils { private static Log log = ExoLogger.getLogger(Utils.class); public static final String COMMA = ",".intern(); public static final String SLASH = "/".intern(); public static final String EMPTY_STR = "".intern(); public static final String COLON = ":".intern(); public static final String SEMICOLON = ";".intern(); public static final String SPACE = " ".intern(); static public String generateCheckSum(byte[] b) throws Exception { try{ MessageDigest md = MessageDigest.getInstance("SHA1"); md.update(b) ; byte[] mdbytes = md.digest(); //convert the byte to hex format StringBuffer sb = new StringBuffer(EMPTY_STR); for (int i = 0; i < mdbytes.length; i++) { sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1)); } return sb.toString() ; }catch(Exception e) { log.warn("Can not generate checksum for exporting data") ; return EMPTY_STR ; } } static public File getXMLFile(ByteArrayOutputStream bos, String appName, String objectType, Date createDate, String fileName) throws Exception { byte[] byteData = bos.toByteArray() ; DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); InputStream is = new ByteArrayInputStream(byteData) ; Document document = docBuilder.parse(is) ; org.w3c.dom.Attr namespace = document.createAttribute("xmlns:exoks") ; namespace.setValue("http://www.exoplatform.com/exoks/2.0") ; document.getFirstChild().getAttributes().setNamedItem(namespace) ; org.w3c.dom.Attr attName = document.createAttribute("exoks:applicationName") ; attName.setValue(appName) ; document.getFirstChild().getAttributes().setNamedItem(attName) ; org.w3c.dom.Attr dataType = document.createAttribute("exoks:objectType") ; dataType.setValue(objectType) ; document.getFirstChild().getAttributes().setNamedItem(dataType) ; org.w3c.dom.Attr exportDate = document.createAttribute("exoks:exportDate") ; exportDate.setValue(createDate.toString()) ; document.getFirstChild().getAttributes().setNamedItem(exportDate) ; org.w3c.dom.Attr checkSum = document.createAttribute("exoks:checkSum") ; checkSum.setValue(generateCheckSum(byteData)) ; document.getFirstChild().getAttributes().setNamedItem(checkSum) ; DOMSource source = new DOMSource(document.getFirstChild()) ; File file = new File(fileName + ".xml"); file.deleteOnExit(); file.createNewFile(); StreamResult result = new StreamResult(file) ; TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(); transformer.transform(source, result) ; return file ; } public static String getImageUrl(String imagePath) throws Exception { StringBuilder url = new StringBuilder() ; ExoContainer container = ExoContainerContext.getCurrentContainer(); try { ExoContainerContext exoContext = (ExoContainerContext)container.getComponentInstanceOfType(ExoContainerContext.class); url.append(SLASH).append(exoContext.getRestContextName()); } catch (Exception e) { url.append("/portal"); log.error("Can not get portal name or rest context name, exception: ",e); } RepositoryService rService = (RepositoryService)container.getComponentInstanceOfType(RepositoryService.class) ; url.append("/jcr/").append(rService.getCurrentRepository().getConfiguration().getName()).append(imagePath).append(SLASH); return url.toString(); } public static String convertCodeHTML(String s) { if (isEmpty(s)) return EMPTY_STR; s = s.replaceAll("(<p>((\\ )*)(\\s*)?</p>)|(<p>((\\ )*)?(\\s*)</p>)", "<br/>").trim(); s = s.replaceFirst("(<br/>)*", EMPTY_STR); s = s.replaceAll("(\\w|\\$)(>?,?\\.?\\*?\\!?\\&?\\%?\\]?\\)?\\}?)(<br/><br/>)*", "$1$2"); try { s = processBBCode(s); s = s.replaceAll("(https?|ftp)://", " $0").replaceAll("(=\"|=\'|\'>|\">)( )(https?|ftp)", "$1$3") .replaceAll("[^=\"|^=\'|^\'>|^\">](https?://|ftp://)([-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])", "<a target=\"_blank\" href=\"$1$2\">$1$2</a>"); s = s.replaceAll("'", "'"); } catch (Exception e) { log.error("Failed to convert HTML" + e.getMessage()); } return s; } /** * This function will change email address in 'from' field by address of mail service which is configured as system property : <code>gatein.email.smtp.from</code> or * <code>mail.from</code>. <br> * That ensures that 'emailAddress' part of 'from' field in a message object is always the same identity with authentication of smtp configuration.<br> * It's because of 2 reasons: <li>we don't want notification message to show email address of user as sender. Instead, we use mail service of kernel.</li> <li>Almost * authenticated smtp systems do not allow to separate email address in <code>from</code> field of message from smtp authentication</b> (for now, GMX, MS exchange deny, Gmail * efforts to modify the such value)</li> * * @param from * @return null if can not find suitable sender. */ public static String makeNotificationSender(String from) { if (from == null) return null; Properties props = new Properties(System.getProperties()); String mailAddr = props.getProperty("gatein.email.smtp.from"); if (mailAddr == null || mailAddr.length() == 0) mailAddr = props.getProperty("mail.from"); if (mailAddr != null) { try { return new InternetAddress(from + "<" + mailAddr + ">").toUnicodeString(); } catch (AddressException e) { if (log.isDebugEnabled()) { log.debug("value of 'gatein.email.smtp.from' or 'mail.from' in configuration file is not in format of mail address", e); } return null; } } else { return null; } } public static String processBBCode(String s) { MarkupRenderingService markupRenderingService = (MarkupRenderingService) ExoContainerContext.getCurrentContainer() .getComponentInstanceOfType(MarkupRenderingService.class); Renderer r = markupRenderingService.getRenderer(SupportedSyntaxes.bbcode.name()); return r.render(s); } /** * Get a Component from the current container context * @param <T> type of the expected component * @param type key for the component * @return */ public static <T>T getComponent(Class<T> type) { return type.cast(ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(type)); } public static ExoContainer getExoContainer(JobExecutionContext context) { if(context == null) return null; String portalName = context.getJobDetail().getGroup(); if(portalName == null) { portalName = PortalContainer.getCurrentPortalContainerName(); } if(portalName.indexOf(COLON) > 0) portalName = portalName.substring(0, portalName.indexOf(":")); return ExoContainerContext.getContainerByName(portalName); } public static String getRSSLink(String appType, String portalName, String objectId) { return SLASH + PortalContainer.getInstance().getRestContextName() + "/ks/" + appType + "/rss/" + objectId; } public static String getUserRSSLink(String apptype, String userId) { return SLASH + PortalContainer.getInstance().getRestContextName() + "/ks/" + apptype + "/rss/user/" + userId; } /** * Check string is null or empty * @param String s * @return boolean */ public static boolean isEmpty(String s) { return (s == null || s.trim().length() <= 0) ? true : false; } /** * check string array is whether empty or not * @param array * @return false if at least one element of array is not empty, true in the opposite case. */ public static boolean isEmpty(String[] array) { if (array != null && array.length > 0) { for (String s : array) { if (s != null && s.trim().length() > 0) return false; } } return true; } /** * Encode special character, use for input search * @param String s, the string input * @return String */ public static String encodeSpecialCharInSearchTerm(String s) { /* * + When all characters in param s is special characters has in charIgnore, we must encode all characters. * + If all characters in param s is not special characters, we can ignore some special characters [!#:?=.,+;~`_] */ String charIgnore = "&#<>[]/:?\"'=.,*$%()\\+@!^*-}{;`~_"; if (!isEmpty(s)) { int i = 0; while (charIgnore.indexOf(String.valueOf(s.charAt(i))) >= 0) { ++i; if (i == s.length()) { charIgnore = EMPTY_STR; break; } } } if (!isEmpty(charIgnore)) charIgnore = "!#:?=.,+;~`_"; return encodeSpecialCharToHTMLnumber(s, charIgnore, true); } /** * Encode special character, use for input title or name of the object. * @param String s, the string input * @return String */ public static String encodeSpecialCharInTitle(String s) { /* * remove double space */ if(!isEmpty(s)) { while (s.indexOf(" ") >= 0) { s = StringUtils.replace(s, " ", SPACE).trim(); } } /* * charIgnore: Some special characters we ignore */ String charIgnore = "!#:?=.,()+;~`_"; return encodeSpecialCharToHTMLnumber(s, charIgnore, true); } /** * Encode special character, use for input content of object (only apply for input by FCKEditer). * @param String s, the string input * @return String */ public static String encodeSpecialCharInContent(String s) { /* * charIgnore: Some special characters we ignore */ String charIgnore = "&#<>[]/:?\"=.,*$%()\\+@!^*-}{;`~_"; return encodeSpecialCharToHTMLnumber(s, charIgnore, false); } /** * Encode special character to html number. Ex: '/' --> / * @param String s, the string input * @param String charIgnore, the string content ignore some special character can not encode. * @param boolean isTitle, the boolean for check convert is title or not. * @return String */ public static String encodeSpecialCharToHTMLnumber(String s, String charIgnore, boolean isTitle) { if (isEmpty(s)) { return EMPTY_STR; } int i = 0; /* * The distance code number content special character. * Ex: from ' '(32) to '0'(48): ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/' * See: http://www.ascii.cl/htmlcodes.htm */ int[] charCodes = new int[] { 48, 32, 65, 57, 97, 90, 127, 122, 39 };// '0', ' ', 'A', '9', 'a', 'Z', '~', 'z', '\'' String apos = "'", str1 = "&#", str2 = "<", str3 = ">"; StringBuilder builder = new StringBuilder(); while (i < s.length()) { char c = s.charAt(i); if (charIgnore.indexOf(String.valueOf(c)) >= 0) { builder.append(c); } else { int t = s.codePointAt(i); if (t == charCodes[8]) { builder.append(apos); } else if (t < charCodes[0] && t > charCodes[1] || t < charCodes[2] && t > charCodes[3] || t < charCodes[4] && t > charCodes[5] || t < charCodes[6] && t > charCodes[7]) { if (isTitle && (t == 60 || t == 62)) { if (t == 60) { builder.append(str2); } else if (t == 62) { builder.append(str3); } } else { builder.append(str1).append(t).append(SEMICOLON); } } else { builder.append(c); } } ++i; } return builder.toString(); } /** * Get current time GMT/Zulu or UTC,(zone time is 0+GMT) * @return Calendar */ static public Calendar getGreenwichMeanTime() { Calendar calendar = GregorianCalendar.getInstance(); calendar.setLenient(false); int gmtoffset = calendar.get(Calendar.DST_OFFSET) + calendar.get(Calendar.ZONE_OFFSET); calendar.setTimeInMillis(System.currentTimeMillis() - gmtoffset); return calendar; } }