Changeset 620


Ignore:
Timestamp:
01/21/10 18:43:37 (2 years ago)
Author:
octorian
Message:

Implemented move in cases where load-from-cache is necessary, and fixed serious issues in MIME serialization of multi-part messages.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LogicMail/src/org/logicprobe/LogicMail/message/AbstractMimeMessagePartVisitor.java

    r469 r620  
    4040        public void visitImagePart(ImagePart part) { } 
    4141        public void visitMessagePart(MessagePart part) { } 
    42         public void visitMultiPart(MultiPart part) { } 
    4342        public void visitTextPart(TextPart part) { } 
    4443        public void visitVideoPart(VideoPart part) { } 
    4544        public void visitUnsupportedPart(UnsupportedPart part) { } 
     45    public void visitMultiPart(MultiPart part) { 
     46        MimeMessagePart[] parts = part.getParts(); 
     47        if(parts != null) { 
     48            for(int i=0;i<parts.length;i++) 
     49                parts[i].accept(this); 
     50        } 
     51    } 
    4652} 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/message/MessageMimeConverter.java

    r467 r620  
    3434import net.rim.device.api.mime.MIMEOutputStream; 
    3535import net.rim.device.api.system.EncodedImage; 
    36  
     36import net.rim.device.api.system.EventLogger; 
     37 
     38import org.logicprobe.LogicMail.AppInfo; 
    3739import org.logicprobe.LogicMail.util.StringParser; 
    3840 
     
    7476    public String toMimeString() { 
    7577        message.getStructure().accept(partVisitor); 
    76         try { 
    77             mimeOutputStream.flush(); 
    78             mimeOutputStream.close(); 
    79         } catch (IOException ex) { 
    80             System.err.println("Unable to close MIMEOutputStream"); 
    81  
    82             return ""; 
    83         } 
    84  
     78        partMimeMap.clear(); 
    8579        return byteArrayOutputStream.toString(); 
    8680    } 
     
    8882    private class MessageMimeConverterPartVisitor extends AbstractMimeMessagePartVisitor { 
    8983            public void visitMultiPart(MultiPart part) { 
    90                 // Handle the case of this being the root part 
    91                 if (mimeOutputStream == null) { 
    92                     mimeOutputStream = new MIMEOutputStream(byteArrayOutputStream, 
    93                             true, null); 
    94                     mimeOutputStream.setContentType(part.getMimeType() + "/" + 
    95                         part.getMimeSubtype()); 
    96                     partMimeMap.put(part, mimeOutputStream); 
    97                 } 
    98                 // Otherwise handle the case of this being a child part 
    99                 else { 
    100                     MIMEOutputStream parentStream = (MIMEOutputStream) partMimeMap.get(part.getParent()); 
    101                     MIMEOutputStream currentStream = parentStream.getPartOutputStream(true, 
    102                             null); 
    103                     partMimeMap.put(part, currentStream); 
    104                 } 
     84                MIMEOutputStream currentStream = startCurrentStream(part, null); 
     85                currentStream.setContentType(part.getMimeType() + '/' + part.getMimeSubtype()); 
     86                 
     87                // Call the superclass implementation which will iterate through 
     88                // all the child parts and cause their handlers to be called. 
     89                super.visitMultiPart(part); 
     90 
     91                finishCurrentStream(currentStream); 
    10592            } 
    10693         
     
    163150                //            encoding = "base64"; 
    164151                //        } 
    165                 MIMEOutputStream currentStream; 
    166          
    167                 if (mimeOutputStream == null) { 
    168                     mimeOutputStream = new MIMEOutputStream(byteArrayOutputStream, 
    169                             false, encoding); 
    170                     currentStream = mimeOutputStream; 
    171                 } else { 
    172                     MIMEOutputStream parentStream = (MIMEOutputStream) partMimeMap.get(part.getParent()); 
    173                     currentStream = parentStream.getPartOutputStream(false, encoding); 
    174                 } 
    175          
    176                 partMimeMap.put(part, currentStream); 
    177                 currentStream.setContentType(part.getMimeType() + "/" + 
     152                MIMEOutputStream currentStream = startCurrentStream(part, encoding); 
     153         
     154                currentStream.setContentType(part.getMimeType() + '/' + 
    178155                    part.getMimeSubtype()); 
    179156                currentStream.addContentTypeParameter("charset", charset.toLowerCase()); 
     
    193170                    } 
    194171                } catch (IOException e) { 
    195                     System.err.println("Error encoding content"); 
    196                 } 
    197             } 
    198          
     172                EventLogger.logEvent(AppInfo.GUID, 
     173                        ("MIME conversion error: " + e.toString()).getBytes(), 
     174                        EventLogger.ERROR); 
     175                } 
     176                 
     177                finishCurrentStream(currentStream); 
     178            } 
     179 
    199180            public void visitImagePart(ImagePart part) { 
    200                 MIMEOutputStream currentStream; 
    201  
    202181                MimeMessageContent content = message.getContent(part); 
    203182                if(!(content instanceof ImageContent)) { return; } 
    204183                EncodedImage image = ((ImageContent)content).getImage(); 
    205184 
    206                  
    207                 if (mimeOutputStream == null) { 
    208                     mimeOutputStream = new MIMEOutputStream(byteArrayOutputStream, 
    209                             false, "base64"); 
    210                     currentStream = mimeOutputStream; 
    211                 } else { 
    212                     MIMEOutputStream parentStream = (MIMEOutputStream) partMimeMap.get(part.getParent()); 
    213                     currentStream = parentStream.getPartOutputStream(false, "base64"); 
    214                 } 
    215          
    216                 partMimeMap.put(part, currentStream); 
    217                 currentStream.setContentType(part.getMimeType() + "/" + 
     185                MIMEOutputStream currentStream = startCurrentStream(part, "base64"); 
     186                 
     187                currentStream.setContentType(part.getMimeType() + '/' + 
    218188                    part.getMimeSubtype()); 
    219189         
     
    222192                    currentStream.write(Base64OutputStream.encode(data, 0, data.length, true, true)); 
    223193                } catch (IOException e) { 
    224                     System.err.println("Error encoding content"); 
    225                 } 
     194                EventLogger.logEvent(AppInfo.GUID, 
     195                        ("MIME conversion error: " + e.toString()).getBytes(), 
     196                        EventLogger.ERROR); 
     197                } 
     198                 
     199                finishCurrentStream(currentStream); 
    226200            } 
    227201         
    228202            public void visitUnsupportedPart(UnsupportedPart part) { 
    229                 MIMEOutputStream currentStream; 
    230          
    231                 if (mimeOutputStream == null) { 
    232                     mimeOutputStream = new MIMEOutputStream(byteArrayOutputStream, 
    233                             false, "7bit"); 
    234                     currentStream = mimeOutputStream; 
    235                 } else { 
    236                     MIMEOutputStream parentStream = (MIMEOutputStream) partMimeMap.get(part.getParent()); 
    237                     currentStream = parentStream.getPartOutputStream(false, "7bit"); 
    238                 } 
    239          
    240                 partMimeMap.put(part, currentStream); 
     203                MIMEOutputStream currentStream = startCurrentStream(part, "7bit"); 
     204         
    241205                currentStream.setContentType("text/plain"); 
    242206         
     
    244208                    currentStream.write("Unable to encode part".getBytes()); 
    245209                } catch (IOException e) { 
    246                     System.err.println("Error encoding content"); 
    247                 } 
    248             } 
     210                EventLogger.logEvent(AppInfo.GUID, 
     211                        ("MIME conversion error: " + e.toString()).getBytes(), 
     212                        EventLogger.ERROR); 
     213                } 
     214                 
     215                finishCurrentStream(currentStream); 
     216            } 
     217             
     218        private MIMEOutputStream startCurrentStream(MimeMessagePart part, String encoding) { 
     219            MIMEOutputStream currentStream; 
     220            boolean isMultiPart = (part instanceof MultiPart); 
     221            if (mimeOutputStream == null) { 
     222                mimeOutputStream = new MIMEOutputStream( 
     223                        byteArrayOutputStream, 
     224                        isMultiPart, 
     225                        encoding); 
     226                currentStream = mimeOutputStream; 
     227            } else { 
     228                MIMEOutputStream parentStream = (MIMEOutputStream) partMimeMap.get(part.getParent()); 
     229                currentStream = parentStream.getPartOutputStream(isMultiPart, encoding); 
     230            } 
     231            partMimeMap.put(part, currentStream); 
     232            return currentStream; 
     233        } 
     234         
     235        private void finishCurrentStream(MIMEOutputStream currentStream) { 
     236            try { 
     237                currentStream.flush(); 
     238                currentStream.close(); 
     239            } catch (IOException e) { 
     240                EventLogger.logEvent(AppInfo.GUID, 
     241                        ("MIME conversion error: " + e.toString()).getBytes(), 
     242                        EventLogger.ERROR); 
     243            } 
     244        } 
    249245    } 
    250246} 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/message/MultiPart.java

    r518 r620  
    8383    public void accept(MimeMessagePartVisitor visitor) { 
    8484        visitor.visitMultiPart(this); 
    85         if(parts != null) { 
    86             for(int i=0;i<parts.length;i++) 
    87                 parts[i].accept(visitor); 
    88         } 
    8985    } 
    9086 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/ui/MessageActions.java

    r618 r620  
    4949import org.logicprobe.LogicMail.model.MailboxNode; 
    5050import org.logicprobe.LogicMail.model.MessageNode; 
     51import org.logicprobe.LogicMail.model.MessageNodeEvent; 
     52import org.logicprobe.LogicMail.model.MessageNodeListener; 
    5153import org.logicprobe.LogicMail.model.OutgoingMessageNode; 
    5254 
     
    379381     */ 
    380382    public void copyToMailbox(MessageNode messageNode) { 
    381         if(messageNode.hasMessageContent()) { 
     383        if(messageNode.hasMessageContent() || messageNode.hasCachedContent()) { 
    382384            // Normal case where the message has been loaded within the 
    383385            // data model and all copy options should be made available. 
     
    398400                                selectedMailbox.copyMessageInto(messageNode); 
    399401                        } 
    400                         else { 
     402                        else if(messageNode.hasMessageContent()) { 
    401403                            // Protocol-level copy is not possible, so just append 
    402404                            // to the destination mailbox. 
    403405                                selectedMailbox.appendMessage(messageNode); 
     406                        } 
     407                        else if(messageNode.hasCachedContent()) { 
     408                            // Message is available in the cache, but not yet loaded. 
     409                            // We need to first load from the cache, then proceed with 
     410                            // an append on the destination mailbox. 
     411                             
     412                            // Add a listener to the message node and then trigger a refresh. 
     413                            messageNode.addMessageNodeListener(new CopyToMessageNodeListener(selectedMailbox)); 
     414                            messageNode.refreshMessage(); 
    404415                        } 
    405416                } 
     
    425436     
    426437    /** 
     438     * Handles the result of a message refresh as triggered by a copy 
     439     * operation when the message needs to be loaded from cache. 
     440     */ 
     441    private class CopyToMessageNodeListener implements MessageNodeListener { 
     442        private MailboxNode selectedMailbox; 
     443        public CopyToMessageNodeListener(MailboxNode selectedMailbox) { 
     444            this.selectedMailbox = selectedMailbox; 
     445        } 
     446 
     447        public void messageStatusChanged(MessageNodeEvent e) { 
     448            if(e.getType() == MessageNodeEvent.TYPE_CONTENT_LOADED) { 
     449                // Remove this listener from the message node, and request 
     450                // that it be appended to the selected destination mailbox. 
     451                MessageNode messageNode = (MessageNode)e.getSource(); 
     452                messageNode.removeMessageNodeListener(this); 
     453                selectedMailbox.appendMessage(messageNode); 
     454            } 
     455        } 
     456    } 
     457     
     458    /** 
    427459     * Move the message to another mailbox. 
    428460     *  
  • trunk/LogicMailTests/src/org/logicprobe/LogicMail/message/MessageMimeConverterTest.java

    r92 r620  
    3131package org.logicprobe.LogicMail.message; 
    3232 
     33import java.io.ByteArrayInputStream; 
     34import java.io.IOException; 
     35import java.util.Hashtable; 
     36 
     37import org.logicprobe.LogicMail.util.MailMessageParser; 
     38 
    3339import j2meunit.framework.Test; 
    3440import j2meunit.framework.TestCase; 
     
    5359    } 
    5460     
    55 //    public void testFoo() { 
    56 //    } 
    57  
     61    public void testSinglePartMessage() { 
     62        TextPart textPart = new TextPart("plain", "", "7bit", "us-ascii", "", "", 0); 
     63        TextContent textContent = new TextContent(textPart, "Hello World"); 
     64         
     65        Message message = new Message(textPart); 
     66        message.putContent(textPart, textContent); 
     67         
     68        MessageMimeConverter instance = new MessageMimeConverter(message); 
     69        String result = instance.toMimeString(); 
     70         
     71        Hashtable resultContentMap = new Hashtable(); 
     72        MimeMessagePart resultPart; 
     73        try { 
     74            resultPart = MailMessageParser.parseRawMessage( 
     75                    resultContentMap, 
     76                    new ByteArrayInputStream(result.getBytes())); 
     77        } catch (IOException e) { 
     78            fail(); 
     79            return; 
     80        } 
     81         
     82        assertTrue(resultPart instanceof TextPart); 
     83        assertEquals("plain", resultPart.getMimeSubtype().toLowerCase()); 
     84        assertEquals("7bit", ((TextPart)resultPart).getEncoding().toLowerCase()); 
     85        assertEquals("us-ascii", ((TextPart)resultPart).getCharset().toLowerCase()); 
     86         
     87        assertTrue(resultContentMap.containsKey(resultPart)); 
     88        TextContent resultTextContent = (TextContent)resultContentMap.get(resultPart); 
     89        assertEquals("Hello World", resultTextContent.getText()); 
     90    } 
     91 
     92    public void testMultiPartMessage() { 
     93        TextPart textPart1 = new TextPart("plain", "", "7bit", "us-ascii", "", "", 0); 
     94        TextContent textContent1 = new TextContent(textPart1, "Hello World"); 
     95        TextPart textPart2 = new TextPart("plain", "", "7bit", "us-ascii", "", "", 0); 
     96        TextContent textContent2 = new TextContent(textPart2, "Goodbye World"); 
     97 
     98        MultiPart multiPart = new MultiPart("mixed"); 
     99        multiPart.addPart(textPart1); 
     100        multiPart.addPart(textPart2); 
     101         
     102        Message message = new Message(multiPart); 
     103        message.putContent(textPart1, textContent1); 
     104        message.putContent(textPart2, textContent2); 
     105         
     106        MessageMimeConverter instance = new MessageMimeConverter(message); 
     107        String result = instance.toMimeString(); 
     108         
     109        Hashtable resultContentMap = new Hashtable(); 
     110        MimeMessagePart resultPart; 
     111        try { 
     112            resultPart = MailMessageParser.parseRawMessage( 
     113                    resultContentMap, 
     114                    new ByteArrayInputStream(result.getBytes())); 
     115        } catch (IOException e) { 
     116            fail(); 
     117            return; 
     118        } 
     119         
     120        assertTrue(resultPart instanceof MultiPart); 
     121        MultiPart resultMultiPart = (MultiPart)resultPart; 
     122        assertEquals("mixed", resultMultiPart.getMimeSubtype()); 
     123         
     124        MimeMessagePart[] resultParts = resultMultiPart.getParts(); 
     125        assertNotNull(resultParts); 
     126        assertEquals(2, resultParts.length); 
     127        assertTrue(resultParts[0] instanceof TextPart); 
     128        assertTrue(resultParts[1] instanceof TextPart); 
     129         
     130        TextPart resultTextPart1 = (TextPart)resultParts[0]; 
     131        assertEquals("plain", resultTextPart1.getMimeSubtype().toLowerCase()); 
     132        assertEquals("7bit", resultTextPart1.getEncoding().toLowerCase()); 
     133        assertEquals("us-ascii", resultTextPart1.getCharset().toLowerCase()); 
     134        assertTrue(resultContentMap.containsKey(resultTextPart1)); 
     135        TextContent resultTextContent1 = (TextContent)resultContentMap.get(resultTextPart1); 
     136        assertEquals("Hello World", resultTextContent1.getText()); 
     137         
     138        TextPart resultTextPart2 = (TextPart)resultParts[1]; 
     139        assertEquals("plain", resultTextPart2.getMimeSubtype().toLowerCase()); 
     140        assertEquals("7bit", resultTextPart2.getEncoding().toLowerCase()); 
     141        assertEquals("us-ascii", resultTextPart2.getCharset().toLowerCase()); 
     142        assertTrue(resultContentMap.containsKey(resultTextPart2)); 
     143        TextContent resultTextContent2 = (TextContent)resultContentMap.get(resultTextPart2); 
     144        assertEquals("Goodbye World", resultTextContent2.getText()); 
     145    } 
     146 
     147    public void testComplexMultiPartMessage() { 
     148        TextPart textPart1a = new TextPart("plain", "", "7bit", "us-ascii", "", "", 0); 
     149        TextContent textContent1a = new TextContent(textPart1a, "Hello World"); 
     150        TextPart textPart1b = new TextPart("plain", "", "7bit", "us-ascii", "", "", 0); 
     151        TextContent textContent1b = new TextContent(textPart1b, "Goodbye World"); 
     152        MultiPart multiPart1 = new MultiPart("mixed"); 
     153        multiPart1.addPart(textPart1a); 
     154        multiPart1.addPart(textPart1b); 
     155         
     156        TextPart textPart2a = new TextPart("plain", "", "7bit", "us-ascii", "", "", 0); 
     157        TextContent textContent2a = new TextContent(textPart2a, "Foo"); 
     158        TextPart textPart2b = new TextPart("plain", "", "7bit", "us-ascii", "", "", 0); 
     159        TextContent textContent2b = new TextContent(textPart2b, "Bar"); 
     160        MultiPart multiPart2 = new MultiPart("mixed"); 
     161        multiPart2.addPart(textPart2a); 
     162        multiPart2.addPart(textPart2b); 
     163         
     164        MultiPart multiPart = new MultiPart("mixed"); 
     165        multiPart.addPart(multiPart1); 
     166        multiPart.addPart(multiPart2); 
     167         
     168        Message message = new Message(multiPart); 
     169        message.putContent(textPart1a, textContent1a); 
     170        message.putContent(textPart1b, textContent1b); 
     171        message.putContent(textPart2a, textContent2a); 
     172        message.putContent(textPart2b, textContent2b); 
     173         
     174        MessageMimeConverter instance = new MessageMimeConverter(message); 
     175        String result = instance.toMimeString(); 
     176         
     177        Hashtable resultContentMap = new Hashtable(); 
     178        MimeMessagePart resultPart; 
     179        try { 
     180            resultPart = MailMessageParser.parseRawMessage( 
     181                    resultContentMap, 
     182                    new ByteArrayInputStream(result.getBytes())); 
     183        } catch (IOException e) { 
     184            fail(); 
     185            return; 
     186        } 
     187         
     188        assertTrue(resultPart instanceof MultiPart); 
     189        MultiPart resultMultiPart = (MultiPart)resultPart; 
     190        assertEquals("mixed", resultMultiPart.getMimeSubtype()); 
     191         
     192        MimeMessagePart[] resultParts = resultMultiPart.getParts(); 
     193        assertNotNull(resultParts); 
     194        assertEquals(2, resultParts.length); 
     195        assertTrue(resultParts[0] instanceof MultiPart); 
     196        assertTrue(resultParts[1] instanceof MultiPart); 
     197         
     198        MultiPart resultMultiPart1 = (MultiPart)resultParts[0]; 
     199        assertEquals("mixed", resultMultiPart1.getMimeSubtype()); 
     200        MimeMessagePart[] resultSubParts1 = resultMultiPart1.getParts(); 
     201        assertEquals(2, resultSubParts1.length); 
     202        assertTrue(resultSubParts1[0] instanceof TextPart); 
     203        assertTrue(resultSubParts1[1] instanceof TextPart); 
     204        TextPart resultTextPart1a = (TextPart)resultSubParts1[0]; 
     205        TextPart resultTextPart1b = (TextPart)resultSubParts1[1]; 
     206         
     207        assertTrue(resultContentMap.containsKey(resultTextPart1a)); 
     208        TextContent resultTextContent1a = (TextContent)resultContentMap.get(resultTextPart1a); 
     209        assertEquals("Hello World", resultTextContent1a.getText()); 
     210        assertTrue(resultContentMap.containsKey(resultTextPart1b)); 
     211        TextContent resultTextContent1b = (TextContent)resultContentMap.get(resultTextPart1b); 
     212        assertEquals("Goodbye World", resultTextContent1b.getText()); 
     213         
     214        MultiPart resultMultiPart2 = (MultiPart)resultParts[1]; 
     215        assertEquals("mixed", resultMultiPart2.getMimeSubtype()); 
     216        MimeMessagePart[] resultSubParts2 = resultMultiPart2.getParts(); 
     217        assertEquals(2, resultSubParts2.length); 
     218        assertTrue(resultSubParts2[0] instanceof TextPart); 
     219        assertTrue(resultSubParts2[1] instanceof TextPart); 
     220        TextPart resultTextPart2a = (TextPart)resultSubParts2[0]; 
     221        TextPart resultTextPart2b = (TextPart)resultSubParts2[1]; 
     222         
     223        assertTrue(resultContentMap.containsKey(resultTextPart2a)); 
     224        TextContent resultTextContent2a = (TextContent)resultContentMap.get(resultTextPart2a); 
     225        assertEquals("Foo", resultTextContent2a.getText()); 
     226        assertTrue(resultContentMap.containsKey(resultTextPart2b)); 
     227        TextContent resultTextContent2b = (TextContent)resultContentMap.get(resultTextPart2b); 
     228        assertEquals("Bar", resultTextContent2b.getText()); 
     229    } 
     230     
    58231    public Test suite() { 
    59232        TestSuite suite = new TestSuite("MessageMimeConverter"); 
    60 //        suite.addTest(new MessageMimeConverterTest("testFoo", new TestMethod() 
    61 //        { public void run(TestCase tc) {((MessageMimeConverterTest)tc).testFoo(); } })); 
     233 
     234        suite.addTest(new MessageMimeConverterTest("singlePartMessage", new TestMethod() 
     235        { public void run(TestCase tc) {((MessageMimeConverterTest)tc).testSinglePartMessage(); } })); 
     236        suite.addTest(new MessageMimeConverterTest("multiPartMessage", new TestMethod() 
     237        { public void run(TestCase tc) {((MessageMimeConverterTest)tc).testMultiPartMessage(); } })); 
     238        suite.addTest(new MessageMimeConverterTest("complexMultiPartMessage", new TestMethod() 
     239        { public void run(TestCase tc) {((MessageMimeConverterTest)tc).testComplexMultiPartMessage(); } })); 
    62240         
    63241        return suite; 
Note: See TracChangeset for help on using the changeset viewer.