Java tutorial
/* 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. */ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Repackage { public static void main(String[] args) throws Exception { new Repackage(args).repackage(); } private Repackage(String[] args) { String sourceDir = null; String targetDir = null; String repackageSpec = null; boolean failure = false; for (int i = 0; i < args.length; i++) { if (args[i].equals("-repackage") && i + 1 < args.length) repackageSpec = args[++i]; else if (args[i].equals("-f") && i + 1 < args.length) sourceDir = args[++i]; else if (args[i].equals("-t") && i + 1 < args.length) targetDir = args[++i]; else failure = true; } if (failure || repackageSpec == null || (sourceDir == null ^ targetDir == null)) throw new RuntimeException("Usage: repackage -repackage [spec] [ -f [sourcedir] -t [targetdir] ]"); _repackager = new Repackager(repackageSpec); if (sourceDir == null || targetDir == null) return; _sourceBase = new File(sourceDir); _targetBase = new File(targetDir); } public void repackage() throws Exception { if (_sourceBase == null || _targetBase == null) { // read from system.in, // write on system.out System.out.println(_repackager.repackage(readInputStream(System.in)).toString()); return; } _fromPackages = _repackager.getFromPackages(); _toPackages = _repackager.getToPackages(); _packagePattern = Pattern.compile("^\\s*package\\s+((?:\\w|\\.)*)\\s*;", Pattern.MULTILINE); _moveAlongFiles = new ArrayList(); _movedDirs = new HashMap(); // System.out.println( "Deleting repackage dir ..." ); // recursiveDelete( _targetBase ); _targetBase.mkdirs(); ArrayList files = new ArrayList(); fillFiles(files, _sourceBase); System.out.println("Repackaging " + files.size() + " files ..."); int prefixLength = _sourceBase.getCanonicalPath().length(); for (int i = 0; i < files.size(); i++) { File from = (File) files.get(i); String name = from.getCanonicalPath().substring(prefixLength + 1); repackageFile(name); } finishMovingFiles(); if (_skippedFiles > 0) System.out.println("Skipped " + _skippedFiles + " unmodified files."); } private boolean fileIsUnchanged(String name) { File sourceFile = new File(_sourceBase, name); File targetFile = new File(_targetBase, name); return (sourceFile.lastModified() < targetFile.lastModified()); } public void repackageFile(String name) throws IOException { if (name.endsWith(".java")) repackageJavaFile(name); else if (name.endsWith(".xsdconfig") || name.endsWith(".xml") || name.endsWith(".g")) repackageNonJavaFile(name); else if (name.startsWith("bin" + File.separatorChar)) repackageNonJavaFile(name); else moveAlongWithJavaFiles(name); } public void moveAlongWithJavaFiles(String name) { _moveAlongFiles.add(name); } public void finishMovingFiles() throws IOException { for (Iterator i = _moveAlongFiles.iterator(); i.hasNext();) { String name = (String) i.next(); String toName = name; String srcDir = Repackager.dirForPath(name); String toDir = (String) _movedDirs.get(srcDir); if (toDir != null) toName = new File(toDir, new File(name).getName()).toString(); if (name.endsWith(".html")) repackageNonJavaFile(name, toName); else justMoveNonJavaFile(name, toName); } } public void repackageNonJavaFile(String name) throws IOException { File sourceFile = new File(_sourceBase, name); File targetFile = new File(_targetBase, name); if (sourceFile.lastModified() < targetFile.lastModified()) _skippedFiles += 1; else writeFile(targetFile, _repackager.repackage(readFile(sourceFile))); } public void repackageNonJavaFile(String sourceName, String targetName) throws IOException { File sourceFile = new File(_sourceBase, sourceName); File targetFile = new File(_targetBase, targetName); if (sourceFile.lastModified() < targetFile.lastModified()) _skippedFiles += 1; else writeFile(targetFile, _repackager.repackage(readFile(sourceFile))); } public void justMoveNonJavaFile(String sourceName, String targetName) throws IOException { File sourceFile = new File(_sourceBase, sourceName); File targetFile = new File(_targetBase, targetName); if (sourceFile.lastModified() < targetFile.lastModified()) _skippedFiles += 1; else copyFile(sourceFile, targetFile); } public void repackageJavaFile(String name) throws IOException { File sourceFile = new File(_sourceBase, name); StringBuffer sb = readFile(sourceFile); Matcher packageMatcher = _packagePattern.matcher(sb); if (packageMatcher.find()) { String pkg = packageMatcher.group(1); int pkgStart = packageMatcher.start(1); int pkgEnd = packageMatcher.end(1); if (packageMatcher.find()) throw new RuntimeException("Two package specifications found: " + name); List filePath = Repackager.splitPath(name, File.separatorChar); String srcDir = Repackager.dirForPath(name); // Sort the repackage spec so that longer from's are first to match // longest package first for (;;) { boolean swapped = false; for (int i = 1; i < filePath.size(); i++) { String spec1 = (String) filePath.get(i - 1); String spec2 = (String) filePath.get(i); if (spec1.indexOf(':') < spec2.indexOf(':')) { filePath.set(i - 1, spec2); filePath.set(i, spec1); swapped = true; } } if (!swapped) break; } List pkgPath = Repackager.splitPath(pkg, '.'); int f = filePath.size() - 2; if (f < 0 || (filePath.size() - 1) < pkgPath.size()) throw new RuntimeException("Package spec differs from file path: " + name); for (int i = pkgPath.size() - 1; i >= 0; i--) { if (!pkgPath.get(i).equals(filePath.get(f))) throw new RuntimeException("Package spec differs from file path: " + name); f--; } List changeTo = null; List changeFrom = null; from: for (int i = 0; i < _fromPackages.size(); i++) { List from = (List) _fromPackages.get(i); if (from.size() <= pkgPath.size()) { for (int j = 0; j < from.size(); j++) if (!from.get(j).equals(pkgPath.get(j))) continue from; changeFrom = from; changeTo = (List) _toPackages.get(i); break; } } if (changeTo != null) { String newPkg = ""; String newName = ""; for (int i = 0; i < changeTo.size(); i++) { if (i > 0) { newPkg += "."; newName += File.separatorChar; } newPkg += changeTo.get(i); newName += changeTo.get(i); } for (int i = filePath.size() - pkgPath.size() - 2; i >= 0; i--) newName = (String) filePath.get(i) + File.separatorChar + newName; for (int i = changeFrom.size(); i < pkgPath.size(); i++) { newName += File.separatorChar + (String) pkgPath.get(i); newPkg += '.' + (String) pkgPath.get(i); } newName += File.separatorChar + (String) filePath.get(filePath.size() - 1); sb.replace(pkgStart, pkgEnd, newPkg); name = newName; String newDir = Repackager.dirForPath(name); if (!srcDir.equals(newDir)) { _movedDirs.put(srcDir, newDir); } } } File targetFile = new File(_targetBase, name); // new name if (sourceFile.lastModified() < targetFile.lastModified()) { _skippedFiles += 1; return; } writeFile(new File(_targetBase, name), _repackager.repackage(sb)); } void writeFile(File f, StringBuffer chars) throws IOException { f.getParentFile().mkdirs(); OutputStream out = new FileOutputStream(f); Writer w = new OutputStreamWriter(out); Reader r = new StringReader(chars.toString()); copy(r, w); r.close(); w.close(); out.close(); } StringBuffer readFile(File f) throws IOException { InputStream in = new FileInputStream(f); Reader r = new InputStreamReader(in); StringWriter w = new StringWriter(); copy(r, w); w.close(); r.close(); in.close(); return w.getBuffer(); } StringBuffer readInputStream(InputStream is) throws IOException { Reader r = new InputStreamReader(is); StringWriter w = new StringWriter(); copy(r, w); w.close(); r.close(); return w.getBuffer(); } public static void copyFile(File from, File to) throws IOException { to.getParentFile().mkdirs(); FileInputStream in = new FileInputStream(from); FileOutputStream out = new FileOutputStream(to); copy(in, out); out.close(); in.close(); } public static void copy(InputStream in, OutputStream out) throws IOException { byte[] buffer = new byte[1024 * 16]; for (;;) { int n = in.read(buffer, 0, buffer.length); if (n < 0) break; out.write(buffer, 0, n); } } public static void copy(Reader r, Writer w) throws IOException { char[] buffer = new char[1024 * 16]; for (;;) { int n = r.read(buffer, 0, buffer.length); if (n < 0) break; w.write(buffer, 0, n); } } public void fillFiles(ArrayList files, File file) throws IOException { if (!file.isDirectory()) { files.add(file); return; } // Exclude the build directory if (file.getName().equals("build")) return; // Exclude CVS directories if (file.getName().equals("CVS")) return; String[] entries = file.list(); for (int i = 0; i < entries.length; i++) fillFiles(files, new File(file, entries[i])); } public void recursiveDelete(File file) throws IOException { if (!file.exists()) return; if (file.isDirectory()) { String[] entries = file.list(); for (int i = 0; i < entries.length; i++) recursiveDelete(new File(file, entries[i])); } file.delete(); } private File _sourceBase; private File _targetBase; private List _fromPackages; private List _toPackages; private Pattern _packagePattern; private Repackager _repackager; private Map _movedDirs; private List _moveAlongFiles; private int _skippedFiles; } /* * 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. */ class Repackager { public Repackager(String repackageSpecs) { _fromPackages = new ArrayList(); _toPackages = new ArrayList(); List repackages = splitPath(repackageSpecs, ';'); // Sort the repackage spec so that longer from's are first to match // longest package first for (;;) { boolean swapped = false; for (int i = 1; i < repackages.size(); i++) { String spec1 = (String) repackages.get(i - 1); String spec2 = (String) repackages.get(i); if (spec1.indexOf(':') < spec2.indexOf(':')) { repackages.set(i - 1, spec2); repackages.set(i, spec1); swapped = true; } } if (!swapped) break; } for (int i = 0; i < repackages.size(); i++) { String spec = (String) repackages.get(i); int j = spec.indexOf(':'); if (j < 0 || spec.indexOf(':', j + 1) >= 0) throw new RuntimeException("Illegal repackage specification: " + spec); String from = spec.substring(0, j); String to = spec.substring(j + 1); _fromPackages.add(Repackager.splitPath(from, '.')); _toPackages.add(Repackager.splitPath(to, '.')); } _fromMatchers = new Matcher[_fromPackages.size() * 2]; _toPackageNames = new String[_fromPackages.size() * 2]; addPatterns('.', 0); addPatterns('/', _fromPackages.size()); } void addPatterns(char sep, int off) { for (int i = 0; i < _fromPackages.size(); i++) { List from = (List) _fromPackages.get(i); List to = (List) _toPackages.get(i); String pattern = ""; for (int j = 0; j < from.size(); j++) { if (j > 0) pattern += "\\" + sep; pattern += from.get(j); } String toPackage = ""; for (int j = 0; j < to.size(); j++) { if (j > 0) toPackage += sep; toPackage += to.get(j); } _fromMatchers[off + i] = Pattern.compile(pattern).matcher(""); _toPackageNames[off + i] = toPackage; } } public StringBuffer repackage(StringBuffer sb) { StringBuffer result = null; for (int i = 0; i < _fromMatchers.length; i++) { Matcher m = (Matcher) _fromMatchers[i]; m.reset(sb); for (boolean found = m.find(); found; found = m.find()) { if (result == null) result = new StringBuffer(); m.appendReplacement(result, _toPackageNames[i]); } if (result != null) { m.appendTail(result); sb = result; result = null; } } return sb; } public List getFromPackages() { return _fromPackages; } public List getToPackages() { return _toPackages; } public static ArrayList splitPath(String path, char separator) { ArrayList components = new ArrayList(); for (;;) { int i = path.indexOf(separator); if (i < 0) break; components.add(path.substring(0, i)); path = path.substring(i + 1); } if (path.length() > 0) components.add(path); return components; } public static String dirForPath(String path) { return new File(path).getParent(); } private List _fromPackages; private List _toPackages; private Matcher[] _fromMatchers; private String[] _toPackageNames; }