fr.gouv.vitam.mdbes.DAip.java Source code

Java tutorial

Introduction

Here is the source code for fr.gouv.vitam.mdbes.DAip.java

Source

/**
 * This file is part of POC MongoDB ElasticSearch Project.
 *
 * Copyright 2009, Frederic Bregier, and individual contributors by the @author
 * tags. See the COPYRIGHT.txt in the distribution for a full listing of
 * individual contributors.
 *
 * All POC MongoDB ElasticSearch Project is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either versionRank 3 of the License, or
 * (at your option) any later versionRank.
 *
 * POC MongoDB ElasticSearch 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 Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with POC MongoDB ElasticSearch . If not, see <http://www.gnu.org/licenses/>.
 */
package fr.gouv.vitam.mdbes;

import static fr.gouv.vitam.mdbes.MongoDbAccess.VitamCollections.Cdaip;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.bson.BSONObject;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoException;

import fr.gouv.vitam.mdbes.MongoDbAccess.VitamLinks;
import fr.gouv.vitam.utils.FileUtil;
import fr.gouv.vitam.utils.UUID;
import fr.gouv.vitam.utils.logging.VitamLogger;
import fr.gouv.vitam.utils.logging.VitamLoggerFactory;

/**
 * DAip object (Data)
 *
 * @author "Frederic Bregier"
 *
 */
public class DAip extends VitamType {
    private static final VitamLogger LOGGER = VitamLoggerFactory.getInstance(DAip.class);

    private static final long serialVersionUID = -2179544540441187504L;

    /**
     * DAIPDEPTHS : { UUID1 : depth2, UUID2 : depth2 }
     */
    public static final String DAIPDEPTHS = "_dds";
    /**
     * DAIPPARENTS : [ UUID1, UUID2 ]
     */
    public static final String DAIPPARENTS = "_dps";
    /**
     * Number of Immediate child (DAip)
     */
    public static final String NBCHILD = "_nb";

    /**
     * Number of Immediate child (DAip)
     */
    public long nb = 0;

    /**
     *
     */
    public DAip() {
        // empty
    }

    /**
     * Update the object to the database
     *
     * @param update
     */
    public void update(final DBObject update) {
        Cdaip.getCollection().update(new BasicDBObject(ID, getId()), update);
    }

    @Override
    protected boolean updated(final MongoDbAccess dbvitam) {
        final DAip vt = (DAip) dbvitam.daips.collection.findOne(getString(ID));
        BasicDBObject update = null;
        if (vt != null) {
            LOGGER.debug("UpdateLinks: {}\n\t{}", this, vt);
            final List<DBObject> list = new ArrayList<>();
            final List<DBObject> listset = new ArrayList<>();
            /*
             * Only parent link, not child link
             * BasicDBObject upd = dbvitam.updateLinks(this, vt, VitamLinks.DAip2DAip, true);
             * if (upd != null) {
             * list.add(upd);
             * }
             */
            BasicDBObject upd = dbvitam.updateLinks(this, vt, VitamLinks.DAip2DAip, false);
            if (upd != null) {
                list.add(upd);
            }
            upd = dbvitam.updateLinks(this, vt, VitamLinks.Domain2DAip, false);
            if (upd != null) {
                list.add(upd);
            }
            upd = dbvitam.updateLink(this, vt, VitamLinks.DAip2PAip, true);
            if (upd != null) {
                listset.add(upd);
            }
            upd = dbvitam.updateLink(this, vt, VitamLinks.DAip2Dua, true);
            if (upd != null) {
                listset.add(upd);
            }
            // DAIPDEPTHS
            @SuppressWarnings("unchecked")
            final HashMap<String, Integer> vtDom = (HashMap<String, Integer>) vt.removeField(DAIPDEPTHS);
            @SuppressWarnings("unchecked")
            HashMap<String, Integer> domainelevels = (HashMap<String, Integer>) get(DAIPDEPTHS);
            if (domainelevels == null) {
                domainelevels = new HashMap<String, Integer>();
            }
            final BasicDBObject vtDomaineLevels = new BasicDBObject();
            if (vtDom != null) {
                // remove all not in current but in vt as already updated, for the others compare vt with current
                for (final String dom : vtDom.keySet()) {
                    final Integer pastval = vtDom.get(dom);
                    final Integer newval = domainelevels.get(dom);
                    if (newval != null) {
                        if (pastval > newval) {
                            vtDomaineLevels.append(dom, newval); // to be remotely updated
                        } else {
                            vtDomaineLevels.append(dom, pastval); // to be remotely updated
                            domainelevels.put(dom, pastval); // update only locally
                        }
                    } else {
                        vtDomaineLevels.append(dom, pastval); // to be remotely updated
                        domainelevels.put(dom, pastval); // update only locally
                    }
                }
                // now add into remote update from current, but only non existing in vt (already done)
                for (final String dom : domainelevels.keySet()) {
                    // remove by default
                    final Integer srcobj = vtDom.get(dom);
                    final Integer obj = domainelevels.get(dom);
                    if (srcobj == null) {
                        vtDomaineLevels.append(dom, obj); // will be updated remotely
                    }
                }
                // Update locally
                append(DAIPDEPTHS, domainelevels);
            }
            if (!vtDomaineLevels.isEmpty()) {
                upd = new BasicDBObject(DAIPDEPTHS, vtDomaineLevels);
                listset.add(upd);
            }
            try {
                update = new BasicDBObject();
                if (!list.isEmpty()) {
                    upd = new BasicDBObject();
                    for (final DBObject dbObject : list) {
                        upd.putAll(dbObject);
                    }
                    update = update.append("$addToSet", upd);
                }
                if (!listset.isEmpty()) {
                    upd = new BasicDBObject();
                    for (final DBObject dbObject : listset) {
                        upd.putAll(dbObject);
                    }
                    update = update.append("$set", upd);
                }
                update = update.append("$inc", new BasicDBObject(NBCHILD, nb));
                nb = 0;
                dbvitam.daips.collection.update(new BasicDBObject(ID, this.get(ID)), update);
            } catch (final MongoException e) {
                LOGGER.error("Exception for " + update, e);
                throw e;
            }
            list.clear();
            listset.clear();
            return true;
        } else {
            // dbvitam.updateLinks(this, null, VitamLinks.DAip2DAip, true);
            dbvitam.updateLinks(this, null, VitamLinks.DAip2DAip, false);
            dbvitam.updateLinks(this, null, VitamLinks.Domain2DAip, false);
            append(NBCHILD, nb);
            nb = 0;
        }
        return false;
    }

    /**
     * Special method to save to file and not to database
     *
     * @param dbvitam
     * @param outputStream
     */
    public void saveToFile(final MongoDbAccess dbvitam, final OutputStream outputStream) {
        putBeforeSave();
        dbvitam.updateLinksToFile(this, VitamLinks.DAip2DAip, false);
        dbvitam.updateLinksToFile(this, VitamLinks.Domain2DAip, false);
        if (containsField(NBCHILD)) {
            final long temp = this.getLong(NBCHILD);
            if (temp > 0) {
                nb += temp;
            }
        }
        append(NBCHILD, nb);
        toFile(outputStream);
    }

    /**
     * Special method to save to file and not to database
     *
     * @param dbvitam
     * @param outputStream
     */
    public void toFile(final OutputStream outputStream) {
        String toprint = toStringDirect() + "\n";
        try {
            outputStream.write(toprint.getBytes(FileUtil.UTF8));
        } catch (final IOException e) {
            LOGGER.error("Cannot save to File", e);
        }
        toprint = null;
    }

    @Override
    public void save(final MongoDbAccess dbvitam) {
        putBeforeSave();
        if (updated(dbvitam)) {
            LOGGER.debug("Updated: {}", this);
            return;
        }
        LOGGER.debug("Save: {}", this);
        updateOrSave(dbvitam.daips);
    }

    /**
     * Used in ingest (get the next dds including itself with depth +1 for all)
     *
     * @return the new domdepth for children
     */
    public Map<String, Integer> getSubDomDepth() {
        final String id = (String) get(ID);
        // must compute depth from parent
        final HashMap<String, Integer> newdepth = new HashMap<>();
        // addAll to temporary HashMap
        @SuppressWarnings("unchecked")
        final HashMap<String, Integer> vtDomaineLevels = (HashMap<String, Integer>) get(DAIPDEPTHS);
        if (vtDomaineLevels != null) {
            for (final java.util.Map.Entry<String, Integer> entry : vtDomaineLevels.entrySet()) {
                newdepth.put(entry.getKey(), entry.getValue() + 1);
            }
        }
        newdepth.put(id, 1);
        return newdepth;
    }

    /**
     *
     * @return the map of dds with depth
     */
    @SuppressWarnings("unchecked")
    public Map<String, Integer> getDomDepth() {
        return (Map<String, Integer>) get(DAIPDEPTHS);
    }

    /**
     * 
     * @return the max depth of this node from existing parents
     */
    public int getMaxDepth() {
        Map<String, Integer> map = getDomDepth();
        int depth = 0;
        for (Iterator<Integer> iterator = map.values().iterator(); iterator.hasNext();) {
            Integer type = (Integer) iterator.next();
            if (depth < type) {
                depth = type;
            }
        }
        return depth + 1;
    }

    /**
     * Add the link N-N between DAip and List of sub DAip
     *
     * @param dbvitam
     * @param daips
     */
    public void addDAip(final MongoDbAccess dbvitam, final List<DAip> daips) {
        DBObject update = null;
        final List<String> ids = new ArrayList<>();
        for (final DAip daip : daips) {
            final DBObject update2 = dbvitam.addLink(this, VitamLinks.DAip2DAip, daip);
            if (update2 != null) {
                ids.add((String) daip.get(ID));
                update = update2;
            }
        }
        if (!ids.isEmpty()) {
            try {
                dbvitam.daips.collection.update(new BasicDBObject(ID, new BasicDBObject("$in", ids)), update, false,
                        true);
            } catch (final MongoException e) {
                LOGGER.error("Exception for " + update, e);
                throw e;
            }
            nb += ids.size();
        }
        ids.clear();
    }

    /**
     * Add the link N-N between current father DAip and one child DAip
     *
     * @param maipChild
     */
    public void addDAipWithNoSave(final DAip maipChild) {
        if (MongoDbAccess.addAsymmetricLinksetNoSave(maipChild, VitamLinks.DAip2DAip.field2to1, this)) {
            nb += 1;
        }
    }

    /**
     *
     * @param dbvitam
     * @return the list of UUID of children (database access)
     */
    public List<String> getChildrenDAipDBRefFromParent(final MongoDbAccess dbvitam) {
        final DBCursor cid = dbvitam.daips.collection.find(
                new BasicDBObject(MongoDbAccess.VitamLinks.DAip2DAip.field2to1, this.get(ID)),
                new BasicDBObject(ID, 1));
        final List<String> ids = new ArrayList<>();
        while (cid.hasNext()) {
            final String mid = (String) cid.next().get(ID);
            ids.add(mid);
        }
        cid.close();
        return ids;
    }

    /**
     *
     * @param remove
     * @return the list of UUID of DAIP parents (immediate)
     */
    @SuppressWarnings("unchecked")
    public List<String> getFathersDAipDBRef(final boolean remove) {
        if (remove) {
            return (List<String>) removeField(VitamLinks.DAip2DAip.field2to1);
        } else {
            return (List<String>) this.get(VitamLinks.DAip2DAip.field2to1);
        }
    }

    /**
     *
     * @param remove
     * @return the list of UUID of DOMAIN parents (immediate)
     */
    @SuppressWarnings("unchecked")
    public List<String> getFathersDomaineDBRef(final boolean remove) {
        if (remove) {
            return (List<String>) removeField(VitamLinks.Domain2DAip.field2to1);
        } else {
            return (List<String>) this.get(VitamLinks.Domain2DAip.field2to1);
        }
    }

    /**
     * Add the link 1- between DAip and DuaRef
     *
     * @param dbvitam
     * @param dua
     */
    public void addDuaRef(final MongoDbAccess dbvitam, final DuaRef dua) {
        dbvitam.addLink(this, VitamLinks.DAip2Dua, dua);
    }

    /**
     * @param remove
     * @return the associated DUA reference
     */
    public String getDuaRefDBRef(final boolean remove) {
        if (remove) {
            return (String) removeField(VitamLinks.DAip2Dua.field1to2);
        } else {
            return (String) this.get(VitamLinks.DAip2Dua.field1to2);
        }
    }

    /**
     * Add the link 1-N between DAip and PAip
     *
     * @param dbvitam
     * @param data
     */
    public void addPAip(final MongoDbAccess dbvitam, final PAip data) {
        final DBObject update = dbvitam.addLink(this, VitamLinks.DAip2PAip, data);
        if (update != null) {
            data.update(dbvitam.paips, update);
        }
    }

    /**
     *
     * @param remove
     * @return the PAIP UUID
     */
    public String getPAipDBRef(final boolean remove) {
        if (remove) {
            return (String) removeField(VitamLinks.DAip2PAip.field1to2);
        } else {
            return (String) this.get(VitamLinks.DAip2PAip.field1to2);
        }
    }

    /**
     * Check if the current DAip has path as immediate parent (either being a DAip or a Domain)
     *
     * @param path
     * @return True if immediate parent, else False (however could be a grand parent)
     */
    public boolean isImmediateParent(final String path) {
        final String lastp = UUID.getLastAsString(path);
        List<String> immediateParents = getFathersDomaineDBRef(false);
        if (immediateParents != null && !immediateParents.isEmpty()) {
            if (immediateParents.contains(lastp)) {
                return true;
            }
        }
        immediateParents = getFathersDAipDBRef(false);
        if (immediateParents != null && !immediateParents.isEmpty()) {
            if (immediateParents.contains(lastp)) {
                return true;
            }
        }
        return false;
    }

    /**
     *
     * @param dbvitam
     * @param path
     * @return the list of valid pathes (protentiialy empty) from this DAip to path, final path not containing neither path,
     *         neither this DAip
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public List<String> getPathesToParent(final MongoDbAccess dbvitam, final String path)
            throws InstantiationException, IllegalAccessException {
        final List<String> pathes = new ArrayList<>();
        if (isImmediateParent(path)) {
            pathes.add("");
            return pathes;
        }
        final String lastp = UUID.getLastAsString(path);
        final List<String> result = new ArrayList<>();
        List<String> subpath = new ArrayList<>();
        subpath.add("");
        getSubPathesToParent(dbvitam, lastp, this, result, subpath);
        subpath.clear();
        subpath = null;
        return result;
    }

    /**
     * Compute all possible path from current to target (being Domaine or DAip)
     *
     * @param dbvitam
     * @param target
     * @param current
     * @param pathResults
     *            final list containing all valid pathes (excluding target and current as implicit first and very last)
     * @param subpathesCurrent
     *            list of intermediary pathes from very first current (not included)
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private static void getSubPathesToParent(final MongoDbAccess dbvitam, final String target, final DAip current,
            final List<String> pathResults, final List<String> subpathesCurrent)
            throws InstantiationException, IllegalAccessException {
        final List<String> immediateParents = current.getFathersDAipDBRef(false);
        List<String> newSubpathes = new ArrayList<>();
        for (final String immediateParent : immediateParents) {
            final DAip parent = DAip.findOne(dbvitam, immediateParent);
            if (parent == null) {
                continue;
            }
            if (parent.isImmediateParent(target)) {
                // End of search for this parent: target/parent/current are directly attached
                for (final String subpath : subpathesCurrent) {
                    pathResults.add(immediateParent + subpath);
                }
            } else if (parent.getDomDepth().containsKey(target)) {
                // Still in path: current becomes immediateParent and subpathesCurrent to new Subpathes
                for (final String subpath : subpathesCurrent) {
                    newSubpathes.add(immediateParent + subpath);
                }
                getSubPathesToParent(dbvitam, target, parent, pathResults, newSubpathes);
                newSubpathes.clear();
            }
            // Else not in the path so ignore this parent
        }
        newSubpathes = null;
    }

    /**
     * Used in loop operation to clean the object
     *
     * @param all
     *            If true, all items are cleaned
     */
    public final void cleanStructure(final boolean all) {
        removeField(VitamLinks.DAip2DAip.field1to2);
        removeField(VitamLinks.DAip2DAip.field2to1);
        removeField(VitamLinks.Domain2DAip.field2to1);
        removeField(VitamLinks.DAip2Dua.field1to2);
        removeField(VitamLinks.DAip2PAip.field1to2);
        removeField("_nb");
        removeField(ID);
        removeField("_refid");
        if (all) {
            removeField(DAIPDEPTHS);
            removeField(NBCHILD);
        }
    }

    /**
     * Should be called only once saved (last time), but for the moment let the object as it is, next should remove not indexable
     * entries
     *
     * @param dbvitam
     * @param indexes
     * @param model
     * @return the number of DAip inserted in ES
     */
    public int addEsIndex(final MongoDbAccess dbvitam, final Map<String, String> indexes, final String model) {
        if (!this.containsField(NBCHILD)) {
            this.append(NBCHILD, nb);
            final int nb = ElasticSearchAccess.addEsIndex(dbvitam, model, indexes, this);
            this.removeField(NBCHILD);
            return nb;
        } else {
            return ElasticSearchAccess.addEsIndex(dbvitam, model, indexes, this);
        }
    }

    /**
     * 
     * @param dbvitam
     * @param model
     * @return True if inserted in ES
     */
    public boolean addEsIndex(final MongoDbAccess dbvitam, final String model) {
        BasicDBObject maip = (BasicDBObject) copy();
        if (!maip.containsField(NBCHILD)) {
            maip.append(NBCHILD, nb);
        }
        return ElasticSearchAccess.addEsIndex(dbvitam, model, maip);
    }

    @Override
    public boolean load(final MongoDbAccess dbvitam) {
        final DAip vt = (DAip) dbvitam.daips.collection.findOne(getString(ID));
        if (vt == null) {
            return false;
        }
        this.putAll((BSONObject) vt);
        getAfterLoad();
        return true;
    }

    /**
     * @param dbvitam
     * @param refid
     * @return the DAip
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static DAip findOne(final MongoDbAccess dbvitam, final String refid)
            throws InstantiationException, IllegalAccessException {
        return (DAip) dbvitam.findOne(Cdaip, refid);
    }

    protected static void addIndexes(final MongoDbAccess dbvitam) {
        dbvitam.daips.collection.createIndex(new BasicDBObject(MongoDbAccess.VitamLinks.Domain2DAip.field2to1, 1));
        // if not set, MAIP and Tree are worst
        // dbvitam.metaaips.collection.createIndex(new BasicDBObject(MongoDbAccess.VitamLinks.DAip2DAip.field1to2, 1));
        dbvitam.daips.collection.createIndex(new BasicDBObject(MongoDbAccess.VitamLinks.DAip2DAip.field2to1, 1));
        dbvitam.daips.collection.createIndex(new BasicDBObject(MongoDbAccess.VitamLinks.DAip2PAip.field1to2, 1));
        dbvitam.daips.collection.createIndex(new BasicDBObject(MongoDbAccess.VitamLinks.DAip2Dua.field1to2, 1));

        // does not improve anything
        dbvitam.daips.collection.createIndex(new BasicDBObject(DAIPDEPTHS, 1));
        // Depth requests are Worst if set
        // dbvitam.metaaips.collection.createIndex(indexDomDepth);
        // dbvitam.metaaips.collection.createIndex(indexDom);

        // Business
        // dbvitam.metaaips.collection.createIndex(new BasicDBObject("name", 1));
    }

}