All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.wikitty.services.WikittyServiceTransaction Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * Wikitty :: api
 * %%
 * Copyright (C) 2009 - 2010 CodeLutin, Benjamin Poussin
 * %%
 * This program 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.
 * 
 * This program 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */
package org.nuiton.wikitty.services;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.config.ApplicationConfig;
import org.nuiton.wikitty.search.Criteria;
import org.nuiton.wikitty.search.FacetTopic;
import org.nuiton.wikitty.search.PagedResult;
import org.nuiton.wikitty.entities.Wikitty;
import org.nuiton.wikitty.entities.WikittyExtension;
import org.nuiton.wikitty.WikittyService;
import org.nuiton.wikitty.WikittyServiceFactory;
import org.nuiton.wikitty.WikittyUtil;
import org.nuiton.wikitty.entities.Element;
import org.nuiton.wikitty.query.WikittyQuery;
import org.nuiton.wikitty.query.WikittyQueryResult;
import org.nuiton.wikitty.query.WikittyQueryResultTreeNode;
import org.nuiton.wikitty.query.conditions.Select;
import org.nuiton.wikitty.search.Search;
import org.nuiton.wikitty.search.TreeNodeResult;

/**
 *
 * @author poussin
 * @version $Revision$
 *
 * Last update: $Date$
 * by : $Author$
 */
public class WikittyServiceTransaction implements WikittyService {

    /** to use log facility, just put in your code: log.info(\"...\"); */
    static private Log log = LogFactory.getLog(WikittyServiceTransaction.class);

    /** Real WikittyService */
    protected WikittyService ws;
    /** WikittyService used to store modified object */
    protected WikittyService tx;

    protected List events;

    /** if autoCommit > 0 all time events numbers element equals to this
     * autoCommit commit is call */
    protected int autoCommit = -1;

    public WikittyServiceTransaction(ApplicationConfig config, WikittyService ws) {
        this.ws = ws;
        // use WikittyService in Memory
        // use configuration to retrive transaction in memory implementation
        // you must used WikittyServiceInMemoryJdbcSolr implementation
        this.tx = WikittyServiceFactory.buildWikittyServiceTransaction(config);
        events = new LinkedList();
    }

    public void setAutoCommit(int autoCommit) {
        this.autoCommit = autoCommit;
    }

    public int getAutoCommit() {
        return autoCommit;
    }

    protected void addEvent(String securityToken, WikittyEvent e) {
        events.add(e);
        if (autoCommit > 0 && events.size() >= autoCommit) {
            commit(securityToken);
        }
    }

    public void commit(String securityToken) {
        ws.replay(securityToken, events, false);
        this.tx.clear(null);
        events.clear();
    }

    public void commit(String securityToken, boolean force) {
        ws.replay(securityToken, events, force);
        this.tx.clear(null);
        events.clear();
    }

    public void rollback(String securityToken) {
        this.tx.clear(null);
        events.clear();
    }
    
    @Override
    public void addWikittyServiceListener(WikittyListener listener, ServiceListenerType type) {
        throw new UnsupportedOperationException(
                "You try to add listener on WikittyServiceTransaction,"
                + "this is an error desgin, you must add WikittyServiceNotifier"
                + "front of your WikittyServiceTransaction.");
    }

    @Override
    public void removeWikittyServiceListener(WikittyListener listener, ServiceListenerType type) {
        throw new UnsupportedOperationException(
                "You try to remove listener on WikittyServiceTransaction,"
                + "this is an error desgin, you must add WikittyServiceNotifier"
                + "front of your WikittyServiceTransaction.");
    }

    @Override
    public String login(String login, String password) {
        return ws.login(login, password);
    }

    /**
     * Question: est un comportement normale, lorsqu'on se delogue depuis une
     * transaction, on est deloguer partout ? je pense que oui
     * @param securityToken
     */
    @Override
    public void logout(String securityToken) {
        ws.logout(securityToken);
    }

    @Override
    public String getToken(String user) {
        return ws.getToken(user);
    }

    @Override
    public WikittyEvent clear(String securityToken) {
        WikittyEvent e = tx.clear(securityToken);
        addEvent(securityToken, e);
        return e;
    }

    @Override
    public boolean canWrite(String securityToken, Wikitty wikitty) {
        // in transaction, we can do all. But not during commit
        return true;
    }

    @Override
    public boolean canDelete(String securityToken, String wikittyId) {
        // in transaction, we can do all. But not during commit
        return true;
    }

    @Override
    public boolean canRead(String securityToken, String wikittyId) {
        boolean result = tx.exists(securityToken, wikittyId);
        if (!result) {
            // on ne l'a pas en local on va voir si on peut le lire en distant
            result = ws.canRead(securityToken, wikittyId);
        }
        return result;
    }

    @Override
    public WikittyEvent replay(
            String securityToken, List events, boolean force) {
        WikittyEvent e = tx.replay(securityToken, events, force);
        events.add(e);
        return e;
    }

    @Override
    public WikittyEvent store(
            String securityToken, Collection wikitties, boolean force) {
        WikittyEvent e = tx.store(securityToken, wikitties, force);
        addEvent(securityToken, e);
        return e;
    }

    @Override
    public List getAllExtensionIds(String securityToken) {
        HashSet tmp = new HashSet();
        
        tmp.addAll(tx.getAllExtensionIds(securityToken));
        tmp.addAll(ws.getAllExtensionIds(securityToken));
        
        List result = new ArrayList(tmp);
        return result;
    }

    @Override
    public List getAllExtensionsRequires(String securityToken, String extensionName) {
        HashSet tmp = new HashSet();

        tmp.addAll(tx.getAllExtensionsRequires(securityToken, extensionName));
        tmp.addAll(ws.getAllExtensionsRequires(securityToken, extensionName));

        List result = new ArrayList(tmp);
        return result;
    }

    @Override
    public WikittyEvent storeExtension(
            String securityToken, Collection exts) {
        WikittyEvent e = tx.storeExtension(securityToken, exts);
        addEvent(securityToken, e);
        return e;
    }

    @Override
    public WikittyEvent deleteExtension(
            String securityToken, Collection extNames) {
        WikittyEvent e = tx.deleteExtension(securityToken, extNames);
        addEvent(securityToken, e);
        return e;
    }

    @Override
    public WikittyExtension restoreExtension(
            String securityToken, String extensionId) {
        WikittyExtension result = tx.restoreExtension(securityToken, extensionId);
        if (result == null) {
            result = ws.restoreExtension(securityToken, extensionId);
        }
        return result;
    }

    @Override
    public WikittyExtension restoreExtensionLastVersion(
            String securityToken, String name) {
        WikittyExtension result =
                tx.restoreExtensionLastVersion(securityToken, name);
        if (result == null) {
            result = ws.restoreExtensionLastVersion(securityToken, name);
        }
        return result;
    }

    @Override
    public List restoreExtensionAndDependenciesLastVesion(String securityToken, Collection extensionNames) {
        List result = new ArrayList();

        for (String extName : extensionNames) {
            WikittyExtension ext = restoreExtensionLastVersion(
                    securityToken, extName);
            if (ext != null) {
                // on recherche les dependances de cette extension ...
                List requires = ext.getRequires();
                if (CollectionUtils.isNotEmpty(requires)) {
                    List dependencies =
                            restoreExtensionAndDependenciesLastVesion(
                            securityToken, requires);
                    // ... et on les ajoute avant dans le resultat
                    result .addAll(dependencies);
                }
                result.add(ext);
            }
        }
        return result;
    }

    @Override
    public List restore(String securityToken, List ids) {
        List resultWS = ws.restore(securityToken, ids);
        List resultTx = tx.restore(securityToken, ids);
        Wikitty[] result = resultWS.toArray(new Wikitty[resultWS.size()]);
        int i = 0;
        for (Wikitty w : resultTx) {
            String id = ids.get(i);
            // il faut prendre en compte que l'objet a pu etre supprime dans la
            // transaction donc meme s'il est null dans tx et pas dans ws, il
            // faut le mettre a null
            // si w n'a pas ete restore (null), mais qu'il exist, alors cela
            // veut dire qu'il est supprime.
            if (w != null || tx.exists(securityToken, id)) {
                // on remplace tout par les nouveaux de la transaction
                result[i] = w;
            }
            i++;
        }
        return Arrays.asList(result);
    }

    @Override
    public WikittyEvent delete(String securityToken, Collection ids) {
        // pour que tout fonctionne bien, il faut que les objets supprimer soit
        // dans la tx, car il faut avoir une vrai trace de cette suppression dans la tx
        List wikitties = ws.restore(securityToken, new ArrayList(ids));
        tx.store(securityToken, wikitties, true);

        WikittyEvent e = tx.delete(securityToken, ids);
        addEvent(securityToken, e);
        return e;
    }

    @Override
    public List> findAllByCriteria(
            String securityToken, List criteria) {
        List> resultTxList =
                tx.findAllByCriteria(securityToken, criteria);
        List> resultWsList =
                ws.findAllByCriteria(securityToken, criteria);

        List> result =
                new ArrayList>(resultWsList.size());
        for (int i=0; i resultTx = resultTxList.get(i);
            PagedResult resultWs = resultWsList.get(i);
            // Il faut fusionner les deux resultats
            // - ne pas avoir de doublon
            // - ne pas retenir ceux supprimer dans la transaction
            // - fusionner les facettes (comment faire ?)
            // - respecter le range demander (comment faire, avec les suppressions possible ?)
            LinkedHashSet ids =
                    new LinkedHashSet(resultTx.size() + resultWs.size());
            ids.addAll(resultTx.getAll());
            for (String id : resultWs.getAll()) {
                if (!tx.exists(securityToken, id) || !tx.isDeleted(securityToken, id)) {
                    ids.add(id);
                }
            }

            String criteriaName = resultWs.getCriteriaName();
            int firstIndice = resultWs.getFirstIndice();
            // FIXME le resultat est faux, le nombre total n'est pas la somme des deux :(
            int numFound = resultTx.getNumFound() + resultWs.getNumFound();
            String queryString = resultWs.getQueryString();
            // FIXME les facettes sont fausses :(
            Map> facets = resultWs.getFacets();
            List results = new ArrayList(ids);

             result.add(new PagedResult(criteriaName,
                    firstIndice, numFound, queryString, facets, results));
        }

        if (criteria.size() != result.size()) {
            log.error(String.format("Criteria input list (%s) has not same size that result list (%s)",
                    criteria.size(), result.size()));
        }

        return result;
    }

    @Override
    public List findByCriteria(String securityToken, List criteria) {
        List result = new ArrayList(criteria.size());
        List criteriaLimit = new ArrayList(criteria.size());
        for (Criteria c : criteria) {
            Criteria climit = Search.query(c).criteria().setFirstIndex(0).setEndIndex(1);
            criteriaLimit.add(climit);
        }

        List> idsList = findAllByCriteria(
                securityToken, criteriaLimit);

        for (PagedResult ids : idsList) {
            if (ids.size() > 0) {
                result.add(ids.getFirst());
            } else {
                result.add(null);
            }
        }

        if (criteria.size() != result.size()) {
            log.error(String.format("Criteria input list (%s) has not same size that result list (%s)",
                    criteria.size(), result.size()));
        }

        return result;
    }

    @Override
    public TreeNodeResult findTreeNode(String securityToken,
            String wikittyId, int depth, boolean count, Criteria filter) {
        // FIXME
        throw new UnsupportedOperationException("Not supported yet.");
    }

    // FIXME poussin 20130218 a revoir car les order by, les facets, limit et offset ne sont pas respecte :(
    @Override
    public List>> findAllByQuery(
            String securityToken, List queries) {

        // on recree une liste avec seulement les clause where
        List queriesWhere = new ArrayList();
        for (WikittyQuery q : queries) {
            if (q.isSelectQuery()) {
                queriesWhere.add(q.getWhereQuery());
            } else {
                queriesWhere.add(q);
            }
        }

        // on ne joue que les clauses where car le select sera rejouer completement
        List>> resultTxList =
                tx.findAllByQuery(securityToken, queriesWhere);
        List>> resultWsList =
                ws.findAllByQuery(securityToken, queriesWhere);

        List>> result =
                new ArrayList>>(queries.size());
        for (int i=0; i> resultTx = resultTxList.get(i);
            WikittyQueryResult> resultWs = resultWsList.get(i);

            //
            // Il faut fusionner les deux resultats
            //

            // - ne pas avoir de doublon
            // - ne pas retenir ceux supprimer dans la transaction
            //   en respectant l'ordre de tri demande (comment faire?)
            // - fusionner les facettes (comment faire ?)
            // - respecter le range demander (comment faire, avec les suppressions possible ?)
            LinkedHashSet ids =
                    new LinkedHashSet(resultTx.getWikittyResultSize() + resultWs.getWikittyResultSize());
            ids.addAll(resultTx.getWikittyResult().getAll());
            for (String id : resultWs.getWikittyResult().getAll()) {
                if ((!tx.exists(securityToken, id) || !tx.isDeleted(securityToken, id))) {
                    ids.add(id);
                } else {
                    // pas un id, donc on ne sais pas encore comment faire :(. On l'ajoute
                    ids.add(id);
                }
            }
            List wikittyId = new ArrayList(ids);

            //
            // il faut calculer le select
            //
            List> selectFusion = null;
            if (query.isSelectQuery()) {
                List> values = new ArrayList>(wikittyId.size());
                // recuperation des wikitties pour pouvoir jouer le select
                List wikitties = restore(securityToken, wikittyId);
                // transformation des wikitties en Map avec l'id dans la map
                String idKey = Element.ID.getValue();
                for (Wikitty w : wikitties) {
                    Map map = new LinkedHashMap(w.getFieldValue());
                    map.put(idKey, w.getWikittyId());
                    values.add(map);
                }

                // rejoue du select
                Select select = (Select)query.getCondition();
                selectFusion = select.getFunction().call(query, values);
            }

            //
            // il faut assigner le resultat principal (select ou wikittyId)
            //
            List> results;
            if (query.isSelectQuery()) {
                // on met selectFusion dans result
                results = selectFusion;
            } else {
                // on met les ids dans results
                results = new ArrayList>(ids.size());
                String idKey = Element.ID.getValue();
                for (String id : ids) {
                    results.add(WikittyUtil.singletonMap(idKey, id));
                }
            }

            String queryName = resultWs.getQueryName();
            int firstIndice = resultWs.getOffset();
            // FIXME le resultat est faux, le nombre total n'est pas la somme des deux :(
            int numFound = resultTx.getTotalResult() + resultWs.getTotalResult();
            String queryString = resultWs.getQueryString();
            // FIXME les facettes sont fausses :(
            Map> facets = resultWs.getFacets();

            long timeEnd = System.currentTimeMillis();
            long timeQuery = resultTx.getTimeQuery() + resultWs.getTimeQuery() + timeEnd - timeStart;

             result.add(new WikittyQueryResult>(
                     queryName, firstIndice, numFound, query, queryString,
                     results, selectFusion, wikittyId, facets,
                     timeQuery, 0));
        }

        if (queries.size() != result.size()) {
            log.error(String.format("Queries input list (%s) has not same size that result list (%s)",
                    queries.size(), result.size()));
        }

        return result;
    }

    @Override
    public List> findByQuery(String securityToken, List queries) {
        List> result = new ArrayList>(queries.size());
        List queriesLimited = new ArrayList(queries.size());
        for (WikittyQuery c : queries) {
            WikittyQuery climit = c.copy().setOffset(0).setLimit(1);
            queriesLimited.add(climit);
        }

        List>> idsList = findAllByQuery(
                securityToken, queriesLimited);

        for (WikittyQueryResult> ids : idsList) {
            if (ids.size() > 0) {
                result.add(ids.peek());
            } else {
                result.add(null);
            }
        }

        if (queries.size() != result.size()) {
            log.error(String.format("Query input list (%s) has not same size that result list (%s)",
                    queries.size(), result.size()));
        }

        return result;
    }

    @Override
    public WikittyQueryResultTreeNode findTreeNode(String securityToken,
            String wikittyId, int depth, boolean count, WikittyQuery filter) {
        // FIXME
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public WikittyEvent deleteTree(String securityToken, String treeNodeId) {
        // FIXME
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Wikitty restoreVersion(String securityToken, String wikittyId, String version) {
        // FIXME
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void syncSearchEngine(String securityToken) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean exists(String securityToken, String wikittyId) {
        boolean result = tx.exists(securityToken, wikittyId);
        if (!result) {
            if (!tx.isDeleted(securityToken, wikittyId)) {
                result = ws.exists(securityToken, wikittyId);
            }
        }
        return result;
    }

    @Override
    public boolean isDeleted(String securityToken, String wikittyId) {
        boolean result = tx.isDeleted(securityToken, wikittyId);
        // pas efface, peut-etre qu'il existe
        if (!result && !tx.exists(securityToken, wikittyId)) {
            // il n'est pas efface et il n'existe pas dans la tx,
            // on recherche dans ws
            result = ws.isDeleted(securityToken, wikittyId);
        }
        return result;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy