0

I'm trying to write a service that will collect data from a remote source and save it to the DB. However, it throws a NullPointerException on server startup. I followed Oracle's tutorial

Here's the log:

java.lang.NullPointerException
    at org.eclipse.persistence.platform.server.ServerPlatformUtils.createServerPlatform(ServerPlatformUtils.java:99)
    at org.eclipse.persistence.sessions.factories.SessionManager.init(SessionManager.java:77)
    at org.eclipse.persistence.sessions.factories.SessionManager.<clinit>(SessionManager.java:71)
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.addSessionToGlobalSessionManager(EntityManagerSetupImpl.java:907)
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.initSession(EntityManagerSetupImpl.java:2671)
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:675)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getAbstractSession(EntityManagerFactoryDelegate.java:205)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.createEntityManagerImpl(EntityManagerFactoryDelegate.java:305)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:337)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:318)
    at com.sun.enterprise.container.common.impl.EntityManagerWrapper._getDelegate(EntityManagerWrapper.java:197)
    at com.sun.enterprise.container.common.impl.EntityManagerWrapper.createNamedQuery(EntityManagerWrapper.java:521)
    at org.glassfish.ejb.persistent.timer.TimerBean.findTimersByOwnerAndState(TimerBean.java:209)
    at org.glassfish.ejb.persistent.timer.TimerBean.findActiveTimersOwnedByThisServer(TimerBean.java:523)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1081)
    at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1153)
    at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:4786)
    at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:656)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
    at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163)
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:140)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
    at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:369)
    at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:4758)
    at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:4746)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
    at com.sun.proxy.$Proxy166.findActiveTimersOwnedByThisServer(Unknown Source)
    at org.glassfish.ejb.persistent.timer.PersistentEJBTimerService.restoreEJBTimers(PersistentEJBTimerService.java:369)
    at org.glassfish.ejb.persistent.timer.PersistentEJBTimerService.resetEJBTimers(PersistentEJBTimerService.java:1400)
    at com.sun.ejb.containers.EJBTimerService.initEJBTimerService(EJBTimerService.java:236)
    at com.sun.ejb.containers.EJBTimerService.getEJBTimerService(EJBTimerService.java:205)
    at com.sun.ejb.containers.EJBTimerService.getEJBTimerService(EJBTimerService.java:187)
    at com.sun.ejb.containers.BaseContainer.<init>(BaseContainer.java:825)
    at com.sun.ejb.containers.AbstractSingletonContainer.<init>(AbstractSingletonContainer.java:127)
    at com.sun.ejb.containers.CMCSingletonContainer.<init>(CMCSingletonContainer.java:76)
    at com.sun.ejb.containers.SingletonContainerFactory.createContainer(SingletonContainerFactory.java:68)
    at org.glassfish.ejb.startup.EjbApplication.loadContainers(EjbApplication.java:221)
    at org.glassfish.ejb.startup.EjbDeployer.load(EjbDeployer.java:291)
    at org.glassfish.ejb.startup.EjbDeployer.load(EjbDeployer.java:99)

And my code:

package db;

import sun.net.www.protocol.http.HttpURLConnection;

import javax.annotation.Resource;
import javax.ejb.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

@Singleton
@Startup
public class DataCollector{

    @Resource
    TimerService timerService;

    private DBController db = new DBController();

    private static final Logger logger = Logger.getLogger("db.DataCollector");

    @Schedule(second = "*/4")
    public void collectData(Timer timer){
        String URL = "...";
        try{
            java.net.URL url = new URL(URL);

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            InputStream is = connection.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            String line;
            String [] columns;

            while((line = reader.readLine()) != null){
                if(line.contains("Err")) {
                    logger.log(Level.WARNING, "[SENSORS]: {s}", line);
                    continue;
                }
                columns = parseData(line);
                if(columns.length != 10) {
                    logger.log(Level.WARNING, "[SENSORS]: BAD DATA");
                    continue;
                }

                db.insertToProcessingCollection(columns);
            }
        } catch (IOException e) {
            logger.log(Level.SEVERE, e.getLocalizedMessage());
        }
    }

    private String [] parseData(String data){
        return data.split("\t");
    }
}

EDIT:

DBController.java:

public class DBController {
    private MongoDatabase db;

    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
    private static final Logger logger = Logger.getLogger("db.DBController");

    public DBController(){
        MongoClient client = new MongoClient();
        db = client.getDatabase("master");
    }

    public boolean insertToProcessingCollection(String [] data){
        MongoCollection<Document> collection = db.getCollection("newData");

        try {
            Document doc = new Document()...

            collection.insertOne(doc);

            return true;
        } catch (ParseException e) {
            logger.log(Level.SEVERE, e.getMessage());
            return false;
        }
    }

    public void pushDataToHistoryCollection(){
        try {
            MongoCollection<Document> historyCollection = db.getCollection("oldData");
            MongoCollection<Document> processingCollection = db.getCollection("newData");

            processingCollection.find().forEach((Block<Document>) historyCollection::insertOne);

            processingCollection.deleteMany(new Document());
        } catch (Exception e) {
            logger.log(Level.SEVERE, e.getMessage());
        }
    }

    public JSONArray getNewData(){
        try {
            MongoCollection<Document> collection = db.getCollection("newData");

            FindIterable<Document> newData = collection.find();

            JSONArray result = convertToJSON(newData);

            pushDataToHistoryCollection();

            return result;
        } catch (Exception e) {
            logger.severe(e.getMessage());
            return null;
        }
    }

    public JSONArray convertToJSON(FindIterable<Document> data){
        JSONArray result = new JSONArray();

        data.forEach((Block<Document>) document -> {
            JSONObject object = new JSONObject(document.toJson());
            object.put("dateTime", dateFormat.format(document.get("dateTime")));
            result.put(object);
        });

        return result;
    }

    public void removeOldData(){
        MongoCollection<Document> collection = db.getCollection("oldData");
        collection.deleteMany(new Document());
    }
}
mityakoval
  • 888
  • 3
  • 12
  • 26
  • 1
    May that be the same issue? http://stackoverflow.com/questions/33296319/java-lang-nullpointerexception-at-org-eclipse-persistence-platform-server-server – vempo Mar 20 '16 at 20:01
  • @vempo I don't think so. I don't use EclipseLink – mityakoval Mar 20 '16 at 20:14
  • From your logs, it seems that the error your getting is during the creation of your entity manager. Perhaps it would be useful to have your `persistence.xml` and the code of your `DBController`. – António Ribeiro Mar 20 '16 at 22:25
  • @aribeiro Actually, I don't have a persistence.xml. Added DBController to the post. However, without TimeService everything works great, but I also get warnings like this: `Instance could not be initialized. Class=interface org.glassfish.grizzly.http.server.AddOn, name=admin-listener, realClassName=org.glassfish.grizzly.http2.Http2AddOn` – mityakoval Mar 20 '16 at 22:53
  • Well, if you're only using `DBController` on your `TimerService` then it makes total sense that without it everything works well. If you take a closer look at the log trace you've posted, the error occurs when JPA tries to `addSessionToGlobalSessionManager`. To narrow your problem I advise you to remove the `DBController db = new DBController();` to see if the timer is triggered correctly. Also, make use of `@PostConstruct` to initialize your instance variables. – António Ribeiro Mar 21 '16 at 08:26
  • @aribeiro Removed `DBController` initialization - the exception was still there and timer service was not starting. When I removed `@Singleton` annotation the exception was gone but service still isn't working – mityakoval Mar 21 '16 at 08:49

2 Answers2

1

So, after some digging I found out that what's happening with your application was already reported on several other issues.

Even though you're not using EclipseLink directly, Glassfish is using it under the hood to establish database connections.

One of the reported issues is present on Glassfish's JIRA, with fix being done at EclipseLink's 2.6.2 release:

Also, I've found out that Payara (which is based on Glassfish) has the same problem:

Furthermore, as @vempo stated, the problem reported is also related with these other two SO questions:

As solution, you could try binding the new (stable) version of EclipseLink (2.6.2) to your project and deploy it, as @Tiny suggests here. The version of EclipseLink, supplied by GlassFish, will replaced by the one packed with your application.

Community
  • 1
  • 1
António Ribeiro
  • 4,129
  • 5
  • 32
  • 49
  • I added EclipseLink 2.6.2 to maven and it didn't fix the problem. But actually, the issue was with the `@Schedule`. Anyway, thanks for your time and pointing out the mix of automatic and programmatic timers :) – mityakoval Mar 21 '16 at 15:28
1

Well, it took some time but I have finally fixed it. As @aribeiro and @vempo stated the problem might have been related to EclipseLink bug fixed in 2.6.2 version. However, after adding EclipseLink 2.6.2 dependency the exception was still thrown. I decided to switch to WildFly 10 server and the issue was gone but the Service wouldn't start anyway. Added constructor that logged the creation of the service and it worked.

As @Max Fichtelmann said here minute and hour parameters in @Schedule are equal 0 by default. Declaring @Schedule(second = "*/4" , minute="*", hour = "*") fixed everything and it worked both in WildFly 10.0.0 and GlassFish 4.1.1

Community
  • 1
  • 1
mityakoval
  • 888
  • 3
  • 12
  • 26
  • Great that you've found the solution for your problem! :) I'm sorry if I wasn't great of a help! Btw, can you please, accept your own answer? – António Ribeiro Mar 21 '16 at 15:59
  • You did help. Led to solution I would say:) StackOverflow says I can accept my own answer only tomorrow – mityakoval Mar 21 '16 at 16:24