001    /*
002     * $Revision: 13278 $ $Date: 2008-03-17 17:12:15 +0100 (Mo, 17 Mrz 2008) $
003     *
004     * This file is part of ***  M y C o R e  ***
005     * See http://www.mycore.de/ for details.
006     *
007     * This program is free software; you can use it, redistribute it
008     * and / or modify it under the terms of the GNU General Public License
009     * (GPL) as published by the Free Software Foundation; either version 2
010     * of the License or (at your option) any later version.
011     *
012     * This program is distributed in the hope that it will be useful, but
013     * WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015     * GNU General Public License for more details.
016     *
017     * You should have received a copy of the GNU General Public License
018     * along with this program, in a file called gpl.txt or license.txt.
019     * If not, write to the Free Software Foundation Inc.,
020     * 59 Temple Place - Suite 330, Boston, MA  02111-1307 USA
021     */
022    
023    package org.mycore.frontend.servlets;
024    
025    import java.io.IOException;
026    import java.net.URLEncoder;
027    import java.util.ArrayList;
028    import java.util.Collections;
029    import java.util.Comparator;
030    import java.util.Iterator;
031    import java.util.List;
032    import java.util.Map;
033    
034    import javax.servlet.http.HttpServletRequest;
035    
036    import org.apache.log4j.Logger;
037    import org.jdom.Document;
038    import org.jdom.Element;
039    
040    import org.mycore.common.MCRConfigurationException;
041    import org.mycore.common.MCRException;
042    import org.mycore.datamodel.classifications2.MCRCategLinkServiceFactory;
043    import org.mycore.datamodel.classifications2.MCRCategory;
044    import org.mycore.datamodel.classifications2.MCRCategoryDAOFactory;
045    import org.mycore.datamodel.classifications2.MCRCategoryID;
046    import org.mycore.datamodel.classifications2.MCRLabel;
047    import org.mycore.parsers.bool.MCRAndCondition;
048    import org.mycore.parsers.bool.MCRCondition;
049    import org.mycore.services.fieldquery.MCRFieldDef;
050    import org.mycore.services.fieldquery.MCRQuery;
051    import org.mycore.services.fieldquery.MCRQueryCondition;
052    import org.mycore.services.fieldquery.MCRQueryManager;
053    import org.mycore.services.fieldquery.MCRQueryParser;
054    
055    /**
056     * This servlet provides a way to visually navigate through the tree of
057     * categories of a classification. The XML output is transformed to HTML
058     * using classificationBrowserData.xsl on the server side, then sent to
059     * the client browser, where AJAX does the rest.
060     * 
061     * @author Frank Lützenkirchen
062     */
063    public class MCRClassificationBrowser2 extends MCRServlet {
064        private static final long serialVersionUID = 1L;
065    
066        private static final Logger LOGGER = Logger.getLogger(MCRClassificationBrowser2.class);
067    
068        public void doGetPost(MCRServletJob job) throws Exception {
069            long time = System.nanoTime();
070    
071            HttpServletRequest req = job.getRequest();
072    
073            String classifID = req.getParameter("classification");
074            String categID = req.getParameter("category");
075            String objectType = req.getParameter("objecttype");
076            String field = req.getParameter("field");
077            String restriction = req.getParameter("restriction");
078            String parameters = req.getParameter("parameters");
079    
080            boolean countResults = Boolean.valueOf(req.getParameter("countresults"));
081            boolean uri = Boolean.valueOf(req.getParameter("adduri"));
082    
083            String el = req.getParameter("emptyleaves");
084            boolean emptyLeaves = true;
085            if ((el != null) && (el.trim().length() > 0))
086                emptyLeaves = Boolean.valueOf(el);
087    
088            LOGGER.info("ClassificationBrowser " + classifID + " " + (categID == null ? "" : categID));
089    
090            MCRCategoryID id = new MCRCategoryID(classifID, categID);
091            Element xml = new Element("classificationBrowserData");
092            xml.setAttribute("classification", classifID);
093            xml.setAttribute("webpage", req.getParameter("webpage"));
094    
095            MCRAndCondition queryCondition = new MCRAndCondition();
096            final MCRFieldDef fieldDef = MCRFieldDef.getDef(field);
097            if (fieldDef == null)
098                throw new MCRConfigurationException("Search field '" + field + "' is not defined.");
099            MCRQueryCondition categCondition = new MCRQueryCondition(fieldDef, "=", "DUMMY");
100            queryCondition.addChild(categCondition);
101    
102            if ((objectType != null) && (objectType.trim().length() > 0)) {
103                xml.setAttribute("objectType", objectType);
104                MCRCondition cond = new MCRQueryCondition(MCRFieldDef.getDef("objectType"), "=", objectType);
105                queryCondition.addChild(cond);
106            }
107            if ((restriction != null) && (restriction.trim().length() > 0)) {
108                MCRCondition cond = new MCRQueryParser().parse(restriction);
109                queryCondition.addChild(cond);
110            }
111    
112            if (parameters != null)
113                xml.setAttribute("parameters", parameters);
114    
115            List<Element> data = new ArrayList<Element>();
116            MCRCategory category = MCRCategoryDAOFactory.getInstance().getCategory(id, 1);
117            for (MCRCategory child : category.getChildren()) {
118                String childID = child.getId().getID();
119                categCondition.setValue(childID);
120                int numResults = (countResults ? MCRQueryManager.search(new MCRQuery(queryCondition)).getNumHits() : 1);
121    
122                if ((!emptyLeaves) && (numResults < 1))
123                    continue;
124    
125                Element categoryE = new Element("category");
126                data.add(categoryE);
127                if (countResults)
128                    categoryE.setAttribute("numResults", String.valueOf(numResults));
129    
130                categoryE.setAttribute("id", childID);
131                categoryE.setAttribute("children", Boolean.toString(child.hasChildren()));
132    
133                categoryE.setAttribute("query", URLEncoder.encode(queryCondition.toString(), "UTF-8"));
134    
135                if (uri && (child.getURI() != null))
136                    categoryE.addContent(new Element("uri").setText(child.getURI().toString()));
137    
138                addLabel(req, child, categoryE);
139            }
140    
141            countLinks(req, emptyLeaves, objectType, category, data);
142            sortCategories(req, data);
143            xml.addContent(data);
144            renderToHTML(job, req, xml);
145    
146            time = (System.nanoTime() - time) / 1000000;
147            LOGGER.info("ClassificationBrowser finished in " + time + " ms");
148        }
149    
150        /**
151         * Add label in current lang, otherwise default lang, optional with
152         * description
153         */
154        private void addLabel(HttpServletRequest req, MCRCategory child, Element category) {
155            MCRLabel label = child.getCurrentLabel();
156    
157            category.addContent(new Element("label").setText(label.getText()));
158    
159            // if true, add description
160            boolean descr = Boolean.valueOf(req.getParameter("adddescription"));
161            if (descr && (label.getDescription() != null))
162                category.addContent(new Element("description").setText(label.getDescription()));
163        }
164    
165        /** Add link count to each category */
166        private void countLinks(HttpServletRequest req, boolean emptyLeaves, String objectType, MCRCategory category, List<Element> data) {
167            if (!Boolean.valueOf(req.getParameter("countlinks")))
168                return;
169            if (objectType.trim().length() == 0)
170                objectType = null;
171            String classifID = category.getId().getRootID();
172            Map<MCRCategoryID, Number> count = MCRCategLinkServiceFactory.getInstance().countLinksForType(category, objectType, true);
173            for (Iterator<Element> it = data.iterator(); it.hasNext();) {
174                Element child = it.next();
175                MCRCategoryID childID = new MCRCategoryID(classifID, child.getAttributeValue("id"));
176                int num = (count.containsKey(childID) ? count.get(childID).intValue() : 0);
177                child.setAttribute("numLinks", String.valueOf(num));
178                if ((!emptyLeaves) && (num < 1))
179                    it.remove();
180            }
181        }
182    
183        /** Sorts by id, by label in current language, or keeps natural order */
184        private void sortCategories(HttpServletRequest req, List<Element> data) {
185            final String sortBy = req.getParameter("sortby");
186            if (sortBy != null)
187                Collections.sort(data, new Comparator<Element>() {
188                    public int compare(Element a, Element b) {
189                        if ("id".equals(sortBy))
190                            return (a.getAttributeValue("id").compareTo(b.getAttributeValue("id")));
191                        else if ("label".equals(sortBy))
192                            return (a.getChildText("label").compareToIgnoreCase(b.getChildText("label")));
193                        else
194                            return 0;
195                    }
196                });
197        }
198    
199        /** Sends output to client browser */
200        private void renderToHTML(MCRServletJob job, HttpServletRequest req, Element xml) throws IOException {
201            String style = req.getParameter("style"); // XSL.Style, optional
202            if ((style != null) && (style.length() > 0))
203                req.setAttribute("XSL.Style", style);
204    
205            MCRServlet.getLayoutService().doLayout(req, job.getResponse(), new Document(xml));
206        }
207    }