JSF pass object values between controllers - jsf

I have a web app that uses JSF pages and entity classes, where a user has to authenticate to be able to publish some exercises to his students.
In the entity class, a "user" object has:
id(int), login(string), password(string) and type(string)
In my "users" controller bean, i have a method to see if the user already exists in database. And that process goes well. All is working fine. So, i know for sure that a "user" object is instantiated with the correct data.
I have another controller that is used in another JSF page where the user can publish an exercise.
In the entity class, an "exercise" object has:
id(int), userID(int)(foreign key to ID on users), description(string), etc.
When i'm preparing the "exercise" object in the "exercises" controller, to save to database, i need to have access to the "user" object in the other controller to set the userID. And this is the reason of my headache! Because the userID allways sets to null !!!
I've tryed with #Named and #Inject(recommended), also with #Managedbean and #ManagedProperty(wich they say will be deprecated) ... Tryed with single and mixed combinations of #RequestScoped and #SessionScoped ... Tryed to instantiated the "user" object inside a #PostConstruct method in "exercises" controller... Have already read many examples on how to do it, but none of it works!
I know this is a very basic problem i'm having! And it only consists on how to pass an object from one controller to another! Still no SUCCESS, after TWO days of experimenting! This is driving me crazy!
Please HELP!:
"users" Controller
package controlers;
import beans.UtilizadoresFacade;
import entities.Utilizadores;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
#Named("utilizadoresController")
#RequestScoped
public class UtilizadoresController implements Serializable {
#EJB
UtilizadoresFacade ejbFacade;
Utilizadores utilizador = new Utilizadores(); //The one i want to pass to the other controller
List<Utilizadores> utilizadores = new ArrayList();
public Utilizadores getUtilizador() {
return utilizador;
}
public void setUtilizador(Utilizadores utilizador) {
this.utilizador = utilizador;
}
public List<Utilizadores> getUtilizadores() {
return utilizadores = (List<Utilizadores>)ejbFacade.consultarUtilizadores();
}
public String verificarUtilizador() { // method to verify the user in database by name and password
utilizadores = (List<Utilizadores>)ejbFacade.consultarUtilizador(utilizador.getNome(), utilizador.getSenha());
if(utilizadores.isEmpty())
return "index.xhtml";
else if(utilizadores.get(0).getTipo().equals("normal")) {
utilizador.setId(utilizadores.get(0).getId()); // Here is where i save the ID to "user" object
return "normal.xhtml";
}
else {
utilizador.setId(utilizadores.get(0).getId());
return "administrador.xhtml";
}
}
public String criarUtilizador(){ // this method is to add new user to database and it works fine.
ejbFacade.adicionarUtilizador(utilizador);
if(utilizador.getTipo().equals("normal"))
return "normal.xhtml";
else
return "administrador.xhtml";
}
}
"exercises" controller
package controlers;
import beans.ExerciciosFacade;
import entities.Exercicios;
import entities.Ucs;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
#Named("exerciciosController")
#RequestScoped
public class ExerciciosController implements Serializable {
#EJB
ExerciciosFacade ejbFacade;
#Inject
UtilizadoresController utilizadoresController;
Ucs cadeira = new Ucs(); //this is a discipline
Exercicios exercicio = new Exercicios();
List<Exercicios> exercicios = new ArrayList();
public List<Exercicios> getExercicios(){
return exercicios = (List<Exercicios>)ejbFacade.consultarExercicios();
}
public String criarExercicio(){ // Method to add an exercise to database
exercicio.setUcid(cadeira); // Sets de discipline ID to "exercise" object (another foreign key) and works well because this value comes from a form in JSF page
exercicio.setUtilizadorid(utilizadoresController.getUtilizador()); // This is where i try to set de user ID to "exercise" object
ejbFacade.adicionarExercicio(exercicio);
return "normal.xhtml";
}
public Exercicios getExercicio() {
return exercicio;
}
public void setExercicio(Exercicios exercicio) {
this.exercicio = exercicio;
}
public Ucs getCadeira() {
return cadeira;
}
public void setCadeira(Ucs cadeira) {
this.cadeira = cadeira;
}
}
I think the "users" controller should be #SessionScoped because i'll be needing the user data while he is navigating through the pages, but i've used #RequestScoped also so there won't be more conflicts i can't control !!!
One more thing: I'm working with Netbeans 8.1 and java DB also from Netbeans.
Hope i'm not forgetting anything!
Many thanks in advance.

I extract some lines of code from my project.
Here is the class for keeping User session
SessionPreferences.java
#ManagedBean(name = "sessionPreferences")
#SessionScoped
public class SessionPreferences implements Serializable {
public static User getLoggedInUser() {
try {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
User authenticatedUser = (User) session.getAttribute("username");
return authenticatedUser;
} catch (Throwable e) {
log.error("Error getting logged in user", e);
return null;
}
}
}
And the login validation
public String validateUsernamePassword() {
CryptWithMD5 clss = new CryptWithMD5();
String md5Pwd = clss.cryptWithMD5(pwd);
boolean valid = DBConnection.validate(user, md5Pwd);
if (valid) {
HttpSession session = SessionBean.getSession();
session.setAttribute("username", user);
return "index";
} else {
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Username and Passowrd",
"Please enter correct username and Password"));
return "login";
}
}
From now on, I can get User object by method
SessionPreferences.getLoggedInUser()

Related

Injecting a different bean during local development with Quarkus

With Spring and Micronaut, there are very concise ways to inject a different bean depending on what environment/profile an application is running in. I'm trying to do the same with Quarkus.
I've read this post: https://quarkus.io/blog/quarkus-dependency-injection/. And the process is alluded to in this StackOverflow post: How can I override a CDI bean in Quarkus for testing?. That last post says, "create bean in test directory".
My problem is slightly different. I'd like to inject a bean when in "development". In production, I'd like the default bean injected. From the docs, I can't see a way to have the app make this distinction.
If I have a default class like this:
#DefaultBean
#ApplicationScoped
class ProdProvider : SomeProvider {}
And I want to override it like this:
#Alternative
#Priority(1)
class DevProvider : SomeProvider {}
How can I make this happen only in dev mode?
In one case, I have a credential provider class that sets up Google's PubSub emulator while in local development. In production, I use a class that implements the same interface, but a real credential provider. The particular case that led me to asking this question, though is a a class that implements one method:
#ApplicationScoped
class VaultLoginJwtProvider : LoginJwtProvider {
#ConfigProperty(name = "vault.tokenPath")
private val jwtPath: String? = null
companion object {
val logger: Logger = LoggerFactory.getLogger("VaultTokenProvider")
}
override fun getLoginJwt(): Optional<String> {
logger.info("Using Vault Login JWT")
return try {
Optional.of(String(Files.readAllBytes(Paths.get(jwtPath))).trim { it <= ' ' })
} catch (e: Exception) {
logger.error("Could not read vault token at $jwtPath")
logger.error(e.printStackTrace().toString())
Optional.empty()
}
}
}
That class is injected into another class via constructor injection:
#Singleton
class JwtServiceImpl(
#RestClient val vaultClient: VaultClient,
#Inject val loginJwtProvider: LoginJwtProvider
) {
private var serviceJwt: String? = null
companion object {
val logger: Logger = LoggerFactory.getLogger("JwtServiceImpl")
}
private fun getLoginToken(): String? {
val vaultLogin = VaultLogin(
role = "user-service",
jwt = loginJwtProvider.getLoginJwt().get()
)
val loginResponse = vaultClient.login(vaultLogin)
return loginResponse.auth.clientToken
}
}
I'd like to inject more of a "mock" class while in development that just returns a static string. I could use ProfileManager.getActiveProfile(), but that has me mixing development concerns into my logic. And I don't feel that that has any place in my compiled production code.
This is possible in Micronaut by using the annotation #Requires(env = ["dev", "test"]). I did briefly look at using #Produces but the Oracle EE docs seemed a little bit difficult for me to grasp. If that's the solution, I'll dig in.
In case anybody else comes across this, this is how to do it: https://quarkus.io/guides/cdi-reference#enabling-beans-for-quarkus-build-profile
For example:
import javax.enterprise.inject.Produces;
import com.oi1p.common.EmailSender;
import com.oi1p.common.ErrorEmailSender;
import com.oi1p.common.LogOnlyEmailSender;
import io.quarkus.arc.DefaultBean;
import io.quarkus.arc.profile.IfBuildProfile;
#ApplicationScoped
public class Producers {
#Produces
#IfBuildProfile("dev")
public EmailSender logOnlyEmailSender() {
return new LogOnlyEmailSender();
}
#Produces
#DefaultBean
public EmailSender errorEmailSender() {
// TODO: implement a real email sender. This one explodes when poked.
return new ErrorEmailSender();
}
}
My solution is to create the final bean on my own inside a #javax.ws.rs.ext.Provider. Not as elegant as Micronaut #Requires, but well, it works.
Note that instance of SomeProvider is not a "bean", you have to care for the lifecycle on your own (dependency injection, PostConstruct, no PreDestroy, ...).
org.acme.SomeProvider.java
package org.acme;
import javax.enterprise.context.ApplicationScoped;
public interface SomeProvider {
void providerMethod();
#ApplicationScoped
class ProdProviderRequirement {
void foo() {}
}
class ProdProvider implements SomeProvider {
private final ProdProviderRequirement prodProviderRequirement;
ProdProvider(final ProdProviderRequirement prodProviderRequirement) {
this.prodProviderRequirement = prodProviderRequirement;
}
#Override
public void providerMethod() {
prodProviderRequirement.foo();
}
}
class DevProvider implements SomeProvider {
#Override
public void providerMethod() {}
}
}
org.acme.SomeProviderFactory.java
package org.acme;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.ws.rs.ext.Provider;
import org.acme.SomeProvider.DevProvider;
import org.acme.SomeProvider.ProdProvider;
import org.acme.SomeProvider.ProdProviderRequirement;
#Provider
class SomeProviderFactory {
SomeProvider someProvider;
#Inject
SomeProviderFactory(final ProdProviderRequirement prodProviderRequirement) {
final var someCondition = true;
someProvider = someCondition ? new DevProvider() : new ProdProvider(prodProviderRequirement);
}
#Produces
#ApplicationScoped
SomeProvider someProvider() {
return someProvider;
}
}

How to override class DefaultScreenNameValidator in liferay 7?

I am trying to override a class DefaultScreenNameValidator that implements ScreenNameValidator interface. For this , I copied the class and put it into another module. One change that I made is in annotation that is as follows:-
#Component(
property = {
"service.ranking:Integer=500"
}
)
I got a successful build using this. But when I tried to deploy the project, I got error as java.lang.NoClassDefFoundError: com/liferay/portal/kernel/security/auth/ScreenNameValidator.Can you suggest me how to eradicate this error. Thanx in advance..
I'm wondering, wouldn't it be better to instead create a module that also implements the ScreenNameValidator interface, and define your custom logic in there? Then you can just simply tell Liferay to use that validator instead of the DefaultScreenNameValidator.
For example, a minimalistic implementation:
import com.liferay.portal.kernel.security.auth.ScreenNameValidator;
import org.osgi.service.component.annotations.Component;
#Component(
immediate = true,
service = ScreenNameValidator.class
)
public class CustomScreenNameValidator implements ScreenNameValidator {
#Override
public boolean validate(long companyId, String screenName) {
// Your custom logic
}
}
make sure you have the dependency to portal-kernel in the build.gradle
dependencies {
compile 'com.liferay.portal:com.liferay.portal.kernel:2.0.0'
I made a screenNameValidator using blade-cli you can see the projet at https://github.com/bruinen/liferay-blade-samples/tree/master/liferay-workspace/modules/blade.screenname.validator
import com.liferay.portal.kernel.security.auth.ScreenNameValidator;
import org.osgi.service.component.annotations.Component;
import java.util.Locale;
#Component(
immediate = true,
property = {"service.ranking:Integer=100"},
service = ScreenNameValidator.class
)
public class CustomScreenNameValidator implements ScreenNameValidator {
#Override
public String getAUIValidatorJS() {
return "function(val) {return !(val.indexOf(\"admin\") !==-1)}";
}
#Override
public String getDescription(Locale locale) {
return "The screenName contains reserved words";
}
#Override
public boolean validate(long companyId, String screenName) {
return !screenName.contains("admin");
}
}

Xpages: How to access database from CacheBean

I have a cacheBean called PCConfig in which I want to store references to databases, so I can access them in other Java methods.
Here is the relevant part of my cacheBean:
package com.scoular.cache;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Vector;
import org.openntf.domino.utils.Factory;
import org.openntf.domino.xsp.XspOpenLogUtil;
import org.openntf.domino.Database;
import org.openntf.domino.Session;
import org.openntf.domino.View;
import org.openntf.domino.ViewEntry;
import org.openntf.domino.ViewNavigator;
public class PCConfig implements Serializable {
private static final long serialVersionUID = 1L;
private static Database PCDataDB;
// #SuppressWarnings("unchecked")
private void initConfigData() {
try {
loadStatus();
loadGeoLocations();
loadModels();
loadDatabases();
} catch (Exception e) {
XspOpenLogUtil.logError(e);
}
}
public PCConfig() {
initConfigData();
}
//Getters
public static Database getPCDataDB() {
return PCDataDB;
}
public static void setPCDataDB(Database dataDB) {
PCDataDB = dataDB;
}
public static void loadDatabases() {
loadPCDataDB();
}
public static void loadPCDataDB() {
Session session = Factory.getSession();
PCConfig.PCDataDB = session.getDatabase(thisDB.getServer(),"scoApps\\PC\\PCData.nsf", false);
}
}
}
In a different java class I import the PCConfig class and try to use this method getPCDataDB(). I have also tried PCConfig.PCDataDB.
I always get the error null pointer exception.
What am I doing wrong?
public void loadByUnid(String unid) {
try {
Document doc = PCConfig.getPCDataDB().getDocumentByUNID(unid);
if (null == doc) {
System.out.println("Document not found");
} else {
loadValues(doc);
}
} catch (Exception e) {
XspOpenLogUtil.logError(e);
}
}
You call the static method getPCDataDB(). As it is static you don't need to instantiate the class. But, your private field Database PCDataDB is not initialized at this point. This only happens if you instantiate the class. That's why you get the null pointer exception.
I guess PCConfig is a managed bean. It would get instantiated automatically if you call a non-static method in SSJS. So, remove all static in your class and it should work. If you want to use the class in Java then instantiate the class before calling getPCDataDB():
PCConfig pcConfig = new PCConfig();
Document doc = pcConfig.getPCDataDB().getDocumentByUNID(unid);
It is not recommended to keep Domino objects as class fields (like your Database PCDataDB) as they are not serializable. They might get recycled over the time especially if the class object resides in a long life scope like application scope. It is better to keep the data itself in fields or in your case database's server name and path so that you can open the database again when you need it.
BTW private Database PCDataDB should be private Database pCDataDB. The convention is that only class names and interfaces start with a capital letter.
As Knut says, storing the database in your static class won't work. Normally you would need to store the server and the database path as separate variables. But since you're using the OpenNTF Domino API, you can take advantage of Database.getApiPath() , which returns a "metaReplicaID" - a combination of servername and replica ID. You can store that and you have a direct reference to where the database resides. You can then use session.getDatabase(metaReplicaID) to retrieve the database when required.

TableView with different objects (javafx)

Im currently developing a application for watching who is responsible for different Patients, however i havent been able to solve how to fill a table with different object types.
Below is my code for my TableView controller. The TableView will end up with four different object typs, all will be retrieved from a database.
I want my table to hold Patient objects, User objects (responsible) and a RelationManager object.
Below is my code, if you need more of the code, please let me know :-).
package fird.presentation;
import fird.Patient;
import fird.RelationManager;
import fird.User;
import fird.data.DAOFactory;
import fird.data.DataDAO;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
/**
* FXML Controller class
*
* #author SimonKragh
*/
public class KMAMainFrameOverviewController implements Initializable {
#FXML
private TextField txtCPRKMAMainFrame;
#FXML
private TableColumn<Patient, String> TableColumnCPR;
#FXML
private TableColumn<Patient, String> TableColumnFirstname;
#FXML
private TableColumn<Patient, String> TableColumnSurname;
#FXML
private TableColumn<User, String> TableColumnResponsible;
#FXML
private TableColumn<RelationManager, String> TableColumnLastEdited;
#FXML
private TableView<RelationManager> tblPatients;
#FXML
private Button btnShowHistory;
#FXML
private TableColumn<?, ?> TableColumnDepartment;
/**
* Initializes the controller clas #FXML private Button btnShowHistory;
*
* #FXML private TableColumn<?, ?> TableColumnDepartment; s.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// Start of logic for the KMAMainFrameOverviewController
DataDAO dao = DAOFactory.getDataDao();
TableColumnCPR.setCellValueFactory(new PropertyValueFactory<Patient, String>("CPR"));
TableColumnFirstname.setCellValueFactory(new PropertyValueFactory<Patient, String>("Firstname"));
TableColumnSurname.setCellValueFactory(new PropertyValueFactory<Patient, String>("Surname"));
TableColumnResponsible.setCellValueFactory(new PropertyValueFactory<User, String>("Responsible"));
TableColumnLastEdited.setCellValueFactory(new PropertyValueFactory<RelationManager, String>("Last Edited"));
ObservableList<RelationManager> relationData = FXCollections.observableArrayList(dao.getAllActiveRelations());
tblPatients.setItems(relationData);
tblPatients.getColumns().addAll(TableColumnCPR, TableColumnFirstname, TableColumnSurname, TableColumnResponsible, TableColumnLastEdited);
System.out.println(tblPatients.getItems().toString());
}
}
relationData is a RelationManager object returned. This object contains a User object, a Patient object and a Responsible object.
Best,
Simon.
The exact details of how you do this depend on your requirements: for example, for a given RelationManager object, do the User, Patient, or Responsible objects associated with it ever change? Do you need the table to be editable?
But the basic idea is that each row in the table represents some RelationManager, so the table type is TableView<RelationManager>. Each column displays a value of some type (call it S), so each column is of type TableColumn<RelationManager, S>, where S might vary from one column to the next.
The cell value factory is an object that specifies how to get from the RelationManager object to an observable value of type S. The exact way you do this depends on how your model classes are set up.
If the individual objects associated with a given RelationManager never change (e.g. the Patient for a given RelationManager is always the same), then it's pretty straightforward. Assuming you have the usual setup for Patient:
public class Patient {
private StringProperty firstName = new SimpleStringProperty(...);
public StringProperty firstNameProperty() {
return firstName ;
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
// etc etc
}
then you can just do
TableColumn<RelationManager, String> firstNameColumn = new TableColumn<>("First Name");
firstNameColumn.setCellValueFactory(new Callback<CellDataFeatures<RelationManager,String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<RelationManager, String> data) {
return data.getValue() // the RelationManager
.getPatient().firstNameProperty();
}
});
If you are not using JavaFX properties, you can use the same fallback that the PropertyValueFactory uses, i.e.:
TableColumn<RelationManager, String> firstNameColumn = new TableColumn<>("First Name");
firstNameColumn.setCellValueFactory(new Callback<CellDataFeatures<RelationManager,String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<RelationManager, String> data) {
return new ReadOnlyStringWrapper(data.getValue().getPatient().getFirstName());
}
});
but note that this won't update if you change the name of the patient externally to the table.
However, none of this will work if the patient object associated with the relation manager is changed (the cell will still be observing the wrong firstNameProperty()). In that case you need an observable value that changes when either the "intermediate" patient property or the firstNameProperty change. JavaFX has a Bindings API with some select(...) methods that can do this: unfortunately in JavaFX 8 they spew out enormous amounts of warnings to the console if any of the objects along the way are null, which they will be in a TableView context. In this case I would recommend looking at the EasyBind framework, which will allow you to do something like
firstNameColumn.setCellValueFactory( data ->
EasyBind.select(data.getValue().patientProperty())
.selectObject(Patient::firstNameProperty));
(EasyBind requires JavaFX 8, so you if you get to use it, you also get to use lambda expressions and method references :).)
In either case, if you want the table to be editable, there's a little extra work to do for the editable cells in terms of wiring editing commits back to the appropriate call to set a property.

xe:objectData - Object has been removed or recycled

I use an xe:objectData as a datasource for a xp:dataTable. objectData1 uses some Java code to retrieve all documents from a view that match a key ( username ). The Java code looks like this:
package com.isatweb.cois;
import static com.ibm.xsp.extlib.util.ExtLibUtil.getCurrentDatabase;
import static com.ibm.xsp.extlib.util.ExtLibUtil.getCurrentSession;
import java.io.Serializable;
import lotus.domino.Database;
import lotus.domino.Name;
import lotus.domino.Session;
import lotus.domino.View;
import lotus.domino.ViewEntryCollection;
public class ObjectDataVisits implements Serializable {
private static final long serialVersionUID = 1L;
ViewEntryCollection vec = null;
public ObjectDataVisits(){
try {
this.update();
} catch (Exception e) {
System.out.print(e);
}
}
public void update() {
try {
Database _db = getCurrentDatabase();
Session _session = getCurrentSession();
Name nam = _session.createName(_session.getEffectiveUserName());
String username = nam.getAbbreviated().replace(" ", "#").replace("/", "#").toUpperCase();
View view = _db.getView("vw_visit_open");
this.vec = view.getAllEntriesByKey(username);
} catch (Exception e) {
System.out.print(e);
}
}
public ViewEntryCollection getVisits(){
return this.vec;
}
}
The XPage has the following code
When I first load the page, the data is read from the wiew and the dataTable displays the NoteIDs of all matching documents.
When I refresh the page using the button, I get an "Object has been removed or recycled" error.
Can anyone pls. show me what I'm doing wrong? ( and perhaps, how to do it right )
The problem is, that Notes objects are not serializable. During the partial refresh the getVisits() method is executed before the update() method. The ViewEntryCollection is a references to a view, and this view is already recycled.
If you just want to store some note id's then you could store them in a Vector instead. Otherwise you have to call your update() method in your getVisits() method everytime.

Resources