Primefaces graphicImage stream not closed, file locked [duplicate] - jsf

This question already has answers here:
Display dynamic image from database or remote source with p:graphicImage and StreamedContent
(4 answers)
Closed 6 years ago.
I'm using primefaces to upload an image, crop it and then display the final image on a graphicImage.
The process works fine, but the problem is that when I retrieve the final image to display on the graphicImage, the stream is not closed and the file is being held up by java.exe, so I'm having problems on deleting the files/directory for example when the user logs out, because it's just a temp directory.
This is the getter of my StreamedContent:
public StreamedContent getGraphicCropped() {
try{
if (newImageName != null) {
File file2 = new File(pathCroppedImage);
InputStream input = new FileInputStream(file2);
graphicCropped = new DefaultStreamedContent(input);
showImageFinal = true;
}
} catch(Exception e){
e.printStackTrace();
}
return graphicCropped;
}
If I do input.close();then I'm able to delete the file, but it is not displayed, because I know that this getter is called more than once on the life cycle.

I've solved it by using the suggested getter of a StreamedContent:
public StreamedContent getGraphicCropped() throws FileNotFoundException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
}
else {
// So, browser is requesting the image. Return a real StreamedContent with the image bytes.
File file2 = new File(pathCroppedImage);
InputStream input = new FileInputStream(file2);
showImageFinal = true;
return new DefaultStreamedContent(input);
}
}

Related

Writing my own image importer, pictures are not recognized as pictures after import

i am writing my own image import for my product catalog. I want to read the images from the local filesystem and store them in the configured assets folder. The import is very simple for now. Its one controller in the admin project and i trigger it by calling an url.
It is creating the files along with the folder structure and the files seem to have the same filesize, but somehow they get messed up along the way and they are not readable as images anymore (picture viewers wont open them). Any ideas why its being messed up ?
here the code:
#Controller("blImageImportController")
#RequestMapping("/imageimport")
public class ImageImportController extends AdminAbstractController {
#Value("${image.import.folder.location}")
private String importFolderLocation;
#Resource(name = "blStaticAssetService")
protected StaticAssetService staticAssetService;
#Resource(name = "blStaticAssetStorageService")
protected StaticAssetStorageService staticAssetStorageService;
#RequestMapping(method = {RequestMethod.GET})
public String chooseMediaForMapKey(HttpServletRequest request,
HttpServletResponse response,
Model model
) throws Exception {
File imageImportFolder = new File(importFolderLocation);
if (imageImportFolder.isDirectory()) {
Arrays.stream(imageImportFolder.listFiles()).forEach(directory ->
{
if (directory.isDirectory()) {
Arrays.stream(directory.listFiles()).forEach(this::processFile);
}
});
}
return "";
}
private void processFile(File file) {
FileInputStream fis = null;
try {
HashMap properties = new HashMap();
properties.put("entityType", "product");
properties.put("entityId", file.getParentFile().getName());
fis = new FileInputStream(file);
StaticAsset staticAsset = this.staticAssetService.createStaticAsset(fis, file.getName(), file.length(), properties);
this.staticAssetStorageService.createStaticAssetStorage(fis, staticAsset);
fis.close();
} catch (Exception e) {
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
There is a check in the StaticAssetService to try to detect this as an image (see https://github.com/BroadleafCommerce/BroadleafCommerce/blob/b55848f/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/file/service/StaticAssetServiceImpl.java#L217-L220). If it detected this correctly, you should get back an ImageStaticAssetImpl in the result to that call.
The flipside of this is the controller that actually reads the file (the StaticAssetViewController that renders a StaticAssetView). One of the things that the StaticAssetView does is set a response header for mimeType which the browser uses to render. This is set by this piece in the StaticAssetStorageService: https://github.com/BroadleafCommerce/BroadleafCommerce/blob/b55848f837f26022a620f0c2c143eed7902ba3f1/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/file/service/StaticAssetStorageServiceImpl.java#L213. I suspect that is the root of your problem.
Also just a note, sending those properties is not necessary when you are uploading the file yourself. That is mainly used in the admin when you are uploading an image for a specific entity (like a product or a category).

Uploading file in JSF (Need correct file pathway) [duplicate]

This question already has an answer here:
How to upload file using JSF 2.2 <h:inputFile>? Where is the saved File?
(1 answer)
Closed 5 years ago.
I am trying to get my JSF site to upload a picture to the server, but am having a time of it. I've found 4 methodologies to do, but I'd like to use h:InputFile as it seems the most direct.
It would seem I just need to supply the upload path correctly.
After adding #MultipartConfig I no longer get an exception, but I can't verify the file is uploaded or see any error.
public void AddPicture()
{
ConnInfo HitIt = new ConnInfo();
try
{
HitIt.save(fileCelebrityToAdd);
}
catch(Exception ex)
{
//?
}
}
#MultipartConfig(location="C:\\local\\pathway\\Netbeans\\project\\web\\Pictures\\items\\")
public class ConnInfo
{
private String uploadLocation;
public ConnInfo()
{
//uploadLocation = ".\\Pictures\\items\\";
uploadLocation = "C:\\local\\pathway\\Netbeans\\project\\web\\Pictures\\items\\";
}
public boolean TryOut(Part file) throws IOException
{
String monkey = uploadLocation+getFilename(file);
try
{
file.write(monkey);
}
catch(Exception ex)
{
return false;
}
return true;
}
}
Hopefully I've copied the necessary information correctly.
After going back and rereading all the articles I had bookmarked, it was actually the from the one Tam had suggested that I was able to strip out some information.
I didn't need the AJAX, or the #MultipartConfig, and my previous attempt was somehow incorrect, but the follow method allowed me to successfully upload a picture where I wanted it:
public boolean SaveHer(Part file)
{
String monkey = getFilename(file);
try (InputStream input = file.getInputStream())
{
Files.copy(input, new File(uploadLocation, monkey).toPath());
}
catch (IOException e)
{
// Show faces message?
return false;
}
return true;
}

Binary file download generated in backing bean appears as plain text in client [duplicate]

This question already has answers here:
How to provide a file download from a JSF backing bean?
(5 answers)
Closed 7 years ago.
I have server side webapp and I am trying to generate an excel file with Apache POI, which is provided as download by backing bean. I am able to write the file on server disk, but not to write it to HTTP response.
Here's my code
public void createExcel(){
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
HSSFWorkbook workBook = new HSSFWorkbook();
HSSFSheet sheet = workBook.createSheet("hello world");
HSSFRow row = sheet.createRow((short) 0);
HSSFCell cell;
cell = row.createCell(0);
cell.setCellValue(new HSSFRichTextString("Hello"));
cell = row.createCell(1);
cell.setCellValue(new HSSFRichTextString("world"));
workBook.write(bos);
bos.flush();
FacesContext fc = FacesContext.getCurrentInstance();
downloadExcel(bos, fc);
} catch (FileNotFoundException e) {
log.debug("file not found ", e);
} catch (IOException e){
log.debug("IOException ", e);
}
}
public void downloadExcel(ByteArrayOutputStream baos, FacesContext fc){
HttpServletResponse response = (HttpServletResponse)fc.getExternalContext().getResponse();
response.setContentType("application/vnd.ms-excel");
response.addHeader("Content-Disposition", "attachment; filename=testxls.xls");
try {
ServletOutputStream out = response.getOutputStream();
baos.writeTo(out);
out.flush();
out.close();
} catch (IOException e) {
log.error("IOException ", e);
}
fc.responseComplete();
}
And the result is following
This happens in all browsers I tried: Chrome, FF and IE. I hope you can point out what I am missing here.
Finally found the solution in BalusC given link. I called createExcel() method in JSF inside <a4j:commandButton> tag, which called method through ajax. Changed it to <h:commandButton> and now it is working.
The browser does not ever open a dialog to invite you to download the file when you navigate your servlet? I guess the reason is that you missed to enclose the filename between quotes:
response.addHeader("Content-Disposition", "attachment; filename=\"testxls.xls\"");

JSF response.setHeader "Content-disposition" no popup

Just starting to learn how to do the download with jsf.
I have looked at couple other related posts. And mainly copy their code, but it seems like I did something wrong.
This is my code
public void download() throws IOException {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
response.reset(); // Some JSF component library or some Filter might have set some headers in the buffer beforehand. We want to get rid of them, else it may collide.
response.setContentType(contentType); // Check http://www.iana.org/assignments/media-types for all types. Use if necessary ServletContext#getMimeType() for auto-detection based on filename.
response.setHeader("Content-disposition", "attachment;filename=\"001.cvf\""); // The Save As popup magic is done here. You can give it any filename you want, this only won't work in MSIE, it will use current request URL as filename instead.
BufferedInputStream input = null;
BufferedOutputStream output = null;
String content =VCFHandler.getContent(profile.getFriendlist());
response.setHeader("Content-Length", String.valueOf(content.length()));
try {
InputStream stream = new ByteArrayInputStream(content.getBytes("UTF-8"));
input = new BufferedInputStream(stream);
output = new BufferedOutputStream(response.getOutputStream());
byte[] buffer = new byte[10240];
for (int length; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
output.flush();
} finally {
output.close();
input.close();
}
facesContext.responseComplete(); // Important! Else JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}
So I tried this code with debugger in eclipse. When download button is clicked, this method is called (which is what I wanted). But after all steps are finished no popup is shown in my page. Anyone have any suggestions?
BTW the content type is
private final static String contentType="text/x-vcard";
By your problem description, I'm not sure but looks like you're firing the download from an ajax request. Remove the ajax behavior for this request and try again.

Primefaces is not immediately closing the stream of DefaultStreamedContent after read

I have the following problem:
I am displaying an image in my webapp using a <p:graphicImage> from Primefaces
The image displayed is delivered by a bean as a DefaultStreamedContent. In my application I am sometimes deleting images displayed this way during runtime.
This always takes a little time till I can delete the image. After debugging a little i used the Files.delete of Java 7 and got the following exception:
The process cannot access the file because it is being used by another process.
I thus suspect that Primefaces is not immediately closing the stream behind the DefaultStreamedContent after displaying and i am not able to delete the file whenever I want.
Is there any way to tell the DefaultStreamedContent to close itself imediately after read (I already looked into the documentation and didn't find any fitting method within the DefaultStreamedContent, but maybe one can tell the stream or something like that?)
Ok I finally found out what is happening using the Unlocker tool
(can be downloaded here: http://www.emptyloop.com/unlocker/#download)
I saw that the java.exe is locking the file once it is displayed. Therefor the Stream behind the StreamedContent is NOT immediately closed after reading.
My solution was as follows:
I made a superclass extending the StreamedContent and let it read the inputstream and "feed" the read bytes into a new InputStream. After that i closed the given stream so that the ressource behind it is released again.
the class looks something like this:
public class PersonalStreamedContent extends DefaultStreamedContent {
/**
* Copies the given Inputstream and closes it afterwards
*/
public PersonalStreamedContent(FileInputStream stream, String contentType) {
super(copyInputStream(stream), contentType);
}
public static InputStream copyInputStream(InputStream stream) {
if (stream != null) {
try {
byte[] bytes = IOUtils.toByteArray(stream);
stream.close();
return new ByteArrayInputStream(bytes);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
System.out.println("inputStream was null");
}
return new ByteArrayInputStream(new byte[] {});
}
}
I am quite sure that the image is retrieved 2 times by Primefaces but only closed the FIRST time it is loaded. I didn't realize this in the beginning.
I hope this can help some other people too :)

Resources