Saturday, December 12, 2020

Create a Simple VueJs Progressive Web Apps (PWA) and Deploy to Firebase

In this tutorial, we are going to create a simple VueJs PWA application and also show you how to deploy it to firebase. As we know that PWA is being more famous these days due to its very fast performance and can be used for different platforms with a single code base as well as the offline functionality and caching support.

1. Install Vue CLI

If you haven't installed the Vue CLI, open the command prompt or terminal and run the following command to install it globally. 

- For npm package manager:

npm install -g @vue/cli
- For yarn package manager:

yarn global add @vue/cli



2. create a VueJs PWA project:

vue create vue-pwa
Now, select the manual option

Select Progressive Web App (PWA) Support option from the list. As you need to go to that option using the down arrow on the keyboard and hit the spacebar to select that option. Also select the other option if you are going to use them like Router, Vuex, etc.



Now, go to the project directory and run the application.
cd vue-pwa
yarn serve
Vue CLI created a sample demo application for us so, we are using the same for this tutorial. If you look into the Application tab by doing the inspect element of the above running project, there you can see the Service Workers. The main heart of the PWA is this service worker. As if we run the PWA application locally the service worker will not work, as it required an HTTPS secure connection.

 

The service worker is the script that will run in the background separately from the application which helps to install, activate, caching of our application. There are more thing about service worker, will discuss in the future article.

So how we can test the PWA application. As we can use some third-party services as well as we can simply deploy to firebase.

3. How to test our PWA application locally:

- Build the application in production mode:

yarn build
This will create the deployment-ready dist folder.

First, run this locally using http-server package. In order to do the show first install it globally.
npm install http-server -g
Now, run the dist folder:
http-server dist/
Which will run the application. Now what we need to do is tunnel our local server with HTTPS. Please follow this Tunnel local server to the public internet with HTTPS using Ngrok. This will tunnel our local server over HTTPS. Now open the tunneled URL. You can see the service worker as follows.



Also, you can see the + icon to install your PWA app in the browser.


If you run the same tunneled URL on the mobile then you will get the following screen to install your PWA application.

Add vue-pwa to Home screen if you click this, it will add the application to the home screen so that you can later open it by simply clicking it.

4. Deploy to firebase.

Now, let's deploy the build dist folder in the firebase server.

- Go to the firebase console "https://console.firebase.google.com/"

- Create a project by giving the project name.

- Installing firebase in our system.

 Open the command prompt or terminal and install firebase globally.
npm install -g firebase-tools
Initialize the project: Make sure to go to the project directory.
firebase login
This will ask for a google login. You can authenticate the google account where your firebase console project is created. If you want to logout use the following command.
firebase logout
Now, initialize the project:
firebase init
This will ask a couple of question make sure you insert the right as below:
We are simply using it for hosting our application so chose the same option.


Make sure the above setting. The public directory will be dist in our case, as we are deploying the dist folder.

This will create two files in our project:

- .firebaserc

where you can find the project's configuration. Make sure you have the same project name in the "default" section to that create on the firebase console. While deploying it, will use the same firebase console project created. In my case, it is "vue-pwa-7ed80". The config file looks like below.

{
  "projects": {
    "default": "vue-pwa-7ed80"
  }
}

- firebase.json

where all the hosting configuration is done. The config file looks like below.

{
  "hosting": {
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

Deploy our application.

First, build the application:
yarn build

Now, deploy the build dist folder

 
firebase deploy

This will deploy our application to the firebase server. You can see the deployment history and track from the console under the Hosting section inside the firebase console.

Firebase gives the live HTTPS URL which you can see in the firebase console. If you run that URL you will see the service worker will register and can be run the application as a PWA application.

Finally, we created a simple VueJs application with PWA support and successfully deployed it to the firebase.



Share:

Friday, December 11, 2020

How to Implement Webcam in VueJs Application

In this tutorial, we are going to implement a webcam in the Vuejs application.


Generally, what it does is:

  1. Stream the video from the webcam
  2. Capture photo from the streaming video
  3. Preview the captured photo
  4. Convert it into the file to send to the server
The overall implementation looks as below:




1. Create a sample Vuejs application.

Open the terminal or command prompt and create the application.

vue create vue-camera
  

Select the default option or can select manually, where you can have a choice to set up.
cd vue-camera
yarn serve

2. Create a Vuejs webcam component



Now, let's create a component called Camera.vue.  
<div class="camera-box">
    <div style="display: flex; justify-content: center;">
        <img style="height: 25px;" v-if="isCameraOpen"
             src="https://img.icons8.com/material-outlined/50/000000/camera--v2.png"
             class="button-img camera-shoot" @click="capture"/>
        <div class="camera-button">
            <button type="button" class="button is-rounded cam-button"
                    style="margin-left: 40%; background-color: white; border: 0px;"
                    @click="toggleCamera"
            >
        <span v-if="!isCameraOpen"><img style="height: 25px;" class="button-img"
                                        src="https://img.icons8.com/material-outlined/50/000000/camera--v2.png"></span>
                <span v-else><img style="height: 25px;" class="button-img"
                                  src="https://img.icons8.com/material-outlined/50/000000/cancel.png"></span>
            </button>
        </div>
    </div>
    <div style="height: 200px">
        <div v-if="isCameraOpen" class="camera-canvas">
            <video ref="camera" :width="canvasWidth" :height="canvasHeight" autoplay></video>
            <canvas v-show="false" id="photoTaken" ref="canvas" :width="canvasWidth" :height="canvasHeight"></canvas>
        </div>
    </div>
</div>
Let's set the data used.
export default {
  name: "Camera",
  components: {
  },
  data() {
    return {
      isCameraOpen: false,
      canvasHeight:200,
      canvasWidth:190,
      items: [],
    }
  },
  }
<style scoped>
.camera-box {
  border: 1px dashed #d6d6d6;
  border-radius: 4px;
  padding: 2px;
  width: 80%;
  min-height: 300px;
}

</style>





The HTML file used will show the camera image button to capture the photo. Here, we are using canvas height and width for the photo size. You can always adjust the different size photo by adjusting canvas height and width.

Let's use the different functions used in HTML.
toggleCamera() {
      if (this.isCameraOpen) {
        this.isCameraOpen = false;
        this.stopCameraStream();
      } else {
        this.isCameraOpen = true;
        this.startCameraStream();
      }
    },
This function simply toggles the camera to capture the photo. And start streaming the video. Let's implement the function used inside this toggleCamer().
startCameraStream() {
      const constraints = (window.constraints = {
        audio: false,
        video: true
      });
      navigator.mediaDevices
          .getUserMedia(constraints)
          .then(stream => {
            this.$refs.camera.srcObject = stream;
          }).catch(error => {
        alert("Browser doesn't support or there is some errors." + error);
      });
    },
The above function will start the camera by using the navigator mediaDevices interface which will access to the connected media input device, in our case its camera. And asign the streaming to canvas dom element to show the video. Here we are setting the constraints as audio is false because we don't need the audio to capture the photo.
stopCameraStream() {
      let tracks = this.$refs.camera.srcObject.getTracks();
      tracks.forEach(track => {
        track.stop();
      });
    },
The above function will simply stop the camera by stopping the sequence of track in streaming.
capture() {
      const FLASH_TIMEOUT = 50;
      let self = this;
      setTimeout(() => {
        const context = self.$refs.canvas.getContext('2d');
        context.drawImage(self.$refs.camera, 0, 0, self.canvasWidth, self.canvasHeight);
        const dataUrl = self.$refs.canvas.toDataURL("image/jpeg")
            .replace("image/jpeg", "image/octet-stream");
        self.addToPhotoGallery(dataUrl);
        self.uploadPhoto(dataUrl);
        self.isCameraOpen = false;
        self.stopCameraStream();
      }, FLASH_TIMEOUT);
    },
When a user clicks the camera button, then it will take the video streaming dom context and captured the 2d photo with the given width and height. We are using the setTimeout because video streaming will take some time to stream.




Let's implement the self.addToPhotoGallery() used in the above function. This is to preview the captured photo. For this, we are using the "vue-picture-swipe" library. So first let's add this to our application.

For yarn package manager:

yarn add vue-picture-swipe

For npm package manager:

npm install --save vue-picture-swipe

Import the library in our application:

import VuePictureSwipe from 'vue-picture-swipe';
Register the component:

components: {
    VuePictureSwipe
  },
Use in the template:

<vue-picture-swipe :items="items"></vue-picture-swipe>

addToPhotoGallery(dataURI) {
      this.items.push(
          {
            src: dataURI,
            thumbnail: dataURI,
            w: this.canvasWidth,
            h: this.canvasHeight,
            alt: '' // optional alt attribute for thumbnail image
          }
      )
    },
This will preview the captured pictures.

Finally, using self.uploadPhoto() we can upload the captured picture to the server.

uploadPhoto(dataURL){
      let uniquePictureName = this.generateCapturePhotoName();
      let capturedPhotoFile = this.dataURLtoFile(dataURL, uniquePictureName+'.jpg')
      let formData = new FormData()
      formData.append('file', capturedPhotoFile)
      // Upload api
      // axios.post('http://your-url-upload', formData).then(response => {
      //   console.log(response)
      // })
    },
    generateCapturePhotoName(){
      return  Math.random().toString(36).substring(2, 15)
    },
    dataURLtoFile(dataURL, filename) {
      let arr = dataURL.split(','),
          mime = arr[0].match(/:(.*?);/)[1],
          bstr = atob(arr[1]),
          n = bstr.length,
          u8arr = new Uint8Array(n);

      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, {type: mime});
    },




generateCapturePhotoName() will generate the unique name for each captured picture, and to send to the server, first we are converting the dataUrl value to file using dataURLtoFile()

The overall implementation of the component Camera.vue looks like as below:

<template>
    <div class="camera-box">
        <div style="display: flex; justify-content: center;">
            <img style="height: 25px;" v-if="isCameraOpen"
                 src="https://img.icons8.com/material-outlined/50/000000/camera--v2.png"
                 class="button-img camera-shoot" @click="capture"/>
            <div class="camera-button">
                <button type="button" class="button is-rounded cam-button"
                        style="margin-left: 40%; background-color: white; border: 0px;"
                        @click="toggleCamera"
                >
        <span v-if="!isCameraOpen"><img style="height: 25px;" class="button-img"
                                        src="https://img.icons8.com/material-outlined/50/000000/camera--v2.png"></span>
                    <span v-else><img style="height: 25px;" class="button-img"
                                      src="https://img.icons8.com/material-outlined/50/000000/cancel.png"></span>
                </button>
            </div>
        </div>
        <div style="height: 200px">
            <div v-if="isCameraOpen" class="camera-canvas">
                <video ref="camera" :width="canvasWidth" :height="canvasHeight" autoplay></video>
                <canvas v-show="false" id="photoTaken" ref="canvas" :width="canvasWidth" :height="canvasHeight"></canvas>
            </div>
        </div>
        <vue-picture-swipe :items="items"></vue-picture-swipe>
    </div>
</template>

<script>
    import VuePictureSwipe from 'vue-picture-swipe';

    export default {
        name: "Camera",
        components: {
            VuePictureSwipe
        },
        data() {
            return {
                isCameraOpen: false,
                canvasHeight:200,
                canvasWidth:190,
                items: [],
            }
        },
        methods: {
            toggleCamera() {
                if (this.isCameraOpen) {
                    this.isCameraOpen = false;
                    this.stopCameraStream();
                } else {
                    this.isCameraOpen = true;
                    this.startCameraStream();
                }
            },
            startCameraStream() {
                const constraints = (window.constraints = {
                    audio: false,
                    video: true
                });
                navigator.mediaDevices
                    .getUserMedia(constraints)
                    .then(stream => {
                        this.$refs.camera.srcObject = stream;
                    }).catch(error => {
                    alert("Browser doesn't support or there is some errors." + error);
                });
            },

            stopCameraStream() {
                let tracks = this.$refs.camera.srcObject.getTracks();
                tracks.forEach(track => {
                    track.stop();
                });
            },

            capture() {
                const FLASH_TIMEOUT = 50;
                let self = this;
                setTimeout(() => {
                    const context = self.$refs.canvas.getContext('2d');
                    context.drawImage(self.$refs.camera, 0, 0, self.canvasWidth, self.canvasHeight);
                    const dataUrl = self.$refs.canvas.toDataURL("image/jpeg")
                        .replace("image/jpeg", "image/octet-stream");
                    self.addToPhotoGallery(dataUrl);
                    self.uploadPhoto(dataUrl);
                    self.isCameraOpen = false;
                    self.stopCameraStream();
                }, FLASH_TIMEOUT);
            },

            addToPhotoGallery(dataURI) {
                this.items.push(
                    {
                        src: dataURI,
                        thumbnail: dataURI,
                        w: this.canvasWidth,
                        h: this.canvasHeight,
                        alt: 'some numbers on a grey background' // optional alt attribute for thumbnail image
                    }
                )
            },
            uploadPhoto(dataURL){
                let uniquePictureName = this.generateCapturePhotoName();
                let capturedPhotoFile = this.dataURLtoFile(dataURL, uniquePictureName+'.jpg')
                let formData = new FormData()
                formData.append('file', capturedPhotoFile)
                // Upload image api
                // axios.post('http://your-url-upload', formData).then(response => {
                //   console.log(response)
                // })
            },

            generateCapturePhotoName(){
                return  Math.random().toString(36).substring(2, 15)
            },

            dataURLtoFile(dataURL, filename) {
                let arr = dataURL.split(','),
                    mime = arr[0].match(/:(.*?);/)[1],
                    bstr = atob(arr[1]),
                    n = bstr.length,
                    u8arr = new Uint8Array(n);

                while (n--) {
                    u8arr[n] = bstr.charCodeAt(n);
                }
                return new File([u8arr], filename, {type: mime});
            },
        }
    }
</script>

<style scoped>
    .camera-box {
        border: 1px dashed #d6d6d6;
        border-radius: 4px;
        padding: 2px;
        width: 80%;
        min-height: 300px;
    }

</style>



Share:

Monday, December 7, 2020

How to Build the Vuejs Application as a Library and Web Component

In this tutorial, we are going to learn how to create a library and a web component of the Vuejs application, so that we can reuse them as a library in a different application and a custom HTML element in different webpages.

Using VueCli 3.x it's very easy to build our application. It gives some command to create them.

1. Create a sample Vuejs application:

Open the command prompt or terminal and use the following command:

vue create vue-build-target-app
  

You can either select the Default option so that you don't manually setup. This will default use the yarn package manager so, make sure to have package manager installed. Also, you can manually select features option.

Now, go to the project directory and run the application using the command:
cd vue-build-target-app
yarn serve
  
If you open the project, you can see the default component called HelloWorld.vue. We are using the same component to test.

2. Build as a Library:

Note: In lib mode, Vue is externalized. This means the bundle will not bundle Vue even if your code imports Vue

While building as a library even if we are importing the Vue in the component it will not use that in the bundle.

Building a single component as a library:

vue-cli-service build --target lib --name myLib [entry]
  
This is the command that we use where myLib is the name of the output bundle file and [entry] is the entity that we use.

For e.g:

vue-cli-service build --target lib --name HelloWorld src/components/HelloWorld.vue
  
This will build the single component HelloWorld.vue as the library. So, what you need to do is place the above command inside the package.json file under scripts.

"build-lib": "vue-cli-service build --target lib --name HelloWorld src/components/HelloWorld.vue",
  

Now, run the script from the command prompt:

yarn build-lib
  
This command will build the target files inside dis folder.


dist\HelloWorld.umd.js is the UMD bundle that can be served in the normal HTML file. As you can see the sample use case inside the dist folder contain the following demo.html file:

<meta charset="utf-8"></meta>
<title>HelloWorld demo</title>
<script src="https://unpkg.com/vue"></script>
<script src="./HelloWorld.umd.js"></script>

 <link href="./HelloWorld.css" rel="stylesheet"> </link>


<div id="app">
  <demo>  </demo>
</div>

<script>
new Vue({
  components: {
    demo: HelloWorld
  }
}).$mount('#app')
</script>
  
If you run this HTML file then you can see the desire output for that page.

dist\HelloWorld.umd.min.js   is the minified version of the UMD bundle 

dist\HelloWorld.common.js  is used in a module-based application

dist\HelloWorld.css is the CSS file that is associated with that component.

You can use those desired files on your web pages.

3. Build as a Web Component:

You can build a single entry as:

vue-cli-service build --target wc --name my-element [entry]
Here wc will build as a web component. For e.g:

vue-cli-service build --target wc -name HelloWorld src/components/HelloWorld.vue



Use this inside script and run the command:

"build-wc":vue-cli-service build --target wc -name HelloWorld src/components/HelloWorld.vue
Here you can give any name instead of  "build-wc" but you need to run the build command with this name

yarn build-wc
Which will create the following files under the dist folder:

dist\hello-world.js 
dist\hello-world.min.js

This is the web pack bundle that can be used in web pages. Sample example is created under the same folder i.e demo.html.

This doesn't require component registration, as the component is already registered while creating it. So it looks like a normal plain HTML element.

If you want to build the multiple components file then use the following command instead:

//package.json
    "build-wc": "vue-cli-service build --target wc --name demo src/components/*.vue",





Share:

Saturday, December 5, 2020

How to Implement Multiple Image Upload Mechanism in Vue.js Application

In this tutorial, we are going to implement the multiple-image upload using Vue.js.

The overall multiple image upload mechanism looks like below:

1. Create a sample Vuejs application:

Open the command prompt or terminal and create a project.
vue create vue-multiple-image-upload
  
Select the default option or manually select feature of your own and hit enter.


This will create a Vuejs application, Now go to the project folder. 
cd vue-multiple-image-upload
  
Run the application.
yarn serve //for yarn package manager
    npm run serve //for npm package manager
  

2. Implement Multiple Image Upload Mechanism.


Here, we are using vue-upload-multiple-image component dependency. The advantage of using this dependency is
  • Can upload single and multiple images
  • Have drag and drop feature
  • Can preview the uploaded images
  • Can add, edit and delete the uploaded images
  • Can be marked as the default or primary image  
Now, add the dependency in our sample application created.

For yarn package manager:

  yarn add vue-upload-multiple-image
  
For npm package manager:

  npm install vue-upload-multiple-image
  
Open the project in your favorite editor. And open the App.vue file or any file where you want to import it.

  import VueUploadMultipleImage from 'vue-upload-multiple-image'
  
Register the component:

  components: {
    VueUploadMultipleImage,
  },
  
Use the component:

 <vue-upload-multiple-image 
    @upload-success="uploadImageSuccess"
    @edit-image="editImage"
    @mark-is-primary="markIsPrimary"
    @limit-exceeded="limitExceeded"
    @before-remove="beforeRemove"
    id-upload="myIdUpload"
    id-edit="myIdEdit"
    :max-image=20
    primary-text="Default"
    browse-text="Browse picture(s)"
    drag-text="Drag pictures"
    mark-is-primary-text="Set as default"
    popup-text="This image will be displayed as default"
    :multiple=true
    :show-edit=true
    :show-delete=true
    :show-add=true
 >
 </vue-upload-multiple-image>
  
Here, all the events and props are implemented.

@upload-success event will be trigger for each image upload.

@edit-image will be trigger when editing an image i.e trying to replace the particular image

@mark-is-primary will be trigger when if you want to mark any image as a default or primary image.

@limit-exceeded will be trigger when the image upload number exceeds that is defined in max-image         props

@before-remove will be trigger when we try to delete the image 

Now let's implement each event function to handle them. In order to do so, use the following functions inside Vuejs methods.



methods: {
    uploadImageSuccess(formData, index, fileList) {
      console.log('data', formData, index, fileList)
      // Upload image api
      // axios.post('http://your-url-upload', formData).then(response => {
      //   console.log(response)
      // })
    },
    beforeRemove(index, removeCallBack) {
      console.log('index', index)
      var r = confirm("remove image")
      if (r == true) {
        removeCallBack()
      }
    },
    editImage(formData, index, fileList) {
      console.log('edit data', formData, index, fileList)
    },
    markIsPrimary(index, fileList){
      console.log('markIsPrimary data', index, fileList)
    },
    limitExceeded(amount){
      console.log('limitExceeded data', amount)
    }
  },
  
Here, you can handle each event triggered. For e.g for uploadImageSuccess function, we can call the endpoint to upload the images.

Now, run the application and test it.




Share:

Tuesday, December 1, 2020

Example to Test Whether String is Null or Empty in Java

This is the short tutorial to test whether the given string is null or empty.

Let's look at the following example:
public class StringUtil {
    public static void main(String[] args) {
        String nonEmptyString = "non empty string";
        String nullString = null;
        String emptyString = "";
        String emptyStringWithWhiteSpace = " ";
        boolean isNonEmpty = isNullOrEmpty(nonEmptyString);
        System.out.println(isNonEmpty); //false
        boolean isNullString = isNullOrEmpty(nullString);
        System.out.println(isNullString); //true
        boolean isEmptyString = isNullOrEmpty(emptyString);
        System.out.println(isEmptyString); //true
        boolean isEmptyStringWithWhiteSpace = isNullOrEmpty(emptyStringWithWhiteSpace);
        System.out.println(isEmptyStringWithWhiteSpace); //true
    }

    private static boolean isNullOrEmpty(String str) {
        if(str == null || str.trim().isEmpty())
            return true;
        return false;
    }

}
  
Here, we are using different types of string value to test whether it is null or empty. In order to test we are simply creating the isNullOrEmpty(String str) method, which will return true if the string is null or empty and false if it is not. If the first condition is satisfied it will not test the second one because we are using OR logic. So, even if the "str" is null it will not throw an error.


The reason behind using trim() is to remove any leading or trailing white space from the given string. So that isEmpty() method will not consider the empty string with white space as a non-empty string.
Basically, isEmpty() will test the length of the string to return the boolean value. So, if the given string contains white space, even if the string is empty it will return false.
Share:

How to Create List of String to Comma Separated String.

This is a short tutorial to show how to convert the list of strings into the comma-separated string.

1. In Java 8 and later:

- Using String.join() method.
import java.util.Arrays;
import java.util.List;

public class JavaStringJoin {
    public static void main(String[] args) {
        List <String> stringList = Arrays.asList("apple","banana","grapes");
        String joinedString = String.join(",", stringList);
        System.out.println(joinedString);
    }
}
Output:
apple,banana,grapes
This will simply join each element of the list with the delimiter provided. Here, we are providing "," as a delimiter. If the element present in the list is null then it will join the "null" to the string. If the delimiter is null then, it will throw Null Pointer Exception.

- Using stream API:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class JavaStringJoin {
    public static void main(String[] args) {
        List <String> stringList = Arrays.asList("apple","banana","grapes");
        String joinedString = stringList.stream().collect(Collectors.joining(","));
        System.out.println(joinedString);
    }
}
  
- Using StringJoiner:
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;

public class JavaStringJoin {
    public static void main(String[] args) {
        List <String> stringList = Arrays.asList("apple","banana","grapes");
        StringJoiner stringJoiner = new StringJoiner(",");
        for (String element : stringList){
            stringJoiner.add(element);
        }
        System.out.println(stringJoiner.toString());
    }
}
  
Actually, String.join() uses this StringJoiner mechanism.

The output will be the same as the previous example.

2. You can use StringBuilder to build the concatenated string:

import java.util.Arrays;
import java.util.List;

public class JavaStringJoin {
    public static void main(String[] args) {
        List <String> stringList = Arrays.asList("apple","banana","grapes");
        StringBuilder stringBuilder = new StringBuilder();
        int size = stringList.size();
        for (int i = 0; i < size; i++) {
            stringBuilder.append(stringList.get(i));
            if (i < size -1){
                stringBuilder.append(",");
            }
        }
        System.out.println(stringBuilder.toString());
    }
}

3. If you are using Apache's commons library, you can use StringUtils.join() method.

String joinedString = StringUtils.join(stringList, ",")
Share:

Sunday, June 14, 2020

Appium how to do scrolling.

In this post, I will show you how to do scrolling in Appium. Appium provides the TouchAction API for gesture implementation.

1. Create an Appium driver:

First, let's create an Appium driver. The general configuration looks like as below:

import io.appium.java_client.android.AndroidDriver;
import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.net.MalformedURLException;
import java.net.URL;

public class AppiumTest {

    private static AndroidDriver driver;
    private static WebDriverWait wait;

    @Before
    public static void setUp() throws MalformedURLException {
        DesiredCapabilities cap = new DesiredCapabilities();
        cap.setCapability("platformName", "Android");
        cap.setCapability("deviceName", "your device name");
        cap.setCapability("appPackage", "appPackage");
        cap.setCapability("appActivity", "appActivity");
        cap.setCapability("automationName", "UiAutomator1");
        cap.setCapability("autoGrantPermissions", true);
        cap.setCapability("autoAcceptAlerts", "true");
        driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), cap);
        wait = new WebDriverWait(driver,60);
    }
    
    @After
    public static void tearDown(){
        driver.quit();
    }

}
This is a sample config to create an Appium driver which we will use later.





2. Scrolling:

//AppiumTest.java
private static void scroll(int scrollStart, int scrollEnd) {
        new TouchAction(driver)
                .press(point(0, scrollStart))
                .waitAction(WaitOptions.waitOptions(Duration.ofSeconds(10)))
                .moveTo(point(0, scrollEnd))
                .release().perform();
    }
Here, we are dealing with scrolling, so we are adjusting the value for the y-axis. The press() method allows you to press on the position x, y coordinates. You can use some offset value for x coordinate instead of 0 x-offset value. The waitAction() method will wait until the duration provided. The moveTo() method allows moving current touch action to a new position specified. The release() method removes the touch. Next, we will adjust the scrollStart and scrollEnd arguments to move down and up.

3. Scrolling Down:


//AppiumTest.java
public static void scrollDown() {
        MobileElement element = (MobileElement) driver.findElement(By.id("resourceId"));
        if (element == null){
            return;
        }
        int numberOfTimes = 10;
        Dimension dimension = driver.manage().window().getSize();
        int windowsHeight = dimension.getHeight();
        int scrollStart = (int) (windowsHeight * 0.5);
        int scrollEnd = (int) (windowsHeight * 0.3);
        int elementLocationOffset = windowsHeight-500;
        for (int i = 0; i < numberOfTimes; i++) {
            int elementLocationY = element.getLocation().y;
            if (elementLocationY < elementLocationOffset){
                i = numberOfTimes;
                System.out.println("Element available.");
            }else {
                scroll(scrollStart, scrollEnd);
                System.out.println("Element not available. Scrolling...");
            }
        }
    }

In the above scrolling down example, we are trying to scroll down until the element is visible on the screen. Here, we are getting the dimension of the screen window; as we are scrolling so, we use windows height to manipulate the position to scroll.




For e.g, if windows height is 1000 scrollStart will be 500 and scrollEnd will be 300 which means while calling scroll() method it will press to the position (x,y) (0, 500) and move to (x,y)(0, 300) which results in scrolling downward. We are looping so that it will scroll down until the element will arrive to the elementLocationOffset position where the element will be visible on the screen.

For testing element availability, if the above approach doesn't work you can try finding the element as below:

for (int i = 0; i < numberOfTimes; i++) {
            List elements = driver.findElements(By.id("resourceId"));
            if (elements.size() > 0){
                i = numberOfTimes;
                System.out.println("Element available.");
            }else {
                scroll(scrollStart, scrollEnd);
                System.out.println("Element not available. Scrolling...");
            }
        }

4. Scrolling Up:

If you want to scroll Up then you need to adjust the coordinates as below:

 int scrollStart = (int) (windowsHeight * 0.3);
 int scrollEnd = (int) (windowsHeight * 0.7);
 
For e.g: if the window's height is 1000 then scrollStart will be 300 and scrollEnd will be 700 which means while calling scroll() method it will press to the position (x,y) (0, 300) and move to (x,y)(0, 700) which results in scrolling upward. Adjust the value that suits you.

The overall Implementation looks like below:

package appium;

import io.appium.java_client.MobileElement;
import io.appium.java_client.TouchAction;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.touch.WaitOptions;
import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;

import static io.appium.java_client.touch.offset.PointOption.point;


public class AppiumTest {

    private static AndroidDriver driver;
    

    @Before
    public static void setUp() throws MalformedURLException {
        DesiredCapabilities cap = new DesiredCapabilities();
        cap.setCapability("platformName", "Android");
        cap.setCapability("deviceName", "your device");
        cap.setCapability("appPackage", "appPackage");
        cap.setCapability("appActivity", "appActivity");
        cap.setCapability("automationName", "UiAutomator1");
        cap.setCapability("autoGrantPermissions", true);
        cap.setCapability("autoAcceptAlerts", "true");
        driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), cap);
    }


    public static void scrollDown() {
        MobileElement element = (MobileElement) driver.findElement(By.id("resourceId"));
        if (element == null){
            return;
        }
        int numberOfTimes = 10;
        Dimension dimension = driver.manage().window().getSize();
        int windowsHeight = dimension.getHeight();
        int scrollStart = (int) (windowsHeight * 0.5);
        int scrollEnd = (int) (windowsHeight * 0.3);
        int elementLocationOffset = windowsHeight-500;
        for (int i = 0; i < numberOfTimes; i++) {
            int elementLocationY = element.getLocation().y;
            if (elementLocationY < elementLocationOffset){
                i = numberOfTimes;
                System.out.println("Element available.");
            }else {
                scroll(scrollStart, scrollEnd);
                System.out.println("Element not available. Scrolling...");
            }
        }
    }

    private static void scroll(int scrollStart, int scrollEnd) {
        new TouchAction(driver)
                .press(point(0, scrollStart))
                .waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1)))
                .moveTo(point(0, scrollEnd))
                .release().perform();
    }

    @After
    public static void tearDown(){
        driver.quit();
    }

}




Share:

Saturday, June 13, 2020

How to convert the JSON file to Map and List in Java using Gson.

In this post, we are going to convert the JSON file to Map or List. Here, we are using the Gson library which provides a clean way to do so. You can download the Gson jar file from here.


Now, load the jar file from your IDE.

For IntelliJ Idea:

Go to: File >> Project Structure(Ctr + Alt + Shift + s) >> Libraries and click the + icon on the top left corner and select library file that we downloaded. Apply and save. If you are using in an existing project like Gradle or Maven: 

For Gradle:

Inside build.gradle file under dependencies,
compile 'com.google.code.gson:gson:2.8.6'



For Maven:

Inside pom.xml
<dependency>
  <groupid>com.google.code.gson</groupid>
  <artifactid>gson</artifactid>
  <version>2.8.6</version>
</dependency>

Create a Class that converts a JSON file to Map or List.
package jsonToMap;

import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Map;


public class JsonConverter {

    public static void main(String[] args) {
        String baseDir = System.getProperty("user.dir");
        String jsonPath = baseDir+"/src/jsonToMap/resources/sample.json";
        //convert json map to Map
        Map jsonMap = getMapFromJson(jsonPath);
        System.out.println(jsonMap);
       
    }

    private static Map getMapFromJson(String filePath){
        Gson gson = new Gson();
        JsonReader reader = null;
        try {
            reader = new JsonReader(new FileReader(filePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return gson.fromJson(reader, Map.class);
    }

}

Also, the sample.json file contains the JSON map under the directory provided.

//sample.json
{
  "text":"first text",
  "digit":1234,
  "boolean":true
}

In the above example, first, it will read the JSON file using JsonReader and we used Gson to convert to Map.

If you want to convert the file which contains the JSON list to List, you can provide the class to convert as below.
//sample.json
[
  {
    "text":"first text",
    "digit":1234,
    "boolean":true
  },
  {
    "text":"second text",
    "digit":1234,
    "boolean":true
  },
  {
    "text":"third text",
    "digit":1234,
    "boolean":true
  }
]


/JsonConverter.java
private static List getListFromJson(String filePath){
        Gson gson = new Gson();
        JsonReader reader = null;
        try {
            reader = new JsonReader(new FileReader(filePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return gson.fromJson(reader, List.class);
    }
If you want to convert to Custom class, create a class compatible with the fields from the JSON file and provide that class while converting. For e.g:
//sample.json
{
  "text":"first text",
  "digit":1234,
  "aBoolean":true
}


//Sample.java
public class Sample {

    private String text;
    private Double digit;
    private Boolean aBoolean;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Double getDigit() {
        return digit;
    }

    public void setDigit(Double digit) {
        this.digit = digit;
    }

    public Boolean getaBoolean() {
        return aBoolean;
    }

    public void setaBoolean(Boolean aBoolean) {
        this.aBoolean = aBoolean;
    }
}


//JsonConverter.java
private static Sample getSampleFromJson(String filePath){
        Gson gson = new Gson();
        JsonReader reader = null;
        try {
            reader = new JsonReader(new FileReader(filePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return gson.fromJson(reader, Sample.class);
    }
Here, we pass the class Sample while converting from the JSON. Make sure your JSON file and class structure match.



Share:

Sunday, June 7, 2020

Create a Self-Signed free SSL certificate for Tomcat on CentOS Linux using Let's Encrypt.

How to Install and configure a free SSL/TLS certificate for Tomcat using Let's Encrypt on Centos Linux.





In this tutorial, we are going to create and set up a free SSL/TLS certificate on the Linux CentOS server. We are using Let's Encrypt for this which provides the free SSL and is valid for 90 days. You can renew it during that time duration. We will show how to renew it too. You can find about Let's Encrypt from here.

This service is used by many people to secure their website worldwide so, it's totally trust-worthy and supported if you can't afford from other paid service provider.


2. prerequisites:

We consider you already have the following setup.

  1. Running CentOS server
  2. Running tomcat server
  3. Domain pointed to the server Ip address


3. Install Certbort and create an SSL certificate:

First, SSH into to the running CentOS server where you want to create your SSL certificate. To create an SSL certificate, we need to first install Certbort on the server so, let's do it. I recommend selecting the desired version from here, which will give the command to install Certbot.


Install Certbot:
yum -y install yum-utils
     yum-config-manager --enable rhui-REGION-rhel-server-extras rhui-REGION-rhel-server-optional 
     sudo yum install certbot

Create a certificate:

If you have already running service which uses port 80 stop it. To obtain an SSL certificate for your domain using a built-in "standalone" webserver type the following command:
sudo certbot certonly --standalone -d example.com
Here, replace the domain name you want to secure instead of example.com 

which will create the following certificate file to the directory:"/etc/letsencrypt/live/example.com/"
cert.pem, chain.pem, fullchain.pem, privkey.pem.

Now, logged in as root user and go to that directory

sudo -i
cd /etc/letsencrypt/live/example.com/

Next step is to convert those certificate PEM file to password-based PFX format so that we can use in tomcat configuration. We can do this by using the OpenSSL command as below.
openssl pkcs12 -export -out bundle.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem -password pass:password
Replace the password with your desired one. It will create a password-protected file bundle.pfx under the same directory "/etc/letsencrypt/live/example.com/" which we need to use in tomcat configuration.

 



4. Tomcat configuration for HTTPs:

Go to your tomcat directory, and backup the server.xml file; as we are going to change the file.
cp conf/server.xml conf/server-copy.xml
Edit the server.xml file.
sudo vi conf/server.xml  // no need to type sudo if you are logged in as root user
You can see the following commented XML tag, which we are going to change:

For Tomcat 7:


For tomcat 8:



Add the following changes near to the above XML tag or you can simply change that XML tag as below.



Here, we are changing port 8443 to 443, keystoreType as "PKCS12", keystoreFile as the path of the pfx file created previously and keystorePass as your password that we used while creating PFX file. 

Change the port 8080 to 80:

Under server.xml you can find the following tag.



change the above XML tag as below:



Here, we are changing the port from 8080 to 80 and 8443 to 443. By doing so, if your domain running with port 8080 i.e example.com:8080, now it will open with port 80 i.e example.com. If you type your domain in the browser then you can run it with both HTTP and https i.e http://example.com and https://example.com.

Save the server.xml file by clicking "Esc" key and type ":wq!" and hit Enter.

As we want to always redirect our domain to https. To do so, open the web.xml file under conf/web.xml.

 
sudo vi conf/web.xml
Click "Shift + G" to go the end of the file and add the below code at the end of the file as below.
<security-constraint>
  <web-resource-collection>
  <web-resource-name>Entire Application</web-resource-name>
   <url-pattern>/*</url-pattern>
 </web-resource-collection>
  <!--auth-constraint goes here if you requre authentication-->
 <user-data-constraint>
 <transport-guarantee>CONFIDENTIAL</transport-guarantee>
 </user-data-constraint>
 </security-constraint>
 


Save the file. This will always redirect to HTTPs.

 
5. Renew certificate:

The certificate is valid for only 90 days so we need to renew before expiry. For this, stop tomcat and type the following command:
sudo certbot renew
sudo -i
cd /etc/letsencrypt/live/example.com/
openssl pkcs12 -export -out bundle.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem -password pass:password
Don't forget to use your existing password. And restart the tomcat server.



Share:

Friday, June 5, 2020

IntelliJ Idea doesn't detect existing Java project.

What to do if your IntelliJ Idea doesn't detect your existing project. Sometimes it may be due to it doesn't find the JDK on you configure path. If you have such a problem reconfigure the JDK.
 
For this, go to: File >> Project Structures(Ctr + Alt + Shift + s) >> Project




Click New >> JDK and provide the path and select JDK. Sometimes it may be due to other versions of JDK setup, in that case, click and select the desired version of java from dropdown menu. Then click apply and ok. That may solve the issue with java not detecting.

Sometimes, although Java is detected we are not able to use the feature of Intellij idea like, run and debug classes, step in step out from class by ctr + click on method or class, find the usage of class and method by click on it. In this case, simply close the project and import it again. For this,

Go to: File >> Close Project >> Import Project




Select your desired project, and select "create from existing source", select the desired library and java version and finish the setup. This will resolve the issues 


Share: