001    /*
002     * $Revision: 15291 $ $Date: 2009-05-28 12:49:38 +0200 (Thu, 28 May 2009) $
003     * 
004     * This file is part of M y C o R e See http://www.mycore.de/ for details. This program is free software; you can use it, redistribute it and / or modify it
005     * under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; either version 2 of the License or (at your option) any
006     * later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
007     * 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
008     * along with this program, in a file called gpl.txt or license.txt. If not, write to the Free Software Foundation Inc., 59 Temple Place - Suite 330, Boston, MA
009     * 02111-1307 USA
010     */
011    
012    package org.mycore.frontend.cli;
013    
014    import java.io.File;
015    import java.io.FileNotFoundException;
016    import java.io.FileOutputStream;
017    import java.io.IOException;
018    import java.io.InputStream;
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.Collections;
022    import java.util.List;
023    
024    import javax.xml.transform.Transformer;
025    import javax.xml.transform.TransformerException;
026    import javax.xml.transform.TransformerFactory;
027    import javax.xml.transform.TransformerFactoryConfigurationError;
028    import javax.xml.transform.stream.StreamResult;
029    import javax.xml.transform.stream.StreamSource;
030    
031    import org.apache.log4j.Logger;
032    import org.jdom.Document;
033    import org.jdom.Element;
034    
035    import org.mycore.access.MCRAccessInterface;
036    import org.mycore.access.MCRAccessManager;
037    import org.mycore.common.MCRException;
038    import org.mycore.common.xml.MCRURIResolver;
039    import org.mycore.datamodel.common.MCRXMLTableManager;
040    import org.mycore.datamodel.ifs.MCRFileImportExport;
041    import org.mycore.datamodel.metadata.MCRDerivate;
042    import org.mycore.datamodel.metadata.MCRMetaLinkID;
043    import org.mycore.datamodel.metadata.MCRObject;
044    import org.mycore.datamodel.metadata.MCRObjectID;
045    
046    /**
047     * Provides static methods that implement commands for the MyCoRe command line interface.
048     * 
049     * @author Jens Kupferschmidt
050     * @author Frank Luetzenkirchen
051     * @version $Revision: 15291 $ $Date: 2009-05-28 12:49:38 +0200 (Thu, 28 May 2009) $
052     */
053    public class MCRDerivateCommands extends MCRAbstractCommands {
054        /** The logger */
055        private static Logger LOGGER = Logger.getLogger(MCRDerivateCommands.class.getName());
056    
057        /** The ACL interface */
058        private static final MCRAccessInterface ACCESS_IMPL = MCRAccessManager.getAccessImpl();
059    
060        /** Default transformer script */
061        public static final String DEFAULT_TRANSFORMER = "save-derivate.xsl";
062    
063        /**
064         * The constructor.
065         */
066        public MCRDerivateCommands() {
067            super();
068    
069            MCRCommand com = null;
070    
071            com = new MCRCommand("delete all derivates", "org.mycore.frontend.cli.MCRDerivateCommands.deleteAllDerivates",
072                            "Removes all derivates from the repository");
073            command.add(com);
074    
075            com = new MCRCommand("delete derivate from {0} to {1}", "org.mycore.frontend.cli.MCRDerivateCommands.delete String String",
076                            "The command remove derivates in the number range between the MCRObjectID {0} and {1}.");
077            command.add(com);
078    
079            com = new MCRCommand("delete derivate {0}", "org.mycore.frontend.cli.MCRDerivateCommands.delete String",
080                            "The command remove a derivate with the MCRObjectID {0}");
081            command.add(com);
082    
083            com = new MCRCommand("load derivate from file {0}", "org.mycore.frontend.cli.MCRDerivateCommands.loadFromFile String",
084                            "The command add a derivate form the file {0} to the system.");
085            command.add(com);
086    
087            com = new MCRCommand("update derivate from file {0}", "org.mycore.frontend.cli.MCRDerivateCommands.updateFromFile String",
088                            "The command update a derivate form the file {0} in the system.");
089            command.add(com);
090    
091            com = new MCRCommand("load all derivates from directory {0}", "org.mycore.frontend.cli.MCRDerivateCommands.loadFromDirectory String",
092                            "The command load all derivates form the directory {0} to the system.");
093            command.add(com);
094    
095            com = new MCRCommand("update all derivates from directory {0}", "org.mycore.frontend.cli.MCRDerivateCommands.updateFromDirectory String",
096                            "The command update all derivates form the directory {0} in the system.");
097            command.add(com);
098    
099            com = new MCRCommand("export derivate {0} to directory {1} with {2}", "org.mycore.frontend.cli.MCRDerivateCommands.export String String String",
100                            "The command store the derivate with the MCRObjectID {0} to the directory {1} with the stylesheet {2}-object.xsl. For {2} save is the default.");
101            command.add(com);
102    
103            com = new MCRCommand("export derivate from {0} to {1} to directory {2} with {3}",
104                            "org.mycore.frontend.cli.MCRDerivateCommands.export String String String String",
105                            "The command store all derivates with MCRObjectID's between {0} and {1} to the directory {2} with the stylesheet {3}-object.xsl. For {3} save is the default.");
106            command.add(com);
107    
108            com = new MCRCommand("export all derivates to directory {0} with {1}", "org.mycore.frontend.cli.MCRDerivateCommands.exportAllDerivates String String",
109                            "Stores all derivates to the directory {0} with the stylesheet mcr_{1}-derivate.xsl. For {1} save is the default.");
110            command.add(com);
111    
112            com = new MCRCommand("show loadable derivate of {0} to directory {1}", "org.mycore.frontend.cli.MCRDerivateCommands.show String String",
113                            "The command store the derivate with the MCRObjectID {0} to the directory {1}, without ifs-metadata");
114            command.add(com);
115    
116            com = new MCRCommand("repair derivate search of type derivate", "org.mycore.frontend.cli.MCRDerivateCommands.repairDerivateSearch",
117                            "The command read the Content store and reindex the derivate search stores.");
118            command.add(com);
119    
120            com = new MCRCommand("repair derivate search of ID {0}", "org.mycore.frontend.cli.MCRDerivateCommands.repairDerivateSearchForID String",
121                            "The command read the Content store for MCRObjectID {0} and reindex the derivate search store.");
122            command.add(com);
123    
124            com = new MCRCommand("synchronize all derivates", "org.mycore.frontend.cli.MCRDerivateCommands.synchronizeAllDerivates",
125                            "The command read each derivate and synchronize the xlink:label with the derivate entry of the mycoreobject.");
126            command.add(com);
127    
128            com = new MCRCommand("synchronize derivate with ID {0}", "org.mycore.frontend.cli.MCRDerivateCommands.synchronizeDerivateForID String",
129                            "The command read a derivate with the MCRObjectID {0} and synchronize the xlink:label with the derivate entry of the mycoreobject.");
130            command.add(com);
131        }
132    
133        /**
134         * deletes all MCRDerivate from the datastore.
135         */
136        public static List<String> deleteAllDerivates() {
137            List<String> ids = MCRXMLTableManager.instance().retrieveAllIDs("derivate");
138            List<String> cmds = new ArrayList<String>(ids.size());
139            for (String id : ids) {
140                cmds.add("delete derivate " + id);
141            }
142            return cmds;
143        }
144    
145        /**
146         * Delete an MCRDerivate from the datastore.
147         * 
148         * @param ID
149         *            the ID of the MCRDerivate that should be deleted
150         */
151        public static void delete(String ID) {
152            MCRDerivate mycore_obj = new MCRDerivate();
153            mycore_obj.deleteFromDatastore(ID);
154            LOGGER.info(mycore_obj.getId().getId() + " deleted.");
155        }
156    
157        /**
158         * Delete MCRDerivates form ID to ID from the datastore.
159         * 
160         * @param IDfrom
161         *            the start ID for deleting the MCRDerivate
162         * @param IDto
163         *            the stop ID for deleting the MCRDerivate
164         */
165        public static void delete(String IDfrom, String IDto) {
166            int from_i = 0;
167            int to_i = 0;
168    
169            MCRObjectID from = new MCRObjectID(IDfrom);
170            MCRObjectID to = new MCRObjectID(IDto);
171            MCRObjectID now = new MCRObjectID(IDfrom);
172            from_i = from.getNumberAsInteger();
173            to_i = to.getNumberAsInteger();
174    
175            if (from_i > to_i) {
176                throw new MCRException("The from-to-interval is false.");
177            }
178    
179            for (int i = from_i; i < (to_i + 1); i++) {
180    
181                now.setNumber(i);
182                if (MCRObject.existInDatastore(now)) {
183                    delete(now.getId());
184                }
185            }
186        }
187    
188        /**
189         * Loads MCRDerivates from all XML files in a directory.
190         * 
191         * @param directory
192         *            the directory containing the XML files
193         */
194        public static List<String> loadFromDirectory(String directory) {
195            return processFromDirectory(directory, false);
196        }
197    
198        /**
199         * Updates MCRDerivates from all XML files in a directory.
200         * 
201         * @param directory
202         *            the directory containing the XML files
203         */
204        public static List<String> updateFromDirectory(String directory) {
205            return processFromDirectory(directory, true);
206        }
207    
208        /**
209         * Loads or updates MCRDerivates from all XML files in a directory.
210         * 
211         * @param directory
212         *            the directory containing the XML files
213         * @param update
214         *            if true, object will be updated, else object is created
215         */
216        private static List<String> processFromDirectory(String directory, boolean update) {
217            File dir = new File(directory);
218    
219            if (!dir.isDirectory()) {
220                LOGGER.warn(directory + " ignored, is not a directory.");
221                return null;
222            }
223    
224            String[] list = dir.list();
225    
226            if (list.length == 0) {
227                LOGGER.warn("No files found in directory " + directory);
228                return null;
229            }
230    
231            List<String> cmds = new ArrayList<String>();
232            for (String file : list)
233                if (file.endsWith(".xml") && file.contains("derivate"))
234                    cmds.add((update ? "update" : "load") + " derivate from file " + new File(dir, file).getAbsolutePath());
235    
236            return cmds;
237        }
238    
239        /**
240         * Loads an MCRDerivates from an XML file.
241         * 
242         * @param file
243         *            the location of the xml file
244         */
245        public static boolean loadFromFile(String file) {
246            return loadFromFile(file, true);
247        }
248    
249        /**
250         * Loads an MCRDerivates from an XML file.
251         * 
252         * @param file
253         *            the location of the xml file
254         * @param importMode
255         *            if true, servdates are taken from xml file
256         */
257        public static boolean loadFromFile(String file, boolean importMode) {
258            return processFromFile(new File(file), false, importMode);
259        }
260    
261        /**
262         * Updates an MCRDerivates from an XML file.
263         * 
264         * @param file
265         *            the location of the xml file
266         */
267        public static boolean updateFromFile(String file) {
268            return updateFromFile(file, true);
269        }
270    
271        /**
272         * Updates an MCRDerivates from an XML file.
273         * 
274         * @param file
275         *            the location of the xml file
276         * @param importMode
277         *            if true, servdates are taken from xml file
278         */
279        public static boolean updateFromFile(String file, boolean importMode) {
280            return processFromFile(new File(file), true, importMode);
281        }
282    
283        /**
284         * Loads or updates an MCRDerivates from an XML file.
285         * 
286         * @param file
287         *            the location of the xml file
288         * @param update
289         *            if true, object will be updated, else object is created
290         * @param importMode
291         *            if true, servdates are taken from xml file
292         */
293        private static boolean processFromFile(File file, boolean update, boolean importMode) {
294            if (!file.getName().endsWith(".xml")) {
295                LOGGER.warn(file + " ignored, does not end with *.xml");
296                return false;
297            }
298    
299            if (!file.isFile()) {
300                LOGGER.warn(file + " ignored, is not a file.");
301                return false;
302            }
303    
304            LOGGER.info("Reading file " + file + " ...");
305    
306            MCRDerivate mycore_obj = new MCRDerivate();
307            mycore_obj.setImportMode(importMode);
308            mycore_obj.setFromURI(file.toURI());
309    
310            // Replace relative path with absolute path of files
311            if (mycore_obj.getDerivate().getInternals() != null) {
312                String path = mycore_obj.getDerivate().getInternals().getSourcePath();
313                path = path.replace('/', File.separatorChar).replace('\\', File.separatorChar);
314                if (path.trim().length() <= 1)
315                    // the path is the path name plus the name of the derivate -
316                    path = mycore_obj.getId().getId().toLowerCase();
317                File sPath = new File(path);
318    
319                if (!sPath.isAbsolute()) {
320                    // only change path to absolute path when relative
321                    String prefix = file.getParent();
322    
323                    if (prefix != null) {
324                        path = prefix + File.separator + path;
325                    }
326                }
327    
328                mycore_obj.getDerivate().getInternals().setSourcePath(path);
329                LOGGER.info("Source path --> " + path);
330            }
331    
332            LOGGER.info("Label --> " + mycore_obj.getLabel());
333    
334            if (update) {
335                mycore_obj.updateInDatastore();
336                LOGGER.info(mycore_obj.getId().getId() + " updated.");
337                LOGGER.info("");
338            } else {
339                mycore_obj.createInDatastore();
340                LOGGER.info(mycore_obj.getId().getId() + " loaded.");
341                LOGGER.info("");
342            }
343    
344            return true;
345        }
346    
347        /**
348         * Save an MCRDerivate to a file named <em>MCRObjectID</em> .xml in a directory with <em>dirname</em> and store the derivate objects in a directory under them named <em>MCRObjectID</em>. The IFS-Attribute of the derivate files aren't saved, for reloading purpose after deleting a derivate in the datastore
349         * 
350         * @param ID
351         *            the ID of the MCRDerivate to be save.
352         * @param dirname
353         *            the dirname to store the derivate
354         */
355        public static void show(String ID, String dirname) {
356            export(ID, ID, dirname, "save");
357        }
358    
359        /**
360         * Save an MCRDerivate to a file named <em>MCRObjectID</em> .xml in a directory with <em>dirname</em> and store the derivate objects in a directory under them named <em>MCRObjectID</em>. The method use the converter stylesheet mcr_<em>style</em>_object.xsl.
361         * 
362         * @param ID
363         *            the ID of the MCRDerivate to be save.
364         * @param dirname
365         *            the dirname to store the derivate
366         * @param style
367         *            the type of the stylesheet
368         */
369        public static void export(String ID, String dirname, String style) {
370            export(ID, ID, dirname, style);
371        }
372    
373        /**
374         * Export any MCRDerivate's to files named <em>MCRObjectID</em> .xml in a directory and the objects under them named <em>MCRObjectID</em>. The saving starts with fromID and runs to toID. ID's they was not found will skiped. The method use the converter stylesheet mcr_<em>style</em>_object.xsl.
375         * 
376         * @param fromID
377         *            the ID of the MCRObject from be save.
378         * @param toID
379         *            the ID of the MCRObject to be save.
380         * @param dirname
381         *            the filename to store the object
382         * @param style
383         *            the type of the stylesheet
384         */
385        public static void export(String fromID, String toID, String dirname, String style) {
386            // check fromID and toID
387            MCRObjectID fid = null;
388            MCRObjectID tid = null;
389    
390            try {
391                fid = new MCRObjectID(fromID);
392            } catch (Exception ex) {
393                LOGGER.error("FromID : " + ex.getMessage());
394    
395                return;
396            }
397    
398            try {
399                tid = new MCRObjectID(toID);
400            } catch (Exception ex) {
401                LOGGER.error("ToID : " + ex.getMessage());
402    
403                return;
404            }
405    
406            // check dirname
407            File dir = new File(dirname);
408    
409            if (dir.isFile()) {
410                LOGGER.error(dirname + " is not a dirctory.");
411    
412                return;
413            }
414    
415            Transformer trans = getTransformer(style);
416    
417            MCRObjectID nid = fid;
418            int k = 0;
419    
420            try {
421                for (int i = fid.getNumberAsInteger(); i < (tid.getNumberAsInteger() + 1); i++) {
422                    nid.setNumber(i);
423    
424                    exportDerivate(dir, trans, nid);
425    
426                    k++;
427                }
428            } catch (Exception ex) {
429                LOGGER.error(ex.getMessage());
430                LOGGER.error("Exception while store file or objects to " + dir.getAbsolutePath(), ex);
431    
432                return;
433            }
434    
435            LOGGER.info(k + " Object's stored under " + dir.getAbsolutePath() + ".");
436        }
437    
438        public static List<String> exportAllDerivates(String dirname, String style) {
439            // check dirname
440            File dir = new File(dirname);
441    
442            if (dir.isFile()) {
443                throw new MCRException(dirname + " is not a dirctory.");
444            }
445    
446            List<String> ids = MCRXMLTableManager.instance().retrieveAllIDs("derivate");
447            List<String> cmds = new ArrayList<String>(ids.size());
448            for (String id : ids) {
449                cmds.add(new StringBuilder("export derivate ").append(id).append(" to directory ").append(dirname).append(" with ").append(style).toString());
450            }
451            return cmds;
452        }
453    
454        /**
455         * @param dirname
456         * @param dir
457         * @param trans
458         * @param nid
459         * @throws FileNotFoundException
460         * @throws TransformerException
461         * @throws IOException
462         */
463        private static void exportDerivate(File dir, Transformer trans, MCRObjectID nid) throws FileNotFoundException, TransformerException, IOException {
464            // store the XML file
465            MCRDerivate obj = new MCRDerivate();
466            Document xml = null;
467    
468            try {
469                obj.receiveFromDatastore(nid.toString());
470                String path = obj.getDerivate().getInternals().getSourcePath();
471                // reset from the absolute to relative path, for later reload
472                LOGGER.info("Old Internal Path ====>" + path);
473                obj.getDerivate().getInternals().setSourcePath(nid.toString());
474                LOGGER.info("New Internal Path ====>" + nid.toString());
475                // add ACL's
476                Collection<String> l = ACCESS_IMPL.getPermissionsForID(nid.toString());
477                for (String permission : l) {
478                    Element rule = ACCESS_IMPL.getRule(nid.toString(), permission);
479                    obj.getService().addRule(permission, rule);
480                }
481                // build JDOM
482                xml = obj.createXML();
483    
484            } catch (MCRException ex) {
485                LOGGER.warn("Could not read " + nid.toString() + ", continue with next ID");
486                return;
487            }
488            File xmlOutput = new File(dir, nid.toString() + ".xml");
489            FileOutputStream out = new FileOutputStream(xmlOutput);
490            dir = new File(dir, nid.toString());
491    
492            if (trans != null) {
493                trans.setParameter("dirname", dir.getPath());
494                StreamResult sr = new StreamResult(out);
495                trans.transform(new org.jdom.transform.JDOMSource(xml), sr);
496            } else {
497                new org.jdom.output.XMLOutputter().output(xml, out);
498                out.flush();
499                out.close();
500            }
501    
502            LOGGER.info("Object " + nid.toString() + " stored under " + xmlOutput + ".");
503    
504            // store the derivate file under dirname
505            try {
506    
507                if (!dir.isDirectory()) {
508                    dir.mkdir();
509                }
510    
511                MCRFileImportExport.exportFiles(obj.receiveDirectoryFromIFS(nid.toString()), dir);
512            } catch (MCRException ex) {
513                LOGGER.error(ex.getMessage());
514                LOGGER.error("Exception while store to object in " + dir.getAbsolutePath());
515                return;
516            }
517    
518            LOGGER.info("Derivate " + nid.toString() + " saved under " + dir.toString() + " and " + xmlOutput.toString() + ".");
519        }
520    
521        /**
522         * @param style
523         * @return
524         * @throws TransformerFactoryConfigurationError
525         */
526        private static Transformer getTransformer(String style) throws TransformerFactoryConfigurationError {
527            String xslfile = DEFAULT_TRANSFORMER;
528            if ((style != null) && (style.trim().length() != 0)) {
529                xslfile = style + "-derivate.xsl";
530            }
531            Transformer trans = null;
532    
533            try {
534                InputStream in = MCRDerivateCommands.class.getResourceAsStream("/" + xslfile);
535    
536                if (in != null) {
537                    StreamSource source = new StreamSource(in);
538                    TransformerFactory transfakt = TransformerFactory.newInstance();
539                    transfakt.setURIResolver(MCRURIResolver.instance());
540                    trans = transfakt.newTransformer(source);
541                }
542            } catch (Exception e) {
543                LOGGER.debug("Cannot build Transformer.", e);
544            }
545            return trans;
546        }
547    
548        /**
549         * The method start the repair the content search index for all derivates.
550         */
551        public static List<String> repairDerivateSearch() {
552            LOGGER.info("Start the repair for type derivate.");
553            List<String> ids = MCRXMLTableManager.instance().retrieveAllIDs("derivate");
554            if (ids.size() == 0) {
555                LOGGER.warn("No ID's was found for type derivate.");
556                return Collections.emptyList();
557            }
558            List<String> cmds = new ArrayList<String>(ids.size());
559            for (String id : ids) {
560                cmds.add("repair derivate search of ID " + id);
561            }
562            return cmds;
563        }
564    
565        /**
566         * The method start the repair the content search index for one.
567         * 
568         * @param id
569         *            the MCRObjectID as String
570         */
571        public static void repairDerivateSearchForID(String id) {
572            LOGGER.info("Start the repair for the ID " + id);
573    
574            MCRObjectID mid = null;
575    
576            try {
577                mid = new MCRObjectID(id);
578            } catch (Exception e) {
579                LOGGER.error("The String " + id + " is not a MCRObjectID.");
580                LOGGER.error(" ");
581    
582                return;
583            }
584    
585            MCRDerivate der = new MCRDerivate();
586            der.repairPersitenceDatastore(mid);
587            LOGGER.info("Repaired " + mid.getId());
588            LOGGER.info(" ");
589        }
590    
591        /**
592         * The method start the repair the content search index for all derivates.
593         */
594        public static List<String> synchronizeAllDerivates() {
595            LOGGER.info("Start the synchronization for derivates.");
596            List<String> ids = MCRXMLTableManager.instance().retrieveAllIDs("derivate");
597            if (ids.size() == 0) {
598                LOGGER.warn("No ID's was found for type derivate.");
599                return Collections.emptyList();
600            }
601            List<String> cmds = new ArrayList<String>(ids.size());
602            for (String id : ids) {
603                cmds.add("synchronize derivate with ID " + id);
604            }
605            return cmds;
606        }
607    
608        /**
609         * The method sychronize the xlink:label of the mycorederivate with the xlink:label of the derivate refernce of mycoreobject.
610         * 
611         * @param id
612         *            the MCRObjectID as String
613         */
614        public static void synchronizeDerivateForID(String id) {
615            MCRObjectID mid = null;
616            try {
617                mid = new MCRObjectID(id);
618            } catch (Exception e) {
619                LOGGER.error("The String " + id + " is not a MCRObjectID.");
620                return;
621            }
622    
623            // set mycoreobject
624            MCRDerivate der = new MCRDerivate();
625            der.receiveFromDatastore(mid);
626            String label = der.getLabel();
627            String href = der.getDerivate().getMetaLink().getXLinkHref();
628            MCRObject obj = new MCRObject();
629            obj.receiveFromDatastore(href);
630            int size = obj.getStructure().getDerivateSize();
631            boolean isset = false;
632            for (int i = 0; i < size; i++) {
633                MCRMetaLinkID link = obj.getStructure().getDerivate(i);
634                if (link.getXLinkHref().equals(mid.getId())) {
635                    String oldlabel = link.getXLinkLabel();
636                    if ((oldlabel != null) && (!oldlabel.trim().equals(label))) {
637                        obj.getStructure().getDerivate(i).setXLinkLabel(label);
638                        isset = true;
639                    }
640                    break;
641                }
642            }
643            // update mycoreobject
644            if (isset) {
645                obj.updateThisInDatastore();
646                LOGGER.info("Synchronized " + mid.getId());
647            }
648        }
649    
650    }