001    /*
002     * 
003     * $Revision: 15202 $ $Date: 2009-05-15 17:00:44 +0200 (Fri, 15 May 2009) $
004     *
005     * This file is part of ***  M y C o R e  ***
006     * See http://www.mycore.de/ for details.
007     *
008     * This program is free software; you can use it, redistribute it
009     * and / or modify it under the terms of the GNU General Public License
010     * (GPL) as published by the Free Software Foundation; either version 2
011     * of the License or (at your option) any later version.
012     *
013     * This program is distributed in the hope that it will be useful, but
014     * WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program, in a file called gpl.txt or license.txt.
020     * If not, write to the Free Software Foundation Inc.,
021     * 59 Temple Place - Suite 330, Boston, MA  02111-1307 USA
022     */
023    
024    package org.mycore.frontend.wcms;
025    
026    import java.io.BufferedReader;
027    import java.io.File;
028    import java.io.FileNotFoundException;
029    import java.io.FileReader;
030    import java.io.IOException;
031    import java.io.PrintWriter;
032    import java.io.StringWriter;
033    import java.util.Iterator;
034    import java.util.List;
035    import java.util.ListIterator;
036    import java.util.Vector;
037    
038    import javax.servlet.http.HttpServletRequest;
039    import javax.servlet.http.HttpServletResponse;
040    
041    import org.jdom.Comment;
042    import org.jdom.Document;
043    import org.jdom.Element;
044    import org.jdom.JDOMException;
045    import org.jdom.Namespace;
046    import org.jdom.Text;
047    import org.jdom.input.SAXBuilder;
048    import org.jdom.output.Format;
049    import org.jdom.output.XMLOutputter;
050    import org.mycore.common.MCRConfiguration;
051    import org.mycore.common.MCRSession;
052    import org.mycore.common.MCRSessionMgr;
053    
054    /**
055     * Select action process for Web-Content-Management-System (WCMS).
056     */
057    public class MCRWCMSChooseServlet extends MCRWCMSServlet {
058    
059        private static final long serialVersionUID = 1L;
060    
061        private Namespace ns = Namespace.XML_NAMESPACE; // xml Namespace for the
062    
063        // language attribute lang
064        private String currentLang = null; //
065    
066        private String defaultLang = null; //
067    
068        private String contentError = null;
069    
070        private String href = null; // representing the href(dir) attribute of the
071    
072        // selected element in the navigation.xml
073        // e.g. type="extern" --> href="http://www.db-thueringen.de" ||
074        // type="intern" --> href="/content/main/information/description.xml" ||
075        // dir != null --> href=dir(e.g. href="/main")
076        private String action = null; // selected action:{add, edit, delete}
077    
078        private String mode = null; // if (action.equals(edit) mode = mode from
079    
080        // selected element:{intern, extern}
081        // else mode=moda
082        private String moda = null; // mode dependent from selected action:{intern,
083    
084        // extern}
085        private String label = null; // representing the label(name) of the
086    
087        // selected
088    
089        // link
090        private String label_currentLang = null; // representing the translated
091    
092        // label(name) of the selected link
093        private String target = null; // target of the selected element: {_blank,
094    
095        // _self}
096        private String template = null; // choosen Template
097    
098        private String style = null; // style of the selected element: {bold, normal}
099    
100        // have a valid dir attribute instead of a href
101        // attribute
102        private String addAtPosition = null; // position, where a link can be
103    
104        // added:
105    
106        // {predecessor, successor, child}
107        private String replaceMenu = null; // Representing a Parameter, allowing an
108    
109        // navigation element to replace the
110        // previous navigation structure only
111        // with its subelements. Can be "true" or
112        // "false".
113        private String constrainPopUp = null; // menu must be open
114    
115        char c; // representing the errorcodes {1,2,5,6,7,8,9,0}
116    
117        char d; // representing the errorcodes {1,2,5,6,7,8,9,0}
118    
119        char fs = File.separatorChar;
120    
121        boolean validXHTML = true;
122    
123        List contentList;
124    
125        List defaultLangContentOutput;
126    
127        List currentLangContentOutput;
128    
129        /**
130         * Main program called by doGet and doPost.
131         */
132        protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
133    
134            MCRSession mcrSession = MCRSessionMgr.getCurrentSession();
135            String userID = (String) mcrSession.get("userID");
136            String userClass = (String) mcrSession.get("userClass");
137            List rootNodes = (List) mcrSession.get("rootNodes");
138            addAtPosition = request.getParameter("addAtPosition");
139    
140            if (request.getParameter("action") != null) {
141                action = request.getParameter("action");
142            } else {
143                action = "false";
144            }
145    
146            File[] contentTemplates = new File(MCRConfiguration.instance().getString("MCR.templatePath") + "content/".replace('/', File.separatorChar)).listFiles();
147            File[] masterTemplates = new File(MCRConfiguration.instance().getString("MCR.templatePath") + "master/".replace('/', File.separatorChar)).listFiles();
148            template = request.getParameter("template");
149    
150            File conTemp = new File(MCRConfiguration.instance().getString("MCR.templatePath") + "content/".replace('/', File.separatorChar));
151            Element templates = new Element("templates");
152            defaultLangContentOutput = null;
153            currentLangContentOutput = null;
154            contentError = null;
155    
156            /* get languages */
157            if (mcrSession != null) {
158                defaultLang = MCRConfiguration.instance().getString("MCR.Metadata.DefaultLang", "en").toLowerCase();
159                currentLang = mcrSession.getCurrentLanguage().toLowerCase();
160            }
161    
162            /*
163             * System.err.println("defaultLang"+defaultLang+"..."); System.err.println("currentLang"+currentLang+"...");
164             */
165    
166            /**
167             * If action parameter contains a character '_' (e.g.: add_intern, add_extern) then split action in action (e.g.: add) and mode (e.g.: intern)
168             */
169            if ((action != null) && (action.indexOf('_') != -1)) {
170                moda = action.substring(action.indexOf('_') + 1);
171                action = action.substring(0, action.indexOf('_'));
172            }
173    
174            if (action.equals("false")) {
175                contentError = "Error: Please select an action to be done.";
176            }
177    
178            /**
179             * Split href parameter (e.g.: 1/content/top/index.xml) in character c and href for identifying the selected element in the navigation.xml and checking
180             * the selected action Transfered characters are: --- valid values ------------------------------------------------------------------------ '1' - if the
181             * selected element has a valid href attribute. '2' - if the selected element was a main element (e.g.: "Men? oberhalb", "Men? links" and "Zusatzmen?
182             * links unten") and has a valid dir attribute instead of a valid href attribute. --- invalid values
183             * ---------------------------------------------------------------------- '5' - if the selected element is a main navigation element like "Men? links"
184             * and addAtPosition is "predecessor" or "successor". '6' - if the selected element has an external target and action was add. This is to avoid the
185             * creation of a child under a parent with external target because it can not reached via navigation tree. '7' - if the selected element has child(s)
186             * and action was delete. Thus, an element with active childs can not be deleted. Deleting elements with active childs is only possible when deleting
187             * all childs first. '8' - if the selected element has childs but is not nested within a rootNode. This occurs only on restricted users trying to edit
188             * such an element. '9' - if a place holder was selected. '0' - if nothing was selected.
189             */
190            if (request.getParameter("href") != null) {
191                href = request.getParameter("href").substring(1);
192                c = d = request.getParameter("href").charAt(0);
193            } else {
194                c = d = '0';
195            }
196    
197            if (c == '2') {
198                mcrSession.put("dir", href);
199            } else {
200                mcrSession.put("dir", "false");
201            }
202    
203            /**
204             * Build jdom object dependence on the selected action and selected element.
205             */
206            Element rootOut = new Element("cms");
207            Document jdom = new Document(rootOut);
208    
209            /**
210             * Try to build a jdom Object from the content of the navigation.xml.
211             */
212            try {
213                SAXBuilder builder = new SAXBuilder();
214                Document doc = builder.build(MCRConfiguration.instance().getString("MCR.navigationFile").replace('/', File.separatorChar));
215                Element root = doc.getRootElement();
216                validate(root);
217            } catch (JDOMException jdome) {
218                PrintWriter errorOut = response.getWriter();
219                errorOut.println(jdome.getMessage());
220                errorOut.close();
221            }
222    
223            /**
224             * Try to build a jdom Object from the content (this has to be valid XHTML content) of the file to be edited. The path of this file is build from the
225             * webapp dir and the href parameter of the selected element found in the navigation.xml.
226             */
227            if ((action.equals("edit") && (c == '1')) || action.equals("add") || (action.equals("translate") && (c == '1'))) {
228                defaultLangContentOutput = new Vector();
229                currentLangContentOutput = new Vector();
230    
231                try {
232                    SAXBuilder sax = new SAXBuilder();
233                    Document ed;
234    
235                    if (!action.equals("add") && mode.equals("intern")) {
236                        ed = sax.build(getServletContext().getRealPath("") + fs + href);
237                    } else {
238                        // if (mode.equals("intern")) {
239                        String edFiller = (MCRConfiguration.instance().getString("MCR.templatePath") + "content/").replace('/', File.separatorChar) + template;
240                        ed = sax.build(edFiller);
241                        System.out.println(edFiller);
242                        // }
243                        // else return;
244                    }
245    
246                    Element begin = ed.getRootElement();
247                    List contentElements = begin.getChildren("section");
248                    Iterator contentElementsIterator = contentElements.iterator();
249    
250                    while (contentElementsIterator.hasNext()) {
251                        Element content = (Element) contentElementsIterator.next();
252    
253                        if (content.getAttributeValue("lang", ns) != null) {
254                            contentList = content.getContent();
255                            validXHTML = true;
256    
257                            if (content.getAttributeValue("lang", ns).equals(defaultLang)) {
258                                for (int i = (contentList.size() - 1); i >= 0; i--) {
259                                    Object o = contentList.get(i);
260    
261                                    // String u = null;
262                                    if (o instanceof Element) {
263                                        ((Element) o).detach();
264                                    }
265    
266                                    if (o instanceof Text) {
267                                        ((Text) o).detach();
268                                    }
269    
270                                    if (o instanceof Comment) {
271                                        ((Comment) o).detach();
272                                    }
273    
274                                    defaultLangContentOutput.add(o);
275                                }
276                                reverse(defaultLangContentOutput);
277                            }
278    
279                            if (content.getAttributeValue("lang", ns).equals(currentLang) && action.equals("translate")) {
280                                for (int i = (contentList.size() - 1); i >= 0; i--) {
281                                    Object o = contentList.get(i);
282                                    // String u = null;
283                                    if (o instanceof Element) {
284                                        ((Element) o).detach();
285                                    }
286                                    if (o instanceof Text) {
287                                        ((Text) o).detach();
288                                    }
289                                    if (o instanceof Comment) {
290                                        ((Comment) o).detach();
291                                    }
292                                    currentLangContentOutput.add(o);
293                                }
294                                reverse(currentLangContentOutput);
295                            }
296                        }
297                        contentList.clear();
298                    }
299                } catch (JDOMException je) {
300                    try {
301                        if (!mode.equals("extern")) {
302                            // "Error: " + getServletContext().getRealPath("") + href.replace('/', File.separatorChar) + " is no valid XHTML file.";
303    
304                            File hrefFile = new File(getServletContext().getRealPath("") + href);
305                            BufferedReader br = new BufferedReader(new FileReader(hrefFile));
306    
307                            validXHTML = false;
308    
309                            String str;
310                            String stri = "";
311    
312                            while (true) {
313                                if ((str = br.readLine()) != null) {
314                                    stri = stri.concat(str + '\n');
315                                } else {
316                                    break;
317                                }
318                            }
319    
320                            br.close();
321    
322                            int begin = stri.indexOf("<section");
323                            String wow = stri.substring(begin, stri.indexOf("</section>"));
324                            String strin = stri.substring(begin + wow.indexOf('>') + 2, stri.indexOf("</section>"));
325                            defaultLangContentOutput.add(strin);
326                        }
327                    } catch (FileNotFoundException fne) {
328                        // System.out.println(fne);
329                    }
330                }
331            }
332    
333            /*
334             * catch (JDOMException je) { if (output != null) { output.clear(); output.add("File konnte nicht geparst werden."); } }
335             */
336            if (action.equals("edit") && (c == '2')) {
337                c = '8';
338            }
339    
340            if (action.equals("delete") && (c == '2')) {
341                c = '7';
342            }
343    
344            /**
345             * If character c consist an invalid value (5, 6, 7, 8, 9, 0) then print out the corresponding error and restart the WCMSChooseServlet (both things will
346             * be done by the belonging stylesheet). Output: <cms> <session>choose </session> <error>5|6|7|8|9|0 </error> <rootNode href="no"|"yes">rootNode
347             * </rootNode>{0,*} <templates><content> <template>$template </template>{0,*} </content> </templates> </cms>
348             */
349            if (((c != '1') && (c != '2')) || (contentError != null)) {
350                rootOut.addContent(new Element("session").setText("choose"));
351    
352                if ((c != '1') && (c != '2')) {
353                    rootOut.addContent(new Element("error").setText(String.valueOf(c)));
354                } else {
355                    rootOut.addContent(new Element("contentError").setAttribute("msg", contentError).setText("yes"));
356                }
357    
358                Iterator rootNodesIterator = rootNodes.iterator();
359    
360                while (rootNodesIterator.hasNext()) {
361                    Element rootNode = (Element) rootNodesIterator.next();
362                    rootOut.addContent(new Element("rootNode").setAttribute("href", rootNode.getAttributeValue("href")).setText(rootNode.getTextTrim()));
363                }
364    
365                Element contentTemp = new Element("content");
366    
367                for (int i = 0; i < contentTemplates.length; i++) {
368                    if (!contentTemplates[i].isDirectory()) {
369                        contentTemp.addContent(new Element("template").setText(contentTemplates[i].getName()));
370                    }
371                }
372    
373                templates.addContent(contentTemp);
374                rootOut.addContent(templates);
375            }
376            /**
377             * Else output: <cms><session>action </session> <userName>uid </userName> <userClass>admin|editor|autor </userClass> <action
378             * mode="intern"|"extern">add|edit|delete </action> <addAtPosition>predecessor|successor|child </addAtPosition> <-- only at action add <href>href
379             * </href> <label>label </label> <target>_blank|_self </target> <style>normal|bold </style> <content>output </content> <-- only at action edit and add
380             * <images>$imagePath </images>{0,*} <documents>$documentPath </documents>{0,*} <templates><master><template>$template </template>{0,*} </master>
381             * <content><template>conTemp </template> </content> </templates> </cms>
382             */
383            else {
384                rootOut.addContent(new Element("session").setText("action"));
385            }
386    
387            rootOut.addContent(new Element("userID").setText(userID));
388            rootOut.addContent(new Element("userClass").setText(userClass));
389    
390            if (action.equals("add") && (mode != null)) {
391                mode = moda;
392                rootOut.addContent(new Element("action").setAttribute("mode", mode).setText(action));
393                rootOut.addContent(new Element("addAtPosition").setText(addAtPosition));
394                rootOut.addContent(new Element("replaceMenu").setText(replaceMenu));
395            }
396    
397            if (action.equals("edit") && (mode != null)) {
398                rootOut.addContent(new Element("action").setAttribute("mode", mode).setText(action));
399    
400                if (mode.equals("intern")) {
401                    rootOut.addContent(new Element("replaceMenu").setText(replaceMenu));
402                }
403    
404                rootOut.addContent(new Element("constrainPopUp").setText(constrainPopUp));
405            }
406    
407            if (action.equals("delete") && (mode != null)) {
408                rootOut.addContent(new Element("action").setAttribute("mode", mode).setText(action));
409            }
410    
411            if (action.equals("translate") && (mode != null)) {
412                rootOut.addContent(new Element("action").setAttribute("mode", mode).setText(action));
413                rootOut.addContent(new Element("label_currentLang").setText(label_currentLang));
414            }
415    
416            rootOut.addContent(new Element("href").setText(href));
417            rootOut.addContent(new Element("label").setText(label));
418            rootOut.addContent(new Element("target").setText(target));
419            rootOut.addContent(new Element("style").setText(style));
420    
421            if (defaultLangContentOutput != null) {
422                try {
423                    if (validXHTML) {
424                        /*
425                         * String test = ""; Element elem = null; for ( int i=0; i <output.size(); i++ ) { elem = (Element)output.get(i); test += elem.getText(); }
426                         * System.out.println(test);
427                         */
428                        StringWriter sw = new StringWriter();
429                        XMLOutputter contentOut = new XMLOutputter(Format.getRawFormat().setTextMode(Format.TextMode.PRESERVE).setEncoding(OUTPUT_ENCODING));
430    
431                        // 1.Method: rootOut.addContent(new
432                        // Element("content").setText(contentOut.output(defaultLangContentOutput,
433                        // contentOut)));
434                        contentOut.output(defaultLangContentOutput, sw);
435    
436                        // System.out.println("testoutput: "+sw.toString());
437                        rootOut.addContent(new Element("content").setText(sw.toString()));
438                        sw.flush();
439                        sw.close();
440    
441                        if (action.equals("translate") && (currentLangContentOutput != null)) {
442                            // rootOut.addContent(new
443                            // Element("content_currentLang").setText(contentOut.outputString(currentLangContentOutput)));
444                            contentOut.output(currentLangContentOutput, sw);
445    
446                            rootOut.addContent(new Element("content_currentLang").setText(sw.toString()));
447                            sw.flush();
448                            sw.close();
449                        }
450                    } else {
451                        rootOut.addContent(new Element("content").setText((String) defaultLangContentOutput.get(0)));
452                        rootOut.addContent(new Element("error").setText("invalidXHTML"));
453                    }
454                } catch (Exception e) {
455                    e.printStackTrace();
456                }
457            }
458    
459            templates = getMultimediaConfig(rootOut);
460    
461            Element master = new Element("master");
462    
463            for (int i = 0; i < masterTemplates.length; i++) {
464                if (masterTemplates[i].isDirectory() && (masterTemplates[i].getName().compareToIgnoreCase("cvs") != 0)) {
465                    master.addContent(new Element("template").setText(masterTemplates[i].getName()));
466                }
467            }
468    
469            Element content = new Element("content");
470            content.addContent(new Element("template").setText(conTemp.toString()));
471            templates.addContent(master);
472            templates.addContent(content);
473            rootOut.addContent(templates);
474    
475            /**
476             * and add some further attributes to the session object: --- allready existing --------------------------------- <session ... uid=uid
477             * userClass="admin"|"editor"|"autor" rootNodes=rootNodes ... --- new attributes ------------------------------------ ... href=href label=label
478             * action="add"|"edit"|"delete" mode="intern"|"extern" ... ... target="intern"|"extern" style="normal"|"bold" />
479             */
480            if (href != null) {
481                mcrSession.put("href", href);
482            }
483    
484            if (label != null) {
485                mcrSession.put("label", label);
486            }
487    
488            if (label_currentLang != null) {
489                mcrSession.put("label_currentLang", label_currentLang);
490            }
491    
492            if (action != null) {
493                mcrSession.put("action", action);
494            }
495    
496            if (mode != null) {
497                mcrSession.put("mode", mode);
498            }
499    
500            if (target != null) {
501                mcrSession.put("target", target);
502            }
503    
504            if (style != null) {
505                mcrSession.put("style", style);
506            }
507    
508            if (defaultLang != null) {
509                mcrSession.put("defaultLang", defaultLang);
510            }
511    
512            if (currentLang != null) {
513                mcrSession.put("currentLang", currentLang);
514            }
515    
516            if (addAtPosition != null) {
517                mcrSession.put("addAtPosition", addAtPosition);
518            }
519    
520            getLayoutService().doLayout(request, response, jdom);
521        }
522    
523        /**
524         * Finds the selected element in the navigation.xml and assigns attribute values for the variables of the jdom object and setting character c respectively.
525         */
526        public void validate(Element element) {
527            List elements = element.getChildren();
528            Iterator elementIterator = elements.iterator();
529    
530            while (elementIterator.hasNext()) {
531                Element child = (Element) elementIterator.next();
532    
533                if (child.getAttribute("href") != null) {
534                    if (child.getAttributeValue("href").equals(href)) {
535                        if (action.equals("delete") && !child.getChildren("item").isEmpty()) {
536                            c = '7';
537                        }
538    
539                        else if (action.equals("add") && child.getAttributeValue("type").equals("extern") && addAtPosition.equals("child"))
540                            c = '6';
541    
542                        else {
543                            c = d;
544                        }
545    
546                        if (child.getAttributeValue("type") != null) {
547                            mode = child.getAttributeValue("type");
548                        }
549    
550                        if ((getLabel(child, defaultLang) != null) && !getLabel(child, defaultLang).equals("")) {
551                            label = getLabel(child, defaultLang);
552                        }
553    
554                        if ((getLabel(child, currentLang) != null) && !getLabel(child, currentLang).equals("")) {
555                            label_currentLang = getLabel(child, currentLang);
556                        }
557    
558                        if (child.getAttributeValue("target") != null) {
559                            target = child.getAttributeValue("target");
560                        }
561    
562                        if (child.getAttributeValue("style") != null) {
563                            style = child.getAttributeValue("style");
564                        }
565    
566                        if (child.getAttributeValue("replaceMenu") != null) {
567                            replaceMenu = child.getAttributeValue("replaceMenu");
568                        }
569    
570                        if (child.getAttributeValue("constrainPopUp") != null) {
571                            constrainPopUp = child.getAttributeValue("constrainPopUp");
572                        } else {
573                            replaceMenu = "false";
574                        }
575    
576                        return;
577                    }
578                }
579    
580                if (child.getAttributeValue("dir") != null) {
581                    if (child.getAttributeValue("dir").equals(href)) {
582                        href = ((Element) child.getParent()).getAttributeValue("dir") + href;
583                        mode = moda;
584    
585                        if (action.equals("delete") && !child.getChildren("item").isEmpty()) {
586                            c = '7';
587                        } else {
588                            c = d;
589                        }
590    
591                        if (action.equals("add") && !addAtPosition.equals("child")) {
592                            c = '5';
593                        }
594    
595                        return;
596                    }
597                }
598    
599                validate(child);
600            }
601        }
602    
603        /**
604         * Finds the right label
605         */
606        public String getLabel(Element element, String language) {
607            List elements = element.getChildren("label");
608            Iterator elementIterator = elements.iterator();
609            String labelReturn = null;
610    
611            while (elementIterator.hasNext()) {
612                Element child = (Element) elementIterator.next();
613    
614                if (child.getAttribute("lang", ns) != null) {
615                    if (child.getAttributeValue("lang", ns).equals(language)) {
616                        if (child.getText() != null) {
617                            labelReturn = child.getTextTrim();
618                        }
619                    }
620                }
621    
622                getLabel(child, language);
623            }
624    
625            return labelReturn;
626        }
627    
628        public void reverse(List l) {
629            ListIterator fwd = l.listIterator();
630            ListIterator rev = l.listIterator(l.size());
631    
632            for (int i = 0, n = l.size() / 2; i < n; i++) {
633                Object tmp = fwd.next();
634                fwd.set(rev.previous());
635                rev.set(tmp);
636            }
637        }
638    }