001    /**
002     * 
003     * $Revision: 15270 $ $Date: 2009-05-25 17:27:57 +0200 (Mon, 25 May 2009) $
004     *
005     * This file is part of ** M y C o R e **
006     * Visit our homepage at http://www.mycore.de/ for details.
007     *
008     * This program is free software; you can use it, redistribute it
009     * and / or modify it under the terms of the GNU General Public License
010     * (GPL) as published by the Free Software Foundation; either version 2
011     * of the License or (at your option) any later version.
012     *
013     * This program is distributed in the hope that it will be useful, but
014     * WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program, normally in the file license.txt.
020     * If not, write to the Free Software Foundation Inc.,
021     * 59 Temple Place - Suite 330, Boston, MA  02111-1307 USA
022     *
023     **/
024    package org.mycore.frontend.cli;
025    
026    import java.io.File;
027    import java.io.FileOutputStream;
028    import java.io.InputStream;
029    import java.net.URISyntaxException;
030    import java.util.ArrayList;
031    import java.util.List;
032    
033    import javax.xml.transform.Transformer;
034    import javax.xml.transform.TransformerConfigurationException;
035    import javax.xml.transform.TransformerFactory;
036    import javax.xml.transform.TransformerFactoryConfigurationError;
037    import javax.xml.transform.stream.StreamResult;
038    import javax.xml.transform.stream.StreamSource;
039    
040    import org.apache.log4j.Logger;
041    import org.jdom.Document;
042    import org.jdom.output.Format;
043    import org.jdom.output.XMLOutputter;
044    
045    import org.mycore.common.xml.MCRURIResolver;
046    import org.mycore.common.xml.MCRXMLHelper;
047    import org.mycore.datamodel.classifications2.MCRCategory;
048    import org.mycore.datamodel.classifications2.MCRCategoryDAO;
049    import org.mycore.datamodel.classifications2.MCRCategoryID;
050    import org.mycore.datamodel.classifications2.MCRLabel;
051    import org.mycore.datamodel.classifications2.impl.MCRCategoryDAOImpl;
052    import org.mycore.datamodel.classifications2.utils.MCRCategoryTransformer;
053    import org.mycore.datamodel.classifications2.utils.MCRXMLTransformer;
054    import org.mycore.datamodel.common.MCRActiveLinkException;
055    
056    /**
057     * Commands for the classification system.
058     * 
059     * @author Thomas Scheffler (yagee)
060     */
061    public class MCRClassification2Commands extends MCRAbstractCommands {
062        private static Logger LOGGER = Logger.getLogger(MCRClassification2Commands.class);
063    
064        private static final MCRCategoryDAO DAO = new MCRCategoryDAOImpl();
065    
066        /** Default transformer script */
067        public static final String DEFAULT_TRANSFORMER = "save-classification.xsl";
068    
069        public MCRClassification2Commands() {
070            command.add(new MCRCommand("load classification from file {0}", "org.mycore.frontend.cli.MCRClassification2Commands.loadFromFile String", "The command add a new classification form file {0} to the system."));
071            command.add(new MCRCommand("update classification from file {0}", "org.mycore.frontend.cli.MCRClassification2Commands.updateFromFile String", "The command add a new classification form file {0} to the system."));
072            command.add(new MCRCommand("delete classification {0}", "org.mycore.frontend.cli.MCRClassification2Commands.delete String", "The command remove the classification with MCRObjectID {0} from the system."));
073            command.add(new MCRCommand("load all classifications from directory {0}", "org.mycore.frontend.cli.MCRClassification2Commands.loadFromDirectory String", "The command add all classifications in the directory {0} to the system."));
074            command.add(new MCRCommand("update all classifications from directory {0}", "org.mycore.frontend.cli.MCRClassification2Commands.updateFromDirectory String", "The command update all classifications in the directory {0} to the system."));
075            command.add(new MCRCommand("export classification {0} to {1} with {2}", "org.mycore.frontend.cli.MCRClassification2Commands.export String String String", "The command store the classification with MCRObjectID {0} to the file named {1} with the stylesheet {2}-object.xsl. For {2} save is the default.."));
076            command.add(new MCRCommand("export all classifications to {0} with {1}", "org.mycore.frontend.cli.MCRClassification2Commands.exportAll String String", "The command store all classifications to the directory with name {0} with the stylesheet {1}-object.xsl. For {1} save is the default."));
077            command.add(new MCRCommand("count classification children of {0}", "org.mycore.frontend.cli.MCRClassification2Commands.countChildren String", "The command remove the classification with MCRObjectID {0} from the system."));
078            command.add(new MCRCommand("list classification {0}", "org.mycore.frontend.cli.MCRClassification2Commands.listClassification String", "The command list the classification with MCRObjectID {0}."));
079            command.add(new MCRCommand("list all classifications", "org.mycore.frontend.cli.MCRClassification2Commands.listAllClassifications", "The command list all classification stored in the database."));
080        }
081    
082        /**
083         * Deletes a classification
084         * 
085         * @param classID
086         * @see MCRCategoryDAO#deleteCategory(MCRCategoryID)
087         */
088        public static void delete(String classID) {
089            DAO.deleteCategory(MCRCategoryID.rootID(classID));
090        }
091    
092        /**
093         * Deletes a classification
094         * 
095         * @param classID
096         * @see MCRCategoryDAO#deleteCategory(MCRCategoryID)
097         */
098        public static void countChildren(String classID) {
099            MCRCategory category = DAO.getCategory(MCRCategoryID.rootID(classID), -1);
100            System.out.printf("%s has %d children", category.getId(), category.getChildren().size());
101        }
102    
103        /**
104         * Adds a classification.
105         * 
106         * Classification is built from a file.
107         * 
108         * @param filname
109         *            file in mcrclass xml format
110         * @throws URISyntaxException 
111         * @see MCRCategoryDAO#addCategory(MCRCategoryID, MCRCategory)
112         */
113        public static void loadFromFile(String filename) throws URISyntaxException {
114            File file = new File(filename);
115            Document xml = MCRXMLHelper.parseURI(file.toURI());
116            MCRCategory category = MCRXMLTransformer.getCategory(xml);
117            DAO.addCategory(null, category);
118        }
119    
120        /**
121         * Replaces a classification with a new version
122         * 
123         * @param filename
124         *            file in mcrclass xml format
125         * @throws URISyntaxException 
126         * @see MCRCategoryDAO#replaceCategory(MCRCategory)
127         */
128        public static void updateFromFile(String filename) throws URISyntaxException {
129            File file = new File(filename);
130            Document xml = MCRXMLHelper.parseURI(file.toURI());
131            MCRCategory category = MCRXMLTransformer.getCategory(xml);
132            if (DAO.exist(category.getId())) {
133                DAO.replaceCategory(category);
134            } else {
135                // add if classification does not exist
136                DAO.addCategory(null, category);
137            }
138        }
139    
140        /**
141         * Loads MCRClassification from all XML files in a directory.
142         * 
143         * @param directory
144         *            the directory containing the XML files
145         * @throws MCRActiveLinkException
146         */
147        public static List<String> loadFromDirectory(String directory) throws MCRActiveLinkException {
148            return processFromDirectory(directory, false);
149        }
150    
151        /**
152         * Updates MCRClassification from all XML files in a directory.
153         * 
154         * @param directory
155         *            the directory containing the XML files
156         * @throws MCRActiveLinkException
157         */
158        public static List<String> updateFromDirectory(String directory) throws MCRActiveLinkException {
159            return processFromDirectory(directory, true);
160        }
161    
162        /**
163         * Loads or updates MCRClassification from all XML files in a directory.
164         * 
165         * @param directory
166         *            the directory containing the XML files
167         * @param update
168         *            if true, classification will be updated, else Classification
169         *            is created
170         * @throws MCRActiveLinkException
171         */
172        private static List<String> processFromDirectory(String directory, boolean update) throws MCRActiveLinkException {
173            File dir = new File(directory);
174    
175            if (!dir.isDirectory()) {
176                LOGGER.warn(directory + " ignored, is not a directory.");
177                return null;
178            }
179    
180            String[] list = dir.list();
181    
182            if (list.length == 0) {
183                LOGGER.warn("No files found in directory " + directory);
184                return null;
185            }
186    
187            List<String> cmds = new ArrayList<String>();
188            for (String file : list)
189                if (file.endsWith(".xml"))
190                    cmds.add((update ? "update" : "load") + " classification from file " + new File(dir, file).getAbsolutePath());
191    
192            return cmds;
193        }
194    
195        /**
196         * Save a MCRClassification.
197         * 
198         * @param ID
199         *            the ID of the MCRClassification to be save.
200         * @param filename
201         *            the filename to store the classification
202         * @param style
203         *            the name part of the stylesheet like <em>style</em>
204         *            -classification.xsl
205         * @return false if an error was occured, else true
206         */
207        public static boolean export(String ID, String dirname, String style) throws Exception {
208            String dname = "";
209            if (dirname.length() != 0) {
210                try {
211                    File dir = new File(dirname);
212                    if (!dir.isDirectory()) {
213                        dir.mkdir();
214                    }
215                    if (!dir.isDirectory()) {
216                        LOGGER.error("Can't find or create directory " + dir.getAbsolutePath());
217                        return false;
218                    } else {
219                        dname = dirname;
220                    }
221                } catch (Exception e) {
222                    LOGGER.error("Can't find or create directory " + dirname, e);
223                    return false;
224                }
225            }
226            MCRCategory cl = DAO.getCategory(MCRCategoryID.rootID(ID), -1);
227            Document classDoc = MCRCategoryTransformer.getMetaDataDocument(cl, false);
228    
229            Transformer trans = getTransformer(style);
230            File xmlOutput = new File(dname, ID + ".xml");
231            FileOutputStream out = new FileOutputStream(xmlOutput);
232            if (trans != null) {
233                StreamResult sr = new StreamResult(out);
234                trans.transform(new org.jdom.transform.JDOMSource(classDoc), sr);
235            } else {
236                XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
237                xout.output(classDoc, out);
238                out.flush();
239            }
240            LOGGER.info("Classifcation " + ID + " saved to " + xmlOutput.getCanonicalPath() + ".");
241            return true;
242        }
243    
244        /**
245         * The method search for a stylesheet mcr_<em>style</em>_object.xsl and
246         * build the transformer. Default is <em>mcr_save-object.xsl</em>.
247         * 
248         * @param style
249         *            the style attribute for the transformer stylesheet
250         * @return the transformer
251         * @throws TransformerFactoryConfigurationError
252         * @throws TransformerConfigurationException
253         */
254        private static final Transformer getTransformer(String style) throws TransformerFactoryConfigurationError, TransformerConfigurationException {
255            String xslfile = DEFAULT_TRANSFORMER;
256            if ((style != null) && (style.trim().length() != 0)) {
257                xslfile = style + "-classification.xsl";
258            }
259            Transformer trans = null;
260    
261            InputStream in = MCRClassification2Commands.class.getResourceAsStream("/" + xslfile);
262            if (in == null) {
263                in = MCRClassification2Commands.class.getResourceAsStream(DEFAULT_TRANSFORMER);
264            }
265            if (in != null) {
266                StreamSource source = new StreamSource(in);
267                TransformerFactory transfakt = TransformerFactory.newInstance();
268                transfakt.setURIResolver(MCRURIResolver.instance());
269                trans = transfakt.newTransformer(source);
270            }
271            return trans;
272        }
273    
274        /**
275         * Save all MCRClassifications.
276         * 
277         * @param dirname
278         *            the directory name to store all classifications
279         * @param style
280         *            the name part of the stylesheet like <em>style</em>
281         *            -classification.xsl
282         * @return false if an error was occured, else true
283         */
284        public static boolean exportAll(String dirname, String style) throws Exception {
285            List<MCRCategoryID> allClassIds = DAO.getRootCategoryIDs();
286            boolean ret = false;
287            for (MCRCategoryID id : allClassIds) {
288                ret = ret & export(id.getRootID(), dirname, style);
289            }
290            return ret;
291        }
292    
293        /**
294         * List all IDs of all classifications stored in the database
295         */
296        public static void listAllClassifications() {
297            List<MCRCategoryID> allClassIds = DAO.getRootCategoryIDs();
298            for (MCRCategoryID id : allClassIds) {
299                LOGGER.info(id.getRootID());
300            }
301            LOGGER.info("");
302        }
303    
304        /**
305         * List a MCRClassification.
306         * 
307         * @param classid
308         *            the MCRObjectID of the classification
309         */
310        public static void listClassification(String classid) {
311            MCRCategoryID clid = MCRCategoryID.rootID(classid);
312            MCRCategory cl = DAO.getCategory(clid, -1);
313            LOGGER.info(classid);
314            if (cl != null) {
315                listCategory(cl);
316            } else {
317                LOGGER.error("Can't find classification " + classid);
318            }
319        }
320    
321        private static void listCategory(MCRCategory categ) {
322            int level = categ.getLevel();
323            StringBuffer sb = new StringBuffer(128);
324            for (int i = 0; i < level * 2; i++) {
325                sb.append(' ');
326            }
327            String space = sb.toString();
328            if (categ.isCategory()) {
329                LOGGER.info(space + "  ID    : " + categ.getId().getID());
330            }
331            for (MCRLabel label : categ.getLabels()) {
332                LOGGER.info(space + "  Label : (" + label.getLang() + ") " + label.getText());
333            }
334            List<MCRCategory> children = categ.getChildren();
335            for (MCRCategory child : children) {
336                listCategory(child);
337            }
338        }
339    }