/* * #! * 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.ltm; import java.io.IOException; import java.io.StringReader; import java.util.AbstractMap; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import net.ontopia.infoset.core.LocatorIF; import net.ontopia.topicmaps.core.TMObjectIF; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.core.TopicMapIF; import net.ontopia.topicmaps.utils.ltm.LTMTopicMapReader; import net.ontopia.utils.OntopiaRuntimeException; import net.ontopia.utils.StringTemplateUtils; import net.ontopia.utils.StringUtils; /** * PUBLIC: Imports an LTM fragment with references to parameter values * specified externally. * * @since 3.2.4 */ public class LTMTemplateImporter { /** * PUBLIC: Imports an LTM fragment with references to parameter values * specified externally. * @param topicmap The topic map to import the LTM into. * @param ltm The LTM fragment. * @param parameters The %foo% parameters referenced from the LTM. * @return A Map containing references to the %new% topics created. */ public static Map<String, TopicIF> read(TopicMapIF topicmap, String ltm, Map<String, Object> parameters) throws IOException { // wrap parameters with translation/quoting/ID-creating map ParameterWrapper parawrapper = new ParameterWrapper(parameters, topicmap); // produce the full LTM using the wrapper and parameters String tmp = StringTemplateUtils.replace(ltm, parawrapper); // then do the actual import LocatorIF base = topicmap.getStore().getBaseAddress(); LTMTopicMapReader reader = new LTMTopicMapReader(new StringReader(tmp), base); reader.importInto(topicmap); // turn ID map into topic map Map<String, String> newids = parawrapper.getNewIds(); Map<String, TopicIF> newtopics = new HashMap<String, TopicIF>(newids.size()); Iterator<String> it = newids.keySet().iterator(); while (it.hasNext()) { String key = it.next(); String id = newids.get(key); newtopics.put(key, (TopicIF) topicmap.getObjectByItemIdentifier(base.resolveAbsolute("#" + id))); } return newtopics; } // ===== INTERNAL ================================================== /** * This class converts parameter values into strings which can * actually be safely inserted into the LTM, and also implements the * %new% and %newX% references. */ static class ParameterWrapper extends AbstractMap<String, Object> { private Map<String, Object> wrapped; private Map<String, String> newids; // new35 -> ID of new35 private TopicMapIF topicmap; public ParameterWrapper(Map<String, Object> wrapped, TopicMapIF topicmap) { this.wrapped = wrapped; this.newids = new HashMap<String, String>(); this.topicmap = topicmap; } public Map<String, String> getNewIds() { return newids; } public Object get(String key) { if (key.startsWith("new")) { // reference to a new topic String id = newids.get(key); if (id == null) { id = makeRandomId(topicmap); newids.put(key, id); } return id; } else { // reference to a parameter value Object value = wrapped.get(key); if (value == null) throw new OntopiaRuntimeException("No LTM parameter '" + key + "'"); if (value instanceof String) { // we need to escape the string so it'll fit nicely into the LTM return StringUtils.replace((String) value, '"', "\"\""); } else if (value instanceof TopicIF) { // we need to turn this into a topic reference TopicIF topic = (TopicIF) value; return getId(topic); } else throw new OntopiaRuntimeException("Bad LTM parameter value: " + value); } } public boolean containsKey(String key) { return get(key) != null; } public int size() { return 3; // a smallish number, that's all } public Set<Map.Entry<String, Object>> entrySet() { throw new net.ontopia.utils.OntopiaRuntimeException("INTERNAL ERROR"); } // internal stuff private String getId(TMObjectIF object) { Iterator<LocatorIF> it = object.getItemIdentifiers().iterator(); if (it.hasNext()) { // FIXME: this doesn't check the base address! LocatorIF loc = it.next(); String address = loc.getAddress(); int pos = address.indexOf("#"); if (pos != -1) return address.substring(pos + 1); } // for the case where the object has no source locator at all, or // it doesn't contain '#' TopicMapIF topicmap = object.getTopicMap(); String id = makeRandomId(topicmap); LocatorIF base = topicmap.getStore().getBaseAddress(); object.addItemIdentifier(base.resolveAbsolute("#" + id)); return id; } private String makeRandomId(TopicMapIF topicmap) { String id; TMObjectIF tmobj; LocatorIF base = topicmap.getStore().getBaseAddress(); do { id = StringUtils.makeRandomId(10); tmobj = topicmap.getObjectByItemIdentifier(base.resolveAbsolute("#" + id)); } while (tmobj != null); return id; } } }