NIHVIVO-3524 UpdateUploadedFiles (and dependent classes) was used to migrate from 0.9 to 1.0 and from 1.1.1 to 1.2 - it is no longer needed.
This commit is contained in:
parent
acf1b1896a
commit
04eb46415a
16 changed files with 0 additions and 2014 deletions
|
@ -1,64 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
|
||||
/**
|
||||
* Adjust any individual that has a thumbnail with no main image.
|
||||
*/
|
||||
public class AllThumbsAdjuster extends FsuScanner {
|
||||
private ImageDirectoryWithBackup imageDirectoryWithBackup;
|
||||
|
||||
public AllThumbsAdjuster(FSUController controller) {
|
||||
super(controller);
|
||||
this.imageDirectoryWithBackup = controller
|
||||
.getImageDirectoryWithBackup();
|
||||
}
|
||||
|
||||
/**
|
||||
* For every individual with thumbnails but no main images, create a main
|
||||
* image from the first thumbnail.
|
||||
*/
|
||||
public void adjust() {
|
||||
updateLog.section("Creating main images for thumbnails "
|
||||
+ "that have none.");
|
||||
|
||||
for (Resource resource : ModelWrapper.listResourcesWithProperty(model,
|
||||
thumbProperty)) {
|
||||
if (ResourceWrapper.getProperty(resource, imageProperty) == null) {
|
||||
createMainImageFromThumbnail(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This individual has a thumbnail but no main image. Create one.
|
||||
* <ul>
|
||||
* <li>Figure a name for the main image.</li>
|
||||
* <li>Copy the thumbnail image file into the main image file.</li>
|
||||
* <li>Set that file as an image (old-style) on the individual.</li>
|
||||
* </ul>
|
||||
*/
|
||||
private void createMainImageFromThumbnail(Resource resource) {
|
||||
String thumbFilename = getValues(resource, thumbProperty).get(0);
|
||||
String mainFilename = addFilenamePrefix("_main_image_", thumbFilename);
|
||||
updateLog.log(resource, "creating a main file at '" + mainFilename
|
||||
+ "' to match the thumbnail at '" + thumbFilename + "'");
|
||||
|
||||
try {
|
||||
File thumbFile = imageDirectoryWithBackup
|
||||
.getExistingFile(thumbFilename);
|
||||
File mainFile = imageDirectoryWithBackup.getNewfile(mainFilename);
|
||||
mainFile = checkNameConflicts(mainFile);
|
||||
FileUtil.copyFile(thumbFile, mainFile);
|
||||
ResourceWrapper.addProperty(resource, imageProperty, mainFilename);
|
||||
} catch (IOException e) {
|
||||
updateLog.error(resource, "failed to create main file '"
|
||||
+ mainFilename + "'", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
|
||||
/**
|
||||
* Removes any image properties (main or thumbnail) that point to files that
|
||||
* don't actually exist.
|
||||
*/
|
||||
public class DeadEndPropertyRemover extends FsuScanner {
|
||||
private ImageDirectoryWithBackup imageDirectoryWithBackup;
|
||||
|
||||
public DeadEndPropertyRemover(FSUController controller) {
|
||||
super(controller);
|
||||
this.imageDirectoryWithBackup = controller
|
||||
.getImageDirectoryWithBackup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove dead end properties for both main images and thumbnails.
|
||||
*/
|
||||
public void remove() {
|
||||
updateLog.section("Removing image properties whose "
|
||||
+ "referenced files do not exist.");
|
||||
|
||||
removeDeadEndProperties(imageProperty, "main image");
|
||||
removeDeadEndProperties(thumbProperty, "thumbnail");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all of the individuals that possess this property.
|
||||
*/
|
||||
private void removeDeadEndProperties(Property prop, String label) {
|
||||
for (Resource resource : ModelWrapper.listResourcesWithProperty(model,
|
||||
prop)) {
|
||||
removeDeadEndPropertiesFromResource(resource, prop, label);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check these statments on this resource. If any of them does not point to
|
||||
* an existing file, remove the statement.
|
||||
*/
|
||||
private void removeDeadEndPropertiesFromResource(Resource resource,
|
||||
Property prop, String label) {
|
||||
for (Statement stmt : getStatements(resource, prop)) {
|
||||
RDFNode node = stmt.getObject();
|
||||
if (node.isLiteral()) {
|
||||
String filename = ((Literal) node).getString();
|
||||
File file = imageDirectoryWithBackup.getExistingFile(filename);
|
||||
if (!file.exists()) {
|
||||
updateLog.warn(
|
||||
resource,
|
||||
"removing link to " + label + " '" + filename
|
||||
+ "': file does not exist at '"
|
||||
+ file.getAbsolutePath() + "'.");
|
||||
|
||||
ModelWrapper.removeStatement(model, stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.UploadedFileHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
|
||||
/**
|
||||
* An object that can initialize one of the {@link FsuScanner}s.
|
||||
*/
|
||||
public interface FSUController {
|
||||
|
||||
/** The Jena model. */
|
||||
Model getModel();
|
||||
|
||||
/** The update log. */
|
||||
FSULog getUpdateLog();
|
||||
|
||||
/** The place to find or to create image files. */
|
||||
ImageDirectoryWithBackup getImageDirectoryWithBackup();
|
||||
|
||||
/** A helper with access to the DAO layer and the file storage system. */
|
||||
UploadedFileHelper getUploadedFileHelper();
|
||||
|
||||
/** The file storage system. */
|
||||
FileStorage getFileStorage();
|
||||
|
||||
/** Where to store the files that were translated. */
|
||||
File getTranslatedDirectory();
|
||||
|
||||
/** Where to store the files that weren't in use anyway. */
|
||||
File getUnreferencedDirectory();
|
||||
|
||||
}
|
|
@ -1,181 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
|
||||
/**
|
||||
* Writes the log file for the {@link FileStorageUpdater}. Be sure to call
|
||||
* {@link #close()} when finished.
|
||||
*/
|
||||
public class FSULog {
|
||||
private final SimpleDateFormat timeStamper = new SimpleDateFormat(
|
||||
"yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private final File logFile;
|
||||
private final PrintWriter writer;
|
||||
private boolean open;
|
||||
|
||||
FSULog(File logDirectory, String prefix) throws IOException {
|
||||
this.logFile = generateTimestampedFilename(logDirectory, prefix);
|
||||
this.writer = new PrintWriter(this.logFile);
|
||||
open = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a filename for the log file that contains a timestamp, so if we
|
||||
* run the process more than once, we will see multiple files.
|
||||
*/
|
||||
private File generateTimestampedFilename(File upgradeDirectory,
|
||||
String prefix) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-sss");
|
||||
String filename = prefix + "." + sdf.format(new Date()) + ".txt";
|
||||
return new File(upgradeDirectory, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Where are we writing the output?
|
||||
*/
|
||||
String getFilename() {
|
||||
return this.logFile.getAbsolutePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write this message.
|
||||
*/
|
||||
void log(String message) {
|
||||
writer.println(timeStamper.format(new Date()) + " INFO " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write this message about this resource.
|
||||
*/
|
||||
void log(Resource resource, String message) {
|
||||
log(showResource(resource) + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write this warning message.
|
||||
*/
|
||||
public void warn(String message) {
|
||||
writer.println(timeStamper.format(new Date()) + " WARN " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write this warning message about this resource.
|
||||
*/
|
||||
public void warn(Resource resource, String message) {
|
||||
warn(showResource(resource) + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write this error message.
|
||||
*/
|
||||
void error(String message) {
|
||||
writer.println(timeStamper.format(new Date()) + " ERROR " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write this exception as an error message..
|
||||
*/
|
||||
void error(Exception e) {
|
||||
error(e.toString());
|
||||
e.printStackTrace(writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an error message with this exception.
|
||||
*/
|
||||
public void error(String message, Exception e) {
|
||||
error(message);
|
||||
e.printStackTrace(writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an error message about this resource and with this exception.
|
||||
*/
|
||||
public void error(Resource resource, String message) {
|
||||
error(showResource(resource) + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an error message about this resource and with this exception.
|
||||
*/
|
||||
public void error(Resource resource, String message, Exception e) {
|
||||
error(showResource(resource) + message, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a section heading.
|
||||
*/
|
||||
public void section(String message) {
|
||||
log(">>>>>>>>>> ");
|
||||
log(">>>>>>>>>> " + message);
|
||||
log(">>>>>>>>>> ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the writer, if not already closed.
|
||||
*/
|
||||
public void close() {
|
||||
if (open) {
|
||||
writer.close();
|
||||
open = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the resource label and URI for output in a message.
|
||||
*/
|
||||
private String showResource(Resource resource) {
|
||||
return "On resource '" + getLabel(resource) + "' (" + getUri(resource)
|
||||
+ "), ";
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the URI for this resource, if there is one.
|
||||
*/
|
||||
private String getUri(Resource resource) {
|
||||
if (resource != null) {
|
||||
String uri = resource.getURI();
|
||||
if (uri != null) {
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
return "no URI";
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the label for this resource, if there is one.
|
||||
*/
|
||||
private String getLabel(Resource resource) {
|
||||
if (resource != null) {
|
||||
Model model = resource.getModel();
|
||||
if (model != null) {
|
||||
Property prop = model.createProperty(VitroVocabulary.LABEL);
|
||||
Statement stmt = resource.getProperty(prop);
|
||||
if (stmt != null) {
|
||||
RDFNode node = stmt.getObject();
|
||||
if (node.isLiteral()) {
|
||||
return ((Literal) node).getString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "no label";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,352 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.query.Query;
|
||||
import com.hp.hpl.jena.query.QueryExecution;
|
||||
import com.hp.hpl.jena.query.QueryExecutionFactory;
|
||||
import com.hp.hpl.jena.query.QueryFactory;
|
||||
import com.hp.hpl.jena.query.QuerySolution;
|
||||
import com.hp.hpl.jena.query.ResultSet;
|
||||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
|
||||
/**
|
||||
* Check all of the FileByteStream objects. If there are any that don't have
|
||||
* alias URLs, fix them.
|
||||
*/
|
||||
public class FileStorageAliasAdder {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(FileStorageAliasAdder.class);
|
||||
|
||||
private static final String FILE_PATH = "/file/";
|
||||
|
||||
/**
|
||||
* Query: get all bytestream resources that do not have alias URLs.
|
||||
*/
|
||||
private static final String QUERY_BYTESTREAMS_WITHOUT_ALIASES = ""
|
||||
+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
|
||||
+ "PREFIX public: <http://vitro.mannlib.cornell.edu/ns/vitro/public#>\n"
|
||||
+ "SELECT ?bs\n" + "WHERE {\n"
|
||||
+ " ?bs rdf:type public:FileByteStream\n"
|
||||
+ " OPTIONAL { ?bs public:directDownloadUrl ?alias }\n"
|
||||
+ " FILTER ( !BOUND(?alias) )\n" + "}\n";
|
||||
|
||||
/**
|
||||
* Query: get the filenames for all bytestream resources that do not have
|
||||
* alias URLs.
|
||||
*/
|
||||
private static final String QUERY_FILENAMES_FOR_BYTESTREAMS = ""
|
||||
+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
|
||||
+ "PREFIX public: <http://vitro.mannlib.cornell.edu/ns/vitro/public#>\n"
|
||||
+ "SELECT ?bs ?fn\n" + "WHERE {\n"
|
||||
+ " ?bs rdf:type public:FileByteStream . \n"
|
||||
+ " ?f public:downloadLocation ?bs . \n"
|
||||
+ " ?f public:filename ?fn . \n"
|
||||
+ " OPTIONAL { ?bs public:directDownloadUrl ?alias . }\n"
|
||||
+ " FILTER ( !BOUND(?alias) )\n" + "}\n";
|
||||
|
||||
private final Model model;
|
||||
private final File upgradeDirectory;
|
||||
private final String vivoDefaultNamespace;
|
||||
|
||||
private FSULog updateLog;
|
||||
|
||||
private Set<String> bytestreamUrisWithoutAliases;
|
||||
private Map<String, String> bytestreamUrisAndFilenames;
|
||||
|
||||
public FileStorageAliasAdder(Model model, File uploadDirectory,
|
||||
String vivoDefaultNamespace) {
|
||||
this.model = model;
|
||||
this.upgradeDirectory = new File(uploadDirectory, "upgrade");
|
||||
this.vivoDefaultNamespace = vivoDefaultNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through all of the FileByteStream objects in the model, creating Alias
|
||||
* URLs for any objects that don't have them.
|
||||
*
|
||||
* If there is nothing to do, don't even create a log file, just exit.
|
||||
*
|
||||
* If there is something to do, go through the whole process.
|
||||
*
|
||||
* At the end, there should be nothing to do.
|
||||
*/
|
||||
public void update() {
|
||||
// If there is nothing to do, we're done: don't even create a log file.
|
||||
if (!isThereAnythingToDo()) {
|
||||
log.debug("Found no FileByteStreams without alias URLs.");
|
||||
return;
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
try {
|
||||
findAndAddMissingAliasUrls();
|
||||
|
||||
if (isThereAnythingToDo()) {
|
||||
throw new IllegalStateException("FileStorageAliasAdder "
|
||||
+ "was unsuccessful -- model still contains "
|
||||
+ "FileByteStreams without alias URLs.");
|
||||
}
|
||||
|
||||
updateLog.section("Finished adding alias URLs to FileByteStreams.");
|
||||
} finally {
|
||||
updateLog.close();
|
||||
}
|
||||
|
||||
log.info("Finished adding alias URLs to FileByteStreams.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the model. If there are any FileByteStream objects with no Alias
|
||||
* URL, we have work to do.
|
||||
*/
|
||||
private boolean isThereAnythingToDo() {
|
||||
String queryString = QUERY_BYTESTREAMS_WITHOUT_ALIASES;
|
||||
log.debug("query: " + queryString);
|
||||
|
||||
QueryExecution qexec = null;
|
||||
try {
|
||||
qexec = createQueryExecutor(queryString);
|
||||
ResultSet results = qexec.execSelect();
|
||||
|
||||
boolean foundSome = results.hasNext();
|
||||
log.debug("any work to do? " + foundSome);
|
||||
|
||||
return foundSome;
|
||||
} catch (Exception e) {
|
||||
log.error(e, e);
|
||||
return false;
|
||||
} finally {
|
||||
if (qexec != null) {
|
||||
qexec.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the upgrade directory. Create the log file. If we fail, drop dead.
|
||||
*/
|
||||
private void setup() {
|
||||
try {
|
||||
this.upgradeDirectory.mkdirs();
|
||||
updateLog = new FSULog(this.upgradeDirectory,
|
||||
"FileStorageAliasAdder-log");
|
||||
log.info("Updating pre-1.1 file references. Log file is "
|
||||
+ updateLog.getFilename());
|
||||
} catch (IOException e) {
|
||||
if (updateLog != null) {
|
||||
updateLog.close();
|
||||
}
|
||||
throw new IllegalStateException("can't create log file: '"
|
||||
+ updateLog.getFilename() + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alias URL to any FileByteStream object that doesn't have one.
|
||||
*/
|
||||
private void findAndAddMissingAliasUrls() {
|
||||
findBytestreamsWithoutAliasUrls();
|
||||
findFilenamesForBytestreams();
|
||||
addAliasUrlsToModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find every bytestream that doesn't have an alias URL.
|
||||
*/
|
||||
private void findBytestreamsWithoutAliasUrls() {
|
||||
BytestreamUriUnpacker unpacker = new BytestreamUriUnpacker();
|
||||
|
||||
runQuery(QUERY_BYTESTREAMS_WITHOUT_ALIASES, unpacker);
|
||||
this.bytestreamUrisWithoutAliases = unpacker.getUris();
|
||||
|
||||
log.debug("Found " + unpacker.getUris().size()
|
||||
+ " bytestreams without alias URLs");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the filename for every bytestream that doesn't have an alias URL.
|
||||
*/
|
||||
private void findFilenamesForBytestreams() {
|
||||
FilenameUnpacker unpacker = new FilenameUnpacker();
|
||||
|
||||
runQuery(QUERY_FILENAMES_FOR_BYTESTREAMS, unpacker);
|
||||
this.bytestreamUrisAndFilenames = unpacker.getFilenameMap();
|
||||
|
||||
log.debug("Found " + unpacker.getFilenameMap().size()
|
||||
+ " bytestreams with filenames but no alias URLs");
|
||||
}
|
||||
|
||||
/** Add an alias URL to each resource in the list. */
|
||||
private void addAliasUrlsToModel() {
|
||||
if (this.bytestreamUrisWithoutAliases.isEmpty()) {
|
||||
updateLog.warn("Found no bytestreams without aliases. "
|
||||
+ "Why am I here?");
|
||||
return;
|
||||
}
|
||||
|
||||
Property aliasProperty = model
|
||||
.createProperty(VitroVocabulary.FS_ALIAS_URL);
|
||||
|
||||
for (String bytestreamUri : this.bytestreamUrisWithoutAliases) {
|
||||
String aliasUrl = figureAliasUrl(bytestreamUri);
|
||||
Resource resource = model.getResource(bytestreamUri);
|
||||
|
||||
ModelWrapper.add(model, resource, aliasProperty, aliasUrl);
|
||||
updateLog.log(resource, "added alias URL: '" + aliasUrl + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the bytestream URI and the filename into an alias URL.
|
||||
*
|
||||
* If they aren't in our default namespace, or they don't have a filename,
|
||||
* then their URI is the best we can do for an alias URL.
|
||||
*/
|
||||
private String figureAliasUrl(String bytestreamUri) {
|
||||
if (!bytestreamUri.startsWith(vivoDefaultNamespace)) {
|
||||
updateLog.warn("bytestream uri does not start "
|
||||
+ "with the default namespace: '" + bytestreamUri + "'");
|
||||
return bytestreamUri;
|
||||
}
|
||||
|
||||
String filename = this.bytestreamUrisAndFilenames.get(bytestreamUri);
|
||||
if (filename == null) {
|
||||
updateLog.warn("bytestream has no surrogate or no filename: '"
|
||||
+ bytestreamUri + "'");
|
||||
return "filename_not_found";
|
||||
}
|
||||
|
||||
try {
|
||||
String remainder = bytestreamUri.substring(vivoDefaultNamespace
|
||||
.length());
|
||||
String encodedFilename = URLEncoder.encode(filename, "UTF-8");
|
||||
String separator = remainder.endsWith("/") ? "" : "/";
|
||||
|
||||
return FILE_PATH + remainder + separator + encodedFilename;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException(e); // No UTF-8? Can't happen.
|
||||
}
|
||||
}
|
||||
|
||||
private void runQuery(String queryString, QueryResultUnpacker unpacker) {
|
||||
log.debug("query: " + queryString);
|
||||
|
||||
QueryExecution qexec = null;
|
||||
try {
|
||||
qexec = createQueryExecutor(queryString);
|
||||
|
||||
Iterator<QuerySolution> results = qexec.execSelect();
|
||||
while (results.hasNext()) {
|
||||
QuerySolution result = results.next();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Query result variables: "
|
||||
+ listVariables(result));
|
||||
}
|
||||
unpacker.unpack(result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e, e);
|
||||
} finally {
|
||||
if (qexec != null) {
|
||||
qexec.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private QueryExecution createQueryExecutor(String queryString) {
|
||||
Query query = QueryFactory.create(queryString);
|
||||
return QueryExecutionFactory.create(query, model);
|
||||
}
|
||||
|
||||
/** For debug logging. */
|
||||
private List<String> listVariables(QuerySolution result) {
|
||||
List<String> list = new ArrayList<String>();
|
||||
for (Iterator<String> names = result.varNames(); names.hasNext();) {
|
||||
String name = names.next();
|
||||
RDFNode value = result.get(name);
|
||||
list.add(name + "=" + value);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper classes
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private interface QueryResultUnpacker {
|
||||
public abstract void unpack(QuerySolution result);
|
||||
}
|
||||
|
||||
private class BytestreamUriUnpacker implements QueryResultUnpacker {
|
||||
private final Set<String> uris = new HashSet<String>();
|
||||
|
||||
@Override
|
||||
public void unpack(QuerySolution result) {
|
||||
Resource bytestream = result.getResource("bs");
|
||||
if (bytestream == null) {
|
||||
updateLog.error("Query result contains no "
|
||||
+ "bytestream resource: " + result);
|
||||
return;
|
||||
}
|
||||
|
||||
uris.add(bytestream.getURI());
|
||||
}
|
||||
|
||||
public Set<String> getUris() {
|
||||
return uris;
|
||||
}
|
||||
}
|
||||
|
||||
private class FilenameUnpacker implements QueryResultUnpacker {
|
||||
private final Map<String, String> filenameMap = new HashMap<String, String>();
|
||||
|
||||
@Override
|
||||
public void unpack(QuerySolution result) {
|
||||
Resource bytestream = result.getResource("bs");
|
||||
if (bytestream == null) {
|
||||
updateLog.error("Query result contains no "
|
||||
+ "bytestream resource: " + result);
|
||||
return;
|
||||
}
|
||||
String bytestreamUri = bytestream.getURI();
|
||||
|
||||
Literal filenameLiteral = result.getLiteral("fn");
|
||||
if (filenameLiteral == null) {
|
||||
updateLog.error("Query result for '" + bytestreamUri
|
||||
+ "' contains no filename.");
|
||||
return;
|
||||
}
|
||||
String filename = filenameLiteral.getString();
|
||||
|
||||
filenameMap.put(bytestreamUri, filename);
|
||||
}
|
||||
|
||||
public Map<String, String> getFilenameMap() {
|
||||
return filenameMap;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,268 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.UploadedFileHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Clean up any files that are stored in the old directory structure and
|
||||
* referenced by old-style image properties.
|
||||
* </p>
|
||||
* <p>
|
||||
* Besides converting the files to the new framework, this process will produce
|
||||
* these artifacts:
|
||||
* <ul>
|
||||
* <li>A log file in the uploaded files directory, with a timestamped name, such
|
||||
* as <code>upgrade/upgradeLog2010-06-20T14-55-00.txt</code>, for example. If
|
||||
* for any reason, the upgrade process must run again, the log will not be
|
||||
* overwritten.</li>
|
||||
* <li>A directory of "deleted" files - these were extra thumbnail files or
|
||||
* extra main image files -- see the details below.</li>
|
||||
* <li>A directory of "unreferenced" files - these were in the image directory,
|
||||
* but not connected to any entity.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* We consider some special cases:
|
||||
* <ul>
|
||||
* <li>An individual may refer to an image file that does not actually exist. If
|
||||
* so, that reference will be deleted.</li>
|
||||
* <li>There may be more than one reference to the same image file. If so, all
|
||||
* but the first such reference will be deleted.</li>
|
||||
* <li>
|
||||
* In the old style, it was possible to have a main image without a thumbnail.
|
||||
* If we find that, we will generate a scaled down copy of the main image, store
|
||||
* that as a thumbnail image file, and then proceed.</li>
|
||||
* <li>
|
||||
* In the old style, it was possible to have a thumbnail without a main image.
|
||||
* If we find that, we will make a copy of the thumbnail image file, declare
|
||||
* that copy to be the main image, and then proceed.</li>
|
||||
* <li>
|
||||
* We may find individuals with more than one main image, or more than one
|
||||
* thumbnail. If so, we will discard all but the first one (move them to the
|
||||
* "deleted" directory).</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* Aside from these special cases, we will:
|
||||
* <ul>
|
||||
* <li>Translate the main image.
|
||||
* <ul>
|
||||
* <li>Store the image in the new file system.</li>
|
||||
* <li>Delete the image from the old images directory.</li>
|
||||
* <li>Create a ByteStream individual for the main image.</li>
|
||||
* <li>Create a Surrogate individual for the main image.</li>
|
||||
* <li>Tie these together and attach to the entity that owns the image.</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>Translate the thumbnail.
|
||||
* <ul>
|
||||
* <li>Store the thumbnail in the new file system.</li>
|
||||
* <li>Create a ByteStream individual for the thumbnail.</li>
|
||||
* <li>Create a Surrogate individual for the thumbnail.</li>
|
||||
* <li>Tie these together and attach to the Surrogate for the main image.</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* After processing all of these cases, there may be some images remaining in
|
||||
* the "images" directory. These will be moved to the "unreferenced" directory,
|
||||
* while preserving any internal tree structure.
|
||||
* </p>
|
||||
*/
|
||||
public class FileStorageUpdater implements FSUController {
|
||||
private static final Log log = LogFactory.getLog(FileStorageUpdater.class);
|
||||
|
||||
/** How wide should a generated thumbnail image be (in pixels)? */
|
||||
public static final int THUMBNAIL_WIDTH = 200;
|
||||
|
||||
/** How high should a generated thumbnail image be (in pixels)? */
|
||||
public static final int THUMBNAIL_HEIGHT = 200;
|
||||
|
||||
/** How is the main image referenced in the old scheme? */
|
||||
public static final String IMAGEFILE = VitroVocabulary.vitroURI
|
||||
+ "imageFile";
|
||||
|
||||
/** How is the thumbnail referenced in the old scheme? */
|
||||
public static final String IMAGETHUMB = VitroVocabulary.vitroURI
|
||||
+ "imageThumb";
|
||||
|
||||
private final Model model;
|
||||
|
||||
private final FileStorage fileStorage;
|
||||
private final UploadedFileHelper uploadedFileHelper;
|
||||
private final ImageDirectoryWithBackup imageDirectoryWithBackup;
|
||||
private final File upgradeDirectory;
|
||||
|
||||
private FSULog updateLog;
|
||||
|
||||
public FileStorageUpdater(WebappDaoFactory wadf, Model model,
|
||||
FileStorage fileStorage, File uploadDirectory,
|
||||
File webappImageDirectory, ServletContext ctx) {
|
||||
this.model = model;
|
||||
this.fileStorage = fileStorage;
|
||||
this.uploadedFileHelper = new UploadedFileHelper(fileStorage, wadf, ctx);
|
||||
this.upgradeDirectory = new File(uploadDirectory, "upgrade");
|
||||
|
||||
this.imageDirectoryWithBackup = new ImageDirectoryWithBackup(new File(
|
||||
uploadDirectory, "images"), webappImageDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Go through all of the individuals who have image files or thumbnail
|
||||
* files, adjusting them to the new way.
|
||||
* </p>
|
||||
* <p>
|
||||
* If there is nothing to do, don't even create a log file, just exit.
|
||||
* </p>
|
||||
* <p>
|
||||
* If there is something to do, go through the whole process.
|
||||
* </p>
|
||||
* <p>
|
||||
* At the end, there should be nothing to do. If that's true, clean out the
|
||||
* old images directory.
|
||||
* </p>
|
||||
*/
|
||||
public void update() {
|
||||
// If there is nothing to do, we're done: don't even create a log file.
|
||||
if (!isThereAnythingToDo()) {
|
||||
log.debug("Found no pre-1.1 file references.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the upgrade directory and the log file.
|
||||
setup();
|
||||
|
||||
try {
|
||||
// Remove any image properties that don't point to literals.
|
||||
new NonLiteralPropertyRemover(this).remove();
|
||||
|
||||
// Remove any image properties that point to files that don't exist.
|
||||
new DeadEndPropertyRemover(this).remove();
|
||||
|
||||
// No resource may have multiple main images or multiple thumbnails.
|
||||
new MultiplePropertyRemover(this).remove();
|
||||
|
||||
// Create a main image for any thumbnail that doesn't have one.
|
||||
new AllThumbsAdjuster(this).adjust();
|
||||
|
||||
// Create a thumbnail for any main image that doesn't have one.
|
||||
new NoThumbsAdjuster(this).adjust();
|
||||
|
||||
// Copy all images into the new file storage system, translating
|
||||
// into the new schema. Get a list of all the images we translated.
|
||||
ImageSchemaTranslater translater = new ImageSchemaTranslater(this);
|
||||
Collection<String> translatedFiles = translater.translate();
|
||||
|
||||
if (isThereAnythingToDo()) {
|
||||
throw new IllegalStateException(
|
||||
"FileStorageUpdate was unsuccessful -- "
|
||||
+ "model still contains pre-1.1 file references.");
|
||||
}
|
||||
|
||||
// Clean out the old image directory, separating into files which
|
||||
// were translated, and files for which we found no reference.
|
||||
new ImageDirectoryCleaner(this).clean(translatedFiles);
|
||||
|
||||
updateLog.section("File Storage update is complete.");
|
||||
} finally {
|
||||
updateLog.close();
|
||||
}
|
||||
|
||||
log.info("Finished updating pre-1.1 file references.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the model. If there are any resources with old-style image
|
||||
* properties, we have work to do.
|
||||
*/
|
||||
private boolean isThereAnythingToDo() {
|
||||
if (!ModelWrapper.listResourcesWithProperty(model,
|
||||
model.createProperty(IMAGEFILE)).isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ModelWrapper.listResourcesWithProperty(model,
|
||||
model.createProperty(IMAGETHUMB)).isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the upgrade directory. Create the log file. If we fail, drop dead.
|
||||
*/
|
||||
private void setup() {
|
||||
try {
|
||||
this.upgradeDirectory.mkdirs();
|
||||
updateLog = new FSULog(this.upgradeDirectory,
|
||||
"FileStorageUpdater-log");
|
||||
log.info("Updating pre-1.1 file references. Log file is "
|
||||
+ updateLog.getFilename());
|
||||
} catch (IOException e) {
|
||||
if (updateLog != null) {
|
||||
updateLog.close();
|
||||
}
|
||||
throw new IllegalStateException("can't create log file: '"
|
||||
+ updateLog.getFilename() + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Methods to set up the individual scanners.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public Model getModel() {
|
||||
return this.model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FSULog getUpdateLog() {
|
||||
return this.updateLog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UploadedFileHelper getUploadedFileHelper() {
|
||||
return this.uploadedFileHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileStorage getFileStorage() {
|
||||
return this.fileStorage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageDirectoryWithBackup getImageDirectoryWithBackup() {
|
||||
return this.imageDirectoryWithBackup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getTranslatedDirectory() {
|
||||
return new File(this.upgradeDirectory, "translatedImages");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getUnreferencedDirectory() {
|
||||
return new File(this.upgradeDirectory, "unreferencedImages");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A collection of static routines for moving, copying and deleting files.
|
||||
*/
|
||||
public class FileUtil {
|
||||
/**
|
||||
* Copy a file from one location to another, and remove it from the original
|
||||
* location.
|
||||
*/
|
||||
public static void moveFile(File from, File to) throws IOException {
|
||||
copyFile(from, to);
|
||||
deleteFile(from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a file from one location to another.
|
||||
*/
|
||||
public static void copyFile(File from, File to) throws IOException {
|
||||
if (!from.exists()) {
|
||||
throw new FileNotFoundException("File '" + from.getAbsolutePath()
|
||||
+ "' does not exist.");
|
||||
}
|
||||
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(from);
|
||||
writeFile(in, to);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file with the contents of this data stream.
|
||||
*
|
||||
* @param stream
|
||||
* the data stream. You must close it afterward.
|
||||
*/
|
||||
public static void writeFile(InputStream stream, File to)
|
||||
throws IOException {
|
||||
if (to.exists()) {
|
||||
throw new IOException("File '" + to.getAbsolutePath()
|
||||
+ "' already exists.");
|
||||
}
|
||||
|
||||
File parent = to.getParentFile();
|
||||
if (!parent.exists()) {
|
||||
parent.mkdirs();
|
||||
if (!parent.exists()) {
|
||||
throw new IOException("Can't create parent directory for '"
|
||||
+ to.getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(to);
|
||||
byte[] buffer = new byte[8192];
|
||||
int howMany;
|
||||
while (-1 != (howMany = stream.read(buffer))) {
|
||||
out.write(buffer, 0, howMany);
|
||||
}
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this file, and make sure that it's gone.
|
||||
*/
|
||||
public static void deleteFile(File file) throws IOException {
|
||||
file.delete();
|
||||
if (file.exists()) {
|
||||
throw new IOException("Failed to delete file '"
|
||||
+ file.getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/** No need to instantiate it -- all methods are static. */
|
||||
private FileUtil() {
|
||||
// Nothing to instantiate.
|
||||
}
|
||||
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
import com.hp.hpl.jena.rdf.model.StmtIterator;
|
||||
import com.hp.hpl.jena.shared.Lock;
|
||||
|
||||
/**
|
||||
* Base class for the tools that scan the model. Holds some useful fields and
|
||||
* some utility methods.
|
||||
*/
|
||||
public abstract class FsuScanner {
|
||||
protected final Model model;
|
||||
protected final FSULog updateLog;
|
||||
|
||||
protected final Property imageProperty;
|
||||
protected final Property thumbProperty;
|
||||
|
||||
public FsuScanner(FSUController controller) {
|
||||
this.model = controller.getModel();
|
||||
this.updateLog = controller.getUpdateLog();
|
||||
|
||||
this.imageProperty = model.createProperty(FileStorageUpdater.IMAGEFILE);
|
||||
this.thumbProperty = model
|
||||
.createProperty(FileStorageUpdater.IMAGETHUMB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all of the specified properties on a resource, and return a
|
||||
* {@link List} of the {@link String} values.
|
||||
*/
|
||||
protected List<String> getValues(Resource resource, Property property) {
|
||||
List<String> list = new ArrayList<String>();
|
||||
StmtIterator stmts = resource.listProperties(property);
|
||||
try {
|
||||
while (stmts.hasNext()) {
|
||||
Statement stmt = stmts.next();
|
||||
RDFNode object = stmt.getObject();
|
||||
if (object.isLiteral()) {
|
||||
list.add(((Literal) object).getString());
|
||||
} else {
|
||||
updateLog.error(resource,
|
||||
"property value was not a literal: "
|
||||
+ "property is '" + property.getURI()
|
||||
+ "', value is '" + object + "'");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
stmts.close();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all of the specified properties on a resource, and return a
|
||||
* {@link List} of the {@link Statement}s.
|
||||
*/
|
||||
protected List<Statement> getStatements(Resource resource, Property property) {
|
||||
List<Statement> list = new ArrayList<Statement>();
|
||||
|
||||
resource.getModel().enterCriticalSection(Lock.READ);
|
||||
StmtIterator stmts = resource.listProperties(property);
|
||||
try {
|
||||
while (stmts.hasNext()) {
|
||||
list.add(stmts.next());
|
||||
}
|
||||
} finally {
|
||||
stmts.close();
|
||||
resource.getModel().leaveCriticalSection();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the filename within a path so we can add this prefix to it, while
|
||||
* retaining the path.
|
||||
*/
|
||||
protected String addFilenamePrefix(String prefix, String path) {
|
||||
int slashHere = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
|
||||
if (slashHere == -1) {
|
||||
return prefix + path;
|
||||
} else {
|
||||
String dirs = path.substring(0, slashHere + 1);
|
||||
String filename = path.substring(slashHere + 1);
|
||||
return dirs + prefix + filename;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We are about to create a file - if a file of this name already exists,
|
||||
* increment the name until we have no collision.
|
||||
*
|
||||
* @return the original file, or the file with the incremented name.
|
||||
*/
|
||||
protected File checkNameConflicts(final File file) {
|
||||
if (!file.exists()) {
|
||||
// No conflict.
|
||||
return file;
|
||||
}
|
||||
|
||||
File parent = file.getParentFile();
|
||||
String filename = file.getName();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
File newFile = new File(parent, i + filename);
|
||||
if (!newFile.exists()) {
|
||||
updateLog.log("File '" + file + "' already exists, using '"
|
||||
+ newFile + "' to avoid conflict.");
|
||||
return newFile;
|
||||
}
|
||||
}
|
||||
|
||||
updateLog.error("File '" + file
|
||||
+ "' already exists. Unable to avoid conflict.");
|
||||
return file;
|
||||
}
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Clean out the old image directory. Copy the files into the upgrade directory,
|
||||
* separating into the ones that we translated, and the ones that weren't
|
||||
* referenced.
|
||||
*/
|
||||
public class ImageDirectoryCleaner extends FsuScanner {
|
||||
private final ImageDirectoryWithBackup imageDirectoryWithBackup;
|
||||
protected final File translatedDirectory;
|
||||
protected final File unreferencedDirectory;
|
||||
|
||||
public ImageDirectoryCleaner(FSUController controller) {
|
||||
super(controller);
|
||||
this.imageDirectoryWithBackup = controller
|
||||
.getImageDirectoryWithBackup();
|
||||
|
||||
this.translatedDirectory = controller.getTranslatedDirectory();
|
||||
this.unreferencedDirectory = controller.getUnreferencedDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all of the files from the old image directory.
|
||||
*/
|
||||
public void clean(Collection<String> translatedFiles) {
|
||||
updateLog.section("Cleaning the old image directory of "
|
||||
+ "files that were translated.");
|
||||
removeTranslatedFiles(translatedFiles);
|
||||
|
||||
updateLog.section("Cleaning the old image directory of "
|
||||
+ "files that were not referenced.");
|
||||
removeRemainingFiles(imageDirectoryWithBackup
|
||||
.getPrimaryImageDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Move all of the files that we translated into the new system.
|
||||
*/
|
||||
private void removeTranslatedFiles(Collection<String> translatedFiles) {
|
||||
for (String path : translatedFiles) {
|
||||
File oldFile = new File(
|
||||
imageDirectoryWithBackup.getPrimaryImageDirectory(), path);
|
||||
if (oldFile.exists()) {
|
||||
updateLog.log("moving image file '" + path
|
||||
+ "' to the 'translated' directory.");
|
||||
File deletedFile = new File(translatedDirectory, path);
|
||||
try {
|
||||
FileUtil.moveFile(oldFile, deletedFile);
|
||||
} catch (IOException e) {
|
||||
updateLog.error("Failed to move translated file '"
|
||||
+ oldFile.getAbsolutePath() + "'");
|
||||
}
|
||||
} else {
|
||||
updateLog.log("Not moving image file '" + path
|
||||
+ "' to the 'translated' directory -- "
|
||||
+ "found it in the backup directory.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through the images directory, and discard any that remain. They must
|
||||
* not have been referenced by any existing individuals.
|
||||
*/
|
||||
private void removeRemainingFiles(File directory) {
|
||||
updateLog.log("Cleaning image directory '" + directory + "'");
|
||||
try {
|
||||
File targetDirectory = makeCorrespondingDirectory(directory);
|
||||
File[] children = directory.listFiles();
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
if (child.isDirectory()) {
|
||||
removeRemainingFiles(child);
|
||||
} else {
|
||||
moveUnreferencedFile(targetDirectory, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
updateLog.error(
|
||||
"Failed to clean images directory '"
|
||||
+ directory.getAbsolutePath() + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move this file from its current location to its new home in the
|
||||
* "unreferenced" directory. Log it.
|
||||
*/
|
||||
private void moveUnreferencedFile(File targetDirectory, File file) {
|
||||
updateLog.log("Moving image file '" + file.getPath()
|
||||
+ "' to the 'unreferenced' directory");
|
||||
try {
|
||||
File newFile = new File(targetDirectory, file.getName());
|
||||
FileUtil.moveFile(file, newFile);
|
||||
} catch (IOException e) {
|
||||
updateLog.error(
|
||||
"Can't move unreferenced file '" + file.getAbsolutePath()
|
||||
+ "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Figure out the path from the "images" directory to this one, and create a
|
||||
* corresponding directory in the "unreferenced" area.
|
||||
*/
|
||||
private File makeCorrespondingDirectory(File directory) throws IOException {
|
||||
String imagesPath = imageDirectoryWithBackup.getPrimaryImageDirectory()
|
||||
.getAbsolutePath();
|
||||
String thisPath = directory.getAbsolutePath();
|
||||
|
||||
if (!thisPath.startsWith(imagesPath)) {
|
||||
throw new IOException("Can't make a corresponding directory for '"
|
||||
+ thisPath + "'");
|
||||
}
|
||||
|
||||
String suffix = thisPath.substring(imagesPath.length());
|
||||
|
||||
File corresponding = new File(unreferencedDirectory, suffix);
|
||||
corresponding.mkdirs();
|
||||
if (!corresponding.exists()) {
|
||||
throw new IOException("Failed to create corresponding directory '"
|
||||
+ corresponding.getAbsolutePath() + "'");
|
||||
}
|
||||
|
||||
return corresponding;
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* A way to look for files in TOMCAT_WEBAPP/vivo/images, if they are not found
|
||||
* in upload.directory/images.
|
||||
*/
|
||||
public class ImageDirectoryWithBackup {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(ImageDirectoryWithBackup.class);
|
||||
|
||||
/** The primary image directory, where we do most of the manipulation. */
|
||||
private final File uploadImageDirectory;
|
||||
|
||||
/**
|
||||
* If we are looking for a file and don't find it in the primary directory,
|
||||
* look for it here.
|
||||
*/
|
||||
private final File webappImageDirectory;
|
||||
|
||||
/**
|
||||
* Be careful! webappImageDirectory may be null.
|
||||
*/
|
||||
public ImageDirectoryWithBackup(File uploadImageDirectory,
|
||||
File webappImageDirectory) {
|
||||
this.uploadImageDirectory = uploadImageDirectory;
|
||||
this.webappImageDirectory = webappImageDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* When looking to read a file, start by looking in the
|
||||
* {@link #uploadImageDirectory}.
|
||||
*
|
||||
* If the file isn't found there, look in the {@link #webappImageDirectory}
|
||||
* as a fallback.
|
||||
*
|
||||
* If not there either, return the pointer to the nonexistent file in the
|
||||
* {@link #uploadImageDirectory}.
|
||||
*/
|
||||
File getExistingFile(String relativePath) {
|
||||
File file1 = new File(uploadImageDirectory, relativePath);
|
||||
if (file1.exists()) {
|
||||
log.trace("Found file: " + file1.getAbsolutePath());
|
||||
return file1;
|
||||
}
|
||||
if (webappImageDirectory != null) {
|
||||
File file2 = new File(webappImageDirectory, relativePath);
|
||||
if (file2.exists()) {
|
||||
log.trace("Found file: " + file2.getAbsolutePath());
|
||||
return file2;
|
||||
}
|
||||
}
|
||||
log.trace("Didn't find file: " + file1.getAbsolutePath());
|
||||
return file1;
|
||||
}
|
||||
|
||||
/**
|
||||
* New files will always be created in the primary directory.
|
||||
*/
|
||||
File getNewfile(String relativePath) {
|
||||
return new File(uploadImageDirectory, relativePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* You can get a direct reference to the primary image directory, but it
|
||||
* should only be used for directory-base operations, like final cleanup.
|
||||
*/
|
||||
public File getPrimaryImageDirectory() {
|
||||
return uploadImageDirectory;
|
||||
}
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.ResIterator;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.UploadedFileHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
||||
|
||||
/**
|
||||
* Make copies of the main image and thumbnail in the new file storage system,
|
||||
* and in the model. Remove the old properties, but don't remove the old files
|
||||
* yet, in case someone else is referring to them also.
|
||||
*/
|
||||
public class ImageSchemaTranslater extends FsuScanner {
|
||||
private final ImageDirectoryWithBackup imageDirectoryWithBackup;
|
||||
protected final FileStorage fileStorage;
|
||||
protected final UploadedFileHelper uploadedFileHelper;
|
||||
|
||||
public ImageSchemaTranslater(FSUController controller) {
|
||||
super(controller);
|
||||
this.imageDirectoryWithBackup = controller
|
||||
.getImageDirectoryWithBackup();
|
||||
this.fileStorage = controller.getFileStorage();
|
||||
this.uploadedFileHelper = controller.getUploadedFileHelper();
|
||||
}
|
||||
|
||||
/**
|
||||
* By the time we get here, any individual with a main image also has a
|
||||
* thumbnail, and vice versa, and exactly one of each. For each one,
|
||||
* translate the main image and the thumbnail into the new system.
|
||||
*/
|
||||
public Collection<String> translate() {
|
||||
updateLog.section("Copying images into the new file storage, "
|
||||
+ "and adding them to the new model.");
|
||||
|
||||
SortedSet<String> translated = new TreeSet<String>();
|
||||
ResIterator haveImage = model.listResourcesWithProperty(imageProperty);
|
||||
try {
|
||||
while (haveImage.hasNext()) {
|
||||
Resource resource = haveImage.next();
|
||||
translateImages(resource, translated);
|
||||
}
|
||||
} finally {
|
||||
haveImage.close();
|
||||
}
|
||||
return translated;
|
||||
}
|
||||
|
||||
/**
|
||||
* This individual should have exactly one main image and exactly one
|
||||
* thumbnail.
|
||||
* <ul>
|
||||
* <li>Translate the first main image into the new system.</li>
|
||||
* <li>Translate the first thumbnail into the new system.</li>
|
||||
* <li>Remove all old-style main image properties.</li>
|
||||
* <li>Remove all old-style thumbnail properties.</li>
|
||||
* </ul>
|
||||
*/
|
||||
private void translateImages(Resource resource,
|
||||
Collection<String> translated) {
|
||||
List<String> mainImages = getValues(resource, imageProperty);
|
||||
if (mainImages.size() != 1) {
|
||||
updateLog.error(resource, "has " + mainImages.size()
|
||||
+ " main images: " + mainImages);
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> thumbnails = getValues(resource, thumbProperty);
|
||||
if (thumbnails.size() != 1) {
|
||||
updateLog.error(resource, "has " + thumbnails.size()
|
||||
+ " thumbnails: " + thumbnails);
|
||||
return;
|
||||
}
|
||||
|
||||
FileInfo main = translateFile(resource, mainImages.get(0), "main image");
|
||||
FileInfo thumb = translateFile(resource, thumbnails.get(0), "thumbnail");
|
||||
if ((main == null) || (thumb == null)) {
|
||||
return;
|
||||
}
|
||||
uploadedFileHelper.setImagesOnEntity(resource.getURI(), main, thumb);
|
||||
|
||||
translated.add(mainImages.get(0));
|
||||
ResourceWrapper.removeAll(resource, imageProperty);
|
||||
|
||||
translated.add(thumbnails.get(0));
|
||||
ResourceWrapper.removeAll(resource, thumbProperty);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an image file into the new system
|
||||
* <ul>
|
||||
* <li>Attempt to infer MIME type.</li>
|
||||
* <li>Copy into the File system.</li>
|
||||
* <li>Create the File and Bytestream individuals in the model.</li>
|
||||
* </ul>
|
||||
*/
|
||||
private FileInfo translateFile(Resource resource, String path, String label) {
|
||||
File oldFile = imageDirectoryWithBackup.getExistingFile(path);
|
||||
String filename = getSimpleFilename(path);
|
||||
String mimeType = guessMimeType(resource, filename);
|
||||
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = new FileInputStream(oldFile);
|
||||
// Create the file individuals in the model
|
||||
FileInfo fileInfo = uploadedFileHelper.createFile(filename,
|
||||
mimeType, inputStream);
|
||||
updateLog.log(resource, "translating " + label + " '" + path
|
||||
+ "' into the file storage as '" + fileInfo.getUri() + "'");
|
||||
return fileInfo;
|
||||
} catch (IOException e) {
|
||||
updateLog.error(resource, "Can't create the " + label + " file. ",
|
||||
e);
|
||||
return null;
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any path parts, and just get the filename and extension.
|
||||
*/
|
||||
private String getSimpleFilename(String path) {
|
||||
return FilenameUtils.getName(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess what the MIME type might be.
|
||||
*/
|
||||
private String guessMimeType(Resource resource, String filename) {
|
||||
if (filename.endsWith(".gif") || filename.endsWith(".GIF")) {
|
||||
return "image/gif";
|
||||
} else if (filename.endsWith(".png") || filename.endsWith(".PNG")) {
|
||||
return "image/png";
|
||||
} else if (filename.endsWith(".jpg") || filename.endsWith(".JPG")) {
|
||||
return "image/jpeg";
|
||||
} else if (filename.endsWith(".jpeg") || filename.endsWith(".JPEG")) {
|
||||
return "image/jpeg";
|
||||
} else if (filename.endsWith(".jpe") || filename.endsWith(".JPE")) {
|
||||
return "image/jpeg";
|
||||
} else {
|
||||
updateLog.warn(resource,
|
||||
"can't recognize the MIME type of this image file: '"
|
||||
+ filename + "'");
|
||||
return "image";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.ResIterator;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
import com.hp.hpl.jena.shared.Lock;
|
||||
|
||||
/**
|
||||
* Utility methods that operate against the Model with proper locks.
|
||||
*/
|
||||
public class ModelWrapper {
|
||||
|
||||
public static Collection<Resource> listResourcesWithProperty(Model model,
|
||||
Property property) {
|
||||
List<Resource> list = new ArrayList<Resource>();
|
||||
ResIterator iterator = model.listResourcesWithProperty(property);
|
||||
try {
|
||||
while (iterator.hasNext()) {
|
||||
Resource resource = iterator.next();
|
||||
list.add(resource);
|
||||
}
|
||||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void removeStatement(Model model, Statement stmt) {
|
||||
model.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
model.remove(stmt);
|
||||
} finally {
|
||||
model.leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
||||
public static void add(Model model, Resource subject, Property predicate,
|
||||
String value) {
|
||||
model.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
model.add(subject, predicate, value);
|
||||
} finally {
|
||||
model.leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
|
||||
/**
|
||||
* If a resource has more than one image or more than one thumbnail, this
|
||||
* discards the extras.
|
||||
*/
|
||||
public class MultiplePropertyRemover extends FsuScanner {
|
||||
|
||||
public MultiplePropertyRemover(FSUController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* By now, we have removed any non-literals or dead ends, so keep the first
|
||||
* one and discard any extras.
|
||||
*/
|
||||
public void remove() {
|
||||
updateLog.section("Checking for resources with more "
|
||||
+ "than one main image, or more than one thumbnail.");
|
||||
|
||||
removeExtraProperties(imageProperty, "main image");
|
||||
removeExtraProperties(thumbProperty, "thumbnail");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check each resource that has this property.
|
||||
*/
|
||||
public void removeExtraProperties(Property prop, String label) {
|
||||
for (Resource resource : ModelWrapper.listResourcesWithProperty(model,
|
||||
prop)) {
|
||||
removeExtraProperties(resource, prop, label);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this resource has more than one of this property, delete the extras.
|
||||
*/
|
||||
private void removeExtraProperties(Resource resource, Property prop,
|
||||
String label) {
|
||||
List<Statement> stmts = getStatements(resource, prop);
|
||||
for (int i = 1; i < stmts.size(); i++) {
|
||||
Statement stmt = stmts.get(i);
|
||||
RDFNode node = stmt.getObject();
|
||||
if (node.isLiteral()) {
|
||||
String value = ((Literal) node).getString();
|
||||
updateLog.warn(resource, "removing extra " + label
|
||||
+ " property: '" + value + "'");
|
||||
} else {
|
||||
updateLog.warn(resource, "removing extra " + label
|
||||
+ " property: '" + node + "'");
|
||||
}
|
||||
ModelWrapper.removeStatement(model, stmt);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.THUMBNAIL_HEIGHT;
|
||||
import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.THUMBNAIL_WIDTH;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.media.jai.JAI;
|
||||
import javax.media.jai.RenderedOp;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.sun.media.jai.codec.MemoryCacheSeekableStream;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.CropRectangle;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadThumbnailer;
|
||||
|
||||
/**
|
||||
* Adjust any individual that has a main image but no thumbnail.
|
||||
*/
|
||||
public class NoThumbsAdjuster extends FsuScanner {
|
||||
private ImageDirectoryWithBackup imageDirectoryWithBackup;
|
||||
|
||||
public NoThumbsAdjuster(FSUController controller) {
|
||||
super(controller);
|
||||
this.imageDirectoryWithBackup = controller
|
||||
.getImageDirectoryWithBackup();
|
||||
}
|
||||
|
||||
/**
|
||||
* For every individual with main images but no thumbnails, create a
|
||||
* thumbnail from the first main image.
|
||||
*/
|
||||
public void adjust() {
|
||||
updateLog.section("Creating thumbnails to match main images.");
|
||||
|
||||
for (Resource resource : ModelWrapper.listResourcesWithProperty(model,
|
||||
imageProperty)) {
|
||||
if (resource.getProperty(thumbProperty) == null) {
|
||||
createThumbnailFromMainImage(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This individual has a main image but no thumbnail. Create one.
|
||||
* <ul>
|
||||
* <li>Figure a name for the thumbnail image.</li>
|
||||
* <li>Make a scaled copy of the main image into the thumbnail.</li>
|
||||
* <li>Set that file as a thumbnail (old-style) on the individual.</li>
|
||||
* </ul>
|
||||
*/
|
||||
private void createThumbnailFromMainImage(Resource resource) {
|
||||
String mainFilename = getValues(resource, imageProperty).get(0);
|
||||
String thumbFilename = addFilenamePrefix("_thumbnail_", mainFilename);
|
||||
updateLog.log(resource, "creating a thumbnail at '" + thumbFilename
|
||||
+ "' from the main image at '" + mainFilename + "'");
|
||||
|
||||
File mainFile = imageDirectoryWithBackup.getExistingFile(mainFilename);
|
||||
File thumbFile = imageDirectoryWithBackup.getNewfile(thumbFilename);
|
||||
thumbFile = checkNameConflicts(thumbFile);
|
||||
|
||||
try {
|
||||
CropRectangle crop = getImageSize(mainFile);
|
||||
if (imageIsSmallEnoughAlready(crop)) {
|
||||
copyMainImageToThumbnail(mainFile, thumbFile);
|
||||
} else {
|
||||
cropScaleAndStore(crop, mainFile, thumbFile);
|
||||
}
|
||||
|
||||
ResourceWrapper.addProperty(resource, thumbProperty, thumbFilename);
|
||||
} catch (IOException e) {
|
||||
updateLog.error(resource, "failed to create thumbnail file '"
|
||||
+ thumbFilename + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
private CropRectangle getImageSize(File file) throws IOException {
|
||||
InputStream imageSource = null;
|
||||
try {
|
||||
imageSource = new FileInputStream(file);
|
||||
MemoryCacheSeekableStream stream = new MemoryCacheSeekableStream(
|
||||
imageSource);
|
||||
RenderedOp image = JAI.create("stream", stream);
|
||||
return new CropRectangle(0, 0, image.getHeight(), image.getWidth());
|
||||
} finally {
|
||||
if (imageSource != null) {
|
||||
try {
|
||||
imageSource.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean imageIsSmallEnoughAlready(CropRectangle crop) {
|
||||
return (crop.height <= THUMBNAIL_HEIGHT)
|
||||
&& (crop.width <= THUMBNAIL_WIDTH);
|
||||
}
|
||||
|
||||
private void copyMainImageToThumbnail(File mainFile, File thumbFile)
|
||||
throws IOException {
|
||||
InputStream imageSource = null;
|
||||
try {
|
||||
imageSource = new FileInputStream(mainFile);
|
||||
storeImage(imageSource, thumbFile);
|
||||
} finally {
|
||||
if (imageSource != null) {
|
||||
try {
|
||||
imageSource.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cropScaleAndStore(CropRectangle crop, File mainFile,
|
||||
File thumbFile) throws IOException {
|
||||
InputStream mainImageStream = null;
|
||||
InputStream imageSource = null;
|
||||
try {
|
||||
mainImageStream = new FileInputStream(mainFile);
|
||||
ImageUploadThumbnailer iut = new ImageUploadThumbnailer(
|
||||
THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH);
|
||||
imageSource = iut.cropAndScale(mainImageStream, crop);
|
||||
storeImage(imageSource, thumbFile);
|
||||
} finally {
|
||||
if (mainImageStream != null) {
|
||||
try {
|
||||
mainImageStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (imageSource != null) {
|
||||
try {
|
||||
imageSource.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void storeImage(InputStream source, File file) throws IOException {
|
||||
OutputStream sink = null;
|
||||
try {
|
||||
sink = new FileOutputStream(file);
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int howMany;
|
||||
while (-1 != (howMany = source.read(buffer))) {
|
||||
sink.write(buffer, 0, howMany);
|
||||
}
|
||||
} finally {
|
||||
if (sink != null) {
|
||||
try {
|
||||
sink.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
import com.hp.hpl.jena.shared.Lock;
|
||||
|
||||
/**
|
||||
* All image properties should have literal values. Burn any that don't.
|
||||
*/
|
||||
public class NonLiteralPropertyRemover extends FsuScanner {
|
||||
|
||||
public NonLiteralPropertyRemover(FSUController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any image properties whose objects are not {@link Literal}s.
|
||||
*/
|
||||
public void remove() {
|
||||
updateLog.section("Checking for image properties whose objects "
|
||||
+ "are not literals.");
|
||||
|
||||
removeNonLiterals(imageProperty, "image file");
|
||||
removeNonLiterals(thumbProperty, "thumbnail");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all resources for bogus values on this property.
|
||||
*/
|
||||
private void removeNonLiterals(Property prop, String label) {
|
||||
for (Resource resource : ModelWrapper.listResourcesWithProperty(model,
|
||||
prop)) {
|
||||
removeNonLiterals(resource, prop, label);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check this resource for bogus values onthis property.
|
||||
*/
|
||||
private void removeNonLiterals(Resource resource, Property prop,
|
||||
String label) {
|
||||
List<RDFNode> bogusValues = new ArrayList<RDFNode>();
|
||||
for (Statement stmt : ResourceWrapper.listProperties(resource, prop)) {
|
||||
RDFNode object = stmt.getObject();
|
||||
if (!object.isLiteral()) {
|
||||
bogusValues.add(object);
|
||||
}
|
||||
}
|
||||
|
||||
for (RDFNode bogusValue : bogusValues) {
|
||||
updateLog.warn(resource, "discarding " + label
|
||||
+ " property with non-literal as object: '" + bogusValue
|
||||
+ "'");
|
||||
model.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
model.createStatement(resource, prop, bogusValue).remove();
|
||||
} finally {
|
||||
model.leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
import com.hp.hpl.jena.rdf.model.StmtIterator;
|
||||
import com.hp.hpl.jena.shared.Lock;
|
||||
|
||||
/**
|
||||
* Utility methods that get the appropriate model locks before manipluating
|
||||
* resources.
|
||||
*/
|
||||
public class ResourceWrapper {
|
||||
|
||||
public static Statement getProperty(Resource resource, Property property) {
|
||||
resource.getModel().enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
return resource.getProperty(property);
|
||||
} finally {
|
||||
resource.getModel().leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addProperty(Resource resource, Property property,
|
||||
String value) {
|
||||
resource.getModel().enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
resource.addProperty(property, value);
|
||||
} finally {
|
||||
resource.getModel().leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeAll(Resource resource, Property property) {
|
||||
resource.getModel().enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
resource.removeAll(property);
|
||||
} finally {
|
||||
resource.getModel().leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection<Statement> listProperties(Resource resource,
|
||||
Property prop) {
|
||||
List<Statement> list = new ArrayList<Statement>();
|
||||
StmtIterator stmts = resource.listProperties(prop);
|
||||
try {
|
||||
while (stmts.hasNext()) {
|
||||
list.add(stmts.next());
|
||||
}
|
||||
return list;
|
||||
} finally {
|
||||
stmts.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue