0

According to my own question i just found another problem with data initialization during PostConstruct in Startup Singleton. The problem is caused by primary key violation, which is generated during:

@Singleton
@Startup
public class DefaultDataIntializer {

  @PostConstruct
  public void init()
  {
    BlinkUser bu = createDefaultUser();
    BlinkGroup bg = createDefaultGroup();
    Link l = createDefaultLink();
    UserLink ul = createDefaultUserLink();

    if(buf.find(bu.getEmail()) != null)
      return;

    bg.addUser(bu);
    ul.setLink(l);
    ul.setOwner(bu);

    lf.create(l);
    bgf.create(bg);
    buf.create(bu);
    ulf.create(ul);     
  } 
}

And here is full deployment's log. Problem is in:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'user@gmail.com' for key 'PRIMARY'

But when i am using debugger that problem is not showing up during creation. Maybe is caused by some cache? Well, that's long shot, i just didn't find anything wrong especially i check existing of example data before creation (DefaultDataInitializer::init():5). Also, it's my persistence.xml:

 <persistence version="2.0" 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">
   <persistence-unit name="BlinkLinkServer-ejbPU" transaction-type="JTA">
   <provider>org.hibernate.ejb.HibernatePersistence</provider>
   <jta-data-source>java:jboss/datasources/BlinkLinkDataSource</jta-data-source>
   <exclude-unlisted-classes>false</exclude-unlisted-classes>
   <properties>
     <property name="hibernate.hbm2ddl.auto" value="create"/>
     <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
   </properties>
 </persistence-unit>

Maybe it's something wrong with some transaction? I shouldn't initialize data that way? Thanks for help!

Edit: Root cause is duplicated invoking postConstruct method. Even synchronized or additional variable (even static) isn't solving problem. Even debugger isn't showing second invoke (isn't stopping on breakpoint second time). So how i figured it out this is different methods?

public synchronized void init()
{
            Logger.getAnonymousLogger().warning("Initializing data!" + (new Random()).nextInt());
            //rest of previous code

}

Which gives:

 16:08:21,079 WARNING [null] (ServerService Thread Pool -- 424) Initializing data!778044534
 16:08:21,116 WARNING [null] (ServerService Thread Pool -- 423) Initializing data!1060447455
Community
  • 1
  • 1
Dawid Pura
  • 991
  • 9
  • 32
  • Can you check whether the user 'user@gmail.com' exists in your DB? Maybe the error is in `buf.find()`. It doesn't find the user but it exists in the DB. – TomasZ. May 03 '14 at 20:36
  • Yup, it is already. But even create method doesn't rise any exception. That looks like some transaction (in selection?) which isn't updated properly. – Dawid Pura May 05 '14 at 05:11
  • You create the default objects and then check if the email already exists and return, but even if you return the transaction gets commited and it wants to write the new data. I will have to do the check as the first thing with something like `getDefaultEmail`. Throwing an exception would rollback the transaction, but I think that would prevent the app from starting. – TomasZ. May 05 '14 at 07:06
  • It's not, because createDefaultUser and other methods call simple constructor, so this objects aren't persistent yet. – Dawid Pura May 05 '14 at 08:12
  • If you run the code in debug mode then it returns at the `if` statement, but if you run it normally then it fails? Can you print something before and after the `if` to see where it gets when running without debug? Maybe you are right and it's something with the hibernate cache. – TomasZ. May 05 '14 at 10:40
  • No, this exception raises after this method, it doesnt matter whether debug is on or not. Looks like this method have a 'clean' database, but some while after it persisting objects and crash. I tried to turn of cache, but it didn't help. – Dawid Pura May 05 '14 at 13:18
  • 1
    Have you implemented in your entity models `BlinkUser,BlinkGroup,...` the `hashCode` and `equals` methods? This could also be the problem. – TomasZ. May 05 '14 at 13:58
  • Well, it can be, but if i disable this method in application startup then there is no problem with entities at all, so 'default' methods hashCode and equals should work well. Of course it isn't an excuse to not implementing hashCode and equals methods. I will do that later. – Dawid Pura May 05 '14 at 18:56
  • In Eclipse (or any other IDE) you can generate `equals` and `hashCode` methods easily, just picking the primary key. It is a must have for proper functionality. Read the first 4 lines here http://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html – TomasZ. May 05 '14 at 19:06
  • Adding `equals` and `hashcode` methods for all classes didn't help, also i find out cause of problem - database is dropped after initialization. Is there any possibitity to change this behavior? – Dawid Pura May 10 '14 at 07:58
  • Try setting the `hibernate.hbm2ddl.auto` to `update`. According to this link http://stackoverflow.com/a/1689769/3392874 your data is dropped on every start, I didn't know about that. `update` will just update changes but won't delete your data. – TomasZ. May 10 '14 at 08:55
  • I want to drop my data, it's okay. I can't set JTA for jboss datasource, maybe this could be a problem? CCM is enabled, but change JTA to enable causing datasource can't be enabled (Log: http://pastebin.com/a3E04Xtp). – Dawid Pura May 10 '14 at 09:01
  • I am getting lost in your questions. You said your cause of problem is that the DB is dropped and then you say you want to drop your data. The second log you pasted has been removed. – TomasZ. May 10 '14 at 09:55
  • I want to drop old data and load new one by this initialization. But it looks like dropping is starting after this postConstruct method is called, or something like that (at transaction level). However, i googled some problems with EntityManager in startup beans. http://openejb.979440.n4.nabble.com/Cannot-persist-in-Singletons-td981419.html – Dawid Pura May 10 '14 at 10:05
  • http://pastebin.com/4CFCAhVX after changing JTA to enabled. However, data is initialized properly into database. – Dawid Pura May 10 '14 at 10:15
  • From the logs I can see a deadlock error `Deadlock found when trying to get lock; try restarting transaction`. I have no idea what could cause this. If you stop JBoss, remove the DB and start JBoss, does it work properly or there are also issues? – TomasZ. May 10 '14 at 10:34
  • When i remove database it works only first time - deployment and data initialization. Also i tried to surround create methods by `UserTransaction`, but its raising exception `14:38:31,583 WARNING [null] (ServerService Thread Pool -- 311) BaseTransaction.checkTransactionState - ARJUNA016051: thread is already associated with a transaction! 14:38:31,583 WARNING [null] (ServerService Thread Pool -- 317) BaseTransaction.checkTransactionState - ARJUNA016051: thread is already associated with a transaction!` – Dawid Pura May 10 '14 at 12:53
  • Iteresting thing, this postConstruct method is called twice! How can it be? – Dawid Pura May 10 '14 at 13:22
  • I googled around and there was a bug in JBoss https://issues.jboss.org/browse/AS7-2785 Maybe the issue still exists. – TomasZ. May 10 '14 at 15:02
  • Well, using EAP and still have a bug :). I will change EAP 6.2 to community version :) Maybe it will help. – Dawid Pura May 10 '14 at 15:27

1 Answers1

0

Ok, so the real cause of this problem is duplicated ejb jars in project - one in WAR, and other packed in EAR. I don't know how debugger won't let me into second invoke of @PostConstruct method. Thanks TomasZ for help, i didn't solve this alone.

Solution:

Check Maven projects. pom.xml in WAR should have dependency:

    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>YourProject-ejb</artifactId>
        <version>${project.version}</version>
    </dependency>

According to this, JAR file with EJB project is packed into WAR. I'm sure you will have a EJB maven project with other dependencies:

    <dependency>
        <groupId>com.example.project</groupId>
        <artifactId>YourProject-ejb</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>ejb</type>
    </dependency>
    <dependency>
        <groupId>com.example.project</groupId>
        <artifactId>YourProject-web</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>war</type>
    </dependency>

So there is also included JAR file. It is wrong behavior (i'm using NetBeans so it is a bug with project creator). There some ways to avoid this:

  1. Add provided scope to pom.xml in WAR project:

    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>YourProject-ejb</artifactId>
        <version>${project.version}</version>
        <scope>provided</scope>
    </dependency>
    

    then jar won't be included into WAR.

  2. Add skinnyWar option to maven-war-plugin configuration described here

  3. You can from some reason want to keep your JAR file in WAR and remove from EAR. So you can simple add provided option to dependency in EAR file.

    <dependency>
        <groupId>com.example.project</groupId>
        <artifactId>YourProject-ejb</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>ejb</type>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.example.project</groupId>
        <artifactId>YourProject-web</artifactId>
        <version>1.0-SNAPSHOT</version>
        <type>war</type>
    </dependency>
    
Community
  • 1
  • 1
Dawid Pura
  • 991
  • 9
  • 32