NIHVIVO-157 manual merge of the changes from branch NIHVIVO-157-file-storage
This commit is contained in:
parent
083aa4e530
commit
fb7d5bbba9
51 changed files with 3535 additions and 1198 deletions
|
@ -109,8 +109,7 @@ public class CuratorEditingPolicy implements VisitingPolicyIface {
|
|||
this.editableVitroUris.add(VitroVocabulary.TIMEKEY);
|
||||
|
||||
this.editableVitroUris.add(VitroVocabulary.CITATION);
|
||||
this.editableVitroUris.add(VitroVocabulary.IMAGEFILE);
|
||||
this.editableVitroUris.add(VitroVocabulary.IMAGETHUMB);
|
||||
this.editableVitroUris.add(VitroVocabulary.IND_MAIN_IMAGE);
|
||||
|
||||
this.editableVitroUris.add(VitroVocabulary.LINK);
|
||||
this.editableVitroUris.add(VitroVocabulary.PRIMARY_LINK);
|
||||
|
|
|
@ -112,8 +112,7 @@ public class DbAdminEditingPolicy implements VisitingPolicyIface {
|
|||
this.editableVitroUris.add(VitroVocabulary.TIMEKEY);
|
||||
|
||||
this.editableVitroUris.add(VitroVocabulary.CITATION);
|
||||
this.editableVitroUris.add(VitroVocabulary.IMAGEFILE);
|
||||
this.editableVitroUris.add(VitroVocabulary.IMAGETHUMB);
|
||||
this.editableVitroUris.add(VitroVocabulary.IND_MAIN_IMAGE);
|
||||
|
||||
this.editableVitroUris.add(VitroVocabulary.LINK);
|
||||
this.editableVitroUris.add(VitroVocabulary.PRIMARY_LINK);
|
||||
|
|
|
@ -110,8 +110,7 @@ public class EditorEditingPolicy implements VisitingPolicyIface{
|
|||
this.editableVitroUris.add(VitroVocabulary.TIMEKEY);
|
||||
|
||||
this.editableVitroUris.add(VitroVocabulary.CITATION);
|
||||
this.editableVitroUris.add(VitroVocabulary.IMAGEFILE);
|
||||
this.editableVitroUris.add(VitroVocabulary.IMAGETHUMB);
|
||||
this.editableVitroUris.add(VitroVocabulary.IND_MAIN_IMAGE);
|
||||
|
||||
this.editableVitroUris.add(VitroVocabulary.LINK);
|
||||
this.editableVitroUris.add(VitroVocabulary.PRIMARY_LINK);
|
||||
|
|
|
@ -5,8 +5,6 @@ package edu.cornell.mannlib.vitro.webapp.auth.policy;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
@ -110,8 +108,7 @@ public class SelfEditingPolicy implements VisitingPolicyIface {
|
|||
this.editableVitroUris.add(VitroVocabulary.TIMEKEY);
|
||||
|
||||
this.editableVitroUris.add(VitroVocabulary.CITATION);
|
||||
this.editableVitroUris.add(VitroVocabulary.IMAGEFILE);
|
||||
this.editableVitroUris.add(VitroVocabulary.IMAGETHUMB);
|
||||
this.editableVitroUris.add(VitroVocabulary.IND_MAIN_IMAGE);
|
||||
|
||||
this.editableVitroUris.add(VitroVocabulary.LINK);
|
||||
this.editableVitroUris.add(VitroVocabulary.PRIMARY_LINK);
|
||||
|
|
|
@ -93,11 +93,11 @@ public interface Individual extends ResourceBean, VitroTimeWindowedResource, Com
|
|||
String getStatus();
|
||||
void setStatus(String s);
|
||||
|
||||
String getImageFile();
|
||||
void setImageFile(String imageFile);
|
||||
|
||||
String getImageThumb();
|
||||
void setImageThumb(String imageThumb);
|
||||
void setMainImageUri(String mainImageUri);
|
||||
String getMainImageUri();
|
||||
|
||||
String getImageUrl();
|
||||
String getThumbUrl();
|
||||
|
||||
String getUrl();
|
||||
void setUrl(String url);
|
||||
|
|
|
@ -1,132 +1,141 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.beans;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.Collator;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents a single entity record.
|
||||
*/
|
||||
public class IndividualImpl extends BaseResourceBean implements Individual, Comparable<Individual> {
|
||||
public String name = null;
|
||||
public String vClassURI = null;
|
||||
protected VClass vClass = null;
|
||||
protected List<VClass> directVClasses = null;
|
||||
protected List<VClass> allVClasses = null;
|
||||
protected Date sunrise = null;
|
||||
protected Date sunset = null;
|
||||
protected Date timekey = null;
|
||||
protected Timestamp modTime = null;
|
||||
protected List <ObjectProperty>propertyList = null;
|
||||
protected Map <String,ObjectProperty> objectPropertyMap = null;
|
||||
protected List <DataProperty>datatypePropertyList = null;
|
||||
protected Map <String,DataProperty> dataPropertyMap = null;
|
||||
protected List <DataPropertyStatement>dataPropertyStatements = null;
|
||||
protected List <ObjectPropertyStatement>objectPropertyStatements = null;
|
||||
protected List <ObjectPropertyStatement>rangeEnts2Ents = null;
|
||||
protected List <DataPropertyStatement>externalIds = null;
|
||||
|
||||
protected String moniker = null;
|
||||
protected String url = null;
|
||||
protected String description = null;
|
||||
protected String imageFile = null;
|
||||
protected String anchor = null;
|
||||
protected String blurb = null;
|
||||
protected String imageThumb = null;
|
||||
protected String citation = null;
|
||||
protected int statusId = 0;
|
||||
protected String status = null;
|
||||
protected List <Link>linksList = null;
|
||||
protected Link primaryLink = null;
|
||||
protected List<String> keywords=null;
|
||||
protected List<Keyword> keywordObjects=null;
|
||||
protected Float searchBoost;
|
||||
|
||||
/** indicates if sortForDisplay has been called */
|
||||
protected boolean sorted = false;
|
||||
protected boolean DIRECT = true;
|
||||
protected boolean ALL = false;
|
||||
|
||||
public IndividualImpl() {
|
||||
}
|
||||
|
||||
public IndividualImpl(String URI) {
|
||||
this.setURI(URI);
|
||||
this.setVClasses(new ArrayList<VClass>(), DIRECT);
|
||||
this.setVClasses(new ArrayList<VClass>(), ALL);
|
||||
this.setObjectPropertyStatements(new ArrayList<ObjectPropertyStatement>());
|
||||
this.setObjectPropertyMap(new HashMap<String, ObjectProperty>());
|
||||
this.setDataPropertyStatements(new ArrayList<DataPropertyStatement>());
|
||||
this.setDataPropertyMap(new HashMap<String, DataProperty>());
|
||||
this.setPropertyList(new ArrayList<ObjectProperty>());
|
||||
this.setDatatypePropertyList(new ArrayList<DataProperty>());
|
||||
}
|
||||
|
||||
public String getName(){return name;}
|
||||
public void setName(String in){name=in;}
|
||||
|
||||
// private String modTime = null;
|
||||
// public String getModtime(){return modTime;}
|
||||
// public void setModtime(String in){modTime=in;}
|
||||
|
||||
public String getVClassURI(){return vClassURI;}
|
||||
public void setVClassURI(String in){vClassURI=in;}
|
||||
|
||||
public Date getSunrise(){return sunrise;}
|
||||
public void setSunrise(Date in){sunrise=in;}
|
||||
|
||||
public Date getSunset(){return sunset;}
|
||||
public void setSunset(Date in){sunset=in;}
|
||||
|
||||
public Date getTimekey(){return timekey;}
|
||||
public void setTimekey(Date in){timekey=in;}
|
||||
|
||||
/**
|
||||
* Returns the last time this object was changed in the model.
|
||||
* Notice Java API craziness: Timestamp is a subclass of Date
|
||||
* but there are notes in the Javadoc that you should not pretend
|
||||
* that a Timestamp is a Date. (Crazy ya?) In particular,
|
||||
* Timestamp.equals(Date) will never return true because of
|
||||
* the 'nanos.'
|
||||
*/
|
||||
public Timestamp getModTime(){return modTime;}
|
||||
public void setModTime(Timestamp in){modTime=in;}
|
||||
|
||||
public List<ObjectProperty> getObjectPropertyList() {
|
||||
return propertyList;
|
||||
}
|
||||
public void setPropertyList(List <ObjectProperty>propertyList) {
|
||||
this.propertyList = propertyList;
|
||||
}
|
||||
public Map<String,ObjectProperty> getObjectPropertyMap() {
|
||||
return this.objectPropertyMap;
|
||||
}
|
||||
public void setObjectPropertyMap( Map<String,ObjectProperty> propertyMap ) {
|
||||
this.objectPropertyMap = propertyMap;
|
||||
}
|
||||
public List <DataProperty>getDataPropertyList() {
|
||||
return datatypePropertyList;
|
||||
}
|
||||
public void setDatatypePropertyList(List <DataProperty>datatypePropertyList) {
|
||||
this.datatypePropertyList = datatypePropertyList;
|
||||
}
|
||||
public Map<String,DataProperty> getDataPropertyMap() {
|
||||
return this.dataPropertyMap;
|
||||
}
|
||||
public void setDataPropertyMap( Map<String,DataProperty> propertyMap ) {
|
||||
this.dataPropertyMap = propertyMap;
|
||||
}
|
||||
public void setDataPropertyStatements(List <DataPropertyStatement>list) {
|
||||
dataPropertyStatements = list;
|
||||
}
|
||||
public List<DataPropertyStatement> getDataPropertyStatements(){
|
||||
return dataPropertyStatements;
|
||||
package edu.cornell.mannlib.vitro.webapp.beans;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.Collator;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents a single entity record.
|
||||
*/
|
||||
public class IndividualImpl extends BaseResourceBean implements Individual, Comparable<Individual> {
|
||||
/**
|
||||
* This can be used as a "not initialized" indicator for a property that
|
||||
* could validly be set to <code>null</code>. If <code>get()</code> is
|
||||
* called on such a property, and the property has this value, the correct
|
||||
* value can be fetched and cached.
|
||||
*/
|
||||
protected static final String NOT_INITIALIZED = "__%NOT_INITIALIZED%__";
|
||||
|
||||
public String name = null;
|
||||
public String vClassURI = null;
|
||||
protected VClass vClass = null;
|
||||
protected List<VClass> directVClasses = null;
|
||||
protected List<VClass> allVClasses = null;
|
||||
protected Date sunrise = null;
|
||||
protected Date sunset = null;
|
||||
protected Date timekey = null;
|
||||
protected Timestamp modTime = null;
|
||||
protected List <ObjectProperty>propertyList = null;
|
||||
protected Map <String,ObjectProperty> objectPropertyMap = null;
|
||||
protected List <DataProperty>datatypePropertyList = null;
|
||||
protected Map <String,DataProperty> dataPropertyMap = null;
|
||||
protected List <DataPropertyStatement>dataPropertyStatements = null;
|
||||
protected List <ObjectPropertyStatement>objectPropertyStatements = null;
|
||||
protected List <ObjectPropertyStatement>rangeEnts2Ents = null;
|
||||
protected List <DataPropertyStatement>externalIds = null;
|
||||
|
||||
protected String moniker = null;
|
||||
protected String url = null;
|
||||
protected String description = null;
|
||||
protected String anchor = null;
|
||||
protected String blurb = null;
|
||||
protected String mainImageUri = NOT_INITIALIZED;
|
||||
protected String imageUrl;
|
||||
protected String thumbUrl;
|
||||
protected String citation = null;
|
||||
protected int statusId = 0;
|
||||
protected String status = null;
|
||||
protected List <Link>linksList = null;
|
||||
protected Link primaryLink = null;
|
||||
protected List<String> keywords=null;
|
||||
protected List<Keyword> keywordObjects=null;
|
||||
protected Float searchBoost;
|
||||
|
||||
/** indicates if sortForDisplay has been called */
|
||||
protected boolean sorted = false;
|
||||
protected boolean DIRECT = true;
|
||||
protected boolean ALL = false;
|
||||
|
||||
public IndividualImpl() {
|
||||
}
|
||||
|
||||
public IndividualImpl(String URI) {
|
||||
this.setURI(URI);
|
||||
this.setVClasses(new ArrayList<VClass>(), DIRECT);
|
||||
this.setVClasses(new ArrayList<VClass>(), ALL);
|
||||
this.setObjectPropertyStatements(new ArrayList<ObjectPropertyStatement>());
|
||||
this.setObjectPropertyMap(new HashMap<String, ObjectProperty>());
|
||||
this.setDataPropertyStatements(new ArrayList<DataPropertyStatement>());
|
||||
this.setDataPropertyMap(new HashMap<String, DataProperty>());
|
||||
this.setPropertyList(new ArrayList<ObjectProperty>());
|
||||
this.setDatatypePropertyList(new ArrayList<DataProperty>());
|
||||
}
|
||||
|
||||
public String getName(){return name;}
|
||||
public void setName(String in){name=in;}
|
||||
|
||||
// private String modTime = null;
|
||||
// public String getModtime(){return modTime;}
|
||||
// public void setModtime(String in){modTime=in;}
|
||||
|
||||
public String getVClassURI(){return vClassURI;}
|
||||
public void setVClassURI(String in){vClassURI=in;}
|
||||
|
||||
public Date getSunrise(){return sunrise;}
|
||||
public void setSunrise(Date in){sunrise=in;}
|
||||
|
||||
public Date getSunset(){return sunset;}
|
||||
public void setSunset(Date in){sunset=in;}
|
||||
|
||||
public Date getTimekey(){return timekey;}
|
||||
public void setTimekey(Date in){timekey=in;}
|
||||
|
||||
/**
|
||||
* Returns the last time this object was changed in the model.
|
||||
* Notice Java API craziness: Timestamp is a subclass of Date
|
||||
* but there are notes in the Javadoc that you should not pretend
|
||||
* that a Timestamp is a Date. (Crazy ya?) In particular,
|
||||
* Timestamp.equals(Date) will never return true because of
|
||||
* the 'nanos.'
|
||||
*/
|
||||
public Timestamp getModTime(){return modTime;}
|
||||
public void setModTime(Timestamp in){modTime=in;}
|
||||
|
||||
public List<ObjectProperty> getObjectPropertyList() {
|
||||
return propertyList;
|
||||
}
|
||||
public void setPropertyList(List <ObjectProperty>propertyList) {
|
||||
this.propertyList = propertyList;
|
||||
}
|
||||
public Map<String,ObjectProperty> getObjectPropertyMap() {
|
||||
return this.objectPropertyMap;
|
||||
}
|
||||
public void setObjectPropertyMap( Map<String,ObjectProperty> propertyMap ) {
|
||||
this.objectPropertyMap = propertyMap;
|
||||
}
|
||||
public List <DataProperty>getDataPropertyList() {
|
||||
return datatypePropertyList;
|
||||
}
|
||||
public void setDatatypePropertyList(List <DataProperty>datatypePropertyList) {
|
||||
this.datatypePropertyList = datatypePropertyList;
|
||||
}
|
||||
public Map<String,DataProperty> getDataPropertyMap() {
|
||||
return this.dataPropertyMap;
|
||||
}
|
||||
public void setDataPropertyMap( Map<String,DataProperty> propertyMap ) {
|
||||
this.dataPropertyMap = propertyMap;
|
||||
}
|
||||
public void setDataPropertyStatements(List <DataPropertyStatement>list) {
|
||||
dataPropertyStatements = list;
|
||||
}
|
||||
public List<DataPropertyStatement> getDataPropertyStatements(){
|
||||
return dataPropertyStatements;
|
||||
}
|
||||
|
||||
public List<DataPropertyStatement> getDataPropertyStatements(String propertyUri) {
|
||||
|
@ -158,41 +167,41 @@ public class IndividualImpl extends BaseResourceBean implements Individual, Comp
|
|||
public String getDataValue(String propertyUri) {
|
||||
List<DataPropertyStatement> stmts = getDataPropertyStatements(propertyUri);
|
||||
return stmts.isEmpty() ? null : stmts.get(0).getData();
|
||||
}
|
||||
|
||||
public VClass getVClass() {
|
||||
return vClass;
|
||||
}
|
||||
public void setVClass(VClass class1) {
|
||||
vClass = class1;
|
||||
}
|
||||
|
||||
public List<VClass> getVClasses() {
|
||||
return allVClasses;
|
||||
}
|
||||
|
||||
public List<VClass> getVClasses(boolean direct) {
|
||||
if (direct) {
|
||||
return directVClasses;
|
||||
} else {
|
||||
return allVClasses;
|
||||
}
|
||||
}
|
||||
|
||||
public void setVClasses(List<VClass> vClassList, boolean direct) {
|
||||
if (direct) {
|
||||
this.directVClasses = vClassList;
|
||||
} else {
|
||||
this.allVClasses = vClassList;
|
||||
}
|
||||
}
|
||||
|
||||
public void setObjectPropertyStatements(List<ObjectPropertyStatement> list) {
|
||||
objectPropertyStatements = list;
|
||||
}
|
||||
|
||||
public List <ObjectPropertyStatement> getObjectPropertyStatements(){
|
||||
return objectPropertyStatements;
|
||||
}
|
||||
|
||||
public VClass getVClass() {
|
||||
return vClass;
|
||||
}
|
||||
public void setVClass(VClass class1) {
|
||||
vClass = class1;
|
||||
}
|
||||
|
||||
public List<VClass> getVClasses() {
|
||||
return allVClasses;
|
||||
}
|
||||
|
||||
public List<VClass> getVClasses(boolean direct) {
|
||||
if (direct) {
|
||||
return directVClasses;
|
||||
} else {
|
||||
return allVClasses;
|
||||
}
|
||||
}
|
||||
|
||||
public void setVClasses(List<VClass> vClassList, boolean direct) {
|
||||
if (direct) {
|
||||
this.directVClasses = vClassList;
|
||||
} else {
|
||||
this.allVClasses = vClassList;
|
||||
}
|
||||
}
|
||||
|
||||
public void setObjectPropertyStatements(List<ObjectPropertyStatement> list) {
|
||||
objectPropertyStatements = list;
|
||||
}
|
||||
|
||||
public List <ObjectPropertyStatement> getObjectPropertyStatements(){
|
||||
return objectPropertyStatements;
|
||||
}
|
||||
|
||||
public List<ObjectPropertyStatement> getObjectPropertyStatements(String propertyUri) {
|
||||
|
@ -218,228 +227,239 @@ public class IndividualImpl extends BaseResourceBean implements Individual, Comp
|
|||
public Individual getRelatedIndividual(String propertyUri) {
|
||||
List<ObjectPropertyStatement> stmts = getObjectPropertyStatements(propertyUri);
|
||||
return stmts.isEmpty() ? null : stmts.get(0).getObject();
|
||||
}
|
||||
|
||||
public List<DataPropertyStatement> getExternalIds(){
|
||||
return externalIds;
|
||||
}
|
||||
public void setExternalIds(List<DataPropertyStatement> externalIds){
|
||||
this.externalIds = externalIds;
|
||||
}
|
||||
|
||||
|
||||
public String getMoniker(){return moniker;}
|
||||
public void setMoniker(String in){moniker=in;}
|
||||
|
||||
public String getDescription(){return description;}
|
||||
public void setDescription(String in){description=in;}
|
||||
|
||||
public String getAnchor(){return anchor;}
|
||||
public void setAnchor(String in){anchor=in;}
|
||||
|
||||
public String getBlurb(){return blurb;}
|
||||
public void setBlurb(String in){blurb=in;}
|
||||
|
||||
public String getCitation(){return citation;}
|
||||
public void setCitation(String in){citation=in;}
|
||||
|
||||
public int getStatusId(){return statusId;}
|
||||
public void setStatusId(int in){statusId=in;}
|
||||
|
||||
public String getStatus() {return status;}
|
||||
public void setStatus(String s) {status=s; }
|
||||
|
||||
public String getImageFile() {
|
||||
return imageFile;
|
||||
}
|
||||
public void setImageFile(String imageFile) {
|
||||
this.imageFile = imageFile;
|
||||
}
|
||||
public String getImageThumb() {
|
||||
return imageThumb;
|
||||
}
|
||||
public void setImageThumb(String imageThumb) {
|
||||
this.imageThumb = imageThumb;
|
||||
}
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
public List<Link> getLinksList() {
|
||||
return linksList;
|
||||
}
|
||||
public void setLinksList(List <Link>linksList) {
|
||||
this.linksList = linksList;
|
||||
}
|
||||
|
||||
public Link getPrimaryLink() {
|
||||
return primaryLink;
|
||||
}
|
||||
|
||||
public void setPrimaryLink(Link link) {
|
||||
primaryLink = link;
|
||||
}
|
||||
|
||||
|
||||
/* look at PortalFlag.numeric2numerics if you want to know which
|
||||
* bits are set in a numeric flag.
|
||||
*
|
||||
* NOTICE:
|
||||
* Values set Entity.getFlagXNumeric() will NOT be saved to the model.
|
||||
*
|
||||
* Also, changes to an entity flag state using Entity.setFlagXNumeric()
|
||||
* are not reflected in Entity.getFlagXSet() and vice versa.
|
||||
*/
|
||||
protected String flag1Set = null;
|
||||
public String getFlag1Set(){return flag1Set;}
|
||||
public void setFlag1Set(String in){flag1Set=in;}
|
||||
|
||||
protected int flag1Numeric = -1;
|
||||
public int getFlag1Numeric(){return flag1Numeric;}
|
||||
public void setFlag1Numeric(int i){flag1Numeric=i;}
|
||||
|
||||
/* Consider the flagBitMask as a mask to & with flags.
|
||||
if flagBitMask bit zero is set then return true if
|
||||
the individual is in portal 2,
|
||||
if flagBitMask bit 1 is set then return true if
|
||||
the individua is in portal 4
|
||||
etc.
|
||||
*/
|
||||
public boolean doesFlag1Match(int flagBitMask) {
|
||||
return (flagBitMask & getFlag1Numeric()) != 0;
|
||||
}
|
||||
|
||||
protected String flag2Set = null;
|
||||
public String getFlag2Set(){return flag2Set;}
|
||||
public void setFlag2Set(String in){flag2Set=in;}
|
||||
|
||||
protected int flag2Numeric = -1;
|
||||
public int getFlag2Numeric(){return flag2Numeric;}
|
||||
public void setFlag2Numeric(int i){flag2Numeric=i;}
|
||||
|
||||
protected String flag3Set = null;
|
||||
public String getFlag3Set(){return flag3Set;}
|
||||
public void setFlag3Set(String in){flag3Set=in;}
|
||||
|
||||
protected int flag3Numeric = -1;
|
||||
public int getFlag3Numeric(){return flag3Numeric;}
|
||||
public void setFlag3Numeric(int i){flag3Numeric=i;}
|
||||
|
||||
public List<String> getKeywords() { return keywords; }
|
||||
public void setKeywords(List<String> keywords) {this.keywords = keywords;}
|
||||
public String getKeywordString(){
|
||||
String rv = "";
|
||||
List keywords=getKeywords();
|
||||
if (getKeywords()!=null){
|
||||
Iterator<String> it1 = getKeywords().iterator();
|
||||
TreeSet<String> keywordSet = new TreeSet<String>(new Comparator<String>() {
|
||||
public int compare( String first, String second ) {
|
||||
if (first==null) {
|
||||
return 1;
|
||||
}
|
||||
if (second==null) {
|
||||
return -1;
|
||||
}
|
||||
Collator collator = Collator.getInstance();
|
||||
return collator.compare(first,second);
|
||||
}
|
||||
});
|
||||
while( it1.hasNext() ){
|
||||
keywordSet.add(it1.next());
|
||||
}
|
||||
Iterator<String> it2 = keywordSet.iterator();
|
||||
while (it2.hasNext()) {
|
||||
rv+= it2.next();
|
||||
if( it2.hasNext())
|
||||
rv+=", ";
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public List<Keyword> getKeywordObjects() { return keywordObjects; }
|
||||
public void setKeywordObjects(List<Keyword> keywords) {this.keywordObjects = keywords;}
|
||||
|
||||
public Float getSearchBoost() { return searchBoost; }
|
||||
public void setSearchBoost(Float boost) { searchBoost = boost; }
|
||||
|
||||
/**
|
||||
* Sorts the ents2ents records into the proper order for display.
|
||||
*
|
||||
*/
|
||||
public void sortForDisplay(){
|
||||
if( sorted ) return;
|
||||
if( getObjectPropertyList() == null ) return;
|
||||
sortPropertiesForDisplay();
|
||||
sortEnts2EntsForDisplay();
|
||||
sorted = true;
|
||||
}
|
||||
|
||||
protected void sortEnts2EntsForDisplay(){
|
||||
if( getObjectPropertyList() == null ) return;
|
||||
|
||||
Iterator it = getObjectPropertyList().iterator();
|
||||
while(it.hasNext()){
|
||||
ObjectProperty prop = (ObjectProperty)it.next();
|
||||
prop.sortObjectPropertyStatementsForDisplay(prop,prop.getObjectPropertyStatements());
|
||||
}
|
||||
}
|
||||
|
||||
protected void sortPropertiesForDisplay( ){
|
||||
//here we sort the Property objects
|
||||
Collections.sort(getObjectPropertyList(), new ObjectProperty.DisplayComparator());
|
||||
}
|
||||
|
||||
public static final String [] INCLUDED_IN_JSON = {
|
||||
"URI",
|
||||
"name",
|
||||
"moniker",
|
||||
"vClassId"
|
||||
};
|
||||
|
||||
|
||||
public JSONObject toJSON() throws JSONException {
|
||||
JSONObject jsonObj = new JSONObject(this, INCLUDED_IN_JSON);
|
||||
return jsonObj;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param fieldName- expected to be the field name in the format
|
||||
* @return
|
||||
* @throws NoSuchMethodException
|
||||
*/
|
||||
public Object getField(String fieldName) throws NoSuchMethodException{
|
||||
if( fieldName == null || fieldName.length() == 0) return null;
|
||||
|
||||
if( "name".equalsIgnoreCase(fieldName) )
|
||||
return getName();
|
||||
if( "timekey".equalsIgnoreCase(fieldName) )
|
||||
return getTimekey();
|
||||
|
||||
//not one of the more common ones, try reflection
|
||||
|
||||
//capitalize first letter
|
||||
String methodName = "get" + fieldName.substring(0,1).toUpperCase()
|
||||
+ fieldName.substring(1,fieldName.length());
|
||||
|
||||
Class cls = this.getClass();
|
||||
try {
|
||||
Method meth = cls.getMethod(methodName, (Class[]) null);
|
||||
return meth.invoke(this,(Object[])null);
|
||||
} catch (Exception e) { }
|
||||
//should never get here
|
||||
throw new NoSuchMethodException("Entity.getField() attempt to use a method called "
|
||||
+ methodName +"() for field " + fieldName + " but the method doesn't exist.");
|
||||
}
|
||||
|
||||
public int compareTo(Individual o2) {
|
||||
Collator collator = Collator.getInstance();
|
||||
if (o2 == null) {
|
||||
return 1;
|
||||
} else {
|
||||
return collator.compare(this.getName(),o2.getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public List<DataPropertyStatement> getExternalIds(){
|
||||
return externalIds;
|
||||
}
|
||||
public void setExternalIds(List<DataPropertyStatement> externalIds){
|
||||
this.externalIds = externalIds;
|
||||
}
|
||||
|
||||
|
||||
public String getMoniker(){return moniker;}
|
||||
public void setMoniker(String in){moniker=in;}
|
||||
|
||||
public String getDescription(){return description;}
|
||||
public void setDescription(String in){description=in;}
|
||||
|
||||
public String getAnchor(){return anchor;}
|
||||
public void setAnchor(String in){anchor=in;}
|
||||
|
||||
public String getBlurb(){return blurb;}
|
||||
public void setBlurb(String in){blurb=in;}
|
||||
|
||||
public String getCitation(){return citation;}
|
||||
public void setCitation(String in){citation=in;}
|
||||
|
||||
public int getStatusId(){return statusId;}
|
||||
public void setStatusId(int in){statusId=in;}
|
||||
|
||||
public String getStatus() {return status;}
|
||||
public void setStatus(String s) {status=s; }
|
||||
|
||||
|
||||
@Override
|
||||
public String getMainImageUri() {
|
||||
return (mainImageUri == NOT_INITIALIZED) ? null : mainImageUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMainImageUri(String mainImageUri) {
|
||||
this.mainImageUri = mainImageUri;
|
||||
this.imageUrl = null;
|
||||
this.thumbUrl = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageUrl() {
|
||||
return "imageUrl";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThumbUrl() {
|
||||
return "thumbUrl";
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
public List<Link> getLinksList() {
|
||||
return linksList;
|
||||
}
|
||||
public void setLinksList(List <Link>linksList) {
|
||||
this.linksList = linksList;
|
||||
}
|
||||
|
||||
public Link getPrimaryLink() {
|
||||
return primaryLink;
|
||||
}
|
||||
|
||||
public void setPrimaryLink(Link link) {
|
||||
primaryLink = link;
|
||||
}
|
||||
|
||||
|
||||
/* look at PortalFlag.numeric2numerics if you want to know which
|
||||
* bits are set in a numeric flag.
|
||||
*
|
||||
* NOTICE:
|
||||
* Values set Entity.getFlagXNumeric() will NOT be saved to the model.
|
||||
*
|
||||
* Also, changes to an entity flag state using Entity.setFlagXNumeric()
|
||||
* are not reflected in Entity.getFlagXSet() and vice versa.
|
||||
*/
|
||||
protected String flag1Set = null;
|
||||
public String getFlag1Set(){return flag1Set;}
|
||||
public void setFlag1Set(String in){flag1Set=in;}
|
||||
|
||||
protected int flag1Numeric = -1;
|
||||
public int getFlag1Numeric(){return flag1Numeric;}
|
||||
public void setFlag1Numeric(int i){flag1Numeric=i;}
|
||||
|
||||
/* Consider the flagBitMask as a mask to & with flags.
|
||||
if flagBitMask bit zero is set then return true if
|
||||
the individual is in portal 2,
|
||||
if flagBitMask bit 1 is set then return true if
|
||||
the individua is in portal 4
|
||||
etc.
|
||||
*/
|
||||
public boolean doesFlag1Match(int flagBitMask) {
|
||||
return (flagBitMask & getFlag1Numeric()) != 0;
|
||||
}
|
||||
|
||||
protected String flag2Set = null;
|
||||
public String getFlag2Set(){return flag2Set;}
|
||||
public void setFlag2Set(String in){flag2Set=in;}
|
||||
|
||||
protected int flag2Numeric = -1;
|
||||
public int getFlag2Numeric(){return flag2Numeric;}
|
||||
public void setFlag2Numeric(int i){flag2Numeric=i;}
|
||||
|
||||
protected String flag3Set = null;
|
||||
public String getFlag3Set(){return flag3Set;}
|
||||
public void setFlag3Set(String in){flag3Set=in;}
|
||||
|
||||
protected int flag3Numeric = -1;
|
||||
public int getFlag3Numeric(){return flag3Numeric;}
|
||||
public void setFlag3Numeric(int i){flag3Numeric=i;}
|
||||
|
||||
public List<String> getKeywords() { return keywords; }
|
||||
public void setKeywords(List<String> keywords) {this.keywords = keywords;}
|
||||
public String getKeywordString(){
|
||||
String rv = "";
|
||||
List keywords=getKeywords();
|
||||
if (getKeywords()!=null){
|
||||
Iterator<String> it1 = getKeywords().iterator();
|
||||
TreeSet<String> keywordSet = new TreeSet<String>(new Comparator<String>() {
|
||||
public int compare( String first, String second ) {
|
||||
if (first==null) {
|
||||
return 1;
|
||||
}
|
||||
if (second==null) {
|
||||
return -1;
|
||||
}
|
||||
Collator collator = Collator.getInstance();
|
||||
return collator.compare(first,second);
|
||||
}
|
||||
});
|
||||
while( it1.hasNext() ){
|
||||
keywordSet.add(it1.next());
|
||||
}
|
||||
Iterator<String> it2 = keywordSet.iterator();
|
||||
while (it2.hasNext()) {
|
||||
rv+= it2.next();
|
||||
if( it2.hasNext())
|
||||
rv+=", ";
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public List<Keyword> getKeywordObjects() { return keywordObjects; }
|
||||
public void setKeywordObjects(List<Keyword> keywords) {this.keywordObjects = keywords;}
|
||||
|
||||
public Float getSearchBoost() { return searchBoost; }
|
||||
public void setSearchBoost(Float boost) { searchBoost = boost; }
|
||||
|
||||
/**
|
||||
* Sorts the ents2ents records into the proper order for display.
|
||||
*
|
||||
*/
|
||||
public void sortForDisplay(){
|
||||
if( sorted ) return;
|
||||
if( getObjectPropertyList() == null ) return;
|
||||
sortPropertiesForDisplay();
|
||||
sortEnts2EntsForDisplay();
|
||||
sorted = true;
|
||||
}
|
||||
|
||||
protected void sortEnts2EntsForDisplay(){
|
||||
if( getObjectPropertyList() == null ) return;
|
||||
|
||||
Iterator it = getObjectPropertyList().iterator();
|
||||
while(it.hasNext()){
|
||||
ObjectProperty prop = (ObjectProperty)it.next();
|
||||
prop.sortObjectPropertyStatementsForDisplay(prop,prop.getObjectPropertyStatements());
|
||||
}
|
||||
}
|
||||
|
||||
protected void sortPropertiesForDisplay( ){
|
||||
//here we sort the Property objects
|
||||
Collections.sort(getObjectPropertyList(), new ObjectProperty.DisplayComparator());
|
||||
}
|
||||
|
||||
public static final String [] INCLUDED_IN_JSON = {
|
||||
"URI",
|
||||
"name",
|
||||
"moniker",
|
||||
"vClassId"
|
||||
};
|
||||
|
||||
|
||||
public JSONObject toJSON() throws JSONException {
|
||||
JSONObject jsonObj = new JSONObject(this, INCLUDED_IN_JSON);
|
||||
return jsonObj;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param fieldName- expected to be the field name in the format
|
||||
* @return
|
||||
* @throws NoSuchMethodException
|
||||
*/
|
||||
public Object getField(String fieldName) throws NoSuchMethodException{
|
||||
if( fieldName == null || fieldName.length() == 0) return null;
|
||||
|
||||
if( "name".equalsIgnoreCase(fieldName) )
|
||||
return getName();
|
||||
if( "timekey".equalsIgnoreCase(fieldName) )
|
||||
return getTimekey();
|
||||
|
||||
//not one of the more common ones, try reflection
|
||||
|
||||
//capitalize first letter
|
||||
String methodName = "get" + fieldName.substring(0,1).toUpperCase()
|
||||
+ fieldName.substring(1,fieldName.length());
|
||||
|
||||
Class cls = this.getClass();
|
||||
try {
|
||||
Method meth = cls.getMethod(methodName, (Class[]) null);
|
||||
return meth.invoke(this,(Object[])null);
|
||||
} catch (Exception e) { }
|
||||
//should never get here
|
||||
throw new NoSuchMethodException("Entity.getField() attempt to use a method called "
|
||||
+ methodName +"() for field " + fieldName + " but the method doesn't exist.");
|
||||
}
|
||||
|
||||
public int compareTo(Individual o2) {
|
||||
Collator collator = Collator.getInstance();
|
||||
if (o2 == null) {
|
||||
return 1;
|
||||
} else {
|
||||
return collator.compare(this.getName(),o2.getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import com.hp.hpl.jena.ontology.OntModel;
|
|||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||
import com.hp.hpl.jena.rdf.model.ModelMaker;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
|
@ -42,6 +41,10 @@ import edu.cornell.mannlib.vitro.webapp.beans.Portal;
|
|||
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileModelHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileServingHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQuery;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQueryWrapper;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapper;
|
||||
|
@ -97,6 +100,13 @@ public class EntityController extends VitroHttpServlet {
|
|||
doNotFound(vreq, res);
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is an uploaded file, redirect to its "alias URL".
|
||||
String aliasUrl = getAliasUrlForBytestreamIndividual(indiv);
|
||||
if (aliasUrl != null) {
|
||||
res.sendRedirect(req.getContextPath() + aliasUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
doHtml( vreq, res , indiv);
|
||||
return;
|
||||
|
@ -476,6 +486,47 @@ public class EntityController extends VitroHttpServlet {
|
|||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this entity represents a File Bytestream, get its alias URL so we can
|
||||
* properly serve the file contents.
|
||||
*/
|
||||
private String getAliasUrlForBytestreamIndividual(Individual entity)
|
||||
throws IOException {
|
||||
if (!FileModelHelper.isFileBytestream(entity)) {
|
||||
log.debug("Entity at '" + entity.getURI()
|
||||
+ "' is not recognized as a FileByteStream.");
|
||||
return null;
|
||||
}
|
||||
|
||||
FileStorage fs = (FileStorage) getServletContext().getAttribute(
|
||||
FileStorageSetup.ATTRIBUTE_NAME);
|
||||
if (fs == null) {
|
||||
log.error("Servlet context does not contain file storage at '"
|
||||
+ FileStorageSetup.ATTRIBUTE_NAME + "'");
|
||||
return null;
|
||||
}
|
||||
|
||||
String filename = fs.getFilename(entity.getURI());
|
||||
if (filename == null) {
|
||||
log.error("Entity at '" + entity.getURI()
|
||||
+ "' is recognized as a FileByteStream, "
|
||||
+ "but the file system does not recognize it.");
|
||||
return null;
|
||||
}
|
||||
|
||||
String url = FileServingHelper.getBytestreamAliasUrl(entity.getURI(),
|
||||
filename);
|
||||
if (url.equals(entity.getURI())) {
|
||||
log.error("Entity at '" + entity.getURI()
|
||||
+ "' is recognized as a FileByteStream, "
|
||||
+ "but can't be translated to an alias URL.");
|
||||
return null;
|
||||
}
|
||||
|
||||
log.debug("Alias URL for '" + entity.getURI() + "' is '" + url + "'");
|
||||
return url;
|
||||
}
|
||||
|
||||
private Model getRDF(Individual entity, OntModel contextModel, Model newModel, int recurseDepth ) {
|
||||
Resource subj = newModel.getResource(entity.getURI());
|
||||
|
@ -578,7 +629,7 @@ public class EntityController extends VitroHttpServlet {
|
|||
out.println("<p>id is the id of the entity to query for. netid also works.</p>");
|
||||
out.println("</body></html>");
|
||||
}
|
||||
|
||||
|
||||
private void doNotFound(HttpServletRequest req, HttpServletResponse res)
|
||||
throws IOException, ServletException {
|
||||
VitroRequest vreq = new VitroRequest(req);
|
||||
|
|
|
@ -116,8 +116,6 @@ public class CloneEntityServlet extends BaseEditController {
|
|||
ind.setBlurb("");
|
||||
ind.setDescription("");
|
||||
ind.setCitation("");
|
||||
ind.setImageFile("");
|
||||
ind.setImageThumb("");
|
||||
|
||||
String cloneURI=individualDao.insertNewIndividual(ind);
|
||||
if (cloneURI == null){ log.error("Error inserting cloned individual"); return; }
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -43,6 +43,10 @@ import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
|
|||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileModelHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileServingHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQuery;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.VitroQueryWrapper;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapper;
|
||||
|
@ -109,6 +113,13 @@ public class IndividualController extends FreeMarkerHttpServlet {
|
|||
return;
|
||||
}
|
||||
|
||||
// If this is an uploaded file, redirect to its "alias URL".
|
||||
String aliasUrl = getAliasUrlForBytestreamIndividual(indiv);
|
||||
if (aliasUrl != null) {
|
||||
res.sendRedirect(req.getContextPath() + aliasUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
doHtml( vreq, res , indiv);
|
||||
return;
|
||||
|
||||
|
@ -488,6 +499,47 @@ public class IndividualController extends FreeMarkerHttpServlet {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this entity represents a File Bytestream, get its alias URL so we can
|
||||
* properly serve the file contents.
|
||||
*/
|
||||
private String getAliasUrlForBytestreamIndividual(Individual entity)
|
||||
throws IOException {
|
||||
if (!FileModelHelper.isFileBytestream(entity)) {
|
||||
log.debug("Entity at '" + entity.getURI()
|
||||
+ "' is not recognized as a FileByteStream.");
|
||||
return null;
|
||||
}
|
||||
|
||||
FileStorage fs = (FileStorage) getServletContext().getAttribute(
|
||||
FileStorageSetup.ATTRIBUTE_NAME);
|
||||
if (fs == null) {
|
||||
log.error("Servlet context does not contain file storage at '"
|
||||
+ FileStorageSetup.ATTRIBUTE_NAME + "'");
|
||||
return null;
|
||||
}
|
||||
|
||||
String filename = fs.getFilename(entity.getURI());
|
||||
if (filename == null) {
|
||||
log.error("Entity at '" + entity.getURI()
|
||||
+ "' is recognized as a FileByteStream, "
|
||||
+ "but the file system does not recognize it.");
|
||||
return null;
|
||||
}
|
||||
|
||||
String url = FileServingHelper.getBytestreamAliasUrl(entity.getURI(),
|
||||
filename);
|
||||
if (url.equals(entity.getURI())) {
|
||||
log.error("Entity at '" + entity.getURI()
|
||||
+ "' is recognized as a FileByteStream, "
|
||||
+ "but can't be translated to an alias URL.");
|
||||
return null;
|
||||
}
|
||||
|
||||
log.debug("Alias URL for '" + entity.getURI() + "' is '" + url + "'");
|
||||
return url;
|
||||
}
|
||||
|
||||
private Model getRDF(Individual entity, OntModel contextModel, Model newModel, int recurseDepth ) {
|
||||
Resource subj = newModel.getResource(entity.getURI());
|
||||
|
||||
|
|
|
@ -2,18 +2,14 @@
|
|||
|
||||
package edu.cornell.mannlib.vitro.webapp.dao;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.vocabulary.XSD;
|
||||
import com.hp.hpl.jena.ontology.AnnotationProperty;
|
||||
|
||||
public class VitroVocabulary {
|
||||
|
||||
|
||||
public static final String vitroURI = "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#";
|
||||
|
||||
public static final String VITRO_PUBLIC = "http://vitro.mannlib.cornell.edu/ns/vitro/public#";
|
||||
|
||||
|
||||
/** BJL23 2008-02-25:
|
||||
* This is a hack. The classic Vitro code is heavily reliant on simple identifiers, and it will take some doing to completely
|
||||
|
@ -91,8 +87,6 @@ public class VitroVocabulary {
|
|||
public static final String DISPLAY_LIMIT = vitroURI+"displayLimitAnnot";
|
||||
|
||||
public static final String CITATION = vitroURI+"citation";
|
||||
public static final String IMAGEFILE = vitroURI+"imageFile";
|
||||
public static final String IMAGETHUMB = vitroURI+"imageThumb";
|
||||
|
||||
// ================== property related =================================
|
||||
|
||||
|
@ -284,5 +278,18 @@ public class VitroVocabulary {
|
|||
|
||||
public static final String ONTOLOGY_PREFIX_ANNOT = vitroURI + "ontologyPrefixAnnot";
|
||||
|
||||
// =============== file storage vocabulary ================================
|
||||
|
||||
public static final String FS_FILE_CLASS = VITRO_PUBLIC + "File";
|
||||
public static final String FS_BYTESTREAM_CLASS = VITRO_PUBLIC + "FileByteStream";
|
||||
|
||||
public static final String FS_FILENAME = VITRO_PUBLIC + "filename";
|
||||
public static final String FS_MIME_TYPE = VITRO_PUBLIC + "mimeType";
|
||||
public static final String FS_ATTRIBUTION = VITRO_PUBLIC + "attribution";
|
||||
public static final String FS_DOWNLOAD_LOCATION = VITRO_PUBLIC + "downloadLocation";
|
||||
public static final String FS_THUMBNAIL_IMAGE = VITRO_PUBLIC + "thumbnailImage";
|
||||
|
||||
public static final String IND_MAIN_IMAGE = VITRO_PUBLIC + "mainImage";
|
||||
public static final String IND_IMAGE = VITRO_PUBLIC + "image";
|
||||
|
||||
}
|
||||
|
|
|
@ -242,18 +242,24 @@ public class IndividualFiltering implements Individual {
|
|||
return _innerIndividual.getFlag3Set();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMainImageUri() {
|
||||
return _innerIndividual.getMainImageUri();
|
||||
}
|
||||
|
||||
public String getImageFile() {
|
||||
return _innerIndividual.getImageFile();
|
||||
}
|
||||
@Override
|
||||
public String getImageUrl() {
|
||||
return _innerIndividual.getImageUrl();
|
||||
}
|
||||
|
||||
|
||||
public String getImageThumb() {
|
||||
return _innerIndividual.getImageThumb();
|
||||
}
|
||||
@Override
|
||||
public String getThumbUrl() {
|
||||
return _innerIndividual.getThumbUrl();
|
||||
}
|
||||
|
||||
|
||||
public List<String> getKeywords() {
|
||||
public List<String> getKeywords() {
|
||||
return _innerIndividual.getKeywords();
|
||||
}
|
||||
|
||||
|
@ -405,15 +411,10 @@ public class IndividualFiltering implements Individual {
|
|||
}
|
||||
|
||||
|
||||
public void setImageFile(String imageFile) {
|
||||
_innerIndividual.setImageFile(imageFile);
|
||||
}
|
||||
|
||||
|
||||
public void setImageThumb(String imageThumb) {
|
||||
_innerIndividual.setImageThumb(imageThumb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMainImageUri(String mainImageUri) {
|
||||
_innerIndividual.setMainImageUri(mainImageUri);
|
||||
}
|
||||
|
||||
public void setKeywords(List<String> keywords) {
|
||||
_innerIndividual.setKeywords(keywords);
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import com.hp.hpl.jena.ontology.DatatypeProperty;
|
||||
import com.hp.hpl.jena.ontology.OntClass;
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
import com.hp.hpl.jena.ontology.OntResource;
|
||||
|
@ -56,7 +55,6 @@ import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
|||
import edu.cornell.mannlib.vitro.webapp.dao.InsertException;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.KeywordDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualCreationEvent;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualDeletionEvent;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualUpdateEvent;
|
||||
|
@ -313,8 +311,10 @@ public class IndividualDaoJena extends JenaBaseDao implements IndividualDao {
|
|||
addPropertyDateTimeValue(ind,SUNSET,ent.getSunset(), ontModel);
|
||||
addPropertyDateTimeValue(ind,TIMEKEY,ent.getTimekey(), ontModel);
|
||||
addPropertyDateTimeValue(ind,MODTIME,Calendar.getInstance().getTime(),ontModel);
|
||||
addPropertyStringValue(ind,IMAGETHUMB,ent.getImageThumb(),ontModel);
|
||||
addPropertyStringValue(ind,IMAGEFILE,ent.getImageFile(),ontModel);
|
||||
if (ent.getMainImageUri() != null) {
|
||||
addPropertyResourceURIValue(ind, IND_MAIN_IMAGE, ent.getMainImageUri());
|
||||
}
|
||||
|
||||
if (ent.getAnchor()!= null && ent.getAnchor().length()>0 && LINK != null) {
|
||||
com.hp.hpl.jena.ontology.Individual primaryLink = ontModel.createIndividual(entURI+"_primaryLink", LINK);
|
||||
primaryLink.addProperty(RDF.type, LINK);
|
||||
|
@ -379,8 +379,9 @@ public class IndividualDaoJena extends JenaBaseDao implements IndividualDao {
|
|||
ent.getFlag1Numeric();
|
||||
ent.getFlag1Set();
|
||||
ent.getFlag2Set();
|
||||
ent.getImageFile();
|
||||
ent.getImageThumb();
|
||||
ent.getMainImageUri();
|
||||
ent.getImageUrl();
|
||||
ent.getThumbUrl();
|
||||
ent.getKeywords();
|
||||
ent.getKeywordString();
|
||||
ent.getLinksList();
|
||||
|
@ -472,9 +473,8 @@ public class IndividualDaoJena extends JenaBaseDao implements IndividualDao {
|
|||
updatePropertyDateTimeValue(ind,SUNRISE,ent.getSunrise(), ontModel);
|
||||
updatePropertyDateTimeValue(ind,SUNSET,ent.getSunset(), ontModel);
|
||||
updatePropertyDateTimeValue(ind,TIMEKEY,ent.getTimekey(), ontModel);
|
||||
updatePropertyStringValue(ind,IMAGETHUMB,ent.getImageThumb(),ontModel);
|
||||
updatePropertyStringValue(ind,IMAGEFILE,ent.getImageFile(),ontModel);
|
||||
updatePropertyDateTimeValue(ind,MODTIME,Calendar.getInstance().getTime(),ontModel);
|
||||
updatePropertyResourceURIValue(ind, IND_MAIN_IMAGE, ent.getMainImageUri(), ontModel);
|
||||
if (ent.getAnchor()!= null && ent.getAnchor().length()>0) {
|
||||
if (LINK != null && PRIMARY_LINK != null) {
|
||||
boolean updatedExisting = false;
|
||||
|
|
|
@ -40,6 +40,8 @@ import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
|
|||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileModelHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileServingHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.FlagMathUtils;
|
||||
|
||||
public class IndividualJena extends IndividualImpl implements Individual {
|
||||
|
@ -474,33 +476,54 @@ public class IndividualJena extends IndividualImpl implements Individual {
|
|||
}
|
||||
}
|
||||
|
||||
public String getImageFile() {
|
||||
if (this.imageFile != null) {
|
||||
return imageFile;
|
||||
} else {
|
||||
ind.getOntModel().enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
imageFile = webappDaoFactory.getJenaBaseDao().getPropertyStringValue(ind,webappDaoFactory.getJenaBaseDao().IMAGEFILE);
|
||||
return imageFile;
|
||||
} finally {
|
||||
ind.getOntModel().leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String getMainImageUri() {
|
||||
if (this.mainImageUri != NOT_INITIALIZED) {
|
||||
return mainImageUri;
|
||||
} else {
|
||||
for (ObjectPropertyStatement stmt : getObjectPropertyStatements()) {
|
||||
if (stmt.getPropertyURI()
|
||||
.equals(VitroVocabulary.IND_MAIN_IMAGE)) {
|
||||
mainImageUri = stmt.getObjectURI();
|
||||
return mainImageUri;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getImageThumb() {
|
||||
if (this.imageThumb != null) {
|
||||
return imageThumb;
|
||||
} else {
|
||||
ind.getOntModel().enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
imageThumb = webappDaoFactory.getJenaBaseDao().getPropertyStringValue(ind,webappDaoFactory.getJenaBaseDao().IMAGETHUMB);
|
||||
return imageThumb;
|
||||
} finally {
|
||||
ind.getOntModel().leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String getImageUrl() {
|
||||
if (this.imageUrl != null) {
|
||||
log.debug("imageUrl was cached for " + getURI() + ": '"
|
||||
+ this.imageUrl + "'");
|
||||
return imageUrl;
|
||||
} else {
|
||||
String imageUri = FileModelHelper.getMainImageBytestreamUri(this);
|
||||
String filename = FileModelHelper.getMainImageFilename(this);
|
||||
imageUrl = FileServingHelper.getBytestreamAliasUrl(imageUri,
|
||||
filename);
|
||||
log.debug("figured imageUrl for " + getURI() + ": '"
|
||||
+ this.imageUrl + "'");
|
||||
return imageUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getThumbUrl() {
|
||||
if (this.thumbUrl != null) {
|
||||
log.debug("thumbUrl was cached for " + getURI() + ": '"
|
||||
+ this.thumbUrl + "'");
|
||||
return thumbUrl;
|
||||
} else {
|
||||
String imageUri = FileModelHelper.getThumbnailBytestreamUri(this);
|
||||
String filename = FileModelHelper.getThumbnailFilename(this);
|
||||
thumbUrl = FileServingHelper.getBytestreamAliasUrl(imageUri, filename);
|
||||
log.debug("figured thumbUrl for " + getURI() + ": '"
|
||||
+ this.thumbUrl + "'");
|
||||
return thumbUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public String getAnchor() {
|
||||
if (this.anchor != null) {
|
||||
|
|
|
@ -60,8 +60,6 @@ public class JenaBaseDaoCon {
|
|||
protected DatatypeProperty MODTIME = _constModel.createDatatypeProperty(VitroVocabulary.MODTIME);
|
||||
protected DatatypeProperty TIMEKEY = _constModel.createDatatypeProperty(VitroVocabulary.TIMEKEY);
|
||||
protected DatatypeProperty CITATION = _constModel.createDatatypeProperty(VitroVocabulary.CITATION);
|
||||
protected DatatypeProperty IMAGETHUMB = _constModel.createDatatypeProperty(VitroVocabulary.IMAGETHUMB);
|
||||
protected DatatypeProperty IMAGEFILE = _constModel.createDatatypeProperty(VitroVocabulary.IMAGEFILE);
|
||||
|
||||
protected DatatypeProperty DISPLAY_RANK = _constModel.createDatatypeProperty(VitroVocabulary.DISPLAY_RANK);
|
||||
protected AnnotationProperty DISPLAY_RANK_ANNOT = _constModel.createAnnotationProperty(VitroVocabulary.DISPLAY_RANK_ANNOT);
|
||||
|
@ -183,6 +181,17 @@ public class JenaBaseDaoCon {
|
|||
|
||||
protected AnnotationProperty ONTOLOGY_PREFIX_ANNOT = _constModel.createAnnotationProperty(VitroVocabulary.ONTOLOGY_PREFIX_ANNOT);
|
||||
|
||||
protected OntClass FS_FILE = _constModel.createClass(VitroVocabulary.FS_FILE_CLASS);
|
||||
protected OntClass FS_BYTESTREAM = _constModel.createClass(VitroVocabulary.FS_BYTESTREAM_CLASS);
|
||||
protected ObjectProperty FS_DOWNLOAD_LOCATION = _constModel.createObjectProperty(VitroVocabulary.FS_DOWNLOAD_LOCATION);
|
||||
protected ObjectProperty FS_THUMBNAIL_IMAGE = _constModel.createObjectProperty(VitroVocabulary.FS_THUMBNAIL_IMAGE);
|
||||
protected DatatypeProperty FS_FILENAME = _constModel.createDatatypeProperty(VitroVocabulary.FS_FILENAME);
|
||||
protected DatatypeProperty FS_MIME_TYPE = _constModel.createDatatypeProperty(VitroVocabulary.FS_MIME_TYPE);
|
||||
protected DatatypeProperty FS_ATTRIBUTION = _constModel.createDatatypeProperty(VitroVocabulary.FS_ATTRIBUTION);
|
||||
|
||||
protected ObjectProperty IND_MAIN_IMAGE = _constModel.createObjectProperty(VitroVocabulary.IND_MAIN_IMAGE);
|
||||
protected ObjectProperty IND_IMAGE = _constModel.createObjectProperty(VitroVocabulary.IND_IMAGE);
|
||||
|
||||
public OntModel getConstModel() {
|
||||
return _constModel;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class TabEntityFactoryGalleryJena extends TabEntityFactoryJena
|
|||
implements TabEntityFactory {
|
||||
|
||||
private TabEntityFactory _innerFactory = null;
|
||||
public final UnaryFunctor<Individual,Boolean>onlyWithThumbs = new OnlyWithThumbs();
|
||||
public final UnaryFunctor<Individual,Boolean>onlyWithMainImage = new OnlyWithMainImage();
|
||||
|
||||
public TabEntityFactoryGalleryJena(TabEntityFactory innerEntFactory, Tab tab, int auth_level, ApplicationBean appBean, WebappDaoFactoryJena wadf) {
|
||||
super(tab, auth_level, appBean, wadf);
|
||||
|
@ -79,7 +79,7 @@ public class TabEntityFactoryGalleryJena extends TabEntityFactoryJena
|
|||
return Collections.EMPTY_LIST;
|
||||
|
||||
List filteredEnts = new LinkedList( );
|
||||
Filter.filter(ents,onlyWithThumbs,filteredEnts);
|
||||
Filter.filter(ents,onlyWithMainImage,filteredEnts);
|
||||
|
||||
if( filteredEnts.size() <= numberOfrequestedEnts)
|
||||
return filteredEnts;
|
||||
|
@ -94,10 +94,10 @@ public class TabEntityFactoryGalleryJena extends TabEntityFactoryJena
|
|||
return entsOut;
|
||||
}
|
||||
|
||||
private class OnlyWithThumbs extends UnaryFunctor<Individual,Boolean>{
|
||||
private class OnlyWithMainImage extends UnaryFunctor<Individual,Boolean>{
|
||||
@Override
|
||||
public Boolean fn(Individual arg) {
|
||||
return arg.getImageThumb() != null;
|
||||
return arg.getMainImageUri()!= null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,411 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatementImpl;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatementImpl;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.InsertException;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A collection of methods to help manipulate the model, with regard to uploaded
|
||||
* files.
|
||||
* </p>
|
||||
* <p>
|
||||
* Some of the public methods are static, since the Individual that is passed as
|
||||
* a parameter holds all necessary references for the operation. Other methods
|
||||
* require an instance, which is initialized with a {@link WebappDaoFactory}.
|
||||
* </p>
|
||||
*/
|
||||
public class FileModelHelper {
|
||||
private static final Logger log = Logger.getLogger(FileModelHelper.class);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Static methods -- the Individual holds all necessary references.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Is this a FileByteStream individual?
|
||||
*/
|
||||
public static boolean isFileBytestream(Individual entity) {
|
||||
for (VClass vClass : entity.getVClasses()) {
|
||||
if (VitroVocabulary.FS_BYTESTREAM_CLASS.equals(vClass.getURI())) {
|
||||
log.debug("Entity '" + entity.getURI() + "' is a bytestream");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
log.debug("Entity '" + entity.getURI() + "' is not a bytestream");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate the file surrogate for the main image of this entity.
|
||||
*
|
||||
* @return the surrogate, or <code>null</code> if there is no such image, or
|
||||
* if the entity itself is <code>null</code>.
|
||||
*/
|
||||
public static Individual getMainImage(Individual entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Individual mainFile = entity
|
||||
.getRelatedIndividual(VitroVocabulary.IND_MAIN_IMAGE);
|
||||
|
||||
if (mainFile == null) {
|
||||
log.debug("Entity '" + entity.getURI()
|
||||
+ "' had no associated main image.");
|
||||
return null;
|
||||
} else {
|
||||
log.debug("Entity '" + entity.getURI()
|
||||
+ "' had associated main image: '" + mainFile.getURI()
|
||||
+ "'");
|
||||
return mainFile;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate the file surrogate for the thumbnail of this file.
|
||||
*
|
||||
* @return the surrogate, or <code>null</code> if there is no thumbnail, or
|
||||
* if the file itself is <code>null</code>.
|
||||
*/
|
||||
public static Individual getThumbnailForImage(Individual fileSurrogate) {
|
||||
if (fileSurrogate == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Individual thumbFile = fileSurrogate
|
||||
.getRelatedIndividual(VitroVocabulary.FS_THUMBNAIL_IMAGE);
|
||||
|
||||
if (thumbFile == null) {
|
||||
log.warn("Main image file '" + fileSurrogate.getURI()
|
||||
+ "' had no associated thumbnail.");
|
||||
return null;
|
||||
} else {
|
||||
log.debug("Main image file '" + fileSurrogate.getURI()
|
||||
+ "' had associated thumbnail: '" + thumbFile.getURI()
|
||||
+ "'");
|
||||
return thumbFile;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate the bytestream object for this file.
|
||||
*
|
||||
* @return the bytestream object, or <code>null</code> if there is no
|
||||
* bytestream, or if the file itself is <code>null</code>.
|
||||
*/
|
||||
public static Individual getBytestreamForFile(Individual fileSurrogate) {
|
||||
if (fileSurrogate == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Individual byteStream = fileSurrogate
|
||||
.getRelatedIndividual(VitroVocabulary.FS_DOWNLOAD_LOCATION);
|
||||
|
||||
if (byteStream == null) {
|
||||
log.error("File surrogate '" + fileSurrogate.getURI()
|
||||
+ "' had no associated bytestream.");
|
||||
return null;
|
||||
} else {
|
||||
log.debug("File surroage'" + fileSurrogate.getURI()
|
||||
+ "' had associated bytestream: '" + byteStream.getURI()
|
||||
+ "'");
|
||||
return byteStream;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the filename for this file.
|
||||
*
|
||||
* @return the filename, or <code>null</code> if the file itself is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public static String getFilename(Individual fileSurrogate) {
|
||||
if (fileSurrogate == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String filename = fileSurrogate
|
||||
.getDataValue(VitroVocabulary.FS_FILENAME);
|
||||
|
||||
if (filename == null) {
|
||||
log.error("File had no filename: '" + fileSurrogate.getURI() + "'");
|
||||
} else {
|
||||
log.debug("Filename for '" + fileSurrogate.getURI() + "' was '"
|
||||
+ filename + "'");
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the MIME type for this file.
|
||||
*
|
||||
* @return the MIME type, or <code>null</code> if the file itself is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public static String getMimeType(Individual fileSurrogate) {
|
||||
if (fileSurrogate == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String mimeType = fileSurrogate
|
||||
.getDataValue(VitroVocabulary.FS_MIME_TYPE);
|
||||
|
||||
if (mimeType == null) {
|
||||
log.error("File had no mimeType: '" + fileSurrogate.getURI() + "'");
|
||||
} else {
|
||||
log.debug("mimeType for '" + fileSurrogate.getURI() + "' was '"
|
||||
+ mimeType + "'");
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URI for this individual, or <code>null</code> if the
|
||||
* individual is <code>null</code>.
|
||||
*/
|
||||
private static String getUri(Individual entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
} else {
|
||||
return entity.getURI();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate the URI of the bytestream of the main image for this entity.
|
||||
*
|
||||
* @return the URI, or <code>null</code> if there is no such bytestream, or
|
||||
* if the entity itself is <code>null</code>.
|
||||
*/
|
||||
public static String getMainImageBytestreamUri(Individual entity) {
|
||||
Individual mainFile = getMainImage(entity);
|
||||
Individual byteStream = getBytestreamForFile(mainFile);
|
||||
return getUri(byteStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the filename of the main image for this entity.
|
||||
*
|
||||
* @return the filename, or <code>null</code> if there is no such image.
|
||||
*/
|
||||
public static String getMainImageFilename(Individual entity) {
|
||||
Individual mainFile = getMainImage(entity);
|
||||
return getFilename(mainFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate the individual that represents the bytestream of the thumbnail of
|
||||
* the main image for this entity.
|
||||
*
|
||||
* @return the URI, or <code>null</code> if there is no such thumbnail
|
||||
* image, or if the entity itself is <code>null</code>.
|
||||
*/
|
||||
public static String getThumbnailBytestreamUri(Individual entity) {
|
||||
Individual mainFile = getMainImage(entity);
|
||||
Individual thumbFile = getThumbnailForImage(mainFile);
|
||||
Individual byteStream = getBytestreamForFile(thumbFile);
|
||||
return getUri(byteStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the filename of the thumbnail of the main image.
|
||||
*
|
||||
* @return the filename, or <code>null</code> if there is no such thumbnail
|
||||
* image, or if the entity itself is <code>null</code>.
|
||||
*/
|
||||
public static String getThumbnailFilename(Individual entity) {
|
||||
Individual mainFile = getMainImage(entity);
|
||||
Individual thumbFile = getThumbnailForImage(mainFile);
|
||||
return getFilename(thumbFile);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Instance methods -- need access to a WebappDaoFactory
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private final IndividualDao individualDao;
|
||||
private final ObjectPropertyStatementDao objectPropertyStatementDao;
|
||||
private final DataPropertyStatementDao dataPropertyStatementDao;
|
||||
|
||||
public FileModelHelper(WebappDaoFactory webappDaoFactory) {
|
||||
this.individualDao = webappDaoFactory.getIndividualDao();
|
||||
this.objectPropertyStatementDao = webappDaoFactory
|
||||
.getObjectPropertyStatementDao();
|
||||
this.dataPropertyStatementDao = webappDaoFactory
|
||||
.getDataPropertyStatementDao();
|
||||
}
|
||||
|
||||
/**
|
||||
* Some of these methods require an Individual as an argument.
|
||||
*/
|
||||
public Individual getIndividualByUri(String uri) {
|
||||
return individualDao.getIndividualByURI(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* If this URI represents a ByteStream object, we need to find it's
|
||||
* surrogate object in order to find the mime type.
|
||||
*
|
||||
* @return the mime type, or <code>null</code> if we couldn't find the mime
|
||||
* type, or if the bytestream object itself is null.
|
||||
*/
|
||||
public String getMimeTypeForBytestream(String bytestreamUri) {
|
||||
if (bytestreamUri == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ObjectPropertyStatement opStmt = new ObjectPropertyStatementImpl(null,
|
||||
VitroVocabulary.FS_DOWNLOAD_LOCATION, bytestreamUri);
|
||||
List<ObjectPropertyStatement> stmts = objectPropertyStatementDao
|
||||
.getObjectPropertyStatements(opStmt);
|
||||
if (stmts.size() > 1) {
|
||||
String uris = "";
|
||||
for (ObjectPropertyStatement stmt : stmts) {
|
||||
uris += "'" + stmt.getSubjectURI() + "' ";
|
||||
}
|
||||
log.warn("Found " + stmts.size() + " Individuals that claim '"
|
||||
+ bytestreamUri + "' as its bytestream:" + uris);
|
||||
}
|
||||
if (stmts.isEmpty()) {
|
||||
log.warn("No individual claims '" + "' as its bytestream.");
|
||||
return null;
|
||||
}
|
||||
Individual surrogate = individualDao.getIndividualByURI(stmts.get(0)
|
||||
.getSubjectURI());
|
||||
|
||||
return getMimeType(surrogate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file surrogate individual in the model.
|
||||
*/
|
||||
public Individual createFileIndividual(String mimeType, String filename,
|
||||
Individual byteStream) {
|
||||
Individual file = new IndividualImpl();
|
||||
file.setVClassURI(VitroVocabulary.FS_FILE_CLASS);
|
||||
|
||||
String uri = null;
|
||||
try {
|
||||
uri = individualDao.insertNewIndividual(file);
|
||||
} catch (InsertException e) {
|
||||
throw new IllegalStateException(
|
||||
"Failed to create the file individual.", e);
|
||||
}
|
||||
|
||||
dataPropertyStatementDao
|
||||
.insertNewDataPropertyStatement(new DataPropertyStatementImpl(
|
||||
uri, VitroVocabulary.FS_FILENAME, filename));
|
||||
dataPropertyStatementDao
|
||||
.insertNewDataPropertyStatement(new DataPropertyStatementImpl(
|
||||
uri, VitroVocabulary.FS_MIME_TYPE, mimeType));
|
||||
objectPropertyStatementDao
|
||||
.insertNewObjectPropertyStatement(new ObjectPropertyStatementImpl(
|
||||
uri, VitroVocabulary.FS_DOWNLOAD_LOCATION, byteStream
|
||||
.getURI()));
|
||||
|
||||
return individualDao.getIndividualByURI(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a bytestream individual in the model.
|
||||
*/
|
||||
public Individual createByteStreamIndividual() {
|
||||
Individual byteStream = new IndividualImpl();
|
||||
byteStream.setVClassURI(VitroVocabulary.FS_BYTESTREAM_CLASS);
|
||||
|
||||
String uri = null;
|
||||
try {
|
||||
uri = individualDao.insertNewIndividual(byteStream);
|
||||
} catch (InsertException e) {
|
||||
throw new IllegalStateException(
|
||||
"Failed to create the bytestream individual.", e);
|
||||
}
|
||||
|
||||
return individualDao.getIndividualByURI(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this file surrogate as the main image on this entity.
|
||||
*/
|
||||
public void setAsMainImageOnEntity(Individual person,
|
||||
Individual imageSurrogate) {
|
||||
person.setMainImageUri(imageSurrogate.getURI());
|
||||
individualDao.updateIndividual(person);
|
||||
log.debug("Set main image '" + getUri(imageSurrogate) + "' on '"
|
||||
+ person.getURI() + "'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the current main image from this entity.
|
||||
*
|
||||
* @return the file surrogate, or <code>null</code> if there was none.
|
||||
*/
|
||||
public Individual removeMainImage(Individual person) {
|
||||
Individual mainImage = getMainImage(person);
|
||||
person.setMainImageUri(null);
|
||||
individualDao.updateIndividual(person);
|
||||
log.debug("Removed main image '" + getUri(mainImage) + "' from '"
|
||||
+ person.getURI() + "'");
|
||||
return mainImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this file surrogate as the thumnail on this entity.
|
||||
*/
|
||||
public void setThumbnailOnIndividual(Individual entity,
|
||||
Individual thumbnailSurrogate) {
|
||||
String mainImageUri = entity.getMainImageUri();
|
||||
objectPropertyStatementDao
|
||||
.insertNewObjectPropertyStatement(new ObjectPropertyStatementImpl(
|
||||
mainImageUri, VitroVocabulary.FS_THUMBNAIL_IMAGE,
|
||||
thumbnailSurrogate.getURI()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Are there any ObjectPropertyStatements in the model whose object is this
|
||||
* file surrogate?
|
||||
*/
|
||||
public boolean isFileReferenced(Individual surrogate) {
|
||||
ObjectPropertyStatement opStmt = new ObjectPropertyStatementImpl(null,
|
||||
null, surrogate.getURI());
|
||||
List<ObjectPropertyStatement> stmts = objectPropertyStatementDao
|
||||
.getObjectPropertyStatements(opStmt);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(stmts.size() + " statements referencing '"
|
||||
+ surrogate.getURI() + "'");
|
||||
for (ObjectPropertyStatement stmt : stmts) {
|
||||
log.debug("'" + stmt.getSubjectURI() + "' -- '"
|
||||
+ stmt.getPropertyURI() + "' -- '"
|
||||
+ stmt.getObjectURI() + "'");
|
||||
}
|
||||
}
|
||||
return !stmts.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* This file is being deleted; remove both the surrogate and its bytestream
|
||||
* from the model.
|
||||
*/
|
||||
public void removeFileFromModel(Individual surrogate) {
|
||||
Individual bytestream = getBytestreamForFile(surrogate);
|
||||
individualDao.deleteIndividual(bytestream);
|
||||
individualDao.deleteIndividual(surrogate);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||
|
||||
/**
|
||||
* Static methods to help when serving uploaded files.
|
||||
*/
|
||||
public class FileServingHelper {
|
||||
private static final Logger log = Logger.getLogger(FileServingHelper.class);
|
||||
|
||||
private static final String DEFAULT_PATH = "/individual/";
|
||||
private static final String FILE_PATH = "/file/";
|
||||
private static final String DEFAULT_NAMESPACE = initializeDefaultNamespace();
|
||||
|
||||
/**
|
||||
* At startup, get the default namespace from the configuration properties,
|
||||
* and trim off the suffix.
|
||||
*/
|
||||
private static String initializeDefaultNamespace() {
|
||||
String defaultNamespace = ConfigurationProperties
|
||||
.getProperty(FileStorageSetup.PROPERTY_DEFAULT_NAMESPACE);
|
||||
if (defaultNamespace == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Configuration properties must contain a value for '"
|
||||
+ FileStorageSetup.PROPERTY_DEFAULT_NAMESPACE + "'");
|
||||
}
|
||||
|
||||
if (!defaultNamespace.endsWith(DEFAULT_PATH)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Default namespace does not match the expected form: '"
|
||||
+ defaultNamespace + "'");
|
||||
}
|
||||
|
||||
return defaultNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Combine the URI and the filename to produce a relative URL for the file
|
||||
* (relative to the context of the webapp).
|
||||
* </p>
|
||||
* <p>
|
||||
* This should involve stripping the default namespace from the front of the
|
||||
* URL, replacing it with the file prefix, and adding the filename to the
|
||||
* end.
|
||||
* </p>
|
||||
*
|
||||
* @return <ul>
|
||||
* <li>the translated URL, if the URI was in the default namespace,</li>
|
||||
* <li>the original URI, if it wasn't in the default namespace,</li>
|
||||
* <li>null, if the original URI or the filename was null.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static String getBytestreamAliasUrl(String uri, String filename) {
|
||||
if ((uri == null) || (filename == null)) {
|
||||
return null;
|
||||
}
|
||||
if (!uri.startsWith(DEFAULT_NAMESPACE)) {
|
||||
log.warn("uri does not start with the default namespace: '" + uri
|
||||
+ "'");
|
||||
return uri;
|
||||
}
|
||||
String remainder = uri.substring(DEFAULT_NAMESPACE.length());
|
||||
String separator = remainder.endsWith("/") ? "" : "/";
|
||||
return FILE_PATH + remainder + separator + filename;
|
||||
}
|
||||
|
||||
/** No need for instances because all of the methods are static. */
|
||||
private FileServingHelper() {
|
||||
// nothing to instantiate.
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Take a relative URL (relative to the context of the webapp) and produce
|
||||
* the URI for the file bytestream.
|
||||
* </p>
|
||||
* <p>
|
||||
* This should involve removing the filename from the end of the URL, and
|
||||
* replacing the file prefix with the default namespace.
|
||||
* </p>
|
||||
*
|
||||
* @return the URI, or <code>null</code> if the URL couldn't be translated.
|
||||
*/
|
||||
public static String getBytestreamUri(String path) {
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
if (!path.startsWith(FILE_PATH)) {
|
||||
log.warn("path does not start with a file prefix: '" + path + "'");
|
||||
return null;
|
||||
}
|
||||
String remainder = path.substring(FILE_PATH.length());
|
||||
|
||||
int slashHere = remainder.lastIndexOf('/');
|
||||
if (slashHere == -1) {
|
||||
log.debug("path does not include a filename: '" + path + "'");
|
||||
return null;
|
||||
}
|
||||
remainder = remainder.substring(0, slashHere);
|
||||
|
||||
return DEFAULT_NAMESPACE + remainder;
|
||||
}
|
||||
}
|
|
@ -23,10 +23,13 @@ import java.util.Properties;
|
|||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* The default implementation of {@link FileStorage}.
|
||||
*/
|
||||
public class FileStorageImpl implements FileStorage {
|
||||
private static final Logger log = Logger.getLogger(FileStorageImpl.class);
|
||||
|
||||
private final File baseDir;
|
||||
private final File rootDir;
|
||||
|
@ -290,6 +293,8 @@ public class FileStorageImpl implements FileStorage {
|
|||
public String getFilename(String id) throws IOException {
|
||||
File dir = FileStorageHelper.getPathToIdDirectory(id,
|
||||
this.namespacesMap, this.rootDir);
|
||||
log.debug("ID '" + id + "' translates to this directory path: '" + dir
|
||||
+ "'");
|
||||
|
||||
if ((!dir.exists()) || (!dir.isDirectory())) {
|
||||
return null;
|
||||
|
|
|
@ -28,13 +28,13 @@ public class FileStorageSetup implements ServletContextListener {
|
|||
* The default implementation will use this key to ask
|
||||
* {@link ConfigurationProperties} for the file storage base directory.
|
||||
*/
|
||||
static final String PROPERTY_FILE_STORAGE_BASE_DIR = "upload.directory";
|
||||
public static final String PROPERTY_FILE_STORAGE_BASE_DIR = "upload.directory";
|
||||
|
||||
/**
|
||||
* The default implementation will use this key to ask
|
||||
* {@link ConfigurationProperties} for the default URI namespace.
|
||||
*/
|
||||
static final String PROPERTY_DEFAULT_NAMESPACE = "Vitro.defaultNamespace";
|
||||
public static final String PROPERTY_DEFAULT_NAMESPACE = "Vitro.defaultNamespace";
|
||||
|
||||
/**
|
||||
* Create an implementation of {@link FileStorage} and store it in the
|
||||
|
@ -46,7 +46,7 @@ public class FileStorageSetup implements ServletContextListener {
|
|||
FileStorage fs;
|
||||
try {
|
||||
File baseDirectory = figureBaseDir();
|
||||
Collection<String> fileNamespace = figureFileNamespace();
|
||||
Collection<String> fileNamespace = confirmDefaultNamespace();
|
||||
fs = new FileStorageImpl(baseDirectory, fileNamespace);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(
|
||||
|
@ -75,16 +75,15 @@ public class FileStorageSetup implements ServletContextListener {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the configuration property for the default namespace, and derive the
|
||||
* file namespace from it. The default namespace is assumed to be in this
|
||||
* form: <code>http://vivo.mydomain.edu/individual/</code>
|
||||
* Get the configuration property for the default namespace, and confirm
|
||||
* that it is in the proper form. The default namespace is assumed to be in
|
||||
* this form: <code>http://vivo.mydomain.edu/individual/</code>
|
||||
*
|
||||
* For use by the constructor in implementations of {@link FileStorage}.
|
||||
*
|
||||
* @returns the file namespace is assumed to be in this form:
|
||||
* <code>http://vivo.mydomain.edu/file/</code>
|
||||
* @returns a collection containing the default namespace.
|
||||
*/
|
||||
private Collection<String> figureFileNamespace() {
|
||||
private Collection<String> confirmDefaultNamespace() {
|
||||
String defaultNamespace = ConfigurationProperties
|
||||
.getProperty(PROPERTY_DEFAULT_NAMESPACE);
|
||||
if (defaultNamespace == null) {
|
||||
|
@ -94,7 +93,6 @@ public class FileStorageSetup implements ServletContextListener {
|
|||
}
|
||||
|
||||
String defaultSuffix = "/individual/";
|
||||
String fileSuffix = "/file/";
|
||||
|
||||
if (!defaultNamespace.endsWith(defaultSuffix)) {
|
||||
throw new IllegalArgumentException(
|
||||
|
@ -102,10 +100,7 @@ public class FileStorageSetup implements ServletContextListener {
|
|||
+ defaultNamespace + "'");
|
||||
}
|
||||
|
||||
int hostLength = defaultNamespace.length() - defaultSuffix.length();
|
||||
String fileNamespace = defaultNamespace.substring(0, hostLength)
|
||||
+ fileSuffix;
|
||||
return Collections.singleton(fileNamespace);
|
||||
return Collections.singleton(defaultNamespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.serving;
|
||||
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.UnavailableException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileModelHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileServingHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Handles a request to serve an uploaded file from the file storage system.
|
||||
* </p>
|
||||
* <p>
|
||||
* The path of the request should be the "alias URL" of the desired file. We
|
||||
* need to:
|
||||
* <ul>
|
||||
* <li>Use the alias URL to find the URI of the file bytestream object.</li>
|
||||
* <li>Find the file surrogate object to get the MIME type of the file, and
|
||||
* confirm the filename.</li>
|
||||
* <li>Set the MIME type on the output stream and serve the bytes.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* If the request is superficially correct, but no such file can be found,
|
||||
* return a 404. If there is a break in the data structures within the model or
|
||||
* the file system, return a 500.
|
||||
* </p>
|
||||
*/
|
||||
public class FileServingServlet extends VitroHttpServlet {
|
||||
private static final Logger log = Logger
|
||||
.getLogger(FileServingServlet.class);
|
||||
|
||||
private FileStorage fileStorage;
|
||||
|
||||
/**
|
||||
* Get a reference to the File Storage system.
|
||||
*/
|
||||
@Override
|
||||
public void init() throws ServletException {
|
||||
Object o = getServletContext().getAttribute(
|
||||
FileStorageSetup.ATTRIBUTE_NAME);
|
||||
if (o instanceof FileStorage) {
|
||||
fileStorage = (FileStorage) o;
|
||||
} else {
|
||||
throw new UnavailableException(
|
||||
"The ServletContext did not hold a FileStorage object at '"
|
||||
+ FileStorageSetup.ATTRIBUTE_NAME
|
||||
+ "'; found this instead: " + o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest rawRequest,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
VitroRequest request = new VitroRequest(rawRequest);
|
||||
|
||||
// Use the alias URL to get the URI of the bytestream object.
|
||||
String path = request.getServletPath() + request.getPathInfo();
|
||||
log.debug("Path is '" + path + "'");
|
||||
|
||||
String uri = FileServingHelper.getBytestreamUri(path);
|
||||
log.debug("Bytestream URI is '" + uri + "'");
|
||||
if (uri == null) {
|
||||
String message = "The request path is not valid for the File servlet: '"
|
||||
+ path + "'";
|
||||
log.error(message);
|
||||
response.sendError(SC_INTERNAL_SERVER_ERROR, message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate that the file exists, with the requested URI and filename.
|
||||
String requestedFilename = getFilename(path);
|
||||
String actualFilename = fileStorage.getFilename(uri);
|
||||
if (actualFilename == null) {
|
||||
log.debug("Requested a non-existent file: " + path);
|
||||
response.sendError(SC_NOT_FOUND, ("File not found: " + path));
|
||||
return;
|
||||
}
|
||||
if (!actualFilename.equals(requestedFilename)) {
|
||||
log.warn("The requested filename does not match the "
|
||||
+ "actual filename; request: '" + path + "', actual: '"
|
||||
+ actualFilename + "'");
|
||||
response.sendError(SC_NOT_FOUND, ("File not found: " + path));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the MIME type.
|
||||
String mimeType = new FileModelHelper(getWebappDaoFactory())
|
||||
.getMimeTypeForBytestream(uri);
|
||||
|
||||
// Open the actual byte stream.
|
||||
InputStream in;
|
||||
try {
|
||||
in = fileStorage.getInputStream(uri, actualFilename);
|
||||
} catch (FileNotFoundException e) {
|
||||
log.error(e);
|
||||
response.sendError(SC_INTERNAL_SERVER_ERROR, e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Everything is ready and working. Set the status and the content type,
|
||||
* and send the image bytes.
|
||||
*/
|
||||
response.setStatus(SC_OK);
|
||||
|
||||
if (mimeType != null) {
|
||||
response.setContentType(mimeType);
|
||||
}
|
||||
|
||||
ServletOutputStream out = null;
|
||||
try {
|
||||
out = response.getOutputStream();
|
||||
byte[] buffer = new byte[8192];
|
||||
int howMany;
|
||||
while (-1 != (howMany = in.read(buffer))) {
|
||||
out.write(buffer, 0, howMany);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The filename is the portion of the path after the last slash.
|
||||
*/
|
||||
private String getFilename(String path) {
|
||||
int slashHere = path.lastIndexOf('/');
|
||||
if (slashHere == -1) {
|
||||
return path;
|
||||
} else {
|
||||
return path.substring(slashHere + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A POST request is treated the same as a GET request.
|
||||
*/
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request,
|
||||
HttpServletResponse response) throws ServletException, IOException {
|
||||
doGet(request, response);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/* $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.ResIterator;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
|
||||
/**
|
||||
* Adjust any individual that has a thumbnail with no main image.
|
||||
*/
|
||||
public class AllThumbsAdjuster extends FsuScanner {
|
||||
protected final File imageDirectory;
|
||||
|
||||
public AllThumbsAdjuster(FSUController controller) {
|
||||
super(controller);
|
||||
this.imageDirectory = controller.getImageDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.");
|
||||
|
||||
ResIterator haveThumb = model.listResourcesWithProperty(thumbProperty);
|
||||
try {
|
||||
while (haveThumb.hasNext()) {
|
||||
Resource resource = haveThumb.next();
|
||||
|
||||
if (resource.getProperty(imageProperty) == null) {
|
||||
createMainImageFromThumbnail(resource);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
haveThumb.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = new File(imageDirectory, thumbFilename);
|
||||
File mainFile = new File(imageDirectory, mainFilename);
|
||||
mainFile = checkNameConflicts(mainFile);
|
||||
FileUtil.copyFile(thumbFile, mainFile);
|
||||
|
||||
resource.addProperty(imageProperty, mainFilename);
|
||||
} catch (IOException e) {
|
||||
updateLog.error(resource, "failed to create main file '"
|
||||
+ mainFilename + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/* $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.ResIterator;
|
||||
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 {
|
||||
protected final File imageDirectory;
|
||||
|
||||
public DeadEndPropertyRemover(FSUController controller) {
|
||||
super(controller);
|
||||
this.imageDirectory = controller.getImageDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
ResIterator resources = model.listResourcesWithProperty(prop);
|
||||
try {
|
||||
while (resources.hasNext()) {
|
||||
Resource resource = resources.next();
|
||||
removeDeadEndPropertiesFromResource(resource, prop, label);
|
||||
}
|
||||
} finally {
|
||||
resources.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = new File(imageDirectory, filename);
|
||||
if (!file.exists()) {
|
||||
updateLog.warn(resource, "removing link to " + label + " '"
|
||||
+ filename + "': file does not exist at '"
|
||||
+ file.getAbsolutePath() + "'.");
|
||||
model.remove(stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/* $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.FileModelHelper;
|
||||
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 directory where the old-style images were stored. */
|
||||
File getImageDirectory();
|
||||
|
||||
/** The file storage system. */
|
||||
FileStorage getFileStorage();
|
||||
|
||||
/** A file model helper with access to the DAO layer. */
|
||||
FileModelHelper getFileModelHelper();
|
||||
|
||||
/** Where to store the files that were translated. */
|
||||
File getTranslatedDirectory();
|
||||
|
||||
/** Where to store the files that weren't in use anyway. */
|
||||
File getUnreferencedDirectory();
|
||||
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
/* $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) throws IOException {
|
||||
this.logFile = generateTimestampedFilename(logDirectory);
|
||||
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) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-sss");
|
||||
String filename = "upgradeLog." + 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";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
/* $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 org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.ResIterator;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileModelHelper;
|
||||
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 = 150;
|
||||
|
||||
/** How high should a generated thumbnail image be (in pixels)? */
|
||||
public static final int THUMBNAIL_HEIGHT = 150;
|
||||
|
||||
/** 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 FileModelHelper fileModelHelper;
|
||||
private final File imageDirectory;
|
||||
private final File upgradeDirectory;
|
||||
|
||||
private FSULog updateLog;
|
||||
|
||||
public FileStorageUpdater(WebappDaoFactory wadf, Model model,
|
||||
FileStorage fileStorage, File uploadDirectory) {
|
||||
this.model = model;
|
||||
this.fileStorage = fileStorage;
|
||||
this.fileModelHelper = new FileModelHelper(wadf);
|
||||
this.imageDirectory = new File(uploadDirectory, "images");
|
||||
this.upgradeDirectory = new File(uploadDirectory, "upgrade");
|
||||
}
|
||||
|
||||
/**
|
||||
* <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);
|
||||
} 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() {
|
||||
ResIterator haveImage = model.listResourcesWithProperty(model
|
||||
.createProperty(IMAGEFILE));
|
||||
try {
|
||||
if (haveImage.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
} finally {
|
||||
haveImage.close();
|
||||
}
|
||||
|
||||
ResIterator haveThumb = model.listResourcesWithProperty(model
|
||||
.createProperty(IMAGETHUMB));
|
||||
try {
|
||||
if (haveThumb.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
} finally {
|
||||
haveThumb.close();
|
||||
}
|
||||
|
||||
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);
|
||||
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 FileModelHelper getFileModelHelper() {
|
||||
return this.fileModelHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileStorage getFileStorage() {
|
||||
return this.fileStorage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getImageDirectory() {
|
||||
return this.imageDirectory;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getTranslatedDirectory() {
|
||||
return new File(this.upgradeDirectory, "translatedImages");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getUnreferencedDirectory() {
|
||||
return new File(this.upgradeDirectory, "unreferencedImages");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/* $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.
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/* $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;
|
||||
|
||||
/**
|
||||
* 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>();
|
||||
StmtIterator stmts = resource.listProperties(property);
|
||||
try {
|
||||
while (stmts.hasNext()) {
|
||||
list.add(stmts.next());
|
||||
}
|
||||
} finally {
|
||||
stmts.close();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/* $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 {
|
||||
protected final File imageDirectory;
|
||||
protected final File translatedDirectory;
|
||||
protected final File unreferencedDirectory;
|
||||
|
||||
public ImageDirectoryCleaner(FSUController controller) {
|
||||
super(controller);
|
||||
this.imageDirectory = controller.getImageDirectory();
|
||||
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(imageDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move all of the files that we translated into the new system.
|
||||
*/
|
||||
private void removeTranslatedFiles(Collection<String> translatedFiles) {
|
||||
for (String path : translatedFiles) {
|
||||
updateLog.log("moving image file '" + path
|
||||
+ "' to the 'translated' directory.");
|
||||
File oldFile = new File(imageDirectory, path);
|
||||
File deletedFile = new File(translatedDirectory, path);
|
||||
try {
|
||||
FileUtil.moveFile(oldFile, deletedFile);
|
||||
} catch (IOException e) {
|
||||
updateLog.error("Failed to move translated file '"
|
||||
+ oldFile.getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = imageDirectory.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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
/* $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.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.FileModelHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
protected final File imageDirectory;
|
||||
protected final FileModelHelper fileModelHelper;
|
||||
protected final FileStorage fileStorage;
|
||||
|
||||
public ImageSchemaTranslater(FSUController controller) {
|
||||
super(controller);
|
||||
this.imageDirectory = controller.getImageDirectory();
|
||||
this.fileStorage = controller.getFileStorage();
|
||||
this.fileModelHelper = controller.getFileModelHelper();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
translateMainImage(resource, mainImages.get(0));
|
||||
translated.add(mainImages.get(0));
|
||||
resource.removeAll(imageProperty);
|
||||
|
||||
List<String> thumbnails = getValues(resource, thumbProperty);
|
||||
if (thumbnails.size() != 1) {
|
||||
updateLog.error(resource, "has " + thumbnails.size()
|
||||
+ " thumbnails: " + thumbnails);
|
||||
return;
|
||||
}
|
||||
|
||||
translateThumbnail(resource, thumbnails.get(0));
|
||||
translated.add(thumbnails.get(0));
|
||||
resource.removeAll(thumbProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the main image into the new system
|
||||
*/
|
||||
private void translateMainImage(Resource resource, String path) {
|
||||
Individual file = translateFile(resource, path, "main image");
|
||||
Individual person = fileModelHelper.getIndividualByUri(resource
|
||||
.getURI());
|
||||
fileModelHelper.setAsMainImageOnEntity(person, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the thumbnail into the new system.
|
||||
*/
|
||||
private void translateThumbnail(Resource resource, String path) {
|
||||
Individual file = translateFile(resource, path, "thumbnail");
|
||||
Individual person = fileModelHelper.getIndividualByUri(resource
|
||||
.getURI());
|
||||
fileModelHelper.setThumbnailOnIndividual(person, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an image file into the new system
|
||||
* <ul>
|
||||
* <li>Create a new File, FileByteStream.</li>
|
||||
* <li>Attempt to infer MIME type.</li>
|
||||
* <li>Copy into the File system.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return the new File surrogate.
|
||||
*/
|
||||
private Individual translateFile(Resource resource, String path,
|
||||
String label) {
|
||||
File oldFile = new File(imageDirectory, path);
|
||||
String filename = getSimpleFilename(path);
|
||||
String mimeType = guessMimeType(resource, filename);
|
||||
|
||||
// Create the file individuals in the model
|
||||
Individual byteStream = fileModelHelper.createByteStreamIndividual();
|
||||
Individual file = fileModelHelper.createFileIndividual(mimeType,
|
||||
filename, byteStream);
|
||||
|
||||
updateLog.log(resource, "translating " + label + " '" + path
|
||||
+ "' into the file storage as '" + file.getURI() + "'");
|
||||
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
// Store the file in the FileStorage system.
|
||||
inputStream = new FileInputStream(oldFile);
|
||||
fileStorage.createFile(byteStream.getURI(), filename, inputStream);
|
||||
} catch (IOException e) {
|
||||
updateLog.error(resource, "Can't create the " + label + " file. ",
|
||||
e);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/* $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.ResIterator;
|
||||
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) {
|
||||
ResIterator resources = model.listResourcesWithProperty(prop);
|
||||
try {
|
||||
while (resources.hasNext()) {
|
||||
Resource resource = resources.next();
|
||||
removeExtraProperties(resource, prop, label);
|
||||
}
|
||||
} finally {
|
||||
resources.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 + "'");
|
||||
}
|
||||
model.remove(stmt);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.filestorage.updater;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.ResIterator;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
|
||||
/**
|
||||
* Adjust any individual that has a main image but no thumbnail.
|
||||
*/
|
||||
public class NoThumbsAdjuster extends FsuScanner {
|
||||
protected final File imageDirectory;
|
||||
|
||||
public NoThumbsAdjuster(FSUController controller) {
|
||||
super(controller);
|
||||
this.imageDirectory = controller.getImageDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.");
|
||||
|
||||
ResIterator haveImage = model.listResourcesWithProperty(imageProperty);
|
||||
try {
|
||||
while (haveImage.hasNext()) {
|
||||
Resource resource = haveImage.next();
|
||||
|
||||
if (resource.getProperty(thumbProperty) == null) {
|
||||
createThumbnailFromMainImage(resource);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
haveImage.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = new File(imageDirectory, mainFilename);
|
||||
File thumbFile = new File(imageDirectory, thumbFilename);
|
||||
thumbFile = checkNameConflicts(thumbFile);
|
||||
try {
|
||||
generateThumbnailImage(mainFile, thumbFile,
|
||||
FileStorageUpdater.THUMBNAIL_WIDTH,
|
||||
FileStorageUpdater.THUMBNAIL_HEIGHT);
|
||||
|
||||
resource.addProperty(thumbProperty, thumbFilename);
|
||||
} catch (IOException e) {
|
||||
updateLog.error(resource, "failed to create thumbnail file '"
|
||||
+ thumbFilename + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in the main image, and scale it to a thumbnail that maintains the
|
||||
* aspect ratio, but doesn't exceed either of these dimensions.
|
||||
*/
|
||||
private void generateThumbnailImage(File mainFile, File thumbFile,
|
||||
int maxWidth, int maxHeight) throws IOException {
|
||||
BufferedImage bsrc = ImageIO.read(mainFile);
|
||||
|
||||
double scale = Math.min(((double) maxWidth) / bsrc.getWidth(),
|
||||
((double) maxHeight) / bsrc.getHeight());
|
||||
AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
|
||||
int newWidth = (int) (scale * bsrc.getWidth());
|
||||
int newHeight = (int) (scale * bsrc.getHeight());
|
||||
updateLog.log("Scaling '" + mainFile + "' by a factor of " + scale
|
||||
+ ", from " + bsrc.getWidth() + "x" + bsrc.getHeight() + " to "
|
||||
+ newWidth + "x" + newHeight);
|
||||
|
||||
BufferedImage bdest = new BufferedImage(newWidth, newHeight,
|
||||
BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g = bdest.createGraphics();
|
||||
|
||||
g.drawRenderedImage(bsrc, at);
|
||||
|
||||
ImageIO.write(bdest, "JPG", thumbFile);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/* $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.ResIterator;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.rdf.model.Statement;
|
||||
import com.hp.hpl.jena.rdf.model.StmtIterator;
|
||||
|
||||
/**
|
||||
* 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, "thumnail");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all resources for bogus values on this property.
|
||||
*/
|
||||
private void removeNonLiterals(Property prop, String label) {
|
||||
ResIterator resources = model.listResourcesWithProperty(prop);
|
||||
try {
|
||||
while (resources.hasNext()) {
|
||||
Resource resource = resources.next();
|
||||
removeNonLiterals(resource, prop, label);
|
||||
}
|
||||
} finally {
|
||||
resources.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check this resource for bogus values onthis property.
|
||||
*/
|
||||
private void removeNonLiterals(Resource resource, Property prop,
|
||||
String label) {
|
||||
List<RDFNode> bogusValues = new ArrayList<RDFNode>();
|
||||
StmtIterator stmts = resource.listProperties(prop);
|
||||
try {
|
||||
while (stmts.hasNext()) {
|
||||
Statement stmt = stmts.next();
|
||||
RDFNode object = stmt.getObject();
|
||||
if (!object.isLiteral()) {
|
||||
bogusValues.add(object);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
stmts.close();
|
||||
}
|
||||
|
||||
for (RDFNode bogusValue : bogusValues) {
|
||||
updateLog.warn(resource, "discarding " + label
|
||||
+ " property with non-literal as object: '" + bogusValue
|
||||
+ "'");
|
||||
model.createStatement(resource, prop, bogusValue).remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.servlet.setup;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.JenaBaseDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||
import edu.cornell.mannlib.vitro.webapp.filestorage.updater.FileStorageUpdater;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
public class UpdateUploadedFiles implements ServletContextListener {
|
||||
private static final Logger log = Logger
|
||||
.getLogger(UpdateUploadedFiles.class);
|
||||
|
||||
/**
|
||||
* Nothing to do on teardown.
|
||||
*/
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the ontology model, the old upload directory, and the file
|
||||
* storage system are all valid. Then do the update.
|
||||
*/
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
try {
|
||||
ServletContext ctx = sce.getServletContext();
|
||||
|
||||
WebappDaoFactory wadf = (WebappDaoFactory) ctx
|
||||
.getAttribute("webappDaoFactory");
|
||||
if (wadf == null) {
|
||||
throw new IllegalStateException("Webapp DAO Factory is null");
|
||||
}
|
||||
|
||||
OntModel jenaOntModel = (OntModel) ctx
|
||||
.getAttribute(JenaBaseDao.JENA_ONT_MODEL_ATTRIBUTE_NAME);
|
||||
if (jenaOntModel == null) {
|
||||
throw new IllegalStateException("Ontology model is null");
|
||||
}
|
||||
|
||||
FileStorage fileStorage = (FileStorage) ctx
|
||||
.getAttribute(FileStorageSetup.ATTRIBUTE_NAME);
|
||||
if (fileStorage == null) {
|
||||
throw new IllegalStateException("File storage system is null");
|
||||
}
|
||||
|
||||
String uploadDirectoryName = ConfigurationProperties
|
||||
.getProperty(FileStorageSetup.PROPERTY_FILE_STORAGE_BASE_DIR);
|
||||
if (uploadDirectoryName == null) {
|
||||
throw new IllegalStateException("Upload directory name is null");
|
||||
}
|
||||
File uploadDirectory = new File(uploadDirectoryName);
|
||||
if (!uploadDirectory.exists()) {
|
||||
throw new IllegalStateException("Upload directory '"
|
||||
+ uploadDirectory.getAbsolutePath()
|
||||
+ "' does not exist.");
|
||||
}
|
||||
|
||||
|
||||
FileStorageUpdater fsu = new FileStorageUpdater(wadf, jenaOntModel,
|
||||
fileStorage, uploadDirectory);
|
||||
fsu.update();
|
||||
} catch (Exception e) {
|
||||
log.error("Unknown problem", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,6 @@ public class FrontEndEditingUtils {
|
|||
private static final List<String> VITRO_NS_DATA_PROPS = Arrays.asList(VitroVocabulary.BLURB,
|
||||
VitroVocabulary.CITATION,
|
||||
VitroVocabulary.DESCRIPTION,
|
||||
VitroVocabulary.IMAGETHUMB,
|
||||
VitroVocabulary.LABEL,
|
||||
VitroVocabulary.MONIKER
|
||||
// VitroVocabulary.RDF_TYPE,
|
||||
|
|
|
@ -108,11 +108,11 @@ public class IndividualView extends ViewObject {
|
|||
return individual.getKeywords();
|
||||
}
|
||||
|
||||
public String getImageFile() {
|
||||
return individual.getImageFile();
|
||||
public String getImageUrl() {
|
||||
return individual.getImageUrl();
|
||||
}
|
||||
|
||||
public String getImageThumb() {
|
||||
return individual.getImageThumb();
|
||||
public String getThumbUrl() {
|
||||
return individual.getThumbUrl();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -235,7 +235,7 @@ public class PropertyEditLinks extends TagSupport{
|
|||
if( contains( allowedAccessTypeArray, EditLinkAccess.ADDNEW ) ){
|
||||
log.debug("vitro namespace property "+propertyUri+" gets an \"add\" link");
|
||||
LinkStruct ls = null;
|
||||
if (propertyUri.equals(VitroVocabulary.IMAGETHUMB)) {
|
||||
if (propertyUri.equals(VitroVocabulary.IND_MAIN_IMAGE)) {
|
||||
ls = getImageLink(subjectUri, contextPath, "add");
|
||||
} else {
|
||||
String url = makeRelativeHref(contextPath +"edit/editDatapropStmtRequestDispatch.jsp",
|
||||
|
@ -346,7 +346,7 @@ public class PropertyEditLinks extends TagSupport{
|
|||
|
||||
LinkStruct[] links = new LinkStruct[2];
|
||||
|
||||
if (predicateUri.equals(VitroVocabulary.IMAGETHUMB)) {
|
||||
if (predicateUri.equals(VitroVocabulary.IND_MAIN_IMAGE)) {
|
||||
if( contains( allowedAccessTypeArray, EditLinkAccess.MODIFY ) ){
|
||||
log.debug("permission found to UPDATE vitro namepsace property statement "+ predicateUri);
|
||||
links[0] = getImageLink(subjectUri, contextPath, "edit");
|
||||
|
@ -643,7 +643,7 @@ public class PropertyEditLinks extends TagSupport{
|
|||
"entityUri", subjectUri);
|
||||
ls.setHref(url);
|
||||
ls.setType(action);
|
||||
ls.setMouseoverText("upload a new image");
|
||||
ls.setMouseoverText("upload a new image");
|
||||
return ls;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue