Friday, April 13, 2012

Starting with JPA with JBoss and MySQL

Environment

  • JBoss 7.1.1

  • MySQL 5.5


Note: Make sure the datasource is configured properly. Visit the post (http://vkslabs.com/adding-mysql-data-store-to-jboss-7-x/) to find out how to configure datasource.

Step 1: Configure persistence.xml

Create a file called persistence.xml and add the following content

[xml]
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="testjpa" transaction-type="RESOURCE_LOCAL">
<jta-data-source>java:jboss/datasources/myDS</jta-data-source>
<class>com.test.StudentBean</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
</properties>
</persistence-unit>
</persistence>
[/xml]

Make sure the datasource name matches the datasource configured in JBoss

Step 2: Create your bean

Create the bean which you would like to persist

[java]
package com.test;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity (name="student")
public class StudentBean {
@Id
@GeneratedValue
private int id;
private String name;
private int age;

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
[/java]

  • @Entity annotations should be mentioned to denote the bean is a entity bean

  • @Id annotation makes the field as primary key of the table

  • @GeneratedValue annotation makes the field value as auto generated


Step 3: Persist your bean using EMF

[java]
EntityManagerFactory entityManagerFactory =  Persistence.createEntityManagerFactory("testjpa");
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction userTransaction = em.getTransaction();

userTransaction.begin();
StudentBean student = new StudentBean();
student.setName(name);
student.setAge(age);
em.persist(student);
em.flush();
userTransaction.commit();
em.close();
entityManagerFactory.close();
[/java]

  1. testjpa is the name of persistence-unit in the persistence.xml

  2. Calling persist() just marks the bean for persistence and might not populate DB immediately, in order to see the data in database immediately flush() must be called.


Note:

  • The value for the property hibernate.hbm2ddl.auto can be


                        validate: validate the schema, makes no changes to the database.
                        update: update the schema.
                        create: creates the schema, destroying previous data.
                        create-drop: drop the schema at the end of the session.

  •    In case there is no exception when bean is persisted but no row is found in DB then make sure the value for the property hibernate.hbm2ddl.auto is not set to create-drop



  • Important:  The common mistake the developers make is to create the file in the META-INF folder under the project folder which is wrong.


The META-INF folder where persistence.xml is present should be in classpath but for JPA the root of the persistence unit is the WEB-INF/classes directory hence the persistence.xml should be copied in to WEB-INF/classes/META-INF folder (You might have to create META-INF folder manually).

If the persistence.xml is not created in the right folder the following error will be encountered
javax.persistence.PersistenceException: No Persistence provider for EntityManager named testjpa:       No META-INF/persistence.xml was found in classpath.

Wrong location for persistence.xml




  • In case you face the following exception make sure the persistence.xml has the  attribute transaction-type="RESOURCE_LOCAL"


ERROR [stderr] (http-localhost-127.0.0.1-8080-1) java.lang.NullPointerException
ERROR [stderr] (http-localhost-127.0.0.1-8080-1)     at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.getStatus(JtaStatusHelper.java:73)
ERROR [stderr] (http-localhost-127.0.0.1-8080-1)     at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.isActive(JtaStatusHelper.java:115)
ERROR [stderr] (http-localhost-127.0.0.1-8080-1)     at org.hibernate.engine.transaction.internal.jta.CMTTransaction.join(CMTTransaction.java:149)
ERROR [stderr] (http-localhost-127.0.0.1-8080-1)     at org.hibernate.ejb.AbstractEntityManagerImpl.joinTransaction(AbstractEntityManagerImpl.java:1207)
ERROR [stderr] (http-localhost-127.0.0.1-8080-1)     at org.hibernate.ejb.AbstractEntityManagerImpl.postInit(AbstractEntityManagerImpl.java:176)
ERROR [stderr] (http-localhost-127.0.0.1-8080-1)     at org.hibernate.ejb.EntityManagerImpl.<init>(EntityManagerImpl.java:89)
ERROR [stderr] (http-localhost-127.0.0.1-8080-1)     at org.hibernate.ejb.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:125)
ERROR [stderr] (http-localhost-127.0.0.1-8080-1)     at org.hibernate.ejb.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:120)

Thursday, April 12, 2012

Adding MySQL data source to JBoss 7.X

Today I spent almost 4-5 hours figuring how to configure MySQL for JBoss. Since I am new to JEE world it was a real struggle for me. So hopefully this post will help newbies like me...

  1. Download and extract  JBoss v7.1.1 (Download URL : http://www.jboss.org/jbossas/downloads/)

  2. Download and install MySQL (Download URL : http://dev.mysql.com/downloads/)

  3. Download MySQL JDBC driver (Download URL: http://dev.mysql.com/downloads/connector/j/)


Step 1 - Copy JDBC driver to JBoss folder

  • Extract the downloaded JDBC Driver (mysql-connector-java-5.1.19.zip) which contains source, readme files along with the driver JAR file (mysql-connector-java-5.1.19-bin.jar). For now we will be using only this JAR file.

  • Go to the folder JBOSS_HOME\modules\com and create a folder called mysql and inside mysql create another folder called main.


                 Note: JBOSS_HOME is your JBoss root folder in my case it is d:\D:\jboss-as-7.1.1.Final

  • Copy the driver JAR file (mysql-connector-java-5.1.19-bin.jar) in to this folder (D:\jboss-as-7.1.1.Final\modules\com\mysql\main)

  • Create a XML file called module.xml with the following content


[xml]
<module xmlns="urn:jboss:module:1.1" name="<strong>com.mysql</strong>"><resources>
<resource-root path="mysql-connector-java-5.1.19-bin.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
<module name="javax.servlet.api" optional="true"/>
</dependencies>
</module>

[/xml]

Note: Make sure the module name in XML (marked in bold) follows the directory structure you have created else this won't work.

Step 2 - Configure MySQL Driver

  • Go to the folder JBOSS_HOME\standalone\configuration and open the standalone.xml

  • Search for the text h2 until you find the datasources configuration which will look like


[xml]
<datasources>
<datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<drivers>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
[/xml]

  • Add MySQL Driver details to the drivers tag


[xml]
<driver name="mysql" module="<strong>com.mysql</strong>">
<xa-datasource-class>com.mysql.jdbc.Driver</xa-datasource-class>
</driver>
[/xml]
Note: the module name (marked in bold) should match the module name specified in the module.xml in Step 1.

Step 3 - Configure MySQL DataSource

Add the MySQL Data Store to the datasources tag
[xml]
<datasource jndi-name="java:jboss/datasources/myds" pool-name="myds" enabled="true" use-java-context="true">
<connection-url>jdbc:mysql://localhost:3306/mydb</connection-url>
<driver><strong>mysql</strong></driver>
<security>
<user-name>root</user-name>
<password>mypassword</password>
</security>
</datasource>
[/xml]
Note: the driver name (marked in bold) should be the same as the driver name specified in Step 2.

The final XML data source tag should look like
[xml]
<subsystem xmlns="urn:jboss:domain:datasources:1.0">
<datasources>
<datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<datasource jndi-name="java:jboss/datasources/myds" pool-name="myds" enabled="true" use-java-context="true">
<connection-url>jdbc:mysql://localhost:3306/mydb</connection-url>
<driver>mysql</driver>
<security>
<user-name>root</user-name>
<password>mypassword</password>
</security>
</datasource>
<drivers>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
<driver name="mysql" module="com.mysql">
<xa-datasource-class>com.mysql.jdbc.Driver</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
[/xml]
Note: Alternatively you can configure your datasource using the admin console by going to http://localhost:9990 and adding the datasource details (http://localhost:9990/console/App.html#datasources)

Wednesday, April 4, 2012

Android Marketplace APIs

Google known for releasing API for every service it offers has still not opened up their marketplace for the developers. There is no official API to access the marketplace and execute a search. But I came across this interesting project that uses the protobuf (The protocol that Google uses for almost all structured data communication).

http://code.google.com/p/android-market-api/

This is a Java implementation of the unofficial marketplace APIs and the site also has links to projects on other languages such as Ruby and PHP. Since this is an unofficial API there are many glitches for instance you cannot search beyond the 500th app details if your search query returns more than 500 results.

Searching by keyword

[java]
String query = "india";

AppsRequest appsRequest = AppsRequest.newBuilder()
.setQuery(query)
.setStartIndex(0).setEntriesCount(10)
.setWithExtendedInfo(true)
.build();

session.append(appsRequest, new Callback<AppsResponse>() {
public void onResult(ResponseContext context, AppsResponse response) {
//Process the response here
List<App> list =     appsResponse.getAppList();
int count = appsResponse.getAppCount();
for (int i = 0; i< count; i++)
{
App app = list.get(i);
System.out.println(" App Title is ::  "+app.getTitle() +"  App  Price:: "+app.getPrice()  +" App  Rating :: "+app.getRating()  +" App  Ratings Count :: "+app.getRatingsCount());
}
}
});
[/java]

You can query apps based on the Package Name as well as publisher name.
Search By Package Name
String query = "pname:<package name>"

eg: String query = "pname:com.vkslabs.buybooks";

Search By Publisher
String query = "pub:<publisher name>";

eg: String query = "pub:vkslabs";

Troubleshooting
If the search API works for keyword based search but not for package name or publisher name search then it might be due to the invalid Android ID. You need to set a valid Android ID for the API to work properly.

How to get a valid Android ID?

  • Install the application "Android System Info" from Marketplace and launch the app.

  • Goto Menu -> More -> Gtalk Service Monitor

  • Find the line aid:<Android ID value> (this is usually the second line in the screen)

  • Copy the value and set it as the Android ID in the MarketSession using the API


session.getContext().setAndroidId("XXXXXXXXXX");

Monday, March 26, 2012

Android Emulator won't connect to internet

Many a time I see this problem where the Android emulator simply refuses to connect to internet. There are 2 easy solutions to fix this problem.

1. The primary reason is that your machine might have both LAN and Wireless enabled and the internet connection is available only on Wireless. Since the emulator always tries LAN to for DNS settings it will be unable to connect. To fix this problem

  • Right click on your "My Network Places" and select properties

  • Select your LAN connection and disable it.

  • Restart your emulator


2. If the above solution doesn't work then try launching your emulator with the following command prompt.
emulator -avd <avd name> -verbose -dns-server 8.8.8.8

or if you are using eclipse to start the emulator then


    • Right click on your project and select "debug as"

    • Select "debug configuration" and select "target" tab

    • Enter the following text in the text field below "Additional Emulator Command Line Options"
      -dns-server 8.8.8.8




Emulator Configuration

  • The above steps applies to "Run Configuration" as well.

Tuesday, March 20, 2012

ProgressDialog with custom view

In one of my application I had to download data from server which took almost 10-15 seconds and I didn't want my users to stare at a progress dialog with just loading message.

I wanted to customize the default ProgressDialog to display interesting facts so that the user feels that they are waiting too long for the data.

My first step was to create my own layout and set the layout using the method setContentView method. But seems this method though available but cannot be used since it throws the following error
android.util.AndroidRuntimeException: requestFeature() must be called before adding content

So I tried to write my own dialog by sub classing Dialog but figured out that there is a better way by sub classing AlertDialog.

[java]
AlertDialog.Builder builder = new AlertDialog.Builder(context);
progressView = LayoutInflater.from(context).inflate(R.layout.progress_dyk, null);
builder.setView(progressView);
progress = builder.create();
progress.requestWindowFeature(Window.FEATURE_NO_TITLE);

progress.show();
[/java]

Eclipse: JVM Terminated. Exit code=-1

I have been using my eclipse instance for months and on the day of a crucial release it stopped working (May be just to prove Murphy's law). I had several instance of eclipse (I usually have different instance for J2EE, Android, Blackberry etc) and all the instance showed me exactly the same error.





[xml]
JVM terminated. Exit code=-1
-Dosgi.requiredJavaVersion=1.5
-Xms40m
-Xmx512m
-XX:MaxPermSize=512M
-Djava.class.path=D:eclipseAndroideclipseplugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar
-os win32
-ws win32
-arch x86
-showsplash
-launcher D:eclipseAndroideclipseeclipse.exe
-name Eclipse
--launcher.library D:eclipseAndroideclipseplugins/org.eclipse.equinox.launcher.win32.win32.x86_1.0.200.v20090519eclipse_1206.dll
-startup D:eclipseAndroideclipseplugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar
-product org.eclipse.epp.package.java.product org.eclipse.platform
-vm C:Javajre6binclientjvm.dll
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Xms40m
-Xmx512m
-XX:MaxPermSize=512M
-Djava.class.path=D:eclipseAndroideclipseplugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar
[/xml]


Tweaking all the memory size parameters in eclipse.ini but irrespective of whatever permutation and combination I tried it didn't budge.

I then removed all the contents of eclipse.ini and voila! it worked perfectly but then I thought these values are there for a reason and removing everything might cause some other issue. Hence I started putting back the values one by one and figured out that removing the following 2 lines in the ini file fixed the problem.
[java]
--launcher.XXMaxPermSize
512M
--launcher.XXMaxPermSize
512M
[/java]
After pin pointing the problem area I added these parameters but tried with different values and after trial and error found that value 128M worked perfectly. Now the final eclipse.ini looks like the one shown below.
[java]
-startup
plugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.0.200.v20090519
-product
org.eclipse.epp.package.java.product
-showsplash
--launcher.XXMaxPermSize
128M
--launcher.XXMaxPermSize
128M
org.eclipse.platform
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Xms40m
-Xmx512m
[/java]
I am still not sure what is the root cause of this issue. May be restarting the machine and reverting back the value to 512 M might do the trick.