Coverage Report - wjhk.jupload2.gui.JUploadTextArea
 
Classes in this File Line Coverage Branch Coverage Complexity
JUploadTextArea
68 %
32/47
100 %
2/2
1,583
JUploadTextArea$LogMessageThread
37 %
12/32
37 %
3/8
1,583
 
 1  
 //
 2  
 // $Id: JUploadTextArea.java 95 2007-05-02 03:27:05Z
 3  
 // /C=DE/ST=Baden-Wuerttemberg/O=ISDN4Linux/OU=Fritz
 4  
 // Elfert/CN=svn-felfert@isdn4linux.de/emailAddress=fritz@fritz-elfert.de $
 5  
 //
 6  
 // jupload - A file upload applet.
 7  
 // Copyright 2007 The JUpload Team
 8  
 //
 9  
 // Created: ?
 10  
 // Creator: William JinHua Kwong
 11  
 // Last modified: $Date: 2011-01-19 15:52:15 +0100 (mer., 19 janv. 2011) $
 12  
 //
 13  
 // This program is free software; you can redistribute it and/or modify it under
 14  
 // the terms of the GNU General Public License as published by the Free Software
 15  
 // Foundation; either version 2 of the License, or (at your option) any later
 16  
 // version. This program is distributed in the hope that it will be useful, but
 17  
 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 18  
 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 19  
 // details. You should have received a copy of the GNU General Public License
 20  
 // along with this program; if not, write to the Free Software Foundation, Inc.,
 21  
 // 675 Mass Ave, Cambridge, MA 02139, USA.
 22  
 
 23  
 package wjhk.jupload2.gui;
 24  
 
 25  
 import java.awt.Color;
 26  
 import java.text.SimpleDateFormat;
 27  
 import java.util.Date;
 28  
 import java.util.concurrent.BlockingQueue;
 29  
 import java.util.concurrent.LinkedBlockingQueue;
 30  
 
 31  
 import javax.swing.JTextArea;
 32  
 
 33  
 import wjhk.jupload2.policies.UploadPolicy;
 34  
 
 35  
 /**
 36  
  * This class represents the text area for debug output.
 37  
  */
 38  
 @SuppressWarnings("serial")
 39  54
 public class JUploadTextArea extends JTextArea {
 40  
 
 41  
     /**
 42  
      * Maximum number of characters in the logWindow.
 43  
      */
 44  
     public final static int MAX_LOG_WINDOW_LENGTH = 800000;
 45  
 
 46  
     /**
 47  
      * The size we truncate the output to, when the maximum size of debug output
 48  
      * is reach. We remove 20%.
 49  
      */
 50  
     public final static int SIZE_TO_TRUNCATE_TO = (int) (MAX_LOG_WINDOW_LENGTH * 0.8);
 51  
 
 52  
     /**
 53  
      * The current upload policy
 54  
      */
 55  
     UploadPolicy uploadPolicy;
 56  
 
 57  
     /**
 58  
      * Indicates whether the logging in the LogMessageThread is active or not.
 59  
      * It's marked as active before starting this thread. It's marked as
 60  
      * non-active, when this thread is interrupted, in {@link #unload()}
 61  
      */
 62  288
     boolean loggingActive = false;
 63  
 
 64  
     /**
 65  
      * The ConcurrentLinkedQueue that'll contain the messages.
 66  
      */
 67  
     private BlockingQueue<String> messages;
 68  
 
 69  
     /**
 70  
      * This value is logged in the debug file, and in the debug output, for each
 71  
      * line. This allows to sort the outputed line correctly.
 72  
      * 
 73  
      * @see #displayMsg(String, String)
 74  
      */
 75  288
     private int nextMessageId = 1;
 76  
 
 77  
     /**
 78  
      * A thread, that will be called in the EventDispatcherThread, to have a
 79  
      * tread-safe update of the GUI. This thread is responsible to display one
 80  
      * String.
 81  
      */
 82  
     static class LogMessageThread extends Thread {
 83  
 
 84  
         /**
 85  
          * The text area that'll contain the messages.
 86  
          */
 87  
         private JUploadTextArea textArea;
 88  
 
 89  
         /**
 90  
          * @param textArea
 91  
          */
 92  288
         LogMessageThread(JUploadTextArea textArea) {
 93  288
             this.textArea = textArea;
 94  288
             setDaemon(true);
 95  288
         }
 96  
 
 97  
         /** The run method of the Runnable Interface */
 98  
         @Override
 99  
         public void run() {
 100  33
             String nextMessage = null;
 101  
 
 102  33
             if (this.textArea.uploadPolicy.getDebugLevel() >= 30) {
 103  7
                 int nextMessageIdBackup = this.textArea.nextMessageId;
 104  7
                 this.textArea.nextMessageId = 0;
 105  7
                 this.textArea.setText(this.textArea.formatMessageOutput(
 106  
                         "[DEBUG]", "Logging system is initialized") + "\n");
 107  7
                 this.textArea.nextMessageId = nextMessageIdBackup;
 108  
             }
 109  
 
 110  33
             while (this.textArea.loggingActive) {
 111  
                 try {
 112  33
                     nextMessage = this.textArea.messages.take() + "\n";
 113  
 
 114  
                     // Ah, a new message has been delivered...
 115  
 
 116  0
                     synchronized (this.textArea) {
 117  0
                         String content = this.textArea.getText();
 118  0
                         int contentLength = content.length();
 119  
                         // If the current content is too long, we truncate it.
 120  0
                         if (contentLength > JUploadTextArea.MAX_LOG_WINDOW_LENGTH) {
 121  0
                             content += nextMessage;
 122  0
                             String newContent = content.substring(content
 123  0
                                     .length()
 124  0
                                     - SIZE_TO_TRUNCATE_TO, content.length());
 125  0
                             this.textArea.setText(newContent);
 126  0
                             contentLength = SIZE_TO_TRUNCATE_TO;
 127  0
                         } else {
 128  
                             // The result is not too long
 129  0
                             this.textArea.append(nextMessage);
 130  0
                             contentLength += nextMessage.length();
 131  
                         }
 132  0
                         this.textArea.setCaretPosition(contentLength - 1);
 133  0
                     } // synchronized
 134  0
                 } catch (InterruptedException e) {
 135  
                     // If we're not running any more, then this 'stop' is
 136  
                     // not a
 137  
                     // problem any more. We're then just notified we must
 138  
                     // stop
 139  
                     // the thread.
 140  0
                     if (this.textArea.loggingActive) {
 141  
                         // This should not happen, and we can not put in the
 142  
                         // standard JUpload output, as this thread is
 143  
                         // responsible for it.
 144  0
                         e.printStackTrace();
 145  
                     }
 146  0
                 }// try
 147  
             }// while
 148  0
         }
 149  
     }
 150  
 
 151  
     /**
 152  
      * The thread, that will put messages in the debug log.
 153  
      */
 154  288
     LogMessageThread logMessageThread = null;
 155  
 
 156  
     /**
 157  
      * Constructs a new empty TextArea with the specified number of rows and
 158  
      * columns.
 159  
      * 
 160  
      * @param rows The desired number of text rows (lines).
 161  
      * @param columns The desired number of columns.
 162  
      * @param uploadPolicy The current uploadPolicy
 163  
      */
 164  
     public JUploadTextArea(int rows, int columns, UploadPolicy uploadPolicy) {
 165  288
         super(rows, columns);
 166  288
         this.uploadPolicy = uploadPolicy;
 167  288
         this.messages = new LinkedBlockingQueue<String>();
 168  288
         setBackground(new Color(255, 255, 203));
 169  288
         setEditable(false);
 170  288
         setLineWrap(true);
 171  288
         setWrapStyleWord(true);
 172  
 
 173  
         // The queue, where messages to display will be posted.
 174  288
         this.logMessageThread = new LogMessageThread(this);
 175  576
         this.logMessageThread.setName(this.logMessageThread.getClass()
 176  288
                 .getName());
 177  
         // NO START HERE: the logMessageThread needs to know the upload policy,
 178  
         // to run properly. The thread is started in the setUploadPolicy method.
 179  
 
 180  
         // The unload callback will be registered, once the uploadPolicy has
 181  
         // been built, by DefaultJUploadContext.init(JUploadApplet)
 182  288
     }
 183  
 
 184  
     /**
 185  
      * Add a string to the queue of string to be added to the logWindow. This is
 186  
      * necessary, to manage the non-thread-safe Swing environment.
 187  
      * 
 188  
      * @param tag The tag (eg: INFO, DEBUG...)
 189  
      * @param msg The message to add, at the end of the JUploadTextArea.
 190  
      * @return The formatted text that was added to the log window.
 191  
      */
 192  
     public final String displayMsg(String tag, String msg) {
 193  649
         String fullMessage = formatMessageOutput(tag, msg);
 194  
 
 195  
         try {
 196  
             // messages is a BlockingQueue. So the next line may 'block' the
 197  
             // applet main thread. But, we're optimistic: this should not happen
 198  
             // as we instanciate an unbound LinkedBlockingQueue. We'll be
 199  
             // blocked at Integer.MAX_VALUE, that is ... much after an
 200  
             // OutOfMemory is thrown !
 201  649
             this.messages.put(fullMessage);
 202  0
         } catch (InterruptedException e) {
 203  0
             System.out.println("WARNING - [" + this.getClass().getName()
 204  0
                     + "] Message lost due to " + e.getClass().getName() + " ("
 205  
                     + fullMessage + ")");
 206  649
         }
 207  649
         return fullMessage;
 208  
     }
 209  
 
 210  
     /**
 211  
      * This call must be synchronized, so that there is no interaction with the
 212  
      * LogMessageThread thread.
 213  
      * 
 214  
      * @see JTextArea#append(String)
 215  
      */
 216  
     synchronized public void append(String t) {
 217  0
         super.append(t);
 218  0
     }
 219  
 
 220  
     /** @see JUploadPanel#copyLogWindow() */
 221  
     public synchronized void copyLogWindow() {
 222  0
         selectAll();
 223  0
         copy();
 224  0
     }
 225  
 
 226  
     /**
 227  
      * This call must be synchronized, so that there is no interaction with the
 228  
      * LogMessageThread thread.
 229  
      * 
 230  
      * @see JTextArea#insert(String, int)
 231  
      */
 232  
     synchronized public void insert(String str, int pos) {
 233  0
         super.insert(str, pos);
 234  0
     }
 235  
 
 236  
     /**
 237  
      * This call must be synchronized, so that there is no interaction with the
 238  
      * LogMessageThread thread.
 239  
      * 
 240  
      * @see JTextArea#replaceRange(String, int, int)
 241  
      */
 242  
     synchronized public void replaceRange(String str, int start, int end) {
 243  0
         super.replaceRange(str, start, end);
 244  0
     }
 245  
 
 246  
     /**
 247  
      * This call must be synchronized, so that there is no interaction with the
 248  
      * LogMessageThread thread.
 249  
      * 
 250  
      * @see JTextArea#setText(String)
 251  
      */
 252  
     synchronized public void setText(String t) {
 253  7
         super.setText(t);
 254  7
     }
 255  
 
 256  
     /**
 257  
      * @param uploadPolicy the uploadPolicy to set
 258  
      */
 259  
     public void setUploadPolicy(UploadPolicy uploadPolicy) {
 260  33
         this.uploadPolicy = uploadPolicy;
 261  33
         this.uploadPolicy.getContext().registerUnload(this, "unload");
 262  
         // We can now start the log thread.
 263  33
         this.loggingActive = true;
 264  33
         this.logMessageThread.start();
 265  33
     }
 266  
 
 267  
     /**
 268  
      * Free any used ressources. Actually close the LogMessageThread thread.
 269  
      */
 270  
     public synchronized void unload() {
 271  0
         this.loggingActive = false;
 272  0
         this.logMessageThread.interrupt();
 273  0
     }
 274  
 
 275  
     /**
 276  
      * Format the message, with the given tag. This method also add the time and
 277  
      * the Thread name.<BR>
 278  
      * e.g.:<BR>
 279  
      * nextMessageId[tab]14:04:30.718[tab]FileUploadManagerThread[tab][DEBUG][tab]
 280  
      * Found one reader for jpg extension
 281  
      * 
 282  
      * @param tag The tag ([WARN], [ERROR]...)
 283  
      * @param msg The message to format.
 284  
      * @return The formatted message, without trailing EOL character.
 285  
      */
 286  
     String formatMessageOutput(String tag, String msg) {
 287  656
         final String stamp = String.format("%1$05d", this.nextMessageId++) + " \t"
 288  656
                 + new SimpleDateFormat("HH:mm:ss.SSS ").format(new Date())
 289  656
                 + "\t" + Thread.currentThread().getName() + "\t" + tag + " \t";
 290  657
         while (msg.endsWith("\n")) {
 291  1
             msg = msg.substring(0, msg.length() - 1);
 292  
         }
 293  656
         return (stamp + msg.replaceAll("\n", "\n" + stamp));
 294  
     }
 295  
 
 296  
 }