001    /*
002     * 
003     * $Revision: 13085 $ $Date: 2008-02-06 18:27:24 +0100 (Mi, 06 Feb 2008) $
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.services.migration;
025    
026    import java.io.File;
027    import java.io.FileInputStream;
028    import java.io.FileNotFoundException;
029    import java.io.FileOutputStream;
030    import java.io.IOException;
031    import java.io.OutputStreamWriter;
032    import java.sql.Connection;
033    import java.sql.SQLException;
034    import java.sql.Statement;
035    import java.util.List;
036    import java.util.Properties;
037    
038    import org.apache.log4j.Logger;
039    import org.hibernate.Session;
040    import org.jdom.Comment;
041    import org.jdom.Document;
042    import org.jdom.Element;
043    import org.jdom.input.SAXBuilder;
044    import org.jdom.output.XMLOutputter;
045    import org.jdom.xpath.XPath;
046    
047    import org.mycore.backend.hibernate.MCRHIBConnection;
048    import org.mycore.common.MCRConfiguration;
049    import org.mycore.user.MCRGroup;
050    import org.mycore.user.MCRUserMgr;
051    
052    /**
053     * Update of User Management to comply with new MyCoRe 2.0
054     * 
055     * Therefore we first checkout all users and groups, drop the concerning tables
056     * and check all users and groups back in. Before check-in the new user tables
057     * will be automatically created by Hibernate which takes care of new primary
058     * key and foreign key constraints.
059     * 
060     * 
061     * @author Robert Stephan
062     */
063    class MCRUserMigrationHelper {
064    
065        private static Logger LOGGER = Logger.getLogger(MCRUserMigrationHelper.class.getName());
066    
067        static File getUserFile() {
068            return new File(getBaseDirectory(), "user-data.xml");
069        }
070    
071        static File getGroupFile() {
072            return new File(getBaseDirectory(), "group-data.xml");
073        }
074    
075        private static File getBaseDirectory() {
076            Properties props = (Properties) (MCRConfiguration.instance().getProperties());
077            String workingDir = props.getProperty("MCR.BaseDirectory", null);
078            if (workingDir == null) {
079                workingDir = System.getProperty("java.io.tmpdir");
080            }
081    
082            File dir = new File(workingDir, "user-migration");
083            dir.mkdirs();
084            return dir;
085        }
086    
087        @SuppressWarnings("all")
088        static final void dropTables() throws SQLException {
089            try {
090                Connection con = MCRHIBConnection.instance().getSession().connection();
091                Statement stmt = con.createStatement();
092                stmt.executeUpdate("DROP TABLE MCRGROUPMEMBERS");
093                stmt.executeUpdate("DROP TABLE MCRGROUPADMINS");
094                stmt.executeUpdate("DROP TABLE MCRUSERS");
095                stmt.executeUpdate("DROP TABLE MCRGROUPS");
096                stmt.close();
097                con.commit();
098    
099            } catch (SQLException e) {
100                LOGGER.debug("Failed to drop table", e);
101                throw e;
102            }
103            Session session = MCRHIBConnection.instance().getSession();
104            session.clear();
105        }
106    
107        static final void deleteTempFiles() {
108            try {
109                File groupFile = getGroupFile();
110                if (groupFile.getAbsolutePath().endsWith(".xml")) {
111                    File f1org = new File(groupFile.getAbsolutePath() + ".org.xml");
112                    f1org.delete();
113                }
114                groupFile.delete();
115    
116                File userFile = getUserFile();
117                if (userFile.getAbsolutePath().endsWith(".xml")) {
118                    File f1org = new File(userFile.getAbsolutePath() + ".org.xml");
119                    f1org.delete();
120                }
121                userFile.delete();
122    
123                File baseDir = getBaseDirectory();
124                baseDir.delete();
125    
126            } catch (Exception e) {
127                LOGGER.debug("Failed to cleanup temp files", e);
128            }
129        }
130    
131        /*
132         * We have to delete all group member information, since we create the
133         * groups before the users we also delete all groups - allready created by
134         * "init superuser"
135         */
136        static void cleanupGroupFile() throws Exception {
137            StringBuffer useradmins = new StringBuffer();
138            StringBuffer groupadmins = new StringBuffer();
139            try {
140                final File groupFile = getGroupFile();
141                copyFile(groupFile, new File(groupFile.getAbsolutePath() + ".org.xml"));
142                SAXBuilder sb = new SAXBuilder();
143                Document doc = sb.build(groupFile);
144                // delete group.members
145                XPath x = XPath.newInstance("//group.members");
146                List list = x.selectNodes(doc);
147                for (Object o : list) {
148                    Element e = (Element) o;
149                    e.removeContent();
150                }
151    
152                // remove empty admins.userID and admins.groupID
153                x = XPath.newInstance("//admins.userID");
154                list = x.selectNodes(doc);
155                for (Object o : list) {
156                    Element e = (Element) o;
157                    if (useradmins.length() > 0)
158                        useradmins.append(";");
159                    useradmins.append(e.getParentElement().getParentElement().getAttributeValue("ID"));
160                    useradmins.append("=");
161                    useradmins.append(e.getText());
162    
163                    e.detach();
164                }
165    
166                x = XPath.newInstance("//admins.groupID");
167                list = x.selectNodes(doc);
168                for (Object o : list) {
169                    Element e = (Element) o;
170                    if (groupadmins.length() > 0)
171                        groupadmins.append(";");
172                    groupadmins.append(e.getParentElement().getParentElement().getAttributeValue("ID"));
173                    groupadmins.append("=");
174                    groupadmins.append(e.getText());
175    
176                    e.detach();
177                }
178    
179                // deltete existing Groups
180                x = XPath.newInstance("//group");
181                list = x.selectNodes(doc);
182                for (Object o : list) {
183                    Element e = (Element) o;
184                    if (MCRUserMgr.instance().existGroup(e.getAttributeValue("ID"))) {
185                        e.getParent().removeContent(e);
186                    }
187                }
188                doc.addContent(new Comment(useradmins.toString() + "|" + groupadmins.toString()));
189                XMLOutputter xmlOut = new XMLOutputter();
190                xmlOut.output(doc, new OutputStreamWriter(new FileOutputStream(groupFile), "utf-8"));
191            } catch (Exception e) {
192                LOGGER.debug("Error in user migration while modifying group members", e);
193                throw e;
194            }
195        }
196    
197        /*
198         * We have to delete all users - allready created by "init superuser"
199         */
200        static void cleanupUserFile() {
201            try {
202                final File userFile = getUserFile();
203                copyFile(userFile, new File(userFile.getAbsolutePath() + ".org.xml"));
204                SAXBuilder sb = new SAXBuilder();
205                Document doc = sb.build(userFile);
206    
207                // deltete existing Users
208                XPath x = XPath.newInstance("//user");
209                List list = x.selectNodes(doc);
210                for (Object o : list) {
211                    Element e = (Element) o;
212                    if (MCRUserMgr.instance().existUser(e.getAttributeValue("ID"))) {
213                        e.getParent().removeContent(e);
214                    }
215                }
216                XMLOutputter xmlOut = new XMLOutputter();
217                xmlOut.output(doc, new OutputStreamWriter(new FileOutputStream(userFile), "utf-8"));
218            } catch (Exception e) {
219                LOGGER.debug("Error in user migration while modifying group members", e);
220            }
221        }
222    
223        static void updateAdmins() {
224            SAXBuilder sb = new SAXBuilder();
225            MCRUserMgr mgr = MCRUserMgr.instance();
226            try {
227                Document doc = sb.build(getGroupFile());
228                for (Object o : doc.getContent()) {
229                    LOGGER.info(o.getClass().getCanonicalName());
230                    if (o instanceof Comment) {
231                        LOGGER.info("Found Comment");
232                        String s = ((Comment) o).getText();
233                        String[] sa = s.split("\\|");
234                        String users = sa[0];
235                        String groups = "";
236                        if (sa.length > 1)
237                            groups = sa[1];
238                        String[] userA = users.split(";");
239                        String[] groupA = groups.split(";");
240                        for (String x : userA) {
241                            final String[] groupAdmin = x.split("=");
242                            if (groupAdmin.length > 1) {
243                                String id = groupAdmin[0];
244                                String value = groupAdmin[1];
245                                MCRGroup mcrGroup = mgr.retrieveGroup(id);
246                                mcrGroup.addAdminUserID(value);
247                                mgr.updateGroup(mcrGroup);
248                                LOGGER.info("Adding user '" + value + "' to admins of group '" + id + "'.");
249                            }
250                        }
251                        for (String x : groupA) {
252                            final String[] groupAdmin = x.split("=");
253                            if (groupAdmin.length > 1) {
254                                String id = groupAdmin[0];
255                                String value = groupAdmin[1];
256                                MCRGroup mcrGroup = mgr.retrieveGroup(id);
257                                mcrGroup.addAdminGroupID(value);
258                                mgr.updateGroup(mcrGroup);
259                                LOGGER.info("Adding group '" + value + "' to admins of group '" + id + "'.");
260                            }
261                        }
262                    }
263    
264                }
265    
266            } catch (Exception e) {
267                LOGGER.warn("Error in user migration while updateing group admin information", e);
268            }
269        }
270    
271        // just for debugging
272        private static void copyFile(File fromFile, File toFile) {
273            FileInputStream from = null;
274            FileOutputStream to = null;
275            try {
276                from = new FileInputStream(fromFile);
277                to = new FileOutputStream(toFile);
278                byte[] buffer = new byte[4096];
279                int bytesRead;
280    
281                while ((bytesRead = from.read(buffer)) != -1)
282                    to.write(buffer, 0, bytesRead); // write
283            } catch (FileNotFoundException e) {
284                e.printStackTrace();
285            } catch (IOException e) {
286                e.printStackTrace();
287            }
288    
289            finally {
290                if (from != null)
291                    try {
292                        from.close();
293                    } catch (IOException e) {
294                        ;
295                    }
296                if (to != null)
297                    try {
298                        to.close();
299                    } catch (IOException e) {
300                        ;
301                    }
302            }
303        }
304    
305    }