/* * #! * Ontopia Engine * #- * 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 net.ontopia.topicmaps.utils.ctm; import java.util.Set; import java.util.Map; import java.util.HashMap; import java.util.Iterator; import java.net.MalformedURLException; import net.ontopia.utils.CompactHashSet; import net.ontopia.utils.OntopiaRuntimeException; import net.ontopia.infoset.core.LocatorIF; import net.ontopia.infoset.impl.basic.URILocator; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.core.TopicMapIF; import net.ontopia.topicmaps.core.TopicMapBuilderIF; import net.ontopia.topicmaps.xml.InvalidTopicMapException; public class GlobalParseContext implements ParseContextIF { private LocatorIF base; private TopicMapIF topicmap; private TopicMapBuilderIF builder; private Map<String, LocatorIF> prefixes; private Map<String, Template> templates; // String = name + paramcount private Set<LocatorIF> include_uris; // extra base URIs passed in from // include masters private int counter; // for anonymous topics public GlobalParseContext(TopicMapIF topicmap, LocatorIF base) { this.topicmap = topicmap; this.base = base; this.builder = topicmap.getBuilder(); this.prefixes = new HashMap<String, LocatorIF>(); this.templates = new HashMap<String, Template>(); this.counter = 0; this.include_uris = new CompactHashSet<LocatorIF>(); } public void addPrefix(String prefix, LocatorIF locator) { LocatorIF boundto = prefixes.get(prefix); if (boundto != null && !boundto.equals(locator)) throw new InvalidTopicMapException("Attempted to bind prefix " + prefix + " to " + locator.getAddress() + ", but "+ "it's already bound to " + boundto.getAddress()); prefixes.put(prefix, locator); } public void addIncludeUri(LocatorIF uri) { include_uris.add(uri); } public Set<LocatorIF> getIncludeUris() { return include_uris; } public LocatorIF resolveQname(String qname) { int ix = qname.indexOf(':'); String prefix = qname.substring(0, ix); String local = qname.substring(ix+1); LocatorIF boundto = prefixes.get(prefix); if (boundto == null) throw new InvalidTopicMapException("Cannot resolve qname " + qname + ", " + "prefix not bound"); try { return new URILocator(boundto.getAddress() + local); } catch (MalformedURLException e) { throw new OntopiaRuntimeException(e); } } public ValueGeneratorIF getTopicById(String id) { if (base == null) // when no base locator only absolute URIs are allowed // see https://github.com/ontopia/ontopia/issues/182 throw new InvalidTopicMapException("Cannot resolve id '" + id + "' when no base locator"); LocatorIF itemid = base.resolveAbsolute('#' + id); return new TopicByItemIdentifierGenerator(this, itemid, id); } public ValueGeneratorIF getTopicByItemIdentifier(LocatorIF itemid) { return new TopicByItemIdentifierGenerator(this, itemid); } public ValueGeneratorIF getTopicBySubjectLocator(LocatorIF subjloc) { return new TopicBySubjectLocatorGenerator(this, subjloc); } public ValueGeneratorIF getTopicBySubjectIdentifier(LocatorIF subjid) { return new TopicBySubjectIdentifierGenerator(this, subjid); } public ValueGeneratorIF getTopicByQname(String qname) { return new TopicBySubjectIdentifierGenerator(this, resolveQname(qname)); } public TopicIF makeAnonymousTopic() { counter++; LocatorIF itemid = base.resolveAbsolute("#$__" + counter); return makeTopicByItemIdentifier(itemid); } public TopicIF makeAnonymousTopic(String wildcard_name) { counter++; LocatorIF itemid = base.resolveAbsolute("#$__" + counter + '.' + wildcard_name); return makeTopicByItemIdentifier(itemid); } public void registerTemplate(String name, Template template) { String key = name + template.getParameterCount(); if (templates.containsKey(key)) throw new InvalidTopicMapException("Template " + name + " already defined" + " with " + template.getParameterCount() + " parameters"); templates.put(key, template); } public Template getTemplate(String name, int paramcount) { return templates.get(name + paramcount); } public Map getTemplates() { return templates; } public TopicIF makeTopicById(String id) { return makeTopicByItemIdentifier(base.resolveAbsolute('#' + id)); } public TopicIF makeTopicByItemIdentifier(LocatorIF itemid) { TopicIF topic = (TopicIF) topicmap.getObjectByItemIdentifier(itemid); if (topic == null) { topic = builder.makeTopic(); topic.addItemIdentifier(itemid); } return topic; } public TopicIF makeTopicBySubjectLocator(LocatorIF subjloc) { TopicIF topic = topicmap.getTopicBySubjectLocator(subjloc); if (topic == null) { topic = builder.makeTopic(); topic.addSubjectLocator(subjloc); } return topic; } public TopicIF makeTopicBySubjectIdentifier(LocatorIF subjid) { TopicIF topic = topicmap.getTopicBySubjectIdentifier(subjid); if (topic == null) { topic = builder.makeTopic(); topic.addSubjectIdentifier(subjid); } return topic; } // --- Internal generator classes static abstract class InternalTopicGenerator extends AbstractTopicGenerator { protected ParseContextIF context; protected LocatorIF locator; public InternalTopicGenerator(ParseContextIF context, LocatorIF locator) { this.context = context; this.locator = locator; } public ValueGeneratorIF copy() { return this; // FIXME: this is safe as long as we keep making new generators } public String getLiteral() { throw new InvalidTopicMapException("Topic reference passed, but literal "+ "expected: " + getDescription()); } public LocatorIF getDatatype() { throw new InvalidTopicMapException("Topic reference passed, but literal "+ "expected: " + getDescription()); } public LocatorIF getLocator() { throw new InvalidTopicMapException("Topic reference passed, but locator "+ "expected: " + getDescription()); } protected abstract String getDescription(); } static class TopicByItemIdentifierGenerator extends InternalTopicGenerator { private String id; public TopicByItemIdentifierGenerator(ParseContextIF context, LocatorIF locator) { super(context, locator); } public TopicByItemIdentifierGenerator(ParseContextIF context, LocatorIF locator, String id) { super(context, locator); this.id = id; } public TopicIF getTopic() { TopicIF topic = context.makeTopicByItemIdentifier(locator); if (id != null && !context.getIncludeUris().isEmpty()) { Iterator it = context.getIncludeUris().iterator(); while (it.hasNext()) { LocatorIF loc = (LocatorIF) it.next(); topic.addItemIdentifier(loc.resolveAbsolute('#' + id)); } } return topic; } protected String getDescription() { if (id != null) return "item identifier #" + id; else return "item identifier " + locator.getExternalForm(); } } static class TopicBySubjectIdentifierGenerator extends InternalTopicGenerator { public TopicBySubjectIdentifierGenerator(ParseContextIF context, LocatorIF locator) { super(context, locator); } public TopicIF getTopic() { return context.makeTopicBySubjectIdentifier(locator); } protected String getDescription() { return "subject identifier " + locator.getExternalForm(); } } static class TopicBySubjectLocatorGenerator extends InternalTopicGenerator { public TopicBySubjectLocatorGenerator(ParseContextIF context, LocatorIF locator) { super(context, locator); } public TopicIF getTopic() { return context.makeTopicBySubjectLocator(locator); } protected String getDescription() { return "subject locator " + locator.getExternalForm(); } } }