Multiple Image upload in primefaces - jsf-2

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}" />

Related

invoke confirmDialog in bean

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

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;
}
}

JSF h:commandLink not work with filter

I create simple login system for my jsf project.
In project I create filter to check user login status.
If login, continue to requested page.
If not login or session is destroy, redirect to login page
My problem is, if I apply filter then all of h:commandLink not process anything after clicked. But when I remove filter, everything work well.
I try to use h:commandButton with fileter, then everthing work correctly.
How can I fixed this problem?
I research for a long time, but not found any solution.
Please help me!
Filter code:
#WebFilter(filterName = "AuthenticationFilter", urlPatterns = {"*.htm"}, dispatcherTypes = {DispatcherType.FORWARD, DispatcherType.REQUEST})
public class AuthenticationFilter implements Filter {
// The filter configuration object we are associated with. If
// this value is null, this filter instance is not currently
// configured.
private FilterConfig filterConfig = null;
#Inject
private AuthenticationManager authenticationManager;
public AuthenticationFilter() {
}
/**
* #param request The servlet request we are processing
* #param response The servlet response we are creating
* #param chain The filter chain we are processing
*
* #exception IOException if an input/output error occurs
* #exception ServletException if a servlet error occurs
*/
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
Throwable problem = null;
try {
HttpServletRequest req = (HttpServletRequest) request;
String requestUrl = req.getRequestURI();
String contextPath = req.getContextPath();
if(contextPath.equals("/")){
contextPath = "";
}
String jsfUrl = requestUrl.replaceFirst(contextPath, "");
if (authenticationManager.allowedAccess(jsfUrl) || requestUrl.equalsIgnoreCase(contextPath+"/login.htm")) {
chain.doFilter(request, response);
}
else {
String redirectPath = contextPath+"/login.htm";
((HttpServletResponse) response).sendRedirect(redirectPath); // Not logged in, so redirect to error page.
}
}
catch (Throwable t) {
// If an exception is thrown somewhere down the filter chain,
// we still want to execute our after processing, and then
// rethrow the problem after that.
problem = t;
}
// If there was a problem, we want to rethrow it if it is
// a known type, otherwise log it.
if (problem != null) {
if (problem instanceof ServletException) {
throw (ServletException) problem;
}
if (problem instanceof IOException) {
throw (IOException) problem;
}
sendProcessingError(problem, response);
}
}
/**
* Return the filter configuration object for this filter.
*/
public FilterConfig getFilterConfig() {
return (this.filterConfig);
}
/**
* Set the filter configuration object for this filter.
*
* #param filterConfig The filter configuration object
*/
public void setFilterConfig(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
if (filterConfig != null) {
}
}
}
Jsf code:
<h:body>
<f:view contentType="text/html" locale="#{authenticationManager.languageCode}">
<div class="header">
<h:form id="topForm" prependId="false">
<div class="logo">
<h1><img src="#{facesContext.externalContext.requestContextPath}/resources/images/login-logo2.png" width="220" height="64"/></h1>
</div>
<ul class="navTop">
<li>
<span class="pictograms">f</span>#{authenticationManager.currentUser.firstName} #{authenticationManager.currentUser.lastName}
</li>
<li>
<span class="pictograms">m</span>Messages
</li>
<li class="logout">
<h:commandButton action="#{authenticationManager.logout()}" value="aaaaaaa" style="color:#fff;" />
<h:commandLink action="#{authenticationManager.logout()}" value="#{label.Logout}"/>
<h:commandLink immediate="true" action="#{authenticationManager.logout}" id="logoutLink">
<span class="pictograms">E</span>***This link is not work correctly***
</h:commandLink>
</li>
</ul>
<ui:insert name="mainmenu"/>
</h:form>
</div>
Your concrete problem is caused because the serving of the JSF default resource jsf.js has been blocked by the filter. This resource is mandatory for functioning of JSF command links and JSF ajax requests (plain command buttons without ajax will just work).
You need to exclude JSF resources from the authentication check. You can do that by just checking if the request URI starts after the webapp context path with ResourceHandler.RESOURCE_IDENTIFIER (which has a value of /javax.faces.resource).
So, basically:
HttpServletRequest req = (HttpServletRequest) request;
if (req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) {
chain.doFilter(request, response); // Let it continue.
return;
}
Checking the file extensions is clumsy and does not sufficiently cover all possible resource requests.
After research, I didn't found any solution.
So I guest to many possible ways, and found the explanation about this.
I filter everything with filter pattern "*.htm", then every request like .js.htm, .css.htm, .gif.htm, .jpg.htm will redirected to login.htm page.
The point is redirect .js.htm to login page instead of right file.
So the important library like jsf.js.htm was redirect to login.htm, this is the main cause to make h:commandLink work not correctly.
Hop this will help someone, like me.
try {
HttpServletRequest req = (HttpServletRequest) request;
String requestUrl = req.getRequestURI();
if(requestUrl.endsWith(".js.htm")
|| requestUrl.endsWith(".css.htm")
|| requestUrl.endsWith(".gif.htm")
|| requestUrl.endsWith(".png.htm")
|| requestUrl.endsWith(".jpg.htm")
|| requestUrl.endsWith(".jpeg.htm")){
chain.doFilter(request, response);
}
else{
String contextPath = req.getContextPath();
if(contextPath.equals("/")){
contextPath = "";
}
String jsfUrl = requestUrl.replaceFirst(contextPath, "");
if (authenticationManager.allowedAccess(jsfUrl) || requestUrl.equalsIgnoreCase(contextPath+"/login.htm")) {
chain.doFilter(request, response);
}
else {
String redirectPath = contextPath+"/login.htm";
((HttpServletResponse) response).sendRedirect(redirectPath); // Not logged in, so redirect to error page.
}
}
}

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!");
}
}
}

Resources