org.mycore.datamodel.common.MCRMarkManager Maven / Gradle / Ivy
/*
* This file is part of *** M y C o R e ***
* See http://www.mycore.de/ for details.
*
* MyCoRe 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 version 3 of the License, or
* (at your option) any later version.
*
* MyCoRe 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 MyCoRe. If not, see .
*/
package org.mycore.datamodel.common;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.mycore.common.events.MCREventHandler;
import org.mycore.datamodel.metadata.MCRBase;
import org.mycore.datamodel.metadata.MCRDerivate;
import org.mycore.datamodel.metadata.MCRObjectID;
/**
* Experimental class to improve performance on delete and import operations.
* You can mark object's as "will be deleted" or "will be imported". You can
* use this information on {@link MCREventHandler}'s to exclude those
* marked objects from operations which makes no sense.
*
*
* Current delete behavior:
*
*
* - An user delete's a parent object with 500 children.
* - MyCoRe tries to delete the parent, but first, it has to delete all children.
* - MyCoRe runs through each child and deletes it.
* - BUT after the deletion of ONE child, the parent object will be updated.
* - This results in updating the parent 500 times, before its actually deleted.
*
*
*
* What this class tries to solve:
* We mark the parent as "will be deleted". When a child is deleted, and the EventHandler tries
* to removed the child from its parent, the parent will not be updated because its "marked as
* deleted".
*
*
*
* Current import behavior:
*
*
*
* - An import is started with a bunch of hierarchic objects.
* - MyCoRe imports all the objects and does a "create" update.
* - BUT for each object created the parent is updated again (because a child was added)!
* - This results in unnecessary updates.
*
*
*
* What this class tries to solve:
* We mark all objects as "will be imported". On import, we ignore all solr index call for
* those objects. After the import, we delete all marks and do an solr import for all
* objects at once.
*
*
* TODO: check side effects
*
* @author Matthias Eichner
*/
public class MCRMarkManager {
private static MCRMarkManager INSTANCE = null;
public enum Operation {
DELETE, IMPORT
}
private Map marks;
private MCRMarkManager() {
this.marks = new ConcurrentHashMap<>();
}
/**
* Returns the instance to the singleton {@link MCRMarkManager}.
*
* @return instance of {@link MCRMarkManager}
*/
public static MCRMarkManager instance() {
if (INSTANCE == null) {
// make it thread safe
synchronized (MCRMarkManager.class) {
if (INSTANCE == null) {
INSTANCE = new MCRMarkManager();
}
}
}
return INSTANCE;
}
/**
* Marks a single object with the given operation.
*
* @param mcrId the mycore object identifier
* @param operation the operation
* @return the previous Operation associated with the mycore identifier or null
*/
public Operation mark(MCRObjectID mcrId, Operation operation) {
return this.marks.put(mcrId, operation);
}
/**
* Removes the current mark for the given mycore identifier.
*
* @param mcrId the object where the mark should be removed
*/
public void remove(MCRObjectID mcrId) {
this.marks.remove(mcrId);
}
/**
* Checks if the object is marked.
*
* @param mcrId the mcr identifier
* @return true if its marked
*/
public boolean isMarked(MCRObjectID mcrId) {
return this.marks.containsKey(mcrId);
}
/**
* Checks if the given base object is marked. If base is an instance of MCRDerivate, this method checks also if the
* linked object is marked.
*
* @param base the mycore object
* @return true if its marked
*/
public boolean isMarked(MCRBase base) {
if (base instanceof MCRDerivate) {
MCRDerivate derivate = (MCRDerivate) base;
return isMarked(derivate.getId()) || isMarked(derivate.getOwnerID());
}
return isMarked(base.getId());
}
/**
* Checks if the object is marked for deletion.
*
* @param mcrId the mcr identifier
* @return true if its marked for deletion
*/
public boolean isMarkedForDeletion(MCRObjectID mcrId) {
return Operation.DELETE.equals(this.marks.get(mcrId));
}
/**
* Checks if the derivate or the corresponding mycore object is
* marked for deletion.
*
* @return true if one of them is marked for deletion
*/
public boolean isMarkedForDeletion(MCRDerivate derivate) {
return isMarkedForDeletion(derivate.getId()) || isMarkedForDeletion(derivate.getOwnerID());
}
/**
* Checks if the object is marked for import.
*
* @param mcrId the mcr identifier
* @return true if its marked for import
*/
public boolean isMarkedForImport(MCRObjectID mcrId) {
return Operation.IMPORT.equals(this.marks.get(mcrId));
}
}