nl.tue.gale.um.UMServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for nl.tue.gale.um.UMServiceImpl.java

Source

/*
    
   This file is part of GALE (Generic Adaptation Language and Engine).
    
GALE is free software: you can redistribute it and/or modify it under the 
terms of the GNU Lesser General Public License as published by the Free 
Software Foundation, either version 3 of the License, or (at your option) 
any later version.
    
GALE is distributed in the hope that it will be useful, but WITHOUT ANY 
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 
more details.
    
You should have received a copy of the GNU Lesser General Public License
along with GALE. If not, see <http://www.gnu.org/licenses/>.
    
 */
/**
 * UMServiceImpl.java
 * Last modified: $Date$
 * In revision:   $Revision$
 * Modified by:   $Author$
 *
 * Copyright (c) 2008-2011 Eindhoven University of Technology.
 * All Rights Reserved.
 *
 * This software is proprietary information of the Eindhoven University
 * of Technology. It may be used according to the GNU LGPL license.
 */
package nl.tue.gale.um;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;

import nl.tue.gale.common.GaleUtil;
import nl.tue.gale.common.cache.Cache;
import nl.tue.gale.common.cache.CacheListener;
import nl.tue.gale.common.cache.CacheResolver;
import nl.tue.gale.common.cache.CacheSession;
import nl.tue.gale.common.cache.Caches;
import nl.tue.gale.common.code.Argument;
import nl.tue.gale.common.code.CodeResolver;
import nl.tue.gale.common.code.GELResolver;
import nl.tue.gale.common.code.JavaCodeManager;
import nl.tue.gale.common.parser.ParserException;
import nl.tue.gale.common.uri.URI;
import nl.tue.gale.common.uri.URIs;
import nl.tue.gale.dm.DMCache;
import nl.tue.gale.dm.data.Attribute;
import nl.tue.gale.dm.data.Concept;
import nl.tue.gale.event.AbstractEventListener;
import nl.tue.gale.event.EventCacheResolver;
import nl.tue.gale.event.EventHash;
import nl.tue.gale.um.data.EntityValue;
import nl.tue.gale.um.data.UserEntity;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.google.common.collect.ImmutableList;

public class UMServiceImpl extends AbstractEventListener {
    private UpdaterThread ut = null;
    private Cache<EntityValue> um = Caches.newCache(16384, new UMCacheResolver(), EntityValue.nullValue);
    private DMCache dm = new DMCache(new DMCacheResolver());
    private UMGraph graph = new UMGraph(dm);
    private JavaCodeManager cm = null;
    private CodeResolver cr = null;
    private HibernateDaoSupport dataManager = null;
    private int sleepTime = 30000;

    public HibernateDaoSupport getDataManager() {
        return dataManager;
    }

    public void setDataManager(HibernateDaoSupport datamanager) {
        this.dataManager = datamanager;
    }

    public JavaCodeManager getCodeManager() {
        return cm;
    }

    public void setCodeManager(JavaCodeManager cm) {
        this.cm = cm;
    }

    public CodeResolver getCodeResolver() {
        return cr;
    }

    public void setCodeResolver(CodeResolver cr) {
        this.cr = cr;
        cr.setGel(new UMGELResolver());
    }

    public void setSleepTime(int sleepTime) {
        this.sleepTime = sleepTime;
    }

    protected void init() {
        if (ut != null)
            ut.running = false;
        ut = new UpdaterThread(sleepTime);
        ut.start();
        dm.addListener(new DMCacheListener());
    }

    public void destroy() {
        if (ut != null) {
            ut.running = false;
            ut.interrupt();
        }
    }

    private class DMCacheResolver extends EventCacheResolver<Concept> {
        public DMCacheResolver() {
            super(Concept.class);
        }

        protected List<String> getEvents(URI uri) {
            try {
                return getEventBus().event("getdm", Arrays
                        .asList(new String[] { EventHash.createSingleEvent("uri", uri.toString()).toString() }));
            } catch (Exception e) {
                throw new IllegalArgumentException("unable to retrieve objects from event bus", e);
            }
        }

        protected List<String> putEvents(List<String> events) {
            return new LinkedList<String>();
        }
    }

    private void updateGraph(Collection<Concept> concepts) {
        for (Concept concept : concepts)
            updateGraph(concept);
    }

    private Set<URI> getDependencies(Attribute attr) {
        Set<URI> result = new HashSet<URI>();
        if (attr == null)
            return result;
        String code = attr.getDefaultCode();
        if (code == null || "".equals(code))
            return result;

        int i = 0;
        int j = 0;
        do {
            i = code.indexOf("${", i);
            if (i >= 0) {
                j = code.indexOf("}", i);
                if (j < 0)
                    throw new IllegalArgumentException("wrong default code: " + code);
                Object resolved = null;
                try {
                    resolved = GaleCode.resolve(attr.getConcept(), dm, code.substring(i + 2, j));
                } catch (ParserException e) {
                    throw new IllegalArgumentException("unable to resolve pseudo-code in: " + code, e);
                }
                if (resolved instanceof String)
                    result.add(attr.getConcept().getUri());
                if (resolved instanceof Concept[])
                    for (Concept c : (Concept[]) resolved)
                        result.add(c.getUri());
                if (resolved instanceof Concept)
                    result.add(((Concept) resolved).getUri());
                if (resolved instanceof Attribute)
                    result.add(((Attribute) resolved).getUri());
                if (resolved instanceof Attribute[])
                    for (Attribute a : (Attribute[]) resolved)
                        result.add(a.getUri());
                i = i + 2;
            }
        } while (code.indexOf("${", i) >= 0);

        return result;
    }

    private void updateGraph(Concept concept) {
        synchronized (graph) {
            for (Attribute attr : concept.getVirtualAttributes()) {
                // remove old graph dependencies
                URI uri = attr.getUri();
                for (URI source : graph.getReverseSet(uri))
                    graph.removeLink(source, uri);

                // add new graph dependencies
                for (URI source : getDependencies(attr))
                    graph.addLink(source, uri);
            }
        }
    }

    private class DMCacheListener implements CacheListener<Concept> {
        public void objectAdded(Concept object) {
            updateGraph(object);
        }
    }

    private EntityValue getDefaultEntityValue(URI uri) {
        EntityValue result = new EntityValue();
        result.setUri(uri);
        Concept concept = dm.get(Concept.getConceptURI(uri));
        if (concept == null)
            return result;
        Attribute attr = concept.getAttribute(uri.getFragment());
        if (attr == null)
            return result;
        CacheSession<EntityValue> session = um.openSession();
        session.setBaseUri(uri);
        result.setValue(cm.evaluate(cr, attr.getDefaultCode(), argumentBuilder(session).build()));
        return result;
    }

    private boolean isPersistent(URI uri) {
        Concept concept = dm.get(Concept.getConceptURI(uri));
        if (concept == null)
            return true;
        Attribute attr = concept.getAttribute(uri.getFragment());
        if (attr == null)
            return true;
        return attr.isPersistent();
    }

    private class UMCacheResolver implements CacheResolver<EntityValue> {
        public Map<URI, EntityValue> get(URI uri, Cache<EntityValue> cache) {
            Map<URI, EntityValue> result = new HashMap<URI, EntityValue>();
            EntityValue ev = null;
            if (isPersistent(uri))
                ev = (EntityValue) dataManager.getHibernateTemplate().get(EntityValue.class, uri.toString());
            if (ev == null)
                ev = getDefaultEntityValue(uri);
            if (ev.getValue() == null && "system.elapsed".equals(ev.getUri().getFragment()))
                ev.setValue(0l);
            checkPublic(uri, false);
            result.put(uri, ev);
            return result;
        }

        public Map<URI, EntityValue> put(final Map<URI, EntityValue> map, Cache<EntityValue> cache) {
            for (EntityValue ev : map.values()) {
                checkPublic(ev.getUri(), true);
                updatequeue.add(ev);
            }
            return new HashMap<URI, EntityValue>();
        }
    }

    private Object deProxy(Object o) {
        if (o instanceof org.hibernate.proxy.HibernateProxy)
            return ((org.hibernate.proxy.HibernateProxy) o).getHibernateLazyInitializer().getImplementation();
        else if (o instanceof UserEntity) {
            final UserEntity oue = (UserEntity) o;
            UserEntity ue = new UserEntity();
            ue.setId(oue.getId());
            ue.getProperties().putAll(oue.getProperties());
            return ue;
        } else
            return o;
    }

    private void checkPublic(URI uri, boolean tell) {
        Concept concept = dm.get(Concept.getConceptURI(uri));
        if (concept == null)
            return;
        Attribute attr = concept.getAttribute(uri.getFragment());
        if (attr == null)
            return;
        if (attr.getProperty("public") == null || "".equals(attr.getProperty("public")))
            return;
        boolean authorative = "true".equals(attr.getProperty("authorative"));
        EventHash eh = new EventHash("publicum");
        eh.put("uri", uri.toString());
        eh.put("authorative", (new Boolean(authorative)).toString());
        eh.put("publicUri", attr.getProperty("public"));
        if (attr.getProperty("publicPredicate") != null)
            eh.put("publicPredicate", attr.getProperty("publicPredicate"));
        eh.put("type", attr.getType());
        String range = attr.getProperty("gumf.range");
        if (range != null)
            eh.put("range", range);
        if (!authorative && !tell)
            getEventBus().event("getPublicUM", Arrays.asList(new String[] { eh.toString() }));
        else if (authorative && tell)
            getEventBus().event("setPublicUM", Arrays.asList(new String[] { eh.toString() }));
    }

    @SuppressWarnings("unchecked")
    private List<String> event_queryum(List<String> params) {
        try {
            EventHash eh = new EventHash(params.get(0));
            if (!eh.getName().equals("query"))
                throw new IllegalArgumentException("first argument is not a query");
            final String query = eh.getItems().get(0);
            ut.flush();
            return (List<String>) dataManager.getHibernateTemplate().execute(new HibernateCallback() {
                public Object doInHibernate(Session session) throws HibernateException, SQLException {
                    List<Object> rlist = new LinkedList<Object>();
                    List<Object> qlist = (List<Object>) session.createQuery(query).list();
                    for (Object o : qlist)
                        rlist.add(deProxy(o));
                    try {
                        return Arrays.asList(new String[] { "result:ok", GaleUtil.gson().toJson(rlist) });
                    } catch (Exception e) {
                        return error(e);
                    }
                }
            });
        } catch (Exception e) {
            return error(e);
        }
    }

    private List<String> event_invalidateum(List<String> params) {
        try {
            Set<URI> toRemove = new HashSet<URI>();
            for (String param : params) {
                EventHash eh = new EventHash(param);
                if (!eh.getName().equals("invalidate"))
                    continue;
                Set<URI> noUserInfo = new HashSet<URI>();
                for (String uriString : eh.getItems()) {
                    URI uri = URIs.of(uriString);
                    if (uri.getUserInfo() == null)
                        noUserInfo.add(uri);
                    else
                        toRemove.add(uri);
                }

                if (noUserInfo.size() > 0) {
                    Set<URI> removeSet = new HashSet<URI>();
                    for (URI uri : um.uriSet())
                        if (noUserInfo.contains(removeUserInfo(uri)))
                            removeSet.add(uri);
                    toRemove.addAll(removeSet);
                }
            }
            Set<URI> toRemoveExpand = new HashSet<URI>();
            for (URI uri : toRemove) {
                Set<URI> tempSet = new HashSet<URI>();
                tempSet.add(uri);
                String userInfo = removeUserInfo(tempSet);
                synchronized (graph) {
                    graph.expandSet(tempSet);
                }
                addUserInfo(tempSet, userInfo);
                toRemoveExpand.addAll(tempSet);
            }
            Map<URI, EntityValue> updateMap = new HashMap<URI, EntityValue>();
            for (URI uri : toRemoveExpand)
                updateMap.put(uri, null);
            um.cacheUpdate(updateMap);
            List<String> rparams = new LinkedList<String>();

            // System.out.println("\ntesting invalidateum:\n");
            // for (String param : params)
            // System.out.println(param + ", ");
            // System.out.println("\n->\n" + toRemoveExpand);

            for (URI uri : toRemoveExpand)
                rparams.addAll(EntityValue.toEvent(new EntityValue(uri, null)));
            getEventBus().event("updateum", rparams);
            return Arrays.asList(new String[] { "result:ok" });
        } catch (Exception e) {
            return error(e);
        }
    }

    private List<String> event_updatedm(List<String> params) {
        try {
            CacheSession<Concept> session = dm.openSession();
            Map<URI, Concept> map = Concept.fromEvent(params, dm);
            Set<URI> updateSet = new HashSet<URI>();
            for (Map.Entry<URI, Concept> entry : map.entrySet()) {
                session.put(entry.getKey(), entry.getValue());
                for (Attribute attr : entry.getValue().getAttributes())
                    updateSet.add(attr.getUri());
            }
            ut.flush();
            session.commit();
            for (URI uri : map.keySet())
                dm.get(uri).refresh();
            updateGraph(map.values());
            synchronized (graph) {
                graph.expandSet(updateSet);
            }
            EventHash eh = new EventHash("invalidate");
            for (URI uri : updateSet)
                eh.addItem(uri.toString());
            getEventBus().event("invalidateum", Arrays.asList(new String[] { eh.toString() }));
        } catch (Exception e) {
            return error(e);
        }
        return Arrays.asList(new String[] { "result:ok" });
    }

    private String removeUserInfo(Collection<URI> uriList) {
        String result = null;
        List<URI> resultList = new LinkedList<URI>();
        for (URI uri : uriList) {
            if (uri.getUserInfo() != null)
                result = uri.getUserInfo();
            resultList.add(removeUserInfo(uri));
        }
        uriList.clear();
        uriList.addAll(resultList);
        return result;
    }

    private URI removeUserInfo(URI uri) {
        return Attribute.getAttributeURI(uri);
    }

    private void addUserInfo(Collection<URI> uriList, String userInfo) {
        List<URI> resultList = new LinkedList<URI>();
        for (URI uri : uriList)
            resultList.add(addUserInfo(uri, userInfo));
        uriList.clear();
        uriList.addAll(resultList);
    }

    private URI addUserInfo(URI uri, String userInfo) {
        try {
            return URIs.of(uri.getScheme(), userInfo, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(),
                    uri.getFragment());
        } catch (Exception e) {
            throw new IllegalArgumentException("unable to add user info to uri", e);
        }
    }

    private List<String> event_setum(List<String> params) {
        try {
            ActionQueue queue = ActionQueue.create(dm, um, cm, cr, graph);
            for (EntityValue ev : EntityValue.fromEvent(params, um).values())
                if (ev.getUri().getFragment().equals("system.elapsed"))
                    queue.queue(calcElapsed(ev));
                else
                    queue.queue(ev);
            queue.run();
            List<String> result = new LinkedList<String>();
            for (EntityValue ev : queue.session().getChangeMap().values())
                result.addAll(EntityValue.toEvent(ev));
            queue.session().commit();
            return result;
        } catch (Exception e) {
            return error(e);
        }
    }

    private EntityValue calcElapsed(EntityValue ev) {
        EntityValue result = new EntityValue();
        result.setUri(ev.getUri());
        Long current = (Long) um.get(ev.getUri()).getValue();
        result.setValue(current + (Long) ev.getValue());
        ev.setValue(result.getValue());
        return result;
    }

    private Argument.ListBuilder argumentBuilder(CacheSession<EntityValue> session) {
        return Argument.listBuilder().arg("dm", "nl.tue.gale.dm.DMCache", dm).arg("session",
                "nl.tue.gale.common.cache.CacheSession", session);
    }

    private List<String> event_getum(List<String> params) {
        // TODO: handle multiple uris
        try {
            EventHash eh = new EventHash(params.get(0));
            if (!eh.getName().equals("uri"))
                throw new IllegalArgumentException("first argument is no uri");
            URI uri = URIs.of(eh.getItems().get(0));
            EntityValue ev = um.get(uri);
            List<String> result = new LinkedList<String>();
            result.add("result:ok");
            result.addAll(EntityValue.toEvent(ev));
            return result;
        } catch (Exception e) {
            return error(e);
        }
    }

    private List<String> event_getentity(List<String> params) {
        try {
            EventHash eh = new EventHash(params.get(0));
            if (!eh.getName().equals("uri"))
                throw new IllegalArgumentException("first argument is no uri");
            URI uri = URIs.of(eh.getItems().get(0));
            UserEntity ue = (UserEntity) dataManager.getHibernateTemplate().get(UserEntity.class,
                    UserEntity.getIdFromUri(uri));
            List<String> result = new LinkedList<String>();
            result.add("result:ok");
            result.addAll(UserEntity.toEvent(ue));
            return result;
        } catch (Exception e) {
            return error(e);
        }
    }

    private List<String> event_setentity(final List<String> params) {
        try {
            dataManager.getHibernateTemplate().execute(new HibernateCallback() {
                public Object doInHibernate(Session session) throws HibernateException, SQLException {
                    Map<URI, UserEntity> map = UserEntity.fromEvent(params, null);
                    for (UserEntity ue : map.values()) {
                        UserEntity old = (UserEntity) session.get(UserEntity.class, ue.getId());
                        if (old != null)
                            session.delete(old);
                        session.save(ue);
                    }
                    return null;
                }
            });
        } catch (Exception e) {
            return error(e);
        }
        return Arrays.asList(new String[] { "result:ok" });
    }

    private Queue<EntityValue> updatequeue = new ConcurrentLinkedQueue<EntityValue>();

    private class UpdaterThread extends Thread {
        private final int sleepTime;

        public UpdaterThread(int sleepTime) {
            this.sleepTime = sleepTime;
        }

        private final List<String> updateEvents = new LinkedList<String>();

        public boolean running = true;
        private AtomicBoolean lock = new AtomicBoolean(false);

        public void run() {
            do {
                updateEvents.clear();
                if (!updatequeue.isEmpty())
                    try {
                        dataManager.getHibernateTemplate().execute(new HibernateCallback() {
                            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                                storeValue(session, updateEvents);
                                return null;
                            }
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                if (!updateEvents.isEmpty())
                    getEventBus().event("updateum", updateEvents);
                while (!lock.compareAndSet(false, true)) {
                }
                try {
                    sleep(sleepTime);
                } catch (InterruptedException e) {
                }
                lock.set(false);
            } while (running);
            if (!updatequeue.isEmpty())
                try {
                    dataManager.getHibernateTemplate().execute(new HibernateCallback() {
                        public Object doInHibernate(Session session) throws HibernateException, SQLException {
                            storeValue(session, updateEvents);
                            return null;
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
        }

        public void flush() {
            if (lock.compareAndSet(true, false)) {
                interrupt();
                while (!lock.get()) {
                }
            }
        }
    }

    private void storeValue(Session session, List<String> updateEvents) {
        EntityValue ev;
        Map<URI, EntityValue> todo = new LinkedHashMap<URI, EntityValue>();
        while ((ev = updatequeue.poll()) != null) {
            if (isPersistent(ev.getUri())) {
                EntityValue old = (EntityValue) session.get(EntityValue.class, ev.getUri().toString());
                if (old != null)
                    session.delete(old);
                todo.put(ev.getUri(), ev);
            }
            if (!ev.getUri().getFragment().startsWith("system."))
                updateEvents.addAll(EntityValue.toEvent(ev));
        }
        for (EntityValue value : todo.values())
            session.save(value);
    }

    private class UMGELResolver implements GELResolver {
        @Override
        public void resolveStateChange(List<Argument> oldValues, List<Argument> newValues) {
            @SuppressWarnings("unchecked")
            CacheSession<EntityValue> session = (CacheSession<EntityValue>) getArgument(oldValues,
                    "nl.tue.gale.common.cache.CacheSession").getValue();
            try {
                for (int i = 0; i < oldValues.size(); i++) {
                    if (oldValues.get(i).getName().startsWith("_v_")
                            && !GaleUtil.safeEquals(oldValues.get(i).getValue(), newValues.get(i).getValue()))
                        storeStateChange(session, newValues.get(i));
                }
            } catch (Exception e) {
                throw new IllegalArgumentException("unable to reconcile state change", e);
            }
        }

        private void storeStateChange(CacheSession<EntityValue> session, Argument argument) {
            if (!(argument.getUserData() instanceof Attribute))
                throw new IllegalStateException("the value of a non user-model variable changed");
            Attribute attr = (Attribute) argument.getUserData();
            if (!isPersistent(attr.getUri()))
                throw new IllegalArgumentException(
                        "can only set persistent user model variables: '" + attr.getUri() + "'");
            URI evURI = session.resolve(attr.getUri());
            session.put(evURI, new EntityValue(evURI, argument.getValue()));
        }

        @Override
        public Argument resolveGaleVariable(String name, List<Argument> params) {
            DMCache dm = (DMCache) getArgument(params, "nl.tue.gale.dm.DMCache").getValue();
            @SuppressWarnings("unchecked")
            CacheSession<EntityValue> session = (CacheSession<EntityValue>) getArgument(params,
                    "nl.tue.gale.common.cache.CacheSession").getValue();
            try {
                Object o = GaleCode.resolve(dm.get(Concept.getConceptURI(session.getBaseUri())), dm, name);
                if (o == null)
                    throw new IllegalArgumentException("variable not found: '" + name + "'");
                int max = -1;
                for (Argument arg : params) {
                    if (arg.getName().startsWith("_v_"))
                        max = Math.max(max, Integer.parseInt(arg.getName().substring(3)));
                    if (o.equals(arg.getUserData()))
                        return arg;
                }
                max++;
                Object userData = o;
                if (o instanceof Attribute) {
                    o = getAttributeValue(session, (Attribute) o);
                } else if (o instanceof Attribute[]) {
                    Attribute[] attrArray = (Attribute[]) o;
                    attrArray = Arrays.copyOf(attrArray, attrArray.length);
                    o = new Object[attrArray.length];
                    for (int i = 0; i < attrArray.length; i++)
                        ((Object[]) o)[i] = getAttributeValue(session, attrArray[i]);
                }
                Argument result = Argument.of("_v_" + max, o.getClass().getSimpleName(), o);
                result.setUserData(userData);
                return result;
            } catch (Exception e) {
                throw new IllegalArgumentException("unable to resolve variable '" + name + "'", e);
            }
        }

        private Object getAttributeValue(CacheSession<EntityValue> session, Attribute attr) {
            return session.get(attr.getUri()).getValue();
        }

        private Argument getArgument(List<Argument> arguments, String className) {
            for (Argument arg : arguments)
                if (arg.getType().equals(className))
                    return arg;
            return null;
        }
    }

    private List<String> event_resetum(List<String> params) {
        try {
            EventHash eh = new EventHash(params.get(0));
            if (!eh.getName().equals("user"))
                throw new IllegalArgumentException("first argument is no userId");
            final String userId = eh.getItems().get(0);
            ut.flush();
            boolean all = (params.size() > 1 && (new EventHash(params.get(1)).getName().equals("all")));
            final String qString = "from EntityValue where userId=:userId"
                    + (all ? "" : " and not (attributeUri like '%#comments')");

            // remove from database
            dataManager.getHibernateTemplate().execute(new HibernateCallback() {
                @Override
                public Object doInHibernate(Session session) throws HibernateException, SQLException {
                    @SuppressWarnings("unchecked")
                    List<EntityValue> evs = (List<EntityValue>) session.createQuery(qString)
                            .setString("userId", userId).list();
                    for (EntityValue ev : evs)
                        if (!Concept.getConceptURI(ev.getUri()).toString()
                                .startsWith("gale://gale.tue.nl/personal"))
                            session.delete(ev);
                    return null;
                }
            });

            // invalidate cache
            List<URI> toInvalidate = new LinkedList<URI>();
            for (URI uri : um.uriSet())
                if (userId.equals(uri.getUserInfo()))
                    toInvalidate.add(uri);
            um.invalidate(toInvalidate);

            return ImmutableList.of("result:ok");
        } catch (Exception e) {
            return error(e);
        }
    }

    private List<String> event_ccum(List<String> params) {
        ut.flush();
        synchronized (graph) {
            dm.invalidate();
            um.invalidate();
            graph.invalidate();
        }
        return ImmutableList.of("result:ok");
    }

    protected String getMethods() {
        return "getum;setum;queryum;getentity;setentity;updatedm;invalidateum;resetum;ccum";
    }

    @Override
    public List<String> event(String method, List<String> params) {
        List<String> result = super.event(method, params);
        if (result != null)
            return result;
        try {
            if ("getum".equals(method))
                return event_getum(params);
            if ("setum".equals(method))
                return event_setum(params);
            if ("queryum".equals(method))
                return event_queryum(params);
            if ("getentity".equals(method))
                return event_getentity(params);
            if ("setentity".equals(method))
                return event_setentity(params);
            if ("updatedm".equals(method))
                return event_updatedm(params);
            if ("invalidateum".equals(method))
                return event_invalidateum(params);
            if ("resetum".equals(method))
                return event_resetum(params);
            if ("ccum".equals(method))
                return event_ccum(params);
        } catch (Exception e) {
            return error(e);
        }
        throw new UnsupportedOperationException("'" + method + "' method not supported");
    }
}