| /* |
| * Copyright 2000-2010 JetBrains s.r.o. |
| * |
| * 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. |
| */ |
| |
| /* |
| * XSD/DTD Model generator tool |
| * |
| * By Gregory Shrago |
| * 2002 - 2006 |
| */ |
| package org.jetbrains.idea.devkit.dom.generator; |
| |
| import com.intellij.util.ArrayUtil; |
| |
| import java.io.*; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.TreeSet; |
| |
| /** |
| * @author Gregory.Shrago |
| * @author Konstantin Bulenkov |
| */ |
| public class MergingFileManager implements FileManager { |
| |
| public File getOutputFile(File target) { |
| File outFile = target; |
| if (!outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs()) { |
| Util.logerr("parent mkdirs failed: " + outFile); |
| return null; |
| } |
| for (int i = 0; outFile.exists(); i++) { |
| outFile = new File(target.getParentFile(), target.getName() + ".tmp." + i); |
| } |
| return outFile; |
| } |
| |
| public File releaseOutputFile(File outFile) { |
| int idx = outFile.getName().indexOf(".tmp."); |
| File target = outFile; |
| if (idx > -1) { |
| target = new File(outFile.getParentFile(), outFile.getName().substring(0, idx)); |
| String[] curLines = loadFile(outFile); |
| String[] prevLines = loadFile(target); |
| String[] mergedLines = mergeLines(curLines, prevLines); |
| if (mergedLines != prevLines) { |
| if (mergedLines == curLines) { |
| if (target.exists() && !target.delete()) { |
| Util.logerr("file replace failed: " + target); |
| outFile.delete(); |
| } else { |
| outFile.renameTo(target); |
| Util.logwarn("file replaced: " + target); |
| } |
| } else { |
| outFile.delete(); |
| if (target.exists() && !target.delete()) { |
| Util.logerr("file replace failed: " + target); |
| } else { |
| writeFile(target, mergedLines); |
| Util.logwarn("file merged: " + target); |
| } |
| } |
| } else { |
| outFile.delete(); |
| } |
| } |
| return target; |
| } |
| |
| private static String[] mergeLines(String[] curLines, String[] prevLines) { |
| if (prevLines.length == 0) return curLines; |
| ArrayList<String> merged = new ArrayList<String>(); |
| int curIdx = 0, prevIdx = 0; |
| String cur, prev; |
| boolean classScope = false; |
| boolean importMerged = false; |
| for (int i = 0; i < Math.max(curLines.length, prevLines.length); i++) { |
| cur = curIdx < curLines.length ? curLines[curIdx] : ""; |
| prev = prevIdx < prevLines.length ? prevLines[prevIdx] : ""; |
| if (classScope) { |
| merged.addAll(Arrays.asList(curLines).subList(curIdx, curLines.length)); |
| break; |
| } else if (prev.trim().startsWith("import ") || cur.trim().startsWith("import ")) { |
| if (importMerged) continue; |
| importMerged = true; |
| int[] indices = new int[]{curIdx, prevIdx}; |
| mergeImports(merged, curLines, prevLines, indices); |
| curIdx = indices[0]; |
| prevIdx = indices[1]; |
| } else if (cur.equals(prev)) { |
| if (cur.trim().startsWith("public interface ") |
| || cur.trim().startsWith("public enum ")) classScope = true; |
| merged.add(cur); |
| curIdx++; |
| prevIdx++; |
| } else if (prev.trim().startsWith("@")) { |
| merged.add(prev); |
| prevIdx++; |
| } else if (cur.trim().startsWith("@")) { |
| merged.add(cur); |
| curIdx++; |
| } else if (cur.trim().startsWith("package ") && prev.trim().startsWith("package ")) { |
| merged.add(prev); |
| curIdx++; |
| prevIdx++; |
| } else if (cur.trim().startsWith("public interface ") && prev.trim().startsWith("public interface ")) { |
| classScope = true; |
| prevIdx = addAllStringsUpTo(merged, prevLines, prevIdx, "{"); |
| curIdx = addAllStringsUpTo(null, curLines, curIdx, "{"); |
| } else if (cur.trim().startsWith("* ")) { |
| curIdx = addAllStringsUpTo(merged, curLines, curIdx, "*/"); |
| if (prev.trim().startsWith("* ") || prev.trim().endsWith("*/")) { |
| prevIdx = addAllStringsUpTo(null, prevLines, prevIdx, "*/"); |
| } |
| } else { |
| merged.add(cur); |
| curIdx++; |
| prevIdx++; |
| } |
| } |
| String[] mergedLines = ArrayUtil.toStringArray(merged); |
| if (compareLines(mergedLines, prevLines, 2) == 0) { |
| return prevLines; |
| } else if (compareLines(mergedLines, curLines, 2) == 0) { |
| return curLines; |
| } else { |
| return mergedLines; |
| } |
| } |
| |
| private static void mergeImports(ArrayList<String> merged, String[] curLines, String[] prevLines, int[] indices) { |
| TreeSet<String> externalClasses = new TreeSet<String>(); |
| for (int i = 0; i < curLines.length; i++) { |
| String line = curLines[i].trim(); |
| if (line.startsWith("import ") && line.endsWith(";")) { |
| indices[0] = i + 1; |
| final String name = line.substring("import ".length(), line.length() - 1).trim(); |
| if (name.endsWith("*")) continue; |
| externalClasses.add(name); |
| } |
| } |
| for (int i = 0; i < prevLines.length; i++) { |
| String line = prevLines[i].trim(); |
| if (line.startsWith("import ") && line.endsWith(";")) { |
| indices[1] = i + 1; |
| final String name = line.substring("import ".length(), line.length() - 1).trim(); |
| if (name.endsWith("*")) continue; |
| externalClasses.add(name); |
| } |
| } |
| boolean javaLang = false; |
| for (String s : externalClasses) { |
| if (s.startsWith("java.")) { |
| javaLang = true; |
| continue; |
| } |
| merged.add("import " + s + ";"); |
| } |
| if (javaLang) { |
| merged.add(""); |
| for (String s : externalClasses) { |
| if (!s.startsWith("java.")) continue; |
| merged.add("import " + s + ";"); |
| } |
| } |
| } |
| |
| private static int addAllStringsUpTo(ArrayList<String> merged, String[] lines, int startIdx, String upTo) { |
| String str; |
| do { |
| str = startIdx < lines.length ? lines[startIdx] : upTo; |
| if (merged != null) merged.add(str); |
| startIdx++; |
| } while (!str.trim().endsWith(upTo) && startIdx < lines.length); |
| return startIdx; |
| } |
| |
| private static int compareLines(String[] mergedLines, String[] curLines, int start) { |
| if (mergedLines.length < curLines.length) return -1; |
| if (mergedLines.length > curLines.length) return 1; |
| for (int i = start; i < mergedLines.length; i++) { |
| final int comp = mergedLines[i].compareTo(curLines[i]); |
| if (comp != 0) return comp; |
| } |
| return 0; |
| } |
| |
| |
| private static void writeFile(File target, String[] mergedLines) { |
| PrintWriter out = null; |
| try { |
| int lineCount = mergedLines.length; |
| while (lineCount > 0 && mergedLines[lineCount - 1].length() == 0) lineCount--; |
| out = new PrintWriter(new FileWriter(target)); |
| for (int i = 0; i < lineCount; i++) { |
| String mergedLine = mergedLines[i]; |
| out.println(mergedLine); |
| } |
| } catch (Exception ex) { |
| ex.printStackTrace(); |
| } finally { |
| if (out != null) { |
| try { |
| out.close(); |
| } catch (Exception e) { |
| } |
| } |
| } |
| } |
| |
| |
| private static String[] loadFile(File f1) { |
| if (!f1.exists()) return ArrayUtil.EMPTY_STRING_ARRAY; |
| ArrayList<String> list = new ArrayList<String>(); |
| BufferedReader in = null; |
| try { |
| in = new BufferedReader(new FileReader(f1)); |
| String str; |
| while ((str = in.readLine()) != null) { |
| list.add(str); |
| } |
| } catch (Exception ex) { |
| ex.printStackTrace(); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| return ArrayUtil.toStringArray(list); |
| } |
| |
| } |