JPA - Hello, World! using Hibernate 5

The article JPA - Hello, World! using Hibernate explains how to use Hibernate v4.x. This tutorial introduces using JPA with the latest Hibernate v5.2.3. Same as the previous article, it also targets beginners who are new to Hibernate and JPA.

You need Java 1.8, Eclipse for Java EE developers and MySQL server in your system in-order to try this tutorial.

Step 1:
Create a database “javahelps” and a table “student” in MySQL.
CREATE DATABASE IF NOT EXISTS javahelps;

CREATE  TABLE javahelps.student ( 
student_id INT NOT NULL ,
student_name VARCHAR(45) NOT NULL ,
student_age INT NOT NULL ,
PRIMARY KEY (student_id) );

Read More

WSO2 CEP - Output Mapping Using Registry Resource

Publishing the output is an important requirement of CEP. WSO2 CEP allows to convert an event to TEXT, XML or JSON, which is known as output mapping . This article explains how a registry resource can be used for custom event mapping in WSO2  CEP 4.2.0.


Step 1:
Start the WSO2 CEP and login to the management console.

Step 2:
Navigate to Home → Manage → Events → Streams → Add Event Stream.

Step 3:
Define an event stream as given below and click on ‘Add Event Stream’ button.
Name: sensorstream
Version: 1.0.0
Meta Data Attributes: sensorId, sensorName and language
Correlation Data Attributes: longitude and latitude
Payload Data Attributes: sensorValue


Step 4:
Navigate to Home → Registry → Browse.

Step 5:
Expand the /_system/config tree view and click on the config folder.

Step 6:
Click on the Add Collection link and add a new collection named template.


Step 7:
Same as Step 6, create another sub folder en inside the template folder.

Step 8:
Click on the ‘Add Resource’ button and select ‘Create Text Content’ as the method. This means that we are going to provide a content that is readable for human.
Provide the name as message and leave the Media type as text/plain. Suppose you want to create an XML or JSON resource, change the media type to application/xml or application/json respectively.

Step 9:
Add the content that matches your media type and click the Add button.


The message used in this screenshot is given below:
Welcome
Sensor {{meta_sensorName}} reports {{sensorValue}} from {{correlation_longitude}}:{{correlation_latitude}}

Step 10:
Navigate to the Home → Manage → Event → Publishers and click on the Add Event Publisher button.

Step 11:
Provide samplelogger as the publisher name, sensorstream:1.0.0 as the event source, logger as the output event adapter type and text as the message format. If your registry resource is XML or JSON, change the message format to your media type.

Then expand the Advanced configuration and select ‘Pick from registry’.
Click on the ‘Configuration Registry’ button, browse and select the message resource.


Leave the Cache Timeout with the default value.

Compare your configuration with the following screenshot.


Finally click the Add button.

Step 12:
Now move to the  Home → Tools → Event Simulator and select the sensorstream:1.0.0 as the events stream name.
Fill the form as shown below and click the send button.
sensorId: 10
sensorName: Temperature
language: en
longitude: 79.861256
latitude: 6.927131
sensorValue: 23.0


Once you clicked the Send button, you should get the following output in the terminal of CEP.



Parametrized Registry Path
WSO2 CEP allows you to parameterize the registry path as well. For example, assume that we want to select a registry resource depending on the meta_language. For this purpose, we need another registry resource.

As you did in Step 4 – 9, cerate a new folder named fr in /_system/config/template and a resource named message in /_system/config/template/fr folder.


The message used in this screenshot is given below:
Bienvenue
Sensor {{meta_sensorName}} reports {{sensorValue}} from {{correlation_longitude}}:{{correlation_latitude}}

Now the registry should contain both en/message and fr/message.


Step 13:
Delete the existing samplelogger publisher and create a new one using the same name as shown in Step 11. But this time, provide the following path as the registry path.
conf:/template/{{meta_language}}/message
Compare this path with the path in Step 11. Instead of hard coding the language folder name en or fr, the attribute meta_language is used. At the runtime, the meta_language will be replaced by the actual language name and the resource at that path will be used by the publisher.


Step 14:
Repeat the Step 12 with languages en, fr and something other than English and French.
In the terminal, CEP will print the message in English and French according to the input and thrown an exception if the resource for the given language does not exists.


If the registry does not contain a resource at the run time evaluated path, an exception will be thrown.

For more details about output mapping, visit to the official document: Output Mapping Types
Read More

Never Duplicate A Window Again - WSO2 Siddhi Event Window

A new feature known as Event Window is introduced in WSO2 Siddhi 3.1.1 version, which is quite similar to the named window of Esper CEP in some aspects. This article presents the application and the architecture of Event Window using a simple example. According to Siddhi version 3.1.0, a window can be defined on a stream inside a query and the output can be used in the same query itself. For example, consider a scenario where WSO2 CEP is used to analyze the sensor reading of a smart home which has multiple sensors in number of rooms. All the sensors are sending their reading to an input stream named SensorStream and there are different analytics components interested in various statistic information.

If there are two analytic components named A and B which are interested in the maximum reading of each sensors in every room in last 5 seconds and the average sensor reading of each type of sensors in the smart home in last 5 seconds respectively, it can be achieved using a query provided below.
define stream SensorStream (name string, value float, roomNo int, deviceID string);

@info(name = 'query0')
from SensorStream#window.timeBatch(1 second)
select name, max(value) as maxValue, roomNo
group by name, roomNo
insert into MaxSensorReadingPerRoomStream;

@info(name = 'query1')
from SensorStream#window.timeBatch(1 second)
select name, max(value) as maxValue, roomNo
group by name, roomNo
insert into AverageSensorReadingPerBuildingStream;
In this definition, the events arrived in last second will be stored in two windows which are identical  to each other. The output is determined only by the selection and grouping. If the time interval is large enough, with thousands of sensors used in a smart house, several megabytes of memory will be wasted by the duplicate events. Also the window defined in a query cannot be reused for any other purpose even inside the same query. To overcome these problems, Event Window is introduced as a global window which can be accessed from any queries any number of times.

The Siddhi queries and the architecture discussed in this article are presented according to the Siddhi version 3.1.1.

Read More

Deploy and Upgrade Android Database From External Directory

After seeing the huge response for the Import and Use External Database in Android article, I have realized the importance of deploying Android database from external sources. The library used in the above article allows you to import database only from the assets directory. However, recently one of my readers, asked for a way to import and upgrade the database from SD card. As a solution for his use case, I have developed a new library named "externalsqliteimporter" which allows you to import database either from assets directory or from SD card. This article explains the application of this Android library using a sample application.


The ExternalSQLiteImporter library allows you to build your SQLite database on your desktop computer, and to import and use it in your Android application. This library has two separate ways to maintain your database.

This library is still under development. Deploying and upgrading  the database from an external directory is not secure as it is publicly available for third party applications as well. Use that feature with caution. 

Read More

Complex Event Processing - An Introduction

Today almost all the big brothers in the software industry are behind big data and data analytics. Not only the large companies, even small scale companies need data processing in order to track and lead their business. Complex Event Processing(CEP) is one of the techniques being used to analyse streams of events for interested events or patterns. This article explains the big picture of complex event processing in a nutshell using a simple example.


As the name suggests Complex Event Processing is mainly about processing events using some predefined rules. Mainly they are used to derive complex events by aggrgating and processing stream of simple events. For example, identifying that you are reading this blog right now is an easy task for your computer since the browser knows the site which is currently being opened on your computer. However, some events cannot be detected as simple as the above example. For example, how could a supermarket send coupons closed to a teen girl’s delivery date while even her father didn’t know that she was pregnant? (Read the incredible story here: ‘How Target Figured Out A Teen Girl Was Pregnant Before Her Father Did’).

Let’s say our problem is identifying the pregnant customers of a supermarket so that the supermarket can send  coupons for baby clothes and cribs. Assume that according to experts report, if a customer bought cocoa-butter lotion, a purse large enough to double as a diaper bag and ZMA supplements within 7 days, the customer is pregnant (or he/she has a pregnant relation). Using this domain knowledge, we can define the rule to identify the pregnant customers. However, in a supermarket with thousands of customers per day, it is hard to search for such patterns manually using a rule.

Complex Event Processor is a tool to process stream of events automatically as they arrive. Compared to database management systems, database engines store the data and pass the query to process on those data. In contrast, CEPs store the query and pass the data against it and extract the necessary information. There are several CEPs available and this article uses WSO2 CEP which is an open source Java based complex event processor.

WSO2 CEP is recommended to be used as a cluster of nodes for an enterprise level requirement. However, in this article, we use the core of WSO2 CEP known as Siddhi which can be used as a Java library.

Step 1:
Create a new Maven project in Eclipse using the following information.
Group Id: com.javahelps
Artifact Id: siddhidemo

Step 2:
Open the pom.xml and add the following repository. This repository is required to download the latest Siddhi library.
<repositories>
    <repository>
        <id>wso2.releases</id>
        <name>WSO2 internal Repository</name>
        <url>http://maven.wso2.org/nexus/content/repositories/releases/</url>
        <releases>
            <enabled>true</enabled>
            <updatePolicy>daily</updatePolicy>
            <checksumPolicy>ignore</checksumPolicy>
        </releases>
    </repository>
</repositories>

Step 3:
Add the following dependencies. (Java version is optional)
<properties>
    <siddhi.version>3.1.0</siddhi.version>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
</properties>

<dependencies>
    <!--Siddhi -->
    <dependency>
        <groupId>org.wso2.siddhi</groupId>
        <artifactId>siddhi-query-api</artifactId>
        <version>${siddhi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.wso2.siddhi</groupId>
        <artifactId>siddhi-core</artifactId>
        <version>${siddhi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.wso2.siddhi</groupId>
        <artifactId>siddhi-query-compiler</artifactId>
        <version>${siddhi.version}</version>
    </dependency>
</dependencies>

After modification, the pom.xml must look like this:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.javahelps</groupId>
    <artifactId>siddhidemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <repositories>
        <repository>
            <id>wso2.releases</id>
            <name>WSO2 internal Repository</name>
            <url>http://maven.wso2.org/nexus/content/repositories/releases/</url>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
                <checksumPolicy>ignore</checksumPolicy>
            </releases>
        </repository>
    </repositories>

    <properties>
        <siddhi.version>3.1.0</siddhi.version>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <!--Siddhi -->
        <dependency>
            <groupId>org.wso2.siddhi</groupId>
            <artifactId>siddhi-query-api</artifactId>
            <version>${siddhi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.siddhi</groupId>
            <artifactId>siddhi-core</artifactId>
            <version>${siddhi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.siddhi</groupId>
            <artifactId>siddhi-query-compiler</artifactId>
            <version>${siddhi.version}</version>
        </dependency>
    </dependencies>
</project>

Step 4:
Create a new package com.javahelps.siddhidemo in src/main/java folder.

Step 5:
Create a new class named Main.java with the main method.

Step 6:
Create a SiddhiManager instance which is used to create an execution plan.
package com.javahelps.siddhidemo;

import org.wso2.siddhi.core.SiddhiManager;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        SiddhiManager siddhiManager = new SiddhiManager();
    }
}

Step 7:
Define a stream as shown below. Here stream is used to define the properties of the input event.
package com.javahelps.siddhidemo;

import org.wso2.siddhi.core.SiddhiManager;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        SiddhiManager siddhiManager = new SiddhiManager();

        String streams = "define stream purchaseStream (customerName string, item string, timestamp long); ";
    }
}
The above definition says, all the events passed to the purchaseStream have the properties customerName and item which are String and timestamp of purchase in long.

Step 8:
The most important step is creating the query.
Here is my logic:
  1. Get all the streams and partition them based on the customer name because there can be more customers and we need to process their data individually.
  2. From every partitions, filter the purchases of interested items.
  3. Again break the events into subsets where each set contains only purchases happened in 7 days interval. For example, if Alice purchased Cocoa-Butter Lotion on Monday, Biscuit on Saturday and Beer on next Tuesday, the  Cocoa-Butter Lotion and Biscuit purchases must be in one subset and Beer must be in another subset.
  4. From each subset of events, take the count of unique items. Count of unique items can range from 1 to 3 since we have already filtered the stream to allow purchases of three items only.
  5. Those who have purchased all three products are pregnant with 100% confidence. Those who have  bought only 2 items are pregnant with 66.67% confidence. Those who have purchased only one product are pregnant with 33.33% confidence.
The Siddhi query for above logic is given below:
partition with (customerName of purchaseStream)
begin
    from purchaseStream[item == 'Cocoa-Butter Lotion' OR item == 'Purse-XL' OR item == 'ZMA']#window.uniqueExternalTimeBatch(item, timestamp, 500 milliseconds)
    select customerName, convert(count(item), 'double') / 3.0 * 100.0 as noOfPurchases insert into possiblePregnant;
end;

1. The input stream is partitioned by customerName.

2. The partitioned stream is filtered to allow only Cocoa-Butter Lotion, Purse-XL and ZMA.

3. Siddhi offers uniqueExternalTimeBatch which can be used to get unique time framed subset of events. The interval of 500 milliseconds is used instead of 7 days for quick response.

4. Select the customerName and count of items from each subset and insert the possible pregnant customers with the level of confidence into the output stream.

Step 9:
Add the stream definition and the query to the Siddhi manager and create the ExecutionPlanRuntime.
package com.javahelps.siddhidemo;

import org.wso2.siddhi.core.ExecutionPlanRuntime;
import org.wso2.siddhi.core.SiddhiManager;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        SiddhiManager siddhiManager = new SiddhiManager();

        String streams = "define stream purchaseStream (customerName string, item string, timestamp long); ";
        String query = "partition with (customerName of purchaseStream) " +
                        "begin " +
                        "from purchaseStream[item == 'Cocoa-Butter Lotion' OR item == 'Purse-XL' OR item == 'ZMA']#window.uniqueExternalTimeBatch(item, timestamp, 500 milliseconds) " +
                        "select customerName, convert(count(item), 'double') / 3.0 * 100.0 as noOfPurchases insert into possiblePregnant; " +
                        "end ";

        // Create ExecutionPlanRuntime using stream definition and query
        ExecutionPlanRuntime executionPlanRuntime = siddhiManager.createExecutionPlanRuntime(streams + query);
    }
}

Step 10:
Create two static arrays one for Customers and the other for Products and a static Random class and add a new method to generate input events.
package com.javahelps.siddhidemo;

import java.util.Random;

import org.wso2.siddhi.core.ExecutionPlanRuntime;
import org.wso2.siddhi.core.SiddhiManager;

public class Main {
    private static final String[] CUSTOMERS = { "Alice", "Barby", "Carol", "Diana" };
    private static final String[] ITEMS = { "Cocoa-Butter Lotion", "Purse-XL", "Purse-L", "Beer", "Biscuit",
            "Chocolate", "ZMA" };
    private static final Random RANDOM = new Random();

    public static void main(String[] args) throws InterruptedException {
        SiddhiManager siddhiManager = new SiddhiManager();

        String streams = "define stream purchaseStream (customerName string, item string, timestamp long); ";
        String query = "partition with (customerName of purchaseStream) " +
                        "begin " +
                        "from purchaseStream[item == 'Cocoa-Butter Lotion' OR item == 'Purse-XL' OR item == 'ZMA']#window.uniqueExternalTimeBatch(item, timestamp, 500 milliseconds) " +
                        "select customerName, convert(count(item), 'double') / 3.0 * 100.0 as noOfPurchases insert into possiblePregnant; " +
                        "end ";

        // Create ExecutionPlanRuntime using stream definition and query
        ExecutionPlanRuntime executionPlanRuntime = siddhiManager.createExecutionPlanRuntime(streams + query);
    }

    private static Object[] generateEvent() {
        String name = CUSTOMERS[RANDOM.nextInt(CUSTOMERS.length)];
        String item = ITEMS[RANDOM.nextInt(ITEMS.length)];
        long time = System.currentTimeMillis(); // Current time

        System.out.println(name + " buys " + item);
        Object[] event = new Object[] { name, item, time };
        return event;
    }
}

Step 11:
Add StreamCallback to receive the output events and InputHandler to send events.
package com.javahelps.siddhidemo;

import java.util.Random;

import org.wso2.siddhi.core.ExecutionPlanRuntime;
import org.wso2.siddhi.core.SiddhiManager;
import org.wso2.siddhi.core.event.Event;
import org.wso2.siddhi.core.stream.input.InputHandler;
import org.wso2.siddhi.core.stream.output.StreamCallback;

public class Main {
    private static final String[] CUSTOMERS = { "Alice", "Barby", "Carol", "Diana" };
    private static final String[] ITEMS = { "Cocoa-Butter Lotion", "Purse-XL", "Purse-L", "Beer", "Biscuit",
            "Chocolate", "ZMA" };
    private static final Random RANDOM = new Random();

    public static void main(String[] args) throws InterruptedException {
        SiddhiManager siddhiManager = new SiddhiManager();

        String streams = "define stream purchaseStream (customerName string, item string, timestamp long); ";
        String query = "partition with (customerName of purchaseStream) " +
                        "begin " +
                        "from purchaseStream[item == 'Cocoa-Butter Lotion' OR item == 'Purse-XL' OR item == 'ZMA']#window.uniqueExternalTimeBatch(item, timestamp, 500 milliseconds) " +
                        "select customerName, convert(count(item), 'double') / 3.0 * 100.0 as noOfPurchases insert into possiblePregnant; " +
                        "end ";

        // Create ExecutionPlanRuntime using stream definition and query
        ExecutionPlanRuntime executionPlanRuntime = siddhiManager.createExecutionPlanRuntime(streams + query);
       
        try {
            // Receive the output events
            executionPlanRuntime.addCallback("possiblePregnant", new StreamCallback() {
                @Override
                public void receive(Event[] events) {
                    String output = String.format("\t\t\t%s is pregnant with %.2f%% confidence.", events[0].getData(0),
                            events[0].getData(1));
                    System.out.println(output);
                }
            });

            // Send input events
            InputHandler purchaseStream = executionPlanRuntime.getInputHandler("purchaseStream");
            executionPlanRuntime.start();
            for (int i = 0; i < 1000; i++) {
                Object[] event = generateEvent();
                purchaseStream.send(event);
                Thread.sleep(10); // Delay for 10 milliseconds
            }
        } finally {
            executionPlanRuntime.shutdown();
        }
    }

    private static Object[] generateEvent() {
        String name = CUSTOMERS[RANDOM.nextInt(CUSTOMERS.length)];
        String item = ITEMS[RANDOM.nextInt(ITEMS.length)];
        long time = System.currentTimeMillis(); // Current time

        System.out.println(name + " buys " + item);
        Object[] event = new Object[] { name, item, time };
        return event;
    }

}

Step 12:
Save all the changes and run the application.

The above query is a sample implementation for the given scenario. There can be other ways to achieve the same output using CEP. For more details about Siddhi, visit to the following link: Siddhi Documentation. This example is a simple application of CEP to process stream of events, however CEP can be used in complex scenarios like weather prediction, the stock market trends, fraud detection in bank transaction, etc as well. If you have any questions or suggestions, please comment below.

Find the project @ Git Hub.
Read More

WSO2 Carbon UI Component - Hello World!

In this article, I will show you how to create a WSO2 Carbon UI front end for an existing web service. Since this is the part II of the last article “WSO2 Carbon Server Component - Hello World!”, the UI will be created for the web service developed in part I. However, the same steps can be followed to create a Carbon UI for any SOAP web services.

Prerequisite:

Read More

Goodbye Log4j

After seeing so many students in last four years, I have decided to write this article about the new loggers which are widely being used by the industry. Almost all the university students I have seen are familiar with Log4j 1.x (at least heard about it) but most of them even did not hear about SLF4J and Logback. The purpose of this article is introducing SLF4J and Logback and convincing you towards them. Before getting into the topic, be informed that Log4j 1.x is not being maintained after August 5, 2015 and Ceki Gülcü the developer of Log4j came up with the new tools SLF4J and Logback. Technically, Logback is an enhanced successor of Log4j and performs better than Log4j.

He did a good job, but we have to move forward.
Read More

Apache Axis2 - Hello World! using Eclipse

The previous article Apache Axis2 - Hello World! provides step by step guide to develop a very basic Axis2 Hello World application without using any IDEs. This article helps you to create a simple application in Axis2 using Eclipse IDE.

Prerequisite:
  • Eclipse IDE for Java EE Developers (Follow this link to install Eclipse)
  • Apache Tomcat (Follow this link to install and integrate with Eclipse)
  • Apache Axis2 (Follow this link to install and integrate with Eclipse)

Step 1:
Create a new Dynamic Web Project named HelloAxis2 and change the Dynamic web module version to 2.5 because the current version of Axis2 core does not support versions higher than 2.5.


Read More
Apache Axis2 - Hello World!

Apache Axis2 - Hello World!

Apache Axis2 is a SOAP processing engine and its main function is to deliver incoming SOAP messages into target applications, and in this context application is a Web service. This tutorial provides step by step guidance on how to create your first Hello World application.

Prerequisite:
  • Java Development Kit (Follow this link to install on Ubuntu)
  • Apache Axis2 (Follow this link to setup on Ubuntu)

Step 1:
Create a new class HelloService as shown below.
public class HelloService {

    /**
    * This method will be the add operation of the web service.
    */
    public int add(int x, int y) {
        int ans = x + y;
        return ans;
    }

}


Read More

Setup Apache Axis2 on Ubuntu

This tutorial helps you to setup Apache Axis2 on Ubuntu and to add it to Eclipse IDE for Java EE Developers.

Step 1:
Download the latest version of Apache Axis2 from this link.

Step 2:
Open the Terminal (Ctrl + Alt + T) and enter the following command to change the directory.
cd /opt/

Step 3:
Enter the command given below to extract the Axis2 from  the ~/Downloads directory. If your downloaded file is in any other directory and replace the last parameter by the actual file path.
sudo unzip ~/Downloads/axis2-1.7.1-bin.zip -d .

Step 4:
Rename the folder name to axis2.
sudo mv axis2-1.7.1/ axis2/

Step 5:
To deploy web services, you may need to add some files inside this folder. Therefore it is required to change the permission of this directory. Enter the following command to change the permission of axis2 folder.
sudo chmod -R 777 axis2/

Step 6:
Environment variables AXIS2_HOME and PATH have to be added to the system. Enter the following command in the terminal to open the /etc/environment.
sudo gedit /etc/environment

Step 7:
Add the following line at the end of the file.
AXIS2_HOME="/opt/axis2"

Add the /opt/axis2/bin to the PATH.

The /etc/environment before the modification.

The /etc/environment after the modification.

Step 8:
Reload the environment variables to the current terminal using this command.
source /etc/environment

Step 9:
Enter the following command to start the Axis2 server.
axis2server.sh

Step 10:
Visit to the following URL.
http://localhost:8080/axis2/services/
If you get the Deployed services page, you have successfully setup the Apache Axis2 in your system.

Step 11:
To stop the Axis2, press Ctrl + C in the terminal which is currently running the axis2server.

Integrate Axis2 with Eclipse
If you do not have Eclipse IDE for Java EE Developers, follow this link and install the Eclipse.

Step 1:
Open the Eclipse.

Step 2:
Goto Windows → Preferences in the menu bar and select the Axis2 Preferences under the Web Services.


Step 3:
Click on the 'Browse' button and select the Axis2 home directory.


Step 4:
Click ‘Apply’ and ‘OK’

Now you are ready to use Apache Axis2 from Eclipse.
Read More

Import Database with Images in Android

The article Import and Use External Database in Android explains, how to distribute an Android application along with the data stored in SQLite database. This tutorial explains, how to store images in such a database and pack it in your application. In other words, we are going to create a database with images from our desktop computer and import it into an Android application.

Step 1:
Create a database "images.db" using your favorite SQLite database application (I use Sqliteman because it allows inserting images into the database. You can use any software or script to insert the images into the database). Create a table 'places' with a two columns 'name' and 'image'. Here the data type of 'name' is TEXT and data type of 'image' is BLOB. Insert the name and image of  some places into the database. In this example, I have inserted the names of the seven wonders of the world along with a compressed (Using TinyPng) picture of them. To download the images used in this project, Click Here.


Read More

Contact Form

Name

Email *

Message *