net.unicon.academus.apps.briefcase.migrate.BriefcaseMigrator.java Source code

Java tutorial

Introduction

Here is the source code for net.unicon.academus.apps.briefcase.migrate.BriefcaseMigrator.java

Source

/*
 * Copyright (C) 2007 Unicon, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free 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,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY 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
 * along with this distribution.  It is also available here:
 * http://www.fsf.org/licensing/licenses/gpl.html
 *
 * As a special exception to the terms and conditions of version
 * 2 of the GPL, you may redistribute this Program in connection
 * with Free/Libre and Open Source Software ("FLOSS") applications
 * as described in the GPL FLOSS exception.  You should have received
 * a copy of the text describing the FLOSS exception along with this
 * distribution.
 */

package net.unicon.academus.apps.briefcase.migrate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import javax.sql.DataSource;

import net.unicon.alchemist.access.rdbms.RdbmsAccessBroker;
import net.unicon.alchemist.rdbms.SimpleDataSource;
import net.unicon.alchemist.access.permissions.DummyAccessType;
import net.unicon.alchemist.access.permissions.DummyCreator;
import net.unicon.alchemist.access.permissions.PermissionsAccessBroker;
import net.unicon.academus.apps.briefcase.BriefcaseAccessType;

import org.dom4j.tree.*;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.QName;
import org.dom4j.dom.DOMDocumentFactory;
import org.dom4j.io.SAXReader;

/**
 * @author ibiswas
 *
 * This class will be used to migrate briefcase data from 
 * Academus 1.5 to Academus 1.6.
 * 
 * Changes:
 * 1. The resource urls will have to be modified in two ways for the following 
 *    reasons:
 *    
 *    a. The briefcase code was refactored into a new package. The urls of the 
 *       resources are dependent on the package structure of the classes. These 
 *       urls will have to be updated.
 *       
 *    b. The structure for shared folder urls has been modified. The shared
 *       resource portion of the url is now completely enclosed in parentheses.
 *       This requires a new unique delimiter to separate the factory from the
 *       shared resource path. '///' is used as the delimiter.  
 * 
 * 2. The OWNER access type assigned to each personal resource factory will 
 *    have to be replaced with the BriefcaseAccessType enumeration.
 *      New entries will be inserted for each of the permissions assigned to the 
 *    identity.
 * 
 * 3. Set the uni_sequence table for the RdbmsAccessBroker Counter and 
 *       FSA_Kernel_Sequencer
 * 
 * 
 * 4. Add impl attribute on <access> element.
 * 
 * 5. Update the <type> element to change the value attribute 
 *    to "handle" and add an attribute value="GRANT" * 
 * 
 * 6. Add impl attribute to specify the UserDirectory impl to user-attribute element
 *                
 * 7. Add access element to specify the AccessType to the RdbmsAccessBroker
 * 
 * 8. Add the civis address book information.
 * 
 * 9. The config file from Academus 1.5 will be updated to work in the 1.6 code base. 
 *    Please use the updated config file in the 1.6 deployment.
 *   
 */
public class BriefcaseMigrator {

    public static void main(String[] args) {

        System.out.println("Starting Briefcase portlet migration of data from Academus 1.5 " + " to Academus 1.6");

        if (args.length == 2) {
            try {
                DataSource ds = new SimpleDataSource();

                SAXReader reader = new SAXReader();

                // replace the old urls with the new classpaths
                System.out.println("Updating the resource urls.");
                updateUrl(ds);
                updateSharedResourceUrls(ds);

                // replace the OWNER access type.
                System.out.println("Updating the accessTypes.");
                updateAccessType(ds);

                // set the uni_sequence table for the RdbmsAccessBroker Counter
                // and the FSA_Kernel_Sequencer
                updateSequencers(ds);

                // read the old config file
                // and correct the classpaths for all the access brokers.  
                Document oldDoc = reader.read(args[0]);

                DOMDocumentFactory dFac = new DOMDocumentFactory();

                // Get all access brokers
                List brokers = oldDoc.selectNodes("//access-broker");
                Element broker = null;

                // Change access brokers to point to alchemist instead of academus
                for (int i = 0; i < brokers.size(); i++) {
                    broker = (Element) brokers.get(i);
                    String implValue = broker.attributeValue("impl").replaceFirst("academus", "alchemist");
                    broker.addAttribute("impl", implValue);
                }

                // Get the Access Broker under the personal Drive, and make sure it's a JIT broker
                Element targetsJitAccessBroker = (Element) ((Element) oldDoc.selectNodes(
                        "/briefcase/drive[@handle='personal']/access-broker[@impl='net.unicon.alchemist.access.jit.JitAccessBroker']")
                        .get(0)).detach();

                // Only enter this code if the personal drive section was successful selected
                if (targetsJitAccessBroker != null) {

                    // Create new permissions element, mirroring targets element
                    Element permissionsJitAccessBroker = (Element) targetsJitAccessBroker.clone();

                    // Change handles
                    targetsJitAccessBroker.addAttribute("handle", "personal-resourses-t");
                    permissionsJitAccessBroker.addAttribute("handle", "personal-resourses-p");

                    // Create new permissions access-broker
                    Element permAccessBroker = dFac.createElement(new QName("access-broker"), 2);
                    permAccessBroker.addAttribute("handle", "personal-jit");
                    permAccessBroker.addAttribute("impl", PermissionsAccessBroker.class.getName());

                    // Create new access element and add it to permAccessBroker
                    Element permAccess = dFac.createElement(new QName("access"), 1);
                    permAccess.addAttribute("impl", BriefcaseAccessType.class.getName());
                    permAccessBroker.add(permAccess);

                    // Create targets and permissions elements and add to the new permissions access-broker
                    Element targets = permAccessBroker.addElement("targets");
                    targets.add(targetsJitAccessBroker);

                    Element permissions = permAccessBroker.addElement("permissions");
                    permissions.add(permissionsJitAccessBroker);

                    // Add new permissions access broker to the drive
                    Element curDrive = (Element) oldDoc.selectNodes("/briefcase/drive[@handle='personal']").get(0);
                    curDrive.add(permAccessBroker);

                    //
                    // Change targets internals
                    //

                    List targetsAccess = targets.selectNodes("access-broker/jit-rule/behavior/access");
                    for (int i = 0; i < targetsAccess.size(); i++) {

                        // Add impl attribute with value of fully-qualified class name
                        ((Element) targetsAccess.get(i)).addAttribute("impl", DummyAccessType.class.getName());

                        // Get all child type elements and remove them
                        List types = ((Element) targetsAccess.get(i)).elements();
                        for (int j = 0; j < types.size(); j++) {
                            ((Element) types.get(j)).detach();
                        }

                        // Add a single dummy element
                        Element eType = dFac.createElement(new QName("type"), 2);
                        eType.addAttribute("value", "GRANT");
                        eType.addAttribute("handle", "DUMMY");

                        ((Element) targetsAccess.get(i)).add(eType);

                    }

                    // Add internal access broker's access element
                    Element targetsIAccessBroker = (Element) (targets.selectNodes("access-broker/access-broker")
                            .get(0));
                    Element targetsIAccess = dFac.createElement(new QName("access"), 1);
                    targetsIAccess.addAttribute("impl", DummyAccessType.class.getName());
                    targetsIAccessBroker.add(targetsIAccess);

                    //
                    // Change permissions internals
                    //

                    List permissionsAccess = permissions.selectNodes("access-broker/jit-rule/behavior/access");
                    for (int i = 0; i < permissionsAccess.size(); i++) {
                        // Add impl attribute with value of fully-qualified class name
                        ((Element) permissionsAccess.get(i)).addAttribute("impl",
                                BriefcaseAccessType.class.getName());

                        // Get all child type elements and replace them
                        List types = ((Element) permissionsAccess.get(i)).elements();
                        for (int j = 0; j < types.size(); j++) {
                            Attribute value = ((Element) types.get(j)).attribute("value");
                            String text = value.getValue();
                            value.setValue("GRANT");

                            if (text.equals("0")) {
                                BriefcaseAccessType[] aTypes = BriefcaseAccessType.getInstances();
                                ((Element) types.get(j)).addAttribute("handle", aTypes[0].getName());

                                for (int k = 1; k < aTypes.length; k++) {
                                    Element eType = dFac.createElement(new QName("type"), 2);
                                    eType.addAttribute("value", "GRANT");
                                    eType.addAttribute("handle", aTypes[k].getName());
                                    ((Element) permissionsAccess.get(i)).add(eType);
                                }
                            } else {
                                ((Element) types.get(j)).addAttribute("handle",
                                        BriefcaseAccessType.getAccessType(Integer.parseInt(text)).getName());
                            }
                        }

                    }

                    // Change other elements in the permissions section
                    List permissionsBehavior = permissions.selectNodes("access-broker/jit-rule/behavior");
                    for (int i = 0; i < permissionsBehavior.size(); i++) {
                        Element trigger = (Element) ((Element) permissionsBehavior.get(i)).elements("trigger")
                                .get(0);
                        Element target = (Element) ((Element) permissionsBehavior.get(i)).elements("target").get(0);
                        Element creator = (Element) ((Element) permissionsBehavior.get(i)).elements("creator")
                                .get(0);

                        // Insert trigger text into target
                        target.addAttribute("type", "GROUP");
                        target.addText(trigger.getText());

                        // Remove current creator element
                        creator.detach();

                        // Add new current creator element
                        Element eCreator = dFac.createElement(new QName("creator"), 1);
                        eCreator.addAttribute("impl", DummyCreator.class.getName());
                        ((Element) permissionsBehavior.get(i)).add(eCreator);
                    }

                    // Change internal access broker's name
                    Element permissionsIAccessBroker = (Element) (permissions
                            .selectNodes("access-broker/access-broker").get(0));
                    permissionsIAccessBroker.addAttribute("handle", "personal-resources-p-i");

                    // Add internal access broker's access element
                    Element permissionsIAccess = dFac.createElement(new QName("access"), 1);
                    permissionsIAccess.addAttribute("impl", BriefcaseAccessType.class.getName());
                    permissionsIAccessBroker.add(permissionsIAccess);

                }

                List access = oldDoc.selectNodes("/briefcase/drive[@handle!='personal']//access");
                for (int i = 0; i < access.size(); i++) {

                    // Add impl attribute with value of fully-qualified class name
                    ((Element) access.get(i)).addAttribute("impl", BriefcaseAccessType.class.getName());

                    List types = ((Element) access.get(i)).elements();
                    for (int j = 0; j < types.size(); j++) {
                        Attribute value = ((Element) types.get(j)).attribute("value");
                        String text = value.getValue();
                        value.setValue("GRANT");

                        if (text.equals("0")) {
                            BriefcaseAccessType[] aTypes = BriefcaseAccessType.getInstances();
                            ((Element) types.get(j)).addAttribute("handle", aTypes[0].getName());

                            for (int k = 1; k < aTypes.length; k++) {
                                Element eType = dFac.createElement(new QName("type"), 2);
                                eType.addAttribute("value", "GRANT");
                                eType.addAttribute("handle", aTypes[k].getName());
                                ((Element) access.get(i)).add(eType);
                            }
                        } else {
                            ((Element) types.get(j)).addAttribute("handle",
                                    BriefcaseAccessType.getAccessType(Integer.parseInt(text)).getName());
                        }
                    }
                }

                // add impl attribute to specify the UserDirectory impl to user-attribute element
                List userAttr = oldDoc.selectNodes("//user-attribute");
                for (int i = 0; i < userAttr.size(); i++) {
                    ((Element) userAttr.get(i)).addAttribute("impl",
                            "net.unicon.academus.apps.briefcase.UserAttributeDirectory");
                }

                //replace the resource factory urls  
                List entries = oldDoc
                        .selectNodes("/briefcase/drive[@handle!='personal']//access-broker/entry[@target!='']");
                for (int i = 0; i < entries.size(); i++) {
                    ((Element) entries.get(i)).addAttribute("target", ((Element) entries.get(i))
                            .attributeValue("target").replaceAll("academus.resource.factory", "demetrius.fac"));
                }

                // add access element to specify the AccessType to the RdbmsAccessBroker
                brokers = oldDoc.selectNodes("/briefcase/drive[@handle!='personal']//access-broker[@impl='"
                        + RdbmsAccessBroker.class.getName() + "']");

                for (int i = 0; i < brokers.size(); i++) {
                    broker = (Element) brokers.get(i);
                    Element eType = dFac.createElement(new QName("access"), 1);
                    eType.addAttribute("impl", BriefcaseAccessType.class.getName());
                    broker.add(eType);
                }

                // add the civis address book information.
                Element drive = (Element) oldDoc.selectSingleNode("briefcase");
                drive.addComment("Civis implementation to be used to resolve usernames and group paths"
                        + " to academus users and groups. This should not require"
                        + " modification, as it utilized the Academus framework for gathering this"
                        + " information.");

                Element civis = dFac.createElement("civis");
                civis.addAttribute("id", "addressBook");
                civis.addAttribute("impl", "net.unicon.civis.fac.academus.AcademusCivisFactory");

                Element restrictor = dFac.createElement("restrictor");
                restrictor.addAttribute("impl", "net.unicon.civis.grouprestrictor.AcademusGroupRestrictor");
                civis.add(restrictor);

                drive.add(civis);

                File f = new File(args[1]);
                PrintWriter pw = new PrintWriter(new FileOutputStream(f));
                pw.write(oldDoc.asXML());
                pw.flush();
                pw.close();

                System.out.println(
                        "Done. Enjoy !! \n Remember to the use the migrated config file with the 1.6 deploy.");

            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            usage();
        }

    }

    /**
     * Command usage.
     *
     * Usage for net.unicon.academus.apps.briefcase.migrate.BriefcaseMigrator:<br>
     *         java -cp &lt;classpath&gt; net.unicon.academus.apps.briefcase.migrate.BriefcaseMigrator [arguments];
     * 
     * <p>In order to update the data in the database, a DataSource must
     * be created. The database specific information has to be set in the 
     * /migrate/migrate.properties file</p>
     * 
     * <p> The migration process needs the config file from Academus 1.5 Briefcase Portlet
     * deployment. The file location needs to be provided as the first argument. 
     * The Briefcase portlet config file will be updated to work with the new deployment. The 
     * second argument needs to specify the path for the updated config file. 
     * </p>
     * 
     */
    public static void usage() {
        System.out.println("Usage for " + BriefcaseMigrator.class.getName() + ":");
        System.out.println("\tjava -cp <classpath> " + BriefcaseMigrator.class.getName() + " [arguments] ");
        System.out.println();
        System.out.println("Arguments include: ");

        System.out.println("In order to update the data in the database, a DataSource must "
                + "be created. The database specific information has to be set in the "
                + "/migrate/migrate.properties file");
        System.out.println("The migration process needs the config file from Academus 1.5"
                + " Briefcase Portlet deployment. The file location needs to be provided "
                + "as the first argument.\n The Briefcase portlet config file will be "
                + "updated to work with the new deployment. The second argument needs "
                + "to specify the path for the updated config file.");
        System.out.println();

        System.exit(2);
    }

    private static void updateUrl(DataSource ds) {

        Connection conn = null;
        Statement stmt = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = ds.getConnection();

            stmt = conn.createStatement();

            stmt.executeUpdate("UPDATE ACCESS_ENTRY SET TARGET = replace(target"
                    + ", 'academus.resource.factory', 'demetrius.fac' ) ");

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (rs != null)
                closeResultSet(rs);
            rs = null;
            if (stmt != null)
                closeStatement(stmt);
            stmt = null;
            if (pstmt != null)
                closeStatement(pstmt);
            pstmt = null;
            if (conn != null)
                closeConnection(conn);
            conn = null;
        }

    }

    private static void updateSharedResourceUrls(DataSource ds) {

        Connection conn = null;
        Statement stmt = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        final String SELECT = "SELECT target, access_entry_id FROM access_entry WHERE access_controller_id=2";
        final String UPDATE = "UPDATE access_entry SET target = ? WHERE access_entry_id = ?";

        try {
            conn = ds.getConnection();

            // Get shared resource urls
            stmt = conn.createStatement();
            rs = stmt.executeQuery(SELECT);

            pstmt = conn.prepareStatement(UPDATE);

            StringBuffer url = new StringBuffer();
            int index = 0;

            while (rs.next()) {

                url.append(rs.getString("target"));
                // Assumes localdatapath portion of target does not contain ')'
                // Safe assumption because Shared folder functionality of 
                // briefcase would be broken if it did
                index = url.indexOf(")");
                url.replace(index, index + 1, "///");
                url.append(")");
                pstmt.setString(1, url.toString());
                pstmt.setLong(2, rs.getLong("access_entry_id"));

                pstmt.executeUpdate();

                // Clear resources
                pstmt.clearParameters();
                url.setLength(0);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (rs != null)
                closeResultSet(rs);
            rs = null;
            if (stmt != null)
                closeStatement(stmt);
            stmt = null;
            if (pstmt != null)
                closeStatement(pstmt);
            pstmt = null;
            if (conn != null)
                closeConnection(conn);
            conn = null;
        }

    }

    private static void updateAccessType(DataSource ds) {

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        PreparedStatement pstmt = null;

        final String INSERT = "INSERT INTO ACCESS_TYPES (ACCESS_ENTRY_ID, ACCESS_TYPE, STATUS)"
                + " VALUES (?, ?, ?)";

        final String DELETE = "DELETE FROM ACCESS_TYPES WHERE ACCESS_ENTRY_ID = ?";

        try {
            conn = ds.getConnection();

            stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

            rs = stmt.executeQuery("SELECT access_entry_id FROM access_types WHERE access_type = 0 ");

            long accessEntryId = -1;

            while (rs.next()) {

                accessEntryId = rs.getLong("access_entry_id");

                // remove the previous entries 
                pstmt = conn.prepareStatement(DELETE);
                pstmt.setLong(1, accessEntryId);

                pstmt.execute();

                // insert all the access_types allowed for owner
                BriefcaseAccessType[] types = BriefcaseAccessType.getInstances();
                for (int i = 0; i < types.length; i++) {
                    pstmt = conn.prepareStatement(INSERT);
                    pstmt.setLong(1, accessEntryId);
                    pstmt.setLong(2, types[i].toInt());
                    pstmt.setString(3, "T");

                    pstmt.execute();
                }
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (rs != null)
                closeResultSet(rs);
            rs = null;
            if (stmt != null)
                closeStatement(stmt);
            stmt = null;
            if (conn != null)
                closeConnection(conn);
            conn = null;
        }

    }

    private static void updateSequencers(DataSource ds) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        PreparedStatement pstmt = null;

        try {
            conn = ds.getConnection();

            stmt = conn.createStatement();

            // initialize the RdbmsAccessBroker sequencer
            rs = stmt.executeQuery(
                    "SELECT count(name) AS count_name FROM UNI_SEQUENCE WHERE NAME='RdbmsAccessBroker'");

            if (rs.next()) {

                int count = rs.getInt("count_name");

                if (count > 0) {
                    stmt.executeUpdate("UPDATE UNI_SEQUENCE SET NEXT_INDEX = "
                            + "(SELECT MAX(ACCESS_ENTRY_ID) + 1 FROM ACCESS_ENTRY) "
                            + "WHERE NAME='RdbmsAccessBroker'");
                } else {
                    stmt.executeUpdate("INSERT INTO UNI_SEQUENCE (NAME, NEXT_INDEX) "
                            + " SELECT 'RdbmsAccessBroker', MAX(ACCESS_ENTRY_ID) + 1 FROM ACCESS_ENTRY ");
                }
            }

            // initialize the FSA_Kernel_Sequencer sequencer
            rs = stmt.executeQuery(
                    "SELECT count(name) AS count_name FROM UNI_SEQUENCE WHERE NAME='FSA_Kernel_Sequencer'");

            if (rs.next()) {
                int count = rs.getInt("count_name");

                if (count > 0) {
                    stmt.executeUpdate("UPDATE UNI_SEQUENCE SET NEXT_INDEX = "
                            + "(SELECT MAX(ACCESS_ENTRY_ID) + 1 FROM ACCESS_ENTRY) "
                            + "WHERE NAME='FSA_Kernel_Sequencer'");
                } else {
                    stmt.executeUpdate("INSERT INTO UNI_SEQUENCE (NAME, NEXT_INDEX) "
                            + " SELECT 'FSA_Kernel_Sequencer', MAX(ID) + 1 FROM FSA_KERNEL_SEQUENCER ");
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (rs != null)
                closeResultSet(rs);
            rs = null;
            if (stmt != null)
                closeStatement(stmt);
            stmt = null;
            if (conn != null)
                closeConnection(conn);
            conn = null;
        }

    }

    private static void closeConnection(Connection conn) {
        if (conn == null) {
            return;
        }

        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static void closeResultSet(ResultSet rs) {
        if (rs == null) {
            return;
        }

        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static void closeStatement(Statement stmt) {
        if (stmt == null) {
            return;
        }

        try {
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}