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 }