Coverage Report - org.webslinger.ext.support.DirectoryLister
 
Classes in this File Line Coverage Branch Coverage Complexity
DirectoryLister
63%
81/128
67%
22/33
0
DirectoryLister$1
100%
10/10
100%
1/1
0
DirectoryLister$FileSorter
88%
7/8
50%
1/2
0
DirectoryLister$OutputConfig
100%
8/8
N/A
0
DirectoryLister$StandardThemingOutputConfig
100%
8/8
N/A
0
 
 1  
 package org.webslinger.ext.support;
 2  
 
 3  
 import java.io.IOException;
 4  
 import java.sql.Timestamp;
 5  
 import java.text.DateFormat;
 6  
 import java.util.ArrayList;
 7  
 import java.util.Comparator;
 8  
 import java.util.HashMap;
 9  
 import java.util.Iterator;
 10  
 import java.util.LinkedHashMap;
 11  
 import java.util.List;
 12  
 import java.util.Map;
 13  
 import java.util.TreeSet;
 14  
 import java.util.Set;
 15  
 import java.util.StringTokenizer;
 16  
 import javax.servlet.ServletException;
 17  
 import javax.servlet.http.HttpServletRequest;
 18  
 import javax.servlet.http.HttpServletResponse;
 19  
 
 20  
 import org.apache.commons.collections.Transformer;
 21  
 import org.apache.commons.collections.map.AbstractReferenceMap;
 22  
 import org.apache.commons.collections.map.LazyMap;
 23  
 import org.apache.commons.collections.map.ReferenceMap;
 24  
 import org.apache.commons.fileupload.FileItem;
 25  
 import org.apache.commons.vfs.FileContent;
 26  
 import org.apache.commons.vfs.FileName;
 27  
 import org.apache.commons.vfs.FileObject;
 28  
 
 29  
 import org.webslinger.PathContext;
 30  
 import org.webslinger.ThemingFactory;
 31  
 import org.webslinger.TypeHandler;
 32  
 import org.webslinger.Webslinger;
 33  
 import org.webslinger.WebslingerServletContext;
 34  
 import org.webslinger.collections.KeyedMapEntryComparator;
 35  
 import org.webslinger.commons.vfs.CachingLister;
 36  
 import org.webslinger.commons.vfs.ReloadingCachingLister;
 37  
 import org.webslinger.container.FileInfo;
 38  
 import org.webslinger.ext.types.thumb;
 39  
 import org.webslinger.servlet.MultipartFormUtil;
 40  
 import org.webslinger.util.TTLObject;
 41  
 
 42  3
 public class DirectoryLister extends TTLObject<Map<Comparator, Map<String, Map<String, Object>>>> {
 43  
     static {
 44  1
         TTLObject.setDefaultTTLForClass(DirectoryLister.class, 1000);
 45  
     }
 46  
 
 47  15
     protected static class FileSorter extends KeyedMapEntryComparator {
 48  
         protected FileSorter(String name, boolean descending) {
 49  1
             super(name, descending);
 50  1
         }
 51  
 
 52  
         public int compare(Map left, Map right) {
 53  15
             Integer leftSeq = (Integer) left.get("sequence");
 54  15
             Integer rightSeq = (Integer) right.get("sequence");
 55  15
             int r = leftSeq.intValue() - rightSeq.intValue();
 56  15
             if (r == 0) return super.compare(left, right);
 57  0
             return direction ? -r : r;
 58  
         }
 59  
     };
 60  
 
 61  1
     private static final Comparator DEFAULT_COMPARATOR = new FileSorter("name", false);
 62  
 
 63  
     public final WebslingerServletContext wsc;
 64  
     public final FileObject base;
 65  
     public final String path;
 66  
     public final FileObject file;
 67  
 
 68  2
     public DirectoryLister(WebslingerServletContext wsc, FileObject base, String path) throws IOException {
 69  2
         this.wsc = wsc;
 70  2
         this.base = base;
 71  3
         while (path.length() > 0 && path.startsWith("/")) path = path.substring(1);
 72  2
         this.path = path;
 73  2
         file = base.resolveFile(path);
 74  2
     }
 75  
 
 76  
     protected Map<Comparator, Map<String, Map<String, Object>>> load(Map<Comparator, Map<String, Map<String, Object>>> oldContext) throws IOException {
 77  3
         file.refresh();
 78  3
         if (!file.getType().hasChildren()) return null;
 79  3
         final Map<String, Map<String, Object>> unsortedFiles = new LinkedHashMap<String, Map<String, Object>>();
 80  3
         FileObject[] children = file.getChildren();
 81  15
         for (int i = 0; i < children.length; i++) {
 82  12
             FileObject child = children[i];
 83  12
             FileContent content = child.getContent();
 84  12
             Map<String, Object> datum = new HashMap<String, Object>();
 85  12
             datum.put("path", child.getName().getPath());
 86  12
             datum.put("time", new Timestamp(content.getLastModifiedTime()));
 87  12
             datum.put("description", content.getAttribute("description"));
 88  12
             FileInfo fileInfo = wsc.getContainer().getFileInfo(child);
 89  12
             datum.put("content-type", fileInfo.getContentType());
 90  12
             String icon = (String) fileInfo.getAttribute("icon");
 91  12
             if (icon == null) icon = "unknown.png";
 92  12
             datum.put("icon", icon);
 93  12
             String sequence = (String) fileInfo.getAttribute("sequence");
 94  12
             if (sequence == null) sequence = "0";
 95  12
             datum.put("sequence", Integer.valueOf(sequence));
 96  12
             if (child.getType().hasChildren()) {
 97  2
                 datum.put("name", child.getName().getBaseName() + "/");
 98  2
                 datum.put("alt", "inode/directory");
 99  
             } else {
 100  10
                 datum.put("name", child.getName().getBaseName());
 101  10
                 datum.put("size", new Long(content.getSize()));
 102  
             }
 103  12
             unsortedFiles.put(child.getName().getBaseName(), datum);
 104  
         }
 105  
 
 106  3
         final Map<Comparator, Map<String, Map<String, Object>>> sorted = LazyMap.decorate(new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.SOFT), new Transformer() {
 107  
             public Object transform(Object key) {
 108  3
                 TreeSet<Map<String, Object>> set = new TreeSet<Map<String, Object>>((Comparator<Map<String, Object>>) key);
 109  3
                 set.addAll(unsortedFiles.values());
 110  3
                 Map<String, Map<String, Object>> files = new LinkedHashMap<String, Map<String, Object>>(set.size());
 111  3
                 Iterator<Map<String, Object>> it = set.iterator();
 112  15
                 while (it.hasNext()) {
 113  12
                     Map<String, Object> datum = it.next();
 114  12
                     files.put((String) datum.get("name"), datum);
 115  12
                 }
 116  3
                 return files;
 117  
             }
 118  
         });
 119  3
         return sorted;
 120  
     }
 121  
 
 122  
     public Map<String, Map<String, Object>> getFiles() throws IOException {
 123  0
         Map<Comparator, Map<String, Map<String, Object>>> sorted = getObject();
 124  0
         return sorted != null ? sorted.get(DEFAULT_COMPARATOR) : null;
 125  
     }
 126  
 
 127  
     public void list(Webslinger webslinger, String prefix, ThemingFactory<OutputConfig> configFactory) throws IOException, ServletException {
 128  3
         list(webslinger, webslinger.getPathContext(), webslinger.getRequest(), webslinger.getResponse(), webslinger.getContext(), prefix, configFactory.getThemedObject(webslinger.getThemePath()));
 129  3
     }
 130  
 
 131  
     public void list(Webslinger webslinger, Map<String, Object> context, String prefix, ThemingFactory<OutputConfig> configFactory) throws IOException, ServletException {
 132  0
         list(webslinger, webslinger.getPathContext(), webslinger.getRequest(), webslinger.getResponse(), context, prefix, configFactory.getThemedObject(webslinger.getThemePath()));
 133  0
     }
 134  
 
 135  
     public void list(Webslinger webslinger, HttpServletRequest request, HttpServletResponse response, Map<String, Object> context, String prefix, ThemingFactory<OutputConfig> configFactory) throws IOException, ServletException {
 136  0
         list(webslinger, webslinger.getPathContext(), request, response, context, prefix, configFactory.getThemedObject(webslinger.getThemePath()));
 137  0
     }
 138  
 
 139  
     public void list(Webslinger webslinger, String prefix, OutputConfig config) throws IOException, ServletException {
 140  0
         list(webslinger, webslinger.getPathContext(), webslinger.getRequest(), webslinger.getResponse(), webslinger.getContext(), prefix, config);
 141  0
     }
 142  
 
 143  
     public void list(Webslinger webslinger, Map<String, Object> context, String prefix, OutputConfig config) throws IOException, ServletException {
 144  0
         list(webslinger, webslinger.getPathContext(), webslinger.getRequest(), webslinger.getResponse(), context, prefix, config);
 145  0
     }
 146  
 
 147  
     public void list(Webslinger webslinger, PathContext pc, HttpServletRequest request, HttpServletResponse response, Map<String, Object> context, String prefix, OutputConfig config) throws IOException, ServletException {
 148  3
         Map<String, List<FileItem>> allParameters = (Map<String, List<FileItem>>) context.get("allParameters");
 149  3
         if (allParameters == null) allParameters = MultipartFormUtil.parseRequestAsMap(request);
 150  3
         Map<String, String> parameters = MultipartFormUtil.filterOutStrings(allParameters);
 151  3
         if (file.getType().hasContent()) {
 152  0
             if (parameters.get("thumb") != null) {
 153  0
                 thumb thumbHandler = (thumb) wsc.getTypeHandler("thumb");
 154  0
                 thumbHandler.serveThumb(wsc.resolve(file), request, response, 100, 100);
 155  0
             } else {
 156  0
                 webslinger.forward(wsc.resolve(file));
 157  
             }
 158  0
             return;
 159  
         }
 160  3
         context.put("TargetFile", file);
 161  3
         context.put("Base", base);
 162  3
         context.put("Path", path);
 163  3
         context.put("Config", config);
 164  3
         context.put("ListingPath", prefix + '/' + path);
 165  3
         context.put("Errors", new ArrayList());
 166  3
         context.put("DateFormat", DateFormat.getDateInstance(DateFormat.LONG));
 167  3
         context.put("TimeFormat", DateFormat.getTimeInstance(DateFormat.LONG));
 168  3
         context.put("DateTimeFormat", DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.FULL));
 169  3
         String view = parameters.get("view");
 170  3
         if (view == null) {
 171  3
             if (file.exists()) view = (String) file.getContent().getAttribute("listing-view");
 172  3
             if (view == null) {
 173  3
                 view = (String) pc.getAttribute("listing-view");
 174  3
                 if (view == null) view = "Details";
 175  
             }
 176  
         }
 177  3
         context.put("View", view);
 178  
 
 179  3
         Iterator<Map.Entry<String, String>> it = parameters.entrySet().iterator();
 180  3
         while (it.hasNext()) {
 181  0
             Map.Entry<String, String> entry = it.next();
 182  0
             String key = entry.getKey();
 183  0
             if (!key.startsWith("Action.")) continue;
 184  0
             StringTokenizer st = new StringTokenizer(key.substring(7), ".");
 185  0
             if (st.hasMoreTokens()) {
 186  0
                 String whichName = st.nextToken();
 187  
                 CachingLister actionLister;
 188  0
                 if ("Global".equals(whichName)) {
 189  0
                     actionLister = config.globalActions;
 190  0
                 } else if ("File".equals(whichName)) {
 191  0
                     actionLister = config.fileActions;
 192  
                 } else {
 193  
                     continue;
 194  
                 }
 195  0
                 if (actionLister != null && st.hasMoreTokens()) {
 196  0
                     String action = st.nextToken();
 197  0
                     FileObject actionFile = actionLister.getDir().resolveFile(action);
 198  0
                     context.put("Name", entry.getValue());
 199  0
                     String argument = key.substring(7 + whichName.length() + 1 + action.length());
 200  0
                     if (st.hasMoreTokens()) argument = argument.substring(1);
 201  0
                     context.put("ActionArgument", argument);
 202  0
                     webslinger.event(webslinger.resolvePath(actionFile), context, "action", allParameters);
 203  0
                     refresh();
 204  
                 }
 205  
             }
 206  0
         }
 207  
 
 208  3
         Map<Comparator, Map<String, Map<String, Object>>> sorted = getObject();
 209  3
         if (sorted == null) {
 210  0
             webslinger.forward(wsc.resolve(file));
 211  0
             return;
 212  
         }
 213  
         Map<String, Map<String, Object>> files;
 214  3
         String orderBy = parameters.get("orderBy");
 215  
         boolean nameDirection, timeDirection, sizeDirection, descending;
 216  3
         nameDirection = timeDirection = sizeDirection = descending = "desc".equals(parameters.get("direction"));
 217  3
         ArrayList<String> qParams = new ArrayList<String>();
 218  3
         if ("name".equals(orderBy)) {
 219  0
             nameDirection = !descending;
 220  0
             files = sorted.get(new FileSorter("name", descending));
 221  0
             qParams.add("orderBy=name");
 222  3
         } else if ("time".equals(orderBy)) {
 223  0
             timeDirection = !descending;
 224  0
             files = sorted.get(new FileSorter("time", descending));
 225  0
             qParams.add("orderBy=time");
 226  3
         } else if ("size".equals(orderBy)) {
 227  0
             sizeDirection = !descending;
 228  0
             files = sorted.get(new FileSorter("size", descending));
 229  0
             qParams.add("orderBy=size");
 230  
         } else {
 231  3
             files = sorted.get(DEFAULT_COMPARATOR);
 232  
         }
 233  3
         qParams.add("desc=" + (descending ? "desc" : "asc"));
 234  
 
 235  3
         context.put("ListingFiles", files);
 236  3
         context.put("ListingFilesList", new ArrayList<Map<String, Object>>(files.values()));
 237  3
         context.put("orderBy", orderBy);
 238  3
         context.put("direction", descending ? "desc" : "asc");
 239  3
         context.put("nameDirection", nameDirection ? "desc" : "asc");
 240  3
         context.put("timeDirection", timeDirection ? "desc" : "asc");
 241  3
         context.put("sizeDirection", sizeDirection ? "desc" : "asc");
 242  
 
 243  3
         webslinger.merge(wsc.resolve(config.views.getDir()), context);
 244  3
     }
 245  
 
 246  
     public static class OutputConfig {
 247  
         public final CachingLister views;
 248  
         public final CachingLister globalActions;
 249  
         public final CachingLister fileActions;
 250  
 
 251  3
         public OutputConfig(CachingLister views, CachingLister globalActions, CachingLister fileActions) {
 252  3
             this.views = views;
 253  3
             this.globalActions = globalActions;
 254  3
             this.fileActions = fileActions;
 255  3
         }
 256  
 
 257  
         public CachingLister getViews() {
 258  3
             return views;
 259  
         }
 260  
 
 261  
         public CachingLister getGlobalActions() {
 262  3
             return globalActions;
 263  
         }
 264  
 
 265  
         public CachingLister getFileActions() {
 266  3
             return fileActions;
 267  
         }
 268  
     }
 269  
 
 270  3
     public static class StandardThemingOutputConfig implements ThemingFactory<OutputConfig> {
 271  
         private final FileObject root;
 272  
         private final String viewsDir;
 273  
         private final String globalActionsDir;
 274  
         private final String fileActionsDir;
 275  
 
 276  1
         public StandardThemingOutputConfig(FileObject root, String viewsDir, String globalActionsDir, String fileActionsDir) {
 277  1
             this.root = root;
 278  1
             this.viewsDir = viewsDir;
 279  1
             this.globalActionsDir = globalActionsDir;
 280  1
             this.fileActionsDir = fileActionsDir;
 281  1
         }
 282  
 
 283  
         public OutputConfig getThemedObject(String themePath) throws IOException {
 284  3
             return makeOutputConfig(root.resolveFile(themePath), viewsDir, globalActionsDir, fileActionsDir);
 285  
         }
 286  
     }
 287  
 
 288  
     public static OutputConfig makeOutputConfig(FileObject base, String viewsDir, String globalActionsDir, String fileActionsDir) throws IOException {
 289  3
         return new OutputConfig(
 290  
             new ReloadingCachingLister(base.resolveFile(viewsDir)),
 291  
             new ReloadingCachingLister(base.resolveFile(globalActionsDir)),
 292  
             new ReloadingCachingLister(base.resolveFile(fileActionsDir))
 293  
         );
 294  
     }
 295  
 }