blob: b801cce302379efe182c9ef009d3ebd7dab1588b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.faces;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.CascadingIOException;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.acting.Action;
import org.apache.cocoon.environment.Context;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Response;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.environment.portlet.ActionResponse;
import org.apache.cocoon.environment.portlet.PortletResponse;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.faces.webapp.FacesServlet;
import java.io.IOException;
import java.util.Map;
/**
* @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
* @version CVS $Id$
*/
public class FacesAction extends AbstractLogEnabled
implements Action, ThreadSafe, Contextualizable,
Configurable, Initializable {
public static final String REQUEST_REDIRECTOR_ATTRIBUTE = "org.apache.cocoon.faces.REDIRECTOR";
private Context context;
private String cutPrefix;
private String cutSuffix;
private String addPrefix;
private String addSuffix;
private FacesContextFactory facesContextFactory;
private Application application;
private Lifecycle lifecycle;
/**
*
*/
class RedirectorImpl implements FacesRedirector {
private Redirector redirector;
private Request request;
private Response response;
RedirectorImpl (Redirector redirector, Request request, Response response) {
this.redirector = redirector;
this.request = request;
this.response = response;
}
public void dispatch(String url) throws IOException {
// System.err.println("INFO: Dispatching to " + url);
try {
// TODO: HACK: Dependency on ActionResponse
if (response instanceof ActionResponse) {
// Can't render response. Redirect to another face.
redirector.redirect(true, url);
} else {
// Need to render face. Convert face URL to view URL.
int begin = 0;
int end = url.length();
if (cutPrefix != null && url.startsWith(cutPrefix)) {
begin = cutPrefix.length();
}
if (cutSuffix != null && url.endsWith(cutSuffix)) {
end = end - cutSuffix.length();
}
StringBuffer buffer = new StringBuffer();
if (addPrefix != null) {
buffer.append(addPrefix);
}
if (begin < end) {
buffer.append(url.substring(begin, end));
}
if (addSuffix != null) {
buffer.append(addSuffix);
}
url = buffer.toString();
// System.err.println("INFO: Dispatching to view " + url);
redirector.redirect(true, "cocoon:/" + url);
}
} catch (Exception e) {
throw new CascadingIOException(e);
}
}
public void redirect(String url) throws IOException {
// System.err.println("redirect: " + url);
try {
redirector.redirect(true, url);
} catch (Exception e) {
throw new CascadingIOException(e);
}
}
public String encodeActionURL(String url) {
// System.err.println("encodeActionURL: " + url);
// TODO: HACK: Dependency on PortletResponse
if (response instanceof PortletResponse) {
final String context = request.getContextPath();
if (url.startsWith(context)) {
url = url.substring(context.length());
// System.err.println("encodeActionURL: cut: " + url);
}
return "portlet:action:" + response.encodeURL(url);
} else {
return response.encodeURL(url);
}
}
public String encodeResourceURL(String url) {
// System.err.println("encodeResourceURL: " + url);
return response.encodeURL(url);
}
}
public void contextualize(org.apache.avalon.framework.context.Context avalonContext) throws ContextException {
context = (Context) avalonContext.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
}
public void configure(Configuration configuration) throws ConfigurationException {
this.cutPrefix = configuration.getChild("cut-prefix").getValue(null);
this.cutSuffix = configuration.getChild("cut-suffix").getValue(".faces");
this.addPrefix = configuration.getChild("add-prefix").getValue(null);
this.addSuffix = configuration.getChild("add-suffix").getValue(".view");
}
public void initialize() throws Exception {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Initializing FacesAction");
}
facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
// facesContextFactory = new FacesContextFactoryImpl();
ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
application = applicationFactory.getApplication();
// application.setDefaultRenderKitId("COCOON_BASIC_XHTML");
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
String lifecycleID = context.getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
if (lifecycleID == null) {
lifecycleID = "DEFAULT";
}
lifecycle = lifecycleFactory.getLifecycle(lifecycleID);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Faces context factory is " + facesContextFactory.getClass().getName());
getLogger().debug("Faces application factory is " + applicationFactory.getClass().getName());
getLogger().debug("Faces lifecycle factory is " + lifecycleFactory.getClass().getName());
}
}
public Map act(Redirector redirector,
SourceResolver resolver,
Map objectModel,
String source,
Parameters parameters)
throws Exception {
Request request = ObjectModelHelper.getRequest(objectModel);
Response response = ObjectModelHelper.getResponse(objectModel);
// Pass FacesRedirector to the FacesContext implementation.
request.setAttribute(REQUEST_REDIRECTOR_ATTRIBUTE, new RedirectorImpl(redirector, request, response));
FacesContext context = facesContextFactory.getFacesContext(this.context, request, response, lifecycle);
try {
lifecycle.execute(context);
lifecycle.render(context);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Request processed; View root ID: " + context.getViewRoot().getId());
}
} catch (FacesException e) {
throw new ProcessingException("Failed to process faces request", e);
} finally {
context.release();
}
return null;
}
}