Java tutorial
/* * Copyright 2013 Alex Lin. * * 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. */ package org.opoo.press.impl; import freemarker.template.TemplateModel; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.LocaleUtils; import org.apache.commons.lang.StringUtils; import org.opoo.press.Category; import org.opoo.press.Config; import org.opoo.press.Converter; import org.opoo.press.Factory; import org.opoo.press.Generator; import org.opoo.press.Observer; import org.opoo.press.Page; import org.opoo.press.Post; import org.opoo.press.Renderer; import org.opoo.press.Site; import org.opoo.press.SiteBuilder; import org.opoo.press.StaticFile; import org.opoo.press.Tag; import org.opoo.press.Theme; import org.opoo.press.ThemeCompiler; import org.opoo.press.Writable; import org.opoo.press.processor.ProcessorsProcessor; import org.opoo.press.NoFrontMatterException; import org.opoo.press.Source; import org.opoo.press.SourceEntry; import org.opoo.press.SourceEntryLoader; import org.opoo.press.SourceParser; import org.opoo.press.task.RunnableTask; import org.opoo.press.task.TaskExecutor; import org.opoo.press.util.StaleUtils; import org.opoo.util.PathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.text.SimpleDateFormat; import java.util.AbstractList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TreeMap; /** * @author Alex Lin * */ public class SiteImpl implements Site, SiteBuilder { private static final Logger log = LoggerFactory.getLogger(SiteImpl.class); private ConfigImpl config; private Map<String, Object> data; private File dest; private File templates; private File working; private File basedir; private ValidDirList sources; private ValidDirList assets; private String root; private List<Page> pages; private List<Post> posts; private List<StaticFile> staticFiles; private Map<String, Category> categories; private List<Tag> tags; private Date time; private boolean showDrafts = false; // private transient List<Generator> generators; private Renderer renderer; // private List<String> includes; // private List<String> excludes; // private RegistryImpl registry; private Locale locale; //private Highlighter highlighter; //private SlugHelper slugHelper; private String permalink; //private RelatedPostsFinder relatedPostsFinder; // private File lastBuildInfoFile; private TaskExecutor taskExecutor; private Theme theme; //private ThemeManager themeManager; //private PluginManager pluginManager; // private boolean setup = false; private ProcessorsProcessor processors; //private Provider provider; private ClassLoader classLoader; private Factory factory; //private SourceEntryLoader sourceEntryLoader; //private SourceParser sourceParser; private String dateFormatPattern; public SiteImpl(ConfigImpl siteConfig) { super(); this.config = siteConfig; this.data = new HashMap<String, Object>(/*config*/); this.basedir = config.getBasedir(); this.root = config.get("root", ""); this.permalink = config.get("permalink"); this.showDrafts = config.get("show_drafts", false); boolean debug = config.get("debug", false); if (showDrafts) { log.info("+ Show drafts option set 'ON'"); } if (debug) { for (Map.Entry<String, Object> en : config.entrySet()) { String name = en.getKey(); name = StringUtils.leftPad(name, 25); log.info(name + ": " + en.getValue()); } } //theme theme = createTheme(); //templates templates = theme.getTemplates(); log.debug("Template directory: {}", templates); //sources sources = new ValidDirList(); sources.addDir(theme.getSource()); List<String> sourcesConfig = config.get("source_dirs"); sources.addDirs(basedir, sourcesConfig); log.debug("Source directories: {}", sources); //assets assets = new ValidDirList(); assets.addDir(theme.getAssets()); List<String> assetsConfig = config.get("asset_dirs"); assets.addDirs(basedir, assetsConfig); log.debug("Assets directories: {}", assets); //target directory String destDir = config.get("dest_dir"); this.dest = PathUtils.appendBaseIfNotAbsolute(basedir, destDir); log.debug("Destination directory: {}", dest); //working directory String workingDir = config.get("work_dir"); this.working = PathUtils.appendBaseIfNotAbsolute(basedir, workingDir); log.debug("Working directory: {}", working); reset(); setup(); } private Theme createTheme() { String name = config.get("theme", "default"); File themes = new File(config.getBasedir(), "themes"); File themeDir = PathUtils.appendBaseIfNotAbsolute(themes, name); if (!themeDir.exists() || !themeDir.isDirectory()) { throw new IllegalArgumentException( "Theme directory not exists or not valid, please install theme first: " + themeDir); } // PathUtils.checkDir(themeDir, PathUtils.Strategy.THROW_EXCEPTION_IF_NOT_EXISTS); compileTheme(themeDir); return new ThemeImpl(themeDir, this); } private void compileTheme(File themeDir) { ThemeCompiler themeCompiler = config.get("theme.compiler"); if (themeCompiler != null) { log.debug("Compile theme by '{}'", themeCompiler.getClass().getName()); themeCompiler.compile(themeDir); } else { log.debug("no theme compiler found."); } } public void build() { build(false); } public void build(boolean force) { if (force) { log.info("force build."); buildInternal(); return; } if (StaleUtils.isStale(this, false)) { buildInternal(); return; } // only asset file(s) changed. List<File> staleAssets = StaleUtils.getStaleAssets(this); if (staleAssets != null) { for (File staleAsset : staleAssets) { //copy asset directory to destination directory log.info("Copying stale asset: {}...", staleAsset); try { FileUtils.copyDirectory(staleAsset, dest, buildFilter()); StaleUtils.saveLastBuildInfo(this); return; } catch (IOException e) { throw new RuntimeException("Copy stale asset exception: " + staleAsset, e); } } } log.info("Nothing to build - all site output files are up to date."); } @Override public void clean() throws Exception { log.info("Cleaning destination directory " + dest); FileUtils.deleteDirectory(dest); log.info("Cleaning working directory " + working); FileUtils.deleteDirectory(working); } private void buildInternal() { // if(!setup){ // setup = true; // setup(); // } reset(); read(); generate(); render(); cleanup(); write(); StaleUtils.saveLastBuildInfo(this); } void reset() { this.time = config.get("time", new Date()); this.pages = new ArrayList<Page>(); this.posts = new ArrayList<Post>(); //Call #add() in multi-threading this.staticFiles = Collections.synchronizedList(new ArrayList<StaticFile>()); // resetCategories(); // resetTags(); } void resetCategories() { this.categories = new LinkedHashMap<String, Category>(); Map<String, String> names = config.get("category_names"); if (names == null || names.isEmpty()) { return; } //sort name names = new TreeMap<String, String>(names); for (Map.Entry<String, String> en : names.entrySet()) { String path = en.getKey(); String name = en.getValue(); String nicename = path; String parentPath = null; int index = path.lastIndexOf('.'); if (index != -1) { nicename = path.substring(index + 1); parentPath = path.substring(0, index); } Category parent = null; if (parentPath != null) { parent = categories.get(parentPath); if (parent == null) { throw new IllegalArgumentException("Parent category not found: " + parentPath); } } CategoryImpl category = new CategoryImpl(nicename, name, parent, this); categories.put(path, category); } } void resetTags() { this.tags = new ArrayList<Tag>(); Map<String, String> names = config.get("tag_names"); if (names == null || names.isEmpty()) { return; } for (Map.Entry<String, String> en : names.entrySet()) { tags.add(new TagImpl(en.getKey(), en.getValue(), this)); } } void setup() { //ensure source not in destination for (File source : sources) { source = PathUtils.canonical(source); if (dest.equals(source) || source.getAbsolutePath().startsWith(dest.getAbsolutePath())) { throw new IllegalArgumentException( "Destination directory cannot be or contain the Source directory."); } } //locale String localeString = config.get("locale"); if (localeString != null) { locale = LocaleUtils.toLocale(localeString); log.debug("Set locale: " + locale); } //date_format dateFormatPattern = config.get("date_format"); if (dateFormatPattern == null) { dateFormatPattern = "yyyy-MM-dd"; } else if ("ordinal".equals(dateFormatPattern)) { dateFormatPattern = "MMM d yyyy"; } //object instances classLoader = createClassLoader(config, theme); taskExecutor = new TaskExecutor(config); factory = FactoryImpl.createInstance(this); processors = new ProcessorsProcessor(factory.getPluginManager().getProcessors()); //Construct RendererImpl after initializing all plugins renderer = factory.createRenderer(this); } private ClassLoader createClassLoader(Config config, Theme theme) { log.debug("Create site ClassLoader."); ClassLoader parent = SiteImpl.class.getClassLoader(); if (parent == null) { parent = ClassLoader.getSystemClassLoader(); } String sitePluginDir = config.get("plugin_dir"); String themePluginDir = (String) theme.get("plugin_dir"); List<File> classPathEntries = new ArrayList<File>(2); if (StringUtils.isNotBlank(sitePluginDir)) { File sitePlugins = PathUtils.canonical(new File(config.getBasedir(), sitePluginDir)); addClassPathEntries(classPathEntries, sitePlugins); } if (StringUtils.isNotBlank(themePluginDir)) { File themePlugins = PathUtils.canonical(new File(theme.getPath(), themePluginDir)); addClassPathEntries(classPathEntries, themePlugins); } //theme classes File themeClasses = new File(theme.getPath(), "target/classes"); File themeSrc = new File(theme.getPath(), "src"); if (themeSrc.exists() && themeClasses.exists() && themeClasses.isDirectory()) { classPathEntries.add(themeClasses); } //theme target/plugins File themeTargetPlugins = new File(theme.getPath(), "target/plugins"); if (themeTargetPlugins.exists() && themeTargetPlugins.list().length > 0) { addClassPathEntries(classPathEntries, themeTargetPlugins); } if (classPathEntries.isEmpty()) { log.info("No custom classpath entries."); return parent; } URL[] urls = new URL[classPathEntries.size()]; try { for (int i = 0; i < classPathEntries.size(); i++) { urls[i] = classPathEntries.get(i).toURI().toURL(); } } catch (MalformedURLException e) { throw new RuntimeException(e); } return new URLClassLoader(urls, parent); } private void addClassPathEntries(List<File> classPathEntries, File dir) { if (dir.exists()) { File[] files = dir.listFiles(new ValidPluginClassPathEntryFileFilter()); if (files != null && files.length > 0) { classPathEntries.addAll(Arrays.asList(files)); } } } // @Deprecated // public <T> T instantiate(Class<T> clazz){ // return instantiate(clazz, null); // } // @Deprecated // public <T> T instantiate(Class<T> clazz, String hint){ // String className = provider.getClassName(clazz.getName(), hint); // if(StringUtils.isBlank(className) || "none".equalsIgnoreCase(className)){ // return null; // } // return instantiate(className); // } // @Deprecated // public <T> T instantiate(String className){ // T t = ClassUtils.newInstance(className, classLoader, this, config); // log.debug("New '{}' instance: {}", className, t); // return t; // } void read() { //read categories and tags from configuration resetCategories(); resetTags(); Runnable t1 = new Runnable() { public void run() { readSources(); } }; Runnable t2 = new Runnable() { public void run() { readStaticFiles(); } }; taskExecutor.run(t1, t2); postRead(); } private void readSources() { log.info("Reading sources ..."); final SourceEntryLoader sourceEntryLoader = factory.getSourceEntryLoader(); final SourceParser sourceParser = factory.getSourceParser(); //load sources and load static files FileFilter fileFilter = buildFilter(); List<SourceEntry> list = new ArrayList<SourceEntry>(); for (File src : sources) { List<SourceEntry> tempList = sourceEntryLoader.loadSourceEntries(src, fileFilter); if (tempList != null && !tempList.isEmpty()) { list.addAll(tempList); } } for (SourceEntry en : list) { read(en, sourceParser); } Collections.sort(posts); Collections.reverse(posts); setPostNextOrPrevious(posts); // sort(categories); // sort(tags); } /** * @param posts */ private void setPostNextOrPrevious(List<Post> posts) { /* for(int i = 0 ; i < posts.size() ; i++){ Post post = posts.get(i); if(i > 0){ post.setNext(posts.get(i - 1)); } if(i < posts.size() - 1){ post.setPrevious(posts.get(i + 1)); } }*/ Iterator<Post> it = posts.iterator(); Post prev = null; Post curr = null; while (it.hasNext()) { curr = it.next(); if (prev != null) { prev.setPrevious(curr); curr.setNext(prev); } prev = curr; } } private void readStaticFiles() { log.info("Reading assets ..."); final SourceEntryLoader sourceEntryLoader = factory.getSourceEntryLoader(); FileFilter fileFilter = buildFilter(); for (File assetDir : assets) { List<SourceEntry> tempList = sourceEntryLoader.loadSourceEntries(assetDir, fileFilter); for (SourceEntry se : tempList) { log.debug("read static file {}", se.getFile()); staticFiles.add(new StaticFileImpl(this, se)); } } } /** * */ private void postRead() { processors.postRead(this); } private void read(SourceEntry en, SourceParser parser) { try { Source src = parser.parse(en); log.debug("read source {}", src.getSourceEntry().getFile()); Map<String, Object> map = src.getMeta(); String layout = (String) map.get("layout"); if ("post".equals(layout)) { readPost(src); } else { pages.add(factory.createPage(this, src)); } } catch (NoFrontMatterException e) { this.staticFiles.add(new StaticFileImpl(this, en)); } } private void readPost(Source src) { if (isDraft(src.getMeta())) { if (showDrafts) { posts.add(factory.createDraft(this, src)); } } else { posts.add(factory.createPost(this, src)); } } private boolean isDraft(Map<String, Object> meta) { if (!meta.containsKey("published")) { return false; } Boolean b = (Boolean) meta.get("published"); return !b.booleanValue(); } FileFilter buildFilter() { final List<String> includes = config.get("includes"); final List<String> excludes = config.get("excludes"); return new FileFilter() { @Override public boolean accept(File file) { String name = file.getName(); if (includes != null && includes.contains(name)) { return true; } if (excludes != null && excludes.contains(name)) { return false; } char firstChar = name.charAt(0); if (firstChar == '.' || firstChar == '_' || firstChar == '#') { return false; } char lastChar = name.charAt(name.length() - 1); if (lastChar == '~') { return false; } if (file.isHidden()) { return false; } return true; } }; } void generate() { for (Generator g : factory.getPluginManager().getGenerators()) { g.generate(this); } postGenerate(); } /** * */ private void postGenerate() { processors.postGenerate(this); } void render() { final Map<String, Object> rootMap = buildRootMap(); renderer.prepare(); // for(Post post: posts){ // post.convert(); // postConvertPost(post); // // post.render(rootMap); // postRenderPost(post); // } log.info("Rendering {} posts...", posts.size()); taskExecutor.run(posts, new RunnableTask<Post>() { public void run(Post post) { post.convert(); postConvertPost(post); // post.render(rootMap); postRenderPost(post); } }); postRenderPosts(); // for(Page page: pages){ // page.convert(); // postConvertPage(page); // // page.render(rootMap); // postRenderPage(page); // } log.info("Rendering {} pages...", pages.size()); taskExecutor.run(pages, new RunnableTask<Page>() { public void run(Page page) { page.convert(); postConvertPage(page); page.render(rootMap); postRenderPage(page); } }); postRenderPages(); } /** * @param post */ private void postConvertPost(Post post) { processors.postConvertPost(this, post); } /** * @param page */ private void postConvertPage(Page page) { processors.postConvertPage(this, page); } /** * @param post */ private void postRenderPost(Post post) { processors.postRenderPost(this, post); } /** * */ private void postRenderPosts() { processors.postRenderAllPosts(this); } /** * @param page */ private void postRenderPage(Page page) { processors.postRenderPage(this, page); } /** * */ private void postRenderPages() { processors.postRenderAllPages(this); } Map<String, Object> buildRootMap() { Map<String, Object> map = new HashMap<String, Object>(); map.put("site", this); map.put("root_url", getRoot()); map.put("basedir", getRoot()); map.put("opoopress", config.get("opoopress")); // Map<String, TemplateModel> models = factory.getTemplateModels(); // if(models != null && !models.isEmpty()){ // map.putAll(models); // } map.put("theme", theme); return map; } /** * */ void cleanup() { log.info("cleanup..."); final List<File> destFiles = getAllDestFiles(dest); List<File> files = new ArrayList<File>(); // for(Post post: posts){ // files.add(post.getOutputFile(dest)); // } // for(Page page: pages){ // files.add(page.getOutputFile(dest)); // } for (StaticFile staticFile : staticFiles) { files.add(staticFile.getOutputFile(dest)); } log.debug("Files in target: {}", destFiles.size()); log.debug("Assets file in src: {}", files.size()); //find obsolete files for (File file : files) { destFiles.remove(file); } // destFiles.removeAll(files); log.debug("Files in target will be deleted: {}", destFiles.size()); //delete obsolete files if (!destFiles.isEmpty()) { // for(File destFile: destFiles){ // //FileUtils.deleteQuietly(destFile); // if(IS_DEBUG_ENABLED){ // log.debug("Delete file " + destFile); // } // } taskExecutor.run(destFiles, new RunnableTask<File>() { public void run(File file) { FileUtils.deleteQuietly(file); log.debug("File deleted: {}", file); } }); } //call post cleanup postCleanup(); } /** * @param dest * @return */ private List<File> getAllDestFiles(File dest) { List<File> files = new ArrayList<File>(); if (dest != null && dest.exists()) { listDestFiles(files, dest); } return files; } private void listDestFiles(List<File> files, File dir) { File[] list = dir.listFiles(); for (File f : list) { if (f.isFile()) { files.add(f); } else if (f.isDirectory()) { listDestFiles(files, f); } } } /** * */ private void postCleanup() { processors.postCleanup(this); } void write() { log.info("Writing {} posts, {} pages, and {} static files ...", posts.size(), pages.size(), staticFiles.size()); if (!dest.exists()) { dest.mkdirs(); } // log.info("Writing " + posts.size() + " posts"); // for(Post post: posts){ // post.write(dest); // } // // log.info("Writing " + pages.size() + " pages"); // for(Page page: pages){ // page.write(dest); // } // // if(!staticFiles.isEmpty()){ // log.info("Copying " + staticFiles.size() + " static files"); // for(StaticFile sf: staticFiles){ // sf.write(dest); // } // } List<Writable> list = new ArrayList<Writable>(); list.addAll(posts); list.addAll(pages); if (!staticFiles.isEmpty()) { list.addAll(staticFiles); } taskExecutor.run(list, new RunnableTask<Writable>() { public void run(Writable o) { o.write(dest); } }); // if(assets != null){ // try { // log.info("Copying 1 assets directory"); // log.debug("Copying assets..."); // FileUtils.copyDirectory(assets, dest, buildFilter()); // // log.debug("All asset files copied."); // } catch (IOException e) { // log.error("Copy assets error", e); // } // } postWrite(); } /** * */ private void postWrite() { processors.postWrite(this); } /** * @return the pages */ public List<Page> getPages() { return pages; } /** * @return the posts */ public List<Post> getPosts() { return posts; } /* (non-Javadoc) * @see org.opoo.press.Site#getConfig() */ @Override public Config getConfig() { return config; } @Override public List<File> getSources() { return sources; } /* (non-Javadoc) * @see org.opoo.press.Site#getDestination() */ @Override public File getDestination() { return dest; } public List<StaticFile> getStaticFiles() { return staticFiles; } /* (non-Javadoc) * @see org.opoo.press.Site#getTime() */ @Override public Date getTime() { return time; } public Object get(String name) { if (data.containsKey(name)) { return data.get(name); } if (config.containsKey(name)) { return config.get(name); } if (theme != null) { return theme.get(name); } return null; } public void set(String name, Object value) { data.put(name, value); //MapUtils.put(data, name, value); } /* (non-Javadoc) * @see org.opoo.press.Site#getRenderer() */ @Override public Renderer getRenderer() { return renderer; } @Override public File getTemplates() { return templates; } @Override public List<File> getAssets() { return assets; } @Override public File getWorking() { return working; } @Override public Converter getConverter(Source source) { return factory.getPluginManager().getConverter(source); } /* (non-Javadoc) * @see org.opoo.press.Site#getRoot() */ @Override public String getRoot() { return root; } /* (non-Javadoc) * @see org.opoo.press.Site#getLocale() */ @Override public Locale getLocale() { return locale; } /* (non-Javadoc) * @see org.opoo.press.Site#getCategories() */ @Override public List<Category> getCategories() { return new CategoriesList(categories); } /* (non-Javadoc) * @see org.opoo.press.Site#getTags() */ @Override public List<Tag> getTags() { return tags; } /* (non-Javadoc) * @see org.opoo.press.SiteHelper#buildCanonical(java.lang.String) */ @Override public String buildCanonical(String url) { /* String canonical = (String) config.get("url"); String permalink = (String) config.get("permalink"); String pageUrl = url; if(permalink != null && permalink.endsWith(".html")){ canonical += pageUrl; }else{ canonical += StringUtils.removeEnd(pageUrl, "index.html"); } return canonical; */ return url; } /* (non-Javadoc) * @see org.opoo.press.SiteHelper#toSlug(java.lang.String) */ @Override public String toSlug(String tagName) { return factory.getSlugHelper().toSlug(tagName); } /* (non-Javadoc) * @see org.opoo.press.SiteHelper#toNicename(java.lang.String) */ @Override public String toNicename(String categoryName) { return factory.getSlugHelper().toSlug(categoryName); } /* (non-Javadoc) * @see org.opoo.press.SiteHelper#getCategory(java.lang.String) */ @Override public Category getCategory(String categoryNameOrNicename) { if (categories == null || categories.isEmpty()) { return null; } //If path equals if (categories.containsKey(categoryNameOrNicename)) { return categories.get(categoryNameOrNicename); } for (Category category : new ArrayList<Category>(categories.values())) { if (category.isNameOrNicename(categoryNameOrNicename)) { return category; } } return null; } /* (non-Javadoc) * @see org.opoo.press.SiteHelper#getTag(java.lang.String) */ @Override public Tag getTag(String tagNameOrSlug) { if (tags == null || tags.isEmpty()) { return null; } for (Tag tag : new ArrayList<Tag>(tags)) { if (tag.isNameOrSlug(tagNameOrSlug)) { return tag; } } return null; } private static class CategoriesList extends AbstractList<Category> { private final List<Category> list = new ArrayList<Category>(); private final Map<String, Category> categories; private CategoriesList(Map<String, Category> categories) { this.categories = categories; //this.list = new ArrayList<Category>(categories.values()); for (Category category : categories.values()) { if (!category.getPosts().isEmpty()) { list.add(category); } } } @Override public boolean add(Category category) { categories.put(category.getPath(), category); return list.add(category); } /* (non-Javadoc) * @see java.util.AbstractList#get(int) */ @Override public Category get(int index) { return list.get(index); } /* (non-Javadoc) * @see java.util.AbstractCollection#size() */ @Override public int size() { return list.size(); } } /* (non-Javadoc) * @see org.opoo.press.Site#getPermalink() */ @Override public String getPermalink() { return permalink; } /** * @return the site */ @Override public File getBasedir() { return basedir; } @Override public ClassLoader getClassLoader() { return classLoader; } @Override public Factory getFactory() { return factory; } @Override public Observer getObserver() { return new SiteObserver(this); } /** * @return the showDrafts */ public boolean showDrafts() { return showDrafts; } /* (non-Javadoc) * @see org.opoo.press.Site#getTheme() */ @Override public Theme getTheme() { return theme; } ProcessorsProcessor getProcessors() { return processors; } @Override public String formatDate(Date date) { if (date != null) { if (locale != null) { return new SimpleDateFormat(dateFormatPattern, locale).format(date); } else { return new SimpleDateFormat(dateFormatPattern).format(date); } } return null; } static class ValidDirList extends ArrayList<File> { private static final long serialVersionUID = 6306507738477638252L; public ValidDirList addDir(File dir) { if (PathUtils.isValidDirectory(dir)) { add(dir); } return this; } public ValidDirList addDir(File base, String path) { return addDir(new File(base, path)); } public ValidDirList addDirs(File base, List<String> paths) { for (String path : paths) { addDir(base, path); } return this; } } static class ValidPluginClassPathEntryFileFilter implements FileFilter { /* (non-Javadoc) * @see java.io.FileFilter#accept(java.io.File) */ @Override public boolean accept(File file) { String name = file.getName(); char firstChar = name.charAt(0); if (firstChar == '.' || firstChar == '_' || firstChar == '#') { return false; } char lastChar = name.charAt(name.length() - 1); if (lastChar == '~') { return false; } if (file.isHidden()) { return false; } if (file.isDirectory()) { return true; } if (file.isFile()) { name = name.toLowerCase(); if (name.endsWith(".jar") || name.endsWith(".zip")) { return true; } } return false; } } }