Tuesday, September 12, 2006

MyFaces Bridge 0.8 Released

MyFaces Bridge 0.8 was released! (I think) it supports Tomahawk 1.1.3 on ALL portal server(dependencies to a special feature for Portal, such as Jetspeed2 HeaderResource, were removed). Using this portlet filter, you can use Upload component and some components that uses JavaScript and CSS. For the test environment, I checked it on Jetspeed2, Liferay and JBoss Portal with IE and/or Firefox. If you have a problem, let us know.

To use MyFaces Bridge:
1) Add portals-bridges-portletfilter-1.0.jar, bridges-myfaces-0.8.jar, commons-fileupload-1.1.jar and commons-io-1.1.jar to /WEB-INF/lib
2) Modify portlet.xml

For example, if you use the following portlet.xml,

<portlet-app id="vfs-portlets" version="1.0">
<portlet id="VFSNavigator">
<description>VFS Navigator</description>
<portlet-name>VFSNavigator</portlet-name>
<display-name>VFS Navigator</display-name>
<portlet-class>
jp.sf.pal.vfs.portlets.VFSPortlet
</portlet-class>
<init-param>
<name>view-page</name>
<value>/jsp/ListView.jsp</value>
</init-param>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<portlet-info>
<title>VFS Navigator</title>
<short-title>VFS</short-title>
</portlet-info>
</portlet>
</portlet-app>

change it to:

<portlet-app id="vfs-portlets" version="1.0">
<portlet id="VFSNavigator">
<description>VFS Navigator</description>
<portlet-name>VFSNavigator</portlet-name>
<display-name>VFS Navigator</display-name>
<portlet-class>org.apache.portals.bridges.portletfilter.FilterPortlet</portlet-class>
<init-param>
<name>portlet-class</name>
<value>jp.sf.pal.vfs.portlets.VFSPortlet</value>
</init-param>
<init-param>
<name>portlet-filters</name>
<value>jp.sf.pal.tomahawk.filter.ExtensionsPortletFilter</value>
</init-param>
<init-param>
<name>view-page</name>
<value>/jsp/ListView.jsp</value>
</init-param>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<portlet-info>
<title>VFS Navigator</title>
<short-title>VFS</short-title>
</portlet-info>
</portlet>
</portlet-app>

Note: you need to set "server" as javax.faces.STATE_SAVING_METHOD in web.xml. Currently, "client" is not supported.

For Portals Portlet Filter, please see Apache Portals Bridges.

Thanks!

16 Comments:

Blogger James McGovern said...

Hopefully you will get this into the main liferay code base...

11:14 AM  
Anonymous Anonymous said...

I checked MyFaces Bridge 0.8 on Liferay 4.1.2. If you find any problem, please let me know. This is a first release to support *ALL* portal. IMO, I think that it's better for Apache MyFaces to have this code.

11:49 AM  
Anonymous Anonymous said...

I have tested with LR 4.1.2, and it works fine, thnxs. An other questions is, to support https://ajax4jsf.dev.java.net too.The filter looks like
Ajax4jsf Filter
org.ajax4jsf.Filter...

6:54 AM  
Anonymous Anonymous said...

Thank you for checking it on LR!! Good news to me :)
For ajax4jsf, I'll check it later..

7:05 AM  
Anonymous Anonymous said...

I checked ajax4jsf. To support ajax4jsf as well, I will have to modify MyFaces Bridge. So, I think that it's a feature in the future.

6:57 AM  
Anonymous Anonymous said...

This sounds great, because ajax makes really sense in a portal environment. Just update the part we need, and not the hole page. I know JSF(SUN) 1.2 is ajax aware, but LR 4.1.2 comes with tomcat 5.5.17 and this version of tomcat can't handle jsf 1.2 :-(.

8:48 AM  
Blogger Marcus Christie said...

Just used this to get file upload to work, and it works very well. I'm using Tomcat 5.5.12 and GridSphere 2.1.2, so you can add GridSphere to your list of portals that this bridge works with.

4:17 AM  
Anonymous Anonymous said...

Thank you for the info :)

5:46 AM  
Anonymous Anonymous said...

have someone tested this on oracle portlets?

11:08 AM  
Anonymous Anonymous said...

Hi shinsuke, any new about ajax4jsf support?

many tks

7:12 PM  
Blogger palab said...

I have a plan to do refactoring on MyFaces Bridge. But, since I have much task on open source projects, I have no time right now..

11:40 PM  
Anonymous Anonymous said...

First off, thank you very much for all your hard work. Hat off to you. Now my experience with the extension filter.

I got two problems so far:
1) If you have two portlets deployed on the same page on Jboss portal. (Say the supplied UserPortlet from Jboss and a Simple portlet using tomahawk calendar.) If you change the day on the calendar jsf, and then hit minimized on the userporlet, your calendar portlet content disappeared.
2) If you minimize your JSF portlet, it throws an exception.

Now the underlying problem.
1) The resason is that the current FacesContext.getcurrentContext.getResponseWriter is not null, and therefore, it won't ask the renderkit to recreate one.
i.e. the byteArrayOutputStream can't capture the output.

2) get a ava.lang.IllegalStateException: No content type defined when trying to get a writer from the response

My fix:
1) store the byteArrayOutstream as portlet session scope object. If there's an existing response writer, reuse the old one. Otherwise, use a new one.

2) don't write to response if windows state is minimized.

I didn't do an exhaustive test, but here is the fix, please review and comment...:


/**
* Copyright 2006 Obelisk Financial Group, LLC
*/
package com.obelisk.sundial.view.portlet;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;

import javax.faces.context.FacesContext;
import javax.portlet.PortletException;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.WindowState;

import jp.sf.pal.tomahawk.filter.ExtensionsPortletFilter;
import jp.sf.pal.tomahawk.handler.ResourceHandlerImpl;
import jp.sf.pal.tomahawk.renderkit.ExtensionsRenderKit;
import jp.sf.pal.tomahawk.wrapper.HttpServletRequestWrapper;
import jp.sf.pal.tomahawk.wrapper.HttpServletResponseWrapper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.renderkit.html.util.AddResource;
import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
import org.apache.myfaces.webapp.filter.ExtensionsFilter;
import org.apache.myfaces.webapp.filter.ExtensionsResponseWrapper;
import org.apache.portals.bridges.portletfilter.PortletFilterChain;

/**
* @author Michael Chan
*
*/
public class MyFacesExtensionFilterPortlet extends ExtensionsPortletFilter {
private static final Log s_Log = LogFactory.getLog(MyFacesExtensionFilterPortlet.class);

public void renderFilter(RenderRequest request, RenderResponse response, PortletFilterChain chain) throws PortletException, IOException {
if (s_Log.isDebugEnabled())
{
s_Log.debug("called renderFilter.");
s_Log.debug("RenderRequest=" + request.getClass().getName());
s_Log.debug("RenderResponse=" + response.getClass().getName());
}
if (request.getAttribute(ExtensionsFilter.DOFILTER_CALLED) != null)
{
chain.renderFilter(request, response);
return;
}

request.setAttribute(ExtensionsFilter.DOFILTER_CALLED, "true");

HttpServletRequestWrapper extendedRequest = new HttpServletRequestWrapper(
request, getPortletConfig().getPortletContext());

// Serve resources
AddResource addResource = null;
try
{
addResource = AddResourceFactory.getInstance(extendedRequest);
}
catch (Throwable th)
{
s_Log.error("Exception while retrieving addResource", th);
throw new PortletException(th);
}

try
{
addResource.responseStarted();

if (addResource.requiresBuffer())
{
ResourceHandlerImpl resourceHandler = new ResourceHandlerImpl();

String outputEncoding = response.getCharacterEncoding();

ByteArrayOutputStream outputStream = getByteArrayOutputStream(request);

synchronized(outputStream) {
if (outputStream.size() > 0) {
s_Log.warn("the old outputStream has residual data - discarding:" + new String(outputStream.toByteArray()));
}
Writer streamWriter = new BufferedWriter(
new OutputStreamWriter(outputStream,
java.nio.charset.Charset
.forName(outputEncoding)));
request.setAttribute(ExtensionsRenderKit.WRITER, streamWriter);

HttpServletResponseWrapper servletResponse = new HttpServletResponseWrapper(
response);
ExtensionsResponseWrapper extendedResponse = new ExtensionsResponseWrapper(
servletResponse);

// call next rednerFilter
chain.renderFilter(request, response);

// flush stream
streamWriter.flush();

addResource.parseResponse(extendedRequest,
ResourceHandlerImpl.HTML_CONTENTS, servletResponse);
addResource.writeMyFacesJavascriptBeforeBodyEnd(
extendedRequest, servletResponse);
// Some headerInfo has to be added
addResource.writeWithFullHeader(extendedRequest,
extendedResponse);
addResource.writeResponse(extendedRequest, extendedResponse);
extendedResponse.finishResponse();

if (s_Log.isDebugEnabled())
{
s_Log.debug("renderFilter extendedResponse.toString()="
+ extendedResponse.toString());
}

resourceHandler.parse(extendedResponse.toString());

if (request.getWindowState() != WindowState.MINIMIZED) {
resourceHandler.renderBeforeContents(response);
}
resourceHandler.addResourcesToHead(request, response);
resourceHandler
.renderResourcesBeforeContents(request, response);

if (request.getWindowState() != WindowState.MINIMIZED) {
// Write Portlet content
String contents = null;
try
{
contents = new String(outputStream.toByteArray(),
outputEncoding);
outputStream.reset();
}
catch (UnsupportedEncodingException e)
{
s_Log.warn("Invalid encoding: " + outputEncoding);
contents = new String(outputStream.toByteArray());
}
response.getWriter().write(contents);
}
}
if (request.getWindowState() != WindowState.MINIMIZED) {
response.getWriter().flush();
}

resourceHandler.renderResourcesAfterContents(request, response);
if (request.getWindowState() != WindowState.MINIMIZED) {
response.getWriter().flush();
}
}
else
{
chain.renderFilter(request, response);
}
}
finally
{
addResource.responseFinished();
}
}

private ByteArrayOutputStream getByteArrayOutputStream(RenderRequest request) {
ByteArrayOutputStream outputStream = null;
PortletSession session = request.getPortletSession(true);
FacesContext facesContext = FacesContext.getCurrentInstance();
boolean fixRequired = true;
if (facesContext == null) {
s_Log.info("FacesContext == null: Do not need to reuse outputStream.");
fixRequired = false;
} else {
if (facesContext.getResponseWriter() == null) {
s_Log.info("response writer == null: Do not need to reuse outputStream.");
fixRequired = false;
}
}

Object oldOutputStream = session.getAttribute("MyFacesExtensionFilterPortlet.session.stored.outputStream");
if (fixRequired && oldOutputStream != null) {
s_Log.info("reusing old outputStream");
outputStream = (ByteArrayOutputStream) oldOutputStream;
} else {
outputStream = new ByteArrayOutputStream();
session.setAttribute("MyFacesExtensionFilterPortlet.session.stored.outputStream", outputStream);
}
return outputStream;
}
}

6:57 AM  
Anonymous Anonymous said...

Thank you for the investigation! It's a helpful information :)
Since I'm working on Tomahawk Bridge(MyFaces Bridge was replaced) right now, I'll fix them.

1:48 PM  
Blogger amagdenko said...

It works for Sun Portal Server
Thanks a lot!
But I added the following files in WEB-INF/lib folder

faces-response-filter-0.2.jar
portals-bridges-portletfilter-1.0.jar
tomahawk-1.1.6.jar
tomahawk-bridge-0.9.1.jar

10:58 PM  
Anonymous Anonymous said...

black mold exposure,
black mold symptoms of exposure,

wrought iron garden gates,
your nest iron garden gates, here,

hair styles for fine thin hair,
search hair styles for fine thin hair,

night vision binoculars,
buy, night vision binoculars,

lipitor reactions,
lipitor reactions,


luxury beach resort in the philippines,
beach resort in the philippines,

homeopathy for baby eczema.,
homeopathy for baby eczema.,

save big with great mineral makeup bargains,
companies marketing mineral makeups,

prodam iphone praha,
Apple prodam iphone praha,

iphone clone cect manual,
manual for iphone clone cect,

fero 52 binoculars night vision,
fero 52 night vision,

best night vision binoculars,
buy, best night vision binoculars,

computer programs to make photo albums,
computer programs, make photo albums,

4:26 AM  
Anonymous Anonymous said...

bez depozytu bonus free pieniadze dla nowych aktualne zastawienie bonusów
za darmo kapitał aktualny
sign-up bonus, no deposit bonus, match and no required darmowy kapitał startowy , and all bonuses in internet bez depozytu platformy
bonus bez depozytu full titan
poker za darmo , bonusy bez depozytu, graj w pokera bez obligacji generycznych bankroll buduj wolno ale dokładnie odbiór dla poker rooms Promocje dla nowych graczy
titan mansion party poker pkr bet most i inne platformy room
poker bankroll without uniqe poker room rooms deposit
Bonus senza deposito mansion Bônus de Pôquer,
titan poker no deposit 50 full tilt Bonus senza deposito
bankroll without deposit poker
poker rooms with titan poker bankroll free poker bankroll no deposit
Play at real money tables completely free with no deposit cash ... The Free Poker Bankroll are given to poker players who open a new account
free poker cash on poker
CD Poker. You will get $50 almost uniqe poker room's instantly and an ...
This free cash and promotions poker bankroll offer
bankroll is probably one of the most popular actual straigh forward of these actual benefit...
free poker no deposit required
wsop excluleading poker signup for Free No Deposit $100 Bankrolls. ...
sorry if spam for you ..

10:47 PM  

Post a Comment

<< Home