001 /* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019 020 package org.apache.wiki.diff; 021 022 import java.io.BufferedReader; 023 import java.io.File; 024 import java.io.IOException; 025 import java.io.StringReader; 026 import java.util.Properties; 027 028 import org.apache.log4j.Logger; 029 import org.apache.wiki.WikiContext; 030 import org.apache.wiki.WikiEngine; 031 import org.apache.wiki.api.exceptions.NoRequiredPropertyException; 032 import org.apache.wiki.util.FileUtil; 033 import org.apache.wiki.util.TextUtil; 034 035 /** 036 * This DiffProvider allows external command line tools to be used to generate 037 * the diff. 038 */ 039 public class ExternalDiffProvider implements DiffProvider 040 { 041 private static final Logger log = Logger.getLogger(ExternalDiffProvider.class); 042 043 /** 044 * Determines the command to be used for 'diff'. This program must be able 045 * to output diffs in the unified format. For example 'diff -u %s1 %s2'. 046 */ 047 public static final String PROP_DIFFCOMMAND = "jspwiki.diffCommand"; 048 049 private String m_diffCommand = null; 050 private String m_encoding; 051 052 private static final char DIFF_ADDED_SYMBOL = '+'; 053 private static final char DIFF_REMOVED_SYMBOL = '-'; 054 055 private static final String CSS_DIFF_ADDED = "<tr><td bgcolor=\"#99FF99\" class=\"diffadd\">"; 056 private static final String CSS_DIFF_REMOVED = "<tr><td bgcolor=\"#FF9933\" class=\"diffrem\">"; 057 private static final String CSS_DIFF_UNCHANGED = "<tr><td class=\"diff\">"; 058 private static final String CSS_DIFF_CLOSE = "</td></tr>"; 059 060 //FIXME This could/should be a property for this provider, there is not guarentee that 061 //the external program generates a format suitible for the colorization code of the 062 //TraditionalDiffProvider, currently set to true for legacy compatibility. 063 //I don't think this 'feature' ever worked right, did it?... 064 private boolean m_traditionalColorization = true; 065 066 /** 067 * Creates a new ExternalDiffProvider. 068 */ 069 public ExternalDiffProvider() 070 { 071 } 072 073 /** 074 * @see org.apache.wiki.WikiProvider#getProviderInfo() 075 * {@inheritDoc} 076 */ 077 public String getProviderInfo() 078 { 079 return "ExternalDiffProvider"; 080 } 081 082 /** 083 * {@inheritDoc} 084 * @see org.apache.wiki.WikiProvider#initialize(org.apache.wiki.WikiEngine, java.util.Properties) 085 */ 086 public void initialize( WikiEngine engine, Properties properties ) 087 throws NoRequiredPropertyException, IOException 088 { 089 m_diffCommand = properties.getProperty( PROP_DIFFCOMMAND ); 090 091 if( (null == m_diffCommand) || (m_diffCommand.trim().equals( "" )) ) 092 { 093 throw new NoRequiredPropertyException( "ExternalDiffProvider missing required property", PROP_DIFFCOMMAND ); 094 } 095 096 m_encoding = engine.getContentEncoding(); 097 } 098 099 100 /** 101 * Makes the diff by calling "diff" program. 102 * {@inheritDoc} 103 */ 104 public String makeDiffHtml( WikiContext ctx, String p1, String p2 ) 105 { 106 File f1 = null; 107 File f2 = null; 108 String diff = null; 109 110 try 111 { 112 f1 = FileUtil.newTmpFile(p1, m_encoding); 113 f2 = FileUtil.newTmpFile(p2, m_encoding); 114 115 String cmd = TextUtil.replaceString(m_diffCommand, "%s1", f1.getPath()); 116 cmd = TextUtil.replaceString(cmd, "%s2", f2.getPath()); 117 118 String output = FileUtil.runSimpleCommand(cmd, f1.getParent()); 119 120 // FIXME: Should this rely on the system default encoding? 121 String rawWikiDiff = new String(output.getBytes("ISO-8859-1"), m_encoding); 122 123 String htmlWikiDiff = TextUtil.replaceEntities( rawWikiDiff ); 124 125 if (m_traditionalColorization) //FIXME, see comment near declaration... 126 diff = colorizeDiff(htmlWikiDiff); 127 else 128 diff = htmlWikiDiff; 129 130 } 131 catch (IOException e) 132 { 133 log.error("Failed to do file diff", e); 134 } 135 catch (InterruptedException e) 136 { 137 log.error("Interrupted", e); 138 } 139 finally 140 { 141 if( f1 != null ) 142 f1.delete(); 143 if( f2 != null ) 144 f2.delete(); 145 } 146 147 return diff; 148 } 149 150 151 /** 152 * Goes through output provided by a diff command and inserts HTML tags to 153 * make the result more legible. Currently colors lines starting with a + 154 * green, those starting with - reddish (hm, got to think of color blindness 155 * here...). 156 */ 157 static String colorizeDiff(String diffText) throws IOException 158 { 159 if( diffText == null ) 160 return "Invalid diff - probably something wrong with server setup."; 161 162 String line = null; 163 String start = null; 164 String stop = null; 165 166 BufferedReader in = new BufferedReader( new StringReader( diffText ) ); 167 StringBuffer out = new StringBuffer(); 168 169 out.append("<table class=\"diff\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"); 170 while( (line = in.readLine()) != null ) 171 { 172 stop = CSS_DIFF_CLOSE; 173 174 if( line.length() > 0 ) 175 { 176 switch( line.charAt( 0 ) ) 177 { 178 case DIFF_ADDED_SYMBOL: 179 start = CSS_DIFF_ADDED; 180 break; 181 case DIFF_REMOVED_SYMBOL: 182 start = CSS_DIFF_REMOVED; 183 break; 184 default: 185 start = CSS_DIFF_UNCHANGED; 186 } 187 } 188 else 189 { 190 start = CSS_DIFF_UNCHANGED; 191 } 192 193 out.append( start ); 194 out.append( line.trim() ); 195 out.append( stop + "\n" ); 196 } 197 198 out.append( "</table>\n" ); 199 return out.toString(); 200 } 201 }