Repackage.java Source code

Java tutorial

Introduction

Here is the source code for Repackage.java

Source

/*   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;
}