001    /*
002     * 
003     * $Revision: 14987 $ $Date: 2009-03-20 22:10:57 +0100 (Fri, 20 Mar 2009) $
004     *
005     * This file is part of ***  M y C o R e  ***
006     * See http://www.mycore.de/ for details.
007     *
008     * This program is free software; you can use it, redistribute it
009     * and / or modify it under the terms of the GNU General Public License
010     * (GPL) as published by the Free Software Foundation; either version 2
011     * of the License or (at your option) any later version.
012     *
013     * This program is distributed in the hope that it will be useful, but
014     * WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program, in a file called gpl.txt or license.txt.
020     * If not, write to the Free Software Foundation Inc.,
021     * 59 Temple Place - Suite 330, Boston, MA  02111-1307 USA
022     */
023    
024    package org.mycore.backend.hibernate;
025    
026    import java.io.BufferedOutputStream;
027    import java.io.File;
028    import java.io.FileNotFoundException;
029    import java.io.FileOutputStream;
030    import java.io.IOException;
031    import java.io.UnsupportedEncodingException;
032    import java.util.Date;
033    import java.util.List;
034    import java.util.regex.Pattern;
035    
036    import org.apache.log4j.Logger;
037    import org.dom4j.DocumentException;
038    import org.dom4j.DocumentFactory;
039    import org.dom4j.Element;
040    import org.dom4j.ElementHandler;
041    import org.dom4j.ElementPath;
042    import org.dom4j.QName;
043    import org.dom4j.io.OutputFormat;
044    import org.dom4j.io.SAXReader;
045    import org.dom4j.io.XMLWriter;
046    import org.hibernate.EntityMode;
047    import org.hibernate.HibernateException;
048    import org.hibernate.ReplicationMode;
049    import org.hibernate.Session;
050    import org.hibernate.tool.hbm2ddl.SchemaUpdate;
051    import org.xml.sax.SAXException;
052    import org.xml.sax.helpers.AttributesImpl;
053    
054    import org.mycore.backend.hibernate.tables.MCRACCESS;
055    import org.mycore.backend.hibernate.tables.MCRACCESSRULE;
056    import org.mycore.common.MCRException;
057    import org.mycore.common.MCRPersistenceException;
058    import org.mycore.frontend.cli.MCRAbstractCommands;
059    import org.mycore.frontend.cli.MCRCommand;
060    
061    /**
062     * This class provides a set of commands for the org.mycore.access package which
063     * can be used by the command line interface. (creates sql tables, run queries
064     * 
065     * @author Thomas Scheffler (yagee)
066     * @author Arne Seifert
067     */
068    public class MCRHIBCtrlCommands extends MCRAbstractCommands {
069        /** The logger */
070        private static final Logger LOGGER = Logger.getLogger(MCRHIBCtrlCommands.class.getName());
071    
072        private static final DocumentFactory DOC_FACTORY = new DocumentFactory();
073    
074        /**
075         * Pattern that matches against every element directly under the root element.
076         */
077        private static final java.util.regex.Pattern OBJECT_PATTERN = Pattern.compile("^/[^/]+/[^/]+$");
078    
079        /**
080         * constructor with commands.
081         */
082        public MCRHIBCtrlCommands() {
083            super();
084    
085            MCRCommand com = null;
086    
087            com = new MCRCommand("init hibernate", "org.mycore.backend.hibernate.MCRHIBCtrlCommands.createTables",
088                    "The command creates all tables for MyCoRe by hibernate.");
089            command.add(com);
090            com = new MCRCommand("export acl rules to file {0}", "org.mycore.backend.hibernate.MCRHIBCtrlCommands.exportAccessRules String",
091                    "Exports all ACL rules to a given file.");
092            command.add(com);
093            com = new MCRCommand("import acl rules from file {0}", "org.mycore.backend.hibernate.MCRHIBCtrlCommands.importAccessRules String",
094                    "Imports all ACL rules from a given file.");
095            command.add(com);
096            com = new MCRCommand("export acl mappings to file {0}", "org.mycore.backend.hibernate.MCRHIBCtrlCommands.exportAccessMappings String",
097                    "Exports all ACL mappings to a given file.");
098            command.add(com);
099            com = new MCRCommand("import acl mappings from file {0}", "org.mycore.backend.hibernate.MCRHIBCtrlCommands.importAccessMappings String",
100                    "Imports all ACL mappings from a given file.");
101            command.add(com);
102            com = new MCRCommand("export entity {0} to file {1}", "org.mycore.backend.hibernate.MCRHIBCtrlCommands.exportEntity String String",
103                    "Exports an entity (fully qualified class name) to a given file.");
104            command.add(com);
105            com = new MCRCommand("import entity {0} from file {1}", "org.mycore.backend.hibernate.MCRHIBCtrlCommands.importEntity String String",
106                    "Imports an entity (fully qualified class name) from a given file.");
107            command.add(com);
108        }
109    
110        /**
111         * 
112         * method creates tables using hibernate
113         */
114        public static void createTables() {
115            try {
116                new SchemaUpdate(MCRHIBConnection.instance().getConfiguration()).execute(true, true);
117    
118                LOGGER.info("tables created.");
119            } catch (MCRPersistenceException e) {
120                throw new MCRException("error while creating tables.", e);
121            } catch (HibernateException e) {
122                throw new MCRException("Hibernate error while creating database tables.", e);
123            }
124        }
125    
126        public static void exportAccessRules(String file) throws IOException, SAXException {
127            exportFile(file, "accessrules", MCRACCESSRULE.class);
128        }
129    
130        public static void importAccessRules(String file) throws IOException, DocumentException {
131            importFile(file, MCRACCESSRULE.class.getName());
132        }
133    
134        public static void exportAccessMappings(String file) throws IOException, SAXException {
135            exportFile(file, "accessmap", MCRACCESS.class);
136        }
137    
138        public static void importAccessMappings(String file) throws IOException, DocumentException {
139            importFile(file, MCRACCESS.class.getName());
140        }
141    
142        public static void exportEntity(String className, String file) throws IOException, SAXException, ClassNotFoundException {
143            Class<?> exportClass = Class.forName(className);
144            exportFile(file, exportClass.getSimpleName().toLowerCase(), exportClass);
145        }
146    
147        public static void importEntity(String className, String file) throws IOException, DocumentException {
148            importFile(file, className);
149        }
150    
151        @SuppressWarnings("unchecked")
152        private static void exportFile(String file, String rootTag, Class persistedClass) throws FileNotFoundException, UnsupportedEncodingException, IOException,
153                SAXException {
154            File exportFile = new File(file);
155            if (exportFile.exists() && exportFile.isDirectory()) {
156                throw new MCRException(exportFile.getAbsolutePath() + " is a directory.");
157            }
158            Session session = MCRHIBConnection.instance().getSession();
159            Session xmlSession = session.getSession(EntityMode.DOM4J);
160            QName rootName = DOC_FACTORY.createQName(rootTag, "mycore", "http://www.mycore.org/");
161            OutputFormat format = OutputFormat.createCompactFormat();
162            format.setTrimText(false);
163            format.setNewLineAfterDeclaration(true);
164            format.setSuppressDeclaration(false);
165            format.setEncoding("UTF-8");
166            FileOutputStream fileOutputStream = new FileOutputStream(exportFile);
167            BufferedOutputStream bout = new BufferedOutputStream(fileOutputStream);
168            XMLWriter xmlWriter = new XMLWriter(bout, format);
169            /*
170             * We don't generate a Document instance here to save memory on large
171             * tables. Instead we code our document by SAX events and directly write
172             * every element generated by hibernate to the OutputStream.
173             */
174            xmlWriter.startDocument();
175            xmlWriter.write(DOC_FACTORY.createComment("Export from: " + new Date().toString()));
176            xmlWriter.startPrefixMapping(rootName.getNamespacePrefix(), rootName.getNamespaceURI());
177            xmlWriter.startElement(rootName.getNamespaceURI(), rootName.getName(), rootName.getQualifiedName(), new AttributesImpl());
178            // get all Objects of persistedClass from hibernate
179            List<Element> elements = xmlSession.createCriteria(persistedClass).list();
180            for (Element result : elements) {
181                // write element to stream
182                xmlWriter.write(result);
183            }
184            // close document
185            xmlWriter.endElement(rootName.getNamespaceURI(), rootName.getName(), rootName.getQualifiedName());
186            xmlWriter.endPrefixMapping(rootName.getNamespacePrefix());
187            xmlWriter.endDocument();
188            xmlWriter.close();
189            bout.close();
190        }
191    
192        private static void importFile(String file, final String entityName) throws DocumentException {
193            File importFile = new File(file);
194            if (importFile.exists() && importFile.isDirectory()) {
195                throw new MCRException(importFile.getAbsolutePath() + " is a directory.");
196            }
197            SAXReader xmlReader = new SAXReader(false);
198            Session session = MCRHIBConnection.instance().getSession();
199            final Session xmlSession = session.getSession(EntityMode.DOM4J);
200            final ReplicationMode replicationMode = ReplicationMode.OVERWRITE;
201            /*
202             * The Document returned below is not of interest. We just care for the
203             * elements directly below the root element. Directly after a element is
204             * completely read, the element gets detached so it can be caught be the
205             * garbage collector.
206             */
207            xmlReader.setDefaultHandler(new ElementHandler() {
208    
209                public void onStart(ElementPath path) {
210                }
211    
212                public void onEnd(ElementPath path) {
213                    // only process elements directly below the root element
214                    if (OBJECT_PATTERN.matcher(path.getPath()).find()) {
215                        Element rule = path.getCurrent();
216                        // import into database
217                        xmlSession.replicate(entityName, rule, replicationMode);
218                        // save some memory
219                        rule.detach();
220                    }
221                }
222            });
223            xmlReader.read(importFile);
224        }
225    
226    }