001package org.biopax.paxtools.io.jena; 002 003import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; 004import com.hp.hpl.jena.ontology.*; 005import com.hp.hpl.jena.rdf.model.Resource; 006import com.hp.hpl.jena.util.iterator.ExtendedIterator; 007import org.apache.commons.logging.Log; 008import org.apache.commons.logging.LogFactory; 009import org.biopax.paxtools.controller.EditorMapImpl; 010import org.biopax.paxtools.controller.ObjectPropertyEditor; 011import org.biopax.paxtools.controller.PropertyEditor; 012import org.biopax.paxtools.model.BioPAXElement; 013import org.biopax.paxtools.model.BioPAXLevel; 014import org.biopax.paxtools.util.IllegalBioPAXArgumentException; 015 016import java.io.OutputStream; 017import java.io.PrintStream; 018import java.util.HashSet; 019import java.util.Set; 020 021 022/** 023 * This class is an editor map that uses Jena to read BioPAX OWL definition and creates property 024 * editors for BioPAX interfaces. 025 * 026 * This editor map is extensively used for I/O, modification, and querying operations applied on the 027 * model. 028 */ 029public final class JenaEditorMap extends EditorMapImpl 030{ 031// ------------------------------ FIELDS ------------------------------ 032 033 private static final Log log = LogFactory.getLog(JenaEditorMap.class); 034 035 // --------------------------- CONSTRUCTORS --------------------------- 036 037 038 public JenaEditorMap(BioPAXLevel level) { 039 super(level); 040 OntModel ontologyDefinition = 041 JenaIOHandler.createModel(); 042 043 ontologyDefinition.read(this.level.getLevelFileAsStream(), 044 this.level.getNameSpace()); 045 init(); 046 preprocessClasses(ontologyDefinition); 047 preprocessProperties(ontologyDefinition); 048 preprocessRestrictions(ontologyDefinition); 049 } 050 051 protected void init() { 052 053 } 054 055 private void preprocessClasses(OntModel model) { 056 //Let's iterate over all classes 057 ExtendedIterator extendedIterator = model.listClasses(); 058 while (extendedIterator.hasNext()) { 059 060 checkOntologyClassAndRegister((OntClass) extendedIterator.next()); 061 } 062 } 063 064 protected void checkOntologyClassAndRegister(OntClass ontClass) { 065 066 if (isInBioPAXNameSpace(ontClass.getNameSpace())) { 067 registerModelClass(ontClass.getLocalName()); 068 } 069 } 070 071 072 private void preprocessProperties(OntModel model) { 073 //Let's iterate over all properties 074 ExtendedIterator extendedIterator = model.listDatatypeProperties(); 075 iteratePropertiesAndResolveDomain(extendedIterator); 076 077 extendedIterator = model.listObjectProperties(); 078 iteratePropertiesAndResolveDomain(extendedIterator); 079 } 080 081 private void iteratePropertiesAndResolveDomain( 082 ExtendedIterator extendedIterator) { 083 while (extendedIterator.hasNext()) { 084 OntProperty property = 085 (OntProperty) extendedIterator.next(); 086 // Let's try to map the domain of the property to a java bean 087 OntResource domain = retrieveDomain(property); 088 089 090 091 092 //Now there are two possibilities 093 //Check this by evaluating the name space 094 //TODO find a more ontology-conscient way 095 recursivelyResolveUnionClasses(property, domain); 096 } 097 } 098 099 private void recursivelyResolveUnionClasses(OntProperty property, OntResource domain) { 100 String nameSpace = domain.getNameSpace(); 101 if (isInBioPAXNameSpace(nameSpace)) { 102 //A: it is a class and we are clear to go 103 createAndRegisterBeanEditor(property, domain); 104 } else { 105 //B: it is a union of classes ( things can actually be more 106 //complicated but for now these are the two cases with BioPAX 107 ExtendedIterator unionSetClassIterator = 108 ((UnionClass) domain.as(UnionClass.class)) 109 .listOperands(); 110 while (unionSetClassIterator.hasNext()) { 111 OntClass ontClass = 112 (OntClass) unionSetClassIterator.next(); 113 recursivelyResolveUnionClasses(property, ontClass); 114 } 115 } 116 } 117 118 protected void createAndRegisterBeanEditor(OntProperty property, OntResource domain) { 119 createAndRegisterBeanEditor(property.getLocalName(), 120 extractClass(domain.asClass()), null); 121 } 122 123 private OntResource retrieveDomain(OntProperty property) { 124 OntResource domain = property.getDomain(); 125 126 if (domain == null) { 127 128 //this is here because subproperties does not automatically 129 //return their "inherited" domains. This is a very rare case 130 OntProperty superProperty = property; 131 while (domain == null) { 132 superProperty = superProperty.getSuperProperty(); 133 domain = superProperty.getDomain(); 134 } 135 136 } 137 return domain; 138 } 139 140 private void preprocessRestrictions(OntModel model) { 141 ExtendedIterator extendedIterator = model.listRestrictions(); 142 while (extendedIterator.hasNext()) { 143 Restriction restriction = (Restriction) extendedIterator.next(); 144 try { 145 preprocessRestriction(restriction); 146 } catch (Exception ex) { 147 if (log.isInfoEnabled()) { 148 log.info("Skipping. " + ex.getMessage()); 149 } 150 } 151 } 152 } 153 154 private void preprocessRestriction(Restriction restriction) { 155 OntProperty ontProperty = restriction.getOnProperty(); 156 Set<PropertyEditor> propertyEditors = propertyToEditorMap.get( 157 ontProperty.getLocalName()); 158 if (propertyEditors == null) { 159 throw new IllegalBioPAXArgumentException("No editors for property " + 160 ontProperty.getLocalName()); 161 } 162 ExtendedIterator iterator = restriction.listSubClasses(true); 163 while (iterator.hasNext()) { 164 OntClass ontClass = (OntClass) iterator.next(); 165 Class domain; 166 try { 167 domain = extractClass(ontClass); 168 } catch (IllegalBioPAXArgumentException e) { 169 if (log.isInfoEnabled()) { 170 log.info("Skipping. (" + e.getMessage() + ")"); 171 } 172 continue; 173 } 174 for (PropertyEditor propertyEditor : propertyEditors) { 175 if (propertyEditor.getDomain().isAssignableFrom(domain)) { 176 if (restriction.isAllValuesFromRestriction()) { 177 AllValuesFromRestriction valuesFromRestriction = 178 restriction.asAllValuesFromRestriction(); 179 if (propertyEditor instanceof ObjectPropertyEditor) { 180 OntClass values = (OntClass) valuesFromRestriction. 181 getAllValuesFrom(). 182 as(OntClass.class); 183 Set<Class<? extends BioPAXElement>> ranges = getSetOfJavaClasses( 184 values); 185 ((ObjectPropertyEditor) propertyEditor). 186 addRangeRestriction(domain, ranges); 187 } 188 } 189// todo restriction.isCardinalityRestriction()|| 190// restriction.isMaxCardinalityRestriction())) 191// { 192// System.out.println(domain); 193// System.out.println(propertyEditor.getProperty()); 194// } 195 } 196 } 197 } 198 } 199 200 201 protected Class<? extends BioPAXElement> extractClass(Resource resource) { 202 String localName = getJavaName(resource); 203 return this.getLevel().getInterfaceForName(localName); 204 } 205 206 private String getJavaName(Resource resource) { 207 // Since java does not allow '-' replace them all with '_' 208 return resource.getLocalName().replaceAll("-", "_"); 209 } 210 211 private Set<Class<? extends BioPAXElement>> getSetOfJavaClasses(OntClass values) { 212 HashSet<Class<? extends BioPAXElement>> set = new HashSet<Class<? extends BioPAXElement>>(); 213 recursivelyTraverse(values, set); 214 assert !set.isEmpty(); 215 return set; 216 } 217 218 private void recursivelyTraverse(OntClass values, HashSet<Class<? extends BioPAXElement>> set) { 219 if (values.isUnionClass()) { 220 UnionClass unionClass = values.asUnionClass(); 221 ExtendedIterator iterator1 = 222 unionClass.listOperands(); 223 while (iterator1.hasNext()) { 224 recursivelyTraverse((OntClass) iterator1.next(), set); 225 } 226 } else { 227 set.add(extractClass(values)); 228 } 229 } 230 231// ------------------------ INTERFACE METHODS ------------------------ 232 233// --------------------- Interface EditorMap --------------------- 234 235 // -------------------------- OTHER METHODS -------------------------- 236 237// --------------------- ACCESORS and MUTATORS--------------------- 238 239 public XSDDatatype getDataTypeFor(PropertyEditor editor) { 240 Class range = editor.getRange(); 241 XSDDatatype type = null; 242 if (range.isEnum() || range.equals(String.class)) { 243 type = XSDDatatype.XSDstring; 244 } else if (range.equals(double.class)) { 245 type = XSDDatatype.XSDdouble; 246 } else if (range.equals(int.class)) { 247 type = XSDDatatype.XSDint; 248 } else if (range.equals(float.class)) { 249 type = XSDDatatype.XSDfloat; 250 } else if (range.equals(Boolean.class) || range.equals(boolean.class)) { 251 type = XSDDatatype.XSDboolean; 252 } 253 254 return type; 255 } 256 257// -------------------------- INNER CLASSES -------------------------- 258 259 260 void writeSimpleEditorMapProperties(OutputStream out) { 261 PrintStream stream = new PrintStream(out); 262 for (Class<? extends BioPAXElement> aClass : classToEditorMap.keySet()) { 263 stream.print(aClass.getSimpleName() + " "); 264 265 } 266 stream.println(); 267 for (Set<PropertyEditor> propertyEditors : propertyToEditorMap.values()) { 268 for (PropertyEditor propertyEditor : propertyEditors) { 269 stream.println(propertyEditor.toString()); 270 } 271 } 272 stream.close(); 273 } 274 275 276 public BioPAXLevel getLevel() 277 { 278 return level; 279 } 280} 281 282 283 284