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 }