Java tutorial
/* * R Service Bus * * Copyright (c) Copyright of Open Analytics NV, 2010-2015 * * =========================================================================== * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.openanalytics.rsb.data; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.GregorianCalendar; import java.util.List; import java.util.UUID; import javax.activation.MimeType; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.comparator.LastModifiedFileComparator; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Component; import eu.openanalytics.rsb.Util; import eu.openanalytics.rsb.component.AbstractComponent; /** * A file-based result store. * * @author "OpenAnalytics <rsb.development@openanalytics.eu>" */ @Component("secureResultStore") public class FileResultStore extends AbstractComponent implements SecureResultStore { private static final String ERROR_MESSAGE = "This method shouldn't have been called: please report the issue."; private static final String ERROR_FILE_INFIX_EXTENSION = ".err"; public boolean deleteByApplicationNameAndJobId(final String applicationName, final UUID jobId) throws IOException { throw new UnsupportedOperationException(ERROR_MESSAGE); } public Collection<PersistedResult> findByApplicationName(final String applicationName) { throw new UnsupportedOperationException(ERROR_MESSAGE); } public PersistedResult findByApplicationNameAndJobId(final String applicationName, final UUID jobId) { throw new UnsupportedOperationException(ERROR_MESSAGE); } public void store(final PersistedResult result) throws IOException { final String resultFileName = result.getJobId().toString() + (result.isSuccess() ? "" : ERROR_FILE_INFIX_EXTENSION) + "." + Util.getResourceType(result.getMimeType()); final File resultsDirectory = getResultsDirectory(result.getApplicationName(), result.getUserName()); FileUtils.forceMkdir(resultsDirectory); final File resultFile = new File(resultsDirectory, resultFileName); final InputStream resultData = result.getData(); final FileOutputStream fos = new FileOutputStream(resultFile); IOUtils.copy(resultData, fos); IOUtils.closeQuietly(result.getData()); IOUtils.closeQuietly(fos); } @PreAuthorize("hasPermission(#applicationName, 'APPLICATION_USER')") public boolean deleteByApplicationNameAndJobId(final String applicationName, final String userName, final UUID jobId) throws IOException { final File resultFile = getResultFile(applicationName, userName, jobId); if (resultFile == null) { return false; } FileUtils.forceDelete(resultFile); return true; } @PreAuthorize("hasPermission(#applicationName, 'APPLICATION_USER')") public Collection<PersistedResult> findByApplicationName(final String applicationName, final String userName) { final File[] resultFiles = getResultsDirectory(applicationName, userName).listFiles(); if ((resultFiles == null) || (resultFiles.length == 0)) { return Collections.emptyList(); } final Collection<PersistedResult> persistedResults = new ArrayList<PersistedResult>(); final List<File> sortedFiles = new ArrayList<File>(Arrays.asList(resultFiles)); Collections.sort(sortedFiles, LastModifiedFileComparator.LASTMODIFIED_REVERSE); for (final File resultFile : sortedFiles) { final UUID jobId = Util.safeUuidFromString(StringUtils.substringBefore(resultFile.getName(), ".")); if (jobId != null) { persistedResults.add(buildPersistedResult(applicationName, userName, jobId, resultFile)); } } return persistedResults; } @PreAuthorize("hasPermission(#applicationName, 'APPLICATION_USER')") public PersistedResult findByApplicationNameAndJobId(final String applicationName, final String userName, final UUID jobId) { final File resultFile = getResultFile(applicationName, userName, jobId); return resultFile == null ? null : buildPersistedResult(applicationName, userName, jobId, resultFile); } private File getResultFile(final String applicationName, final String userName, final UUID jobId) { final String jobIdAsString = jobId.toString(); final File[] resultFiles = getResultsDirectory(applicationName, userName).listFiles(new FilenameFilter() { public boolean accept(final File dir, final String name) { return jobIdAsString.equals(StringUtils.substringBefore(name, ".")); } }); if ((resultFiles == null) || (resultFiles.length == 0)) { return null; } if (resultFiles.length > 1) { throw new IllegalStateException("Found " + resultFiles.length + " results for job Id: " + jobId); } return resultFiles[0]; } private PersistedResult buildPersistedResult(final String applicationName, final String userName, final UUID jobId, final File resultFile) { final GregorianCalendar resultTime = (GregorianCalendar) GregorianCalendar.getInstance(); resultTime.setTimeInMillis(resultFile.lastModified()); final boolean success = !StringUtils.contains(resultFile.getName(), ERROR_FILE_INFIX_EXTENSION + "."); final MimeType mimeType = Util.getMimeType(resultFile); return new PersistedResult(applicationName, userName, jobId, resultTime, success, mimeType) { @Override public InputStream getData() { try { return new FileInputStream(resultFile); } catch (final FileNotFoundException fnfe) { throw new IllegalStateException(fnfe); } } @Override public long getDataLength() { return resultFile.length(); } }; } private File getResultsDirectory(final String applicationName, final String userName) { // this is to prevent trying to use application names with / or \ in order to // reach disallowed directories Validate.isTrue(Util.isValidApplicationName(applicationName), "Invalid application name: " + applicationName); final File applicationResultsDirectory = new File(getConfiguration().getResultsDirectory(), applicationName); return StringUtils.isBlank(userName) ? applicationResultsDirectory : new File(applicationResultsDirectory, userName); } }