we have a Java EE application with primefaces and we are wondering if there's a way to have a "global" application variable.
I mean: imagine user1 is editing document1, when user2 try to access document1 we'd like to show a message: "User1 is already editing this document".
So, we have to use something "global" for keep track of user action or document locking and so on, what's the best way to achieve this?
I've search the internet but opinion differs and generally no working examples are provided, so link and pointer are welcome!
EDIT: the above is just an example, please not focus on "documents", you can call it "resources", or whatever you like. I've used the document lock problem as an example, but it can be a total counter or something else that need to be stores at application level.
What I'm asking (and sorry if it was not clear) is not how to manage document locking, but what's the best way to have a "global" variable at application level in Java EE, if it's possible.
Thank you
Just curious: why if I add "hola," or "hi," as first line it disappear when I save the edit?
If you want to save something globally, in Java EE 6+ it should use the Application Scope
http://docs.oracle.com/javaee/6/api/javax/enterprise/context/ApplicationScoped.html
For example:
#ApplicationScoped
class Global {
void setDocInUse(boolean) { ... }
boolean isDocInUse() { ... }
}
#RequestScoped
class MyDocEditor {
#Inject Global global;
public void edit() {
if (global.isDocInUse()) { ... }
else { ... }
}
}
For most simple cases you can use a static field inside your managed beans for that purpose because it will be shared by all the instances of your managed bean. For example, let us imagine that to edit documents you users interact with the following bean:
#ManagedBean
#ViewScoped
public class DocumentManager {
private static Map<Long, String> editedDocs = new HashMap<>();
private Document selectedDoc;
}
Then let us imagine that after users have selected the document (for example from the dataTable so that it gets into the selectedDoc field) they get the document editing page by clicking on a button which action attribute points to the method editDocument like this:
then in your editDocument method we add the document's id and username of the user that clicked on the button to the mapping that tracks presently edited documents.
public String editDocument() {
if (!editedDocs.contains(selectedDoc.getId())) {
String username = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal().getName();
editedDocs.put(selectedDoc.getId(), username);
String msg = "User " + username + " is already editing the document";
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg));
}
return theAddressOfEditDocumentPage;
}
Please do not forget to delete the document id and the username from the editedDocs when the user leaves the edit page (by clicking Save or Cancel buttons).
Another possibility is to store such mapping externally (e.g. in the database)
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 10 months ago.
The community is reviewing whether to reopen this question as of 9 months ago.
Improve this question
I have a project that was started and orchestrated by someone wayyyyyy more talented than I, and I've hit a point that I can't figure how to bridge.
This is a Java/JavaFX/Spring Boot project, and NOT a Swing project. I see a lot of answers re: Swing. Both applications are also set up in Gradle, so both applications have their own separate ./gradlew bootRun commands and are running in CentOS 7. Both applications have their own, separate, main() methods. I believe the original design was intended, purposefully, to remove any access to the data from the GUI, entirely, which is the reason for the separation. I'm just having a tough time finding a way to pass necessary data back and forth.
There are separate applications that are designed to work together.
**Kiosk** which houses the GUI elements and GUI-related controllers
**Governor** which houses an API and an APP application. The API, as of now, is helping with Source and File interfaces. The APP houses an H2 database (all stored from JSON files, but the content is irrelevant for this particular question), a User package (which houses the User data that feeds the H2 database), and a Source package (which does all the files methods)
What I want to do is:
Get the username and password, supplied by the user at the **Kiosk** level, and pass that somehow into the **Governor**.
Once I can pass the data, I know how to do the rest, to check against the db and verify if the user has valid credentials or not, etc.
Once I have a boolean value (let's call id validUser), I want to pass that information back from the **Governor** to the **Kiosk**, and I can move on from there.
I don't have any code to copy and paste, so I am hoping that the description above is enough to point me in the right direction. I have tried googling all over for "pass data between separate java applications", "separate gui and logic java application", and everything you can think of, but I've hit a wall.
I'm happy to provide any other information you might need, and I'm not looking for anyone to write the code for me, but if you have any examples you've seen, or a concept I may not be familiar with that would help me pass this data back and forth, I would be eternally grateful!
*** Edit *** Trying to add MVP as best I can. Hopefully everything needed to answer question above can be gleaned from below.
Kiosk/LoginController
#Component
public class LoginController extends Controller {
#FXML
TextField username;
#FXML
TextField password;
#FXML
Button loginButton;
#FXML
public void tryLogin() {
UserServices userServices = new UserServices();
String usernameEntered = username.textProperty().getValue();
String passwordEntered = password.textProperty().getValue();
userServices.validateUser(usernameEntered, passwordEntered);
// ... other non-related methods re: tryLogin()
}
}
Kiosk/UserServices
public class UserServices {
public boolean validateUser(String username, String password) {
// **** How do I pass the args (username and password) to Governor?
if (!userFound) {
return false; // user not found, deny entry
}
return true; // allow entry
}
}
}
Governor/API/FileEntry
Note: This file is only a sample of an API module interacting with KIOSK--I do not understand this completely--again, doing the best I can with my limited resources; I believe I need to create my own API User module, but unsure how to proceed)
#JsonDeserialize(as = DefaultFileEntry.class)
public interface FileEntry {
Path getPath();
boolean isDirectory();
#JsonIgnore
default Optional<String> getName() {
if (getPath().getFileName() == null) {
return Optional.empty();
} else {
return Optional.of(getPath().getFileName().toString());
}
}
}
Governor/APP/UserRepository
public interface UserRepository extends JpaRespository<User, String> {
User findByUsername(String username);
}
Governor/APP/UserService
#Service
public class UserService {
private UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// SQL methods to create database, if necessary, search, create, update, and delete users
}
There are several ways to for applications to share data with one another:
JMS, AMQ, or some other messaging system.
A shared database where applications poll for changes.
Open up a REST endpoint that each application can call to update each other. Be sure to secure with certs so outsider can't use them.
I have 3 classes, Main, Pin, and Employee. (More classes to be added in the future)
The Main class runs a program that prompts use to enter an password from a method in the Pin class. The password is sent using SQL to a database to be verified from methods in the Employee and Pin classes. If the password matches, it returns back the ID of that employee.
The problem I am having is saving the ID. I retrieved the ID, but I want to be able to use this ID for the rest of the program. I want to save it in the Employee class but it is returned in a method from the Pin class. How would I be able to save this ID to be used by the Employee class, or any class?
Hmm, if I understand you correctly you may want something like a composition of Employee and Pin?
Employee e = ...
e.setPin(pin);
Or is the problem, that you don't know how to assign a specific pin to an Employee, so that it is still assigned to the Employee in the next run of your application?
UPDATE: After receiving more information: You need to create an application context for your program. As it seems to be a standalone application with one user at a time, this can be a static field in some class.
If the application is a multi-user application, then the context needs to be static per user.
If the application is a web-application, then your application scope is the Session, that will be terminated during Logout. (That is actually not precise, as the session is the session scope, and the application scope is really the context of the application. But in your case, the pin is session scoped.)
A sample for a standalone/single user application:
public class ApplicationContext {
static ApplicationContext CTX;
public static ApplicationContext get() {
if( CTX == null ) {
CTX = new ApplicationContext();
}
return CTX;
}
private Pin pin;
public Pin getPin() { return pin; }
public void setPin(Pin pin) { this.pin = pin; }
// ... add more stuff here ...
public void logout() {
CTX = null;
}
}
What you need is a concept of a so called application scoped object.
There are various libraries that work with JavaEE but I assume you're using Java SE.
DeltaSpike of apache allows to do such scoped beans within Java SE, too. See an example. Like this, you can create an #ApplicationScoped bean where you can store values across your application.
Please know that there are other scopes possible, such as SessionScoped(HTTP), WindowsScoped(BrowserWindow) etc.
This example shall point you to the right direction but there might be better approaches than to use the application scoped in your case.
I'm trying to create a simple crud form to insert data into a database with hibernate, without knowing what the object type is. The ultimate goal is to only have one insert form for every table in the database. So far i get the methods that the current object has, check to see if it has any set methods and create a text input for every field that has a set.
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
HtmlPanelGrid hpg = (HtmlPanelGrid) viewRoot.findComponent("panel");
for (Method method : declaredFields) {
String name = method.getName();
if (name.contains("set")) {
HtmlOutputText hot = new HtmlOutputText();
HtmlInputText hit = new HtmlInputText();
hot.setValue(name.substring(3));
try {
hit.setValue(newObject.getClass().getMethod(name, String.class));
} catch (Exception ex) {
Logger.getLogger(ReflectController.class.getName()).log(Level.SEVERE, null, ex);
}
hpg.getChildren().add(hot);
hpg.getChildren().add(hit);
}
}
Here newObject is the object that is going to be inserted into the database later with hibernate. My problem is this:
How do assign a certain field from that object to the text input that is being created at the moment. So far if I put the method in the value like I'm doing above, it will just print out the method in the value attribute for that input. what i want is that when this form is submited, for to assign the value in that text box to the property with that name.
I can give you a partial answer - You need to create a ValueExpression dynamically
Application app = FacesContext.getCurrentInstance().getApplication();
hit.setValueExpression("value", app.getExpressionFactory().createValueExpression(FacesContext.getCurrentInstance().getELContext(), "#{bean.item}", Item.class));
The hard part will be creating the valueExpression that will actually map to a field within your object's value. That requires a great deal more thought but you will for sure need the dynamic valueExpression. As written, this will result in the execution of your bean's setItem();method with a parameter of type Item. You will require something a little more complex.
In JSF, binding input components to properties is accomplished with EL-expressions. You can create one programmatically as Steve shows, but that syntax is really ugly. On a related note, programmatic manipulation of the component tree is a rather unorthodox way of using JSF. The orthodox way to tackle your requirement would be something like:
<ui:repeat var="prop" value="#{genericEditorBean.propertyNames}">
<h:outputLabel value="#{prop}" for="input"/>
<h:inputText id="input" value="#{genericEditorBean.object[prop]}"/>
</ui:repeat>
where
public List<String> getPropertyNames() {
List<String> propertyNames = new ArrayList<>();
BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
propertyNames.add(pd.getName());
}
return propertyNames;
}
(There really is no reason to reimplement scanning for Java Bean properties when the Java API offers a class for that very purpose. Unlike your home-grown version, this will also handle properties inherited from a super class ...)
I once used an open-source library named MetaWidget to do this.
It was a few years ago, but it worked well and was easy to set up.
It looks like the project is still active:
http://metawidget.sourceforge.net/index.php
1) i have added an element in request object given below, i need to get/read this in my webpage, how can i do it?
<input type="hidden"> wicket:id="submitted" value="false" />
eg: in servlet, use request.getParameter("submitted") from hidden session.
2) in my controller class i want to set the value in session or hidden field, so that i can identify the user if he already processed the request or enetered my block of code.
1) use HiddenField
2) use a custom WebSession object:
public class MySession extends WebSession{
public Mysession(Request request){super(request);}
private boolean completedRegistration;
public boolean hasCompletedRegistration() {
return completedRegistration;
}
public void setCompletedRegistration(boolean completedRegistration) {
this.completedRegistration = completedRegistration;
}
}
I am not sure I have fully understood your questions.
But to make it short, if you want to get the value stored in your request object, you'll need to make the model of your input map to this value (by using HiddenField wicket internal class).
If you want to track your user, the best thing to do is looking around for a cookie set on the client side that'll allow you to manage its visits.
Please refine your question if you want a more precise answer...
I have to warn you: the question may be rather silly, but I can't seem to wrap my head around it right now.
I have two managed beans, let's say A and B:
class A
{
private Date d8; // ...getters & setters
public String search()
{
// search by d8
}
}
class B
{
private Date d9; //...getters & setters
public String insert()
{
// insert a new item for date d9
}
}
and then I have two JSP pages, pageA.jsp (the search page) and pageB.jsp (the input page).
What I would like to do is placing a commandbutton in pageB so to open the search page pageA passing the parameter d9 somehow, or navigating to pageA directly after b.insert(). What I would like to do is showing the search result after the insertion.
Maybe it's just that I can't see the clear, simple solution, but I'd like to know what the best practice might be here, also...
I though of these possible solutions:
including **A** in **B** and linking the command button with **b.a.search**
passing **d9** as a **hiddenInput** and adding a new method **searchFromB** in **A** (ugly!)
collapsing the two beans into one
JSF 1.1/1.2 raw doesn't provide an easy way to do this. Seam/Spring both have ways around this and there are a couple of things you can do. JSF 2 should also have solutions to this once it is released.
Probably the easiest and most expedient would be to collapse the two beans into one and make it session scoped. The worry, of course, is that this bean will not get removed and stay in session until the session times out. Yay Memory leaks!
The other solution would be to pass the date on as a GET parameter. For instance, you action method could call the
FacesContext.getCurrentInstance().getExternalContext().redirect("pageB?d9=" + convertDateToLong(d9));
and then get the parameter on the other side.
You should configure the navigation flow in faces-config.xml. In ideal scenario you would return a "status" message which would decide the flow. Read more at following link:
http://www.horstmann.com/corejsf/faces-config.html
http://publib.boulder.ibm.com/infocenter/rtnlhelp/v6r0m0/index.jsp?topic=/com.businessobjects.integration.eclipse.doc.devtools/developer/JSF_Walkthrough8.html
As far as passing the values from one page to another is concerned you can use backing beans. More about backing beans here:
http://www.netbeans.org/kb/articles/jAstrologer-intro.html
http://www.coderanch.com/t/214065/JSF/java/backing-beans-vs-managed-beans
Hope i have understood and answered correctly to your question
Way to share values between beans
FacesContext facesContext = FacesContext.getCurrentInstance();
Application app = facesContext.getApplication();
ExpressionFactory elFactory = app.getExpressionFactory();
ELContext elContext = facesContext.getELContext();
ValueExpression valueExp = elFactory.createValueExpression(elContext, expression, Object.class);
return valueExp.getValue(elContext);
In above code "expression" would be something like #{xyzBean.beanProperty}
Since JSF uses singleton instances, you should be able to access the values from other beans. If you find more details on this technique, I am sure you'll get what you are looking for.
Add commandButton action attribute referencing to B'insert method
<h:commandLink action="#{b.insert}" value="insert"/>
In B'insert method,add d9 parameter as request parameter. Then return an arbitrary string from insert method.
FacesContext fc = FacesContext.getCurrentInstance();
fc.getExternalContext().getRequestMap().put("d9", d9);
Then go to faces context and add navigation from B to A with "from-outcome" as the arbitrary String you returned from insert method. But don't add redirect tag to navigation tags as it will destroy the request coming from B and the parameter you added (d9) will be cleared.
<from-outcome>return string of insert method</from-outcome>
<to-view-id>address of A</to-view-id>
Then you might get the "d9" in A class by fetching it from request map at its constructor or in a place where its more appropriate (getters). You might add it into a session scope or place it to a hidden variable if you want to keep track of it later.
in class A, when page is navigated, A should be initialized as it will be referenced.
FacesContext fc = FacesContext.getCurrentInstance();
fc.getExternalContext().getRequestMap().get("d9", d9);
Sorry i cant give full code, as i have no ide at here, its internet machine at work. I could not give details therefore.
In my opinion, the simplest way is 3-rd option - have both query and insert methods in same class. And you can do something like that:
public String query () {
//...
}
public String Insert() {
//insert
return Query(); }
If your classes are managed Beans you can load class A from class B and call A.query() in your insert method at the end. Also class A can have
<managed-bean-scope>session</managed-bean-scope>
parameter in faces-config.xml and it wouldn't be instantiated again when loaded.