Displaying contents from an inputstream

hi All,

I want to open a pdf document on click of a command button. In its action method, I have an inputStream object from which I need to read the content and display the pdf document.

Have gone through IFileExportBean and its implementing classes, couldn’t find any of the implementing classes having a constructor / method which accepts an input stream or can write bytes to it by reading from an input stream in fixed size packets(may be with 1024B packet size) in an iteration.

Following implementing classes might be useful but not in our usecase :(.

FileContentExportBean - In my usecase, we should not create any temp file in any temp location to give that file path as an input to this class’s constructor.
SimpleFileExportBean - In my usecase, as the documents which I am going to display are of larger size, I should not convert it to a byteArray(to avoid Java Heap space error) to give this byteArray as an input to this class’s constructor.

Do you have any idea if any other alternative is present which I can use to display contents by reading from an inputstream.

Kind regards,
Raja sekhar Kintali

You can implement the IFileExportBean interface with your own class. For example, using an anonymous class like this:

final InputStream inStream = [TODO get input stream here];

//stream the file back to the user
streamFileDataToResponse(new IFileExportBean() {
	
	/* (non-Javadoc)
	 * @see com.webmethods.caf.faces.bean.IFileExportBean#isDownloadForced()
	 */
	public boolean isDownloadForced() {
		return false; //open the file inline rather than forcing the user to choose what to do with it.
	}

	/* (non-Javadoc)
	 * @see com.webmethods.caf.faces.bean.IFileExportBean#getExportContentLength()
	 */
	public int getExportContentLength() {
		return IFileExportBean.UNKNOWN_CONTENT_LENGTH; //use this for unknown file size, or the actual file size if known.
	}
	
	/* (non-Javadoc)
	 * @see com.webmethods.caf.faces.bean.IFileExportBean#getExportContentType()
	 */
	public String getExportContentType() {
		String contentType = "application/pdf";
		return contentType;
	}
	
	/* (non-Javadoc)
	 * @see com.webmethods.caf.faces.bean.IFileExportBean#getExportFileName()
	 */
	public String getExportFileName() {
		return "export.pdf";
	}
	
	/* (non-Javadoc)
	 * @see com.webmethods.caf.faces.bean.IFileExportBean#isExportBinary()
	 */
	public boolean isExportBinary() {
		return true;
	}
	
	/* (non-Javadoc)
	 * @see com.webmethods.caf.faces.bean.IFileExportBean#writeExportBytes(java.io.OutputStream)
	 */
	public void writeExportBytes(OutputStream outStream) throws IOException {
		byte [] buffer = new byte[1024 * 8]; //8k buffer
		int len = -1;
		while ( (len = inStream.read(buffer)) != -1 ) {
			//copy the buffer to the outstream
			outStream.write(buffer, 0, len);
		}
	}
	
	/* (non-Javadoc)
	 * @see com.webmethods.caf.faces.bean.IFileExportBean#writeExportText(java.io.PrintWriter)
	 */
	public void writeExportText(PrintWriter arg0) {
		//not used, since the export is a binary file
	}
});
1 Like

hi Eric,

Thanks for the alternative sample provided. Am able to display the contents now from an input stream using custom implemntor.

Kind regards,
Raja sekhar Kintali

Hi Eric,

I am having the same problem trying to display the bytes as an image on the screen.

But the way of linking image url to the action that does the streaming implementation you provided does not work because the action does not get invoked after all. I refer to the article below which I tried.

[url]http://tech.forums.softwareag.com/techjforum/posts/list/14924.page[/url]

here is my action below, could you advise what is wrong, or is it another way doing this task.

Thank you
Leonard


	/**
	 * Use this custom method to build the action url that you can bind to the
	 * Image control value.
	 */
	public String getDynamicImageURL() {
		try {
			
			IPortletURL actionUrl = createActionUrl();
			// set the target action to an expression that resolves to the JSF  action
			actionUrl.setTargetAction("#{activePageBean.doStreamImage}");

			System.out.println("----getting image url:" + actionUrl.toString());
			return actionUrl.toString();
			
		} catch (Exception e) {
			e.printStackTrace();
			error(e);
		}
		return null;
	}

	/**
	 * Use this custom action method to retrieve the image data and stream it
	 * back
	 */
	public String doStreamImage() {
		System.out.println("---doStreamImage");
		IFileExportBean fileExportBean = null;


		try {
			streamFileToUser();
		} catch (Exception e) {

			e.printStackTrace();
		}
		return OUTCOME_OK;
	}
	
	private void streamFileToUser() throws Exception{
		
		final InputStream inStream = new BufferedInputStream(
				new FileInputStream("C:\\path-to-dfs-sdk\\output\\09002329800130a8.pdf"));

	    
		
		//stream the file back to the user
		streamFileDataToResponse(new IFileExportBean() {
			
			/* (non-Javadoc)
			 * @see com.webmethods.caf.faces.bean.IFileExportBean#isDownloadForced()
			 */
			public boolean isDownloadForced() {
				return false; //open the file inline rather than forcing the user to choose what to do with it.
			}

			/* (non-Javadoc)
			 * @see com.webmethods.caf.faces.bean.IFileExportBean#getExportContentLength()
			 */
			public int getExportContentLength() {
				return IFileExportBean.UNKNOWN_CONTENT_LENGTH; //use this for unknown file size, or the actual file size if known.
			}
			
			/* (non-Javadoc)
			 * @see com.webmethods.caf.faces.bean.IFileExportBean#getExportContentType()
			 */
			public String getExportContentType() {
				String contentType = "application/pdf";
				return contentType;
			}
			
			/* (non-Javadoc)
			 * @see com.webmethods.caf.faces.bean.IFileExportBean#getExportFileName()
			 */
			public String getExportFileName() {
				return "export.pdf";
			}
			
			/* (non-Javadoc)
			 * @see com.webmethods.caf.faces.bean.IFileExportBean#isExportBinary()
			 */
			public boolean isExportBinary() {
				return true;
			}
			
			/* (non-Javadoc)
			 * @see com.webmethods.caf.faces.bean.IFileExportBean#writeExportBytes(java.io.OutputStream)
			 */
			public void writeExportBytes(OutputStream outStream) throws IOException {
				
				byte [] buffer = new byte[1024 * 8]; //8k buffer
				int len = -1;
				while ( (len = inStream.read(buffer)) != -1 ) {
					
					//copy the buffer to the outstream
					outStream.write(buffer, 0, len);
				}
			}
			
			/* (non-Javadoc)
			 * @see com.webmethods.caf.faces.bean.IFileExportBean#writeExportText(java.io.PrintWriter)
			 */
			public void writeExportText(PrintWriter arg0) {

				//not used, since the export is a binary file
			}
		});

	}

	/**
	 * Action Event Handler for the control with id='button'
	 */
	public String button_action() {

		String url = getDynamicImageURL();
		System.out.println("----url: "+ url);
		
		FacesContext context = getFacesContext();
		url = "C:\\path-to-dfs-sdk\\output\\09002329800130a8.pdf";
		url = context.getExternalContext().encodeResourceURL(url);
		System.out.println("url: --"+ url);
//		getHtmlGraphicImage().setUrl(url);
		getHtmlGraphicImage().setValue(url);
		System.out.println("url: ----"+ getHtmlGraphicImage().getUrl());
		

	    
	    return null;
	}

	/**
	 * Getter method for the control with id='defaultForm:htmlGraphicImage'
	 */
	public com.webmethods.caf.faces.component.standard.HtmlGraphicImage getHtmlGraphicImage()  {
		
		return (com.webmethods.caf.faces.component.standard.HtmlGraphicImage)findComponentInRoot("defaultForm:htmlGraphicImage");
	}

	public com.webmethods.caf.is.wsclient.investecpoc.flows.front.documentum.doczwsd.GetContent1 getGetContent()  {
		if (getContent == null) {
		    getContent = (com.webmethods.caf.is.wsclient.investecpoc.flows.front.documentum.doczwsd.GetContent1)resolveExpression("#{GetContent}");
		}
	
	    resolveDataBinding(GETCONTENT_PROPERTY_BINDINGS, getContent, "getContent", false, false);
		return getContent;
	}

	public com.webmethods.caf.is.wsclient.investecpoc.ws.consumer.xpression.PublishAndReturnDocument getPublishAndReturnDocument()  {
		if (publishAndReturnDocument == null) {
		    publishAndReturnDocument = (com.webmethods.caf.is.wsclient.investecpoc.ws.consumer.xpression.PublishAndReturnDocument)resolveExpression("#{PublishAndReturnDocument}");
		}
	
	    resolveDataBinding(PUBLISHANDRETURNDOCUMENT_PROPERTY_BINDINGS, publishAndReturnDocument, "publishAndReturnDocument", false, false);
		return publishAndReturnDocument;
	}

	public com.webmethods.caf.is.wsclient.investecpoc.ws.consumer.xpression.PublishAndReturnDocument2 getPublishAndReturnDocument2()  {
		if (publishAndReturnDocument2 == null) {
		    publishAndReturnDocument2 = (com.webmethods.caf.is.wsclient.investecpoc.ws.consumer.xpression.PublishAndReturnDocument2)resolveExpression("#{PublishAndReturnDocument2}");
		}
	
	    resolveDataBinding(PUBLISHANDRETURNDOCUMENT2_PROPERTY_BINDINGS, publishAndReturnDocument2, "publishAndReturnDocument2", false, false);
		return publishAndReturnDocument2;
	}
	
	}

Please check your portlet.xml file to see if your portlet is configured to use annotated portlet actions (I believe this is on by default with 8.x)


		<init-param>
			<name>ANNOTATED_PORTLET_ACTIONS</name>
			<value>true</value>
		</init-param>

If that is on, then you would need to add the @PortletAction annotation to the method to allow it to be run via a portlet action request.

For example:


    @PortletAction
    public String doStreamImage() {  
...

And then, in your getDynamicImageURL method, the target action for the action url would just be the name of the method instead of an expression.

Like this:


            // set the target action to an expression that resolves to the JSF  action  
            actionUrl.setTargetAction("doStreamImage");  

Thank you very much Eric,

I applied the changes you advised and it almost works, i.e. the screen displays the correct image url in the debug section.

The problem is now likely with the image control configuration (Dynamic Image URL), where I am setting the Value->URL (or Value->Value) to my custom property DynamicImageURL that appears in the binding after defining the respective method getDynamicImageURL() that is actually called on the screen load.

I do not see anything wrong, and it worked for the other url images such as

The screenshot is shown in the attachment.

I greatly appreciate your help.

Regards
Leonard

Ok. If the action url is a relative url (starts with ‘/’ instead of http://) then the image control may be making the url relative to the portlet application servlet context instead of relative to the root (MWS) context.

If so, you can change the java code in your getDynamicImageURL method like this:


			return "fe:" + actionUrl.toString(); //prepend fe: to make url relative to the mws front end url instead of this webapp context

unfortunately this code does not make a difference, i.e. the action doStreamImage() is not invoked when the page is loaded.

return "fe:" + actionUrl.toString();

But adding a CommandButton control which action calls doStreamImage() explicitly loads the image.

/**
	 * Action Event Handler for the control with id='htmlCommandButton'
	 */
	public String htmlCommandButton_action() {
	    
		doStreamImage();
	    
	    return null;
	}

Can you inspect the html to see what URL the tag is trying to load? If you open that same URL in the browser, do you get the image streamed back?

No, the image link points back to the screen without image content displayed… javascript:emoticon(‘:shock:’);

When you view the html source of the page that was rendered, do you see an img tag that looks similar to this?

<img alt="" src="/meta/default/wm_caf_misc___fileexport/0000005329?wmp_tc=5329&wmp_rt=action&wmp_ax=uagRH5GabEBD76Ke%2fSAQ3hcNXgk%3d&wmp_ta=exportImageButton_action&wmp_ws=maximized" id="jsfwmp5329:defaultForm:htmlGraphicImage">

…oh, one more thing you may need:
On your action URL, you probably will need to call this:

			actionUrl.setAXSRFT(true);

which will add the anti-cross-site-request-forgery token to the URL which is required by default when running a portlet action from a url.

You should see an error like this in the MWS logs if the axsrft is missing:

2012-06-12 12:13:56 PDT (jsf:INFO)  [RID:53] - [POP.016.0050] The target action was invalid: The target action "exportImageButton_action" requires an anti-xsrf token.

I see like this

  • Now the action is triggered, url is right but the image still does not want to appear on load.javascript:emoticon(‘:roll:’);
  • As I mentioned when the action is called directly from the command action (‘Display Document’), the former brings the content to the whole screen.
  • To return user needs to use Backspace because all controls then replaced by the content.
  • So, I can not display content on load in the limited screen area, and limited to use push button with the full screen

Here is the project attached with the discussed portlet called Documentum, wamhich contains the image to stream.
The following line needs modification in regards of this image location.

PortletDocumentum.zip (118 KB)

Are you trying to display a PDF with the image control?

If your goal is to display a pdf document inline, then this topic may be helpful:

Yee, I tried both

and

on the stage when nothing worked…

Now image is working fine. Thank you very much.

Looking at another article.

Leonard
sAG/ ZA

Hello.
I am new here and my english is very poor.

i have the same problem to display the bytes from an image.
i followed your indications but nothing was displayed.

could you tell me how did you resolve this problem ?

thanks

it’s OK.

displaying image works!.

Hi Eric,

I am trying to display an image inline in the CAF, I am not able to display image inline even though I tried all the methods that were discussed in this thread.

Please find my code below:

public java.lang.String getGetDynamicImageURLproperty()  {
		try {
			IPortletURL actionUrl = createActionUrl();
			actionUrl.clearState();
			actionUrl.setAXSRFT(true);
			actionUrl.setTargetAction("dynamicImageURLactionaction"); 
			return "fe:"+actionUrl.toString();
			
			
		} catch (Exception e) {
			error(e);
			return "javscript:void(0)"; //return a do nothing url
		}
		//return getDynamicImageURLproperty;
	}

	public void setGetDynamicImageURLproperty(java.lang.String getDynamicImageURLproperty)  {
		this.getDynamicImageURLproperty = getDynamicImageURLproperty;
	}

	@PortletAction
	public String dynamicImageURLactionaction() {
	    resolveDataBinding(DYNAMICIMAGEURLACTIONACTION_PROPERTY_BINDINGS, this, "dynamicImageURLactionaction.this", true, false);
		try
		{
			final URL resourceURL = getFacesContext().getExternalContext().getResource("d:/wM8.2/checkImage.png");
			IFileExportBean exportBean = new URLContentExportBean(resourceURL,false);
			streamFileDataToResponse(exportBean);
			
			/*String url = "d:/wM8.2/checkImage.png";
			FacesContext context = getFacesContext();
			url = context.getApplication().getViewHandler().getResourceURL(context, url);
			url = context.getExternalContext().encodeResourceURL(url);*/
		}
		catch (Exception e) {
			throw new FacesException(e);
		}	
	
	    return OUTCOME_OK;
	}

The url value that i am getting is :

Kindly suggest me what I am missing or how can I display inline image in the CAF.

Thanks in advance

Akshay

  1. Which control are you using to render the image?

  2. Are you able to verify the PortletAction method is getting called? Either using an attached java debugger or logging a message to the log file?

  3. The way you are getting the image file looks suspicious and seems to violate the intent of that API (see ServletContext (Java EE 6 ) ). Instead of getting the file from the faces external context, you could probably just get the file directly instead. For example:

java.io.File file = new java.io.File("d:/wM8.2/checkImage.png");
IFileExportBean exportBean = new FileContentExportBean(file, false);  
1 Like

Hi Eric,

I am using Image control to render the image.

You are correct the way i was getting the image file was wrong, after implementing the code you provided it worked and i could see the image inline.

Thank you for you help.

Regards,
Akshay