Wednesday 3 October 2012

Java Swing PDF Viewer

I'll use pdf-renderer to create an pdf viewer in java swing application.
  • Dependencies
  • 
        org.swinglabs
        pdf-renderer
        1.0.5
    
    
        com.google.guava
        guava
        13.0.1
    
    
  • PDF Viewer
  • import com.google.common.base.CharMatcher;
    import com.sun.pdfview.PDFFile;
    import com.sun.pdfview.PDFPage;
    import com.sun.pdfview.PagePanel;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.File;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    import static com.google.common.base.Strings.isNullOrEmpty;
    
    public class PdfViewer extends JPanel {
        private static enum Navigation {GO_FIRST_PAGE, FORWARD, BACKWARD, GO_LAST_PAGE, GO_N_PAGE}
    
        private static final CharMatcher POSITIVE_DIGITAL = CharMatcher.anyOf("0123456789");
        private static final String GO_PAGE_TEMPLATE = "%s of %s";
        private static final int FIRST_PAGE = 1;
        private int currentPage = FIRST_PAGE;
        private JButton btnFirstPage;
        private JButton btnPreviousPage;
        private JTextField txtGoPage;
        private JButton btnNextPage;
        private JButton btnLastPage;
        private PagePanel pagePanel;
        private PDFFile pdfFile;
    
        public PdfViewer() {
            initial();
        }
    
        private void initial() {
            setLayout(new BorderLayout(0, 0));
            JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
            add(topPanel, BorderLayout.NORTH);
            btnFirstPage = createButton("|<<");
            topPanel.add(btnFirstPage);
            btnPreviousPage = createButton("<<");
            topPanel.add(btnPreviousPage);
            txtGoPage = new JTextField(10);
            txtGoPage.setHorizontalAlignment(JTextField.CENTER);
            topPanel.add(txtGoPage);
            btnNextPage = createButton(">>");
            topPanel.add(btnNextPage);
            btnLastPage = createButton(">>|");
            topPanel.add(btnLastPage);
            JScrollPane scrollPane = new JScrollPane();
            add(scrollPane, BorderLayout.CENTER);
            JPanel viewPanel = new JPanel(new BorderLayout(0, 0));
            scrollPane.setViewportView(viewPanel);
    
            pagePanel = new PagePanel();
            Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
            pagePanel.setPreferredSize(screenSize);
            viewPanel.add(pagePanel, BorderLayout.CENTER);
    
            disableAllNavigationButton();
    
            btnFirstPage.addActionListener(new PageNavigationListener(Navigation.GO_FIRST_PAGE));
            btnPreviousPage.addActionListener(new PageNavigationListener(Navigation.BACKWARD));
            btnNextPage.addActionListener(new PageNavigationListener(Navigation.FORWARD));
            btnLastPage.addActionListener(new PageNavigationListener(Navigation.GO_LAST_PAGE));
            txtGoPage.addActionListener(new PageNavigationListener(Navigation.GO_N_PAGE));
        }
    
        private JButton createButton(String text) {
            JButton button = new JButton(text);
            button.setPreferredSize(new Dimension(55, 20));
    
            return button;
        }
    
        private void disableAllNavigationButton() {
            btnFirstPage.setEnabled(false);
            btnPreviousPage.setEnabled(false);
            btnNextPage.setEnabled(false);
            btnLastPage.setEnabled(false);
        }
    
        private boolean isMoreThanOnePage(PDFFile pdfFile) {
            return pdfFile.getNumPages() > 1;
        }
    
        private class PageNavigationListener implements ActionListener {
            private final Navigation navigation;
    
            private PageNavigationListener(Navigation navigation) {
                this.navigation = navigation;
            }
    
            public void actionPerformed(ActionEvent e) {
                if (pdfFile == null) {
                    return;
                }
    
                int numPages = pdfFile.getNumPages();
                if (numPages <= 1) {
                    disableAllNavigationButton();
                } else {
                    if (navigation == Navigation.FORWARD && hasNextPage(numPages)) {
                        goPage(currentPage, numPages);
                    }
    
                    if (navigation == Navigation.GO_LAST_PAGE) {
                        goPage(numPages, numPages);
                    }
    
                    if (navigation == Navigation.BACKWARD && hasPreviousPage()) {
                        goPage(currentPage, numPages);
                    }
    
                    if (navigation == Navigation.GO_FIRST_PAGE) {
                        goPage(FIRST_PAGE, numPages);
                    }
    
                    if (navigation == Navigation.GO_N_PAGE) {
                        String text = txtGoPage.getText();
                        boolean isValid = false;
                        if (!isNullOrEmpty(text)) {
                            boolean isNumber = POSITIVE_DIGITAL.matchesAllOf(text);
                            if (isNumber) {
                                int pageNumber = Integer.valueOf(text);
                                if (pageNumber >= 1 && pageNumber <= numPages) {
                                    goPage(Integer.valueOf(text), numPages);
                                    isValid = true;
                                }
                            }
                        }
    
                        if (!isValid) {
                            JOptionPane.showMessageDialog(PdfViewer.this, format("Invalid page number '%s' in this document", text));
                            txtGoPage.setText(format(GO_PAGE_TEMPLATE, currentPage, numPages));
                        }
                    }
                }
            }
    
            private void goPage(int pageNumber, int numPages) {
                currentPage = pageNumber;
                PDFPage page = pdfFile.getPage(currentPage);
                pagePanel.showPage(page);
                boolean notFirstPage = isNotFirstPage();
                btnFirstPage.setEnabled(notFirstPage);
                btnPreviousPage.setEnabled(notFirstPage);
                txtGoPage.setText(format(GO_PAGE_TEMPLATE, currentPage, numPages));
                boolean notLastPage = isNotLastPage(numPages);
                btnNextPage.setEnabled(notLastPage);
                btnLastPage.setEnabled(notLastPage);
            }
    
            private boolean hasNextPage(int numPages) {
                return (++currentPage) <= numPages;
            }
    
            private boolean hasPreviousPage() {
                return (--currentPage) >= FIRST_PAGE;
            }
    
            private boolean isNotLastPage(int numPages) {
                return currentPage != numPages;
            }
    
            private boolean isNotFirstPage() {
                return currentPage != FIRST_PAGE;
            }
        }
    
        public PagePanel getPagePanel() {
            return pagePanel;
        }
    
        public void setPDFFile(PDFFile pdfFile) {
            this.pdfFile = pdfFile;
            currentPage = FIRST_PAGE;
            disableAllNavigationButton();
            txtGoPage.setText(format(GO_PAGE_TEMPLATE, FIRST_PAGE, pdfFile.getNumPages()));
            boolean moreThanOnePage = isMoreThanOnePage(pdfFile);
            btnNextPage.setEnabled(moreThanOnePage);
            btnLastPage.setEnabled(moreThanOnePage);
        }
    }
    
    Line:58-59 automatically match the current screen resolution. The default is 800*600.

    The utility method "format" is here: format

  • Tester
  • public static void main(String[] args) {
            try {
                long heapSize = Runtime.getRuntime().totalMemory();
                System.out.println("Heap Size = " + heapSize);
    
                JFrame frame = new JFrame("PDF Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
                //load a pdf from a byte buffer
                File file = new File("/Users/Sean/Documents/test-pdf.pdf");
                RandomAccessFile raf = new RandomAccessFile(file, "r");
                FileChannel channel = raf.getChannel();
                ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
                final PDFFile pdffile = new PDFFile(buf);
                PdfViewer pdfViewer = new PdfViewer();
                pdfViewer.setPDFFile(pdffile);
                frame.add(pdfViewer);
                frame.pack();
                frame.setVisible(true);
    
                PDFPage page = pdffile.getPage(0);
                pdfViewer.getPagePanel().showPage(page);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
  • screen shots


Wednesday 19 September 2012

How to create or initialize Generic Type Array


  • solution 1





  • Limitation: It's not work if input array is null.

    public static <T> T[] subarray(T[] array, int startIndexInclusive, int endIndexExclusive) {
            if (array == null) {
                return null;
            }
    
            if (startIndexInclusive < 0) {
                startIndexInclusive = 0;
            }
            if (endIndexExclusive > array.length) {
                endIndexExclusive = array.length;
            }
    
            Class<?> type = array.getClass().getComponentType();
            int newSize = endIndexExclusive - startIndexInclusive;
            if (newSize < 0) {
                final T[] emptyArray = (T[]) Array.newInstance(type, 0);
                return emptyArray;
            }
    
            T[] subarray = (T[]) Array.newInstance(type, newSize);
            System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
            return subarray;
        }
    
  • solution 2
  • It's work if input array is null. But it's more verbose for invoking.
    public static <T> T[] subarray(T[] array, int startIndexInclusive, int endIndexExclusive, Class<T>> clazz) {
         T[] emptyArray = (T[]) Array.newInstance(clazz, 0);
    
            if (array == null) {
                return emptyArray;
            }
    
            if (startIndexInclusive < 0) {
                startIndexInclusive = 0;
            }
            if (endIndexExclusive > array.length) {
                endIndexExclusive = array.length;
            }
    
            if (newSize < 0) {
                return emptyArray;
            }
    
            T[] subarray = (T[]) Array.newInstance(clazz, newSize);
            System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
            return subarray;
        }
    

    Tuesday 18 September 2012

    Java Swing JTextField: Number only and give length



  • Solution 1

  • Simple but It can't work for "CTRL + V" scenario
    private class NumberOnlyAdapter extends KeyAdapter {
    
            private final int maxLength;
    
            private NumberOnlyAdapter(int maxLength) {
                this.maxLength = maxLength;
            }
    
            @Override
            public void keyTyped(KeyEvent e) {
                char typed = e.getKeyChar();
                CharMatcher notDigit = noneOf("0123456789").and(isNot((char) VK_BACK_SPACE)).and(isNot((char) VK_DELETE));
                JTextField textField = (JTextField) e.getComponent();
                if (notDigit.apply(typed) || textField.getText().length() >= maxLength) {
                    e.consume();
                }
            }
    
        }
    
    ...
    int maxLength = 8;
    JTextField textField = new JTextField();
    textField.addKeyListener(new NumberOnlyAdapter(maxLength));
    
  • Solution 2

  • It's work for all conditions
    import static org.apache.commons.lang3.StringUtils.*;
    
    import javax.swing.text.AttributeSet;
    import javax.swing.text.BadLocationException;
    import javax.swing.text.DocumentFilter;
    
    public class NumericOnlyAndMaxLengthFilter extends DocumentFilter {
        private int maxLength = 0;
    
    
        public NumericOnlyAndMaxLengthFilter() {
           // allow any length of numeric
        }
    
        public NumericOnlyAndMaxLengthFilter(int maxLength) {
            this.maxLength = maxLength;
        }
    
        @Override
        public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
            if (isNumeric(string)) {
                if (isExceedMaxLength(fb, string)) {
                    return;
                }
                super.insertString(fb, offset, string, attr);
            }
        }
    
        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
            if (isNumeric(text)) {
                if (isExceedMaxLength(fb, text)) {
                    return;
                }
                super.insertString(fb, offset, text, attrs);
            }
        }
    
        private boolean isExceedMaxLength(FilterBypass fb, String text) {
            return maxLength > 0 && (fb.getDocument().getLength() + text.length()) > maxLength;
        }
    }
    
    ...
    int maxLength = 8;
    JTextField textField = new JTextField();
    ((AbstractDocument)textField .getDocument()).setDocumentFilter(new NumericOnlyAndMaxLengthFilter(maxLength));
    

    Thursday 13 September 2012

    Maven generate HTML Junit report

    • add to pom.xml
    • 
          org.apache.maven.plugins
          maven-surefire-plugin
          
              true
          
      
      
      
          org.jvnet.maven-antrun-extended-plugin
          maven-antrun-extended-plugin
          
              
                  test-reports
                  test
                  
                      
                          
                              
                                  
                              
                              
                          
                      
                  
                  
                      run
                  
              
          
          
              
                  org.apache.ant
                  ant-junit
                  1.8.4
              
              
                  org.apache.ant
                  ant-trax
                  1.8.0
              
          
      
      
    • Don't bind the AntRun plugin to the test phase, move the configuration outside the execution and call mvn antrun:run on the command line to generate the reports when wanted.
    • Or use the testFailureIgnore option of the test mojo and set it to true in the surefire plugin
    • Use maven command arguments
    • $mvn test -Dmaven.test.failure.ignore=true
      

    Wednesday 5 September 2012

    Java - better performance String formatter

    /**
         * Substitutes each {@code %s} in {@code template} with an argument. These
         * are matched by position - the first {@code %s} gets {@code args[0]}, etc.
         * If there are more arguments than placeholders, the unmatched arguments will
         * be appended to the end of the formatted message in square braces.
         *
         * @param template a non-null string containing 0 or more {@code %s}
         *     placeholders.
         * @param args the arguments to be substituted into the message
         *     template. Arguments are converted to strings using
         *     {@link String#valueOf(Object)}. Arguments can be null.
         */
        public static String format(String template, Object... args) {
            template = String.valueOf(template); // null -> "null"
            // start substituting the arguments into the '%s' placeholders
            StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
            int templateStart = 0;
            int i = 0;
            while (i < args.length) {
                int placeholderStart = template.indexOf("%s", templateStart);
                if (placeholderStart == -1) {
                    break;
                }
                builder.append(template.substring(templateStart, placeholderStart));
                builder.append(args[i++]);
                templateStart = placeholderStart + 2;
            }
            builder.append(template.substring(templateStart));
    
            // if we run out of placeholders, append the extra args in square braces
            if (i < args.length) {
                builder.append(" [");
                builder.append(args[i++]);
                while (i < args.length) {
                    builder.append(", ");
                    builder.append(args[i++]);
                }
                builder.append(']');
            }
    
            return builder.toString();
        }
    
       public static void main(String[] args) {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.start();
            String result = Formatter.format("My name is: %s. I was start from: %s. ", "Sean", "25/05/2012", "another value here");
            stopwatch.stop();
            System.out.println(stopwatch.elapsedTime(TimeUnit.NANOSECONDS));
            System.out.println(result);
            stopwatch.reset();
            stopwatch.start();
            result = String.format("My name is: %s. I was start from: %s.", "Sean", "25/05/2012", "another value here");
            stopwatch.stop();
            System.out.println(stopwatch.elapsedTime(TimeUnit.NANOSECONDS));
            System.out.println(result);
        }
    

    Tuesday 14 August 2012

    Read line (or get line count) from JTextArea with wrap enabled

    public class Demo {
         JTextArea textArea = new JTextArea(text, 5, 50);
         textArea.setFont(new Font("Monospaced", Font.PLAIN, 12));
         textArea.setEditable(false);
         textArea.setLineWrap(true);
         textArea.setWrapStyleWord(true);
    
         private static String[] readLinesFromTextArea(JTextArea textArea, int limitRows) {
               String content = textArea.getText();
               String[] lines = new String[limitRows];
               Arrays.fill(lines, "");
               try {
                  int count = 0;
                  int offs = 0;
                  while (offs < content.length() && count < limitRows ) {
                     int end = Utilities.getRowEnd(textArea, offs);
                     String line = StringUtils.substring(content, offs, end);
                     lines[count++] = line;
                     offs = end + 1;
                  }
               } catch (BadLocationException e) {
                 log.error("Read line from 'Other' text area failed. Cause:\n", Throwables.getStackTraceAsString(e));
            }
    
            return lines;
        }
    }
    

    Monday 6 August 2012

    Use Apache PDFBox convert PDF to image (support BMP,bmp,jpeg,wbmp,gif,png,JPG,jpg,JPEG,WBMP)

    • dependency
    • 
         org.apache.pdfbox
         pdfbox
         1.7.0
      
      
         org.bouncycastle
         bcprov-jdk15
         1.46
      
      
         org.bouncycastle
         bcmail-jdk15
         1.46
      
      
         org.apache.pdfbox
         fontbox
         1.7.0
                         
      
    • Code
    • import au.gov.nsw.police.nodi.common.CustomProperties;
      import org.apache.pdfbox.exceptions.CryptographyException;
      import org.apache.pdfbox.exceptions.InvalidPasswordException;
      import org.apache.pdfbox.pdmodel.PDDocument;
      import org.apache.pdfbox.pdmodel.PDPage;
      import org.apache.pdfbox.util.PDFImageWriter;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.w3c.dom.Node;
      import org.w3c.dom.NodeList;
      
      import javax.imageio.*;
      import javax.imageio.metadata.IIOInvalidTreeException;
      import javax.imageio.metadata.IIOMetadata;
      import javax.imageio.metadata.IIOMetadataNode;
      import java.awt.*;
      import java.awt.image.BufferedImage;
      import java.awt.image.RenderedImage;
      import java.io.ByteArrayInputStream;
      import java.io.IOException;
      import java.util.Iterator;
      import java.util.List;
      
      import static com.google.common.base.Throwables.getStackTraceAsString;
      
      public class PDFToImage {
          private static final Logger log = LoggerFactory.getLogger(PDFToImage.class);
          private static final String STANDARD_METADATA_FORMAT = "javax_imageio_1.0";
          private static final String PDF_ENCRYPTED_PASSWORD = CustomProperties.getInstance().getProperty("pdf.from.esb.encrypted.password");
          private static final String IMAGE_FORMAT = "png";
          private static final int DEFAULT_IMAGE_RESOLUTION = 256;
      
          public static RenderedImage convertPdfOfGivenPageNumberToRenderImage(PDDocument document, int pageNumber) throws IOException {
              try {
                  decryptDocument(PDF_ENCRYPTED_PASSWORD, document);
      
                  int imageType = BufferedImage.TYPE_INT_RGB;
                  int resolution = DEFAULT_IMAGE_RESOLUTION;
                  try {
                      int screenResolution = Toolkit.getDefaultToolkit().getScreenResolution();
                      if (screenResolution > resolution) {
                          resolution = screenResolution;
                      }
                  } catch (HeadlessException e) {
                      log.debug("As it can't get the screen resolution. Use default resolution: {}", resolution);
                  }
      
                  List pages = document.getDocumentCatalog().getAllPages();
                  PDPage page = (PDPage) pages.get(pageNumber);
                  BufferedImage image = page.convertToImage(imageType, resolution);
                  return covertBufferedImageToRenderImage(image, IMAGE_FORMAT, resolution);
              } finally {
                  if (document != null) {
                      document.close();
                  }
              }
          }
      
          private static void decryptDocument(String password, PDDocument document) throws IOException {
              if (document.isEncrypted()) {
                  try {
                      document.decrypt(password);
                  } catch (InvalidPasswordException e) {
                      log.error("Error: The document is encrypted. Please provide correct PDF_ENCRYPTED_PASSWORD. Cause:\n{}", getStackTraceAsString(e));
                  } catch (CryptographyException e) {
                      log.error(getStackTraceAsString(e));
                  }
              }
          }
      
          private static RenderedImage covertBufferedImageToRenderImage(BufferedImage image, String imageFormat, int resolution) throws IOException {
              ImageWriter imageWriter = null;
              Iterator imageWriterIterator = ImageIO.getImageWritersByFormatName(imageFormat);
              if (imageWriterIterator.hasNext()) {
                  try {
                      imageWriter = imageWriterIterator.next();
                      ImageWriteParam writerParams = imageWriter.getDefaultWriteParam();
                      if (writerParams.canWriteCompressed()) {
                          writerParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                          // reset the compression type if overwritten by setCompressionMode
                          if (writerParams.getCompressionType() == null) {
                              writerParams.setCompressionType(writerParams.getCompressionTypes()[0]);
                          }
                          writerParams.setCompressionQuality(1.0f);
                      }
                      IIOMetadata meta = createMetadata(image, imageWriter, writerParams, resolution);
                      IIOImage iioImage = new IIOImage(image, null, meta);
                      return iioImage.getRenderedImage();
                  } finally {
                      if (imageWriter != null) {
                          imageWriter.dispose();
                      }
                  }
              }
      
              return null;
          }
      
          private static PDDocument loadPdfDocumentFromBytes(byte[] imageOfPdf) throws IOException {
              ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(imageOfPdf);
              return PDDocument.load(byteArrayInputStream);
      
          }
      
          private static PDDocument loadPdfDocumentFromFile(String fileName) throws IOException {
              return PDDocument.load(fileName);
          }
      
          //----------------------Copy from (start): org.apache.pdfbox.util.ImageIOUtil-----------------------------------
          private static IIOMetadata createMetadata(RenderedImage image, ImageWriter imageWriter, ImageWriteParam writerParams, int resolution) {
              ImageTypeSpecifier type;
              if (writerParams.getDestinationType() != null) {
                  type = writerParams.getDestinationType();
              } else {
                  type = ImageTypeSpecifier.createFromRenderedImage(image);
              }
              IIOMetadata meta = imageWriter.getDefaultImageMetadata(type, writerParams);
              return (addResolution(meta, resolution) ? meta : null);
          }
      
          private static boolean addResolution(IIOMetadata meta, int resolution) {
              if (!meta.isReadOnly() && meta.isStandardMetadataFormatSupported()) {
                  IIOMetadataNode root = (IIOMetadataNode) meta.getAsTree(STANDARD_METADATA_FORMAT);
                  IIOMetadataNode dimension = getChildNode(root, "Dimension");
                  IIOMetadataNode horizontalPixelSize = getChildNode(dimension, "HorizontalPixelSize");
                  String pixelSize = Double.toString(resolution / 25.4);
                  horizontalPixelSize.setAttribute("value", pixelSize);
      
                  IIOMetadataNode verticalPixelSize = getChildNode(dimension, "VerticalPixelSize");
                  verticalPixelSize.setAttribute("value", pixelSize);
                  try {
                      meta.mergeTree(STANDARD_METADATA_FORMAT, root);
                  } catch (IIOInvalidTreeException e) {
                      throw new RuntimeException("Cannot update image metadata: " + e.getMessage());
                  }
                  return true;
              }
              return false;
          }
      
      
          private static IIOMetadataNode getChildNode(IIOMetadataNode parentNode, String childNodeName) {
              NodeList nodes = parentNode.getChildNodes();
              for (int i = 0; i < nodes.getLength(); i++) {
                  Node child = nodes.item(i);
                  if (childNodeName.equals(child.getNodeName())) {
                      return (IIOMetadataNode) child;
                  }
              }
      
              return createChildNodeIfNotExist(parentNode, childNodeName);
          }
      
      
          private static IIOMetadataNode createChildNodeIfNotExist(IIOMetadataNode parentNode, String childNodeName) {
              IIOMetadataNode childNode = new IIOMetadataNode(childNodeName);
              parentNode.appendChild(childNode);
              return childNode;
          }
          //----------------------Copy from (end): org.apache.pdfbox.util.ImageIOUtil-----------------------------------
      
          public static void main(String[] args) throws IOException {
              String pdfFile = "c:/temp/test_avo.pdf";
              String outputPrefix = "c:/temp/";
      
              PDDocument document = loadPdfDocumentFromFile(pdfFile);
              int numberOfPages = document.getNumberOfPages();
              for (int i = 0; i < numberOfPages; i++) {
                  int pageNumber = i + 1;
                  RenderedImage renderedImage = convertPdfOfGivenPageNumberToRenderImage(document, pageNumber);
                  // render image to ui or
              }
      
              // if you just want to covert pdf file to image file, it's much easier.
              PDFImageWriter imageWriter = new PDFImageWriter();
              boolean success = imageWriter.writeImage(document, IMAGE_FORMAT, password, startPage, endPage, outputPrefix, BufferedImage.TYPE_INT_RGB, resolution);
              if (!success) {
                  System.err.println("Error: no writer found for image format '" + IMAGE_FORMAT + "'");
                  System.exit(1);
              }
          }
      
    • You can use following code to detected which image format is support
    • public static String getImageFormats() {
              StringBuffer retval = new StringBuffer();
              String[] formats = ImageIO.getReaderFormatNames();
              for (int i = 0; i < formats.length; i++) {
                  retval.append(formats[i]);
                  if (i + 1 < formats.length) {
                      retval.append(",");
                  }
              }
              return retval.toString();
          }
      
    • Dependencies can be download here
    • Others
    • Tiff image need native libary. You can find more information on java.net

    Monday 30 July 2012

    Soap Web Service with attachment Over JMS

    • dependency
    • 
          com.sun.messaging.mq
          imqxm
          4.6-b01
      
      
          javaee
          javaee-api
          5
      
      
          xalan
          xalan
          2.7.0
      
      
          com.sun.messaging.mq
          jaxm-api
          4.6-b01
                  
      
    • JMS message sender (Embedded SoapMessage with Attachment)
    • import com.google.common.io.Files;
      import com.sun.messaging.xml.MessageTransformer;
      
      import javax.activation.DataHandler;
      import javax.activation.FileDataSource;
      import javax.jms.*;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.xml.soap.*;
      import java.io.File;
      import java.io.IOException;
      import java.nio.charset.Charset;
      import java.util.Hashtable;
      
      public class MockWebServiceOverJMSSender {
          private static final String CONNECTION_FACTORY_JNDI_NAME = "weblogic.jms.XAConnectionFactory";
          private static final String QUEUE_JNDI_NAME = "jms/TestQueueJNDI";
      
          public static void sendMessage() {
              try {
                  QueueConnection connection = null;
                  QueueSession session = null;
                  QueueSender queueSender = null;
                  try {
                      Hashtable<String,String> properties = new Hashtable();
                      properties.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
                      properties.put(Context.PROVIDER_URL, "t3://localhost:7001");
      
                      InitialContext context = new InitialContext(properties);
                      QueueConnectionFactory connectionFactory = (QueueConnectionFactory) context.lookup(CONNECTION_FACTORY_JNDI_NAME);
                      connection = connectionFactory.createQueueConnection();
                      session = connection.createQueueSession(false, 0);
                      Queue queue = (Queue) context.lookup(QUEUE_JNDI_NAME);
                      queueSender = session.createSender(queue);
      
                      MessageFactory messageFactory = MessageFactory.newInstance();
                      SOAPMessage soapMessage = messageFactory.createMessage();
                      soapMessage.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
                      SOAPPart soapPart = soapMessage.getSOAPPart();
                      SOAPEnvelope envelope = soapPart.getEnvelope();
                      SOAPBody soapBody = envelope.getBody();
      
                      soapBody.setTextContent(buildSoapBodyContent());
      
                      AttachmentPart attachment = buildSoapAttachment(soapMessage);
                      soapMessage.addAttachmentPart(attachment);
      
                      soapMessage.saveChanges();
                      Message message = MessageTransformer.SOAPMessageIntoJMSMessage(soapMessage, session);
                      queueSender.send(message);
                  } finally {
                      queueSender.close();
                      session.close();
                      connection.close();
                  }
              } catch (Exception e) {
                  e.printStackTrace();
                  System.exit(0);
              }
          }
      
          private static String buildSoapBodyContent() throws IOException {
              String responseFile = "c:/temp/PoliceAVOApplicationResponse-Non-provisional.xml";
              return Files.toString(new File(responseFile), Charset.forName("UTF-8"));
          }
      
          private static AttachmentPart buildSoapAttachment(SOAPMessage soapMessage) {
              DataHandler dh = new DataHandler(new FileDataSource("c:/temp/test_avo.pdf"));
              return soapMessage.createAttachmentPart(dh);
          }
      
          public static void main(String args[]) {
              sendMessage();
          }
      
    • JMS consumer(parse message body & save attachment to disk)
    • import au.gov.nsw.police.nodi.common.IOHelper;
      import com.google.common.io.Files;
      import com.sun.messaging.xml.MessageTransformer;
      import org.w3c.dom.Document;
      import org.xml.sax.SAXException;
      
      import javax.jms.*;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.xml.parsers.DocumentBuilder;
      import javax.xml.parsers.DocumentBuilderFactory;
      import javax.xml.parsers.ParserConfigurationException;
      import javax.xml.soap.*;
      import javax.xml.xpath.*;
      import java.io.ByteArrayInputStream;
      import java.io.File;
      import java.io.IOException;
      import java.io.InputStream;
      import java.util.Date;
      import java.util.Hashtable;
      import java.util.Iterator;
      
      public class MockJMSMessageConsumer {
          private static final String CONNECTION_FACTORY_JNDI_NAME = "weblogic.jms.XAConnectionFactory";
          private static final String QUEUE_JNDI_NAME = "jms/TestQueueJNDI";
      
          private static void consumeMessage() {
              try {
                  QueueConnection connection = null;
                  QueueSession session = null;
                  QueueReceiver queueReceiver = null;
                  try {
                      Hashtable<String, String> properties = new Hashtable();
                      properties.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
                      properties.put(Context.PROVIDER_URL, "t3://localhost:7001");
      
                      InitialContext context = new InitialContext(properties);
                      QueueConnectionFactory connectionFactory = (QueueConnectionFactory) context.lookup(CONNECTION_FACTORY_JNDI_NAME);
                      connection = connectionFactory.createQueueConnection();
                      session = connection.createQueueSession(false, 0);
                      Queue queue = (Queue) context.lookup(QUEUE_JNDI_NAME);
                      queueReceiver = session.createReceiver(queue);
                      connection.start();
      
                      while (true) {
                          Message message = queueReceiver.receive(1);
                          MessageFactory messageFactory = MessageFactory.newInstance();
      
                          if (message != null) {
                              SOAPMessage soapMessage = MessageTransformer.SOAPMessageFromJMSMessage(message, messageFactory);
                              onMessage(soapMessage);
                          }
                      }
                  } finally {
                      queueReceiver.close();
                      session.close();
                      connection.close();
                  }
              } catch (Exception e) {
                  e.printStackTrace(System.err);
                  System.exit(0);
              }
          }
      
          private static void onMessage(SOAPMessage soapMessage) {
              try {
                  System.out.println("Start to processing message from ESB...");
                  SOAPBody soapBody = soapMessage.getSOAPPart().getEnvelope().getBody();
      
                  Iterator iterator = soapMessage.getAttachments();
                  if (iterator.hasNext()) {
                      AttachmentPart attachmentPart = (AttachmentPart) iterator.next();
                      System.out.println("here");
                      parseMetadataFromSoapMessage(soapBody, attachmentPart);
                  }
                  System.out.println("Finish to processing message from ESB");
              } catch (Throwable e) {
                  e.printStackTrace();
              }
          }
      
      
          private static void parseMetadataFromSoapMessage(SOAPBody soapBody, AttachmentPart attachmentPart) throws IOException, SAXException, ParserConfigurationException, XPathExpressionException, SOAPException {
              String content = soapBody.getTextContent();
              Document doc = buildDocumentFromString(content);
      
              XPath xPath = createXPath();
              String courtReferenceNumber = getStringValueWithGiveXPath(xPath, doc, "/n1:PublishDocumentMessage/@ProceedingNumber");
              String courtName = getStringValueWithGiveXPath(xPath, doc, "/n1:PublishDocumentMessage/n1:Listing/Court/@Name");
              String eventNumber = getStringValueWithGiveXPath(xPath, doc, "/n1:PublishDocumentMessage/n1:QuestionsAndAnswers/n1:DataField[@Name='IDF POLAPPEVENTNO']/@Value");
              String cni = getStringValueWithGiveXPath(xPath, doc, "/n1:PublishDocumentMessage/n1:Participant[n1:ParticipantID[@ParticipantRole='DEFENDANT']]/n1:CrimeIndividual/common:IndividualDetails/@CNI");
              System.out.println("court reference number: " + courtReferenceNumber);
              System.out.println("court name: " + courtName);
              System.out.println("event number: " + eventNumber);
              System.out.println("cni: " + cni);
      
              saveAttachmentToDisk(attachmentPart);
          }
      
          private static Document buildDocumentFromString(String content) throws ParserConfigurationException, SAXException, IOException {
              DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
              docBuilderFactory.setNamespaceAware(true);
              DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
              InputStream inputStream = new ByteArrayInputStream(content.getBytes());
              return docBuilder.parse(inputStream);
          }
      
          private static XPath createXPath() {
              XPathFactory xPathfactory = XPathFactory.newInstance();
              XPath xpath = xPathfactory.newXPath();
              xpath.setNamespaceContext(new AVONamespaceContext());
      
              return xpath;
          }
      
          private static String getStringValueWithGiveXPath(XPath xpath, Document document, String expression) throws XPathExpressionException {
              XPathExpression xPathExpression = xpath.compile(expression);
              return (String) xPathExpression.evaluate(document, XPathConstants.STRING);
          }
      
          private static void saveAttachmentToDisk(AttachmentPart attachmentPart) throws IOException, SOAPException {
              byte[] pdfFile= IOHelper.readInputStream(attachmentPart.getDataHandler().getInputStream());
              Date now = new Date();
              Files.write(faxImages, new File("c:/temp/" + now.getTime() + ".pdf"));
          }
      
          public static void main(String args[]) {
              consumeMessage();
          }
      
    • help class
    • import javax.xml.XMLConstants;
      import javax.xml.namespace.NamespaceContext;
      import java.util.Iterator;
      
      public class AVONamespaceContext implements NamespaceContext {
          public String getNamespaceURI(String prefix) {
              if (prefix == null) throw new NullPointerException("Invalid Namespace Prefix");
              else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
                  return "http://www.w3.org/2001/XMLSchema-instance";
              } else if ("n1".equals(prefix)) {
                  return "http://cats.agd.nsw.gov.au/PublishDocumentMessage/v1_0";
              } else if ("common".equals(prefix)) {
                  return "http://cats.agd.nsw.gov.au/DocumentLodgementInterfaces/Common/v1_0";
              } else if ("cim".equals(prefix)) {
                  return "http://cim.justicesector.nsw.gov.au/Common/1";
              } else if ("as4590".equals(prefix)) {
                  return "http://cim.justicesector.nsw.gov.au/as459";
              } else {
                  return XMLConstants.NULL_NS_URI;
              }
          }
      
          public String getPrefix(String namespaceURI) {
              return null;
          }
      
          public Iterator getPrefixes(String namespaceURI) {
              return null;
          }
      }
      
    • Another Solution
    • You don't need to dependent the above dependencies. You just implement your own transformer. My sample as follow:
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      import javax.jms.BytesMessage;
      import javax.jms.JMSException;
      import javax.jms.Message;
      import javax.jms.Session;
      import javax.xml.messaging.JAXMException;
      import javax.xml.soap.*;
      import java.io.*;
      import java.util.Enumeration;
      import java.util.Hashtable;
      import java.util.Iterator;
      
      import static com.google.common.base.Throwables.getStackTraceAsString;
      
      /**
       * The Rcode>Transformer</code> class encapsulates the functionality
       * to transform SOAP and JMS messages.
       */
      public class MessageTransformer {
          private static final Logger log = LoggerFactory.getLogger(MessageTransformer.class);
          private MessageTransformer() {
          }
      
          /**
           * Transforms a <code>javax.xml.soap.SOAPMessage</code> message
           * into a <code>javax.jms.Message</code> message.
           *
           * @param soapMessage the SOAPMessage to be converted to the JMS Message.
           * @param session     The JMS Session to be used to construct the JMS Message.
           * @throws JAXMException If any error is encountered when transforming the message.
           */
          public static Message SOAPMessageIntoJMSMessage(SOAPMessage soapMessage, Session session) throws JAXMException {
              try {
                  /**
                   * Construct a bytes message object.
                   * This is to make sure the utility works across all vendors.
                   */
                  BytesMessage bytesMessage = session.createBytesMessage();
      
                  /**
                   * This is here to make sure that RI's bad SOAP implementation
                   * will get updated for internal buffers.
                   */
                  soapMessage.saveChanges();
      
                  writeMimeHeaders(soapMessage, bytesMessage);
                  writeSOAPBody(soapMessage, bytesMessage);
      
                  return bytesMessage;
              } catch (JAXMException JAXMe) {
                  throw JAXMe;
              } catch (Exception e) {
                  log.error(getStackTraceAsString(e));
                  throw new JAXMException(e);
              }
          }
      
          private static void writeMimeHeaders(SOAPMessage soapMessage, BytesMessage bytesMessage) throws Exception {
              MimeHeaders mimeHeaders = soapMessage.getMimeHeaders();
              Hashtable hashtable = convertMimeHeadersToHashtable(mimeHeaders);
      
              ByteArrayOutputStream mimeOut = writeHashtableToByteArrayOutputStream(hashtable);
      
              byte[] mimeHeadersBytes = mimeOut.toByteArray();
              int mimeHeadersLength = mimeHeadersBytes.length;
              bytesMessage.writeInt(mimeHeadersLength);
              bytesMessage.writeBytes(mimeHeadersBytes);
              mimeOut.close();
              log.debug("SOAP to JMS mime headers length: {}", mimeHeadersLength);
          }
      
          /**
           * Convert MimeHeaders to Hashtable.  The hashtable is then used to write
           * to JMS BytesMessage.
           */
          private static Hashtable convertMimeHeadersToHashtable(MimeHeaders mimeHeaders) {
              Hashtable hashtable = new Hashtable();
              Iterator it = mimeHeaders.getAllHeaders();
              while (it.hasNext()) {
                  MimeHeader mimeHeader = (MimeHeader) it.next();
                  hashtable.put(mimeHeader.getName(), mimeHeader.getValue());
              }
      
              return hashtable;
          }
      
          private static ByteArrayOutputStream writeHashtableToByteArrayOutputStream(Hashtable hashtable) throws IOException {
              ByteArrayOutputStream mimeOut = new ByteArrayOutputStream();
              ObjectOutputStream objectOutputStream = new ObjectOutputStream(mimeOut);
              objectOutputStream.writeObject(hashtable);
              objectOutputStream.flush();
              objectOutputStream.close();
              return mimeOut;
          }
      
          private static void writeSOAPBody(SOAPMessage soapMessage, BytesMessage bytesMessage) throws Exception {
              ByteArrayOutputStream bodyOutput = new ByteArrayOutputStream();
              soapMessage.writeTo(bodyOutput);
      
              byte[] bodyBytes = bodyOutput.toByteArray();
              int bodyLength = bodyBytes.length;
              bytesMessage.writeInt(bodyLength);
              bytesMessage.writeBytes(bodyBytes);
      
              bodyOutput.close();
              log.debug("SOAP to JMS body length: {}", bodyLength);
          }
      
      
          /**
           * Extracts a <code>javax.xml.soap.SOAPMessage</code> object from the
           * <code>javax.jms.Message</code> object into which it was transformed
           * using the <code>SOAPMessageIntoJMSMessage</code> method.
           * <p/>* The <code>MessageFactory</code> parameter is used to construct the
           * <code>javax.xml.soap.SOAPMessage</code> object.
           * <p/>* If <code>MessageFactory</code> is <code>null</code> then the
           * default SOAP MessageFactory will be used to construct the
           * SOAP message.
           *
           * @param message        The JMS message from which the SOAP message is to be extracted.
           * @param messageFactory The SOAP MessageFactory to be used to contruct the SOAP message.
           * @throws JAXMException If any error is encountered when extracting the message.
           */
          public static SOAPMessage extractSOAPMessageFromJMSMessage(Message message, MessageFactory messageFactory) throws JAXMException {
              BytesMessage bytesMessage = (BytesMessage) message;
              try {
                  MimeHeaders mimeHeaders = readMimeHeaders(bytesMessage);
                  ByteArrayInputStream bodyByteArrayInputStream = readSoapBodyToByteArrayInputStream(bytesMessage);
      
                  return constructSoapMessage(messageFactory, mimeHeaders, bodyByteArrayInputStream);
              } catch (Exception e) {
                  throw new JAXMException(e);
              }
          }
      
          private static MimeHeaders readMimeHeaders(BytesMessage bytesMessage) throws JMSException, IOException, ClassNotFoundException {
              int mimeHeadersLength = bytesMessage.readInt();
              byte[] mimeHeadersBytes = new byte[mimeHeadersLength];
              bytesMessage.readBytes(mimeHeadersBytes, mimeHeadersLength);
      
              ByteArrayInputStream mimeHeadersByteArrayInputStream = new ByteArrayInputStream(mimeHeadersBytes);
              ObjectInputStream objectInputStream = new ObjectInputStream(mimeHeadersByteArrayInputStream);
              Hashtable hashtable = (Hashtable) objectInputStream.readObject();
              return convertHashtableToMimeHeaders(hashtable);
          }
      
          private static MimeHeaders convertHashtableToMimeHeaders(Hashtable hashtable) {
              MimeHeaders mimeHeaders = new MimeHeaders();
      
              Enumeration enm = hashtable.keys();
              while (enm.hasMoreElements()) {
                  Object key = enm.nextElement();
                  mimeHeaders.addHeader((String) key, (String) hashtable.get(key));
                  log.debug("mime-header: {} = {}", key, hashtable.get(key));
              }
      
              return mimeHeaders;
          }
      
          private static ByteArrayInputStream readSoapBodyToByteArrayInputStream(BytesMessage bytesMessage) throws JMSException {
              int bodyLength = bytesMessage.readInt();
              byte[] buf = new byte[bodyLength];
              bytesMessage.readBytes(buf, bodyLength);
      
              return new ByteArrayInputStream(buf);
          }
      
          private static SOAPMessage constructSoapMessage(MessageFactory messageFactory, MimeHeaders mimeHeaders,
                                                          ByteArrayInputStream bodyByteArrayInputStream) throws SOAPException, IOException {
              if (messageFactory == null) {
                  messageFactory = getMessageFactory();
              }
      
              return messageFactory.createMessage(mimeHeaders, bodyByteArrayInputStream);
          }
      
          private static MessageFactory getMessageFactory() throws SOAPException {
              return MessageFactory.newInstance();
          }
      }
      
    • reference
    • SOAP over Java Message Service 1.0

    Create xml Document from File or String & convert Document to String

    • Create xml Document from File or String
    • public Document buildDocumentFromExternalResource() throw Exception {
          String content = "....";
          DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
          docBuilderFactory.setNamespaceAware(true);
          DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
          InputStream inputStream = new ByteArrayInputStream(content.getBytes());
          Document doc = docBuilder.parse(inputStream);
          // read from file
          doc = docBuilder.parse(new File("c:/temp/myContent.xml"));
      }
      
    • convert Document to String
    • public String convertDocumentToString(SOAPBody soapBody) throw Excepiton {
              Document doc = soapBody.getOwnerDocument();
              Source source = new DOMSource(doc);
              StringWriter out = new StringWriter();
              Result result = new StreamResult(out);
      
              TransformerFactory transformerFactory = TransformerFactory.newInstance();
              Transformer transformer = transformerFactory.newTransformer();
              transformer.transform(source, result);
      
              String content = out.toString();
         }
      

    Wednesday 25 July 2012

    A simple JMSClient to test JMS queue/topic in Weblogic

    import javax.jms.*;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import java.util.Hashtable;
    
    public class TestJMS {
        private static InitialContext context = null;
        private static QueueConnectionFactory connectionFactory = null;
        private static QueueConnection connection = null;
        private static QueueSession session = null;
        private static Queue queue = null;
        private static QueueSender queueSender = null;
        private static TextMessage message = null;
        //Using the Default Connection Factories
        //ref --> http://docs.oracle.com/cd/E15051_01/wls/docs103/jms/fund.html
        private static final String CONNECTION_FACTORY_JNDI_NAME = "weblogic.jms.ConnectionFactory";
        private static final String QUEUE_JNDI_NAME = "Police.Eno.CourtServiceQueue";
    
        public TestJMS() {
            super();
        }
    
        public static void sendMessage(String messageText) {
            try {
                try {
                    Hashtable properties = new Hashtable();
                    properties.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
                    properties.put(Context.PROVIDER_URL, "t3://localhost:7001");
    
                    context = new InitialContext(properties);
                    connectionFactory = (QueueConnectionFactory) context.lookup(CONNECTION_FACTORY_JNDI_NAME);
                    connection = connectionFactory.createQueueConnection();
                    session = connection.createQueueSession(false, 0);
    
                    queue = (Queue) context.lookup(QUEUE_JNDI_NAME);
                    queueSender = session.createSender(queue);
                    message = session.createTextMessage();
                    message.setText(messageText);
                    queueSender.send(message);
                } finally {
                    message = null;
                    queueSender.close();
                    queueSender = null;
                    queue = null;
                    session.close();
                    session = null;
                    connection.close();
                    connection = null;
                    connectionFactory = null;
                    context = null;
                }
            } catch (NamingException e) {
                e.printStackTrace(System.err);
                System.exit(0);
            } catch (JMSException e) {
                e.printStackTrace(System.err);
                System.exit(0);
            }
        }
    
        public static void main(String args[]) {
            sendMessage("test message here!!!");
        }
    }
    

    Monday 9 July 2012

    Regular express validate date time

    reference:
    http://stackoverflow.com/questions/1315376/regular-expression-for-date-time-format-mm-dd-yy-hhmmss-am-pm-in-asp-net-reg


    RegEx for matching all dates, including leap years.
    1. For DD-MM-YYYY format
    2. ^(?:31#(?:(?:0[13578])|(?:1[02]))#)|(?:(?:29|30)#(?:(?:0[1,3-9])|(?:1[0-2]))#)(?:(?:1[6-9]|[2-9]\d)\d{2})$|^(?:29#02#(?:(?:(?:1[6-9]|[2-9]\d)(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0[1-9])|(?:1\d)|(?:2[0-8]))#(?:(?:0[1-9])|(?:1[0-2]))#(?:(?:1[6-9]|[2-9]\d)\d{2})$
      
    3. For MM-DD-YYYY format
    4. ^(?:(?:(?:0?[13578]|1[02])#31)\1|(?:(?:0?[1,3-9]|1[0-2])#(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:0?2#29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))#(?:0?[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$
      
    5. Java Code
    6. String inputDate;
      String regex="^(?:31/(?:(?:0[13578])|(?:1[02]))/)|(?:(?:29|30)/(?:(?:0[1,3-9])|(?:1[0-2]))/)(?:(?:1[6-9]|[2-9]\\d)\\d{2})$|^(?:29/02/(?:(?:(?:1[6-9]|[2-9]\\d)(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0[1-9])|(?:1\\d)|(?:2[0-8]))/(?:(?:0[1-9])|(?:1[0-2]))/(?:(?:1[6-9]|[2-9]\\d)\\d{2})$";
      Pattern pattern = Pattern.compile(inputDate);
      Matcher matcher = pattern.matcher(inputDate);
      boolean found = matcher.matches();
      
    7. For Time
    8. ^([0|1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$
      

    Thursday 19 April 2012

    How to unit test with @ResponseBody return Json in Spring MVC controller

    1. model
    2. public class Dealer {
          private String id;
          private String name;
      
          public String getId() {
              return id;
          }
      
          public void setId(String id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      }
      
    3. Controller
    4. import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.ResponseBody;
      
      import javax.annotation.Resource;
      import java.util.List;
      
      @Controller
      @RequestMapping("/dealer")
      public class DealerController {
          @Resource(name = "dealerService")
          private DealerService dealerService;
      
          @RequestMapping("json/all")
          public @ResponseBody List<Dealer> getAllDealers() {
              return dealerService.getAllDealers();
          }
      }
      
    5. applicationContext.xml
    6. 
          
              
                  <entry key="xml" value="application/xml" />
                  <entry key="json" value="application/json" />
              
          
          
              
                 <bean class="org.springframework.web.servlet.view.xml.MarshallingView" p:marshaller-ref="unmarshaller" />
                 <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" p:objectMapper-ref="jacksonJsonObjectMapper" />
              
          
      
      
      
          <oxm:class-to-be-bound name="mypackge.Dealer"/>
      
      
    7. Unit test
    8. import com.google.common.collect.Lists;
      import org.apache.http.HttpHeaders;
      import org.junit.Before;
      import org.junit.Test;
      import org.springframework.http.MediaType;
      import org.springframework.http.converter.HttpMessageConverter;
      import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
      import org.springframework.mock.web.MockHttpServletRequest;
      import org.springframework.mock.web.MockHttpServletResponse;
      import org.springframework.test.util.ReflectionTestUtils;
      import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
      
      import java.util.List;
      
      import static org.junit.Assert.assertEquals;
      import static org.mockito.Mockito.mock;
      import static org.mockito.Mockito.when;
      
      public class TestDealerController {
          private DealerController dealerController;
      
          @Before
          public void before() throws Exception {
              DealerService dealerService = mock(DealerService.class);
              when(dealerService.getAllDealers()).thenReturn(mockDealers());
              
              dealerController = new DealerController();
              ReflectionTestUtils.setField(dealerController, "dealerService", dealerService);
          }
      
          @Test
          public void testGetAllDealers() throws Exception {
              MockHttpServletRequest mockRequest = new MockHttpServletRequest();
              mockRequest.setContentType(MediaType.APPLICATION_JSON.toString());
              mockRequest.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON.toString());
              mockRequest.setMethod("GET");
              mockRequest.setRequestURI("/dealer/json/all");
      
              AnnotationMethodHandlerAdapter handlerAdapter = new AnnotationMethodHandlerAdapter();
              HttpMessageConverter[] messageConverters = {new MappingJacksonHttpMessageConverter()};
              handlerAdapter.setMessageConverters(messageConverters);
      
              MockHttpServletResponse mockResponse = new MockHttpServletResponse();
              handlerAdapter.handle(mockRequest, mockResponse, dealerController);
      
              String expected="[{\"id\":\"01\",\"name\":\"dealer-01\"}, {\"id\":\"02\",\"name\":\"dealer-02\"}]";
              assertEquals(expected, mockResponse.getContentAsString());
          }
      
          private List<Dealer> mockDealers() {
              Dealer dealer01 = new Dealer();
              dealer01.setId("01");
              dealer01.setName("dealer-01");
      
              Dealer dealer02 = new Dealer();
              dealer02.setId("02");
              dealer02.setName("dealer-02");
      
              return Lists.newArrayList(dealer01, dealer02);
          }
      
    9. reference
    10. Spring Framework TEST RESTful Web Service (Controller) Offline i.e. No Server, No Database

    Wednesday 21 March 2012

    Spring support multiple @Transactional datasource

    1. Define tx-manager
    
        <tx:annotation-driven/>
        
            <property name="dataSource" ref="dataSource1"/>
        
    
        
            <property name="dataSource" ref="dataSource2"/>
        
    
    
    

    2. In you service layer code
    @Transactional(value = "jdbcTxManager")
    public List<String> getNames() {
        return userDao.getNames();
    }
    
    @Transactional(value = "jpaTxManager")
    public void persitentUser(User user) {
        return user.persist();
    }
    

    Friday 2 March 2012

    get directory of current class in java

    URL url = getClass().getProtectionDomain().getCodeSource().getLocation();
    String path = URLDecoder.decode(url.getPath(), "utf-8"); //important: if directory has space or chinese words
    File file= new File(path);
    System.out.println("directory is: " + file.getPath());
    

    Convert file path to URL and vice verse in java

    1 URL --> File path
    URL url = ...;
    File f = new File(url.getPath());
    

    2. File Path to url
    File f =...;
    
    URI uri = file.toURI();
    URL url = uri.toURL();
    

    Wednesday 29 February 2012

    How to mock http servlet with jetty to test some http-post,http-get in unit test?

    Solution:
    1. Write you own mock servlet
    public class MockServlet extends HttpServlet {
        private String servletData;
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            contextService(req, resp);
        }
    
        @Override
        protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    
        private void contextService(HttpServletRequest req, HttpServletResponse resp)  throws ServletException, IOException {
            servletData = IOUtils.toString(req.getInputStream());
    
            resp.setContentType("text/html");
            resp.setStatus(HttpServletResponse.SC_OK);
            resp.getWriter().print("Response from mock server: Submit is success.");
        }
    
        public String getServletData() {
            return servletData;
        }
    }
    

    2. define mock beans in spring application context (servlet and jetty server)
    2.1 servlet:

    <bean id="mockServlet" class="my.MockServlet"/>
    

    2.2 jetty server
    
            
                
                    
                        <property name="host" value="localhost"/>
                        <property name="port" value="8900"/>
                    
                
            
            
                
                    
                        <property name="contextPath" value="/"/>
                        
                            <bean class="org.mortbay.jetty.servlet.SessionHandler">
                        
                        <property name="resourceBase" value="c:/temp"/>
                        
                            
                                
                                
                                    
                                        
                                        
                                            <property name="name" value="defaultServlet"/>
                                            
                                                <bean class="org.mortbay.jetty.servlet.DefaultServlet"/>
                                            
                                            
                                                
                                                    <entry key="resourceBase" value="./"/>
                                                
                                            
                                        
                                        
                                            <property name="name" value="mockServlet"/>
                                            <property name="servlet" ref="mockServlet"/>
                                            
                                                
                                                    <entry key="resourceBase" value="./"/>
                                                
                                            
                                        
                                    
                                
                                
                                    
                                        
                                            
                                                
                                                    /
                                                
                                            
                                            <property name="servletName" value="defaultServlet"/>
                                        
                                        
                                            
                                                
                                                    /test/myAction
                                                
                                            
                                            <property name="servletName" value="mockCharityServlet"/>
                                        
                                    
                                
                            
                        
                    
                    
                    
                
            
        
    


    3. You Http Client code

    final HttpPost post = new HttpPost("http://127.0.0.1:9800/test/myAction");
    final HttpResponse resp = hc.execute(post);
    final HttpEntity respContent = resp.getEntity();
    final InputStream is = respContent.getContent();
    final StringWriter strWr = new StringWriter();
    IOUtils.copy(is, strWr);
    return strWr.toString();
    

    4. Junit
    String expected = "Response from mock server: Submit is success.";
    String actual = mockClient.submit();
    assertEquals(expected, actual);
    

    How to test email of junit

    How can it test email of junit? Solution use dumbster as a fake smtp server 1. add dependency to pom.xml
    
        dumbster
        dumbster
        1.6
        test
    
    
    2. add bean definition to spring applicationContext.xml
    
        <constructor-arg index="0" value="2525"/>
    
    
    using javax mail session
    
        
            
                127.0.0.1
                2525
            
        
    
    
        <constructor-arg ref="mailSession" type="javax.mail.Session"/>
    
    
    or if you using spring mail sender:
    <bean class="org.springframework.mail.javamail.JavaMailSenderImpl" id="mailSender" p:host="localhost" p:port="2525"/>
    
    3. define one util class
    import com.dumbster.smtp.SimpleSmtpServer;
    import com.dumbster.smtp.SmtpMessage;
    import com.dumbster.smtp.SmtpResponse;
    import com.dumbster.smtp.SmtpState;
    import org.hamcrest.Description;
    import org.hamcrest.Factory;
    import org.hamcrest.Matcher;
    import org.hamcrest.TypeSafeMatcher;
    
    import java.util.Iterator;
    
    public class BodySmtpMessage extends TypeSafeMatcher<Smtpmessage> {
        private SmtpMessage smtpMessage;
    
        public BodySmtpMessage(SmtpMessage smtpMessage) {
            this.smtpMessage = smtpMessage;
        }
    
        @Override
        public boolean matchesSafely(SmtpMessage smtpMessage) {
            return smtpMessage.getBody().equals(smtpMessage.getBody());
        }
    
        @Override
        public void describeTo(Description description) {
            description.appendText("not same body message");
        }
    
        @Factory
        public static <T> Matcher<smtpmessage> bodyEqualTo(SmtpMessage smtpMessage) {
            return new BodySmtpMessage(smtpMessage);
        }
    
        public static SmtpMessage getExpectedSmtpMessage(String body) {
            SmtpResponse smtpResponse = new SmtpResponse(1, "", SmtpState.DATA_BODY);
            SmtpMessage expectedMessage = new SmtpMessage();
            expectedMessage.store(smtpResponse, body);
    
            return expectedMessage;
        }
    
        public static SmtpMessage getFirstReceivedMessage(SimpleSmtpServer simpleSmtpServer) {
            Iterator<smtpmessage> receivedEmail = simpleSmtpServer.getReceivedEmail();
    
            while (receivedEmail.hasNext()) {
                return receivedEmail.next();
            }
            return null;
        }
    }
    
    4. Junit
    import com.dumbster.smtp.SimpleSmtpServer;
    import com.dumbster.smtp.SimpleSmtpServer;
    import com.dumbster.smtp.SmtpMessage;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import javax.annotation.Resource;
    
    import static au.com.hothouse.toyota.utils.email.BodySmtpMessage.*;
    import static org.hamcrest.CoreMatchers.is;
    import static org.junit.Assert.*;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath*:applicationContext-test.xml")
    public class TestEmailerImpl {
        @Resource(name = "saveYourCarEmailer")
        private EmailerImpl emailer;
        @Resource(name = "fakeSmtpServer")
        private SimpleSmtpServer simpleSmtpServer;
    
        private static String EXPECTED = "Dear Jianjun Shou,\n" +
                "\n" +
                "Here is the permanent link to the vehicle you have created:\n" +
                "\n" +
                "http://test.email.hothouse.com.au\n" +
                "\n" +
                "Thank you for vising the Toyota website.\n" +
                "\n" +
                "Regards,\n" +
                "\n" +
                "The Toyota Team";
    
        @Test
        public void testEmail() throws Exception {
            emailer.email("Jianjun", "Shou", "sean.shou@hothouse.com.au", "http://test.email.hothouse.com.au");
            assertTrue("test failed", simpleSmtpServer.getReceivedEmailSize() > 0);
            SmtpMessage sentMessage = getFirstReceivedMessage(simpleSmtpServer);
            SmtpMessage expectedSmtpMessage = getExpectedSmtpMessage(EXPECTED);
            assertThat(sentMessage, is(bodyEqualTo(expectedSmtpMessage)));
        }
    }
    

    Friday 17 February 2012

    How to enable jmx on tomcat in linux

    create setenv.sh in $CATALINA_HOME/bin, add following lines to here

    CATALINA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8086 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.4.38"
    


    Important!: don't forget to give quote(")

    Thursday 16 February 2012

    Tomcat: “java.lang.OutOfMemoryError: PermGen space” error

    solution:

    create setenv.sh as follow and put it into $CANTLINA_HOME/bin

    #!/bin/sh
    JAVA_OPTS="-Xms256m -Xmx512m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=256m"

    Monday 30 January 2012

    Validate xml use XSD

    import javax.xml.transform.stream.StreamSource; 
    import javax.xml.validation.SchemaFactory; 
    import javax.xml.validation.Schema;
    import javax.xml.XMLConstants;
    import javax.xml.validation.Validator;
    
    public void validateXml(String xsdFile, String xmlFile) {
       try {
          final String schemaURI = XMLConstants.W3C_XML_SCHEMA_NS_URI; 
          SchemaFactory factory = SchemaFactory.newInstance(schemaURI); 
          Schema schema = factory.newSchema(new StreamSource(xsdFile)); 
          Validator validator = schema.newValidator();
          validator.validate(new StreamSource(xmlFile));
       } catch(Exception e) {
         System.err.println(e);
       }
    }