VIVO-1246 Improve the ConfigurationBeanLoader (#52)
* VIVO-1246 improve the ConfigurationBeanLoader: Add cardinality parameters minOccurs and maxOccurs Create README.md document in the edu.cornell.mannlib.vitro.webapp.utils.configuration package Split large class of unit tests into separate classes by functionality * VIVO-1247, remove duplicate code used with ConfigurationBeanLoader. Now that the @Property annotation includes cardinality parameters, we can remove a lot of duplicate code. * VIVO-1246 Move unit tests to the new location. * VIVO-1246 The documentation was in the wrong place.
This commit is contained in:
parent
fc83c9f48d
commit
a8ec633f71
22 changed files with 1414 additions and 703 deletions
|
@ -25,7 +25,6 @@ import edu.cornell.mannlib.vitro.webapp.startup.ComponentStartupStatusImpl;
|
||||||
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||||
import edu.cornell.mannlib.vitro.webapp.triplesource.impl.BasicCombinedTripleSource;
|
import edu.cornell.mannlib.vitro.webapp.triplesource.impl.BasicCombinedTripleSource;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The basic implementation of the Application interface.
|
* The basic implementation of the Application interface.
|
||||||
|
@ -69,15 +68,9 @@ public class ApplicationImpl implements Application {
|
||||||
return searchEngine;
|
return searchEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchEngine")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchEngine", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setSearchEngine(SearchEngine se) {
|
public void setSearchEngine(SearchEngine se) {
|
||||||
if (searchEngine == null) {
|
searchEngine = se;
|
||||||
searchEngine = se;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple SearchEngine instances: "
|
|
||||||
+ searchEngine + ", and " + se);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -85,15 +78,9 @@ public class ApplicationImpl implements Application {
|
||||||
return searchIndexer;
|
return searchIndexer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchIndexer")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchIndexer", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setSearchIndexer(SearchIndexer si) {
|
public void setSearchIndexer(SearchIndexer si) {
|
||||||
if (searchIndexer == null) {
|
searchIndexer = si;
|
||||||
searchIndexer = si;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple SearchIndexer instances: "
|
|
||||||
+ searchIndexer + ", and " + si);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -101,15 +88,9 @@ public class ApplicationImpl implements Application {
|
||||||
return imageProcessor;
|
return imageProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasImageProcessor")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasImageProcessor", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setImageProcessor(ImageProcessor ip) {
|
public void setImageProcessor(ImageProcessor ip) {
|
||||||
if (imageProcessor == null) {
|
imageProcessor = ip;
|
||||||
imageProcessor = ip;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple ImageProcessor instances: "
|
|
||||||
+ imageProcessor + ", and " + ip);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -117,15 +98,9 @@ public class ApplicationImpl implements Application {
|
||||||
return fileStorage;
|
return fileStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasFileStorage")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasFileStorage", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setFileStorage(FileStorage fs) {
|
public void setFileStorage(FileStorage fs) {
|
||||||
if (fileStorage == null) {
|
fileStorage = fs;
|
||||||
fileStorage = fs;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple FileStorage instances: "
|
|
||||||
+ fileStorage + ", and " + fs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -133,15 +108,9 @@ public class ApplicationImpl implements Application {
|
||||||
return contentTripleSource;
|
return contentTripleSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasContentTripleSource")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasContentTripleSource", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setContentTripleSource(ContentTripleSource source) {
|
public void setContentTripleSource(ContentTripleSource source) {
|
||||||
if (contentTripleSource == null) {
|
contentTripleSource = source;
|
||||||
contentTripleSource = source;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple instances of ContentTripleSource: "
|
|
||||||
+ contentTripleSource + ", and " + source);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -149,15 +118,9 @@ public class ApplicationImpl implements Application {
|
||||||
return configurationTripleSource;
|
return configurationTripleSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasConfigurationTripleSource")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasConfigurationTripleSource", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setConfigurationTripleSource(ConfigurationTripleSource source) {
|
public void setConfigurationTripleSource(ConfigurationTripleSource source) {
|
||||||
if (configurationTripleSource == null) {
|
configurationTripleSource = source;
|
||||||
configurationTripleSource = source;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple instances of ConfigurationTripleSource: "
|
|
||||||
+ configurationTripleSource + ", and " + source);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -165,47 +128,9 @@ public class ApplicationImpl implements Application {
|
||||||
return tboxReasonerModule;
|
return tboxReasonerModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTBoxReasonerModule")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTBoxReasonerModule", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setTBoxReasonerModule(TBoxReasonerModule module) {
|
public void setTBoxReasonerModule(TBoxReasonerModule module) {
|
||||||
if (tboxReasonerModule == null) {
|
tboxReasonerModule = module;
|
||||||
tboxReasonerModule = module;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple instances of TBoxReasonerModule: "
|
|
||||||
+ tboxReasonerModule + ", and " + module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Validation
|
|
||||||
public void validate() throws Exception {
|
|
||||||
if (searchEngine == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a SearchEngine.");
|
|
||||||
}
|
|
||||||
if (searchIndexer == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a SearchIndexer.");
|
|
||||||
}
|
|
||||||
if (imageProcessor == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include an ImageProcessor.");
|
|
||||||
}
|
|
||||||
if (fileStorage == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a FileStorage.");
|
|
||||||
}
|
|
||||||
if (contentTripleSource == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a ContentTripleSource.");
|
|
||||||
}
|
|
||||||
if (configurationTripleSource == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a ConfigurationTripleSource.");
|
|
||||||
}
|
|
||||||
if (tboxReasonerModule == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a TBoxReasonerModule.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,7 +26,6 @@ import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResponse;
|
||||||
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResultDocument;
|
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResultDocument;
|
||||||
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResultDocumentList;
|
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResultDocumentList;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the life-cycle of the SearchEngine. Adds logging, controlled by
|
* Manages the life-cycle of the SearchEngine. Adds logging, controlled by
|
||||||
|
@ -40,26 +39,11 @@ public class InstrumentedSearchEngineWrapper implements SearchEngine {
|
||||||
|
|
||||||
private volatile LifecycleState lifecycleState = NEW;
|
private volatile LifecycleState lifecycleState = NEW;
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#wraps")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#wraps", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setInnerEngine(SearchEngine inner) {
|
public void setInnerEngine(SearchEngine inner) {
|
||||||
if (innerEngine == null) {
|
innerEngine = inner;
|
||||||
innerEngine = inner;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple SearchEngine instancess: "
|
|
||||||
+ innerEngine + ", and " + inner);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Validation
|
|
||||||
public void validate() throws Exception {
|
|
||||||
if (innerEngine == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a wrapped SearchEngine.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complain unless ACTIVE.
|
* Complain unless ACTIVE.
|
||||||
*/
|
*/
|
||||||
|
@ -227,8 +211,8 @@ public class InstrumentedSearchEngineWrapper implements SearchEngine {
|
||||||
// Helper classes
|
// Helper classes
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
private static class SearchResponseForDocumentCount implements
|
||||||
private static class SearchResponseForDocumentCount implements SearchResponse {
|
SearchResponse {
|
||||||
private final int count;
|
private final int count;
|
||||||
|
|
||||||
public SearchResponseForDocumentCount(int count) {
|
public SearchResponseForDocumentCount(int count) {
|
||||||
|
@ -255,26 +239,27 @@ public class InstrumentedSearchEngineWrapper implements SearchEngine {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class EmptyDocumentListWithCount implements SearchResultDocumentList {
|
private class EmptyDocumentListWithCount implements
|
||||||
@Override
|
SearchResultDocumentList {
|
||||||
public Iterator<SearchResultDocument> iterator() {
|
@Override
|
||||||
return Collections.emptyIterator();
|
public Iterator<SearchResultDocument> iterator() {
|
||||||
}
|
return Collections.emptyIterator();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNumFound() {
|
public long getNumFound() {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SearchResultDocument get(int i) {
|
public SearchResultDocument get(int i) {
|
||||||
throw new ArrayIndexOutOfBoundsException(i);
|
throw new ArrayIndexOutOfBoundsException(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ public class SearchIndexerImpl implements SearchIndexer {
|
||||||
private Set<IndexingUriFinder> uriFinders;
|
private Set<IndexingUriFinder> uriFinders;
|
||||||
private WebappDaoFactory wadf;
|
private WebappDaoFactory wadf;
|
||||||
|
|
||||||
private boolean rebuildOnUnpause = false;
|
private boolean rebuildOnUnpause = false;
|
||||||
|
|
||||||
private volatile int paused = 0;
|
private volatile int paused = 0;
|
||||||
|
|
||||||
|
@ -110,25 +110,14 @@ public class SearchIndexerImpl implements SearchIndexer {
|
||||||
// ConfigurationBeanLoader methods.
|
// ConfigurationBeanLoader methods.
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#threadPoolSize")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#threadPoolSize", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setThreadPoolSize(String size) {
|
public void setThreadPoolSize(String size) {
|
||||||
if (threadPoolSize == null) {
|
threadPoolSize = Integer.parseInt(size);
|
||||||
threadPoolSize = Integer.parseInt(size);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple values for threadPoolSize: "
|
|
||||||
+ threadPoolSize + ", and " + size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Validation
|
@Validation
|
||||||
public void validate() throws Exception {
|
public void validate() throws Exception {
|
||||||
if (threadPoolSize == null) {
|
this.pool = new WorkerThreadPool(threadPoolSize);
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a value for threadPoolSize.");
|
|
||||||
} else {
|
|
||||||
this.pool = new WorkerThreadPool(threadPoolSize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
@ -241,7 +230,7 @@ public class SearchIndexerImpl implements SearchIndexer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void schedulePendingUris() {
|
private synchronized void schedulePendingUris() {
|
||||||
if (paused == 0 && pendingUris.size() > 0) {
|
if (paused == 0 && pendingUris.size() > 0) {
|
||||||
scheduleUpdatesForUris(pendingUris);
|
scheduleUpdatesForUris(pendingUris);
|
||||||
pendingUris = new ArrayList<>();
|
pendingUris = new ArrayList<>();
|
||||||
|
@ -278,13 +267,14 @@ public class SearchIndexerImpl implements SearchIndexer {
|
||||||
if (changes == null || changes.isEmpty()) {
|
if (changes == null || changes.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (paused > 0) {
|
if (paused > 0) {
|
||||||
if (addToPendingStatements(changes)) {
|
if (addToPendingStatements(changes)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler.scheduleTask(new UpdateStatementsTask(new IndexerConfigImpl(this), changes));
|
scheduler.scheduleTask(new UpdateStatementsTask(new IndexerConfigImpl(
|
||||||
|
this), changes));
|
||||||
log.debug("Scheduled updates for " + changes.size() + " statements.");
|
log.debug("Scheduled updates for " + changes.size() + " statements.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,13 +296,14 @@ public class SearchIndexerImpl implements SearchIndexer {
|
||||||
if (uris == null || uris.isEmpty()) {
|
if (uris == null || uris.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (paused > 0) {
|
if (paused > 0) {
|
||||||
if (pendingUris.addAll(uris)) {
|
if (pendingUris.addAll(uris)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler.scheduleTask(new UpdateUrisTask(new IndexerConfigImpl(this), uris));
|
scheduler.scheduleTask(new UpdateUrisTask(new IndexerConfigImpl(this),
|
||||||
|
uris));
|
||||||
log.debug("Scheduled updates for " + uris.size() + " uris.");
|
log.debug("Scheduled updates for " + uris.size() + " uris.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,13 +323,14 @@ public class SearchIndexerImpl implements SearchIndexer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fireEvent(REBUILD_REQUESTED);
|
fireEvent(REBUILD_REQUESTED);
|
||||||
if (paused > 0) {
|
if (paused > 0) {
|
||||||
// Make sure that we are rebuilding when we unpause
|
// Make sure that we are rebuilding when we unpause
|
||||||
// and don't bother noting any other changes until unpaused
|
// and don't bother noting any other changes until unpaused
|
||||||
rebuildOnUnpause = true;
|
rebuildOnUnpause = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scheduler.scheduleTask(new RebuildIndexTask(new IndexerConfigImpl(this)));
|
scheduler
|
||||||
|
.scheduleTask(new RebuildIndexTask(new IndexerConfigImpl(this)));
|
||||||
log.debug("Scheduled a full rebuild.");
|
log.debug("Scheduled a full rebuild.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,13 +439,13 @@ public class SearchIndexerImpl implements SearchIndexer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void scheduleTask(Task task) {
|
public synchronized void scheduleTask(Task task) {
|
||||||
if (!started) {
|
if (!started) {
|
||||||
deferredQueue.add(task);
|
deferredQueue.add(task);
|
||||||
log.debug("added task to deferred queue: " + task);
|
log.debug("added task to deferred queue: " + task);
|
||||||
} else {
|
} else {
|
||||||
taskQueue.scheduleTask(task);
|
taskQueue.scheduleTask(task);
|
||||||
log.debug("added task to task queue: " + task);
|
log.debug("added task to task queue: " + task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void start() {
|
public synchronized void start() {
|
||||||
|
@ -463,8 +455,9 @@ public class SearchIndexerImpl implements SearchIndexer {
|
||||||
|
|
||||||
private void processDeferredTasks() {
|
private void processDeferredTasks() {
|
||||||
for (Task task : deferredQueue) {
|
for (Task task : deferredQueue) {
|
||||||
taskQueue.scheduleTask(task);
|
taskQueue.scheduleTask(task);
|
||||||
log.debug("moved task from deferred queue to task queue: " + task);
|
log.debug("moved task from deferred queue to task queue: "
|
||||||
|
+ task);
|
||||||
}
|
}
|
||||||
deferredQueue.clear();
|
deferredQueue.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,27 +17,18 @@ public class FieldBooster implements DocumentModifier {
|
||||||
private final List<String> fieldNames = new ArrayList<>();
|
private final List<String> fieldNames = new ArrayList<>();
|
||||||
private volatile Float boost;
|
private volatile Float boost;
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTargetField")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTargetField", minOccurs = 1)
|
||||||
public void addTargetField(String fieldName) {
|
public void addTargetField(String fieldName) {
|
||||||
fieldNames.add(fieldName);
|
fieldNames.add(fieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasBoost")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasBoost", minOccurs = 1)
|
||||||
public void setBoost(float boost) {
|
public void setBoost(float boost) {
|
||||||
this.boost = boost;
|
this.boost = boost;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Validation
|
@Validation
|
||||||
public void validate() {
|
public void validate() {
|
||||||
if (boost == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a boost value.");
|
|
||||||
}
|
|
||||||
if (fieldNames.isEmpty()) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a target field.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> uniqueFieldNames = new HashSet<>(fieldNames);
|
Set<String> uniqueFieldNames = new HashSet<>(fieldNames);
|
||||||
List<String> duplicateFieldNames = new ArrayList<>(fieldNames);
|
List<String> duplicateFieldNames = new ArrayList<>(fieldNames);
|
||||||
for (String fn : uniqueFieldNames) {
|
for (String fn : uniqueFieldNames) {
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class SelectQueryUriFinder implements IndexingUriFinder,
|
||||||
label = l;
|
label = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSelectQuery")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSelectQuery", minOccurs = 1)
|
||||||
public void addQuery(String query) {
|
public void addQuery(String query) {
|
||||||
queries.add(query);
|
queries.add(query);
|
||||||
}
|
}
|
||||||
|
@ -89,10 +89,6 @@ public class SelectQueryUriFinder implements IndexingUriFinder,
|
||||||
if (label == null) {
|
if (label == null) {
|
||||||
label = this.getClass().getSimpleName() + ":" + this.hashCode();
|
label = this.getClass().getSimpleName() + ":" + this.hashCode();
|
||||||
}
|
}
|
||||||
if (queries.isEmpty()) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration contains no queries for " + label);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,7 +19,6 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceFactorySingle;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.logging.LoggingRDFServiceFactory;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.logging.LoggingRDFServiceFactory;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sparql.RDFServiceSparql;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sparql.RDFServiceSparql;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,34 +40,14 @@ public class ContentTripleSourceSPARQL extends ContentTripleSource {
|
||||||
private Dataset dataset;
|
private Dataset dataset;
|
||||||
private ModelMaker modelMaker;
|
private ModelMaker modelMaker;
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasEndpointURI")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasEndpointURI", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setEndpointURI(String eUri) {
|
public void setEndpointURI(String eUri) {
|
||||||
if (endpointURI == null) {
|
endpointURI = eUri;
|
||||||
endpointURI = eUri;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple instances of EndpointURI: "
|
|
||||||
+ endpointURI + ", and " + eUri);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasUpdateEndpointURI")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasUpdateEndpointURI", maxOccurs = 1)
|
||||||
public void setUpdateEndpointURI(String ueUri) {
|
public void setUpdateEndpointURI(String ueUri) {
|
||||||
if (updateEndpointURI == null) {
|
updateEndpointURI = ueUri;
|
||||||
updateEndpointURI = ueUri;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple instances of UpdateEndpointURI: "
|
|
||||||
+ updateEndpointURI + ", and " + ueUri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Validation
|
|
||||||
public void validate() throws Exception {
|
|
||||||
if (endpointURI == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include an EndpointURI.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,7 +24,6 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.tdb.RDFServiceTDB;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.logging.LoggingRDFServiceFactory;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.logging.LoggingRDFServiceFactory;
|
||||||
import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase;
|
import edu.cornell.mannlib.vitro.webapp.servlet.setup.JenaDataSourceSetupBase;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,23 +48,9 @@ public class ContentTripleSourceTDB extends ContentTripleSource {
|
||||||
private Dataset dataset;
|
private Dataset dataset;
|
||||||
private ModelMaker modelMaker;
|
private ModelMaker modelMaker;
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTdbDirectory")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTdbDirectory", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setTdbPath(String path) {
|
public void setTdbPath(String path) {
|
||||||
if (tdbPath == null) {
|
tdbPath = path;
|
||||||
tdbPath = path;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple instances of TdbDirectory: "
|
|
||||||
+ tdbPath + ", and " + path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Validation
|
|
||||||
public void validate() throws Exception {
|
|
||||||
if (tdbPath == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a TdbDirectory.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -106,7 +91,8 @@ public class ContentTripleSourceTDB extends ContentTripleSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForFirstTimeStartup() {
|
private void checkForFirstTimeStartup() {
|
||||||
if (this.dataset.getNamedModel(ModelNames.TBOX_ASSERTIONS).getGraph().isEmpty()) {
|
if (this.dataset.getNamedModel(ModelNames.TBOX_ASSERTIONS).getGraph()
|
||||||
|
.isEmpty()) {
|
||||||
JenaDataSourceSetupBase.thisIsFirstStartup();
|
JenaDataSourceSetupBase.thisIsFirstStartup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.virtuoso.RDFServiceVirtuoso;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.virtuoso.RDFServiceVirtuoso;
|
||||||
import edu.cornell.mannlib.vitro.webapp.triplesource.impl.sparql.ContentTripleSourceSPARQL;
|
import edu.cornell.mannlib.vitro.webapp.triplesource.impl.sparql.ContentTripleSourceSPARQL;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,54 +18,19 @@ public class ContentTripleSourceVirtuoso extends ContentTripleSourceSPARQL {
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasBaseURI")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasBaseURI", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setBaseUri(String uri) {
|
public void setBaseUri(String uri) {
|
||||||
if (baseUri == null) {
|
baseUri = uri;
|
||||||
baseUri = uri;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple instances of BaseURI: "
|
|
||||||
+ baseUri + ", and " + uri);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasUsername")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasUsername", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setUsername(String user) {
|
public void setUsername(String user) {
|
||||||
if (username == null) {
|
username = user;
|
||||||
username = user;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple instances of Username: "
|
|
||||||
+ username + ", and " + user);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasPassword")
|
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasPassword", minOccurs = 1, maxOccurs = 1)
|
||||||
public void setPassword(String pass) {
|
public void setPassword(String pass) {
|
||||||
if (password == null) {
|
password = pass;
|
||||||
password = pass;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration includes multiple instances of Password: "
|
|
||||||
+ password + ", and " + pass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Validation
|
|
||||||
public void validate() throws Exception {
|
|
||||||
if (baseUri == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a BaseURI.");
|
|
||||||
}
|
|
||||||
if (username == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a Username.");
|
|
||||||
}
|
|
||||||
if (password == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Configuration did not include a Password.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -116,6 +116,7 @@ public class ConfigurationBeanLoader {
|
||||||
WrappedInstance<T> wrapper = InstanceWrapper.wrap(parsedRdf
|
WrappedInstance<T> wrapper = InstanceWrapper.wrap(parsedRdf
|
||||||
.getConcreteClass());
|
.getConcreteClass());
|
||||||
wrapper.satisfyInterfaces(ctx, req);
|
wrapper.satisfyInterfaces(ctx, req);
|
||||||
|
wrapper.checkCardinality(parsedRdf.getPropertyStatements());
|
||||||
wrapper.setProperties(this, parsedRdf.getPropertyStatements());
|
wrapper.setProperties(this, parsedRdf.getPropertyStatements());
|
||||||
wrapper.validate();
|
wrapper.validate();
|
||||||
return wrapper.getInstance();
|
return wrapper.getInstance();
|
||||||
|
|
|
@ -6,7 +6,9 @@ import java.lang.reflect.Method;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyMethod;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyMethod;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException;
|
||||||
|
@ -16,11 +18,17 @@ import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.Propert
|
||||||
* instance of the class.
|
* instance of the class.
|
||||||
*/
|
*/
|
||||||
public class InstanceWrapper {
|
public class InstanceWrapper {
|
||||||
|
private static final Log log = LogFactory.getLog(InstanceWrapper.class);
|
||||||
|
|
||||||
public static <T> WrappedInstance<T> wrap(Class<? extends T> concreteClass)
|
public static <T> WrappedInstance<T> wrap(Class<? extends T> concreteClass)
|
||||||
throws InstanceWrapperException {
|
throws InstanceWrapperException {
|
||||||
return new WrappedInstance<T>(createInstance(concreteClass),
|
T instance = createInstance(concreteClass);
|
||||||
parsePropertyAnnotations(concreteClass),
|
HashSet<Method> validationMethods = new HashSet<>(
|
||||||
parseValidationAnnotations(concreteClass));
|
parseValidationAnnotations(concreteClass).values());
|
||||||
|
Map<String, PropertyMethod> propertyMethods = new PropertyAnnotationsMap(
|
||||||
|
concreteClass).byUri();
|
||||||
|
return new WrappedInstance<T>(instance, propertyMethods,
|
||||||
|
validationMethods);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> T createInstance(Class<? extends T> concreteClass)
|
private static <T> T createInstance(Class<? extends T> concreteClass)
|
||||||
|
@ -33,58 +41,131 @@ public class InstanceWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, PropertyMethod> parsePropertyAnnotations(
|
private static Map<String, Method> parseValidationAnnotations(Class<?> clazz)
|
||||||
Class<?> concreteClass) throws InstanceWrapperException {
|
throws InstanceWrapperException {
|
||||||
Map<String, PropertyMethod> map = new HashMap<>();
|
if (Object.class.equals(clazz)) {
|
||||||
for (Method method : concreteClass.getDeclaredMethods()) {
|
return new HashMap<>();
|
||||||
Property annotation = method.getAnnotation(Property.class);
|
} else {
|
||||||
if (annotation == null) {
|
Map<String, Method> methods = parseValidationAnnotations(clazz
|
||||||
continue;
|
.getSuperclass());
|
||||||
}
|
for (Method method : clazz.getDeclaredMethods()) {
|
||||||
if (!method.getReturnType().equals(Void.TYPE)) {
|
String name = method.getName();
|
||||||
throw new InstanceWrapperException("Property method '" + method
|
if (methods.containsKey(name)) {
|
||||||
+ "' should return void.");
|
Method m = methods.get(name);
|
||||||
}
|
throw new InstanceWrapperException("Method " + name
|
||||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
+ " in " + method.getDeclaringClass().getName()
|
||||||
if (parameterTypes.length != 1) {
|
+ " overrides a validation method in "
|
||||||
throw new InstanceWrapperException("Property method '" + method
|
+ m.getDeclaringClass().getName());
|
||||||
+ "' must accept exactly one parameter.");
|
}
|
||||||
}
|
if (method.getAnnotation(Validation.class) == null) {
|
||||||
|
continue;
|
||||||
String uri = annotation.uri();
|
}
|
||||||
if (map.containsKey(uri)) {
|
if (method.getParameterTypes().length > 0) {
|
||||||
throw new InstanceWrapperException(
|
throw new InstanceWrapperException("Validation method '"
|
||||||
"Two property methods have the same URI value: "
|
+ method + "' should not have parameters.");
|
||||||
+ map.get(uri).getMethod() + ", and " + method);
|
}
|
||||||
}
|
if (!method.getReturnType().equals(Void.TYPE)) {
|
||||||
try {
|
throw new InstanceWrapperException("Validation method '"
|
||||||
map.put(uri, PropertyType.createPropertyMethod(method));
|
+ method + "' should return void.");
|
||||||
} catch (PropertyTypeException e) {
|
}
|
||||||
throw new InstanceWrapperException(
|
methods.put(name, method);
|
||||||
"Failed to create the PropertyMethod", e);
|
|
||||||
}
|
}
|
||||||
|
return methods;
|
||||||
}
|
}
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<Method> parseValidationAnnotations(Class<?> concreteClass)
|
private static class PropertyAnnotationsMap {
|
||||||
throws InstanceWrapperException {
|
private Map<String, PropertyMethod> mapByUri = new HashMap<>();
|
||||||
Set<Method> methods = new HashSet<>();
|
private Map<String, PropertyMethod> mapByName = new HashMap<>();
|
||||||
for (Method method : concreteClass.getDeclaredMethods()) {
|
|
||||||
if (method.getAnnotation(Validation.class) == null) {
|
public PropertyAnnotationsMap(Class<?> clazz)
|
||||||
continue;
|
throws InstanceWrapperException {
|
||||||
|
if (!Object.class.equals(clazz)) {
|
||||||
|
populateTheMaps(clazz);
|
||||||
}
|
}
|
||||||
if (method.getParameterTypes().length > 0) {
|
|
||||||
throw new InstanceWrapperException("Validation method '"
|
|
||||||
+ method + "' should not have parameters.");
|
|
||||||
}
|
|
||||||
if (!method.getReturnType().equals(Void.TYPE)) {
|
|
||||||
throw new InstanceWrapperException("Validation method '"
|
|
||||||
+ method + "' should return void.");
|
|
||||||
}
|
|
||||||
methods.add(method);
|
|
||||||
}
|
}
|
||||||
return methods;
|
|
||||||
|
private void populateTheMaps(Class<?> clazz)
|
||||||
|
throws InstanceWrapperException {
|
||||||
|
PropertyAnnotationsMap superMap = new PropertyAnnotationsMap(
|
||||||
|
clazz.getSuperclass());
|
||||||
|
mapByUri = superMap.byUri();
|
||||||
|
mapByName = superMap.byName();
|
||||||
|
for (Method method : clazz.getDeclaredMethods()) {
|
||||||
|
String name = method.getName();
|
||||||
|
|
||||||
|
Method matchByName = methodByName(name);
|
||||||
|
if (matchByName != null) {
|
||||||
|
throw new InstanceWrapperException("Method " + name
|
||||||
|
+ " in " + clazz.getName()
|
||||||
|
+ " conflicts with a property method in "
|
||||||
|
+ matchByName.getDeclaringClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Property annotation = method.getAnnotation(Property.class);
|
||||||
|
if (annotation == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!method.getReturnType().equals(Void.TYPE)) {
|
||||||
|
throw new InstanceWrapperException("Property method '"
|
||||||
|
+ method + "' should return void.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.getParameterTypes().length != 1) {
|
||||||
|
throw new InstanceWrapperException("Property method '"
|
||||||
|
+ method + "' must accept exactly one parameter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String uri = annotation.uri();
|
||||||
|
Method matchByUri = methodByUri(uri);
|
||||||
|
if (matchByUri != null) {
|
||||||
|
throw new InstanceWrapperException(
|
||||||
|
"Two property methods have the same URI value: "
|
||||||
|
+ matchByUri + ", and " + method);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (annotation.minOccurs() < 0) {
|
||||||
|
throw new InstanceWrapperException(
|
||||||
|
"minOccurs must not be negative.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (annotation.maxOccurs() < annotation.minOccurs()) {
|
||||||
|
throw new InstanceWrapperException(
|
||||||
|
"maxOccurs must not be less than minOccurs.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PropertyMethod pm = PropertyType.createPropertyMethod(
|
||||||
|
method, annotation);
|
||||||
|
mapByUri.put(uri, pm);
|
||||||
|
mapByName.put(name, pm);
|
||||||
|
} catch (PropertyTypeException e) {
|
||||||
|
throw new InstanceWrapperException(
|
||||||
|
"Failed to create the PropertyMethod", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method methodByName(String name) {
|
||||||
|
PropertyMethod pm = mapByName.get(name);
|
||||||
|
return (pm == null) ? null : pm.getMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method methodByUri(String name) {
|
||||||
|
PropertyMethod pm = mapByUri.get(name);
|
||||||
|
return (pm == null) ? null : pm.getMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, PropertyMethod> byUri() {
|
||||||
|
return mapByUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, PropertyMethod> byName() {
|
||||||
|
return mapByName;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class InstanceWrapperException extends Exception {
|
public static class InstanceWrapperException extends Exception {
|
||||||
|
|
|
@ -15,4 +15,6 @@ import java.lang.annotation.Target;
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
public @interface Property {
|
public @interface Property {
|
||||||
String uri();
|
String uri();
|
||||||
|
int minOccurs() default 0;
|
||||||
|
int maxOccurs() default Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import java.lang.reflect.Method;
|
||||||
import org.apache.jena.datatypes.RDFDatatype;
|
import org.apache.jena.datatypes.RDFDatatype;
|
||||||
import org.apache.jena.datatypes.xsd.impl.RDFLangString;
|
import org.apache.jena.datatypes.xsd.impl.RDFLangString;
|
||||||
import org.apache.jena.rdf.model.Literal;
|
import org.apache.jena.rdf.model.Literal;
|
||||||
import org.apache.jena.rdf.model.Property;
|
|
||||||
import org.apache.jena.rdf.model.RDFNode;
|
import org.apache.jena.rdf.model.RDFNode;
|
||||||
import org.apache.jena.rdf.model.Statement;
|
import org.apache.jena.rdf.model.Statement;
|
||||||
|
|
||||||
|
@ -26,38 +25,41 @@ public enum PropertyType {
|
||||||
RESOURCE {
|
RESOURCE {
|
||||||
@Override
|
@Override
|
||||||
public PropertyStatement buildPropertyStatement(Statement s) {
|
public PropertyStatement buildPropertyStatement(Statement s) {
|
||||||
return new ResourcePropertyStatement(s.getPredicate(), s
|
return new ResourcePropertyStatement(s.getPredicate().getURI(), s
|
||||||
.getObject().asResource().getURI());
|
.getObject().asResource().getURI());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PropertyMethod buildPropertyMethod(Method method) {
|
protected PropertyMethod buildPropertyMethod(Method method,
|
||||||
return new ResourcePropertyMethod(method);
|
Property annotation) {
|
||||||
|
return new ResourcePropertyMethod(method, annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
STRING {
|
STRING {
|
||||||
@Override
|
@Override
|
||||||
public PropertyStatement buildPropertyStatement(Statement s) {
|
public PropertyStatement buildPropertyStatement(Statement s) {
|
||||||
return new StringPropertyStatement(s.getPredicate(), s.getObject()
|
return new StringPropertyStatement(s.getPredicate().getURI(), s
|
||||||
.asLiteral().getString());
|
.getObject().asLiteral().getString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PropertyMethod buildPropertyMethod(Method method) {
|
protected PropertyMethod buildPropertyMethod(Method method,
|
||||||
return new StringPropertyMethod(method);
|
Property annotation) {
|
||||||
|
return new StringPropertyMethod(method, annotation);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
FLOAT {
|
FLOAT {
|
||||||
@Override
|
@Override
|
||||||
public PropertyStatement buildPropertyStatement(Statement s) {
|
public PropertyStatement buildPropertyStatement(Statement s) {
|
||||||
return new FloatPropertyStatement(s.getPredicate(), s.getObject()
|
return new FloatPropertyStatement(s.getPredicate().getURI(), s
|
||||||
.asLiteral().getFloat());
|
.getObject().asLiteral().getFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PropertyMethod buildPropertyMethod(Method method) {
|
protected PropertyMethod buildPropertyMethod(Method method,
|
||||||
return new FloatPropertyMethod(method);
|
Property annotation) {
|
||||||
|
return new FloatPropertyMethod(method, annotation);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,24 +103,25 @@ public enum PropertyType {
|
||||||
return type.buildPropertyStatement(s);
|
return type.buildPropertyStatement(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PropertyMethod createPropertyMethod(Method method)
|
public static PropertyMethod createPropertyMethod(Method method,
|
||||||
throws PropertyTypeException {
|
Property annotation) throws PropertyTypeException {
|
||||||
Class<?> parameterType = method.getParameterTypes()[0];
|
Class<?> parameterType = method.getParameterTypes()[0];
|
||||||
PropertyType type = PropertyType.typeForParameterType(parameterType);
|
PropertyType type = PropertyType.typeForParameterType(parameterType);
|
||||||
return type.buildPropertyMethod(method);
|
return type.buildPropertyMethod(method, annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract PropertyStatement buildPropertyStatement(Statement s);
|
protected abstract PropertyStatement buildPropertyStatement(Statement s);
|
||||||
|
|
||||||
protected abstract PropertyMethod buildPropertyMethod(Method method);
|
protected abstract PropertyMethod buildPropertyMethod(Method method,
|
||||||
|
Property annotation);
|
||||||
|
|
||||||
public static abstract class PropertyStatement {
|
public static abstract class PropertyStatement {
|
||||||
private final PropertyType type;
|
private final PropertyType type;
|
||||||
private final String predicateUri;
|
private final String predicateUri;
|
||||||
|
|
||||||
public PropertyStatement(PropertyType type, Property predicate) {
|
public PropertyStatement(PropertyType type, String predicateUri) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.predicateUri = predicate.getURI();
|
this.predicateUri = predicateUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyType getType() {
|
public PropertyType getType() {
|
||||||
|
@ -135,8 +138,8 @@ public enum PropertyType {
|
||||||
public static class ResourcePropertyStatement extends PropertyStatement {
|
public static class ResourcePropertyStatement extends PropertyStatement {
|
||||||
private final String objectUri;
|
private final String objectUri;
|
||||||
|
|
||||||
public ResourcePropertyStatement(Property predicate, String objectUri) {
|
public ResourcePropertyStatement(String predicateUri, String objectUri) {
|
||||||
super(RESOURCE, predicate);
|
super(RESOURCE, predicateUri);
|
||||||
this.objectUri = objectUri;
|
this.objectUri = objectUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,8 +152,8 @@ public enum PropertyType {
|
||||||
public static class StringPropertyStatement extends PropertyStatement {
|
public static class StringPropertyStatement extends PropertyStatement {
|
||||||
private final String string;
|
private final String string;
|
||||||
|
|
||||||
public StringPropertyStatement(Property predicate, String string) {
|
public StringPropertyStatement(String predicateUri, String string) {
|
||||||
super(STRING, predicate);
|
super(STRING, predicateUri);
|
||||||
this.string = string;
|
this.string = string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,8 +166,8 @@ public enum PropertyType {
|
||||||
public static class FloatPropertyStatement extends PropertyStatement {
|
public static class FloatPropertyStatement extends PropertyStatement {
|
||||||
private final float f;
|
private final float f;
|
||||||
|
|
||||||
public FloatPropertyStatement(Property predicate, float f) {
|
public FloatPropertyStatement(String predicateUri, float f) {
|
||||||
super(FLOAT, predicate);
|
super(FLOAT, predicateUri);
|
||||||
this.f = f;
|
this.f = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,10 +180,23 @@ public enum PropertyType {
|
||||||
public static abstract class PropertyMethod {
|
public static abstract class PropertyMethod {
|
||||||
protected final PropertyType type;
|
protected final PropertyType type;
|
||||||
protected final Method method;
|
protected final Method method;
|
||||||
|
protected final String propertyUri;
|
||||||
|
protected final int minOccurs;
|
||||||
|
protected final int maxOccurs;
|
||||||
|
|
||||||
public PropertyMethod(PropertyType type, Method method) {
|
// Add cardinality values here! Final, with getters.
|
||||||
|
public PropertyMethod(PropertyType type, Method method,
|
||||||
|
Property annotation) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
|
this.propertyUri = annotation.uri();
|
||||||
|
this.minOccurs = annotation.minOccurs();
|
||||||
|
this.maxOccurs = annotation.maxOccurs();
|
||||||
|
checkCardinalityBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCardinalityBounds() {
|
||||||
|
// This is where we check for negative values or out of order.
|
||||||
}
|
}
|
||||||
|
|
||||||
public Method getMethod() {
|
public Method getMethod() {
|
||||||
|
@ -191,6 +207,18 @@ public enum PropertyType {
|
||||||
return method.getParameterTypes()[0];
|
return method.getParameterTypes()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPropertyUri() {
|
||||||
|
return propertyUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinOccurs() {
|
||||||
|
return minOccurs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxOccurs() {
|
||||||
|
return maxOccurs;
|
||||||
|
}
|
||||||
|
|
||||||
public void confirmCompatible(PropertyStatement ps)
|
public void confirmCompatible(PropertyStatement ps)
|
||||||
throws PropertyTypeException {
|
throws PropertyTypeException {
|
||||||
if (type != ps.getType()) {
|
if (type != ps.getType()) {
|
||||||
|
@ -213,20 +241,20 @@ public enum PropertyType {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ResourcePropertyMethod extends PropertyMethod {
|
public static class ResourcePropertyMethod extends PropertyMethod {
|
||||||
public ResourcePropertyMethod(Method method) {
|
public ResourcePropertyMethod(Method method, Property annotation) {
|
||||||
super(RESOURCE, method);
|
super(RESOURCE, method, annotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StringPropertyMethod extends PropertyMethod {
|
public static class StringPropertyMethod extends PropertyMethod {
|
||||||
public StringPropertyMethod(Method method) {
|
public StringPropertyMethod(Method method, Property annotation) {
|
||||||
super(STRING, method);
|
super(STRING, method, annotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class FloatPropertyMethod extends PropertyMethod {
|
public static class FloatPropertyMethod extends PropertyMethod {
|
||||||
public FloatPropertyMethod(Method method) {
|
public FloatPropertyMethod(Method method, Property annotation) {
|
||||||
super(FLOAT, method);
|
super(FLOAT, method, annotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
# package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
## Overview
|
||||||
|
### Purpose
|
||||||
|
This package consists of `ConfigurationBeanLoader` and associated classes.
|
||||||
|
`ConfigurationBeanLoader` will instantiate and populate objects according to a
|
||||||
|
description encoded in the triples of an RDF Graph,
|
||||||
|
and annotations within the Java class of the instantiated object.
|
||||||
|
|
||||||
|
The description must include
|
||||||
|
|
||||||
|
+ the URI of exactly one concrete Java class, from which the instance will be created.
|
||||||
|
|
||||||
|
The description may also include
|
||||||
|
|
||||||
|
+ URIs of Java interfaces which the concrete class implements.
|
||||||
|
The description may be use to satisfy a request
|
||||||
|
for any of those interfaces, as well as a request for the concrete class.
|
||||||
|
|
||||||
|
+ Data properties. These will be passed to "property methods" in the instance
|
||||||
|
as part of the creation/initialization. The data value must be an untyped
|
||||||
|
literal (String) or a numeric literal (Float).
|
||||||
|
|
||||||
|
+ Object properties. The URI is assumed to be that of another loader description.
|
||||||
|
The loader will attempt to instantiate the described object, and pass it to
|
||||||
|
the appropriate property method on the original instance. The result may be a
|
||||||
|
network of instances, nested to an arbitrary level.
|
||||||
|
|
||||||
|
The loader also recognizes two special interfaces: `RequestModelsUser` and `ContextModelsUser`.
|
||||||
|
If a created instance implements these interfaces,
|
||||||
|
the loader will provide the appropriate `ModelAccess` object,
|
||||||
|
allowing the instance to access the Vitro triple-stores.
|
||||||
|
|
||||||
|
### Examples of use
|
||||||
|
|
||||||
|
#### ApplicationSetup
|
||||||
|
|
||||||
|
When Vitro starts up, `ApplicationSetup` uses a `ConfigurationBeanLoader` to instantiate the Vitro's component modules.
|
||||||
|
The loader creates an RDF Graph from the file `applicationSetup.n3` and instantiates a `SearchEngine` instance,
|
||||||
|
a `FileStorage` instance, etc.
|
||||||
|
|
||||||
|
Here is some RDF that might be used by `ApplicationSetup`:
|
||||||
|
|
||||||
|
@prefix : <http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#> .
|
||||||
|
:application
|
||||||
|
a <java:edu.cornell.mannlib.vitro.webapp.application.ApplicationImpl> ,
|
||||||
|
<java:edu.cornell.mannlib.vitro.webapp.modules.Application> ;
|
||||||
|
:hasSearchEngine :instrumentedSearchEngineWrapper ;
|
||||||
|
:hasFileStorage :ptiFileStorage .
|
||||||
|
|
||||||
|
:ptiFileStorage
|
||||||
|
a <java:edu.cornell.mannlib.vitro.webapp.filestorage.impl.FileStorageImplWrapper> ,
|
||||||
|
<java:edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage> .
|
||||||
|
|
||||||
|
:instrumentedSearchEngineWrapper
|
||||||
|
a <java:edu.cornell.mannlib.vitro.webapp.searchengine.InstrumentedSearchEngineWrapper> ,
|
||||||
|
<java:edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine> ;
|
||||||
|
:wraps :solrSearchEngine .
|
||||||
|
|
||||||
|
:solrSearchEngine
|
||||||
|
a <java:edu.cornell.mannlib.vitro.webapp.searchengine.solr.SolrSearchEngine> ,
|
||||||
|
<java:edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine> .
|
||||||
|
|
||||||
|
In this case, the `ConfigurationBeanLoader` would be asked to load all instances of
|
||||||
|
`edu.cornell.mannlib.vitro.webapp.modules.Application`.
|
||||||
|
The application individual is declared to be both an `Application` and an `ApplicationImpl`.
|
||||||
|
This is valid because `Application` is an interface, and `ApplicationImpl` implements that interface.
|
||||||
|
An instance of `ApplicationImpl` will be created.
|
||||||
|
|
||||||
|
The application instance has two child objects: a `SearchEngine` and a `FileStorage`.
|
||||||
|
These objects will also be created, and calls will be made to the application's "property methods" (see below).
|
||||||
|
|
||||||
|
The `SearchEngine` in turn has a child object, so that also will be created, and provided to the `SearchEngine`.
|
||||||
|
|
||||||
|
#### SearchIndexer
|
||||||
|
|
||||||
|
When Vitro's `SearchIndexer` is initialized, it uses a `ConfigurationBeanLoader` to create
|
||||||
|
lists of `SearchIndexExcluder`s, `DocumentModifier`s, and `IndexingUriFinder`s.
|
||||||
|
Descriptions of these are taken from Vitro's display model.
|
||||||
|
|
||||||
|
## Specifications
|
||||||
|
|
||||||
|
### ConfigurationBeanLoader
|
||||||
|
The principal methods are:
|
||||||
|
|
||||||
|
+ `public <T> T loadInstance(String uri, Class<T> resultClass) throws ConfigurationBeanLoaderException`
|
||||||
|
+ Search the graph for triples that describe the `uri`.
|
||||||
|
If the description indicates that the individual is of type `resultClass`, create an instance and populate it.
|
||||||
|
Return a reference to the created instance. Throw an exception if the `uri` does not exist in the graph,
|
||||||
|
or if the description does not correctly describe an individual.
|
||||||
|
|
||||||
|
The `resultClass` may be an interface. In that case, each individual must also have a type statement that refers
|
||||||
|
to a concrete class that satisfies the interface. An instance of the concrete class will be created.
|
||||||
|
|
||||||
|
+ `public <T> Set<T> loadAll(Class<T> resultClass) throws ConfigurationBeanLoaderException`
|
||||||
|
+ Search the graph for all individuals of type `resultClass`. For each such individual, call `loadInstance`.
|
||||||
|
Return a set containing the created instances. If no individuals are found, return an empty `Set`.
|
||||||
|
|
||||||
|
### Restrictions on instantiated classes.
|
||||||
|
Each class to be instantiated must have a niladic constructor.
|
||||||
|
|
||||||
|
### Property methods
|
||||||
|
When the loader encounters a data property or an object property in a description,
|
||||||
|
it will look in the instantiated class for a method tagged with the
|
||||||
|
`edu.cornell.mannlib.vitro.webapp.utils.configuration.Property` annotation.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasConfigurationTripleSource"
|
||||||
|
minOccurs = 1,
|
||||||
|
maxOccurs = 3)
|
||||||
|
public void setTBoxReasonerModule(TBoxReasonerModule module) {
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
In more detail:
|
||||||
|
|
||||||
|
+ A class must contain exactly one method that serves each property URI in the description.
|
||||||
|
+ The description need not include properies for all of the property methods in the class.
|
||||||
|
+ Each property method must be public, must have exactly one parameter, and must return null.
|
||||||
|
+ The name of the property method is immaterial, except that there must not be another method
|
||||||
|
with the same name in the class.
|
||||||
|
+ Property methods in superclasses will be recognized and accepted, but they may not be
|
||||||
|
overridden in a subclass.
|
||||||
|
+ If `minOccurs` is omitted, the default is `0`. If `minOccurs` is provided, it must be non-negative.
|
||||||
|
+ If `maxOccurs` is omitted, the default is `MAXINT`. If `maxOccurs` is provided, it must not be less than `minOccurs`.
|
||||||
|
|
||||||
|
When instantiating:
|
||||||
|
|
||||||
|
+ The parameter on a property method must match the value supplied in the RDF description.
|
||||||
|
+ If the type of the parameter is `Float`, the object of the triple must be a numeric literal, or
|
||||||
|
an untyped literal that can be parsed as a number.
|
||||||
|
+ If the type of the parameter is `String`, the object of the triple must be a String literal or an untyped literal.
|
||||||
|
+ If the type of the parameter is another class, then the object of the triple must be the URI of
|
||||||
|
another RDF description, from which the loader can create an instance of the required class.
|
||||||
|
+ The number of values for a given property URI must not be less than the `minOccurs` value on the corresponding property method.
|
||||||
|
+ The number of values for a given property URI must not be greater than the `maxOccurs` value on the corresponding property method.
|
||||||
|
|
||||||
|
### Validation methods
|
||||||
|
When the loader has satisfied all of the properties in an instance, it will
|
||||||
|
look in the instantiated class for any methods tagged with the
|
||||||
|
`edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation` annotation.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@Validation
|
||||||
|
public void validate() throws Exception {
|
||||||
|
if (baseUri == null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Configuration did not include a BaseURI.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Each such method will be called by the loader, and provides a opportunity to
|
||||||
|
confirm that the bean has been properly initialized.
|
||||||
|
|
||||||
|
Again, in detail:
|
||||||
|
|
||||||
|
+ Each validation method must be public, must accept no parameters, and must return null.
|
||||||
|
+ The name of the validation method is immaterial, except that there must not be another
|
||||||
|
+ method with the same name in the lass.
|
||||||
|
+ Validation methods in superclasses will be called, but may not be overridden in a subclass.
|
||||||
|
|
||||||
|
### Life cycle
|
||||||
|
For each instance that the loader creates, the loader will:
|
||||||
|
|
||||||
|
+ Call the appropriate property method for each property in the description.
|
||||||
|
For object properties, this includes recursive calls to create subordinate objects.
|
||||||
|
The order of property method calls is undefined.
|
||||||
|
+ Call the validation methods on the class. The order of validation method calls is undefined.
|
||||||
|
|
||||||
|
If any property method or validation method throws an exception, the process stops,
|
||||||
|
and the exception is propagated upward.
|
|
@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -63,6 +64,45 @@ public class WrappedInstance<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The loader provides the distilled property statements from the RDF. Check
|
||||||
|
* that they satisfy the cardinality requested on their methods.
|
||||||
|
*/
|
||||||
|
public void checkCardinality(Set<PropertyStatement> propertyStatements)
|
||||||
|
throws CardinalityException {
|
||||||
|
Map<String, Integer> statementCounts = countPropertyStatementsByPredicateUri(propertyStatements);
|
||||||
|
for (PropertyMethod pm : propertyMethods.values()) {
|
||||||
|
Integer c = statementCounts.get(pm.getPropertyUri());
|
||||||
|
int count = (c == null) ? 0 : c;
|
||||||
|
if (count < pm.getMinOccurs()) {
|
||||||
|
throw new CardinalityException("Expecting at least "
|
||||||
|
+ pm.getMinOccurs() + " values for '"
|
||||||
|
+ pm.getPropertyUri() + "', but found " + count + ".");
|
||||||
|
}
|
||||||
|
if (count > pm.getMaxOccurs()) {
|
||||||
|
throw new CardinalityException("Expecting no more than "
|
||||||
|
+ pm.getMaxOccurs() + " values for '"
|
||||||
|
+ pm.getPropertyUri() + "', but found " + count + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statementCounts.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Integer> countPropertyStatementsByPredicateUri(
|
||||||
|
Set<PropertyStatement> propertyStatements) {
|
||||||
|
Map<String, Integer> statementCounts = new HashMap<>();
|
||||||
|
for (String pmPredicateUri : propertyMethods.keySet()) {
|
||||||
|
int count = 0;
|
||||||
|
for (PropertyStatement ps : propertyStatements) {
|
||||||
|
if (ps.getPredicateUri().equals(pmPredicateUri)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statementCounts.put(pmPredicateUri, count);
|
||||||
|
}
|
||||||
|
return statementCounts;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The loader provides the distilled property statements from the RDF, to
|
* The loader provides the distilled property statements from the RDF, to
|
||||||
* populate the instance.
|
* populate the instance.
|
||||||
|
@ -76,7 +116,6 @@ public class WrappedInstance<T> {
|
||||||
if (pm == null) {
|
if (pm == null) {
|
||||||
throw new NoSuchPropertyMethodException(ps);
|
throw new NoSuchPropertyMethodException(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
pm.confirmCompatible(ps);
|
pm.confirmCompatible(ps);
|
||||||
|
|
||||||
if (ps instanceof ResourcePropertyStatement) {
|
if (ps instanceof ResourcePropertyStatement) {
|
||||||
|
@ -132,4 +171,10 @@ public class WrappedInstance<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class CardinalityException extends Exception {
|
||||||
|
public CardinalityException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -43,6 +43,12 @@ public class ModelUtilitiesTestHelper {
|
||||||
createProperty(propertyUri), createPlainLiteral(objectValue));
|
createProperty(propertyUri), createPlainLiteral(objectValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Statement dataProperty(String subjectUri, String propertyUri,
|
||||||
|
Float objectValue) {
|
||||||
|
return createStatement(createResource(subjectUri),
|
||||||
|
createProperty(propertyUri), createTypedLiteral(objectValue));
|
||||||
|
}
|
||||||
|
|
||||||
public static Statement dataProperty(String subjectUri, String propertyUri,
|
public static Statement dataProperty(String subjectUri, String propertyUri,
|
||||||
Object objectValue, XSDDatatype dataType) {
|
Object objectValue, XSDDatatype dataType) {
|
||||||
return createStatement(createResource(subjectUri),
|
return createStatement(createResource(subjectUri),
|
||||||
|
|
|
@ -5,7 +5,6 @@ package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDfloat;
|
import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDfloat;
|
||||||
import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDstring;
|
import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDstring;
|
||||||
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.dataProperty;
|
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.dataProperty;
|
||||||
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.model;
|
|
||||||
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.objectProperty;
|
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.objectProperty;
|
||||||
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.typeStatement;
|
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.typeStatement;
|
||||||
import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toJavaUri;
|
import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toJavaUri;
|
||||||
|
@ -20,7 +19,6 @@ import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -32,16 +30,13 @@ import stubs.javax.servlet.http.HttpSessionStub;
|
||||||
import org.apache.jena.rdf.model.Model;
|
import org.apache.jena.rdf.model.Model;
|
||||||
import org.apache.jena.rdf.model.Statement;
|
import org.apache.jena.rdf.model.Statement;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess;
|
import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess;
|
||||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.ModelAccessFactory;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.RequestModelAccess;
|
import edu.cornell.mannlib.vitro.webapp.modelaccess.RequestModelAccess;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationRdfParser.InvalidConfigurationRdfException;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationRdfParser.InvalidConfigurationRdfException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.InstanceWrapper.InstanceWrapperException;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.InstanceWrapper.InstanceWrapperException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.NoSuchPropertyMethodException;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.NoSuchPropertyMethodException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.ResourceUnavailableException;
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.ResourceUnavailableException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.ValidationFailedException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
|
@ -50,47 +45,8 @@ import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.Vali
|
||||||
* instances by URIs, so if a property refers to a created instance, we just
|
* instances by URIs, so if a property refers to a created instance, we just
|
||||||
* pass it in.
|
* pass it in.
|
||||||
*/
|
*/
|
||||||
public class ConfigurationBeanLoaderTest extends AbstractTestClass {
|
public class ConfigurationBeanLoaderTest extends
|
||||||
private static final String GENERIC_INSTANCE_URI = "http://mytest.edu/some_instance";
|
ConfigurationBeanLoaderTestBase {
|
||||||
private static final String GENERIC_PROPERTY_URI = "http://mytest.edu/some_property";
|
|
||||||
|
|
||||||
private static final String SIMPLE_SUCCESS_INSTANCE_URI = "http://mytest.edu/simple_success_instance";
|
|
||||||
|
|
||||||
private static final String FULL_SUCCESS_INSTANCE_URI = "http://mytest.edu/full_success_instance";
|
|
||||||
private static final String FULL_SUCCESS_BOOST_PROPERTY = "http://mydomain.edu/hasBoost";
|
|
||||||
private static final String FULL_SUCCESS_TEXT_PROPERTY = "http://mydomain.edu/hasText";
|
|
||||||
private static final String FULL_SUCCESS_HELPER_PROPERTY = "http://mydomain.edu/hasHelper";
|
|
||||||
private static final String FULL_SUCCESS_HELPER_INSTANCE_URI = "http://mytest.edu/full_success_helper_instance";
|
|
||||||
|
|
||||||
private ServletContextStub ctx;
|
|
||||||
private HttpSessionStub session;
|
|
||||||
private HttpServletRequestStub req;
|
|
||||||
|
|
||||||
private Model model;
|
|
||||||
|
|
||||||
private ConfigurationBeanLoader loader;
|
|
||||||
private ConfigurationBeanLoader noRequestLoader;
|
|
||||||
private ConfigurationBeanLoader noContextLoader;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup() {
|
|
||||||
ctx = new ServletContextStub();
|
|
||||||
|
|
||||||
session = new HttpSessionStub();
|
|
||||||
session.setServletContext(ctx);
|
|
||||||
|
|
||||||
req = new HttpServletRequestStub();
|
|
||||||
req.setSession(session);
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
ModelAccessFactory maf = new ModelAccessFactoryStub();
|
|
||||||
|
|
||||||
model = model();
|
|
||||||
|
|
||||||
loader = new ConfigurationBeanLoader(model, req);
|
|
||||||
noRequestLoader = new ConfigurationBeanLoader(model, ctx);
|
|
||||||
noContextLoader = new ConfigurationBeanLoader(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// Constructor tests
|
// Constructor tests
|
||||||
|
@ -308,276 +264,6 @@ public class ConfigurationBeanLoaderTest extends AbstractTestClass {
|
||||||
|
|
||||||
// --------------------------------------------
|
// --------------------------------------------
|
||||||
|
|
||||||
@Test
|
|
||||||
public void propertyMethodHasNoParameter_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(NoParameterOnPropertyMethod.class)));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
NoParameterOnPropertyMethod.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(InstanceWrapperException.class,
|
|
||||||
"must accept exactly one parameter"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class NoParameterOnPropertyMethod {
|
|
||||||
@Property(uri = GENERIC_PROPERTY_URI)
|
|
||||||
public void methodTakesNoParameters() {
|
|
||||||
// Not suitable as a property method.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void propertyMethodHasMultipleParameters_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(MultipleParametersOnPropertyMethod.class)));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
MultipleParametersOnPropertyMethod.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(InstanceWrapperException.class,
|
|
||||||
"must accept exactly one parameter"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MultipleParametersOnPropertyMethod {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Property(uri = GENERIC_PROPERTY_URI)
|
|
||||||
public void methodTakesMultipleParameters(String s, Float f) {
|
|
||||||
// Not suitable as a property method.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void propertyMethodHasInvalidParameter_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(InvalidParameterOnPropertyMethod.class)));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
InvalidParameterOnPropertyMethod.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(InstanceWrapperException.class,
|
|
||||||
"Failed to create the PropertyMethod"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class InvalidParameterOnPropertyMethod {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Property(uri = GENERIC_PROPERTY_URI)
|
|
||||||
public void methodTakesInvalidParameters(byte b) {
|
|
||||||
// Not suitable as a property method.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void propertyMethodDoesNotReturnVoid_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(PropertyMethodMustReturnVoid.class)));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
PropertyMethodMustReturnVoid.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(InstanceWrapperException.class, "should return void"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PropertyMethodMustReturnVoid {
|
|
||||||
@Property(uri = GENERIC_PROPERTY_URI)
|
|
||||||
public String methodReturnIsNotVoid(String s) {
|
|
||||||
// Not suitable as a property method.
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void propertyMethodNotAccessible_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(PropertyMethodIsPrivate.class)));
|
|
||||||
model.add(dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
|
||||||
"can't store in a private method."));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
PropertyMethodIsPrivate.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(PropertyTypeException.class,
|
|
||||||
"Property method failed."));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PropertyMethodIsPrivate {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Property(uri = GENERIC_PROPERTY_URI)
|
|
||||||
private void methodReturnIsNotVoid(String s) {
|
|
||||||
// Not suitable as a property method.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void propertyMethodThrowsException_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(PropertyMethodFails.class)));
|
|
||||||
model.add(dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
|
||||||
"exception while loading."));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
PropertyMethodFails.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(PropertyTypeException.class,
|
|
||||||
"Property method failed."));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PropertyMethodFails {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Property(uri = GENERIC_PROPERTY_URI)
|
|
||||||
public void methodThrowsException(String s) {
|
|
||||||
if (true) {
|
|
||||||
throw new RuntimeException("property method fails.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void propertyMethodDuplicateUri_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(TwoMethodsWithSameUri.class)));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
TwoMethodsWithSameUri.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(InstanceWrapperException.class,
|
|
||||||
"methods have the same URI"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TwoMethodsWithSameUri {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Property(uri = GENERIC_PROPERTY_URI)
|
|
||||||
public void firstProperty(String s) {
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Property(uri = GENERIC_PROPERTY_URI)
|
|
||||||
public void secondProperty(String s) {
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void validationMethodHasParameters_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(ValidationMethodWithParameter.class)));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
ValidationMethodWithParameter.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(InstanceWrapperException.class,
|
|
||||||
"should not have parameters"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ValidationMethodWithParameter {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Validation
|
|
||||||
public void validateWithParameter(String s) {
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void validationMethodDoesNotReturnVoid_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(ValidationMethodShouldReturnVoid.class)));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
ValidationMethodShouldReturnVoid.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(InstanceWrapperException.class, "should return void"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ValidationMethodShouldReturnVoid {
|
|
||||||
@Validation
|
|
||||||
public String validateWithReturnType() {
|
|
||||||
return "Hi there!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void validationMethodNotAccessible_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(ValidationMethodIsPrivate.class)));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
ValidationMethodIsPrivate.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(ValidationFailedException.class,
|
|
||||||
"Error executing validation method"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ValidationMethodIsPrivate {
|
|
||||||
@Validation
|
|
||||||
private void validateIsPrivate() {
|
|
||||||
// private method
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void validationMethodThrowsException_throwsException()
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
|
||||||
toJavaUri(ValidationThrowsException.class)));
|
|
||||||
|
|
||||||
expectSimpleFailure(
|
|
||||||
ValidationThrowsException.class,
|
|
||||||
throwable(ConfigurationBeanLoaderException.class,
|
|
||||||
"Failed to load"),
|
|
||||||
throwable(ValidationFailedException.class,
|
|
||||||
"Error executing validation method"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ValidationThrowsException {
|
|
||||||
@Validation
|
|
||||||
public void validateFails() {
|
|
||||||
throw new RuntimeException("from validation method");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loaderCantSatisfyContextModelsUser_throwsException()
|
public void loaderCantSatisfyContextModelsUser_throwsException()
|
||||||
throws ConfigurationBeanLoaderException {
|
throws ConfigurationBeanLoaderException {
|
||||||
|
@ -1041,6 +727,7 @@ public class ConfigurationBeanLoaderTest extends AbstractTestClass {
|
||||||
// Additional tests
|
// Additional tests
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -1049,6 +736,7 @@ public class ConfigurationBeanLoaderTest extends AbstractTestClass {
|
||||||
fail("circularReferencesAreNotFatal not implemented");
|
fail("circularReferencesAreNotFatal not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
// TODO deals with circularity.
|
// TODO deals with circularity.
|
||||||
|
@ -1057,6 +745,7 @@ public class ConfigurationBeanLoaderTest extends AbstractTestClass {
|
||||||
fail("subordinateObjectCantBeLoaded_leavesNoAccessibleInstanceOfParent not implemented");
|
fail("subordinateObjectCantBeLoaded_leavesNoAccessibleInstanceOfParent not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
// TODO deals with circularity.
|
// TODO deals with circularity.
|
||||||
|
@ -1065,42 +754,4 @@ public class ConfigurationBeanLoaderTest extends AbstractTestClass {
|
||||||
fail("parentObjectCantBeLoaded_leavesNoAccessibleInstanceOfSubordinate not implemented");
|
fail("parentObjectCantBeLoaded_leavesNoAccessibleInstanceOfSubordinate not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
// Helper methods for simple failure
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
private void expectSimpleFailure(Class<?> failureClass,
|
|
||||||
ExpectedThrowable expected, ExpectedThrowable cause)
|
|
||||||
throws ConfigurationBeanLoaderException {
|
|
||||||
expectException(expected.getClazz(), expected.getMessageSubstring(),
|
|
||||||
cause.getClazz(), cause.getMessageSubstring());
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
Object unused = loader.loadInstance(GENERIC_INSTANCE_URI, failureClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ExpectedThrowable throwable(Class<? extends Throwable> clazz,
|
|
||||||
String messageSubstring) {
|
|
||||||
return new ExpectedThrowable(clazz, messageSubstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ExpectedThrowable {
|
|
||||||
private final Class<? extends Throwable> clazz;
|
|
||||||
private final String messageSubstring;
|
|
||||||
|
|
||||||
public ExpectedThrowable(Class<? extends Throwable> clazz,
|
|
||||||
String messageSubstring) {
|
|
||||||
this.clazz = clazz;
|
|
||||||
this.messageSubstring = messageSubstring;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<? extends Throwable> getClazz() {
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessageSubstring() {
|
|
||||||
return messageSubstring;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.model;
|
||||||
|
|
||||||
|
import org.apache.jena.rdf.model.Model;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.ModelAccessFactory;
|
||||||
|
import stubs.edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccessFactoryStub;
|
||||||
|
import stubs.javax.servlet.ServletContextStub;
|
||||||
|
import stubs.javax.servlet.http.HttpServletRequestStub;
|
||||||
|
import stubs.javax.servlet.http.HttpSessionStub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
public class ConfigurationBeanLoaderTestBase extends AbstractTestClass {
|
||||||
|
protected static final String GENERIC_INSTANCE_URI = "http://mytest.edu/some_instance";
|
||||||
|
protected static final String GENERIC_PROPERTY_URI = "http://mytest.edu/some_property";
|
||||||
|
|
||||||
|
protected static final String SIMPLE_SUCCESS_INSTANCE_URI = "http://mytest.edu/simple_success_instance";
|
||||||
|
|
||||||
|
protected static final String FULL_SUCCESS_INSTANCE_URI = "http://mytest.edu/full_success_instance";
|
||||||
|
protected static final String FULL_SUCCESS_BOOST_PROPERTY = "http://mydomain.edu/hasBoost";
|
||||||
|
protected static final String FULL_SUCCESS_TEXT_PROPERTY = "http://mydomain.edu/hasText";
|
||||||
|
protected static final String FULL_SUCCESS_HELPER_PROPERTY = "http://mydomain.edu/hasHelper";
|
||||||
|
protected static final String FULL_SUCCESS_HELPER_INSTANCE_URI = "http://mytest.edu/full_success_helper_instance";
|
||||||
|
|
||||||
|
private ServletContextStub ctx;
|
||||||
|
private HttpSessionStub session;
|
||||||
|
private HttpServletRequestStub req;
|
||||||
|
|
||||||
|
protected Model model;
|
||||||
|
|
||||||
|
protected ConfigurationBeanLoader loader;
|
||||||
|
protected ConfigurationBeanLoader noRequestLoader;
|
||||||
|
protected ConfigurationBeanLoader noContextLoader;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
ctx = new ServletContextStub();
|
||||||
|
|
||||||
|
session = new HttpSessionStub();
|
||||||
|
session.setServletContext(ctx);
|
||||||
|
|
||||||
|
req = new HttpServletRequestStub();
|
||||||
|
req.setSession(session);
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
ModelAccessFactory maf = new ModelAccessFactoryStub();
|
||||||
|
|
||||||
|
model = model();
|
||||||
|
|
||||||
|
loader = new ConfigurationBeanLoader(model, req);
|
||||||
|
noRequestLoader = new ConfigurationBeanLoader(model, ctx);
|
||||||
|
noContextLoader = new ConfigurationBeanLoader(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Helper methods for simple failure
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
protected void expectSimpleFailure(Class<?> failureClass,
|
||||||
|
ExpectedThrowable expected, ExpectedThrowable cause)
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
expectException(expected.getClazz(), expected.getMessageSubstring(),
|
||||||
|
cause.getClazz(), cause.getMessageSubstring());
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
Object unused = loader.loadInstance(GENERIC_INSTANCE_URI, failureClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ExpectedThrowable throwable(Class<? extends Throwable> clazz,
|
||||||
|
String messageSubstring) {
|
||||||
|
return new ExpectedThrowable(clazz, messageSubstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ExpectedThrowable {
|
||||||
|
private final Class<? extends Throwable> clazz;
|
||||||
|
private final String messageSubstring;
|
||||||
|
|
||||||
|
public ExpectedThrowable(Class<? extends Throwable> clazz,
|
||||||
|
String messageSubstring) {
|
||||||
|
this.clazz = clazz;
|
||||||
|
this.messageSubstring = messageSubstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends Throwable> getClazz() {
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessageSubstring() {
|
||||||
|
return messageSubstring;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,251 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.dataProperty;
|
||||||
|
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.objectProperty;
|
||||||
|
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.typeStatement;
|
||||||
|
import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toJavaUri;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.jena.rdf.model.Statement;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.InstanceWrapper.InstanceWrapperException;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.CardinalityException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for minOccurs, maxOccurs on the @Property annotation.
|
||||||
|
*/
|
||||||
|
public class ConfigurationBeanLoader_Cardinality_Test extends
|
||||||
|
ConfigurationBeanLoaderTestBase {
|
||||||
|
|
||||||
|
private static final Statement[] FOUND_NONE = new Statement[0];
|
||||||
|
|
||||||
|
private static final Statement[] FOUND_ONE = new Statement[] { dataProperty(
|
||||||
|
GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI, "value One") };
|
||||||
|
|
||||||
|
private static final Statement[] FOUND_TWO = new Statement[] {
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"value One"),
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"value Two") };
|
||||||
|
|
||||||
|
private static final Statement[] FOUND_THREE = new Statement[] {
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"value One"),
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"value Two"),
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"value Three") };
|
||||||
|
|
||||||
|
private static final Statement[] FOUND_FOUR = new Statement[] {
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"value One"),
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"value Two"),
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"value Three"),
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"value Four") };
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void minOccursIsNegative_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(NegativeMinOccurs.class)));
|
||||||
|
model.add(objectProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"http://some.other/uri"));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
NegativeMinOccurs.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"must not be negative"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NegativeMinOccurs {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI, minOccurs = -1)
|
||||||
|
public void setValue(String value) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void maxOccursLessThanMinOccurs_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(MaxOccursLessThanMinOccurs.class)));
|
||||||
|
model.add(objectProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"http://some.other/uri"));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
MaxOccursLessThanMinOccurs.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"not be less than minOccurs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MaxOccursLessThanMinOccurs {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI, minOccurs = 2, maxOccurs = 1)
|
||||||
|
public void setValue(String value) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expectingSomeFoundNone_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ExpectingSome.class)));
|
||||||
|
model.add(FOUND_NONE);
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
ExpectingSome.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(CardinalityException.class, "Expecting at least 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expectingSomeFoundFewer_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ExpectingSome.class)));
|
||||||
|
model.add(FOUND_ONE);
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
ExpectingSome.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(CardinalityException.class, "Expecting at least 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expectingSomeFoundMore_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ExpectingSome.class)));
|
||||||
|
model.add(FOUND_FOUR);
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
ExpectingSome.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(CardinalityException.class,
|
||||||
|
"Expecting no more than 3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expectingSomeFoundSome_success()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ExpectingSome.class)));
|
||||||
|
model.add(FOUND_THREE);
|
||||||
|
Set<ExpectingSome> instances = loader.loadAll(ExpectingSome.class);
|
||||||
|
assertEquals(1, instances.size());
|
||||||
|
model.removeAll();
|
||||||
|
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ExpectingSome.class)));
|
||||||
|
model.add(FOUND_TWO);
|
||||||
|
instances = loader.loadAll(ExpectingSome.class);
|
||||||
|
assertEquals(1, instances.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExpectingSome {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI, minOccurs = 2, maxOccurs = 3)
|
||||||
|
public void setValue(String value) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void notSpecifiedFoundNone_success()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(CardinalityNotSpecified.class)));
|
||||||
|
model.add(FOUND_NONE);
|
||||||
|
|
||||||
|
Set<CardinalityNotSpecified> instances = loader
|
||||||
|
.loadAll(CardinalityNotSpecified.class);
|
||||||
|
assertEquals(1, instances.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void notSpecifiedFoundSome_success()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(CardinalityNotSpecified.class)));
|
||||||
|
model.add(FOUND_FOUR);
|
||||||
|
|
||||||
|
Set<CardinalityNotSpecified> instances = loader
|
||||||
|
.loadAll(CardinalityNotSpecified.class);
|
||||||
|
assertEquals(1, instances.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CardinalityNotSpecified {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public void setValue(String value) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expectNoneFoundNone_success()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ExpectNone.class)));
|
||||||
|
model.add(FOUND_NONE);
|
||||||
|
|
||||||
|
Set<ExpectNone> instances = loader.loadAll(ExpectNone.class);
|
||||||
|
assertEquals(1, instances.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExpectNone {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI, maxOccurs = 0)
|
||||||
|
public void setValue(String value) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expectExactlyFoundExactly_success()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ExpectTwo.class)));
|
||||||
|
model.add(FOUND_TWO);
|
||||||
|
|
||||||
|
Set<ExpectTwo> instances = loader.loadAll(ExpectTwo.class);
|
||||||
|
assertEquals(1, instances.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExpectTwo {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI, minOccurs = 2, maxOccurs = 2)
|
||||||
|
public void setValue(String value) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,338 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.dataProperty;
|
||||||
|
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.typeStatement;
|
||||||
|
import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toJavaUri;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import org.apache.jena.rdf.model.Statement;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.InstanceWrapper.InstanceWrapperException;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests of the @Property annotation.
|
||||||
|
*/
|
||||||
|
public class ConfigurationBeanLoader_PropertyTest extends
|
||||||
|
ConfigurationBeanLoaderTestBase {
|
||||||
|
protected static final String OTHER_PROPERTY_URI = "http://mytest.edu/different_property";
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyMethodHasNoParameter_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(NoParameterOnPropertyMethod.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
NoParameterOnPropertyMethod.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"must accept exactly one parameter"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NoParameterOnPropertyMethod {
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public void methodTakesNoParameters() {
|
||||||
|
// Not suitable as a property method.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyMethodHasMultipleParameters_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(MultipleParametersOnPropertyMethod.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
MultipleParametersOnPropertyMethod.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"must accept exactly one parameter"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MultipleParametersOnPropertyMethod {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public void methodTakesMultipleParameters(String s, Float f) {
|
||||||
|
// Not suitable as a property method.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyMethodHasInvalidParameter_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(InvalidParameterOnPropertyMethod.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
InvalidParameterOnPropertyMethod.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"Failed to create the PropertyMethod"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InvalidParameterOnPropertyMethod {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public void methodTakesInvalidParameters(byte b) {
|
||||||
|
// Not suitable as a property method.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyMethodDoesNotReturnVoid_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(PropertyMethodMustReturnVoid.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
PropertyMethodMustReturnVoid.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class, "should return void"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PropertyMethodMustReturnVoid {
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public String methodReturnIsNotVoid(String s) {
|
||||||
|
// Not suitable as a property method.
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyMethodNotAccessible_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(PropertyMethodIsPrivate.class)));
|
||||||
|
model.add(dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"can't store in a private method."));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
PropertyMethodIsPrivate.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(PropertyTypeException.class,
|
||||||
|
"Property method failed."));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PropertyMethodIsPrivate {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
private void methodReturnIsNotVoid(String s) {
|
||||||
|
// Not suitable as a property method.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyMethodThrowsException_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(PropertyMethodFails.class)));
|
||||||
|
model.add(dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"exception while loading."));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
PropertyMethodFails.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(PropertyTypeException.class,
|
||||||
|
"Property method failed."));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PropertyMethodFails {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public void methodThrowsException(String s) {
|
||||||
|
if (true) {
|
||||||
|
throw new RuntimeException("property method fails.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyMethodDuplicateUri_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(TwoMethodsWithSameUri.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
TwoMethodsWithSameUri.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"methods have the same URI"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TwoMethodsWithSameUri {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public void firstProperty(String s) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public void secondProperty(String s) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void superclassContainsPropertyAnnotation_success()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(new Statement[] {
|
||||||
|
typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(EmptyPropertyMethodSubclass.class)),
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"Value") });
|
||||||
|
|
||||||
|
EmptyPropertyMethodSubclass instance = loader.loadInstance(
|
||||||
|
GENERIC_INSTANCE_URI, EmptyPropertyMethodSubclass.class);
|
||||||
|
|
||||||
|
assertNotNull(instance);
|
||||||
|
assertEquals("Value", instance.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyMethodOverridesPropertyMethod_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(PropertyMethodOverPropertyMethodSubclass.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
PropertyMethodOverPropertyMethodSubclass.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"conflicts with a property method"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void plainMethodOverridesPropertyMethod_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(PlainOverPropertyMethodSubclass.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
PlainOverPropertyMethodSubclass.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"conflicts with a property method"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void uriConflictsBetweenSubclassAndSuperclassPropertyMethods_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ConflictingUriPropertyMethodSubclass.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
ConflictingUriPropertyMethodSubclass.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"Two property methods have the same URI"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyMethodSameNameButDoesNotOverride_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(new Statement[] {
|
||||||
|
typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(DistinctPropertyMethodSubclass.class)),
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, GENERIC_PROPERTY_URI,
|
||||||
|
"Value"),
|
||||||
|
dataProperty(GENERIC_INSTANCE_URI, OTHER_PROPERTY_URI,
|
||||||
|
100.0F) });
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
DistinctPropertyMethodSubclass.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"conflicts with a property method"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PropertyMethodSuperclass {
|
||||||
|
public String value = null;
|
||||||
|
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public void propertySuper(String v) {
|
||||||
|
if (value != null) {
|
||||||
|
throw new RuntimeException("propertySuper has already run.");
|
||||||
|
}
|
||||||
|
value = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EmptyPropertyMethodSubclass extends
|
||||||
|
PropertyMethodSuperclass {
|
||||||
|
// Just want to see that the superclass method is run.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DistinctPropertyMethodSubclass extends
|
||||||
|
PropertyMethodSuperclass {
|
||||||
|
public float fvalue;
|
||||||
|
|
||||||
|
@Property(uri = OTHER_PROPERTY_URI)
|
||||||
|
public void propertySuper(Float f) {
|
||||||
|
if (fvalue != 0.0) {
|
||||||
|
throw new RuntimeException("propertySub has already run.");
|
||||||
|
}
|
||||||
|
fvalue = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConflictingUriPropertyMethodSubclass extends
|
||||||
|
PropertyMethodSuperclass {
|
||||||
|
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public void propertyConflict(String v) {
|
||||||
|
// nothing to do.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PropertyMethodOverPropertyMethodSubclass extends
|
||||||
|
EmptyPropertyMethodSubclass {
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Property(uri = GENERIC_PROPERTY_URI)
|
||||||
|
public void propertySuper(String v) {
|
||||||
|
// Should fail (two levels down)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PlainOverPropertyMethodSubclass extends
|
||||||
|
PropertyMethodSuperclass {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void propertySuper(Float f) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,215 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
|
||||||
|
|
||||||
|
import static edu.cornell.mannlib.vitro.testing.ModelUtilitiesTestHelper.typeStatement;
|
||||||
|
import static edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader.toJavaUri;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.InstanceWrapper.InstanceWrapperException;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.configuration.WrappedInstance.ValidationFailedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the @Validation annotation.
|
||||||
|
*/
|
||||||
|
public class ConfigurationBeanLoader_ValidationTest extends
|
||||||
|
ConfigurationBeanLoaderTestBase {
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validationMethodHasParameters_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ValidationMethodWithParameter.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
ValidationMethodWithParameter.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"should not have parameters"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ValidationMethodWithParameter {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Validation
|
||||||
|
public void validateWithParameter(String s) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validationMethodDoesNotReturnVoid_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ValidationMethodShouldReturnVoid.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
ValidationMethodShouldReturnVoid.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class, "should return void"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ValidationMethodShouldReturnVoid {
|
||||||
|
@Validation
|
||||||
|
public String validateWithReturnType() {
|
||||||
|
return "Hi there!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validationMethodNotAccessible_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ValidationMethodIsPrivate.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
ValidationMethodIsPrivate.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(ValidationFailedException.class,
|
||||||
|
"Error executing validation method"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ValidationMethodIsPrivate {
|
||||||
|
@Validation
|
||||||
|
private void validateIsPrivate() {
|
||||||
|
// private method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validationMethodThrowsException_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ValidationThrowsException.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
ValidationThrowsException.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(ValidationFailedException.class,
|
||||||
|
"Error executing validation method"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ValidationThrowsException {
|
||||||
|
@Validation
|
||||||
|
public void validateFails() {
|
||||||
|
throw new RuntimeException("from validation method");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void superclassContainsValidationMethod_success()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(EmptyValidationSubclass.class)));
|
||||||
|
|
||||||
|
EmptyValidationSubclass instance = loader.loadInstance(
|
||||||
|
GENERIC_INSTANCE_URI, EmptyValidationSubclass.class);
|
||||||
|
|
||||||
|
assertNotNull(instance);
|
||||||
|
assertTrue(instance.validatorSuperHasRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void superclassAndSubclassContainValidationMethods_success()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(AdditionalValidationSubclass.class)));
|
||||||
|
|
||||||
|
AdditionalValidationSubclass instance = loader.loadInstance(
|
||||||
|
GENERIC_INSTANCE_URI, AdditionalValidationSubclass.class);
|
||||||
|
|
||||||
|
assertNotNull(instance);
|
||||||
|
assertTrue(instance.validatorSuperHasRun);
|
||||||
|
assertTrue(instance.validatorSubHasRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validationMethodOverridesValidationMethod_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(ValidationOverValidationSubclass.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
ValidationOverValidationSubclass.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"overrides a validation method"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void plainMethodOverridesValidationMethod_throwsException()
|
||||||
|
throws ConfigurationBeanLoaderException {
|
||||||
|
model.add(typeStatement(GENERIC_INSTANCE_URI,
|
||||||
|
toJavaUri(PlainOverValidationSubclass.class)));
|
||||||
|
|
||||||
|
expectSimpleFailure(
|
||||||
|
PlainOverValidationSubclass.class,
|
||||||
|
throwable(ConfigurationBeanLoaderException.class,
|
||||||
|
"Failed to load"),
|
||||||
|
throwable(InstanceWrapperException.class,
|
||||||
|
"overrides a validation method"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ValidationSuperclass {
|
||||||
|
public boolean validatorSuperHasRun = false;
|
||||||
|
|
||||||
|
@Validation
|
||||||
|
public void validatorSuper() {
|
||||||
|
if (validatorSuperHasRun) {
|
||||||
|
throw new RuntimeException("validatorSuper has already run.");
|
||||||
|
}
|
||||||
|
validatorSuperHasRun = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EmptyValidationSubclass extends ValidationSuperclass {
|
||||||
|
// Just want to see that the superclass validation is run.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AdditionalValidationSubclass extends
|
||||||
|
ValidationSuperclass {
|
||||||
|
public boolean validatorSubHasRun = false;
|
||||||
|
|
||||||
|
@Validation
|
||||||
|
public void validatorSub() {
|
||||||
|
if (validatorSubHasRun) {
|
||||||
|
throw new RuntimeException("validatorSub has already run.");
|
||||||
|
}
|
||||||
|
validatorSubHasRun = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ValidationOverValidationSubclass extends
|
||||||
|
EmptyValidationSubclass {
|
||||||
|
@Override
|
||||||
|
@Validation
|
||||||
|
public void validatorSuper() {
|
||||||
|
// Should fail (two levels down)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PlainOverValidationSubclass extends
|
||||||
|
ValidationSuperclass {
|
||||||
|
@Override
|
||||||
|
public void validatorSuper() {
|
||||||
|
// Should fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue