PageRenderTime 57ms CodeModel.GetById 10ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/razpub/src/com/razie/pub/base/files/SSFilesRazie.java

http://razpub.googlecode.com/
Java | 456 lines | 412 code | 14 blank | 30 comment | 4 complexity | d12b973d1d0a52a5533233358f56669e MD5 | raw file
  1/**
  2 * Razvan's public code. Copyright 2008 based on Apache license (share alike) see LICENSE.txt for
  3 * details.
  4 */
  5package com.razie.pub.base.files;
  6
  7import java.io.File;
  8import java.io.FileFilter;
  9import java.util.ArrayList;
 10import java.util.List;
 11import java.util.regex.Pattern;
 12
 13import javax.xml.parsers.SAXParser;
 14import javax.xml.parsers.SAXParserFactory;
 15
 16import org.xml.sax.Attributes;
 17import org.xml.sax.SAXException;
 18import org.xml.sax.helpers.DefaultHandler;
 19
 20import com.razie.pub.FileUtils;
 21import com.razie.pub.base.log.Log;
 22import com.razie.pubstage.data.JStrucList;
 23import com.razie.pubstage.data.JStrucTree;
 24import com.razie.pubstage.data.JStructure;
 25import com.razie.pubstage.data.TreeImplNode;
 26import com.razie.pubstage.life.BeingDyingRtException;
 27import com.razie.pubstage.life.Worker;
 28
 29/**
 30 * utility helper for working with files - especially finding files
 31 * 
 32 * @author $Author: razvanc $
 33 */
 34public class SSFilesRazie {
 35
 36    public static interface FileFoundCback {
 37        void fileFound(File file);
 38    }
 39
 40    /**
 41     * @param start the path to look in
 42     * @param filter - a filter, see Reg* classes defined here
 43     * @param recurse if true will search recursively through directories
 44     * @return a list of xml file names in the given path with the given mask, having the root tag
 45     *         and root attribute matching an expression. It may be empty but not null
 46     */
 47    public static JStrucList<File> listFiles(String start, FileFilter filter, boolean recurse,
 48            FileFoundCback... cback) {
 49        JStrucList<File> l = new JStrucList.Impl<File>(null);
 50
 51        ifindFiles(start, l, filter, recurse, cback);
 52
 53        return l;
 54    }
 55
 56    /**
 57     * @param start the path to look in
 58     * @param filter - a filter, see Reg* classes defined here
 59     * @param recurse if true will search recursively through directories
 60     * @return a list of xml file names in the given path with the given mask, having the root tag
 61     *         and root attribute matching an expression. It may be empty but not null
 62     */
 63    public static JStrucTree<File> treeFiles(String start, FileFilter filter, boolean recurse,
 64            FileFoundCback... cback) {
 65        JStrucTree<File> l = new JStrucTree.ImplNode<File>(null);
 66
 67        ifindFiles(start, l, filter, recurse, cback);
 68
 69        return l;
 70    }
 71
 72    /**
 73     * @param start the path to look in
 74     * @param filter - a filter, see Reg* classes defined here
 75     * @param recurse if true will search recursively through directories
 76     * @return a list of xml file names in the given path with the given mask, having the root tag
 77     *         and root attribute matching an expression. It may be empty but not null
 78     */
 79    public static void ifindFiles(String start, JStructure<File> l, FileFilter filter, boolean recurse,
 80            FileFoundCback... cback) {
 81        if (start == null)
 82            return;
 83
 84        String dir = start;
 85        if (!dir.endsWith("/") && !dir.endsWith("\\")) {
 86            dir += "/";
 87        }
 88
 89        File f = new File(dir);
 90
 91        if (f.isDirectory() && l instanceof JStrucTree)
 92            ((JStrucTree.ImplNode<File>) l).setContents(f);
 93
 94        findFiles(f, l, filter, recurse, 2, 100, cback);
 95
 96        Log.logThis(l.toString());
 97    }
 98
 99    private static JStructure<File> add(JStructure<File> l, File f, boolean isDirectory) {
100        if (l instanceof JStrucTree) {
101            if (isDirectory)
102                return ((JStrucTree.ImplNode<File>) l).addNode(f);
103            else
104                ((JStrucTree.ImplNode<File>) l).addLeaf(f);
105        } else if (!isDirectory) {
106            JStrucList.Impl<File> tree = (JStrucList.Impl<File>) l;
107            tree.add(f);
108            return tree;
109        } else return l;
110        return null;
111    }
112
113    /**
114     * TODO SECURITY add a filter for the directory name
115     * 
116     * @param dir the directory to start the search in
117     * @param files will add files to this list
118     * @param filter the filter for files
119     * @param recurse if true will search recursively
120     */
121    public static void findFiles(File dir, JStructure<File> files, FileFilter filter, boolean recurse,
122            int min, int max, FileFoundCback... cback) {
123
124        if (Worker.dying()) {
125            throw new BeingDyingRtException();
126        }
127
128        try {
129            File[] s = filter != null ? dir.listFiles(filter) : dir.listFiles();
130            if (s != null) {
131                for (int i = 0; s != null && i < s.length; i++) {
132                    add(files, s[i], false);
133                    if (cback.length > 0) {
134                        cback[0].fileFound(s[i]);
135                    }
136                }
137            }
138
139            // TODO optimize this so we only find directories
140            if (recurse) {
141                File[] dirs = dir.listFiles();
142                if (dirs == null) {
143                    return;
144                }
145
146                int noDirs = 0;
147                for (int i = 0; i < dirs.length; i++) {
148                    if (dirs[i].isDirectory()) {
149                        noDirs++;
150                    }
151                }
152
153                if (noDirs > 0) {
154                    int curDirNo = 0;
155
156                    for (int i = 0; i < dirs.length; i++) {
157                        if (dirs[i].isDirectory()) {
158                            findFiles(dirs[i], add(files, dirs[i], true), filter, recurse, min
159                                    + (int) ((max - min) * (curDirNo * 1.0 / noDirs)), min
160                                    + (int) ((max - min) * ((curDirNo + 1) * 1.0 / noDirs)), cback);
161                            curDirNo++;
162                            Worker.updateProgress(min + (int) ((max - min) * (curDirNo * 1.0 / noDirs)),
163                                    dirs[i].getName());
164                        }
165                    }
166                }
167            }
168        } catch (SecurityException ex) {
169            // do nothing here
170        }
171    }
172
173    /**
174     * return nice string with filesize
175     * 
176     * @param size a file size in bytes
177     * @return a nice string in K/M/G
178     */
179    public static String niceFileSize(long size) {
180        float f = size;
181        if (size > G) {
182            return String.valueOf(formatFloat(f / G, 3)) + " Gb";
183        } else if (size > M) {
184            return String.valueOf(formatFloat(f / M, 3)) + " Mb";
185        } else if (size > K) {
186            return String.valueOf(formatFloat(f / K, 3)) + " Kb";
187        } else {
188            return String.valueOf(size) + " bytes";
189        }
190    }
191
192    /**
193     * format a float as string with the given no of digits
194     * 
195     * @param f the float to format
196     * @param nbDigits no of digits after .
197     * @return nice float string
198     */
199    private static String formatFloat(float f, int nbDigits) {
200        String s = "" + f;
201        int idx = s.indexOf('.');
202        if ((idx >= 0) && (idx + nbDigits + 1 < s.length()))
203            s = s.substring(0, idx + nbDigits + 1);
204        return s;
205    }
206
207    public static String getRootAttrFromFile(File file, String rootAttrNm) {
208        RootElementChecker handler = new RootElementChecker();
209        try {
210            SAXParserFactory parserFactory = SAXParserFactory.newInstance();
211            parserFactory.setValidating(false);
212            SAXParser parser = parserFactory.newSAXParser();
213            parser.parse(file, handler);
214        } catch (FirstElementFoundException e) {
215            // do nothing
216        } catch (Exception e) {
217            return null;
218        }
219        String attrVal = rootAttrNm == null ? null : handler.elementAttributes.getValue(rootAttrNm);
220        return attrVal;
221    }
222
223    /** SAX handler to stop parsing at the first element and get its attributes */
224    private static class RootElementChecker extends DefaultHandler {
225        String     elementName;
226        Attributes elementAttributes;
227
228        public RootElementChecker() {
229        }
230
231        public void startElement(String uri, String localName, String qName, Attributes attributes)
232                throws SAXException {
233            elementAttributes = attributes;
234            elementName = qName;
235            throw new FirstElementFoundException("First Element found");
236        }
237    }
238
239    /** specific exception thrown when first element found */
240    static class FirstElementFoundException extends SAXException {
241        public FirstElementFoundException(String message) {
242            super(message);
243        }
244    }
245
246    /**
247     * a regexp based file filter, will filter files based on their name, if it matches the given
248     * regular expression
249     */
250    public static class ORFileFilter implements FileFilter, Cloneable {
251        protected List<FileFilter> filters = new ArrayList<FileFilter>();
252
253        public ORFileFilter() {
254        }
255
256        public ORFileFilter(ORFileFilter f) {
257            this.filters.addAll(f.filters);
258        }
259
260        public boolean accept(File pathname) {
261            for (FileFilter ff : filters) {
262                if (ff.accept(pathname)) {
263                    return true;
264                }
265            }
266            return false;
267        }
268
269        public void add(FileFilter f) {
270            this.filters.add(f);
271        }
272
273        public Object clone() {
274            return new ORFileFilter(this);
275        }
276
277        public String toString() {
278            return "SmpFiles.OrFileFilter " + Log.tryToString("", this.filters);
279        }
280    }
281
282    public static class ANDFileFilter extends ORFileFilter {
283
284        public ANDFileFilter() {
285        }
286
287        public ANDFileFilter(ANDFileFilter f) {
288            super(f);
289        }
290
291        public boolean accept(File pathname) {
292            for (FileFilter ff : filters) {
293                if (!ff.accept(pathname)) {
294                    return false;
295                }
296            }
297            return true;
298        }
299
300        public Object clone() {
301            return new ANDFileFilter(this);
302        }
303
304        public String toString() {
305            return "SmpFiles.ANDFileFilter " + Log.tryToString("", this.filters);
306        }
307    }
308
309    public static class NOTFileFilter implements FileFilter {
310        FileFilter filter;
311
312        public NOTFileFilter() {
313        }
314
315        public NOTFileFilter(NOTFileFilter f) {
316            this.filter = f.filter;
317        }
318
319        public boolean accept(File pathname) {
320            if (filter.accept(pathname)) {
321                return false;
322            }
323            return true;
324        }
325
326        public void setFilter(FileFilter f) {
327            filter = f;
328        }
329
330        public Object clone() {
331            return new NOTFileFilter(this);
332        }
333
334        public String toString() {
335            return "SmpFiles.NOTFileFilter " + Log.tryToString("", this.filter);
336        }
337    }
338
339    /**
340     * a regexp based file filter, will filter files based on their name, if it matches the given
341     * regular expression
342     */
343    public static class RegExpFileFilter implements FileFilter {
344        protected String  regExp;
345        protected Pattern pattern;
346
347        public RegExpFileFilter(String regExp) {
348            this.regExp = regExp;
349            pattern = Pattern.compile(regExp);
350        }
351
352        public boolean accept(File pathname) {
353            boolean b = pathname.isFile() && pattern.matcher(pathname.getName()).matches();
354            if (b && SSFilesRazie.logger.isTraceLevel(3)) {
355                // SmpFilesRazie.logger.trace(3, "RegExpFileFilter accepted file: " +
356                // pathname.getName());
357            } else if ((!b) && SSFilesRazie.logger.isTraceLevel(3)) {
358                // SmpFilesRazie.logger.trace(3, "RegExpFileFilter REJECTED file: " +
359                // pathname.getName());
360            }
361
362            return b;
363        }
364
365        public Object clone() {
366            return new RegExpFileFilter(regExp);
367        }
368
369        public String toString() {
370            return "SmpFiles.RegExpFileFilter(regExp=" + this.regExp + ")";
371        }
372    }
373
374    /**
375     * a regexp based XML file filter, will filter files based on their name, if it matches the
376     * given regular expression and if it contains a specific root tag and/or root attribute
377     * name/value
378     */
379    public static class RegExpXmlFileFilter extends RegExpFileFilter implements FileFilter {
380        private String    rootTag, rootAttrNm, rootAttrRegExp;
381
382        /**
383         * c-tor
384         * 
385         * @param regexp regexp for filename. cannot be null
386         * @param rootTag root tag name - can be null (no check for root tag but will check for root
387         *        attr)
388         * @param rootAttrNm root attr name - can be null (no check for root attr)
389         * @param rootAttrRegExp regexp for root attr value - can be null (no check for root attr)
390         */
391        public RegExpXmlFileFilter(String regexp, String rootTag, String rootAttrNm, String rootAttrRegExp) {
392            super(regexp);
393            this.rootTag = rootTag;
394            this.rootAttrNm = rootAttrNm;
395            this.rootAttrRegExp = rootAttrRegExp;
396        }
397
398        public String toString() {
399            return "SmpFiles.RegExpXmlFileFilter(regExp=" + this.regExp + ", rootTag=" + this.rootTag
400                    + ", rootAttrNm=" + rootAttrNm + ", rootAttrRegExp=" + this.rootAttrRegExp + ")";
401        }
402
403        public boolean accept(File pathname) {
404            boolean b = pathname.isFile() && pattern.matcher(pathname.getName()).matches()
405                    && checkRoot(pathname);
406            if (b && SSFilesRazie.logger.isTraceLevel(1)) {
407                SSFilesRazie.logger.trace(1, "RegExpXmlFileFilter accepted file: " + pathname.getName());
408            } else if ((!b) && SSFilesRazie.logger.isTraceLevel(3)) {
409                SSFilesRazie.logger.trace(3, "RegExpXmlFileFilter REJECTED file: " + pathname.getName());
410            }
411
412            return b;
413        }
414
415        public boolean checkRoot(File file) {
416            RootElementChecker handler = new RootElementChecker();
417            try {
418                SAXParserFactory parserFactory = SAXParserFactory.newInstance();
419                parserFactory.setValidating(false);
420                SAXParser parser = parserFactory.newSAXParser();
421                parser.parse(file, handler);
422            } catch (FirstElementFoundException e) {
423                // do nothing
424            } catch (Exception e) {
425                return false;
426            }
427            String attrVal = rootAttrNm == null ? null : handler.elementAttributes.getValue(rootAttrNm);
428            // TODO i don't handle rootAttrNm==null && rootAttrRegExp!=null, i.e. there is at least
429            // an attribute matching the exp
430            return (rootTag == null || rootTag.equals(handler.elementName))
431                    && (rootAttrRegExp == null || ((attrVal != null) && attrVal.matches(rootAttrRegExp)));
432        }
433
434        public Object clone() {
435            return new RegExpXmlFileFilter(regExp, rootTag, rootAttrNm, rootAttrRegExp);
436        }
437
438    }
439
440    public static void main(String args[]) throws Exception {
441        RegExpXmlFileFilter filter = new RegExpXmlFileFilter("", "script", "test", "vall.*");
442        System.out.println(filter.checkRoot(new File("c:/work/gigi.xml")));
443        String fn = "file:/c:/gugu\\./vasile/..\\ionel.xml";
444        System.out.println("canonical (" + fn + ") = " + FileUtils.toCanonicalPath(fn));
445        fn = "file:/c:/gugu\\./vasile\\ionel.xml";
446        System.out.println("canonical (" + fn + ") = " + FileUtils.toCanonicalPath(fn));
447    }
448
449    /** formatting file sizes */
450    private static float    K      = 1024;
451    private static float    M      = K * 1024;
452    private static float    G      = M * 1024;
453
454    public static final Log logger = Log.factory.create("", SSFilesRazie.class.getName());
455
456}