001    /*
002     * $Revision: 15621 $ $Date: 2009-07-25 08:32:01 +0200 (Sat, 25 Jul 2009) $ This file is part of M y C o R e See http://www.mycore.de/ for details. This program
003     * is free software; you can use it, redistribute it and / or modify it under the terms of the GNU General Public License (GPL) as published by the Free
004     * Software Foundation; either version 2 of the License or (at your option) any later version. This program is distributed in the hope that it will be useful,
005     * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
006     * more details. You should have received a copy of the GNU General Public License along with this program, in a file called gpl.txt or license.txt. If not,
007     * write to the Free Software Foundation Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
008     */
009    
010    package org.mycore.frontend.cli;
011    
012    import java.io.File;
013    import java.io.FileNotFoundException;
014    import java.io.FileOutputStream;
015    import java.io.IOException;
016    import java.io.InputStream;
017    import java.util.ArrayList;
018    import java.util.Collections;
019    import java.util.Hashtable;
020    import java.util.List;
021    
022    import javax.xml.transform.Transformer;
023    import javax.xml.transform.TransformerConfigurationException;
024    import javax.xml.transform.TransformerException;
025    import javax.xml.transform.TransformerFactory;
026    import javax.xml.transform.TransformerFactoryConfigurationError;
027    import javax.xml.transform.stream.StreamResult;
028    import javax.xml.transform.stream.StreamSource;
029    
030    import org.apache.log4j.Logger;
031    
032    import org.mycore.common.MCRException;
033    import org.mycore.common.MCRSessionMgr;
034    import org.mycore.common.xml.MCRURIResolver;
035    import org.mycore.common.xml.MCRXMLHelper;
036    import org.mycore.datamodel.common.MCRActiveLinkException;
037    import org.mycore.datamodel.metadata.MCRObject;
038    import org.mycore.datamodel.metadata.MCRObjectID;
039    import org.mycore.datamodel.common.MCRXMLTableManager;
040    
041    import org.mycore.parsers.bool.MCRCondition;
042    import org.mycore.services.fieldquery.MCRFieldDef;
043    import org.mycore.services.fieldquery.MCRFieldValue;
044    import org.mycore.services.fieldquery.MCRQuery;
045    import org.mycore.services.fieldquery.MCRQueryManager;
046    import org.mycore.services.fieldquery.MCRQueryParser;
047    import org.mycore.services.fieldquery.MCRHit;
048    import org.mycore.services.fieldquery.MCRResults;
049    import org.mycore.services.fieldquery.MCRSearcher;
050    import org.mycore.services.fieldquery.MCRSearcherFactory;
051    
052    /**
053     * Provides static methods that implement commands for the MyCoRe command line interface.
054     * 
055     * @author Jens Kupferschmidt
056     * @author Frank Luetzenkirchen
057     * @version $Revision: 15621 $ $Date: 2009-07-25 08:32:01 +0200 (Sat, 25 Jul 2009) $
058     */
059    public class MCRObjectCommands extends MCRAbstractCommands {
060        /** The logger */
061        private static Logger LOGGER = Logger.getLogger(MCRObjectCommands.class.getName());
062    
063        /** Default transformer script */
064        public static final String DEFAULT_TRANSFORMER = "save-object.xsl";
065    
066        /** static compiled transformer stylesheets */
067        private static Hashtable<String, javax.xml.transform.Transformer> translist = new Hashtable<String, javax.xml.transform.Transformer>();
068    
069        /**
070         * The empty constructor.
071         */
072        public MCRObjectCommands() {
073            super();
074    
075            MCRCommand com = null;
076    
077            com = new MCRCommand("delete all objects of type {0}", "org.mycore.frontend.cli.MCRObjectCommands.deleteAllObjects String",
078                    "Removes MCRObjects in the number range between the MCRObjectID {0} and {1}.");
079            command.add(com);
080    
081            com = new MCRCommand("delete object from {0} to {1}", "org.mycore.frontend.cli.MCRObjectCommands.deleteFromTo String String",
082                    "Removes MCRObjects in the number range between the MCRObjectID {0} and {1}.");
083            command.add(com);
084    
085            com = new MCRCommand("delete object {0}", "org.mycore.frontend.cli.MCRObjectCommands.delete String",
086                    "Removes a MCRObject with the MCRObjectID {0}");
087            command.add(com);
088    
089            com = new MCRCommand("load object from file {0}", "org.mycore.frontend.cli.MCRObjectCommands.loadFromFile String",
090                    "Adds a MCRObject form the file {0} to the system.");
091            command.add(com);
092    
093            com = new MCRCommand("load all objects from directory {0}", "org.mycore.frontend.cli.MCRObjectCommands.loadFromDirectory String",
094                    "Loads all MCRObjects form the directory {0} to the system.");
095            command.add(com);
096    
097            com = new MCRCommand("update object from file {0}", "org.mycore.frontend.cli.MCRObjectCommands.updateFromFile String",
098                    "Updates a MCRObject form the file {0} in the system.");
099            command.add(com);
100    
101            com = new MCRCommand("update all objects from directory {0}",
102                    "org.mycore.frontend.cli.MCRObjectCommands.updateFromDirectory String",
103                    "Updates all MCRObjects form the directory {0} in the system.");
104            command.add(com);
105    
106            com = new MCRCommand(
107                    "export object from {0} to {1} to directory {2} with {3}",
108                    "org.mycore.frontend.cli.MCRObjectCommands.export String String String String",
109                    "Stores all MCRObjects with MCRObjectID's between {0} and {1} to the directory {2} with the stylesheet {3}-object.xsl. For {3} save is the default.");
110            command.add(com);
111    
112            com = new MCRCommand("export object {0} to directory {1} with {2}",
113                    "org.mycore.frontend.cli.MCRObjectCommands.export String String String",
114                    "Stores the MCRObject with the MCRObjectID {0} to the directory {1} with the stylesheet {2}-object.xsl. For {2} save is the default.");
115            command.add(com);
116    
117            com = new MCRCommand("export all objects of type {0} to directory {1} with {2}",
118                    "org.mycore.frontend.cli.MCRObjectCommands.exportAllObjects String String String",
119                    "Stores all MCRObjects of type {0} to directory {1} with the stylesheet mcr_{2}-object.xsl. For {2} save is the default.");
120            command.add(com);
121    
122            com = new MCRCommand("get last ID for base {0}", "org.mycore.frontend.cli.MCRObjectCommands.getLastID String",
123                    "Returns the last used MCRObjectID for the ID base {0}.");
124            command.add(com);
125    
126            com = new MCRCommand("get next ID for base {0}", "org.mycore.frontend.cli.MCRObjectCommands.getNextID String",
127                    "Returns the next free MCRObjectID for the ID base {0}.");
128            command.add(com);
129    
130            com = new MCRCommand("check file {0}", "org.mycore.frontend.cli.MCRObjectCommands.checkXMLFile String",
131                    "Checks the data file {0} against the XML Schema.");
132            command.add(com);
133    
134            com = new MCRCommand("repair metadata search of type {0}", "org.mycore.frontend.cli.MCRObjectCommands.repairMetadataSearch String",
135                    "Reads the SQL store table of MCRObject XML files for the type {0} and restore them to the search store.");
136            command.add(com);
137    
138            com = new MCRCommand("repair metadata search of ID {0}",
139                    "org.mycore.frontend.cli.MCRObjectCommands.repairMetadataSearchForID String",
140                    "Read the SQL store table of MCRObject XML files with MCRObjectID {0} and restore them to the search store.");
141            command.add(com);
142    
143            com = new MCRCommand("select objects with query {0}", "org.mycore.frontend.cli.MCRObjectCommands.selectObjectsWithQuery String",
144                    "Select MCRObjects with MCRQueryString {0}.");
145            command.add(com);
146    
147            com = new MCRCommand("delete selected", "org.mycore.frontend.cli.MCRObjectCommands.deleteSelected", "Removes selected MCRObjects.");
148            command.add(com);
149    
150            com = new MCRCommand("export selected to directory {0} with {1}",
151                    "org.mycore.frontend.cli.MCRObjectCommands.exportSelected String String",
152                    "Stores selected MCRObjects to the directory {0} with the stylesheet {1}-object.xsl. For {1} save is the default.");
153            command.add(com);
154    
155            com = new MCRCommand("remove selected from searchindex {0}",
156                    "org.mycore.frontend.cli.MCRObjectCommands.removeFromSearchindex String",
157                    "Remove selected MCRObjects from searchindex {0}.");
158            command.add(com);
159    
160            com = new MCRCommand("check selected in sql store", "org.mycore.frontend.cli.MCRObjectCommands.checkSelected",
161                    "Checks existence of selected MCRObjects in SQL store and deletes missing ones from search index.");
162            command.add(com);
163    
164            com = new MCRCommand("check metadata search of type {0}", "org.mycore.frontend.cli.MCRObjectCommands.checkMetadataSearch String",
165                    "Checks existence of MCRObjects of type {0} in search index and rapairs missing ones in search index.");
166            command.add(com);
167    
168            com = new MCRCommand("set mode {0} of searcher for index {1}",
169                    "org.mycore.frontend.cli.MCRObjectCommands.notifySearcher String String",
170                    "Notify Searcher of Index {1} what is going on {0}.");
171            command.add(com);
172        }
173    
174        public static void setSelectedObjectIDs(List<String> selected) {
175            MCRSessionMgr.getCurrentSession().put("mcrSelectedObjects", selected);
176        }
177    
178        @SuppressWarnings("unchecked")
179        public static List<String> getSelectedObjectIDs() {
180            final List<String> list = (List<String>) MCRSessionMgr.getCurrentSession().get("mcrSelectedObjects");
181            if (list == null) {
182                return Collections.EMPTY_LIST;
183            }
184            return list;
185        }
186    
187        /**
188         * Delete all MCRObject from the datastore for a given type.
189         * 
190         * @param type
191         *            the type of the MCRObjects that should be deleted
192         */
193        public static final List<String> deleteAllObjects(String type) throws MCRActiveLinkException {
194            final List<String> objectIds = MCRXMLTableManager.instance().retrieveAllIDs(type);
195            List<String> cmds = new ArrayList<String>(objectIds.size());
196            for (String id : objectIds) {
197                cmds.add("delete object " + id);
198            }
199            return cmds;
200        }
201    
202        /**
203         * Delete a MCRObject from the datastore.
204         * 
205         * @param ID
206         *            the ID of the MCRObject that should be deleted
207         */
208        public static final void delete(String ID) throws MCRActiveLinkException {
209            MCRObject mycore_obj = new MCRObject();
210    
211            try {
212                mycore_obj.deleteFromDatastore(ID);
213                LOGGER.info(mycore_obj.getId().getId() + " deleted.");
214            } catch (MCRException ex) {
215                LOGGER.error("Can't delete " + mycore_obj.getId().getId() + ".", ex);
216            }
217        }
218    
219        /**
220         * Delete MCRObject's form ID to ID from the datastore.
221         * 
222         * @param IDfrom
223         *            the start ID for deleting the MCRObjects
224         * @param IDto
225         *            the stop ID for deleting the MCRObjects
226         */
227        public static final void deleteFromTo(String IDfrom, String IDto) throws MCRActiveLinkException {
228            int from_i = 0;
229            int to_i = 0;
230    
231            try {
232                MCRObjectID from = new MCRObjectID(IDfrom);
233                MCRObjectID to = new MCRObjectID(IDto);
234                MCRObjectID now = new MCRObjectID(IDfrom);
235                from_i = from.getNumberAsInteger();
236                to_i = to.getNumberAsInteger();
237    
238                if (from_i > to_i) {
239                    throw new MCRException("The from-to-interval is false.");
240                }
241    
242                for (int i = from_i; i < (to_i + 1); i++) {
243                    now.setNumber(i);
244                    if (MCRObject.existInDatastore(now)) {
245                        delete(now.getId());
246                    }
247                }
248            } catch (MCRException ex) {
249                LOGGER.debug(ex.getStackTraceAsString());
250                LOGGER.error(ex.getMessage());
251            }
252        }
253    
254        /**
255         * Load MCRObject's from all XML files in a directory.
256         * 
257         * @param directory
258         *            the directory containing the XML files
259         * @throws MCRActiveLinkException
260         */
261        public static final List<String> loadFromDirectory(String directory) throws MCRActiveLinkException {
262            return processFromDirectory(directory, false);
263        }
264    
265        /**
266         * Update MCRObject's from all XML files in a directory.
267         * 
268         * @param directory
269         *            the directory containing the XML files
270         * @throws MCRActiveLinkException
271         */
272        public static final List<String> updateFromDirectory(String directory) throws MCRActiveLinkException {
273            return processFromDirectory(directory, true);
274        }
275    
276        /**
277         * Load or update MCRObject's from all XML files in a directory.
278         * 
279         * @param directory
280         *            the directory containing the XML files
281         * @param update
282         *            if true, object will be updated, else object is created
283         * @throws MCRActiveLinkException
284         */
285        private static final List<String> processFromDirectory(String directory, boolean update) throws MCRActiveLinkException {
286            File dir = new File(directory);
287    
288            if (!dir.isDirectory()) {
289                LOGGER.warn(directory + " ignored, is not a directory.");
290                return null;
291            }
292    
293            String[] list = dir.list();
294    
295            if (list.length == 0) {
296                LOGGER.warn("No files found in directory " + directory);
297                return null;
298            }
299    
300            List<String> cmds = new ArrayList<String>();
301            for (String file : list)
302                if (file.endsWith(".xml") && (!file.contains("derivate")))
303                    cmds.add((update ? "update" : "load") + " object from file " + new File(dir, file).getAbsolutePath());
304    
305            return cmds;
306        }
307    
308        /**
309         * Load a MCRObjects from an XML file.
310         * 
311         * @param file
312         *            the location of the xml file
313         * @throws MCRActiveLinkException
314         */
315        public static final boolean loadFromFile(String file) throws MCRActiveLinkException {
316            return loadFromFile(file, true);
317        }
318    
319        /**
320         * Load a MCRObjects from an XML file.
321         * 
322         * @param file
323         *            the location of the xml file
324         * @param importMode
325         *            if true, servdates are taken from xml file
326         * @throws MCRActiveLinkException
327         */
328        public static final boolean loadFromFile(String file, boolean importMode) throws MCRActiveLinkException {
329            return processFromFile(new File(file), false, importMode);
330        }
331    
332        /**
333         * Update a MCRObject's from an XML file.
334         * 
335         * @param file
336         *            the location of the xml file
337         * @throws MCRActiveLinkException
338         */
339        public static final boolean updateFromFile(String file) throws MCRActiveLinkException {
340            return updateFromFile(file, true);
341        }
342    
343        /**
344         * Update a MCRObject's from an XML file.
345         * 
346         * @param file
347         *            the location of the xml file
348         * @param importMode
349         *            if true, servdates are taken from xml file
350         * @throws MCRActiveLinkException
351         */
352        public static final boolean updateFromFile(String file, boolean importMode) throws MCRActiveLinkException {
353            return processFromFile(new File(file), true, importMode);
354        }
355    
356        /**
357         * Load or update an MCRObject's from an XML file.
358         * 
359         * @param file
360         *            the location of the xml file
361         * @param update
362         *            if true, object will be updated, else object is created
363         * @param importMode
364         *            if true, servdates are taken from xml file
365         * @throws MCRActiveLinkException
366         */
367        private static final boolean processFromFile(File file, boolean update, boolean importMode) throws MCRActiveLinkException {
368            if (!file.getName().endsWith(".xml")) {
369                LOGGER.warn(file + " ignored, does not end with *.xml");
370                return false;
371            }
372    
373            if (!file.isFile()) {
374                LOGGER.warn(file + " ignored, is not a file.");
375                return false;
376            }
377    
378            LOGGER.info("Reading file " + file + " ...");
379    
380            MCRObject mycore_obj = new MCRObject();
381            mycore_obj.setImportMode(importMode);
382            mycore_obj.setFromURI(file.toURI());
383            LOGGER.debug("Label --> " + mycore_obj.getLabel());
384    
385            if (update) {
386                mycore_obj.updateInDatastore();
387                LOGGER.info(mycore_obj.getId().getId() + " updated.");
388            } else {
389                mycore_obj.createInDatastore();
390                LOGGER.info(mycore_obj.getId().getId() + " loaded.");
391            }
392    
393            return true;
394        }
395    
396        /**
397         * Shows the next free MCRObjectIDs.
398         * 
399         * @param base
400         *            the base String of the MCRObjectID
401         */
402        public static final void showNextID(String base) {
403            MCRObjectID mcr_id = new MCRObjectID();
404    
405            try {
406                mcr_id.setNextFreeId(base);
407                LOGGER.info("The next free ID  is " + mcr_id.getId());
408            } catch (MCRException ex) {
409                LOGGER.error(ex.getMessage());
410            }
411        }
412    
413        /**
414         * Shows the last used MCRObjectIDs.
415         * 
416         * @param base
417         *            the base String of the MCRObjectID
418         */
419        public static final void showLastID(String base) {
420            MCRObjectID mcr_id = new MCRObjectID();
421    
422            try {
423                mcr_id.setNextFreeId(base);
424                mcr_id.setNumber(mcr_id.getNumberAsInteger() - 1);
425                LOGGER.info("The last used ID  is " + mcr_id.getId());
426            } catch (MCRException ex) {
427                LOGGER.error(ex.getMessage());
428            }
429        }
430    
431        /**
432         * Export an MCRObject to a file named <em>MCRObjectID</em> .xml in a directory. The method use the converter stylesheet mcr_<em>style</em>_object.xsl.
433         * 
434         * @param ID
435         *            the ID of the MCRObject to be save.
436         * @param dirname
437         *            the dirname to store the object
438         * @param style
439         *            the type of the stylesheet
440         */
441        public static final void export(String ID, String dirname, String style) {
442            export(ID, ID, dirname, style);
443        }
444    
445        /**
446         * Save any MCRObject's to files named <em>MCRObjectID</em> .xml in a directory. The saving starts with fromID and runs to toID. ID's they was not found
447         * will skiped. The method use the converter stylesheet mcr_<em>style</em>_object.xsl.
448         * 
449         * @param fromID
450         *            the ID of the MCRObject from be save.
451         * @param toID
452         *            the ID of the MCRObject to be save.
453         * @param dirname
454         *            the filename to store the object
455         * @param style
456         *            the type of the stylesheet
457         */
458        public static final void export(String fromID, String toID, String dirname, String style) {
459            MCRObjectID fid, tid;
460    
461            // check fromID and toID
462            try {
463                fid = new MCRObjectID(fromID);
464                tid = new MCRObjectID(toID);
465            } catch (Exception ex) {
466                LOGGER.error("FromID : " + ex.getMessage());
467                return;
468            }
469            // check dirname
470            File dir = new File(dirname);
471            if (!dir.isDirectory()) {
472                LOGGER.error(dirname + " is not a dirctory.");
473                return;
474            }
475    
476            MCRObjectID nid = fid;
477            int k = 0;
478            try {
479                Transformer trans = getTransformer(style);
480                for (int i = fid.getNumberAsInteger(); i < (tid.getNumberAsInteger() + 1); i++) {
481                    nid.setNumber(i);
482                    if (!MCRObject.existInDatastore(nid)) {
483                        continue;
484                    }
485                    if (!exportMCRObject(dir, trans, nid)) {
486                        continue;
487                    }
488                    k++;
489                }
490            } catch (Exception ex) {
491                LOGGER.error(ex.getMessage());
492                LOGGER.error("Exception while store file to " + dir.getAbsolutePath());
493                return;
494            }
495            LOGGER.info(k + " Object's stored under " + dir.getAbsolutePath() + ".");
496        }
497    
498        /**
499         * Save all MCRObject's to files named <em>MCRObjectID</em> .xml in a <em>dirname</em>directory for the data type <em>type</em>. The method use the
500         * converter stylesheet mcr_<em>style</em>_object.xsl.
501         * 
502         * @param fromID
503         *            the ID of the MCRObject from be save.
504         * @param toID
505         *            the ID of the MCRObject to be save.
506         * @param dirname
507         *            the filename to store the object
508         * @param style
509         *            the type of the stylesheet
510         */
511        public static final List<String> exportAllObjects(String type, String dirname, String style) {
512            // check dirname
513            File dir = new File(dirname);
514    
515            if (dir.isFile()) {
516                LOGGER.error(dirname + " is not a dirctory.");
517                return Collections.emptyList();
518            }
519            List<String> objectIds = MCRXMLTableManager.instance().retrieveAllIDs(type);
520            List<String> cmds = new ArrayList<String>(objectIds.size());
521            for (String id : objectIds) {
522                cmds.add(new StringBuilder("export object from ").append(id).append(" to ").append(id).append(" to directory ").append(dirname)
523                        .append(" with ").append(style).toString());
524            }
525            return cmds;
526        }
527    
528        /**
529         * The method search for a stylesheet mcr_<em>style</em>_object.xsl and build the transformer. Default is <em>mcr_save-object.xsl</em>.
530         * 
531         * @param style
532         *            the style attribute for the transformer stylesheet
533         * @return the transformer
534         * @throws TransformerFactoryConfigurationError
535         * @throws TransformerConfigurationException
536         */
537        private static final Transformer getTransformer(String style) throws TransformerFactoryConfigurationError,
538                TransformerConfigurationException {
539            String xslfile = DEFAULT_TRANSFORMER;
540            if ((style != null) && (style.trim().length() != 0)) {
541                xslfile = style + "-object.xsl";
542            }
543            Transformer trans = translist.get(xslfile);
544            if (trans != null) {
545                return trans;
546            }
547            LOGGER.debug("Will load transformer stylesheet " + xslfile + "for export.");
548    
549            InputStream in = MCRObjectCommands.class.getResourceAsStream("/" + xslfile);
550            if (in == null) {
551                in = MCRObjectCommands.class.getResourceAsStream("/xsl/" + DEFAULT_TRANSFORMER);
552            }
553            try {
554                if (in != null) {
555                    StreamSource source = new StreamSource(in);
556                    TransformerFactory transfakt = TransformerFactory.newInstance();
557                    transfakt.setURIResolver(MCRURIResolver.instance());
558                    trans = transfakt.newTransformer(source);
559                    translist.put(xslfile, trans);
560                    return trans;
561                } else {
562                    LOGGER.warn("Can't load transformer ressource " + xslfile + " or " + DEFAULT_TRANSFORMER + ".");
563                }
564            } catch (Exception e) {
565                LOGGER.warn("Error while load transformer ressource " + xslfile + " or " + DEFAULT_TRANSFORMER + ".");
566                if (LOGGER.isDebugEnabled()) {
567                    e.printStackTrace();
568                }
569            }
570            return null;
571        }
572    
573        /**
574         * The method read a MCRObject and use the transformer to write the data to a file. They are any steps to handel errors and save the damaged data.
575         * <ul>
576         * <li>Read data for object ID in the MCRObject, add ACL's and store it as checked and transformed XML. Return true.</li>
577         * <li>If it can't find a transformer instance (no script file found) it store the checked data with ACL's native in the file. Warning and return true.</li>
578         * <li>If it get an exception while build the MCRObject, it try to read the XML blob and stor it without check and ACL's to the file. Warning and return
579         * true.</li>
580         * <li>If it get an exception while store the native data without check, ACĂ–'s and transformation it return a warning and false.</li>
581         * </ul>
582         * 
583         * @param dir
584         *            the file instance to store
585         * @param trans
586         *            the XML transformer
587         * @param nid
588         *            the MCRObjectID
589         * @return true if the store was okay (see description), else return false
590         * @throws FileNotFoundException
591         * @throws TransformerException
592         * @throws IOException
593         */
594        private static final boolean exportMCRObject(File dir, Transformer trans, MCRObjectID nid) throws FileNotFoundException,
595                TransformerException, IOException {
596            byte[] xml = null;
597            try {
598                // if object do'snt exist - no exception is catched!
599                xml = MCRObject.receiveXMLFromDatastore(nid.toString());
600            } catch (MCRException ex) {
601                return false;
602            }
603    
604            File xmlOutput = new File(dir, nid.toString() + ".xml");
605            FileOutputStream out = new FileOutputStream(xmlOutput);
606    
607            if (trans != null) {
608                StreamResult sr = new StreamResult(out);
609                trans.transform(new org.jdom.transform.JDOMSource(MCRXMLHelper.parseXML(xml, false)), sr);
610            } else {
611                out.write(xml);
612                out.flush();
613            }
614            LOGGER.info("Object " + nid.toString() + " saved to " + xmlOutput.getCanonicalPath() + ".");
615            return true;
616        }
617    
618        /**
619         * Get the next free MCRObjectID for the given MCRObjectID base.
620         * 
621         * @param base
622         *            the MCRObjectID base string
623         */
624        public static final void getNextID(String base) {
625            MCRObjectID id = new MCRObjectID();
626    
627            try {
628                id.setNextFreeId(base);
629                LOGGER.info(id.getId());
630            } catch (MCRException ex) {
631                LOGGER.error(ex.getMessage());
632            }
633        }
634    
635        /**
636         * Get the last used MCRObjectID for the given MCRObjectID base.
637         * 
638         * @param base
639         *            the MCRObjectID base string
640         */
641        public static final void getLastID(String base) {
642            LOGGER.info(MCRObjectID.getLastID(base).getId());
643        }
644    
645        /**
646         * The method parse and check an XML file.
647         * 
648         * @param fileName
649         *            the location of the xml file
650         */
651        public static final boolean checkXMLFile(String fileName) {
652            if (!fileName.endsWith(".xml")) {
653                LOGGER.warn(fileName + " ignored, does not end with *.xml");
654    
655                return false;
656            }
657    
658            File file = new File(fileName);
659    
660            if (!file.isFile()) {
661                LOGGER.warn(fileName + " ignored, is not a file.");
662    
663                return false;
664            }
665    
666            LOGGER.info("Reading file " + file + " ...");
667    
668            if (MCRXMLHelper.parseURI(file.toURI()) != null) {
669                LOGGER.info("The file has no XML errors.");
670            }
671    
672            return true;
673        }
674    
675        /**
676         * The method start the repair of the metadata search for a given MCRObjectID type.
677         * 
678         * @param type
679         *            the MCRObjectID type
680         */
681        public static final List<String> repairMetadataSearch(String type) {
682            LOGGER.info("Start the repair for type " + type);
683            String typetest = CONFIG.getString("MCR.Metadata.Type." + type, "");
684    
685            if (typetest.length() == 0) {
686                LOGGER.error("The type " + type + " was not found.");
687                return Collections.emptyList();
688            }
689            List<String> ar = (List<String>) MCRXMLTableManager.instance().retrieveAllIDs(type);
690            if (ar.size() == 0) {
691                LOGGER.warn("No ID's was found for type " + type + ".");
692                return Collections.emptyList();
693            }
694    
695            removeFromIndex("objectType", type);
696            List<String> cmds = new ArrayList<String>(ar.size());
697    
698            for (String stid : ar) {
699                cmds.add("repair metadata search of ID " + stid);
700            }
701            return cmds;
702    
703        }
704    
705        /**
706         * The method start the repair of the metadata search for a given MCRObjectID as String.
707         * 
708         * @param id
709         *            the MCRObjectID as String
710         */
711        public static final void repairMetadataSearchForID(String id) {
712            LOGGER.info("Start the repair for the ID " + id);
713    
714            MCRObjectID mid = null;
715    
716            try {
717                mid = new MCRObjectID(id);
718            } catch (Exception e) {
719                LOGGER.error("The String " + id + " is not a MCRObjectID.");
720                return;
721            }
722    
723            removeFromIndex("id", id);
724    
725            MCRObject obj = new MCRObject();
726            obj.repairPersitenceDatastore(mid);
727            LOGGER.info("Repaired " + mid.getId());
728        }
729    
730        /**
731         * The method removes entries from searchindex.
732         * 
733         * @param fieldname
734         *            Name of field used to delete entries
735         * @param value
736         *            Value of the field
737         */
738        private static final void removeFromIndex(String fieldname, String value) {
739            MCRFieldDef fd = MCRFieldDef.getDef(fieldname);
740            MCRSearcher searcher = getSearcherForField(fieldname);
741            MCRFieldValue fv = new MCRFieldValue(fd, value);
742            searcher.clearIndex(fieldname, fv.getValue());
743        }
744    
745        private static final MCRSearcher getSearcherForField(String fieldname) {
746            MCRFieldDef fd = MCRFieldDef.getDef(fieldname);
747            String index = fd.getIndex();
748            return MCRSearcherFactory.getSearcherForIndex(index);
749        }
750    
751        /**
752         * Builds a resulset with a query. Used in later command to do work with.
753         * 
754         * @param querystring
755         *            MCRQuery as String
756         */
757        public static final void selectObjectsWithQuery(String querystring) {
758            LOGGER.info("Build Resultset with query " + querystring);
759    
760            MCRCondition cond = (new MCRQueryParser()).parse(querystring);
761            MCRQuery query = new MCRQuery(cond);
762            final MCRResults results = MCRQueryManager.search(query);
763            ArrayList<String> ids = new ArrayList<String>(results.getNumHits());
764            for (MCRHit hit : results) {
765                ids.add(hit.getID());
766            }
767            setSelectedObjectIDs(ids);
768    
769            LOGGER.info("Resultset built");
770        }
771    
772        /**
773         * Delete all selected MCRObjects from the datastore.
774         */
775        public static final void deleteSelected() throws MCRActiveLinkException {
776            LOGGER.info("Start removing selected MCRObjects");
777    
778            if (null == getSelectedObjectIDs()) {
779                LOGGER.info("No Resultset to work with, use command \"select objects with query {0}\" to build one");
780                return;
781            }
782            for (String id : getSelectedObjectIDs()) {
783                delete(id);
784            }
785            LOGGER.info("Selected MCRObjects deleted");
786        }
787    
788        /*
789         * Export selected MCRObjects to a file named <em>MCRObjectID</em> .xml in a directory. The method use the converter stylesheet
790         * mcr_<em>style</em>_object.xsl.
791         * @param dirname the dirname to store the object @param style the type of the stylesheet
792         */
793        public static final List<String> exportSelected(String dirname, String style) {
794            LOGGER.info("Start exporting selected MCRObjects");
795    
796            if (null == getSelectedObjectIDs()) {
797                LOGGER.info("No Resultset to work with, use command \"select objects with query {0}\" to build one");
798                return Collections.emptyList();
799            }
800            List<String> cmds = new ArrayList<String>(getSelectedObjectIDs().size());
801            for (String id : getSelectedObjectIDs()) {
802                cmds.add(new StringBuilder("export object from ").append(id).append(" to ").append(id).append(" to directory ").append(dirname)
803                        .append(" with ").append(style).toString());
804            }
805            return cmds;
806        }
807    
808        /**
809         * The method removes all selected entries from search index.
810         * 
811         * @param index
812         *            index of searcher
813         */
814        public static final void removeFromSearchindex(String index) {
815            LOGGER.info("Start removing selected entries from search index " + index);
816    
817            MCRSearcher searcher = MCRSearcherFactory.getSearcherForIndex(index);
818    
819            if (null == getSelectedObjectIDs()) {
820                LOGGER.info("No Resultset to work with, use command \"select objects with query {0}\" to build one");
821                return;
822            }
823            for (String id : getSelectedObjectIDs()) {
824                searcher.removeFromIndex(id);
825            }
826            LOGGER.info("Selected entries from search index removed");
827        }
828    
829        /**
830         * The method checks the existence of selected MCRObjects in SQL store.
831         */
832        public static final void checkSelected() {
833            LOGGER.info("Start checking existence of selected MCRObjects in sql store");
834    
835            if (null == getSelectedObjectIDs()) {
836                LOGGER.info("No Resultset to work with, use command \"select objects with query {0}\" to build one");
837                return;
838            }
839    
840            int instore = 0;
841            int notinstore = 0;
842    
843            for (String id : getSelectedObjectIDs()) {
844                if (MCRObject.existInDatastore(id)) {
845                    instore++;
846                } else {
847                    LOGGER.info("is not in store " + id + " delete from search index ...");
848                    removeFromIndex("id", id);
849                    notinstore++;
850                }
851            }
852    
853            LOGGER.info("entries in Resultset    : " + getSelectedObjectIDs().size());
854            LOGGER.info("entries in SQL Store    : " + instore);
855            LOGGER.info("entries NOT in SQL Store: " + notinstore);
856        }
857    
858        /**
859         * Checks existence of MCRObjectID type {0} in search index and rapairs missing ones in search index.
860         * 
861         * @param type
862         *            the MCRObjectID type
863         */
864        public static final void checkMetadataSearch(String type) {
865            LOGGER.info("Start the check for type " + type);
866            String typetest = CONFIG.getString("MCR.Metadata.Type." + type, "");
867    
868            if (typetest.length() == 0) {
869                LOGGER.error("The type " + type + " was not found.");
870                return;
871            }
872            List<String> ar = (List<String>) MCRXMLTableManager.instance().retrieveAllIDs(type);
873            if (ar.size() == 0) {
874                LOGGER.warn("No ID's was found for type " + type + ".");
875                return;
876            }
877    
878            for (String stid : ar) {
879                String querystring = "id = " + stid;
880                MCRCondition cond = (new MCRQueryParser()).parse(querystring);
881                MCRQuery query = new MCRQuery(cond);
882                MCRResults results = MCRQueryManager.search(query);
883                if (1 != results.getNumHits()) {
884                    repairMetadataSearchForID(stid);
885                }
886            }
887        }
888    
889        /**
890         * Inform Searcher what is going on.
891         * 
892         * @param mode
893         *            what is going on, for example rebuild insert ... finish
894         * @param index
895         *            of searcher
896         */
897        public static final void notifySearcher(String mode, String index) {
898            MCRSearcher searcher = MCRSearcherFactory.getSearcherForIndex(index);
899            searcher.notifySearcher(mode);
900        }
901    }