001/****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one   *
003 * or more contributor license agreements.  See the NOTICE file *
004 * distributed with this work for additional information        *
005 * regarding copyright ownership.  The ASF licenses this file   *
006 * to you under the Apache License, Version 2.0 (the            *
007 * "License"); you may not use this file except in compliance   *
008 * with the License.  You may obtain a copy of the License at   *
009 *                                                              *
010 *   http://www.apache.org/licenses/LICENSE-2.0                 *
011 *                                                              *
012 * Unless required by applicable law or agreed to in writing,   *
013 * software distributed under the License is distributed on an  *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015 * KIND, either express or implied.  See the License for the    *
016 * specific language governing permissions and limitations      *
017 * under the License.                                           *
018 ****************************************************************/
019package org.apache.james.mailbox.jpa.migrator.command;
020
021import javax.persistence.EntityManager;
022import javax.persistence.Query;
023
024import org.apache.james.mailbox.jpa.migrator.exception.JpaMigrateException;
025import org.apache.openjpa.kernel.DelegatingResultList;
026import org.apache.openjpa.lib.rop.ResultList;
027
028/**
029 * JIRA IMAP-180 is "Add @ElementJoinColumn for Property and Header tables".
030 * 
031 * 1. Add the needed columns on HEADER and PROPERTY
032 * ALTER TABLE HEADER ADD COLUMN MESSAGE_ID BIGINT
033 * ALTER TABLE PROPERTY ADD COLUMN MESSAGE_ID BIGINT
034 * 
035 * 2. Link the HEADER/PROPERTY tables with the MESSAGE table
036 * SELECT * FROM MESSAGE_HEADER / MESSAGE_HEADER
037 * 
038 * 3. Add the needed FK and indexes on HEADER and PROPERTY
039 * CREATE INDEX SQL100727182411700 ON HEADER(MESSAGE_ID)
040 * ALTER TABLE HEADER ADD CONSTRAINT SQL100727182411700 FOREIGN KEY (MESSAGE_ID) REFERENCES MESSAGE(ID)
041 * CREATE INDEX SQL100727182411780 ON PROPERTY(MESSAGE_ID)
042 * ALTER TABLE PROPERTY ADD CONSTRAINT SQL100727182411780 FOREIGN KEY (MESSAGE_ID) REFERENCES MESSAGE(ID)
043 * 
044 * 4. Drop the MESSAGE_HEADER and MESSAGE_PROPERY tables
045 * DROP TABLE MESSAGE_HEADER
046 * DROP TABLE MESSAGE_PROPERTY
047 * 
048 * @link https://issues.apache.org/jira/browse/IMAP-180
049 * 
050 */
051public class IMAP180JpaMigrateCommand implements JpaMigrateCommand {
052
053    /**
054     * @see org.apache.james.mailbox.jpa.migrator.command#migrate(javax.persistence.EntityManager)
055     */
056    public void migrate(EntityManager em) throws JpaMigrateException {
057        em.getTransaction().commit();
058        migrateHeaders(em);
059        // Commit after header migration.
060        migrateProperties(em);
061        em.getTransaction().begin();
062    }
063        
064    /**
065     * Migrate the headers.
066     */
067    @SuppressWarnings("rawtypes")
068    private static void migrateHeaders(EntityManager em) {
069        
070        em.getTransaction().begin();
071        Query headerCountQuery = em.createNativeQuery("SELECT COUNT(MESSAGE_ID) FROM MESSAGE_HEADER", Integer.class);
072        Integer headerCount = (Integer) headerCountQuery.getResultList().get(0);
073        System.out.println("Number of headers=" + headerCount);
074        
075        JpaMigrateQuery.executeUpdate(em, "ALTER TABLE HEADER ADD COLUMN MESSAGE_ID BIGINT");
076        
077        Query headerQuery = em.createNativeQuery("SELECT MESSAGE_ID, HEADERS_ID FROM MESSAGE_HEADER");
078        em.getTransaction().commit();
079        
080        DelegatingResultList headerNameList = (DelegatingResultList) headerQuery.getResultList();
081        ResultList rl = headerNameList.getDelegate();
082        for (int i=0; i < rl.size(); i++) {
083            Object[] results = (Object[]) rl.get(i);
084            Long messageId = (Long) results[0];
085            Long headerId = (Long) results[1];
086            em.getTransaction().begin();
087            Query update = em.createNativeQuery("UPDATE HEADER SET MESSAGE_ID = ? WHERE ID = ?");
088            update.setParameter(1, messageId);
089            update.setParameter(2, headerId);
090            int result = update.executeUpdate();
091            System.out.printf("ExecuteUpdate returned a result=" + result + " for header %d of %d\n", i+1, headerCount);
092            em.getTransaction().commit();
093        }
094
095        em.getTransaction().begin();
096        System.out.println("Creating index.");
097        JpaMigrateQuery.executeUpdate(em, "CREATE INDEX SQL100727182411700 ON HEADER(MESSAGE_ID)");
098        em.getTransaction().commit();
099        
100        em.getTransaction().begin();
101        System.out.println("Creating foreign key.");
102        JpaMigrateQuery.executeUpdate(em, "ALTER TABLE HEADER ADD CONSTRAINT SQL100727182411700 FOREIGN KEY (MESSAGE_ID) REFERENCES MESSAGE(ID)");
103        em.getTransaction().commit();
104
105        em.getTransaction().begin();
106        System.out.println("Dropping table.");
107        JpaMigrateQuery.executeUpdate(em, "DROP TABLE MESSAGE_HEADER");
108        em.getTransaction().commit();
109
110    }
111        
112    /**
113     * Migrate the properties.
114     */
115    @SuppressWarnings("rawtypes")
116    private static void migrateProperties(EntityManager em) {
117        
118        em.getTransaction().begin();
119        Query propertyCountQuery = em.createNativeQuery("SELECT COUNT(MESSAGE_ID) FROM MESSAGE_PROPERTY", Integer.class);
120        Integer propertyCount = (Integer) propertyCountQuery.getResultList().get(0);
121        System.out.println("Number of headers=" + propertyCount);
122
123        JpaMigrateQuery.executeUpdate(em, "ALTER TABLE PROPERTY ADD COLUMN MESSAGE_ID BIGINT");
124
125        Query propertyQuery = em.createNativeQuery("SELECT MESSAGE_ID, PROPERTIES_ID FROM MESSAGE_PROPERTY");
126        em.getTransaction().commit();
127
128        DelegatingResultList propertyNameList = (DelegatingResultList) propertyQuery.getResultList();
129        ResultList rl = propertyNameList.getDelegate();
130        for (int i=0; i < rl.size(); i++) {
131            Object[] results = (Object[]) rl.get(i);
132            Long messageId = (Long) results[0];
133            Long propertyId = (Long) results[1];
134            em.getTransaction().begin();
135            Query update = em.createNativeQuery("UPDATE PROPERTY SET MESSAGE_ID = ? WHERE ID = ?");
136            update.setParameter(1, messageId);
137            update.setParameter(2, propertyId);
138            int result = update.executeUpdate();
139            System.out.printf("ExecuteUpdate returned a result=" + result + " for property %d of %d\n", i+1, propertyCount);     
140            em.getTransaction().commit();
141        }
142        
143        em.getTransaction().begin();
144        System.out.println("Creating index.");
145        JpaMigrateQuery.executeUpdate(em, "CREATE INDEX SQL100727182411780 ON PROPERTY(MESSAGE_ID)");
146        em.getTransaction().commit();
147        
148        em.getTransaction().begin();
149        System.out.println("Creating foreign key.");
150        JpaMigrateQuery.executeUpdate(em, "ALTER TABLE PROPERTY ADD CONSTRAINT SQL100727182411780 FOREIGN KEY (MESSAGE_ID) REFERENCES MESSAGE(ID)");
151        em.getTransaction().commit();
152
153        em.getTransaction().begin();
154        System.out.println("Dropping table.");
155        JpaMigrateQuery.executeUpdate(em, "DROP TABLE MESSAGE_PROPERTY");
156        em.getTransaction().commit();
157        
158    }
159
160}