001: /*
002: * Copyright (C) 2006 Methodhead Software LLC. All rights reserved.
003: *
004: * This file is part of TransferCM.
005: *
006: * TransferCM is free software; you can redistribute it and/or modify it under the
007: * terms of the GNU General Public License as published by the Free Software
008: * Foundation; either version 2 of the License, or (at your option) any later
009: * version.
010: *
011: * TransferCM is distributed in the hope that it will be useful, but WITHOUT ANY
012: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
013: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
014: * details.
015: *
016: * You should have received a copy of the GNU General Public License along with
017: * TransferCM; if not, write to the Free Software Foundation, Inc., 51 Franklin St,
018: * Fifth Floor, Boston, MA 02110-1301 USA
019: */
020:
021: package com.methodhead.res;
022:
023: import java.io.Serializable;
024: import java.util.Enumeration;
025: import javax.servlet.http.HttpServletRequest;
026:
027: import org.apache.log4j.Logger;
028: import org.apache.commons.lang.StringUtils;
029: import org.apache.commons.lang.exception.ExceptionUtils;
030:
031: import java.io.File;
032: import java.util.List;
033: import java.util.ArrayList;
034: import java.util.Collections;
035: import java.util.Comparator;
036: import java.util.Iterator;
037:
038: import org.apache.struts.action.Action;
039: import org.apache.struts.action.ActionMapping;
040: import org.apache.struts.action.ActionMessages;
041: import org.apache.struts.action.ActionForm;
042: import org.apache.struts.action.DynaActionForm;
043: import org.apache.struts.action.ActionForward;
044: import org.apache.struts.util.LabelValueBean;
045: import org.apache.struts.action.ActionMapping;
046: import org.apache.struts.action.ActionErrors;
047: import org.apache.struts.action.ActionError;
048: import org.apache.struts.validator.DynaValidatorForm;
049: import org.apache.struts.upload.FormFile;
050:
051: import com.methodhead.persistable.PersistableException;
052: import com.methodhead.tree.FoldingTreeNode;
053: import com.methodhead.auth.AuthUser;
054: import com.methodhead.auth.AuthUtil;
055:
056: /**
057: * An action form that performs validation and initializes properties
058: * for the JSPs.
059: */
060: public final class ResForm extends DynaValidatorForm implements
061: Serializable {
062:
063: /**
064: * Returns the part of <tt>f</tt>'s path relative to <tt>base</tt>.
065: */
066: protected String getRelativePath(File base, File f) {
067:
068: String path = f.getPath().substring(base.getPath().length());
069:
070: if (path.startsWith(File.separator))
071: return path.substring(1);
072: else
073: return path;
074: }
075:
076: /**
077: * Recursively adds <tt>LabelValueBean</tt>s for <tt>path</tt> and its
078: * subdirectories to <tt>options</tt>, rooting the search at <tt>base</tt>,
079: * and using <tt>name</tt> a logical name for that base.
080: */
081: protected void addSubdirOptions(List options, String name,
082: File base, String path) {
083:
084: //
085: // create the option and add it to the list
086: //
087: String label = name;
088: if (!"".equals(path))
089: label = name + "/" + path;
090:
091: options.add(new LabelValueBean(label, label));
092:
093: //
094: // recurse into any subdirectories
095: //
096: File f = new File(base, path);
097: File[] files = f.listFiles();
098: for (int i = 0; i < files.length; i++) {
099: if (files[i].isDirectory()) {
100: addSubdirOptions(options, name, base, getRelativePath(
101: base, files[i]));
102: }
103: }
104: }
105:
106: /**
107: * Returns options for all authorized paths and their subdirectories.
108: */
109: public List getDestinationOptions(FileManager fileManager) {
110:
111: List options = new ArrayList();
112:
113: //
114: // add subdirectories for each directory managed by the file manager
115: //
116: Directory[] dirs = fileManager.getDirectories();
117: for (int i = 0; i < dirs.length; i++) {
118: addSubdirOptions(options, dirs[i].getName(), dirs[i]
119: .getFile(), "");
120: }
121:
122: //
123: // sort the options
124: //
125: Collections.sort(options, new Comparator() {
126: public int compare(Object o1, Object o2) {
127: return ((LabelValueBean) o1).getLabel()
128: .compareToIgnoreCase(
129: ((LabelValueBean) o2).getLabel());
130: }
131: });
132:
133: return options;
134: }
135:
136: /**
137: * Returns the tree in the session, building it if necessary. NOT UNIT TESTED
138: */
139: protected FileTree getTree(ResPolicy policy,
140: HttpServletRequest request) {
141:
142: FileTree tree = (FileTree) request.getSession().getAttribute(
143: ResGlobals.FILETREE_KEY);
144:
145: if (tree == null) {
146: tree = policy.newFileTree();
147: tree.build(ResUtils.getFileManager(policy, request));
148: request.getSession().setAttribute(ResGlobals.FILETREE_KEY,
149: tree);
150: }
151:
152: return tree;
153: }
154:
155: /**
156: * Resets the form by determining valid destinations for the user, setting
157: * the directory tree, and building a list of <tt>FoldingTreeNode</tt>s for
158: * <tt>form.path</tt> and <tt>form.file<i>n</i></tt>, setting
159: * <tt>form.files</tt> to this list. Each node has its label set to the file
160: * name, and its user object set to the <tt>File</tt> it represents.
161: */
162: public void reset(
163: ActionMapping mapping,
164: HttpServletRequest request ) {
165:
166: try {
167: //
168: // don't do anything if noone is logged in
169: //
170: if ( AuthUtil.getUser( request ) != null ) {
171:
172: //
173: // get the res policy
174: //
175: ResPolicy policy = ResUtils.getPolicy( mapping );
176:
177: //
178: // get the file manager
179: //
180: FileManager fileManager = ResUtils.getFileManager( policy, request );
181:
182: //
183: // build the destination options
184: //
185: set(
186: "destinations",
187: getDestinationOptions( ResUtils.getFileManager( policy, request ) ) );
188:
189: //
190: // set tree
191: //
192: set( "tree", getTree( policy, request ).getRoot() );
193:
194: //
195: // collect any file names in a list of FoldingTreeNodes
196: //
197: String path = request.getParameter( "path" );
198:
199: List files = new ArrayList();
200:
201: if ( !StringUtils.isBlank( path ) ) {
202:
203: for (
204: Enumeration enum = request.getParameterNames();
205: enum.hasMoreElements(); ) {
206:
207: String s = ( String )enum.nextElement();
208:
209: if ( s.matches( "file\\d+" ) ) {
210:
211: //
212: // verify the file
213: //
214: File f = fileManager.getFile( path, request.getParameter( s ) );
215:
216: if ( f == null )
217: throw new ResException(
218: "File \"" + path + "/" + request.getParameter( s ) +
219: "\" does not exist." );
220:
221: //
222: // create a node for the file
223: //
224: FoldingTreeNode n = new FoldingTreeNode();
225:
226: n.setLabel( f.getName() );
227: n.setUserObject( f );
228:
229: if ( f.isDirectory() )
230: n.setIconHint( "dir" );
231:
232: files.add( n );
233: }
234: }
235: }
236:
237: //
238: // sort the files
239: //
240: Collections.sort( files, new Comparator() {
241: public int compare( Object o1, Object o2 ) {
242: return
243: ( ( FoldingTreeNode )o1 ).getLabel().compareToIgnoreCase(
244: ( ( FoldingTreeNode )o2 ).getLabel() );
245: }
246: } );
247:
248: //
249: // set the files in the form
250: //
251: set( "files", files );
252: }
253: }
254: catch ( ResException e ) {
255: logger_.error( ExceptionUtils.getStackTrace( e ) );
256: }
257: }
258:
259: /**
260: * NOT UNIT TESTED
261: */
262: public ActionErrors validate(ActionMapping mapping,
263: HttpServletRequest request) {
264:
265: ActionErrors errors = new ActionErrors();
266:
267: //
268: // don't do anything if no one is logged in
269: //
270: if (AuthUtil.getUser(request) == null)
271: return errors;
272:
273: //
274: // don't do anything if we're cancelling; the action will handle this
275: //
276: if (!StringUtils.isBlank((String) get("cancel")))
277: return errors;
278:
279: //
280: // get some things we'll need
281: //
282: String name = (String) get("name");
283: String path = (String) get("path");
284: String moveto = (String) get("moveto");
285: String movetoname = (String) get("movetoname");
286: String copyto = (String) get("copyto");
287: String copytoname = (String) get("copytoname");
288: FormFile formFile = (FormFile) get("file");
289:
290: //
291: // get the file manager
292: //
293: FileManager fileManager = ResUtils.getFileManager(ResUtils
294: .getPolicy(mapping), request);
295:
296: //
297: // build an array of file names
298: //
299: String[] srcFiles = ResUtils
300: .nodesToFileNames((List) get("files"));
301:
302: if (mapping.getPath().equals("/manageFiles")) {
303:
304: //
305: // make sure we're not cancelling the manage files form
306: //
307: if (StringUtils.isBlank((String) get("cancelManage"))) {
308:
309: //
310: // move?
311: //
312: if ("move".equals(get("action"))) {
313:
314: //
315: // validate the move
316: //
317: String result = fileManager.validateMove(path,
318: srcFiles, moveto, movetoname);
319:
320: if (result != null)
321: errors.add("moveto", new ActionError(result));
322: }
323:
324: //
325: // copy?
326: //
327: else if ("copy".equals(get("action"))) {
328:
329: //
330: // validate the copy
331: //
332: String result = fileManager.validateMove(path,
333: srcFiles, copyto, copytoname);
334:
335: if (result != null)
336: errors.add("copyto", new ActionError(result));
337: }
338:
339: //
340: // delete?
341: //
342: else if ("delete".equals(get("action"))) {
343: //
344: // nothing to do here
345: //
346: }
347:
348: //
349: // edit?
350: //
351: else if ("edit".equals(get("action"))) {
352: //
353: // nothing to do here
354: //
355: }
356:
357: //
358: // unzip?
359: //
360: else if ("unzip".equals(get("action"))) {
361: //
362: // nothing to do here
363: //
364: } else {
365: errors.add("action", new ActionError(
366: "res.missingaction"));
367: }
368: }
369: }
370:
371: if (mapping.getPath().equals("/manageFilesForm")) {
372:
373: //
374: // make sure one or more files were checked
375: //
376: if (srcFiles.length == 0)
377: errors.add(ActionErrors.GLOBAL_ERROR, new ActionError(
378: "res.nofileschecked"));
379: }
380:
381: if (mapping.getPath().equals("/uploadFile")) {
382:
383: //
384: // formFile is not null only when submitting the multipart form
385: //
386: if (formFile != null) {
387:
388: //
389: // blank?
390: //
391: if (StringUtils.isBlank(formFile.getFileName()))
392: errors.add("file", new ActionError(
393: "res.missingfile", formFile.getFileName()));
394:
395: //
396: // valid?
397: //
398: if (!ResUtils.isValidFileName(formFile.getFileName()))
399: errors.add("file", new ActionError(
400: "res.invalidfilename", formFile
401: .getFileName()));
402: }
403: }
404:
405: if (mapping.getPath().equals("/createFile")) {
406:
407: //
408: // blank?
409: //
410: if (StringUtils.isBlank(name))
411: errors.add("name", new ActionError("res.missingname"));
412:
413: //
414: // valid?
415: //
416: if (!ResUtils.isValidFileName(name))
417: errors.add("file", new ActionError(
418: "res.invalidfilename", name));
419:
420: //
421: // can we create this file?
422: //
423: if (errors.isEmpty()) {
424: String result = fileManager
425: .validateCreate(path, name, !StringUtils
426: .isBlank((String) get("createdir")));
427:
428: if (result != null)
429: errors.add("name", new ActionError(result));
430: }
431: }
432:
433: return errors;
434: }
435:
436: private Logger logger_ = Logger.getLogger("ResForm");
437: }
|