blob: b8837ea7dd6046fd10da7fc92e86cbc03ab62db8 [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.xmlbeans.impl.tool;
import org.apache.xmlbeans.SystemProperties;
import org.apache.xmlbeans.impl.schema.SchemaTypeSystemImpl;
import java.io.*;
import java.util.List;
import java.util.Arrays;
import java.util.Comparator;
import java.util.ArrayList;
import java.util.jar.JarFile;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
public class Diff
{
public static void main(String[] args)
{
if (args.length != 2)
{
System.out.println("Usage: diff <jarname1> <jarname2> to compare two jars");
System.out.println(" or diff <dirname1> <dirname2> to compare two dirs");
return;
}
File file1 = new File(args[0]);
if (!file1.exists())
{
System.out.println("File \"" + args[0] + "\" not found.");
return;
}
File file2 = new File(args[1]);
if (!file2.exists())
{
System.out.println("File \"" + args[1] + "\" not found.");
return;
}
List result = new ArrayList();
if (file1.isDirectory())
{
if (!file2.isDirectory())
{
System.out.println("Both parameters have to be directories if the first parameter is a directory.");
return;
}
dirsAsTypeSystems(file1, file2, result);
}
else
{
if (file2.isDirectory())
{
System.out.println("Both parameters have to be jar files if the first parameter is a jar file.");
return;
}
try
{
JarFile jar1 = new JarFile(file1);
JarFile jar2 = new JarFile(file2);
jarsAsTypeSystems(jar1, jar2, result);
}
catch (IOException ioe)
{ ioe.printStackTrace(); }
}
if (result.size() < 1)
System.out.println("No differences encountered.");
else
{
System.out.println("Differences:");
for (int i = 0; i < result.size(); i++)
System.out.println(result.get(i).toString());
}
}
/**
* Diffs the contents of two jars, looking only at the schema typesystems
* saved inside those jars
*/
public static void jarsAsTypeSystems(JarFile jar1, JarFile jar2, List diffs)
{
Enumeration entries1 = jar1.entries();
Enumeration entries2 = jar2.entries();
List list1 = new ArrayList();
List list2 = new ArrayList();
for (; entries1.hasMoreElements(); )
{
ZipEntry ze = (ZipEntry) entries1.nextElement();
String name = ze.getName();
if (name.startsWith("schema" + SchemaTypeSystemImpl.METADATA_PACKAGE_GEN + "/system/s") && name.endsWith(".xsb"))
list1.add(ze);
}
for (; entries2.hasMoreElements(); )
{
ZipEntry ze = (ZipEntry) entries2.nextElement();
String name = ze.getName();
if (name.startsWith("schema" + SchemaTypeSystemImpl.METADATA_PACKAGE_GEN + "/system/s") && name.endsWith(".xsb"))
list2.add(ze);
}
ZipEntry[] files1 = (ZipEntry[]) list1.toArray(new ZipEntry[list1.size()]);
ZipEntry[] files2 = (ZipEntry[]) list2.toArray(new ZipEntry[list2.size()]);
ZipEntryNameComparator comparator = new ZipEntryNameComparator();
Arrays.sort(files1, comparator);
Arrays.sort(files2, comparator);
int i1 = 0;
int i2 = 0;
while (i1 < files1.length && i2 < files2.length)
{
String name1 = files1[i1].getName();
String name2 = files2[i2].getName();
int dif = name1.compareTo(name2);
if (dif == 0)
{
// Compare the files
zipEntriesAsXsb(files1[i1], jar1, files2[i2], jar2, diffs);
i1++; i2++; // Move to next pair
}
else if (dif < 0)
{
// dir1 contains a file that dir2 doesn't
diffs.add("Jar \"" + jar1.getName() + "\" contains an extra file: \"" +
name1 + "\"");
i1++;
}
else if (dif > 0)
{
// dir2 contains a file that dir1 doesn't
diffs.add("Jar \"" + jar2.getName() + "\" contains an extra file: \"" +
name2 + "\"");
i2++;
}
}
while (i1 < files1.length)
{
diffs.add("Jar \"" + jar1.getName() + "\" contains an extra file: \"" +
files1[i1].getName() + "\"");
i1++;
}
while (i2 < files2.length)
{
diffs.add("Jar \"" + jar2.getName() + "\" contains an extra file: \"" +
files2[i2].getName() + "\"");
i2++;
}
}
/**
* Diffs the contents of two dirs looking only at the xsb files
* contained in these two dirs
* Updated diffs with a list of differences (for the time being, strings
* describing the difference)
*/
public static void dirsAsTypeSystems(File dir1, File dir2, List diffs)
{
assert dir1.isDirectory() : "Parameters must be directories";
assert dir2.isDirectory() : "Parameters must be directories";
/**
* Navigate three directories deep to get to the type system.
* Assume the schema[METADATA_PACKAGE_LOAD]/system/* structure
*/
File temp1 = new File(dir1, "schema" + SchemaTypeSystemImpl.METADATA_PACKAGE_GEN + "/system");
File temp2 = new File(dir2, "schema" + SchemaTypeSystemImpl.METADATA_PACKAGE_GEN + "/system");
if (temp1.exists() && temp2.exists())
{
File[] files1 = temp1.listFiles();
File[] files2 = temp2.listFiles();
if (files1.length == 1 && files2.length == 1)
{
temp1 = files1[0];
temp2 = files2[0];
}
else
{
if (files1.length == 0)
temp1 = null;
if (files2.length == 0)
temp2 = null;
if (files1.length > 1)
{
diffs.add("More than one typesystem found in dir \"" +
dir1.getName() + "\"");
return;
}
if (files2.length > 1)
{
diffs.add("More than one typesystem found in dir \"" +
dir2.getName() + "\"");
return;
}
}
}
else
{
if (!temp1.exists())
temp1 = null;
if (!temp2.exists())
temp2 = null;
}
if (temp1 == null && temp2 == null)
return;
else if (temp1 == null || temp2 == null)
{
if (temp1 == null)
diffs.add("No typesystems found in dir \"" + dir1 + "\"");
if (temp2 == null)
diffs.add("No typesystems found in dir \"" + dir2 + "\"");
return;
}
else
{
dir1 = temp1;
dir2 = temp2;
}
boolean diffIndex = isDiffIndex();
XsbFilenameFilter xsbName = new XsbFilenameFilter();
File[] files1 = dir1.listFiles(xsbName);
File[] files2 = dir2.listFiles(xsbName);
FileNameComparator comparator = new FileNameComparator();
Arrays.sort(files1, comparator);
Arrays.sort(files2, comparator);
int i1 = 0;
int i2 = 0;
while (i1 < files1.length && i2 < files2.length)
{
String name1 = files1[i1].getName();
String name2 = files2[i2].getName();
int dif = name1.compareTo(name2);
if (dif == 0)
{
if (diffIndex || !files1[i1].getName().equals("index.xsb"))
filesAsXsb(files1[i1], files2[i2], diffs); // Compare the files
i1++; i2++; // Move to next pair
}
else if (dif < 0)
{
// dir1 contains a file that dir2 doesn't
diffs.add("Dir \"" + dir1.getName() + "\" contains an extra file: \"" +
name1 + "\"");
i1++;
}
else if (dif > 0)
{
// dir2 contains a file that dir1 doesn't
diffs.add("Dir \"" + dir2.getName() + "\" contains an extra file: \"" +
name2 + "\"");
i2++;
}
}
while (i1 < files1.length)
{
diffs.add("Dir \"" + dir1.getName() + "\" contains an extra file: \"" +
files1[i1].getName() + "\"");
i1++;
}
while (i2 < files2.length)
{
diffs.add("Dir \"" + dir2.getName() + "\" contains an extra file: \"" +
files2[i2].getName() + "\"");
i2++;
}
}
private static boolean isDiffIndex()
{
String prop = SystemProperties.getProperty("xmlbeans.diff.diffIndex");
if (prop == null)
return true;
if ("0".equals(prop) || "false".equalsIgnoreCase(prop))
return false;
return true;
}
/**
* Diffs the two given files assuming they are in xsb format
* Updates diffs with differences in string format
*/
public static void filesAsXsb(File file1, File file2, List diffs)
{
assert file1.exists() : "File \"" + file1.getAbsolutePath() + "\" does not exist.";
assert file2.exists() : "File \"" + file2.getAbsolutePath() + "\" does not exist.";
try
{
FileInputStream stream1 = new FileInputStream(file1);
FileInputStream stream2 = new FileInputStream(file2);
streamsAsXsb(stream1, file1.getName(), stream2, file2.getName(), diffs);
}
catch (FileNotFoundException fnfe)
{ }
catch (IOException ioe)
{ }
}
public static void zipEntriesAsXsb(ZipEntry file1, JarFile jar1,
ZipEntry file2, JarFile jar2, List diffs)
{
try
{
InputStream stream1 = jar1.getInputStream(file1);
InputStream stream2 = jar2.getInputStream(file2);
streamsAsXsb(stream1, file1.getName(), stream2, file2.getName(), diffs);
}
catch (IOException ioe)
{ }
}
public static void streamsAsXsb(InputStream stream1, String name1,
InputStream stream2, String name2, List diffs)
throws IOException
{
ByteArrayOutputStream buf1 = new ByteArrayOutputStream();
ByteArrayOutputStream buf2 = new ByteArrayOutputStream();
XsbDumper.dump(stream1, "", new PrintStream(buf1));
XsbDumper.dump(stream2, "", new PrintStream(buf2));
stream1.close();
stream2.close();
readersAsText(new StringReader(buf1.toString()), name1,
new StringReader(buf2.toString()), name2, diffs);
}
public static void readersAsText(Reader r1, String name1, Reader r2, String name2,
List diffs)
throws IOException
{
org.apache.xmlbeans.impl.util.Diff.readersAsText(r1, name1, r2, name2, diffs);
}
private static class XsbFilenameFilter implements FilenameFilter
{
public boolean accept(File dir, String name)
{
return name.endsWith(".xsb");
}
}
private static class ZipEntryNameComparator implements Comparator
{
public boolean equals(Object object)
{
return this == object;
}
public int compare(Object object1, Object object2)
{
assert (object1 instanceof ZipEntry) : "Must pass in a java.util.zip.ZipEntry as argument";
assert (object2 instanceof ZipEntry) : "Must pass in a java.util.zip.ZipEntry as argument";
String name1 = ((ZipEntry) object1).getName();
String name2 = ((ZipEntry) object2).getName();
return name1.compareTo(name2);
}
}
private static class FileNameComparator implements Comparator
{
public boolean equals(Object object)
{
return this == object;
}
public int compare(Object object1, Object object2)
{
assert (object1 instanceof File) : "Must pass in a java.io.File as argument";
assert (object2 instanceof File) : "Must pass in a java.io.File as argument";
String name1 = ((File) object1).getName();
String name2 = ((File) object2).getName();
return name1.compareTo(name2);
}
}
}