001    package org.mycore.datamodel.classifications;
002    
003    import java.util.ArrayList;
004    import java.util.Collection;
005    import java.util.HashMap;
006    import java.util.HashSet;
007    import java.util.Iterator;
008    import java.util.Set;
009    
010    import org.apache.log4j.Logger;
011    
012    import org.mycore.common.MCRSessionMgr;
013    import org.mycore.datamodel.classifications2.MCRCategLinkService;
014    import org.mycore.datamodel.classifications2.MCRCategLinkServiceFactory;
015    import org.mycore.datamodel.classifications2.MCRCategory;
016    import org.mycore.datamodel.classifications2.MCRCategoryDAO;
017    import org.mycore.datamodel.classifications2.MCRCategoryDAOFactory;
018    import org.mycore.datamodel.classifications2.MCRCategoryID;
019    import org.mycore.frontend.cli.MCRObjectCommands;
020    
021    /**
022     * @author Radi Radichev
023     * 
024     */
025    
026    public class MCRClassificationPool {
027    
028        /**
029         * stores all edited classifications
030         */
031        private HashMap<MCRCategoryID, MCRCategory> classifications = new HashMap<MCRCategoryID, MCRCategory>();
032    
033        private HashSet<MCRCategoryID> movedCategories = new HashSet<MCRCategoryID>();
034    
035        static Logger LOGGER = Logger.getLogger(MCRClassificationPool.class);
036    
037        private static MCRCategoryDAO DAO = MCRCategoryDAOFactory.getInstance();
038    
039        public MCRClassificationPool() {
040            //store reference of classifications in current session
041            MCRSessionMgr.getCurrentSession().put("classifications", classifications); // Put
042        }
043    
044        /**
045         * This method returns all ClassificationIDs. From the database and pool
046         * together.
047         * 
048         * @return
049         */
050        public Set<MCRCategoryID> getAllIDs() {
051            Set<MCRCategoryID> ids = new HashSet<MCRCategoryID>();
052            ids.addAll(DAO.getRootCategoryIDs());
053            ids.addAll(classifications.keySet());
054            return ids;
055        }
056    
057        /**
058         * Save all changes to the database.
059         * 
060         * @return
061         */
062        public boolean saveAll() {
063            synchronized (classifications) {
064                HashMap<MCRCategoryID, MCRCategory> classCopy = new HashMap<MCRCategoryID, MCRCategory>();
065                classCopy.putAll(classifications);
066                Iterator<MCRCategory> rootCategories = classifications.values().iterator();
067                try {
068                    while (rootCategories.hasNext()) {
069                        MCRCategory clas = rootCategories.next();
070                        LOGGER.debug("Classification to be saved: " + clas.getId());
071                        if (DAO.exist(clas.getId())) {
072                            DAO.replaceCategory(clas);
073                        } else {
074                            DAO.addCategory(null, clas);
075                        }
076                        rootCategories.remove();
077                    }
078                } catch (Exception e) {
079                    LOGGER.warn("Error while saving all classifications.", e);
080                    return false;
081                }
082                LOGGER.debug("Getting all categories that where moved to left or right");
083                HashSet<MCRCategoryID> modifiedCategories = new HashSet<MCRCategoryID>();
084                for (MCRCategoryID categID : getMovedCategories()) {
085                    LOGGER.debug("Getting sub categories of "+categID);
086                    MCRCategory cat = findCategory(classCopy.get(MCRCategoryID.rootID(categID.getRootID())), categID);
087                    modifiedCategories.addAll(getSubTree(cat));
088                }
089                LOGGER.debug("Getting all objects that where affected my category movements");
090                HashSet<String> linkedObjects = new HashSet<String>();
091                MCRCategLinkService linkService = MCRCategLinkServiceFactory.getInstance();
092                for (MCRCategoryID cat:modifiedCategories){
093                    LOGGER.debug("Getting linked objects for "+cat);
094                    linkedObjects.addAll(linkService.getLinksFromCategory(cat));
095                }
096                for (String objectID:linkedObjects){
097                    MCRObjectCommands.repairMetadataSearchForID(objectID);
098                }
099                movedCategories.clear();
100            }
101            return true;
102        }
103    
104        private static Collection<MCRCategoryID> getSubTree(MCRCategory subTreeNode) {
105            ArrayList<MCRCategoryID> children = new ArrayList<MCRCategoryID>();
106            children.add(subTreeNode.getId());
107            for (MCRCategory child : subTreeNode.getChildren()) {
108                children.addAll(getSubTree(child));
109            }
110            return children;
111        }
112    
113        private static MCRCategory findCategory(MCRCategory parent, MCRCategoryID id) {
114            MCRCategory found = null;
115            for (MCRCategory cat : parent.getChildren()) {
116                if (cat.getId().equals(id)) {
117                    found = cat;
118                    LOGGER.debug("Found Category: " + found.getId().getID());
119                    break;
120                }
121                MCRCategory rFound = findCategory(cat, id);
122                if (rFound != null) {
123                    found = rFound;
124                    break;
125                }
126            }
127    
128            return found;
129        }
130    
131        /**
132         * Cancel all changes. Clear the hashtable.
133         * 
134         * @return
135         */
136        public boolean purgeAll() {
137    
138            LOGGER.debug("Purging all in progress...");
139            synchronized (classifications) {
140                classifications.clear();
141                movedCategories.clear();
142            }
143            return true;
144        }
145    
146        /**
147         * Check if the Classification with classID is already edited and in the
148         * session.
149         * 
150         * @param classID
151         *            Classification ID to check for
152         * @return <code>true</code> when Classification is edited,
153         *         <code>false</code> when not.
154         */
155        public boolean isEdited(MCRCategoryID classID) {
156            return classifications.containsKey(classID);
157        }
158    
159        /**
160         * Put the classification in the Session. This method is executed every time
161         * a Classification or a Category is edited
162         * 
163         * @param cl
164         *            Classification to be stored in the session.
165         */
166        public void updateClassification(MCRCategory cl) {
167            classifications.put(cl.getId(), cl);
168            LOGGER.info("Classification: " + cl.getId() + " added to session!");
169        }
170    
171        /**
172         * Delete a classfication from the pool
173         * @param cl
174         */
175        public void deleteClassification(MCRCategoryID cl) {
176            if (classifications.containsKey(cl))
177                classifications.remove(cl);
178        }
179    
180        /**
181         * This method checks to see if the classification which is expected is in
182         * the Session (when edited) or it takes the classification from the
183         * database
184         * 
185         * @param clid
186         * @param writeAccess
187         * @return MCRCategory classif
188         */
189    
190        public MCRCategory getClassificationAsPojo(MCRCategoryID clid, boolean writeAccess) {
191            MCRCategory classif = classifications.get(clid);
192            if (classif != null) {
193                return classif;
194            } else {
195                MCRCategory cl = DAO.getCategory(clid, writeAccess ? -1 : 0);
196                return cl;
197            }
198        }
199    
200        public HashSet<MCRCategoryID> getMovedCategories() {
201            return movedCategories;
202        }
203    
204    }