Tag: vaadin

  • Implementing a QR servlet in java

    In this posting I want to implement a sample application which creates a QR-Code (for any URL) and displays as PNG image in the browser.

    As in previous postings I will use Eclipse and integrate the QR-Code in a simple Vaadin 8 application, because it simplifies the workflow. But the code will work with any kind of UI framework.

    To create the QR-Code I decided to use the net.glxn.QRGen framework.

    Okay let us directley start into the object representation of a QR-Code:

    QRCode:

    package at.nettania.dev.sample.qrcodeapp.core;
    
    import java.io.ByteArrayOutputStream;
    import java.io.Serializable;
    
    import net.glxn.qrgen.image.ImageType;
    
    /**
     * Implementation of QRCode. Use this class to create an arbitrary {@link QRCode} object.
     * Use {@link QRCodeUtil} to display the QRCode as PNG image in the browser.
     * This object is not persistent and will be created on the fly.
     * 
     * @author florian
     *
     */
    public class QRCode implements Serializable {
      
      /**
       * 
       */
      private static final long serialVersionUID = 6368834871126835904L;
      
      private String name;
      private String qrCodeValue;
      private int width;
      private int height;
      
      /**
       * Use this constructor to create an empty {@link QRCode} with the dimensions 250x250 and name qrcode
       */
      public QRCode() {
        this.name = "qrcode";
        this.width = 100;
        this.height = 100;
      }
      
      /**
       * Use this constructor to create a {@link QRCode} with the given value and the given name,
       * which is used as filename if displayed in the browser in combination with {@link QRUtil}
       * @param name
       * @param qrCodeValue
       */
      public QRCode(String name, String qrCodeValue) {
        this.name = name;
        this.qrCodeValue = qrCodeValue;
        this.width = 250;
        this.height = 250;
      }
      
      /**
       * @return the name
       */
      public String getName() {
        return name;
      }
    
      /**
       * @param name the name to set
       */
      public void setName(String name) {
        this.name = name;
      }
    
      /**
       * @return the qrCodeValue
       */
      public String getQrCodeValue() {
        return qrCodeValue;
      }
    
      /**
       * @param qrCodeValue the qrCodeContent to set
       */
      public void setQrCodeValue(String qrCodeValue) {
        this.qrCodeValue = qrCodeValue;
      }
    
      /**
       * @return the width
       */
      public int getWidth() {
        return width;
      }
    
      /**
       * @param width the width to set
       */
      public void setWidth(int width) {
        this.width = width;
      }
    
      /**
       * @return the height
       */
      public int getHeight() {
        return height;
      }
    
      /**
       * @param height the height to set
       */
      public void setHeight(int height) {
        this.height = height;
      }
    
      /**
     * Return the QRCode as byte array in UTF-8 and as PNG image
     * @return
     */
     public byte[] getQRCode() {
        ByteArrayOutputStream stream = net.glxn.qrgen.QRCode.from(qrCodeValue).withSize(width, height).withCharset("UTF-8").to(ImageType.PNG).stream();
        return stream.toByteArray();
     }
    }

    This is a quiet simple class and only used to simplify the method arguments for the QRCodeUtil class. The qrCodeValue string will contain the text form which the QRCode should be generated. The name string is only used as filename for the image. with the two int values for width and height I set the dimension of the QRCode. This could also be merged into one integer, because a QRCode should usually be quadratic. Of course, creating an own QRCode object might be oversized for this example, but I personally always like to work with objects instead of methods with multiple parameters.

    The key method of this class and also from the whole application is the last public byte[] getQRCode() method. In this method, we use the QRGen framework to create an QRCode and return it as png UTF-8 byte array. Later we will use this method in the servlet class to create a BufferedImage.

    Our next class will be a static utility class providing methods to quickly create an QRCode.

    QRCodeUtil:

    package at.nettania.dev.sample.qrcodeapp.core;
    
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    /**
     * This class implements static utility methods for {@link QRCode}
     * 
     * @author florian
     *
     */
    public class QRCodeUtil {
      
      private static Log log = LogFactory.getLog(QRCodeUtil.class);
      
      public static String getQrCodeUrl(String url, String qrCodeContent) {
        QRCode code = new QRCode();
        code.setName("myqrcode");
        code.setQrCodeValue(qrCodeContent);
        code.setHeight(250);
        code.setWidth(250);
        
        return getQRCodeUrl(url, code);
      }
    
      /**
       * Returns the URL to display this {@link QRCode} in the browser
       * @param qrcode
       * @return
       */
      public static String getQRCodeUrl(String url, QRCode qrcode) {
        String uurl = "";
        try {
          uurl = url+"qrcode/{filename}.png?code={qrcode}&dimension={width}x{height}";
          uurl = uurl.replace("{filename}", qrcode.getName());
          uurl = uurl.replace("{qrcode}", URLEncoder.encode(qrcode.getQrCodeValue(), "UTF-8"));
          uurl = uurl.replace("{width}", qrcode.getWidth()+"");
          uurl = uurl.replace("{height}", qrcode.getHeight()+"");
          log.debug("URL: "+uurl);
        } catch (UnsupportedEncodingException e) {
          log.error("Unexpected error occured.", e);
        }
        
        return uurl;
      }
    }

    This class provides two methods which creates a QRCode and returns the URL to its image representation. The getQrCodeUrl(String url, String qrCodeContent) method requires the base URL of the application and a String with the content for the QRCode. With this information the method creates a QRCode object and calls the second getQRCodeUrl(String url, QRCode qrcode) method of this class.

    Let us go a little bit into detail of the getQRCodeUrl(String url, QRCode qrcode) method, where we assemble the URL. In line 37 we define the url pattern for the servlet, consisting of the application url, the servlet extension (qrcode), the filename an file type (.png) as well as the GET parameters for the servlet. code: The String which should be displayed as QRCode, and the dimension: Defines the width and height of the created QRCode (separated by x).

    The next code lines only replaces the defined placeholders with data. Line 39 should be considered where we encode the QR-Code to UTF-8, which is important to avoid encoding problems.

    Finally, we return the created URL as String.

    QRCodeServlet:

    This class is a simple servlet which creates form a ByteArray an image.

    package at.nettania.dev.sample.qrcodeapp.web;
    
    import java.awt.image.BufferedImage;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    
    import javax.imageio.ImageIO;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import at.nettania.dev.sample.qrcodeapp.core.QRCode;
    
    /**
     * This class implements a servlet to display a QRCode
     * 
     * @author florian
     *
     */
    @WebServlet(urlPatterns = "/qrcode/*", name = "QRCodeServlet", asyncSupported = true)
    public class QRCodeServlet extends HttpServlet {
    
      /**
       * 
       */
      private static final long serialVersionUID = -6031742898289759780L;
      private static Log log = LogFactory.getLog(QRCodeServlet.class);
      
      public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        int width = 250;
        int height = 250;
        
        String filename = req.getPathInfo();
        String code = req.getParameter("code");
        String dimension = req.getParameter("dimension");
        if(dimension != null && dimension.matches("\\d+x\\d+")) {
          width = Integer.parseInt(dimension.split("x")[0]);
          height = Integer.parseInt(dimension.split("x")[1]);
        }
        
        
        if(code == null) {
          log.debug("Code parameter is missing.");
          res.sendError(HttpServletResponse.SC_BAD_REQUEST);
        } else {
          log.debug("Creating QRCode for filename "+filename);
          
          QRCode qrCode = new QRCode();
          qrCode.setWidth(width);
          qrCode.setHeight(height);
          qrCode.setQrCodeValue(code);
          qrCode.setName(filename);
          
          
          ByteArrayInputStream in = new ByteArrayInputStream(qrCode.getQRCode()); // The input Stream
          BufferedImage image = ImageIO.read(in);
          getImage(image, qrCode.getName(), qrCode.getFiletype(), res);
        }
      }
      
      private static void getImage(BufferedImage image, String filename, String type, HttpServletResponse res){
        try {
          String formatName = "JPEG";
          if(filename.contains(".")) {
            String[] split = filename.split("\\.");
            formatName = split[split.length-1];
          }
          
          log.debug("Filename: "+filename);
          log.debug("Type of image: "+formatName);
          
          // As default type we use RGB, because if the JPEG is of type CMYK a bug in Java leads to a wrong representation of the colors. 
          // RBG does not support transparency, but JPEG does not do it either, therefore it does not matter that we have no alpha channel.
          int imageType = BufferedImage.TYPE_INT_RGB;
          
          // We change the image type to ARGB to support transparent backgrounds for PNG
          if(formatName.toLowerCase().equals("png"))
            imageType = BufferedImage.TYPE_INT_ARGB;
          // We change the image type to ARGB to support transparent backgrounds for GIF
          if(formatName.toLowerCase().equals("gif"))
            imageType = BufferedImage.TYPE_INT_ARGB;
          
          
            BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), imageType);
            convertedImage.getGraphics().drawImage(image, 0, 0, null);
            convertedImage.getGraphics().dispose();
            
          // Write the image with the java's ImageIO
          ImageIO.write(convertedImage, formatName, res.getOutputStream());
        }
        // if something happens an exception is thrown
        catch(Exception e){
          log.error(e);
        }
      }
    }

    We use annotations instead of web.xml file to define the settings of the servlet. This servlet has the name QRCodeServlet and “/qrcode/*” as relative path.

    The doGet method uses the GET parameters to create a new instance of a QRCode object. If the dimension parameters do not exist, the servlet defines a default width and height of 250. If the code parameter does not exist the servlet throws an http 400 error, which means bad request.

    Then we create an ByteArrayInputStream which contains the ByteArray representation of our QRCode. With the help of the static ImageIO class we create a BufferedImage and call the static getImage(BufferedImage image, String filename, String type, HttpServletResponse res) method to write the Image and display it as servlet content.

    As already mentioned at the beginning I integrated this sample into a Vaadin 8 application, consisting of a TextField a Button and an Image (which displays the QRCode) to have a working example. The following code represents the Vaadin UI:

    /**
     * This is a sample application which creates from a {@link TextField} input a QR-Code.
     * 
     * @author florian
     *
     */
    @Theme("mytheme")
    public class QrCodeUi extends UI {
    
        /**
       * 
       */
      private static final long serialVersionUID = 1633256676992649404L;
    
      @Override
        protected void init(VaadinRequest vaadinRequest) {
        Page.getCurrent().setTitle("QR-Code sample");
            
            //
            // UI components
            //
        final VerticalLayout layout = new VerticalLayout();
            final Image qrImage;
            
            //
            // Wrapper around the TextField
            //
            final HorizontalLayout wrapper = new HorizontalLayout();
            wrapper.setWidthUndefined();
            layout.addComponent(wrapper);
            layout.setComponentAlignment(wrapper, Alignment.TOP_CENTER);
            
            final Label caption = new Label("Enter an URL to display as QRCode:");
            wrapper.addComponent(caption);
            wrapper.setComponentAlignment(caption, Alignment.MIDDLE_CENTER);
            
            final TextField name = new TextField();
            name.setWidth(250, Unit.PIXELS);
            name.setPlaceholder("www.florian-rhomberg.net");
            wrapper.addComponent(name);
            name.focus();
            
            final Button button = new Button("Create QR-Code");
            wrapper.addComponents(button);
            
            //
            // The QR-Image
            //
            qrImage = new Image();
            layout.addComponent(qrImage);
            layout.setComponentAlignment(qrImage, Alignment.TOP_CENTER);
            
            button.addClickListener(new ClickListener() {
    
          /**
           * 
           */
          private static final long serialVersionUID = 7507056868576045294L;
    
          @Override
          public void buttonClick(ClickEvent event) {
                  qrImage.setSource(new ExternalResource(QRCodeUtil.getQrCodeUrl(Page.getCurrent().getLocation().toString(), name.getValue())));
          }});
            
            setContent(layout);
        }
    
        @WebServlet(urlPatterns = "/*", name = "QrCodeUiServlet", asyncSupported = true)
        @VaadinServletConfiguration(ui = QrCodeUi.class, productionMode = false)
        public static class QrCodeUiServlet extends VaadinServlet {
    
        /**
         * 
         */
        private static final long serialVersionUID = 3594396700811845967L;
        }
    }

    That’s it, I hope this posting might help someone who also needs to implement QRCode in a java web applications. The whole project is available on github.

    Links:

  • Implementing a simple LoginApp with Vaadin

    If you have a small vaadin application you might want to avoid using complex authentication and authentifaction frameworks like Spring. In this post I want to show a small vaadin application with authentication functionality only using views. This solution might not fullfill complex authorization or authentication functionalities, but it is a simple ways to secure a vaadin interface. The whole application is available on github.

    First we need an object which represents an user and some sort of repository where we can store the user object:

    public class User implements Serializable {
    
      /**
       * 
       */
      private static final long serialVersionUID = 4753508683469842961L;
      
      private String name;
      private String username;
      private String password;
      
      public User() {
        this.name = "";
        this.username = "";
        this.password = "";
      }
      
      public User(String name, String username, String password) {
        this.name = name;
        this.username = username;
        this.password = password;
      }
    
      @Override
      public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((password == null) ? 0 : password.hashCode());
        result = prime * result + ((username == null) ? 0 : username.hashCode());
        return result;
      }
    
      @Override
      public boolean equals(Object obj) {
        if (this == obj)
          return true;
        if (obj == null)
          return false;
        if (getClass() != obj.getClass())
          return false;
        User other = (User) obj;
        if (password == null) {
          if (other.password != null)
            return false;
        } else if (!password.equals(other.password))
          return false;
        if (username == null) {
          if (other.username != null)
            return false;
        } else if (!username.equals(other.username))
          return false;
        return true;
      }
    
      public String getName() {
        return name;
      }
    
      public void setName(String name) {
        this.name = name;
      }
    
      public String getUsername() {
        return username;
      }
    
      public void setUsername(String username) {
        this.username = username;
      }
    
      public String getPassword() {
        return password;
      }
    
      public void setPassword(String password) {
        this.password = password;
      }
      
    }

    The repository class:

    public class UserRepository {
      
      private static HashSet<User> getUsers() {
        HashSet<User> users = new HashSet<User>();
        users.add(new User("John Doe", "john", "amanda"));
        users.add(new User("Amanda Doe", "amanda", "john"));
        
        return users;
      }
      
      public static User authenticate(String username, String password) {
        // We simple create a new user with this credentials and check the hash set if exists.
        User userToCheck = new User("", username, password);
        
        for (Iterator<User> it = getUsers().iterator(); it.hasNext(); ) {
              User f = it.next();
              if (f.equals(userToCheck))
                  return f;
          }
        
        return null;
      }
    }

    The User class implements a simple object which represents a User for login, consisting of name, username and password. This is just an example therefore we will not store the password crypted, never do this in a productive environment! We use username and password to check if an user is equal, or not.

    The UserRepository class should represents a database with stores users, in this case we create two user “John” Doe” and “Amanda Doe” and if we call the autheticate class we simple iterate through the created users until we found the one with the given username and password and return him/her.

    This two classes are implementing the environment, we need to implement our goal.

    The main application consits of four classes:

    • LoginView: Represents the application view before the user has logged in.
    • MainView: The application view after login
    • SimpleLoginApp: The servlet which navigates between the two views.
    • LoginAppUiController: A simple controller which implements the login logic.

    I will start with the the two Views:

    public class LoginView extends VerticalLayout implements View {
    
      /**
       * 
       */
      private static final long serialVersionUID = 3070811273936236288L;
      public static String VIEWNAME = "login";
      
      public LoginView(LoginAppUiController uicontroller) {
        this.setLocale(UI.getCurrent().getLocale());
        this.setSizeFull();
        this.setSpacing(false);
        this.setMargin(false);
        
        VerticalLayout loginWrapper = new VerticalLayout();
        loginWrapper.setWidth(500, Unit.PIXELS);
        loginWrapper.setSpacing(true);
        this.addComponent(loginWrapper);
        this.setComponentAlignment(loginWrapper, Alignment.MIDDLE_CENTER);
        
        TextField username = new TextField();
        username.setWidth(100, Unit.PERCENTAGE);
        username.setPlaceholder("Username");
        username.setIcon(VaadinIcons.USER);
        username.setStyleName("inline-icon");
        username.focus();
        loginWrapper.addComponent(username);
        
        PasswordField password = new PasswordField();
        password.setWidth(100, Unit.PERCENTAGE);
        password.setPlaceholder("Password");
        password.setIcon(VaadinIcons.LOCK);
        password.setStyleName("inline-icon");
        loginWrapper.addComponent(password);
        
        NativeButton loginButton = new NativeButton("Login");
        loginWrapper.addComponent(loginButton);
        loginWrapper.setComponentAlignment(loginButton, Alignment.MIDDLE_CENTER);
        loginButton.addClickListener(listener -> uicontroller.login(username, password));
        loginButton.addShortcutListener(new ShortcutListener("", ShortcutAction.KeyCode.ENTER, null) {
    
          /**
           * 
           */
          private static final long serialVersionUID = 8664364871536035397L;
    
          @Override
          public void handleAction(Object sender, Object target) {
            uicontroller.login(username, password);
          }});
      }
      
      @Override
      public void enter(ViewChangeEvent event) {
        Page.getCurrent().setTitle("SimpleLoginApp - Login");
        }
    }

    Some remarks to the listing above:

    • public class LoginView extends VerticalLayout implements View: This class should implement a vaadin view, therefore we must implemente the View interface.
    • public static String VIEWNAME: This constant is quit important, because if defines the navigation name for this view. We will need the name in the SimpleLoginApp servlet.
    •  If he/she presses on login the LoginAppUiController is called to verify the credentials and to continue.
    public class MainView extends VerticalLayout implements View {
    
      /**
       * 
       */
      private static final long serialVersionUID = 3070811273936236288L;
      public static String VIEWNAME = "main";
      
      public MainView(LoginAppUiController uicontroller) {
        this.setLocale(UI.getCurrent().getLocale());
        this.setSizeFull();
        this.setSpacing(false);
        this.setMargin(false);
        
        VerticalLayout wrapper = new VerticalLayout();
        wrapper.setWidth(500, Unit.PIXELS);
        wrapper.setSpacing(true);
        this.addComponent(wrapper);
        this.setComponentAlignment(wrapper, Alignment.MIDDLE_CENTER);
        
        Label info = new Label("This is the main view of our application, you can reload and close the browser tab, until the session"
            + " does not expire, or you press the logout button, you will always stay on this view.");
        info.setContentMode(ContentMode.HTML); // Set to html to allow line breaks.
        info.setWidth(100, Unit.PERCENTAGE);
        wrapper.addComponent(info);
        
        NativeButton logoutButton = new NativeButton("Logout");
        wrapper.addComponent(logoutButton);
        wrapper.setComponentAlignment(logoutButton, Alignment.MIDDLE_CENTER);
        logoutButton.addClickListener(listener -> uicontroller.logout());
      }
      
      @Override
      public void enter(ViewChangeEvent event) {
        Page.getCurrent().setTitle("SimpleLoginApp - Main");
        }
    }

    Like the listing of the LoginView, we need to implemente the View interface for the MainView as well. Apart of this, we only have a NativeButton which calls the logout method of the LoginAppUiController if pressed.

    The next listing represents the LoginAppUiController, which implements the login logic of the application:

    public class LoginAppUiController implements Serializable {
    
      /**
       * 
       */
      private static final long serialVersionUID = -7570570535339156683L;
      public static String SESSION_ATTRIBUTE = "loginAppUiController";
      
      private User user; // The current user of this instance of the application
      private SimpleLoginApp app; // Our application class
      
      public LoginAppUiController(SimpleLoginApp app) {
        this.app = app;
      }
      
      public void login(TextField username, PasswordField password) {
        // If the username and password combination exists the repository will return the user
        this.user = UserRepository.authenticate(username.getValue(), password.getValue());
        
        // The user has been authenticated therefore we continue to the main application view.
        if(this.user != null) {
          // After login you need to add the current controller to the session.
          UI.getCurrent().getSession().setAttribute(SESSION_ATTRIBUTE, this);
        
          // Finally navigate to the main view of the application
          this.app.getNavigator().navigateTo(MainView.VIEWNAME);
        } else {
          Notification.show("This combination of username and password does not exists", Type.ERROR_MESSAGE);
          username.clear();
          password.clear();
          username.focus();
        }
      }
      
      /**
       * This method checks if the {@link User} is authenticated.
       * @return
       */
      public boolean isAuthenticated() {
        if(user != null)
          return true;
        else
          return false;
      }
      
      /**
       * This method implements the logout procedure of the application
       */
      public void logout() {
        // Close the session, this means we destroy the session including this instance of the LoginAppUiController
            UI.getCurrent().getSession().close();
        
            // Go to the login page 
            UI.getCurrent().getPage().reload();
      }
    }

    Let us go a little bit more into detail of some aspects of this class:

    • public static String SESSION_ATTRIBUTE: We will store the whole LoginAppUiController as session attribute in the vaadin session, under this name.
    • private SimpleLoginApp app: Reference to the servlet which implements the navigation for the two views.
    • public void login(TextField username, PasswordField password): Performs the validation of the user credentials, called from the LoginView. If the credentials are confirmed we add the instance of this LoginAppUiController to the Vaadin session and navigate to the MainView. Otherwise we clear the username and password field and prompt the user to enter its credentials again.
    • public boolean isAuthenticated(): This method checks if the user is authenticated or not.
    • public void logout(): This method is called from the MainView of the application, after the logout button is pressed. It closes the current Vaddin session and forces a reload of the whole UI of the application.

    The last class is the servlet which creates a Vaadin Navigator and implements the java servlet:

    @Theme("mytheme")
    public class SimpleLoginApp extends UI {
      
      /**
       * 
       */
      private static final long serialVersionUID = -8272040115893003478L;
      
      private Navigator navigator;
    
        @Override
        protected void init(VaadinRequest vaadinRequest) {
        		//
        // Create an instance of the LoginAppUiController and add it to the session
        //
        LoginAppUiController uicontroller;
        
        // If a session already exists, there must be an attribute containing the LoginAppUiController
        if(UI.getCurrent().getSession().getAttribute(LoginAppUiController.SESSION_ATTRIBUTE) != null)
          uicontroller = (LoginAppUiController) UI.getCurrent().getSession().getAttribute(LoginAppUiController.SESSION_ATTRIBUTE);
        // Create a new instance of the FrontendUiController, which means the user must enter his/her credentials
        else
          uicontroller = new LoginAppUiController(this);
        
        //
        // Create the navigator
        //
        this.navigator = new Navigator(this, this);
        this.navigator.addView(LoginView.VIEWNAME, new LoginView(uicontroller));
        this.navigator.addView(MainView.VIEWNAME, new MainView(uicontroller));
        
        //
        // Enter the right view
        //
        if(uicontroller.isAuthenticated())
          this.navigator.navigateTo(MainView.VIEWNAME);
        else
          this.navigator.navigateTo(LoginView.VIEWNAME);
        }
    
        @WebServlet(urlPatterns = "/*", name = "SimpleLoginAppServlet", asyncSupported = true)
        @VaadinServletConfiguration(ui = SimpleLoginApp.class, productionMode = false)
        public static class SimpleLoginAppServlet extends VaadinServlet {
    
        /**
         * 
         */
        private static final long serialVersionUID = 4683186830720335264L;
        }
    }
    • This class extends Vaadin UI and therefore implements the method init() and an internal class which extends VaadinServlet.
    • In line 15-24 we create an instance of the LoginAppUiController. First we check if the current session has already an instance of the controller by checking if the session attribute loginAppUiController is not null. Remember we defined the session attribute for this controller in its class. If the attribute is not null we will continue using this instance of the controller class, if not we create a new instance.
    • Next we create a vaadin navigator and add the two view, we have, LoginView and MainView (29-32).
    • Next we decide which view should be loaded. If the user is already authenticated (remember at that point of the application we will have a valid instance of the LoginAppUiController), we will directly navigate to the MainView, else to the LoginView.

    That´s it, now we have a simple Vaadin application with authentication. If there are any questions, just leave a message.

    Links: