/* * #! * Ontopoly Editor * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed under the Apache 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.apache.org/licenses/LICENSE-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. * !# */ package ontopoly.sysmodel; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import net.ontopia.infoset.core.LocatorIF; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.core.TopicMapBuilderIF; import net.ontopia.topicmaps.core.TopicMapIF; import net.ontopia.topicmaps.core.TopicMapStoreIF; import net.ontopia.topicmaps.entry.TopicMapReferenceIF; import net.ontopia.topicmaps.entry.TopicMapRepositoryIF; import net.ontopia.topicmaps.entry.TopicMapSourceIF; import net.ontopia.topicmaps.entry.TopicMaps; import net.ontopia.topicmaps.query.core.QueryProcessorIF; import net.ontopia.topicmaps.query.utils.QueryUtils; import net.ontopia.topicmaps.utils.IdentityUtils; import net.ontopia.topicmaps.utils.MergeUtils; import net.ontopia.topicmaps.utils.ltm.LTMTopicMapWriter; import net.ontopia.topicmaps.xml.XTMTopicMapReference; import net.ontopia.utils.DeciderIF; import net.ontopia.utils.ObjectUtils; import net.ontopia.utils.OntopiaRuntimeException; import net.ontopia.utils.URIUtils; import ontopoly.model.PSI; import ontopoly.model.QueryMapper; import ontopoly.utils.OntopolyModelUtils; /** * INTERNAL: Represents the system topic map describing all the topic * maps in the Ontopoly topic maps repository. */ public class OntopolyRepository { public static final String ONTOLOGY_TOPIC_MAP_ID = "ontopoly-ontology.xtm"; private static final Comparator<TopicMapReference> REFERENCE_COMPARATOR = new Comparator<TopicMapReference>() { public int compare(TopicMapReference r1, TopicMapReference r2) { return ObjectUtils.compareIgnoreCase(r1.getName(), r2.getName()); } }; private transient TopicMapRepositoryIF repository; public OntopolyRepository() { this.repository = createTopicMapRepository(); } protected String getSystemTopicMapId() { return "ontopoly-system.ltm"; } private TopicMapIF getSystemTopicMap() { // open system topic map String systemTopicMapId = getSystemTopicMapId(); TopicMapReferenceIF topicMapReferenceIF = getTopicMapRepository().getReferenceByKey(systemTopicMapId); if (topicMapReferenceIF == null) throw new OntopiaRuntimeException("Cannot find topic map with id '" + systemTopicMapId); try { return topicMapReferenceIF.createStore(false).getTopicMap(); } catch(IOException e) { throw new OntopiaRuntimeException(e); } } private List<String> getRegisteredTopicMaps() { // now query to find Ontopoly topic maps QueryProcessorIF processor = QueryUtils.getQueryProcessor(getSystemTopicMap()); QueryMapper<String> qm = new QueryMapper<String>(processor); return qm.queryForList( "using ont for i\"http://psi.ontopia.net/ontology/\" " + "select $ID from instance-of($T, ont:ted-topic-map), " + "ont:topic-map-id($T, $ID)?"); } protected TopicMapRepositoryIF createTopicMapRepository() { return TopicMaps.getRepository(); } public TopicMapRepositoryIF getTopicMapRepository() { return repository; } /** * INTERNAL: Returns an alphabetically sorted list of all the * Ontopoly topic maps. * @return a List of TopicMapReference objects */ public List<TopicMapReference> getOntopolyTopicMaps() { List<String> registeredTopicMaps = getRegisteredTopicMaps(); List<TopicMapReference> result = new ArrayList<TopicMapReference>(registeredTopicMaps.size()); for (String referenceId : registeredTopicMaps) { result.add(new TopicMapReference(referenceId)); } Collections.sort(result, REFERENCE_COMPARATOR); return result; } /** * INTERNAL: Returns an alphabetically sorted list of all the * non-Ontopoly topic maps. * @return a List of TopicMapReference objects */ public List<TopicMapReference> getNonOntopolyTopicMaps() { Set<String> registeredTopicMaps = new HashSet<String>(getRegisteredTopicMaps()); List<TopicMapReference> result = new ArrayList<TopicMapReference>(); for (TopicMapReferenceIF ref : getTopicMapRepository().getReferences()) { if (!registeredTopicMaps.contains(ref.getId())) { result.add(new TopicMapReference(ref)); } } Collections.sort(result, REFERENCE_COMPARATOR); return result; } public List<TopicMapSource> getEditableSources() { return getSources(new DeciderIF() { public boolean ok(Object o) { TopicMapSourceIF source = (TopicMapSourceIF)o; return source.supportsCreate() && source.getId() != null; } }); } private List<TopicMapSource> getSources(DeciderIF decider) { Collection<TopicMapSourceIF> sources = getTopicMapRepository().getSources(); List<TopicMapSource> result = new ArrayList<TopicMapSource>(sources.size()); for (TopicMapSourceIF source : sources) { if (decider.ok(source)) result.add(new TopicMapSource(source.getId())); } return result; } /** * INTERNAL: Creates a new Ontopoly topic map, and updates the * system topic map accordingly. * @return The reference id of the new topic map */ public String createOntopolyTopicMap(String sourceId, String name) { TopicMapSourceIF source = getTopicMapRepository().getSourceById(sourceId); TopicMapReferenceIF ref = source.createTopicMap(name, null); TopicMapStoreIF store = null; try { store = ref.createStore(false); TopicMapIF tm = store.getTopicMap(); // import ontopoly ontology TopicMapReferenceIF ontologyTopicMapReference = getTopicMapRepository().getReferenceByKey(ONTOLOGY_TOPIC_MAP_ID); if (ontologyTopicMapReference == null) throw new OntopiaRuntimeException("Could not find ontology topic map '" + ONTOLOGY_TOPIC_MAP_ID + "'"); TopicMapStoreIF ontologyTopicMapStore = ontologyTopicMapReference.createStore(true); try { TopicMapIF ontologyTopicMap = ontologyTopicMapStore.getTopicMap(); MergeUtils.mergeInto(tm, ontologyTopicMap); // do some magic to port old reifier to new topic map TopicIF oldReifier = ontologyTopicMap.getReifier(); TopicIF newReifier = null; if (oldReifier != null) { Collection<TopicIF> sameTopic = IdentityUtils.findSameTopic(tm, oldReifier); if (!sameTopic.isEmpty()) newReifier = sameTopic.iterator().next(); } TopicIF reifier = tm.getReifier(); if (reifier != null && newReifier != null && !reifier.equals(newReifier)) { reifier.merge(newReifier); } else if (reifier == null && newReifier != null) { tm.setReifier(newReifier); reifier = tm.getReifier(); } Collection<TopicIF> scope = Collections.emptySet(); OntopolyModelUtils.setName(null, reifier, name, scope); } finally { ontologyTopicMapStore.close(); } // save topic map with ontology if (ref instanceof XTMTopicMapReference) ((XTMTopicMapReference) ref).save(); store.commit(); } catch (IOException e) { throw new OntopiaRuntimeException(e); } finally { if (store != null) store.close(); } // notify repository and wrap up getTopicMapRepository().refresh(); // make ontopoly topic map registerOntopolyTopicMap(ref.getId(), name); return ref.getId(); } public void deleteTopicMap(String referenceId) { TopicMapRepositoryIF repository = getTopicMapRepository(); TopicMapReferenceIF reference = repository.getReferenceByKey(referenceId); // remove from topic map repository if (reference != null && !reference.isDeleted()) reference.delete(); // make ontopoly topic map unregisterOntopolyTopicMap(reference.getId()); repository.refresh(); } /** * INTERNAL: Turns the topic map into an Ontopoly topic map in the * repository, but does not actually change the topic map itself. */ public void registerOntopolyTopicMap(String referenceId, String name) { if (getTopicMapRepository().getReferenceByKey(referenceId) == null) throw new OntopiaRuntimeException("Can't upgrade non-existent topic map: '" + referenceId + "'"); // create topic for topic map TopicMapIF systemtm = getSystemTopicMap(); TopicIF tmtype = systemtm.getTopicBySubjectIdentifier(PSI.ON_TED_TOPIC_MAP); TopicIF idtype = systemtm.getTopicBySubjectIdentifier(PSI.ON_TOPIC_MAP_ID); TopicMapBuilderIF builder = systemtm.getBuilder(); TopicIF tmtopic = builder.makeTopic(tmtype); builder.makeOccurrence(tmtopic, idtype, referenceId); builder.makeTopicName(tmtopic, name); saveSystemTopicMap(systemtm); } public void unregisterOntopolyTopicMap(String referenceId) { TopicMapIF systemtm = getSystemTopicMap(); QueryProcessorIF processor = QueryUtils.getQueryProcessor(systemtm); QueryMapper<TopicIF> qm = new QueryMapper<TopicIF>(processor); List<TopicIF> topics = qm.queryForList( "using ont for i\"http://psi.ontopia.net/ontology/\" " + "select $T from instance-of($T, ont:ted-topic-map), " + "ont:topic-map-id($T, %ID%)?", Collections.singletonMap("ID", referenceId)); for (TopicIF topic : topics) { topic.remove(); } saveSystemTopicMap(systemtm); } /** * INTERNAL: Saves the system topic map to disk. */ private void saveSystemTopicMap(TopicMapIF systemtm) { try { LocatorIF base = systemtm.getStore().getBaseAddress(); File file = URIUtils.getURIFile(base); FileOutputStream stream = new FileOutputStream(file); new LTMTopicMapWriter(stream).write(systemtm); stream.close(); } catch (IOException e) { throw new OntopiaRuntimeException(e); } } }