invoke confirmDialog in bean - jsf-2

I use Primefaces 5.1 with JSF 2.2.6.
i need identify if one file already exists in folder when user fileupload (primefaces).
I have a class that uses PrimeFaces which uploads user files to a particular folder, but if the user attempts to upload a file with the same name as one that is already present i need alert and cancel the handler.
Any idea?
the code in xhtml is:
<h:form enctype="multipart/form-data" id="addFileDialog">
<p:fileUpload fileUploadListener="#{attachmentsComponent.handleFileUpload}"
mode="advanced" multiple="true" dragDropSupport="true"
label="#{text['tasksbacking.addFile.choose']}" uploadLabel="#{text['tasksbacking.addFile.upload']}" cancelLabel="#{text['tasksbacking.addFile.cancel']}"
allowTypes="/(\.|\/)(gif|jpe?g|png|pdf|doc|docx|txt|xml)$/" invalidFileMessage="#{text['tasksbacking.addFile.invalidFile']}"
fileLimit="4" fileLimitMessage="#{text['tasksbacking.addFile.invalidCount']}"
oncomplete="PF('addfile').hide();"/>
</h:form>
the code in bean is:
public void handleFileUpload(FileUploadEvent event) {
// vars
String originalName = event.getFile().getFileName();
if (log.isDebugEnabled()) {
log.debug("create file: " + originalName);
}
User loggedInUser = getSessionUser();
// define parent folder
Folder folder = null;
// versionamento
FileDetail fileDTSVersion = null;
// verifica se ficheiro já existe na folder
if (this.selectedNodeAttach != null) {
if (this.selectedNodeAttach.getData() instanceof Attachment) {
folder = (Folder) (this.selectedNodeAttach.getParent().getData());
} else {
folder = (Folder) (this.selectedNodeAttach.getData());
}
for (TreeNode tree : this.selectedNodeAttach.getChildren()) {
if (tree.getType().equals("file")) {
Attachment fileChild = this.attachmentManager.initializeAttachment((Attachment) (tree.getData()));
if (fileChild.getName().equals(originalName)) {
if (fileChild.getContentObject() instanceof File) {
//file already exists --- need confirm action ???????????
}
}
}
}
}
// guarda ficheiro localmente
try {
if (log.isDebugEnabled()) {
log.debug("saving file in local..." + internalName);
}
copyFileToDisk(internalName, event.getFile().getInputstream());
} catch (IOException ex) {
log.error(null, ex);
}
}

You can achieve that by first defining a <p:confirmDialog/> in your XHTML and showing it with your Managed Bean by sending a JS through the Request Context, like so:
XHTML:
<p:confirmDialog widgetVar="dialog" appendToBody="true" header="Erro!"/>
Controller:
RequestContext.getCurrentInstance().execute("PF('dialog').show();")
By the way, there is already another question just like yours. Remember to search before posting a new question.
Calling Primefaces dialog box from Managed Bean function

Related

JSF View- returning null on actions do not update the view

i have read the post that have same problem as mine
JSF ViewScope - returning null on actions do not update the view
but it haven't worked for me cause i already use the h:commandLink in another page and its works perfectly but in this page it doesn't .
this is the request Bean
public class AddSectionBean {
public String delete(String id) {
try {
HttpSession session = SessionUtil.getSession();
UserVO userVOCreater = (UserVO) session.getAttribute("userVO");
SectionsDao.getInstance().deleteSectionById(
Integer.parseInt(id));
LoggerVO loggerVO =new LoggerVO();
loggerVO.setUserid(userVOCreater.getId());
loggerVO.setLog("deleted Section Id:"+id);
LoggerDao.getInstance().insertLogger(loggerVO);
} catch (Exception e) {
e.printStackTrace();
BundleMessages.getInstance().setMessage("error",
FacesMessage.SEVERITY_ERROR);
logger.error(e.getMessage(), e);
}
return null;
}
}
and the link is inside a richtable for every column
<rich:column>
<h:commandLink id="actualDelete" styleClass="delete_#{sectionsBean.datatableSections.rowIndex}" action ="#{addSectionBean.delete(s.id)}" />
</rich:column>
Note That: i tried to return the outcome instead of null but when i do that i lose the style and scripts in page
, note that the scripts have no effect cause i have tested it with them and had the same result
the problem solved by moving the delete method to the bean that view the table and calling the database method again inside the delete function to reload the table even its reloads in the postConstruct function
public class SectionsBean{
List<SectionVO> sectionsList = new ArrayList<SectionVO>();
#PostConstruct
public void postConstruct() {
try {
this.sectionsList = SectionsDao.getInstance().getSections();
} catch (Exception e) {
e.printStackTrace();
logger.error(e.getMessage(), e);
}
}
public String delete(String id) {
try {
HttpSession session = SessionUtil.getSession();
UserVO userVOCreater = (UserVO) session.getAttribute("userVO");
SectionsDao.getInstance().deleteSectionById(
Integer.parseInt(id));
LoggerVO loggerVO =new LoggerVO();
loggerVO.setUserid(userVOCreater.getId());
loggerVO.setLog("deleted Section Id:"+id);
LoggerDao.getInstance().insertLogger(loggerVO);
//reload the database table
this.sectionsList = SectionsDao.getInstance().getSections();
} catch (Exception e) {
e.printStackTrace();
BundleMessages.getInstance().setMessage("error",
FacesMessage.SEVERITY_ERROR);
logger.error(e.getMessage(), e);
}
BundleMessages.getInstance().setMessage("success",
FacesMessage.SEVERITY_INFO);
System.out.println("calling delete id="+id);
return null;
}
}

p:dataTable selections are lost after paginating a LazyDataModel

My problem is that after I've selected a few items on the 1st page, if I paginate to another page and come back, my initial selections are not shown. I've tried to implement the SelectableDataModel as well as using the rowKey attribute but the problem persists.
This is my test bean:
#ManagedBean
#ViewScoped
public class MrBean {
private List<Item> chosenItems;
private LazyDataModel lazyModel;
#PostConstruct
public void prepareTest() {
this.lazyModel = new LazyItemDataModel();
}
public void countItems() {
System.out.println("TEST 3: chosenItems's size: " + chosenItems.size());
}
private class LazyItemDataModel extends LazyDataModel<Item> implements SelectableDataModel<Item> {
#Override
public Item getRowData(String rowKey) {
System.out.println("TEST 1: getRowData");
Iterator<Item> iter = ((List<Item>) this.getWrappedData()).iterator();
while (iter.hasNext()) {
Item item = iter.next();
if (item.getId().equals(rowKey)) {
return item;
}
}
return null;
}
#Override
public Object getRowKey(Item item) {
return item.getId();
}
#Override
public List<Item> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map filters) {
System.out.println("TEST 2: load");
// Code to retrieve items from database
}
}
// Getters and Setters
}
This is my test page:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Test page</title>
</h:head>
<h:body>
<h:form>
<p:dataTable id="itemTable" var="item" value="#{mrBean.items}" rows="5"
paginator="true" selection="#{mrBean.chosenItems}" lazy="true" >
<p:ajax event="rowSelectCheckbox" listener="mrBean.countItems" />
<p:column selectionMode="multiple" />
<p:column headerText="ID">
<h:outputText value="#{item.id}" />
</p:column>
<p:column headerText="Name">
<h:outputText value="#{item.name}" />
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
I'd be very grateful if you could show me what I've done wrong here.
UPDATE: After I added more System.out.println("TEST") to the above code, I observed the following things:
On the console, every time I paginate, TEST 1: getRowData is always printed before TEST 2: load. As a consequence, I believe the method #LazyDataModel.getWrappedData() may return data from the old page. At first, I thought this method's goal was to retrieve the selected rows to highlight on the table. However, if this method is called before load, there's no way it can do the job right?
After I selected the 1st 2 items on the 1st page, on the console, I saw TEST 3: chosenItems's size: 2. If I paginate to the 2nd page and then back to the 1st page, the selections are lost as mentioned. However, if I continued to select another item, on the console, I saw TEST 3: chosenItems's size: 3. Obviously, the chosenItems list still kept my old selections but they're not rendered on the table.
In webPage just add a event for when page switch:
<p:ajax event="page" listener="#{listingBean.updateSelected()}" />
In the listingBean, just save the selected:
private List<Entity> selectedInstances;
private List<Entity> selectedInstancesSaved;
public List<Entity> getSelectedInstances()
{
return selectedInstancesSaved;
}
public void setSelectedInstances(List<Entity> selectedInstances)
{
this.selectedInstances = selectedInstances;
}
public void updateSelected()
{
if (selectedInstances != null && !selectedInstances.isEmpty()) {
for (Entity inst : lazyModel.getDatasource()) {
if (selectedInstances.contains(inst)) {
selectedInstancesSaved.add( inst);
} else {
selectedInstancesSaved.remove( inst);
}
}
}
}
This is because when SelectionFeature is decoded a new list is created.
And if table.getRowData(rowKeys[i]) (related to your LazyDataModel implementation) returns null your old selectıons in the previous page are gone.may try to solve it by changing your LazyDataModel implementation I didn't try these but take a look at this and this
Had the same problem and I think this solution is easier if you have a lot of different tables implementing LazyDataModel.
This is what I did: check if it is lazy first then add currently selected rows to the selectionList.
For primefaces 4.0
1)Override DataTableRenderer
In faces-config.xml
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.DataTableRenderer</renderer-type>
<renderer-class>com.package.LazyDataTableRenderer</renderer-class>
</renderer>
</render-kit>
And
public class LazyDataTableRenderer extends DataTableRenderer {
static Map<DataTableFeatureKey,DataTableFeature> FEATURES;
static {
FEATURES = new HashMap<DataTableFeatureKey,DataTableFeature>();
FEATURES.put(DataTableFeatureKey.DRAGGABLE_COLUMNS, new DraggableColumnsFeature());
FEATURES.put(DataTableFeatureKey.FILTER, new FilterFeature());
FEATURES.put(DataTableFeatureKey.PAGE, new PageFeature());
FEATURES.put(DataTableFeatureKey.SORT, new SortFeature());
FEATURES.put(DataTableFeatureKey.RESIZABLE_COLUMNS, new ResizableColumnsFeature());
FEATURES.put(DataTableFeatureKey.SELECT, new LazySelectionFeature());
FEATURES.put(DataTableFeatureKey.ROW_EDIT, new RowEditFeature());
FEATURES.put(DataTableFeatureKey.CELL_EDIT, new CellEditFeature());
FEATURES.put(DataTableFeatureKey.ROW_EXPAND, new RowExpandFeature());
FEATURES.put(DataTableFeatureKey.SCROLL, new ScrollFeature());
}
#Override
public void decode(FacesContext context, UIComponent component) {
DataTable table = (DataTable) component;
for(Iterator<DataTableFeature> it = FEATURES.values().iterator(); it.hasNext();) {
DataTableFeature feature = it.next();
if(feature.shouldDecode(context, table)) {
feature.decode(context, table);
}
}
decodeBehaviors(context, component);
}
}
2)Override SelectionFeature's decode
Updated: edited to allow deselecting
public class LazySelectionFeature extends org.primefaces.component.datatable.feature.SelectionFeature{
#Override
public void decode(FacesContext context, DataTable table) {
String clientId = table.getClientId(context);
Map<String,String> params = context.getExternalContext().getRequestParameterMap();
String selection = params.get(clientId + "_selection");
if(table.isSingleSelectionMode())
decodeSingleSelection(table, selection);
else
decodeMultipleSelection(context, table, selection);
}
void decodeSingleSelection(DataTable table, String selection) {
if(ComponentUtils.isValueBlank(selection))
table.setSelection(null);
else
table.setSelection(table.getRowData(selection));
}
void decodeMultipleSelection(FacesContext context, DataTable table, String selection) {
Class<?> clazz = table.getValueExpression("selection").getType(context.getELContext());
boolean isArray = clazz.isArray();
if(!isArray && !List.class.isAssignableFrom(clazz)) {
throw new FacesException("Multiple selection reference must be an Array or a List for datatable " + table.getClientId());
}
if(ComponentUtils.isValueBlank(selection)) {
if(isArray) {
table.setSelection(Array.newInstance(clazz.getComponentType(), 0));
}
else {
table.setSelection(new ArrayList<Object>());
}
}
else {
String[] rowKeys = selection.split(",");
List<Object> selectionList = new ArrayList<Object>();
boolean lazy=table.isLazy();
if (lazy) {
List<String> currentRowKeys = new ArrayList<String>(Arrays.asList(rowKeys));
if (table.getSelection() != null) {
List<Object> alreadySelected = (List<Object>) table.getSelection();
for (Object object : alreadySelected) {//For deselecting
Object rowKeyFromModel = table.getRowKeyFromModel(object);
if (currentRowKeys.contains(rowKeyFromModel)) {
selectionList.add(object);
currentRowKeys.remove(rowKeyFromModel);
}
}
}
for (String key : currentRowKeys) {//For selecting
Object rowData = table.getRowData(key);
if (rowData != null && !selectionList.contains(rowData)) {
selectionList.add(rowData);
}
}
}else{
for(int i = 0; i < rowKeys.length; i++) {
Object rowData = table.getRowData(rowKeys[i]);
if(rowData != null)
selectionList.add(rowData);
}
}
if(isArray) {
Object selectionArray = Array.newInstance(clazz.getComponentType(), selectionList.size());
table.setSelection(selectionList.toArray((Object[]) selectionArray));
}
else {
table.setSelection(selectionList);
}
}
}
}
Might not be the best solution but should work, let me know if there is a better way. Hope this helps someone.
Just implement the property bound to selection property of DataTable (selection="#{pageBackingForm.selectedEntityList}") like this and it will work :
private Map<Integer, List<Entity>> selectedEntityListMap = new Hashtable<>();
public List<Entity> getSelectedEntityList() {
return selectedEntityListMap.get(getCurrentEntitySelectionPage());
}
public void setSelectedEntityList(List<Entity> selectedEntityList) {
if (selectedEntityList == null) {
selectedEntityListMap.remove(getCurrentEntitySelectionPage());
return;
}
selectedEntityListMap.put(getCurrentEntitySelectionPage(), selectedEntityList);
}
public Integer getCurrentEntitySelectionPage() {
DataTable dataTable = (DataTable) FacesContext.getCurrentInstance().getViewRoot().findComponent("formId:dataTableId");
return dataTable.getPage();
}
While Bruno's solution works for keeping selections across paginations, it doesn't account for retaining selections on an individual page (i.e. when never changing pages).
This problem can be resolved more simply by using the rowSelectCheckbox and rowUnselectCheckbox ajax events, in addition to having a separate "saved" row list.
JSF:
<p:dataTable selection="#{myBean.selectedRows}" ... >
<p:ajax event="rowSelectCheckbox" process="#this" listener="#{myBean.onSelectRow}" />
<p:ajax event="rowUnselectCheckbox" process="#this" listener="#{myBean.onUnselectRow}" />
<p:column selectionMode="multiple" ... />
...
</p:dataTable>
Backing Bean:
private List<MyRowClass> selectedRows;
private List<MyRowClass> selectedRowsSaved;
...
public void onSelectRow(SelectEvent event){
MyRowClass row = (MyRowClass) event.getObject();
selectedRowsSaved.add(row);
}
public void onUnselectRow(UnselectEvent event){
MyRowClass row = (MyRowClass) event.getObject();
selectedRowsSaved.remove(row);
}
public List<MyRowClass> getSelectedRows(){
return selectedRowsSaved;
}
public void setSelectedRows(List<MyRowClass> selectedRows){
this.selectedRows = selectedRows;
}
This way the list of saved rows is always kept up to date without needing a "page" ajax event.
I had the same problem with my data table. Although my case is a bit different because I am using selectBooleanCheckbox instead. I found a simple solution that works for me. It hit me when you said "old selection are not rendered in the table".
strap the checkbox with a a4j:support event
code:
<h:selectBooleanCheckbox value="#{batch.toPortfolio}">
<a4j:support event="onchange" />
</h:selectBooleanCheckbox>

Conversation Scoped bean for same view

I have a DTO which has a list. I want to add new rows to datatable when user clicks add button. But when I click add the dto i.e constructor is called and value is initialized and list size is 0. The bean is conversation scoped. Should I start and end conversation for same view while using conversation scoped bean? I am using same bean for edit and it is working well. How to solve initialization problem while using richfaces 4 and jsf 2 and ajax.
View:
<rich:panel id ="dataPnl">
<rich:dataTable value="#{legendbean.legendDTO.list}" var="legend" style="width:100%">
<rich:column>
<f:facet name="header">
<h:outputText value="SN"/>
</f:facet>
<h:inputText value="#{legend.sn}"/>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Description"/>
</f:facet>
<h:inputText value="#{legend.desc}"/>
</rich:column>
<rich:column>
<a4j:commandLink value="Add" actionListener="#{legendbean.addLegendRange()}" render="nisForm:dataPnl"/>
<h:outputText value=" / "/>
<a4j:commandLink value="Remove" actionListener="#{legendbean.removeLegendRange(legend)}" render="nisForm:dataPnl"/>
</rich:column>
</rich:dataTable>
</rich:panel>
Bean :
#Named("legendbean")
#ConversationScoped
public class LegendController implements Serializable {
LegendDTO legendDTO = new LegendDTO();
String selectedLegend;
boolean edit;
#Inject
private Conversation conversation;
public boolean isEdit() {
return edit;
}
public void setEdit(boolean edit) {
this.edit = edit;
}
public LegendController() {
Logger.getLogger(LegendController.class.getName()).warning("The value of Edit is : " + edit);
if (!edit) {
legendDTO.getList().add(new Legend());
Logger.getLogger(LegendController.class.getName()).warning("The size of list" + legendDTO.getList().size());
}
}
public LegendDTO getLegendDTO() {
return legendDTO;
}
public void setLegendDTO(LegendDTO legendDTO) {
this.legendDTO = legendDTO;
}
public void addLegendRange() {
Logger.getLogger(LegendController.class.getName()).warning("List Size " + legendDTO.getList().size());
legendDTO.getList().add(new Legend());
Logger.getLogger(LegendController.class.getName()).warning("List Size " + legendDTO.getList().size());
}
public void removeLegendRange(Legend legend) {
if (legendDTO.getList().size() != 1) {
legendDTO.getList().remove(legend);
}
}
public String saveLegend() {
Logger.getLogger(LegendController.class.getName()).warning("Save Legend Edit" + edit);
LegendDAO dao = new LegendDAO();
if (dao.addLegend(legendDTO, edit)) {
if (edit) {
conversation.end();
edit = false;
Logger.getLogger(LegendController.class.getName()).warning("Save Legend Edit" + edit);
return "VIEWLEGEND";
} else {
legendDTO = new LegendDTO();
legendDTO.getList().add(new Legend());
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Saved !"));
return "";
}
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Could Not Save Confim if you have already defined Legend " + legendDTO.getLegendName() + "!"));
return "";
}
}
public List<LegendDTO> getLegends() {
LegendDAO dao = new LegendDAO();
return dao.getLegendDTO();
}
//All function from here are for legend delete
public void deleteLegendType(LegendDTO dto) {
LegendDAO dao = new LegendDAO();
if (dao.deleteLegendType(dto.getLegendName())) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Deleted !"));
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Deleted Error !"));
}
}
//All function from here is to legend edit
public String editLegendType(LegendDTO dto) {
conversation.begin();
edit = true;
legendDTO = dto;
LegendDAO dao = new LegendDAO();
dto.getList().clear();
try {
List<Legend> legends = dao.getDetailForEditLegend(dto.getLegendName());
dto.setList(legends);
} catch (SQLException ex) {
Logger.getLogger(LegendController.class.getName()).warning("SQL EXception has occoured");
}
Logger.getLogger(LegendController.class.getName()).warning("The size of list" + dto.getList().size());
return "addLegend";
}
public String cancel() {
conversation.end();
return "VIEWLEGEND";
}
}
Yes, you need to start a long-running conversation in order to make your conversation (and conversation scoped beans) span multiple requests. Otherwise conversation gets killed at the end of a JSF request (conversation is transient by default: refer to ConversationScoped javadoc).
Also a common solution in such cases as yours is to use ViewScoped beans, but the annotation is JSF2 specific and is not presented in CDI (you can port it to CDI or use seam-faces module, more details: http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/).
If you're not constrained to using CDI/Seam annotations, you can change your bean to use #ManagedBean(name="legendbean") from the javax.faces.bean.ManagedBean package and then use a #ViewScoped annotation on your class that guarantees that as long as the user is on the same page, you'll be using the same instance of the managed bean. Nothing else needs to change at all with your setup, all #Injects will work as normal. To initialize the backing legendDTO.list, annotate a method in your ViewScoped JSF bean with #PostConstruct JSF annotation and put the list population logic in there. You can safely add/remove to the list without it being re-initialized to empty. But you must remember to commit the changes to this list back to the database.
Just a thought, you might want to show a popup that will allow your users confirm they want to delete anything from your db, as safe practice. Cheers

Validating JSF view parameter and error message

I have a JSF2 page with a view parameter that must be looked up in a database.
On the page the properties of that entity are then displayed.
Now I would like to handle the case where the view parameter is missing/invalid
<f:metadata>
<f:viewParam name="id" value="#{fooBean.id}" />
<f:event type="preRenderView" listener="#{fooBean.init()}" />
</f:metadata>
And the init() code is as follows:
String msg = "";
if (id == null) {
msg = "Missing ID!";
}
else {
try {
entity = manager.find(id);
} catch (Exception e) {
msg = "No entity with id=" + id;
}
}
if (version == null) {
FacesUtils.addGlobalMessage(FacesMessage.SEVERITY_FATAL, msg);
FacesContext.getCurrentInstance().renderResponse();
}
Now my problem is that the remaing page is still rendered and I get errors in the application server log saying that entity is null (and therefore some elements are not rendered properly).
I would like only the error message to be displayed.
Should I be returning a String so that a POST to an error page is issued?
However if I choose that way, how do I add a custom error message? Passing Strings as view
parameters does not seem like a good idea at all.
In my opinion, the best thing to do in these cases, is to send an HTTP response with the appropriate error code (404 for not found/invalid, 403 for forbidden, etc):
Add to your FacesUtils this utility method:
public static void responseSendError(int status, String message)
throws IOException {
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.getExternalContext().responseSendError(status, message);
facesContext.responseComplete();
}
and then, change in your preRenderView listener to:
public void init() throws IOException {
if (id == null || id.isEmpty()) {
FacesUtils.responseSendError(404, "URL incomplete or invalid!");
}
else {
try {
entity = manager.find(id);
} catch (Exception e) { // <- are you sure you want to do that? ;)
FacesUtils.responseSendError(404, "No entity found!");
}
}
}

Multiple Image upload in primefaces

I am using PrimeFaces fileUpload with multiple upload options. In my project i want to send email notification during image upload. My problem is when i upload 10 images means simultaneously 10 email notifications are send. I want to send only one email notification during uploading 10 images. I am using primefaces 3.0 and jsf 2.0. How can I solve it?
My jsf pages:
<p:fileUpload id="imaload" fileUploadListener="#{photoUploadAction.handleImage}"
mode="advanced" multiple="true" process="#form"
update="messages,#form"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>
Backing Bean:
public void handleImage(FileUploadEvent event) throws IOException, EmailException {
try {
photoUploadVO.setDisabled("false");
//BufferedImage image = ImageIO.read(in);
ImageIO.write(resize(bufferedImage, 400, bufferedImage.getHeight()), "jpg", new File(tmpFile));
flag = photoUploadDaoService.uploadPhotos(photoUploadVO);
// profileImageService.uploadPhotos(profileImageBean);
if (flag == true) {
if(!loginBean.getType().equals("ngo") && !loginBean.getType().equals("admin") &&
!loginBean.getType().equals("ngo_coordinator") ){
volName = getVolunteerName(photoUploadVO.getUsrId(),photoUploadVO.getUser_type());
lst = apDao.retreiveSetup();
notification = lst.get(0).activity_email.toString();
email = lst.get(0).approval_toEmail.toString();
if(notification.equalsIgnoreCase(tmp)){
ecs.sendPhotoNotiFication(email,photoUploadVO,volName);
}
}
FacesMessage msg = new FacesMessage("Successfully Uploaded");
FacesContext.getCurrentInstance().addMessage(null, msg);
} else {
FacesMessage msg = new FacesMessage("Failure", event
.getFile().getFileName() + " to uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
} catch (IOException e) {
e.printStackTrace();
FacesMessage error = new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"The files were not uploaded!", "");
FacesContext.getCurrentInstance().addMessage(null, error);
}
}
This is my email notification method inside handle upload methos:
ecs.sendPhotoNotiFication(email,photoUploadVO,volName);
Redesign your bean as such that the file upload handler method merely captures and remembers all uploaded files in some collection. Then add a "Save" button below the form which is bound to an action method which will actually process and save all those uploaded files and finally send the mail. If you put the bean in the view scope, then one and same bean instance will just be reused as long as the enduser interacts with the same view. You could then just collect the uploaded files in a collection property.
Something like this:
#ManagedBean
#ViewScoped
public class Bean implements Serializable {
private List<UploadedFile> uploadedFiles;
#PostConstruct
public void init() {
uploadedFiles = new ArrayList<UploadedFile>();
}
public void upload(FileUploadEvent event) {
uploadedFiles.add(event.getFile());
}
public void save() {
for (UploadedFile uploadedFile : uploadedFiles) {
// Process them all here.
}
// Send only one email.
}
}
with
<p:fileUpload ... fileUploadListener="#{bean.upload}" />
<p:commandButton value="Save" action="#{bean.save}" />

Resources