/*
* Copyright 2003-2010 Tufts University Licensed under the
* Educational Community License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.osedu.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS"
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/**
*
* @author akumar03
*/
package edu.tufts.vue.metadata;
import java.util.*;
import java.net.*;
import java.io.*;
import edu.tufts.vue.ontology.*;
import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.ontology.*;
import tufts.Util;
import tufts.vue.DEBUG;
public class CategoryModel extends ArrayList<edu.tufts.vue.ontology.Ontology>
{
private static final org.apache.log4j.Logger Log = org.apache.log4j.Logger.getLogger(CategoryModel.class);
public static final String CUSTOM_METADATA_FILE = tufts.vue.VueUtil.getDefaultUserFolder()+File.separator+tufts.vue.VueResources.getString("metadata.custom.file");
public static final String ONT_SEPARATOR = "#";
// note: the next two constants may not be in sync with the actual
// properties file -- see code in loader thread below
// which attempts to detect the problem (and prints a warning)
public static final int DUBLIN_CORE = 1;
public static final int VRA = 2;
private boolean ontologiesLoaded = false;
private String[] defaultOntologyUrls;
int ontTypesCount = 0; // is never updated on remove, tho access API method appears to have never been used
private static final Map<URL,edu.tufts.vue.ontology.Ontology> ontCache = new HashMap<URL,edu.tufts.vue.ontology.Ontology>(); // is never cleared
private edu.tufts.vue.ontology.Ontology customOntology;
public CategoryModel() {
Log.debug("Creating Category Model");
Runnable ontologyLoader = new Runnable()
{
public void run()
{
loadDefaultVUEOntologies();
loadCustomOntology(false);
/*if(defaultOntologyUrls[VRA].toString().indexOf("/edu/tufts/vue/metadata/vra_core_3.rdf") == -1)
{
System.out.println("warning: may be removing incorrect VRA url " + defaultOntologyUrls[VRA] );
}
removeDefaultOntology(VRA);*/
edu.tufts.vue.preferences.implementations.MetadataSchemaPreference
msp =
edu.tufts.vue.preferences.implementations.MetadataSchemaPreference.getInstance();
if(!msp.getDublinCoreValue())
removeDefaultOntology(DUBLIN_CORE);
if(!msp.getVRAValue())
removeDefaultOntology(VRA);
ontologiesLoaded = true;
}
};
Thread loader = new Thread(ontologyLoader);
loader.start();
}
// Actually, the way to do this is to hash in the Ontology, just by label/id, and we can lookup
// the Ontology by OntType.base (hashed also if we like). Leaving this in for debug.
@Override public boolean add(edu.tufts.vue.ontology.Ontology o) {
if (DEBUG.Enabled) Log.debug("add[" + size() + "] " + o.getBase() + " " + Util.tags(o.getLabel()));
scanOntTypes(o);
return super.add(o);
}
@Override public edu.tufts.vue.ontology.Ontology set(int index, edu.tufts.vue.ontology.Ontology o) {
if (DEBUG.Enabled) Log.debug("set[" + index + "] " + o.getBase() + " " + Util.tags(o.getLabel()));
// impl is messy: will add empty ontologies with numbered names to replace ones removed
// if (o.getBase() == null) Util.printStackTrace();
scanOntTypes(o);
return super.set(index, o);
}
@Override public boolean remove(Object _o) {
edu.tufts.vue.ontology.Ontology o = (edu.tufts.vue.ontology.Ontology) _o;
if (DEBUG.Enabled) Log.debug("remove " + o.getBase() + " " + Util.tags(o.getLabel()));
// todo: flush cache
return super.remove(o);
}
private void scanOntTypes(edu.tufts.vue.ontology.Ontology o) {
// ontTypesCount += o.getOntTypes().size(); // won't need: can ask ontTypeByKey.size()
for (OntType ontType : o.getOntTypes()) {
if (DEBUG.PAIN || DEBUG.DATA) Log.info(ontType);
// OntType old = ontTypeByKey.put(ontType.getAsKey(), ontType);
// if (old != null) Log.warn("duplicate ontType key: " + old.getAsKey());
// else Log.info("cached: " + ontType);
}
}
public boolean isLoaded() {
return ontologiesLoaded;
}
public void loadDefaultVUEOntologies() {
defaultOntologyUrls = tufts.vue.VueResources.getStringArray("metadata.load.files");
for(int i =0;i<defaultOntologyUrls.length;i++) {
try {
loadOntology(/*tufts.vue.VueResources.getBundle().getClass()*/tufts.vue.VueResources.class.getResource(defaultOntologyUrls[i]));
} catch(Throwable t) {
Log.error("Problem loading metadata: "+defaultOntologyUrls[i]+" Error:"+t.getMessage());
}
}
}
public void loadDefaultVUEOntology(int location) {
defaultOntologyUrls = tufts.vue.VueResources.getStringArray("metadata.load.files");
//for(int i =0;i<defaultOntologyUrls.length;i++) {
try {
loadOntology(location,tufts.vue.VueResources.class.getResource(defaultOntologyUrls[location]));
} catch(Throwable t) {
Log.error("Problem loading metadata: "+defaultOntologyUrls[location]+" Error:"+t.getMessage());
}
//}
}
public void loadOntology(int index, URL url) {
if(ontCache.get(url) == null) {
edu.tufts.vue.ontology.Ontology ontology = new RDFSOntology(url);
ontTypesCount += ontology.getOntTypes().size();
set(index, ontology);
ontCache.put(url, ontology);
} else {
set(index, ontCache.get(url));
}
}
public void loadOntology(URL url) {
if(ontCache.get(url) == null) {
edu.tufts.vue.ontology.Ontology ontology = new RDFSOntology(url);
ontTypesCount += ontology.getOntTypes().size();
add(ontology);
ontCache.put(url,ontology);
} else {
// Weird: if already loaded, we add it again to the end? Was this a cut/paste fail from above?
add(ontCache.get(url));
}
}
public int getOntTypesSize() {
return ontTypesCount;
}
/** @return matching OntType if found, null otherwise */
public OntType getCustomCategoryByLabel(String label) {
return customOntology.getOntTypeByLabel(label);
}
public OntType addCustomCategory(String name) {
final OntType ontType = new OntType();
ontType.setLabel(name);
ontType.setBase(customOntology.getBase());
ontType.setId(customOntology.getBase()+name);
customOntology.getOntTypes().add(ontType);
return ontType;
}
public OntType addCustomCategory(String name,OntType value) {
OntType ontType = new OntType();
ontType.setLabel(name);
ontType.setBase(customOntology.getBase());
ontType.setId(customOntology.getBase()+name);
if (customOntology.getOntTypes().indexOf(value) > -1)
customOntology.getOntTypes().set(customOntology.getOntTypes().indexOf(value),ontType);
//customOntology.getOntTypes().add(ontType);
return ontType;
}
public void removeCustomCategory(OntType ontType) {
customOntology.getOntTypes().remove(ontType);
}
public void removeDefaultOntology(int location)
{
if(location == DUBLIN_CORE)
{
//remove(defaultOntologyUrls[DUBLIN_CORE]);
edu.tufts.vue.ontology.Ontology dcOntology = ontCache.get(tufts.vue.VueResources.getBundle().getClass().getResource(defaultOntologyUrls[DUBLIN_CORE]));
RDFSOntology emptyOntology = new RDFSOntology();
set(DUBLIN_CORE,emptyOntology);
//set(dcOntologyLocation,emptyOntology);
//remove(dcOntology);
}
if(location == VRA)
{
edu.tufts.vue.ontology.Ontology vraOntology = ontCache.get(tufts.vue.VueResources.getBundle().getClass().getResource(defaultOntologyUrls[VRA]));
RDFSOntology emptyOntology = new RDFSOntology();
set(VRA,emptyOntology);
// VRALocation...
remove(vraOntology);
}
}
public edu.tufts.vue.ontology.Ontology getCustomOntology() {
return customOntology;
}
synchronized public void saveCustomOntology() {
try {
OntModel m = ModelFactory.createOntologyModel(OntModelSpec.RDFS_MEM,null);
for(OntType ontType: customOntology.getOntTypes()) {
m.createClass(customOntology.getBase()+ONT_SEPARATOR+ontType.getLabel());
}
RDFWriter writer = m.getWriter();
writer.setProperty("allowBadURIs","true");
writer.write(m,new BufferedWriter(new FileWriter(CUSTOM_METADATA_FILE)),customOntology.getBase());
}catch(Throwable t) {
Log.error("Problem saving custom metadata - Error:"+t.getMessage());
t.printStackTrace();
}
}
private void loadCustomOntology(boolean flag) {
try {
if(customOntology == null && !flag) {
customOntology = new RDFSOntology(new File(CUSTOM_METADATA_FILE).toURI().toURL());
ontTypesCount += customOntology.getOntTypes().size();
add(customOntology);
} else if(flag) {
remove(customOntology);
customOntology = new RDFSOntology(new File(CUSTOM_METADATA_FILE).toURI().toURL());
ontTypesCount += customOntology.getOntTypes().size();
add(customOntology);
}
} catch(Throwable t) {
File test = new File(CUSTOM_METADATA_FILE);
URL url = null;
URI uri = null;
try
{
uri = test.toURI();
//System.out.print("Category Model load -- uri " + uri);
url = uri.toURL();
}
catch(Exception e)
{
System.out.println("Category Model load -- inner exception: " + e);
}
customOntology = new RDFSOntology();
customOntology.setBase(url.toString());
add(customOntology);
if (t.getCause() instanceof FileNotFoundException) {
Log.info("no custom meta-data: " + t.getCause().getMessage());
} else {
Log.info("Didn't load custom metadata, probably just hasn't been created yet - users can enter custom "
+ "metadata through the info window GUI to create file in user directory, if needed. "
+ "Additional details on specific condition follow: "+t.getMessage());
}
}
}
}