How to correctly implement PubSub with Autobahn on android? - java

I have been struggling to find a good way of implementing PubSub with Autobahn for android. I am currenty using the Singleton pattern to use the same AutobahnConnection in my whole app. I got the calls and subscribing working but when i unsubscribe and then come back to the same fragment and try to subscribe again it doesnt work. Below my current Autobahn Class:
package nl.w3s.hulpverlener.utils;
import nl.w3s.hulpverlener.helper.DebugHelper;
import android.util.Log;
import de.tavendo.autobahn.Autobahn;
import de.tavendo.autobahn.Autobahn.SessionHandler;
import de.tavendo.autobahn.AutobahnConnection;
import de.tavendo.autobahn.AutobahnOptions;
public final class AutobahnService{
private static AutobahnService INSTANCE;
private static AutobahnConnection connection;
private AutobahnOptions options;
private boolean connected = false;
private String url = "http://johelpen.w3s.nl/";
private String websocketUrl;
private AutobahnService() {
connection = new AutobahnConnection();
options = new AutobahnOptions();
options.setReceiveTextMessagesRaw(true);
websocketUrl = CommonUtilities.STAGING_WEBSOCKET_URL;
connect();
}
public static AutobahnService getInstance() {
if(INSTANCE == null)
INSTANCE = new AutobahnService();
else
INSTANCE.connect();
return INSTANCE;
}
public void connect() {
if(!connection.isConnected()) {
connection.connect(websocketUrl, new SessionHandler() {
#Override
public void onOpen() {
connected = true;
Log.i(DebugHelper.TAG_DEBUG, "CONNECTED");
}
#Override
public void onClose(int p_intCode, String p_strReason) {
connected = false;
Log.i(DebugHelper.TAG_DEBUG, "DISCONNECTED");
}
}, options);
}
}
public void doCall(final String callType, final Class<?> classRef, final Autobahn.CallHandler autobahnEventHandler, final Object... arguments) {
connection.call(url + "#" + callType, classRef, autobahnEventHandler, arguments);
}
public void doSubscribe(final String callType, final Class<?> classRef, final Autobahn.EventHandler autobahnEventHandler) {
connection.subscribe(url + callType, classRef, autobahnEventHandler);
}
public void doUnsubscribe(final String callType) {
connection.unsubscribe(url + callType);
}
}
When I look at my logs it doesnt disconnect while unsubscribing and resubscribing.

Related

Akka Persistence: Issue starting PersistentActor: java.lang.IllegalArgumentException: Default journal plugin is not configured, see 'reference.conf'

I am trying to work with PersistentActor in Akka.
I tried the basic example provided in the Akka documentation at https://doc.akka.io/docs/akka/current/persistence.html.
I am getting the following error at the starting of the actor:
Caused by: java.lang.IllegalArgumentException: Default journal plugin
is not configured, see 'reference.conf' at
akka.persistence.Persistence$.verifyPluginConfigIsDefined(Persistence.scala:193)
at
akka.persistence.Persistence.defaultJournalPluginId$lzycompute(Persistence.scala:228)
at
akka.persistence.Persistence.defaultJournalPluginId(Persistence.scala:226)
at
akka.persistence.Persistence.journalConfigFor(Persistence.scala:336)
at akka.persistence.Eventsourced.$init$(Eventsourced.scala:97) at
akka.persistence.AbstractPersistentActor.(PersistentActor.scala:455)
at
org.spituk.learning.akka.samples.ExamplePersistentActor.(ExamplePersistentActor.java:72)
The code I tried is like:
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.persistence.AbstractPersistentActor;
import akka.persistence.SnapshotOffer;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
class Cmd implements Serializable {
private static final long serialVersionUID = 1L;
private final String data;
public Cmd(String data) {
this.data = data;
}
public String getData() {
return data;
}
}
class Evt implements Serializable {
private static final long serialVersionUID = 1L;
private final String data;
public Evt(String data) {
this.data = data;
}
public String getData() {
return data;
}
}
class ExampleState implements Serializable {
private static final long serialVersionUID = 1L;
private final ArrayList<String> events;
public ExampleState() {
this(new ArrayList<>());
}
public ExampleState(ArrayList<String> events) {
this.events = events;
}
public ExampleState copy() {
return new ExampleState(new ArrayList<>(events));
}
public void update(Evt evt) {
events.add(evt.getData());
}
public int size() {
return events.size();
}
#Override
public String toString() {
return events.toString();
}
}
public class ExamplePersistentActor extends AbstractPersistentActor {
private int snapShotInterval = 1000;
private ExampleState state = new ExampleState();
public static Props props() {
return Props.create(ExamplePersistentActor.class);
}
public int getNumEvents() {
return state.size();
}
#Override
public String persistenceId() {
return "sample-id-1";
}
#Override
public Receive createReceiveRecover() {
return receiveBuilder()
.match(Evt.class, state::update)
.match(SnapshotOffer.class, ss -> state = (ExampleState) ss.snapshot())
.build();
}
#Override
public Receive createReceive() {
return receiveBuilder()
.match(
Cmd.class,
c -> {
final String data = c.getData();
final Evt evt = new Evt(data + "-" + getNumEvents());
System.out.println("Cmd received::" + c);
persist(
evt,
(Evt e) -> {
state.update(e);
getContext().getSystem().getEventStream().publish(e);
if (lastSequenceNr() % snapShotInterval == 0 && lastSequenceNr() != 0)
// IMPORTANT: create a copy of snapshot because ExampleState is mutable
saveSnapshot(state.copy());
});
})
.matchEquals("print", s -> System.out.println(state))
.build();
}
public static void main(String[] args) throws IOException {
ActorSystem persistentSystem = ActorSystem.create("persistent-system");
ActorRef persistentSystemActor = persistentSystem.actorOf(ExamplePersistentActor.props());
persistentSystemActor.tell(new Cmd("Hello"), ActorRef.noSender());
System.in.read();
persistentSystem.terminate();
}
}
I have not defined any configurations for the persistence intend to use the built-in default plugins. Can someone please help me with this?
I had to add the following to the application.conf file:
akka.persistence.journal.plugin = "akka.persistence.journal.leveldb"
akka.persistence.snapshot-store.plugin = "akka.persistence.snapshot-store.local"
akka.persistence.journal.leveldb.dir = "target/example/journal"
akka.persistence.snapshot-store.local.dir = "target/example/snapshots"
# DO NOT USE THIS IN PRODUCTION !!!
akka.persistence.journal.leveldb.native = false

How to implement builder inside my already defined class

I am trying to convert my class to support builder in order to prettify my code, this is the code I am using and I try to define my method called addSMTPIntegration to use builder.
this is my class:
public class IntegrationsPage extends SettingsTab {
private static final By newIntegrationBth = Locators.findBy("settings_page_integrations_page_add_new_button");
private IntegrationsTable integrationsTable;
private SmtpIntegrationForm smtpIntegrationForm;
private ConfirmPopup confirmPopup;
public IntegrationsPage(DriverWrapper driver){
super(driver, "integrations",newIntegrationBth);
integrationsTable = new IntegrationsTable(driver);
smtpIntegrationForm = new SmtpIntegrationForm(driver);
confirmPopup = new ConfirmPopup(driver);
}
public void addSMTPIntegration(String name, String server, String port, String fromAddress, boolean mode, String userName, String password){
clickNewIntegrationButton();
smtpIntegrationForm.chooseIntegration(IntegrationType.SMTP);
smtpIntegrationForm.setIntegrationName(name);
smtpIntegrationForm.setIntegrationServer(server);
smtpIntegrationForm.setIntegrationPort(port);
smtpIntegrationForm.setIntegrationFromAddress(fromAddress);
smtpIntegrationForm.setIntegrationAuth(mode);
smtpIntegrationForm.setIntegrationUserName(userName);
smtpIntegrationForm.setIntegrationPassword(password);
smtpIntegrationForm.clickSaveButton();
LOG.i("SMTP configuration passed successfully");
}
private void clickNewIntegrationButton(){
clickButton(newIntegrationBth);
}
public IntegrationsRow waitIntegrationRowTable(String configurationName) {
return integrationsTable.waitRowDisplay(configurationName);
}
public boolean deleteIntegration(String integrationName) {
integrationsTable.findRow(integrationName).clickRow();
integrationsTable.delete(integrationName);
confirmPopup.clickYes();
return integrationsTable.findRow(integrationName) == null;
}
}
I am trying to define my addSMTPIntegration method to support builder in a manner that I would be able to build it in the following way:
smtpIntegrationForm.chooseIntegration(IntegrationType.SMTP).setIntegrationName(name).setIntegrationServer(server).... etc
This is my smtpIntegrationForm class:
public class SmtpIntegrationForm extends IntegrationCommonSection {
private static final By integrationServerBy = Locators.findBy("settings_page_integrations_page_integration_server_name_txt");
private static final By integrationPortBy = Locators.findBy("settings_page_integrations_page_integration_port_txt");
private static final By integrationFromAddressBy = Locators.findBy("settings_page_integrations_page_integration_from_address_txt");
SmtpIntegrationForm(DriverWrapper driver){
super(driver);
}
void setIntegrationServer(String server){
setText(integrationServerBy, server);
}
void setIntegrationPort(String port){
setText(integrationPortBy, port);
}
void setIntegrationFromAddress(String address){
setText(integrationFromAddressBy, address);
}
void chooseIntegration(IntegrationType integrationType){
clickButton(By.cssSelector("li[class~='qa_" + integrationType.value + "']"));
}
and this is IntegrationCommonSection class:
class IntegrationCommonSection extends PageElement {
private static final By integrationNameBy = Locators.findBy("settings_page_integrations_page_integration_name_txt");
private static final By integrationAuthBy = Locators.findBy("settings_page_integrations_page_integration_auth_bth");
private static final By integrationUserNameBy = Locators.findBy("settings_page_integrations_page_integration_username_txt");
private static final By integrationPasswordBy = Locators.findBy("settings_page_integrations_page_integration_password_txt");
private static final By integrationSaveBthBy = Locators.findBy("settings_page_integrations_page_integration_save_bth");
private static final By integrationTestBthBy = Locators.findBy("settings_page_integrations_page_integration_test_bth");
IntegrationCommonSection(DriverWrapper driver){
super(driver);
}
void setIntegrationName(String name){
clearAndSetCharacters(integrationNameBy, name);
}
void setIntegrationAuth(boolean mode){ //true - with auth, false - no auth
if(!isCheckBoxEnabled(integrationAuthBy) && mode) {
clickButton(integrationAuthBy);
}
}
void setIntegrationUserName(String userName){
setText(integrationUserNameBy, userName);
}
void setIntegrationPassword(String password){
setText(integrationPasswordBy, password);
}
void clickSaveButton(){
clickButton(integrationSaveBthBy);
}
void clickTestButton(){
clickButton(integrationTestBthBy);
}
}
just return "this" :
SmtpIntegrationForm setIntegrationServer(String server){
setText(integrationServerBy, server);
return this;
}
In order to do that, you need to modify the methods of SmtpIntegrationForm with the return of this object so that you can construct the statements in a builder pattern. There is nothing you can do in addSMTPIntegration() method to achieve this.
chooseIntegration(), setIntegrationName(), setIntegrationServer(), etc. methods inside SmtpIntegrationForm should have return type of SmtpIntegrationForm and the last statement in these methods should be return this; in order for you to achieve this.
Make the changes as:
public class SmtpIntegrationForm extends IntegrationCommonSection {
private static final By integrationServerBy = Locators.findBy("settings_page_integrations_page_integration_server_name_txt");
private static final By integrationPortBy = Locators.findBy("settings_page_integrations_page_integration_port_txt");
private static final By integrationFromAddressBy = Locators.findBy("settings_page_integrations_page_integration_from_address_txt");
SmtpIntegrationForm(DriverWrapper driver){
super(driver);
}
SmtpIntegrationForm setIntegrationServer(String server){
setText(integrationServerBy, server);
return this;
}
SmtpIntegrationForm setIntegrationPort(String port){
setText(integrationPortBy, port);
return this;
}
SmtpIntegrationForm setIntegrationFromAddress(String address){
setText(integrationFromAddressBy, address);
return this;
}
SmtpIntegrationForm chooseIntegration(IntegrationType integrationType){
clickButton(By.cssSelector("li[class~='qa_" + integrationType.value + "']"));
return this;
}
}

HttpSessionBindingListener throws NullPointerException on TomCat server

I'm using HttpSessionBindingListener to maintain a record of all active logged in users in a web application.The below code works well for WildFly server but throws NullPointerException on Tomcat in valueBound method while fetching the session attribute which was set before calling this method.
package com.abc.def.xyz.dto;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import com.abc.def.xyz.util.Logger;
public class ActiveLoginUserDetails implements Serializable,HttpSessionBindingListener {
private Logger log = Logger.getLogger(this.getClass());
private static final long serialVersionUID = 1L;
private long usrId;
private String usrCode;
private String usrShortName;
private static Map<ActiveLoginUserDetails, HttpSession> activeLoginDtls = new ConcurrentHashMap<ActiveLoginUserDetails, HttpSession>();
private static Map<ActiveLoginUserDetails, HttpSession> loggedInUserDtlsMap = new ConcurrentHashMap<ActiveLoginUserDetails, HttpSession>();
public long getUsrId() {
return usrId;
}
public void setUsrId(long usrId) {
this.usrId = usrId;
}
public String getUsrCode() {
return usrCode;
}
public void setUsrCode(String usrCode) {
this.usrCode = usrCode;
}
public String getUsrShortName() {
return usrShortName;
}
public void setUsrShortName(String usrShortName) {
this.usrShortName = usrShortName;
}
public static Map<ActiveLoginUserDetails, HttpSession> getActiveLoginDtls() {
return activeLoginDtls;
}
public static void setActiveLoginDtls(Map<ActiveLoginUserDetails, HttpSession> activeLoginDtls) {
ActiveLoginUserDetails.activeLoginDtls = activeLoginDtls;
}
public static Map<ActiveLoginUserDetails, HttpSession> getLoggedInUserDtlsMap() {
return loggedInUserDtlsMap;
}
public static void setLoggedInUserDtlsMap(
Map<ActiveLoginUserDetails, HttpSession> loggedInUserDtlsMap) {
ActiveLoginUserDetails.loggedInUserDtlsMap = loggedInUserDtlsMap;
}
#Override
public void valueBound(HttpSessionBindingEvent event) {
ActiveLoginUserDetails sessionUsrDtls = (ActiveLoginUserDetails) event.getSession().getAttribute("LoggedInUsers");
Boolean userHasSmInteractiveLoginAction = false;
Boolean multiLoginAllowed = false;
Boolean check = true;
log.info("sessionUsrDtls:::::"+ );
List<ActionDetails> actnDtlsList = (List<ActionDetails>) event.getSession().getAttribute("sessionActnList");
for(ActionDetails actnDtls : actnDtlsList){
if(actnDtls.getActionAccessValue().equalsIgnoreCase("smLogin")){
userHasSmInteractiveLoginAction = true;
}
}
if(userHasSmInteractiveLoginAction){
String amultiLoginAllowedUserCodeList = "adminUser";
String[] usrCodeArr = amultiLoginAllowedUserCodeList.split(",");
for(String tempUserCode : usrCodeArr){
if(sessionUsrDtls.getUsrCode().equalsIgnoreCase(tempUserCode)){
multiLoginAllowed = true;
}
}
}
if(!multiLoginAllowed){
for( Entry<ActiveLoginUserDetails, HttpSession> tempLoginDtls : activeLoginDtls.entrySet()){
ActiveLoginUserDetails temp = tempLoginDtls.getKey();
if(temp.getUsrCode().equals(sessionUsrDtls.getUsrCode())){
if (event.getSession() != null) {
check = false;
event.getSession().invalidate();
log.debug("After Invalidating duplicate session for "+sessionUsrDtls.getUsrCode());
}
}
}
}
if(check){
log.debug("Inside adding user from session:::");
activeLoginDtls.put(this, event.getSession());
}
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
log.debug("Inside removing user from session:::");
activeLoginDtls.remove(this);
loggedInUserDtlsMap.remove(this);
}
}
It is throwing NullPointerException (for sessionUsrDtls object) at line
if(sessionUsrDtls.getUsrCode().equalsIgnoreCase(tempUserCode)){
which denotes that the attribute is not set into session. but this method will get called only after setting the value into session, so couldn't get what's the exact problem going on here.

Is there a "clean" way to automatically un-register a listener in Java?

I believe I've seen variants of this question, but no "definitive answer". In the code below, I understand that SomeEventManager holds a reference to someImplClassTwo.myEventListenerA and someImplClassTwo.myEventListenerB, and that this does not allow for someImplClassTwo to be garbage collected, and this results in the output generated the second time someEventManager.notifyListeners() is invoked.
But, I'd really like for users of SomeImplClass not to have to know that there are listeners involved in the implementation, and that these listeners need to be manually un-registered (i.e., SomeImplClass.releaseListeners()) before releasing the SomeImplClass object.
Is there a clean/accepted way of doing this?
p.s. I've already played with finalize(), just for fun, and confirmed that GC is not even attempted in this case, for either instance of SomeImplClass. So, that seems to be a non-starter as a potential solution.
Test Driver
public class TestDriver {
public static void main(String[] args) {
SomeEventManager someEventManager = SomeEventManager.getInstance();
SomeImplClass someImplClassOne = new SomeImplClass("One");
SomeImplClass someImplClassTwo = new SomeImplClass("Two");
someEventManager.notifyListeners();
someImplClassOne.releaseListeners();
someImplClassOne = null;
someImplClassTwo = null;
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
someEventManager.notifyListeners();
}
}
Event Interface
public interface SomeEventListener {
public void handleSomeEvent();
}
Event Manager
import java.util.ArrayList;
import java.util.List;
public class SomeEventManager {
private static SomeEventManager eventManager = null;
private List<SomeEventListener> listeners = null;
private SomeEventManager() {
listeners = new ArrayList<SomeEventListener>();
}
public static SomeEventManager getInstance() {
if (eventManager == null) {
eventManager = new SomeEventManager();
}
return eventManager;
}
public void addListener(SomeEventListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public void removeListener(SomeEventListener listener) {
listeners.remove(listener);
}
public void notifyListeners() {
for(SomeEventListener listener : listeners) {
listener.handleSomeEvent();
}
}
}
Event Listener Implementation
public class SomeImplClass {
private InnerEventListener myEventListenerA = null;
private InnerEventListener myEventListenerB = null;
private String id = null;
public SomeImplClass(String id) {
this.id = id;
myEventListenerA = new InnerEventListener(id + "_A");
myEventListenerB = new InnerEventListener(id + "_B");
}
public void releaseListeners() {
myEventListenerA.unregisterListener();
myEventListenerB.unregisterListener();
}
private class InnerEventListener implements SomeEventListener {
private SomeEventManager someEventManager = null;
private String id = null;
public InnerEventListener(String id) {
someEventManager = SomeEventManager.getInstance();
this.id = id;
registerListener();
}
public void registerListener() {
someEventManager.addListener(this);
}
public void unregisterListener() {
someEventManager.removeListener(this);
}
public void handleSomeEvent() {
System.out.println("InnerEventListener->" + id);
}
}
}
The solution we use is to have the listener automatically unregister itself if it gets called and the thing it's updating has been collected.
It looks a bit like this:
private static class InnerEventListener implements SomeEventListener {
private final WeakReference<ThingToUpdate> thingRef;
public InnerEventListener(ThingToUpdate thing) {
thingRef = new WeakReference<>(thing);
}
#Override
public void handleSomeEvent(SomeEvent event) {
ThingToUpdate thing = thingRef.get();
if (thing != null) {
thing.updateSomehow();
} else {
((SomeEventedThing) event.getSource())
.removeSomeEventListener(this);
}
}
}
//...
SomeEventedThing eventedThing;
ThingToUpdate thingToUpdate;
//...
eventedThing.addListener(new InnerEventListener(thingToUpdate));
I wouldn't say it's a perfect solution because the listener sticks around until it gets an event, and it's still somewhat dependent on garbage collection. We've been trying to replace it with explicit removal where possible, usually on addNotify/removeNotify on GUI components.

Why does my singleton class throw a StackOverflowerror?

I have been writing a program. Everything is in program is controlled by the 'Engine' class. I have hence made it a singleton. Here is my current code that runs just fine.
package org.bautista.cybersafe.core;
import javax.swing.SwingUtilities;
import org.bautista.cybersafe.ui.MainUI;
import org.bautista.cybersafe.util.Cache;
import org.bautista.cybersafe.util.Config;
import org.bautista.cybersafe.util.account.Account;
import org.bautista.cybersafe.util.account.AccountManager;
import org.bautista.cybersafe.util.user.User;
import org.bautista.cybersafe.util.user.UserManager;
public class Engine {
private static Engine instance;
private AccountManager accountManager;
private final MainUI ui;
private final UserManager userManager;
private final Config config;
private User currentUser;
private Engine() {
instance = this; //THIS IS LINE 22
if (!Cache.cacheExists()) {
if (!Cache.createCache()) {
System.out.println("Error creating cache.");
}
}
config = new Config();
userManager = new UserManager();
ui = new MainUI();
}
public static Engine getInstance() {
return instance == null ? instance = new Engine() : instance;
}
public void setCurrentUser(User user) {
currentUser = user;
}
public User getCurrentUser() {
return currentUser;
}
public AccountManager getAccountManager() {
return accountManager;
}
public Config getConfig() {
return config;
}
public UserManager getUserManager() {
return userManager;
}
public void logOut() {
currentUser = null;
accountManager = null;
ui.showLogin();
}
public void openAccountViewer(final Account account) {
ui.showAccount(account);
ui.setTitle("Cyber Safe - [" + currentUser.getUsername() + "] -"
+ account.getName());
}
public void openCreateAccountScreen() {
ui.showCreateAccount();
}
public void openCreateUserScreen() {
ui.showCreateUser();
}
public void openLoginScreen() {
ui.showLogin();
ui.setTitle("Cyber Safe");
}
public void openSafeScreen() {
if (accountManager == null) {
accountManager = new AccountManager(currentUser);
}
ui.showSafe();
ui.setTitle("Cyber Safe - [" + currentUser.getUsername() + "]");
}
public void refreshUI() {
ui.refresh();
}
public void updateAccountPreviews() {
ui.updateAccountScroller();
}
public void run() {
try {
SwingUtilities.invokeAndWait(() -> ui.setVisible(true));
} catch (final Exception e) {
e.printStackTrace();
}
}
}
When I comment out line 22
instance = this;
I receive a StackOverflowerror. When I debug the program I find that the Engine constructor is being called repeatedly, as if it were performing recursion, until I final get the error. Why does that happen? Should't my #getInstance() method be initiating instance as a new instance of the 'Engine' class?
Here is the stacktrace:
Exception in thread "main" java.lang.StackOverflowError
at java.io.InputStream.<init>(InputStream.java:45)
at java.io.FileInputStream.<init>(FileInputStream.java:123)
at org.bautista.cybersafe.util.Config.loadProperties(Config.java:67)
at org.bautista.cybersafe.util.Config.<init>(Config.java:29)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:28)
at org.bautista.cybersafe.core.Engine.getInstance(Engine.java:34)
at org.bautista.cybersafe.util.user.UserManager.loadUsers(UserManager.java:73)
at org.bautista.cybersafe.util.user.UserManager.<init>(UserManager.java:20)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:29)
at org.bautista.cybersafe.core.Engine.getInstance(Engine.java:34)
at org.bautista.cybersafe.util.user.UserManager.loadUsers(UserManager.java:73)
at org.bautista.cybersafe.util.user.UserManager.<init>(UserManager.java:20)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:29)
at org.bautista.cybersafe.core.Engine.getInstance(Engine.java:34)
at org.bautista.cybersafe.util.user.UserManager.loadUsers(UserManager.java:73)
at org.bautista.cybersafe.util.user.UserManager.<init>(UserManager.java:20)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:29)
at org.bautista.cybersafe.core.Engine.getInstance(Engine.java:34)
at org.bautista.cybersafe.util.user.UserManager.loadUsers(UserManager.java:73)
at org.bautista.cybersafe.util.user.UserManager.<init>(UserManager.java:20)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:29)
And here is the full project on Github
Thanks in advance!
The stack trace shows the following loop:
at org.bautista.cybersafe.util.user.UserManager.loadUsers(UserManager.java:73)
at org.bautista.cybersafe.util.user.UserManager.<init>(UserManager.java:20)
at org.bautista.cybersafe.core.Engine.<init>(Engine.java:29)
at org.bautista.cybersafe.core.Engine.getInstance(Engine.java:34)
Engine.getInstance() calls new Engine().
new Engine() calls new UserManager().
new UserManager() calls UserManager.loadUsers().
UserManager.loadUsers() calls Engine.getInstance(), but Engine.instance hasn't been assigned yet, since the previous new Engine() call hasn't returned yet.
This is why assigning Engine.instance in the constructor, before it calls new UserManager(), fixes the problem.
You should reorganize your code to prevent that initialization loop. UserManager and Engine should not be co-dependent during initialization.
Note that doing private static Engine instance = new Engine() as suggested in another answer will not fix your initialization loop.

Categories

Resources