001/*
002 * Copyright 2009 The Kuali Foundation
003 * 
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * 
008 * http://www.opensource.org/licenses/ecl2.php
009 * 
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.ole.sys.businessobject.lookup;
017
018import java.io.File;
019import java.io.IOException;
020import java.text.ParseException;
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.Date;
024import java.util.List;
025import java.util.Map;
026import java.util.Properties;
027
028import org.apache.commons.io.DirectoryWalker;
029import org.apache.commons.io.IOCase;
030import org.apache.commons.io.filefilter.AbstractFileFilter;
031import org.apache.commons.io.filefilter.FileFilterUtils;
032import org.apache.commons.io.filefilter.IOFileFilter;
033import org.apache.commons.io.filefilter.WildcardFileFilter;
034import org.apache.commons.lang.StringUtils;
035import org.kuali.ole.sys.batch.BatchFile;
036import org.kuali.ole.sys.batch.BatchFileUtils;
037import org.kuali.ole.sys.batch.service.BatchFileAdminAuthorizationService;
038import org.kuali.ole.sys.util.KfsDateUtils;
039import org.kuali.rice.core.api.datetime.DateTimeService;
040import org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl;
041import org.kuali.rice.kns.lookup.HtmlData;
042import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
043import org.kuali.rice.kns.web.ui.Field;
044import org.kuali.rice.kns.web.ui.Row;
045import org.kuali.rice.krad.bo.BusinessObject;
046import org.kuali.rice.krad.util.GlobalVariables;
047import org.kuali.rice.krad.util.KRADConstants;
048import org.kuali.rice.krad.util.UrlFactory;
049
050public class BatchFileLookupableHelperServiceImpl extends AbstractLookupableHelperServiceImpl {
051    protected DateTimeService dateTimeService;
052    protected BatchFileAdminAuthorizationService batchFileAdminAuthorizationService;
053    
054    @Override
055    public List<? extends BusinessObject> getSearchResults(Map<String, String> fieldValues) {
056        List<BatchFile> results = new ArrayList<BatchFile>();
057
058        IOFileFilter filter = FileFilterUtils.fileFileFilter();
059        
060        IOFileFilter pathBasedFilter = getPathBasedFileFilter();
061        if (pathBasedFilter != null) {
062            filter = FileFilterUtils.andFileFilter(filter, pathBasedFilter);
063        }
064        
065        String fileNamePattern = fieldValues.get("fileName");
066        IOFileFilter fileNameBasedFilter = getFileNameBasedFilter(fileNamePattern);
067        if (fileNameBasedFilter != null) {
068            filter = FileFilterUtils.andFileFilter(filter, fileNameBasedFilter);
069        }
070        
071        String lastModifiedDate = fieldValues.get("lastModifiedDate");
072        IOFileFilter lastModifiedDateBasedFilter = getLastModifiedDateBasedFilter(lastModifiedDate);
073        if (lastModifiedDateBasedFilter != null) {
074            filter = FileFilterUtils.andFileFilter(filter, lastModifiedDateBasedFilter);
075        }
076        
077        BatchFileFinder finder = new BatchFileFinder(results, filter);
078        List<File> rootDirectories = BatchFileUtils.retrieveBatchFileLookupRootDirectories();
079        finder.find(rootDirectories);
080        
081        return results;
082    }
083
084    protected IOFileFilter getPathBasedFileFilter() {
085        List<File> selectedFiles = getSelectedDirectories(getSelectedPaths());
086        if (selectedFiles.isEmpty()) {
087            return null;
088        }
089        IOFileFilter fileFilter = null;
090        for (File selectedFile : selectedFiles) {
091            IOFileFilter subFilter = new SubDirectoryFileFilter(selectedFile);
092            if (fileFilter == null) {
093                fileFilter = subFilter;
094            }
095            else {
096                fileFilter = FileFilterUtils.orFileFilter(fileFilter, subFilter);
097            }
098        }
099        return fileFilter;
100    }
101    
102    protected IOFileFilter getFileNameBasedFilter(String fileNamePattern) {
103        if (StringUtils.isNotBlank(fileNamePattern)) {
104            return new WildcardFileFilter(fileNamePattern, IOCase.INSENSITIVE);
105        }
106        return null;
107    }
108    
109    protected IOFileFilter getLastModifiedDateBasedFilter(String lastModifiedDatePattern) {
110        if (StringUtils.isBlank(lastModifiedDatePattern)) {
111            return null;
112        }
113        try {
114            if (lastModifiedDatePattern.startsWith("<=")) {
115                String dateString = StringUtils.removeStart(lastModifiedDatePattern, "<=");
116                Date toDate = dateTimeService.convertToDate(dateString);
117                return new LastModifiedDateFileFilter(null, toDate);
118            }
119            if (lastModifiedDatePattern.startsWith(">=")) {
120                String dateString = StringUtils.removeStart(lastModifiedDatePattern, ">=");
121                Date fromDate = dateTimeService.convertToDate(dateString);
122                return new LastModifiedDateFileFilter(fromDate, null);
123            }
124            if (lastModifiedDatePattern.contains("..")) {
125                String[] dates = StringUtils.splitByWholeSeparator(lastModifiedDatePattern, "..", 2);
126                Date fromDate = dateTimeService.convertToDate(dates[0]);
127                Date toDate = dateTimeService.convertToDate(dates[1]);
128                return new LastModifiedDateFileFilter(fromDate, toDate);
129            }
130        }
131        catch (ParseException e) {
132            throw new RuntimeException("Can't parse date", e);
133        }
134        throw new RuntimeException("Unable to perform search using last modified date " + lastModifiedDatePattern);
135    }
136    
137    protected List<File> getSelectedDirectories(String[] selectedPaths) {
138        List<File> directories = new ArrayList<File>();
139        if (selectedPaths != null) {
140            for (String selectedPath : selectedPaths) {
141                File directory = new File(BatchFileUtils.resolvePathToAbsolutePath(selectedPath));
142                if (!directory.exists()) {
143                    throw new RuntimeException("Non existent directory " + BatchFileUtils.resolvePathToAbsolutePath(selectedPath));
144                }
145                directories.add(directory);
146            }
147        }
148        return directories;
149    }
150    /**
151     * KRAD Conversion: gets rows after customizing the field values
152     * 
153     * No use of data dictionary
154     */
155    protected String[] getSelectedPaths() {
156        List<Row> rows = getRows();
157        if (rows == null) {
158            return null;
159        }
160        for (Row row : rows) {
161            for (Field field : row.getFields()) {
162                if ("path".equals(field.getPropertyName()) && Field.MULTISELECT.equals(field.getFieldType())) {
163                    String[] values = field.getPropertyValues();
164                    return values;
165                }
166            }
167        }
168        return null;
169    }
170    
171    protected class SubDirectoryFileFilter extends AbstractFileFilter {
172        private File superDirectory;
173        
174        public SubDirectoryFileFilter(File superDirectory) {
175            this.superDirectory = superDirectory.getAbsoluteFile();
176        }
177        
178        @Override
179        public boolean accept(File file) {
180            file = file.getAbsoluteFile();
181            file = file.getParentFile();
182            while (file != null) {
183                if (file.equals(superDirectory)) {
184                    return true;
185                }
186                file = file.getParentFile();
187            }
188            return false;
189        }
190    }
191    
192    protected class LastModifiedDateFileFilter extends AbstractFileFilter {
193        private Date fromDate;
194        private Date toDate;
195        
196        public LastModifiedDateFileFilter(Date fromDate, Date toDate) {
197            this.fromDate = fromDate;
198            this.toDate = toDate;
199        }
200        
201        @Override
202        public boolean accept(File file) {
203            Date lastModifiedDate = KfsDateUtils.clearTimeFields(new Date(file.lastModified()));
204            
205            if (fromDate != null && fromDate.after(lastModifiedDate)) {
206                return false;
207            }
208            if (toDate != null && toDate.before(lastModifiedDate)) {
209                return false;
210            }
211            return true;
212        }
213    }
214    
215    protected class BatchFileFinder extends DirectoryWalker {
216        private List<BatchFile> results;
217        
218        public BatchFileFinder(List<BatchFile> results, IOFileFilter fileFilter) {
219            super(null, fileFilter, -1);
220            this.results = results;
221        }
222        
223        public void find(Collection<File> rootDirectories) {
224            try {
225                for (File rootDirectory : rootDirectories) {
226                    walk(rootDirectory, null);
227                }
228            }
229            catch (IOException e) {
230                throw new RuntimeException("Error performing lookup", e);
231            }
232        }
233
234        /**
235         * @see org.apache.commons.io.DirectoryWalker#handleFile(java.io.File, int, java.util.Collection)
236         */
237        @Override
238        protected void handleFile(File file, int depth, Collection results) throws IOException {
239            super.handleFile(file, depth, results);
240            BatchFile batchFile = new BatchFile();
241            batchFile.setFile(file);
242            this.results.add(batchFile);
243        }
244    }
245
246    public void setDateTimeService(DateTimeService dateTimeService) {
247        this.dateTimeService = dateTimeService;
248    }
249
250    @Override
251    public List<HtmlData> getCustomActionUrls(BusinessObject businessObject, List pkNames) {
252        List<HtmlData> links = new ArrayList<HtmlData>();
253        
254        BatchFile batchFile = (BatchFile) businessObject;
255        if (canDownloadFile(batchFile)) {
256            links.add(getDownloadUrl(batchFile));
257        }
258        if (canDeleteFile(batchFile)) {
259            links.add(getDeleteUrl(batchFile));
260        }
261        return links;
262    }
263
264    protected boolean canDownloadFile(BatchFile batchFile) {
265        return batchFileAdminAuthorizationService.canDownload(batchFile, GlobalVariables.getUserSession().getPerson());
266    }
267
268    protected boolean canDeleteFile(BatchFile batchFile) {
269        return batchFileAdminAuthorizationService.canDelete(batchFile, GlobalVariables.getUserSession().getPerson());
270    }
271    
272    protected HtmlData getDownloadUrl(BatchFile batchFile) {
273        Properties parameters = new Properties();
274        parameters.put("filePath", BatchFileUtils.pathRelativeToRootDirectory(batchFile.retrieveFile().getAbsolutePath()));
275        parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, "download");
276        String href = UrlFactory.parameterizeUrl("../batchFileAdmin.do", parameters);
277        return new AnchorHtmlData(href, "download", "Download");
278    }
279    
280    protected HtmlData getDeleteUrl(BatchFile batchFile) {
281        Properties parameters = new Properties();
282        parameters.put("filePath", BatchFileUtils.pathRelativeToRootDirectory(batchFile.retrieveFile().getAbsolutePath()));
283        parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, "delete");
284        String href = UrlFactory.parameterizeUrl("../batchFileAdmin.do", parameters);
285        return new AnchorHtmlData(href, "delete", "Delete");
286    }
287
288    /**
289     * @see org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl#validateSearchParameters(java.util.Map)
290     */
291    @Override
292    public void validateSearchParameters(Map fieldValues) {
293        super.validateSearchParameters(fieldValues);
294        
295        String[] selectedPaths = getSelectedPaths();
296        if (selectedPaths != null) {
297            for (String selectedPath : selectedPaths) {
298                String resolvedPath = BatchFileUtils.resolvePathToAbsolutePath(selectedPath);
299                if (!BatchFileUtils.isDirectoryAccessible(resolvedPath)) {
300                    throw new RuntimeException("Can't access path " + selectedPath);
301                }
302            }
303        }
304    }
305
306    /**
307     * Sets the batchFileAdminAuthorizationService attribute value.
308     * @param batchFileAdminAuthorizationService The batchFileAdminAuthorizationService to set.
309     */
310    public void setBatchFileAdminAuthorizationService(BatchFileAdminAuthorizationService batchFileAdminAuthorizationService) {
311        this.batchFileAdminAuthorizationService = batchFileAdminAuthorizationService;
312    }
313}