001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: aschultz $'
006 * '$Date: 2011-04-08 23:06:46 +0000 (Fri, 08 Apr 2011) $' 
007 * '$Revision: 27484 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.sms;
031
032import java.io.File;
033import java.net.URI;
034import java.util.ArrayList;
035import java.util.Collections;
036import java.util.HashSet;
037import java.util.Iterator;
038import java.util.List;
039import java.util.Random;
040import java.util.Set;
041import java.util.TreeSet;
042import java.util.Vector;
043import java.util.regex.Matcher;
044import java.util.regex.Pattern;
045
046import org.apache.commons.logging.Log;
047import org.apache.commons.logging.LogFactory;
048import org.semanticweb.owl.model.AddAxiom;
049import org.semanticweb.owl.model.OWLAnnotation;
050import org.semanticweb.owl.model.OWLAnnotationAxiom;
051import org.semanticweb.owl.model.OWLAxiom;
052import org.semanticweb.owl.model.OWLClass;
053import org.semanticweb.owl.model.OWLDataFactory;
054import org.semanticweb.owl.model.OWLDescription;
055import org.semanticweb.owl.model.OWLLabelAnnotation;
056import org.semanticweb.owl.model.OWLOntology;
057import org.semanticweb.owl.model.OWLOntologyChangeException;
058import org.semanticweb.owl.model.OWLOntologyCreationException;
059import org.semanticweb.owl.model.OWLOntologyManager;
060import org.semanticweb.owl.model.OWLOntologyStorageException;
061import org.semanticweb.owl.model.OWLProperty;
062import org.semanticweb.owl.model.RemoveAxiom;
063import org.semanticweb.owl.util.SimpleURIMapper;
064
065/**
066 * This class encapsulates/wraps an ontology model. TODO: still developing the
067 * interface for this class.
068 */
069public class NamedOntModel implements Comparable {
070
071    private OWLOntology _ontology; // the ontology in the model
072    private String _name; // the name of the ontology, or the namespace
073    private OWLOntologyManager _manager;
074        private Color color;
075        private boolean local;
076        
077    private String _filePath; // the name of the OWL file
078
079    /**
080     * Creates a named ont model for the ontology given in filePath
081     * 
082     * @param filePath
083     *            The path to the file to load. We assume the ontology is
084     *            already classified.
085     */
086    public NamedOntModel(String filePath) throws Exception {
087        _filePath = filePath;
088    }
089        
090    public static String parseLabel(OWLAnnotationAxiom axiom) {
091        return parseLabel(axiom.getAnnotation());
092    }
093        
094    public static String parseLabel(OWLAnnotation annot) {
095        Pattern pattern = Pattern.compile("\"(.*)\"\\^\\^string");
096        if(annot == null || annot.getAnnotationValue() == null)
097            return null;
098        String a = annot.getAnnotationValue().toString();
099        Matcher matcher = pattern.matcher(a);
100        if (matcher.matches()) {
101            return matcher.group(1);
102        }
103        return a;
104    }
105        
106    public String getTopLevelLabel() {
107        Set<OWLAnnotationAxiom> axioms = _ontology.getAnnotationAxioms();
108        URI labelURI = URI.create("http://www.w3.org/2000/01/rdf-schema#label");
109        for (OWLAnnotationAxiom axiom : axioms) {
110            if (axiom.getAnnotation().getAnnotationURI().equals(labelURI) && axiom.getSubject() instanceof OWLOntology) {
111                _name = parseLabel(axiom);
112                return _name;
113            }
114        }
115        _name = _ontology.toString();
116        return _name;
117    }
118        
119    public void initializeNew(String label) {
120        Random random = new Random();
121        int i;
122        do {
123            i = random.nextInt();
124        }
125        while(i < 0);
126                
127        _manager = OntologyCatalog.getManager();
128        URI logicalUri = URI.create("urn:lsid:localhost:onto:" + random.nextInt() + ":1");
129        URI physicalUri = new File(_filePath).toURI();
130        SimpleURIMapper mapper = new SimpleURIMapper(logicalUri, physicalUri);
131        _manager.addURIMapper(mapper);
132
133        try {
134            _ontology = _manager.createOntology(logicalUri);
135        }
136        catch(OWLOntologyCreationException e) {
137            e.printStackTrace();
138        }
139                
140        setTopLevelLabel(label);
141        _name = label;          
142    }
143        
144    public void removeTopLevelLabel() {
145        if (_ontology == null) {
146            return;
147        }
148                
149        Set<OWLAnnotationAxiom> axioms = _ontology.getAnnotationAxioms();
150        URI labelURI = URI.create("http://www.w3.org/2000/01/rdf-schema#label");
151        for (OWLAnnotationAxiom axiom : axioms) {
152            if (axiom.getAnnotation().getAnnotationURI().equals(labelURI) && axiom.getSubject() instanceof OWLOntology) {
153                try {
154                    _manager.applyChange(new RemoveAxiom(_ontology, axiom));
155                }
156                catch(OWLOntologyChangeException ex) {
157                    ex.printStackTrace();
158                }
159                return;
160            }
161        }
162    }
163
164        @Override
165        public boolean equals(Object o) {
166                if (this == o) return true;
167                if (o == null || getClass() != o.getClass()) return false;
168
169                NamedOntModel that = (NamedOntModel) o;
170
171                if (_filePath != null ? !_filePath.equals(that._filePath) : that._filePath != null) return false;
172                if (_name != null ? !_name.equals(that._name) : that._name != null) return false;
173
174                return true;
175        }
176
177        @Override
178        public int hashCode() {
179                int result = _name != null ? _name.hashCode() : 0;
180                result = 31 * result + (_filePath != null ? _filePath.hashCode() : 0);
181                return result;
182        }
183
184        
185    public void setTopLevelLabel(String label) {
186        if (_ontology == null) {
187            return;
188        }
189                
190        OWLDataFactory factory = _manager.getOWLDataFactory();
191        OWLLabelAnnotation annotation = factory.getOWLLabelAnnotation(label);
192        OWLAxiom axiom = factory.getOWLOntologyAnnotationAxiom(_ontology, annotation);
193        try {
194            _manager.applyChange(new AddAxiom(_ontology, axiom));
195        }
196        catch(OWLOntologyChangeException ex) {
197            log.error("Error adding ontology label", ex);
198        }
199    }
200        
201    public File getFile() {
202        return new File(_filePath);
203    }
204        
205    /**
206     * Initializes a named ont model wrapper for the ontology.
207     */
208    public boolean initialize() {
209        _manager = OntologyCatalog.getManager();
210        try {
211            _ontology = _manager.loadOntologyFromPhysicalURI(new File(_filePath).toURI());
212                SimpleURIMapper mapper = new SimpleURIMapper(_ontology.getURI(), new File(_filePath).toURI());
213                _manager.addURIMapper(mapper);
214        }
215        catch(OWLOntologyCreationException ex) {
216            return false;
217        }
218        _name = getTopLevelLabel();
219        
220                // garbage collect to keep memory usage from spiking
221                System.gc();
222                
223                return true;
224    }
225
226    /**
227     * @return The namespace for the ontology
228     */
229    public String getNameSpace() {
230        return _ontology.getURI().toString();
231    }
232        
233    public OWLOntology getOntology() {
234        return this._ontology;
235    }
236
237    /**
238     * @return The root classes, i.e., without a named superclass, for this
239     *         ontology.
240     */
241    public Iterator<NamedOntClass> getRootClasses(boolean sorted) {
242        // get all the classesg
243        Vector<OWLClass> classes = new Vector(_ontology.getReferencedClasses());
244        Vector<NamedOntClass> results = new Vector();
245        boolean foundResult = true;
246        // check each class to see if a root
247        for (OWLClass c : _ontology.getReferencedClasses()) {           // TODO: Is this an appropriate replacement for listNamedClasses()?
248            for (OWLDescription superClassAxiom : c.getSuperClasses(_ontology)) {
249                            
250                if(!superClassAxiom.isAnonymous()) {
251                    OWLClass s = superClassAxiom.asOWLClass();
252                    if (classes.contains(s)) {
253                        foundResult = false;
254                        break;
255                    }
256                }
257            }
258
259            if (foundResult) {
260                results.add(new NamedOntClass(c, _ontology));
261            }
262            foundResult = true;
263        }
264        if (sorted)
265            Collections.sort(results);
266        return results.iterator();
267    }
268    
269    public void write() {
270        try {
271            _manager.saveOntology(_ontology);
272        }
273        catch(OWLOntologyStorageException ex) {
274            ex.printStackTrace();
275        }
276    }
277
278    /**
279     * gets a list of the named classes in the ontology
280     * 
281     * @param sorted
282     *            Return sorted list if true
283     * @return A sorted list of named ontology classes
284     */
285    public Iterator<NamedOntClass> getNamedClasses() {
286
287        //use TreeSet instead of Vector so contains() is fast. TreeSet also
288        //gives ascending natural ordering sorting for free. fix for bug #4539
289        //Vector<NamedOntClass> results = new Vector<NamedOntClass>();
290        TreeSet<NamedOntClass> results = new TreeSet<NamedOntClass>();
291        NamedOntClass noc = null;
292        for (OWLClass c : _ontology.getReferencedClasses()) {
293                noc = new NamedOntClass(c, _ontology);
294                
295                if (!results.contains(noc))
296                        results.add(noc);
297        }
298                
299        return results.iterator();
300    }
301
302    public NamedOntClass getNamedClass(String name) {
303        for(OWLClass c : _ontology.getReferencedClasses()) {
304            String uri = c.getURI().toString();
305            String [] parts = uri.split("#");
306            if(parts.length != 2)
307                return null;
308            if(parts[1].equals(name))
309                return new NamedOntClass(c, _ontology);
310        }
311        return null;
312    }
313
314        /**
315         * gets a list of the named properties in the ontology
316         *
317         * @param sorted
318         *            Return sorted list if true
319         * @return A sorted list of named ontology classes
320         */
321        public Iterator<NamedOntProperty> getNamedProperties(boolean sorted) {
322                        Set<OWLProperty> owlProperties = new HashSet<OWLProperty>();
323                        owlProperties.addAll(_ontology.getReferencedDataProperties());
324                        owlProperties.addAll(_ontology.getReferencedObjectProperties());
325
326                        List<NamedOntProperty> results = new ArrayList<NamedOntProperty>();
327                        for (OWLProperty owlProperty : owlProperties) {
328                                results.add(new NamedOntProperty(owlProperty, _ontology, this));
329                        }
330
331                if (sorted) {
332                        Collections.sort(results);
333                        }
334                return results.iterator();
335        }
336
337    /**
338     *
339     */
340    public String toString() {
341        return getName();
342    }
343
344    /**
345     * @return The name of the model
346     */
347    public String getName() {
348        return _name;
349    }
350
351    public int compareTo(Object obj) {
352        String str1 = toString();
353        String str2 = obj.toString();
354        return str1.compareTo(str2);
355    }
356
357    private static final Log log = LogFactory.getLog(NamedOntModel.class);
358
359        public Color getColor() {
360                return color;
361        }
362
363        public void setColor(Color color) {
364                this.color = color;
365        }
366
367        public boolean isLocal() {
368                return local;
369        }
370
371        public void setLocal(boolean local) {
372                this.local = local;
373        }
374} // NamedOntModel