/**
* Licensed to the Austrian Association for Software Tool Integration (AASTI)
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. The AASTI licenses this file to you 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.openengsb.loom.csharp.comon.wsdltodll.csfilehandling;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.maven.plugin.logging.Log;
// Note: Under Linux, WSDL and WSDL2 converts a WSDL not to an interface. It creates an abstract class that
// is not compatible with the .Net Bridge (RealProxy only accepts interface or Classes that implement
// MarshalByRefObject). It follows that the abstract classes have to be replaced by interfaces.
// To be compatible with wsdl.exe (windows) the interface names are converted to I+"NAME"+SoapBinding
public class FileComparer {
private static final String ABSTRACT_CLASS_SIGNITURE = "abstract partial class";
private static final String CSHARP_CLASS_NAME = "class";
private File csFile1;
private File csFile2;
private Boolean windows;
private Log logging;
public FileComparer(Log logger) {
this.logging = logger;
}
public FileComparer(File csFile1, File csFile2, Log logging,
Boolean windows) {
this.csFile1 = csFile1;
this.csFile2 = csFile2;
this.windows = windows;
this.logging = logging;
}
/**
* Removes similar classes in the first cs File
*
* @throws IOException
*/
public void removeSimilarClassesFromFile1() throws IOException {
logging.info("Start reding cs File");
List<String> linescs1 = getFileLinesAsList(csFile1);
logging.info("Start reding cs File");
List<String> linescs2 = getFileLinesAsList(csFile2);
logging.info("Search classes");
List<String> classNames1 = searchClasses(linescs1);
logging.info("Found " + classNames1.size() + " classes");
logging.info("Search classes");
List<String> classNames2 = searchClasses(linescs2);
logging.info("Found " + classNames2.size() + " classes");
logging.info("Removing similarities from the file");
for (String name : findSimilarClassNames(classNames1, classNames2)) {
linescs1 = removeLinesContainingClassname(linescs1, name);
}
logging.info("Remove Attributes, which stands alone");
linescs1 = removeAttributesNotBoundToClass(linescs1);
if (!windows) {
logging.info("Replace abstract classes with interfaces");
linescs1 = replaceAbstractClasses(linescs1);
linescs2 = replaceAbstractClasses(linescs2);
logging.info("Save files");
}
replaceFilesWithNewContent(linescs1, csFile1);
replaceFilesWithNewContent(linescs2, csFile2);
}
/**
* Searches for abstract classes and replace it by an interface.
*
* @param lines
* @return
*/
public List<String> replaceAbstractClasses(List<String> lines) {
List<String> result = new LinkedList<String>();
for (int i = 0; i < lines.size(); i++) {
result.add(removeAbstract(lines.get(i)));
}
return result;
}
private String removeAbstract(String line) {
String tmpLine = line;
if (isAbstractClassLine(tmpLine)) {
logging.info("Found abstract class. Convert it to a interface");
tmpLine = tmpLine.replace(ABSTRACT_CLASS_SIGNITURE + " ", "interface I");
if (tmpLine.contains(":")) {
tmpLine = tmpLine.substring(0, tmpLine.indexOf(":")) + "{";
}
tmpLine = tmpLine.replace(" {", "SoapBinding {");
} else {
if (tmpLine.contains("abstract")) {
logging.info("Found abstract method. Convert it");
tmpLine = tmpLine.replace("abstract", "");
tmpLine = tmpLine.replace("public", "");
tmpLine = tmpLine.replace("private", "");
tmpLine = tmpLine.replace("protected", "");
}
}
return tmpLine;
}
private boolean isAbstractClassLine(String line) {
return line.contains(ABSTRACT_CLASS_SIGNITURE);
}
public void replaceFilesWithNewContent(List<String> lines, File file) throws IOException {
BufferedWriter out = new BufferedWriter(new FileWriter(file));
for (int i = 0; i < lines.size(); i++) {
out.write(lines.get(i));
out.newLine();
}
out.close();
}
public List<String> removeLinesContainingClassname(List<String> lines, String className) {
List<String> result = new LinkedList<String>();
boolean ignoreLine = false;
int openingBracket = 0;
for (int i = 0; i < lines.size(); i++) {
if (containsLineClassname(lines.get(i), className) && isCSharpClass(lines.get(i))) {
ignoreLine = true;
}
if (!ignoreLine) {
result.add(lines.get(i));
} else {
if (lines.get(i).contains("{")) {
openingBracket++;
}
if (lines.get(i).contains("}")) {
openingBracket--;
}
if (openingBracket <= 0) {
result.add("");
ignoreLine = false;
openingBracket = 0;
}
}
}
return result;
}
private boolean containsLineClassname(String line, String classname) {
String classline = line;
if (line.contains(":")) {
classline = line.substring(0, line.indexOf(":"));
}
String patternString = "\\b(" + classname + ")\\b";
Pattern pattern = Pattern.compile(patternString);
return pattern.matcher(classline).find();
}
public List<String> removeAttributesNotBoundToClass(List<String> lines) {
List<String> linesWithoutUnboundAttributes = new LinkedList<String>();
List<Integer> tmpLineIndexToDelete = new LinkedList<Integer>();
List<Integer> linesToDelete = new LinkedList<Integer>();
boolean addAttributesToDelete = false;
for (int i = 0; i < lines.size(); i++) {
linesWithoutUnboundAttributes.add(lines.get(i));
if (lines.get(i).contains("[")) {
addAttributesToDelete = true;
}
if (addAttributesToDelete) {
tmpLineIndexToDelete.add(i);
if (lines.get(i).contains("{")
|| (lines.get(i) != "" && !lines.get(i).contains("["))) {
addAttributesToDelete = false;
tmpLineIndexToDelete = new LinkedList<Integer>();
continue;
} else {
if (lines.get(i) == "") {
linesToDelete.addAll(tmpLineIndexToDelete);
addAttributesToDelete = false;
tmpLineIndexToDelete = new LinkedList<Integer>();
}
}
}
}
return removeLines(linesWithoutUnboundAttributes, linesToDelete);
}
private List<String> removeLines(List<String> input,
List<Integer> removeLinesAsInteger) {
Collections.sort(removeLinesAsInteger, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return -(o1 - o2);
}
});
List<String> result = new LinkedList<String>(input);
for (int line : removeLinesAsInteger) {
result.remove(line);
}
return result;
}
private List<String> findSimilarClassNames(List<String> classnames1,
List<String> classnames2) {
List<String> result = new LinkedList<String>();
for (String name : classnames2) {
if (classnames1.contains(name)) {
result.add(name);
}
}
return result;
}
/**
* Finds all the classes in a File (lines=read File line by line)
*
* @param lines
* @return
*/
private List<String> searchClasses(List<String> lines) {
List<String> result = new LinkedList<String>();
for (String line : lines) {
if (isCSharpClass(line)) {
result.add(getClassName(line));
}
}
return result;
}
/**
* Returns the Class name of a line
*
* @param line
* @return
*/
private String getClassName(String line) {
String result = line.substring(line.indexOf(CSHARP_CLASS_NAME)
+ CSHARP_CLASS_NAME.length());
if (result.contains("{")) {
result = result.substring(0, result.indexOf("{"));
}
if (result.contains(":")) {
result = result.substring(0, result.indexOf(":"));
}
return result.replaceAll("\\s", "");
}
/**
* Checks if the line is a C# class
*
* @param line
* @return
*/
private boolean isCSharpClass(String line) {
return line.contains("class") && line.contains("{");
}
/**
* Reads a file and returns the content as List
*
* @param f
* @return
* @throws IOException
*/
public List<String> getFileLinesAsList(File f) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(
new DataInputStream(new FileInputStream(f))));
List<String> result = new LinkedList<String>();
String strLine;
while ((strLine = br.readLine()) != null) {
result.add(strLine);
}
br.close();
return result;
}
/**
* Removes all the similar parts from all the files
*
* @param filepathes
* @throws IOException
*/
public static void removeSimilaritiesAndSaveFiles(List<String> filepathes,
Log logging, Boolean isWindows) throws IOException {
List<File> files = new LinkedList<File>();
for (String path : filepathes) {
files.add(new File(path));
}
FileComparer fcomparer;
for (int i = 0; i < files.size(); i++) {
for (int y = i + 1; y < files.size(); y++) {
fcomparer = new FileComparer(files.get(i), files.get(y),
logging, isWindows);
fcomparer.removeSimilarClassesFromFile1();
}
}
}
}