blob: 17bd1385ac1984e0d5cc06e9dcd37899169cd3e9 [file] [log] [blame]
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.mime4j.samples.tree;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Date;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeSelectionModel;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.dom.BinaryBody;
import org.apache.james.mime4j.dom.Body;
import org.apache.james.mime4j.dom.Entity;
import org.apache.james.mime4j.dom.Header;
import org.apache.james.mime4j.dom.Message;
import org.apache.james.mime4j.dom.MessageBuilder;
import org.apache.james.mime4j.dom.Multipart;
import org.apache.james.mime4j.dom.TextBody;
import org.apache.james.mime4j.dom.address.Mailbox;
import org.apache.james.mime4j.dom.address.MailboxList;
import org.apache.james.mime4j.dom.field.AddressListField;
import org.apache.james.mime4j.dom.field.ContentTypeField;
import org.apache.james.mime4j.dom.field.DateTimeField;
import org.apache.james.mime4j.dom.field.UnstructuredField;
import org.apache.james.mime4j.field.address.AddressFormatter;
import org.apache.james.mime4j.message.BodyPart;
import org.apache.james.mime4j.message.MessageImpl;
import org.apache.james.mime4j.message.DefaultMessageBuilder;
import org.apache.james.mime4j.stream.Field;
/**
* Displays a parsed Message in a window. The window will be divided into
* two panels. The left panel displays the Message tree. Clicking on a
* node in the tree shows information on that node in the right panel.
*
* Some of this code have been copied from the Java tutorial's JTree section.
*/
public class MessageTree extends JPanel implements TreeSelectionListener {
private static final long serialVersionUID = 1L;
private final JTextArea textView;
private final JTree tree;
/**
* Wraps an Object and associates it with a text. All message parts
* (headers, bodies, multiparts, body parts) will be wrapped in
* ObjectWrapper instances before they are added to the JTree instance.
*/
public static class ObjectWrapper {
private String text = "";
private Object object = null;
public ObjectWrapper(String text, Object object) {
this.text = text;
this.object = object;
}
@Override
public String toString() {
return text;
}
public Object getObject() {
return object;
}
}
/**
* Creates a new <code>MessageTree</code> instance displaying the
* specified <code>Message</code>.
*
* @param message the message to display.
*/
public MessageTree(Message message) {
super(new GridLayout(1,0));
DefaultMutableTreeNode root = createNode(message);
tree = new JTree(root);
tree.getSelectionModel().setSelectionMode(
TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.addTreeSelectionListener(this);
JScrollPane treeView = new JScrollPane(tree);
JPanel contentPane = new JPanel(new GridLayout(1, 0));
JScrollPane contentView = new JScrollPane(contentPane);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
splitPane.setLeftComponent(treeView);
splitPane.setRightComponent(contentView);
Dimension minimumSize = new Dimension(100, 50);
contentView.setMinimumSize(minimumSize);
treeView.setMinimumSize(minimumSize);
splitPane.setDividerLocation(250);
splitPane.setPreferredSize(new Dimension(750, 500));
add(splitPane);
textView = new JTextArea();
textView.setEditable(false);
textView.setLineWrap(true);
contentPane.add(textView);
}
/**
* Create a node given a Multipart body.
* Add the Preamble, all Body parts and the Epilogue to the node.
*
* @return the root node of the tree.
*/
private DefaultMutableTreeNode createNode(Header header) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(
new ObjectWrapper("Header", header));
for (Field field : header.getFields()) {
String name = field.getName();
node.add(new DefaultMutableTreeNode(new ObjectWrapper(name, field)));
}
return node;
}
/**
* Create a node given a Multipart body.
* Add the Preamble, all Body parts and the Epilogue to the node.
*
* @param multipart the Multipart.
* @return the root node of the tree.
*/
private DefaultMutableTreeNode createNode(Multipart multipart) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(
new ObjectWrapper("Multipart", multipart));
node.add(new DefaultMutableTreeNode(
new ObjectWrapper("Preamble", multipart.getPreamble())));
for (Entity part : multipart.getBodyParts()) {
node.add(createNode(part));
}
node.add(new DefaultMutableTreeNode(
new ObjectWrapper("Epilogue", multipart.getEpilogue())));
return node;
}
/**
* Creates the tree nodes given a MIME entity (either a Message or
* a BodyPart).
*
* @param entity the entity.
* @return the root node of the tree displaying the specified entity and
* its children.
*/
private DefaultMutableTreeNode createNode(Entity entity) {
/*
* Create the root node for the entity. It's either a
* Message or a Body part.
*/
String type = "Message";
if (entity instanceof BodyPart) {
type = "Body part";
}
DefaultMutableTreeNode node = new DefaultMutableTreeNode(
new ObjectWrapper(type, entity));
/*
* Add the node encapsulating the entity Header.
*/
node.add(createNode(entity.getHeader()));
Body body = entity.getBody();
if (body instanceof Multipart) {
/*
* The body of the entity is a Multipart.
*/
node.add(createNode((Multipart) body));
} else if (body instanceof MessageImpl) {
/*
* The body is another Message.
*/
node.add(createNode((MessageImpl) body));
} else {
/*
* Discrete Body (either of type TextBody or BinaryBody).
*/
type = "Text body";
if (body instanceof BinaryBody) {
type = "Binary body";
}
type += " (" + entity.getMimeType() + ")";
node.add(new DefaultMutableTreeNode(new ObjectWrapper(type, body)));
}
return node;
}
/**
* Called whenever the selection changes in the JTree instance showing
* the Message nodes.
*
* @param e the event.
*/
public void valueChanged(TreeSelectionEvent e) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)
tree.getLastSelectedPathComponent();
textView.setText("");
if (node == null) {
return;
}
Object o = ((ObjectWrapper) node.getUserObject()).getObject();
if (node.isLeaf()) {
if (o instanceof TextBody){
/*
* A text body. Display its contents.
*/
TextBody body = (TextBody) o;
StringBuilder sb = new StringBuilder();
try {
Reader r = body.getReader();
int c;
while ((c = r.read()) != -1) {
sb.append((char) c);
}
} catch (IOException ex) {
ex.printStackTrace();
}
textView.setText(sb.toString());
} else if (o instanceof BinaryBody){
/*
* A binary body. Display its MIME type and length in bytes.
*/
BinaryBody body = (BinaryBody) o;
int size = 0;
try {
InputStream is = body.getInputStream();
while ((is.read()) != -1) {
size++;
}
} catch (IOException ex) {
ex.printStackTrace();
}
textView.setText("Binary body\n"
+ "MIME type: "
+ body.getParent().getMimeType() + "\n"
+ "Size of decoded data: " + size + " bytes");
} else if (o instanceof ContentTypeField) {
/*
* Content-Type field.
*/
ContentTypeField field = (ContentTypeField) o;
StringBuilder sb = new StringBuilder();
sb.append("MIME type: ").append(field.getMimeType()).append("\n");
for (Map.Entry<String, String> entry : field.getParameters().entrySet()) {
sb.append(entry.getKey()).append(" = ").append(entry.getValue()).append("\n");
}
textView.setText(sb.toString());
} else if (o instanceof AddressListField) {
/*
* An address field (From, To, Cc, etc)
*/
AddressListField field = (AddressListField) o;
MailboxList list = field.getAddressList().flatten();
StringBuilder sb = new StringBuilder();
for (Mailbox mailbox : list) {
sb.append(AddressFormatter.DEFAULT.format(mailbox, false)).append("\n");
}
textView.setText(sb.toString());
} else if (o instanceof DateTimeField) {
Date date = ((DateTimeField) o).getDate();
textView.setText(date.toString());
} else if (o instanceof UnstructuredField){
textView.setText(((UnstructuredField) o).getValue());
} else if (o instanceof Field){
textView.setText(((Field) o).getBody());
} else {
/*
* The Object should be a Header or a String containing a
* Preamble or Epilogue.
*/
textView.setText(o.toString());
}
}
}
/**
* Creates and displays the gui.
*
* @param message the Message to display in the tree.
*/
private static void createAndShowGUI(Message message) {
/*
* Create and set up the window.
*/
JFrame frame = new JFrame("MessageTree");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/*
* Create and set up the content pane.
*/
MessageTree newContentPane = new MessageTree(message);
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
/*
* Display the window.
*/
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
try {
final MessageBuilder builder = new DefaultMessageBuilder();
final Message message = builder.parseMessage(new FileInputStream(args[0]));
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI(message);
}
});
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Wrong number of arguments.");
System.err.println("Usage: org.mime4j.samples.tree.MessageTree"
+ " path/to/message");
} catch (FileNotFoundException e) {
System.err.println("The file '" + args[0] + "' could not be found.");
} catch (IOException e) {
System.err.println("The file '" + args[0] + "' could not be read.");
} catch (MimeException e) {
System.err.println("The file '" + args[0] + "' is invalid.");
}
}
}