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