/* * #! * Ontopia Webed * #- * 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.webed.impl.actions.tmobject; import java.io.StringReader; import java.util.AbstractMap; import java.util.Collection; import java.util.Collections; 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.topicmaps.webed.core.ActionIF; import net.ontopia.topicmaps.webed.core.ActionParametersIF; import net.ontopia.topicmaps.webed.core.ActionResponseIF; import net.ontopia.topicmaps.webed.core.ActionRuntimeException; import net.ontopia.topicmaps.webed.core.WebEdRequestIF; import net.ontopia.topicmaps.webed.impl.basic.Constants; import net.ontopia.topicmaps.webed.impl.utils.ActionSignature; import net.ontopia.utils.OntopiaRuntimeException; import net.ontopia.utils.StringTemplateUtils; import net.ontopia.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * PUBLIC: Action for adding information to a topic map by evaluating * an LTM fragment. * * @since 2.0 */ public class EvaluateLTM implements ActionIF { // initialization of logging facility private static Logger log = LoggerFactory.getLogger(EvaluateLTM.class.getName()); public void perform(ActionParametersIF params, ActionResponseIF response) { // test params ActionSignature paramsType = ActionSignature.getSignature("m! s!"); paramsType.validateArguments(params, this); TopicMapIF topicmap = (TopicMapIF) params.get(0); String template = (String) params.get(1); WebEdRequestIF request = params.getRequest(); Collection values = null; TMObjectIF object = params.getTMObjectValue(); if (object == null) { String strval = params.getStringValue(); if (strval != null) { // escape quotes so LTM will parse correctly String value = StringUtils.replace(strval, '"', "\"\""); values = Collections.singleton(value); } } else values = params.getTMObjectValues(); String lastid = null; if (values == null) // no object value; just do it anyway importFragment(template, topicmap); else { // repeat once for each object value Iterator it = values.iterator(); while (it.hasNext()) { lastid = makeRandomId(topicmap); Map map = new RequestMapWrapper(request, it.next(), lastid, topicmap); String tmp = StringTemplateUtils.replace(template, map); importFragment(tmp, topicmap); } } // register new topic in response TopicIF topic = getTopicById(topicmap, lastid); if (lastid != null && topic != null) response.addParameter(Constants.RP_TOPIC_ID, topic.getObjectId()); } // --- Internal methods private void importFragment(String fragment, TopicMapIF topicmap) { log.debug("Importing fragment " + fragment); LocatorIF base = topicmap.getStore().getBaseAddress(); LTMTopicMapReader reader = new LTMTopicMapReader(new StringReader(fragment), base); try { reader.importInto(topicmap); } catch (java.io.IOException e) { log.error("Syntax error in LTM fragment", e); throw new ActionRuntimeException(e); } } 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; } private String getId(TMObjectIF object) { Iterator it = object.getItemIdentifiers().iterator(); if (it.hasNext()) { LocatorIF loc = (LocatorIF) 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; } protected TopicIF getTopicById(TopicMapIF topicmap, String id) { LocatorIF base = topicmap.getStore().getBaseAddress(); return (TopicIF) topicmap.getObjectByItemIdentifier(base.resolveAbsolute("#" + id)); } // --- Wrapper class for request class RequestMapWrapper extends AbstractMap { private WebEdRequestIF request; private Object value; private String randid; private TopicMapIF topicmap; private Map newkeys; public RequestMapWrapper(WebEdRequestIF request, Object value, String randid, TopicMapIF topicmap) { this.request = request; this.value = value; this.randid = randid; this.topicmap = topicmap; this.newkeys = new HashMap(); } public boolean containsKey(Object key) { return get(key) != null; } public Object get(Object keyy) { String key = (String) keyy; Object o = null; if (key.equals("value") || key.equals("topic")) o = value; else if (key.equals("new")) o = randid; // keys of form newXXX where XXX is an integer else if (key.startsWith("new") && StringUtils.isInteger(key.substring(3))) { if (newkeys.containsKey(key)) o = newkeys.get(key); else { o = makeRandomId(topicmap); newkeys.put(key, o); } } else { ActionParametersIF params = request.getActionParameters((String) key); if (params == null) throw new OntopiaRuntimeException("Reference in LTM template to undefined action: '" + key + "'"); o = params.getTMObjectValue(); if (o == null) o = params.getStringValue(); } if (o instanceof TMObjectIF) o = getId((TMObjectIF) o); log.debug("RMW.get('" + key + "') -> " + o); return o; } public int size() { return 3; // a smallish number, that's all } public Set entrySet() { throw new net.ontopia.utils.OntopiaRuntimeException("INTERNAL ERROR"); } } }