001/* 002 * (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * troger 018 */ 019package org.nuxeo.ecm.platform.annotations.preview; 020 021import java.io.IOException; 022import java.io.InputStreamReader; 023import java.io.Reader; 024import java.util.regex.Matcher; 025import java.util.regex.Pattern; 026 027import org.apache.commons.codec.digest.DigestUtils; 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030import org.jboss.seam.international.LocaleSelector; 031import org.nuxeo.ecm.core.api.Blob; 032import org.nuxeo.ecm.core.api.Blobs; 033import org.nuxeo.ecm.platform.preview.adapter.BlobPostProcessor; 034import org.nuxeo.ecm.platform.web.common.vh.VirtualHostHelper; 035 036/** 037 * @author <a href="mailto:[email protected]">Thomas Roger</a> 038 */ 039public class AnnotationBlobPostProcessor implements BlobPostProcessor { 040 041 private static final Log log = LogFactory.getLog(AnnotationBlobPostProcessor.class); 042 043 protected static final int BUFFER_SIZE = 4096 * 16; 044 045 protected static final String GWT_LOCALE = "<meta name=\"gwt:property\" content=\"locale=%s\" />"; 046 047 protected static final String ANNOTATION_MODULE_JS = "<script type=\"text/javascript\" src='" 048 + VirtualHostHelper.getContextPathProperty() 049 + "/org.nuxeo.ecm.platform.annotations.gwt.AnnotationFrameModule/org.nuxeo.ecm.platform.annotations.gwt.AnnotationFrameModule.nocache.js'></script>"; 050 051 protected static final String INTERNET_EXPLORER_RANGE_JS = "<script type=\"text/javascript\" src='" 052 + VirtualHostHelper.getContextPathProperty() + "/scripts/InternetExplorerRange.js'></script>"; 053 054 protected Pattern headPattern = Pattern.compile("(.*)(<head>)(.*)", Pattern.CASE_INSENSITIVE | Pattern.DOTALL); 055 056 protected Pattern htmlPattern = Pattern.compile("(.*)(<html>)(.*)", Pattern.CASE_INSENSITIVE | Pattern.DOTALL); 057 058 protected Pattern charsetPattern = Pattern.compile("(.*) charset=(.*?)\"(.*)", Pattern.CASE_INSENSITIVE 059 | Pattern.DOTALL); 060 061 public Blob process(Blob blob) { 062 String mimetype = blob.getMimeType(); 063 if (mimetype == null || !mimetype.startsWith("text/")) { 064 // blob does not carry HTML payload hence there is no need to try to 065 // inject HTML metadata 066 return blob; 067 } 068 try { 069 String encoding = null; 070 if (blob.getEncoding() == null) { 071 Matcher m = charsetPattern.matcher(blob.getString()); 072 if (m.matches()) { 073 encoding = m.group(2); 074 } 075 } else { 076 encoding = blob.getEncoding(); 077 } 078 079 String blobAsString = getBlobAsString(blob, encoding); 080 String processedBlob = addAnnotationModule(blobAsString); 081 082 blob = Blobs.createBlob(processedBlob, blob.getMimeType(), encoding, blob.getFilename()); 083 blob.setDigest(DigestUtils.md5Hex(processedBlob)); 084 } catch (IOException e) { 085 log.debug("Unable to process Blob", e); 086 } 087 return blob; 088 } 089 090 protected String getBlobAsString(Blob blob, String encoding) throws IOException { 091 if (encoding == null) { 092 return blob.getString(); 093 } 094 Reader reader = new InputStreamReader(blob.getStream(), encoding); 095 return readString(reader); 096 } 097 098 protected String addAnnotationModule(String blob) { 099 LocaleSelector localeSelector = LocaleSelector.instance(); 100 StringBuilder sb = new StringBuilder(); 101 Matcher m = headPattern.matcher(blob); 102 if (m.matches()) { 103 sb.append(m.group(1)); 104 sb.append(m.group(2)); 105 if (localeSelector != null) { 106 sb.append(String.format(GWT_LOCALE, localeSelector.getLocaleString())); 107 } 108 sb.append(INTERNET_EXPLORER_RANGE_JS); 109 sb.append(ANNOTATION_MODULE_JS); 110 sb.append(m.group(3)); 111 } else { 112 m = htmlPattern.matcher(blob); 113 if (m.matches()) { 114 sb.append(m.group(1)); 115 sb.append(m.group(2)); 116 sb.append("<head>"); 117 if (localeSelector != null) { 118 sb.append(String.format(GWT_LOCALE, localeSelector.getLocaleString())); 119 } 120 sb.append(INTERNET_EXPLORER_RANGE_JS); 121 sb.append(ANNOTATION_MODULE_JS); 122 sb.append("</head>"); 123 sb.append(m.group(3)); 124 } else { 125 log.debug("Unable to inject Annotation module javascript"); 126 sb.append(blob); 127 } 128 } 129 return sb.toString(); 130 } 131 132 public static String readString(Reader reader) throws IOException { 133 StringBuilder sb = new StringBuilder(BUFFER_SIZE); 134 try { 135 char[] buffer = new char[BUFFER_SIZE]; 136 int read; 137 while ((read = reader.read(buffer, 0, BUFFER_SIZE)) != -1) { 138 sb.append(buffer, 0, read); 139 } 140 } finally { 141 if (reader != null) { 142 reader.close(); 143 } 144 } 145 return sb.toString(); 146 } 147 148}