Passing Parameter From One Method To Another - java

I have a rather silly question, I need to pass a parameter from one method to another method.
I have the following method
public String test(Employees emp)
{
return emp.getempno();
}
I need to pass emp.getempno() to my another method loadDetails();
My problem is I cannot add an argument in loadDetails() method because I am calling this method in couple of other places.
How can I achieve this? I tried putting emp.getempno() in collecion object but problem is test(Employees emp) methood is not being invoked in my second method.
Excuse me for my ignorance, any help is highly appreciable.
Thanks
Update 1
This is how I assign value to test method and getTestValues method is being called from another class when I pass parameter from one page to another.
public void getTestValues(List<Employees> paramList) {
for (Employees dataItem: paramList) {
test(dataItem);
}
}
Update 2
This is my loadDetails() method where I am fetching db values and to display as datatable in jsf page.
private void loadDetails() {
try {
dataDetails = anotherclass.deptDetails(passempno);
} catch (Exception e) {
e.printStackTrace();
logger.error("error from loadDetails" + e.getMessage());
}
}

Basically what I am trying to do is when I click a row in a datatable I would like to pass that row's primary key to second page's bean class so that I could populate datatable in second page.
JSF 1.1 and would like to pass as POST GET with commandlink outputlink in datatable.
Use the following (assuming JSF 1.1):
EmployeeBacking
public class EmployeeBacking {
private List<Employee> list;
public EmployeeBacking() {
list = employeeService.list();
}
// ...
}
employees.jsp
<h:dataTable value="#{employeeBacking.list}" var="employee">
<h:column>
<h:outputText value="#{employee.name}" />
</h:column>
<h:column>
<h:outputLink value="departments.jsp">
<h:outputText value="Show departments" />
<f:param name="employeeId" value="#{employee.id}" />
</h:outputLink>
</h:column>
</h:dataTable>
DepartmentBacking
public class DepartmentBacking {
private Long employeeId;
private List<Department> list;
private void load() {
list = departmentService.list(employeeId);
}
public List<Department> getList() {
if (list == null) load();
return list;
}
// ...
}
(please note the lazy loading in getter, in JSF 1.2 you could better use #PostConstruct method for this)
departments.jsp
<h:dataTable value="#{departmentBacking.list}" var="department">
<h:column>
<h:outputText value="#{department.name}" />
</h:column>
</h:dataTable>
faces-config.xml
<managed-bean>
<managed-bean-name>employeeBacking</managed-bean-name>
<managed-bean-class>com.example.EmployeeBacking</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>departmentBacking</managed-bean-name>
<managed-bean-class>com.example.DepartmentBacking</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>employeeId</property-name>
<value>#{param.employeeId}</value>
</managed-property>
</managed-bean>
What happens here, the outputlink will navigate to departments.jsp with the current employee ID as request parameter and the <managed-property> in faces-config.xml will set it in the department backing and finally the getter on the list will lazily load the right departments based on the employee ID.

OK, I'm still trying to wrap my head around this, but I think it's becoming a bit clearer. In order to make loadDetails() function properly, you need to know an employee number (shown above in passempno). I have two responses:
Best case, it appears that passempno is really a parameter of the loadDetails() method. I.e., the value of passempno is part of the method's behavior. As such, the strongly preferred option is to simply add the employee number as an argument. You state that you don't want to do this because other places are using it -- how are the other clients of the method using it without having an employee number specified?
If this is part of some non-trivial state of the parent class, then possibly you need to sock away the employee number in a field of the object. This is less than desirable because it's hiding (or at least making implicit) important state that loadDetails() needs to function.
If there is a stateful interaction with the backing database, and the employee number here is a piece of that state, I'd recommend factoring out the state of the database interaction into a subsidiary class that holds the employee number and any other state (as suggested in 2 above).
Let me know if this helps; if not... let me know what I missed.

I work on an ERP software for a living. Your LoadDetails method shouldn't take an Employee as a parameter.
I'm assuming loadDetails is on a Load class, and that you have an Employee who scheduled the load, or filled the load. If that's the case, the Load class should have a reference to that Employee from creation time.

Related

How to correctly call method from jsf to ManagedBean

well I'm learning jsf/hibernate and I'm having trouble understanding how to correctly call methods to my ManagedBean
its a simple CRUD so I need to pass vía the jsf form a Ciclista object, but since the inputs are Ciclista attributes how do I pass the Object ? (how to create instance of it) here's the code:
#Override
public String create(Ciclista c) {
Session s = sFac.openSession();
s.beginTransaction();
s.save(c);
s.getTransaction().commit();
s.close();
return "Administrador?faces-redirect=true";
}
and jsf form:
<h:form class="form">
<div id="input-wrapper">
<h:inputText class="inputs" value="#{ciclistaBeanDB.nombre}" />
<h:inputText class="inputs" value="#{ciclistaBeanDB.nacionalidad}" />
<h:inputText class="inputs" value="#{ciclistaBeanDB.equipo}" />
</div>
<h:commandButton class="btn" action="#{ciclistaBeanDB.create()}" value="Create" />
</h:form>
I get error: method not found because i don't pass the Ciclista c object in crear(//here)
since i don't have the object per se, just its attributes how do I proceed ??
You are getting the MethodNotFoundException, because you wrote crear instead of Create.
But the right way to do it, would be to call a save() method without arguments, which is responsible to assemble your object you want to persist.
Since you are already binding your input fields to bean properties, all you would need to do is, use a method like this:
public String save(){
Ciclista c = new Ciclista();
c.setNombre(this.nombre);
c.setNacionalidad(this.nacionalidad);
c.setEquipo(this.equipo);
create(c);
return "Administrador?faces-redirect=true";
}
your commandbutton now should target the save() method of your bean. The input values in the form will be inserted into your baking bean properties and the save() method would assemble the instance and finally calls your persist-method.
<h:commandButton class="btn" action="#{ciclistaBeanDB.save}" value="Create" />
Usually you should not call the DatabaseBean directly, but kind of a Controller - or how ever one would like to call it. This Bean then should utilize your database-service which should only be responsible for CRUD-Functionality.
At least for big applications it would be a mess having the databasemethods and other (view-related) methods mixed in one class.

JSF: rich datatable filtering, dynamic columns, and passing arguments

I'm working on a rich:datatable on a JSF page. The table can get pretty big and is paged with a rich:datascroller. Most of the columns are hardwired and will always be there, but then there are some optional columns based on additional values that need to be generated for each potential additional value. I've been able to make this happen easily enough. However, I'm running into a problem with filtering.
I'm using a filter on each column. It's placed in the header with the column label and sorting function. That much is working fine on each column, but I'm hitting a snag on filtering due to the way filtermethod works by default. Here's a quick example:
<rich:datatable id="thetable" value=#{backingBean.stuff} var="b">
<!-- First column, standard filter method, works just fine -->
<rich:column sortBy="#{b.field1}" filterMethod="#{filterBean.filterField1}">
<f:facet name="header">
<ui:fragment>
<h:outputText value="Field 1" />
<h:inputText value="#{filterBean.filterMap['Field1']}" />
</ui:fragment>
</f:facet>
#{b.field1}
</rich:column>
<c:forEach items="#{backingBean.extraStuff}" var="e">
<rich:column sortBy="#{b.getExtra(e)}" filterMethod="???">
<f:facet name="header">
<ui:fragment>
<h:outputText value="#{b.getExtra(e).description}" />
<h:inputText value="#{filterBean.filterMap['b.getExtra(e).code']}" />
</ui:fragment>
</f:facet>
#{b.getExtra(e).description}
</rich:column>
</rich:datatable>
The ??? will be covered shortly. As for the filter bean:
public class FilterBean {
public Map<String, String> filterMap = new HashMap<String, String>();
public boolean filterField1(Object current){
return ((BackingBean) current).contains(filterMap.get("Field1"));
}
}
It's fairly straightforward. The filter inputText binds to a preset string in the hashMap, which is retrieved in the method and used to filter so I don't need a separate field for every filter. This is working great, but I still need a separate method for each filter, which brings me to the ??? in the JSF code...
What I'd like to do is pass arguments to the filter method to account for the dynamic columns. In fact, I'd like to simplify the whole class with a single filter method and pass the mapped String in along with the field from the current object. However, this isn't working. I've tried:
filterMethod="#{filterBean.filterStuff(b, 'Field1')}"
but I wind up getting the filter string just fine, but null for the current object. I'm not sure what's going on. If I'm reading the dependencies in the project correctly, I'm using some pretty old versions of EL, JSF, JSP, etc, and I really have no way of changing that. The project does use Seam, though, and I've passed arguments successfully in EL before in this project. Is it just that EL 2.2 supports passing objects while older versions only supported primitives and Strings? Is there any way for me to make this happen or am I stuck without building a ton of extra stuff from the ground up?
Okay, looks like this might be possible with Seam, but it doesn't like iteration variables. I CAN pass the object if I refer to an index in the List from the backing bean, but that doesn't help as I have no way of telling it to search every row...
My use case is a bit different, but basically I had the same problem and found a working solution.
The use case: I have several XHTML-files with their backing-beans all offering a table with a list of entities of different types. In this table there are several columns for some attributes of the entities with the possibility to filter. Since the built-in filter does only a "starts-with" search and I need a more advanced one, I have to use the filterMethod.
But I did not want to mess up my backing-beans with hundreds of simple filter-methods doing all exactly the same (only with different attributes). So I was looking for a more generic way - and this is my approach:
In the backend, I created a new class named FilterMethodWrapper (for easier understanding I put it as nested static class here) and a method to access it:
import org.apache.commons.beanutils.PropertyUtils;
public class BackendBean
{
private String[] filterValues;
// initialize filterValues somewhere, add getter and setter
public static class FilterMethodWrapper
{
private final String fieldName;
private final String filterValue;
public FilterMethodWrapper(final String fieldName, String filterValue)
{
this.fieldName = fieldName;
this.filterValue = filterValue;
}
public boolean doFilter(Object current) throws ...
{
final String stringValue = (String) PropertyUtils.getSimpleProperty(current, fieldName);
// compare stringValue and filterValue somehow (e.g. contains)
// and return result
}
}
public FilterMethodWrapper getFilterMethodWrapper(String fieldName, int filterValueIndex)
{
return new FilterMethodWrapper(fieldName, getFilterValues()[filterValueIndex]);
}
}
And in the XHTMLs use it as follows:
<rich:column filterMethod="#{backendBean.getFilterMethodWrapper('username', 0).doFilter}" filterEvent="onkeyup" >
<f:facet name="header">
<h:panelGrid style="display:inline;">
<h:outputText value="Username"/>
<h:inputText value="#{backendBean.filterValues[0]}" />
</h:panelGrid>
</f:facet>
<h:outputText value="#{_item.username}" />
</rich:column>
Edit: I'm using JSF 1.2 and RichFaces 3.3.3.Final
Edit2: instead of writing the FilterMethodWrapper you could also use some Predicate-implementation and use the apply-method in the frontend (or you write your own Predicate-implementation according to this proposal which is more reusable than this FilterMethodWrapper)

Why Set doesnt work in web flow and Primefaces

I get call in a flow a method which returns a HashSet of Person back. Then i call the Set in my xhtml file with the Primeface-dataTable. Now i want to display the prename of the person, but a error appear and say, he doesn't found "prename"...
Then i put the HashSet in a ArrayList and do the same. And... it works fine! But why?
Set and List use as Superinterfaces Collection & Iterable. So why this don't work with Set?
Here are the parts of the files:
flow.xml
<view-state id="rcpm" view="rc/rcmembers.xhtml">
<on-entry>
<evaluate expression="RCHtmlCache.getCommunityList('rcpm')"
result="flowScope.members" />
</on-entry>
</view-state>
rcmembers.xhtml
<p:dataTable id="table1" var="member" value="#{members}"
sortMode="multiple" rowIndexVar="status"
emptyMessage="The Community is empty.">
<p:column>
<f:facet name="header">
<h:outputText value="Vorname" />
</f:facet>
<h:outputText value="#{member.vorname}" />
</p:column>
RCHtmlCache.java Set Version
public Set<Person> getCommunity(String key) {
return htmlCache.get(key);
}
RCHtmlCache.java List Version
public List<Person> getCommunityList(String key) {
Set<Person> comList = htmlCache.get(key);
ArrayList<Person> result = new ArrayList<Person>();
for (Person person : comList) {
result.add(person);
}
return result;
}
Hope you can explain me this weird incident...
It is just a hint, but I think PrimeFaces only accept the List interface, hence you can't use Set interface, they are not the same.
You may create your own List + Set Adapter class by using the Adapter Pattern. It may suit very well to your problem, since you want to adapt the Set interface to a List interface. If you do so, then you won't need to convert your Set to a List every time.
Take a look at this: http://en.wikipedia.org/wiki/Adapter_pattern
Hope I could help.
DataTable works with DataModels...and DataModels only supports:
* java.util.List
* Array of java.util.Object
* java.sql.ResultSet (which therefore also supports javax.sql.RowSet)
* javax.servlet.jsp.jstl.sql.Result
* Any other Java object is wrapped by a DataModel instance with a single row.
(The above objects are implicitly used to build a DataModel)
See JSF Specification.

<h:commandButton> doesn't start the action - NO IDEA?

I'm trying to use dataModel instead of binding dataTable and have this issue. At the last column there is a commandButton which should be used for delete item from database. But when I press it, the java method isn't started.
Part of xhtml (reduced code):
<h:form>
<rich:extendedDataTable
id="table"
var="fItem"
value="#{myFood.model}"
selectionMode="none">
<rich:column width="150px">
<f:facet name="header">Datum:</f:facet>
<h:outputText value="#{fItem.date}"/>
</rich:column>
<rich:column>
<h:commandButton id="save" action="#{myFood.delete}" value="delete"/>
</rich:column>
<f:facet name="footer">
<h:commandButton id="btnTest" action="#{myFood.test}" value="test"/>
</f:facet>
</rich:extendedDataTable>
</h:form>
Part of MyFood.java:
public void delete()
{
System.out.println("TEST");
try
{
DaoCrud.delete(model.getRowData(), 'P');
}
catch (Exception e) {.....}
}
public void test()
{
System.out.println("TEST");
}
But even "TEST" is not writen to console!
Where could be the problem?
UPDATE: I've updated code examples (facet & test()), it works. Everything works fine until I've tried using dataModel private DataModel<Item> model;...
When I simply move the same commandButton to the facet, it works.
If the bean is request scoped, then you need to ensure that exactly the same model is been created during bean's (post)construction of the form submit request as it was during displaying the initial form.
private List<Item> list;
private DataModel<Item> model;
#PostConstruct
public void init() {
list = itemService.list();
model = new ListDataModel<Item>(list);
}
JSF will namely iterate over the model during the apply request values phase to determine the button pressed so that it can be invoked during the invoke application phase.
If preserving the model in the subsequent request isn't exactly trivial due to some business restrictions (e.g. missing parameters, etc), then you need to put the bean in the view scope by marking it #ViewScoped instead of #RequestScoped. This works only if you're using JSF 2.0.
#ManagedBean
#ViewScoped
public class MyBean {}
Alternatively, since you're using RichFaces, you could also use <a4j:keepAlive> for this. Put this somewhere in the same page as the form:
<a4j:keepAlive beanName="#{myBean}" />
This does effectively the same as #ViewScoped does in JSF 2.0.
It should be under <h:form>
Your delete() method should return an Object. It won't be called if the signature is not correct. "signature must match java.lang.Object action()". See here.
As far as I remember you can just return null if you want to stay at the page.
public String delete()
{
System.out.println("TEST");
try
{
DaoCrud.delete(model.getRowData(), 'P');
}
catch (Exception e) {.....}
return null;
}
You might want to use the actionListener attribute with its corresponding method if you dont want to use the method outcome for navigation. Also consider to use a <a4j:commandButton> if you want to reRender something after the actionListener has been executed.

Recurring JSF problem

I have a recurring JSF problem everytime I output datatables or composite components using ui:repeat. Suppose you are displaying a list of users, and in one column you have 3 icons, one to view the full profile, another to delete the user, and another to edit his data. Since i can't do something like #{fooBean.delete(user)} how should I handle this?
Here's they layout I'm talking about:
http://img821.imageshack.us/img821/9039/tablev.png
I can use commandLink to invoke logic but how do I get the user or article or product etc.
Is there any non-hackish way?
If you're using a dataTable, you can bind the dataTable component to the backing bean and figure out which row was clicked.
<h:dataTable binding="#{backingBean.userTable}" value="#{backingBean.users}" var="user"> ... </h:dataTable>
and
<h:commandLink actionListener="#{backingBean.deleteLinkClicked}">Delete</h:commandLink>
Then the backing bean:
public class BackingBean implements Serializable {
private HtmlDataTable userTable;
// implement getter/setter for userTable
public void deleteLinkClicked(ActionEvent event) {
User user = (User)userTable.getRowData();
// implement code to delete user
}
}
When using ui:repeat, I don't know the best practice, but I've used f:param to pass a parameter in the link. Below is the ui:repeat equivalent of the above.
<ui:repeat value="#{backingBean.users}" var="user">
<h:commandLink value="Delete" action="#{backingBean.deleteUser}">
<f:param name="userId" value="#{user.id}">
</h:commandLink>
</ui:repeat>
In the backing bean:
public class BackingBean implements Serializable {
#ManagedProperty(value="#{param.userId}")
private Long userId;
// implement getter/setter for userId
public String deleteUser() {
// at this point, the userId field should have been set via the param
}
}
I think that you could use an actionListener instead of an action (as I did in the dataTable example), but I haven't tried it.

Categories