You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by so...@apache.org on 2010/01/06 20:18:09 UTC
svn commit: r896628 - in
/myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared:
application/ view/
Author: sobryan
Date: Wed Jan 6 19:18:08 2010
New Revision: 896628
URL: http://svn.apache.org/viewvc?rev=896628&view=rev
Log:
Changes to expose the ViewDeclarationLanguageBase class and all it's dependencies so that it may be used by the MyFaces Portlet Bridge as well.
Added:
myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/
myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/DefaultViewHandlerSupport.java
myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/FacesServletMapping.java
myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/InvalidViewIdException.java
myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/ViewHandlerSupport.java
myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/
myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/JspViewDeclarationLanguageBase.java
myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/ViewDeclarationLanguageBase.java
myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/ViewResponseWrapper.java
Added: myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/DefaultViewHandlerSupport.java
URL: http://svn.apache.org/viewvc/myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/DefaultViewHandlerSupport.java?rev=896628&view=auto
==============================================================================
--- myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/DefaultViewHandlerSupport.java (added)
+++ myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/DefaultViewHandlerSupport.java Wed Jan 6 19:18:08 2010
@@ -0,0 +1,396 @@
+/*
+ * 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.myfaces.shared.application;
+
+import java.net.MalformedURLException;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.faces.application.ViewHandler;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+
+/**
+ * A ViewHandlerSupport implementation for use with standard Java Servlet engines,
+ * ie an engine that supports javax.servlet, and uses a standard web.xml file.
+ *
+ * @author Mathias Broekelmann (latest modification by $Author: lu4242 $)
+ * @version $Revision: 887436 $ $Date: 2009-12-04 16:11:25 -0700 (Fri, 04 Dec 2009) $
+ */
+public class DefaultViewHandlerSupport implements ViewHandlerSupport
+{
+ /**
+ * Identifies the FacesServlet mapping in the current request map.
+ */
+ private static final String CACHED_SERVLET_MAPPING =
+ DefaultViewHandlerSupport.class.getName() + ".CACHED_SERVLET_MAPPING";
+
+ //private static final Log log = LogFactory.getLog(DefaultViewHandlerSupport.class);
+ private static final Logger log = Logger.getLogger(DefaultViewHandlerSupport.class.getName());
+
+ public String calculateViewId(FacesContext context, String viewId)
+ {
+ //If no viewId found, don't try to derive it, just continue.
+ if (viewId == null)
+ {
+ return null;
+ }
+ FacesServletMapping mapping = getFacesServletMapping(context);
+ if (mapping == null || mapping.isExtensionMapping())
+ {
+ viewId = handleSuffixMapping(context, viewId);
+ }
+ else if(mapping.isPrefixMapping())
+ {
+ viewId = handlePrefixMapping(viewId,mapping.getPrefix());
+ }
+ else if (viewId != null && mapping.getUrlPattern().startsWith(viewId))
+ {
+ throw new InvalidViewIdException(viewId);
+ }
+
+ //if(viewId != null)
+ //{
+ // return (checkResourceExists(context,viewId) ? viewId : null);
+ //}
+
+ return viewId; // return null if no physical resource exists
+ }
+
+ public String calculateAndCheckViewId(FacesContext context, String viewId)
+ {
+ //If no viewId found, don't try to derive it, just continue.
+ if (viewId == null)
+ {
+ return null;
+ }
+ FacesServletMapping mapping = getFacesServletMapping(context);
+ if (mapping == null || mapping.isExtensionMapping())
+ {
+ viewId = handleSuffixMapping(context, viewId);
+ }
+ else if(mapping.isPrefixMapping())
+ {
+ viewId = handlePrefixMapping(viewId,mapping.getPrefix());
+ }
+ else if (viewId != null && mapping.getUrlPattern().startsWith(viewId))
+ {
+ throw new InvalidViewIdException(viewId);
+ }
+
+ if(viewId != null)
+ {
+ return (checkResourceExists(context,viewId) ? viewId : null);
+ }
+
+ return viewId; // return null if no physical resource exists
+ }
+
+ public String calculateActionURL(FacesContext context, String viewId)
+ {
+ if (viewId == null || !viewId.startsWith("/"))
+ {
+ throw new IllegalArgumentException("ViewId must start with a '/': " + viewId);
+ }
+
+ FacesServletMapping mapping = getFacesServletMapping(context);
+ ExternalContext externalContext = context.getExternalContext();
+ String contextPath = externalContext.getRequestContextPath();
+ StringBuilder builder = new StringBuilder(contextPath);
+ if (mapping != null)
+ {
+ if (mapping.isExtensionMapping())
+ {
+ String[] contextSuffixes = getContextSuffix(context);
+ boolean founded = false;
+ for (String contextSuffix : contextSuffixes)
+ {
+ if (viewId.endsWith(contextSuffix))
+ {
+ builder.append(viewId.substring(0, viewId.indexOf(contextSuffix)));
+ builder.append(mapping.getExtension());
+ founded = true;
+ break;
+ }
+ }
+ if (!founded)
+ {
+ if(viewId.lastIndexOf(".") != -1 )
+ {
+ builder.append(viewId.substring(0,viewId.lastIndexOf(".")));
+ }
+ else
+ {
+ builder.append(viewId);
+ }
+ builder.append(contextSuffixes[0]);
+ }
+ }
+ else
+ {
+ builder.append(mapping.getPrefix());
+ builder.append(viewId);
+ }
+ }
+ else
+ {
+ builder.append(viewId);
+ }
+ String calculatedActionURL = builder.toString();
+ if (log.isLoggable(Level.FINEST))
+ {
+ log.finest("Calculated actionURL: '" + calculatedActionURL + "' for viewId: '" + viewId + "'");
+ }
+ return calculatedActionURL;
+ }
+
+ /**
+ * Read the web.xml file that is in the classpath and parse its internals to
+ * figure out how the FacesServlet is mapped for the current webapp.
+ */
+ protected FacesServletMapping getFacesServletMapping(FacesContext context)
+ {
+ Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
+
+ // Has the mapping already been determined during this request?
+ if (!requestMap.containsKey(CACHED_SERVLET_MAPPING))
+ {
+ ExternalContext externalContext = context.getExternalContext();
+ FacesServletMapping mapping =
+ calculateFacesServletMapping(
+ externalContext.getRequestServletPath(),
+ externalContext.getRequestPathInfo());
+
+ requestMap.put(CACHED_SERVLET_MAPPING, mapping);
+ }
+
+ return (FacesServletMapping) requestMap.get(CACHED_SERVLET_MAPPING);
+ }
+
+ /**
+ * Determines the mapping of the FacesServlet in the web.xml configuration
+ * file. However, there is no need to actually parse this configuration file
+ * as runtime information is sufficient.
+ *
+ * @param servletPath The servletPath of the current request
+ * @param pathInfo The pathInfo of the current request
+ * @return the mapping of the FacesServlet in the web.xml configuration file
+ */
+ protected static FacesServletMapping calculateFacesServletMapping(
+ String servletPath, String pathInfo)
+ {
+ if (pathInfo != null)
+ {
+ // If there is a "extra path", it's definitely no extension mapping.
+ // Now we just have to determine the path which has been specified
+ // in the url-pattern, but that's easy as it's the same as the
+ // current servletPath. It doesn't even matter if "/*" has been used
+ // as in this case the servletPath is just an empty string according
+ // to the Servlet Specification (SRV 4.4).
+ return FacesServletMapping.createPrefixMapping(servletPath);
+ }
+ else
+ {
+ // In the case of extension mapping, no "extra path" is available.
+ // Still it's possible that prefix-based mapping has been used.
+ // Actually, if there was an exact match no "extra path"
+ // is available (e.g. if the url-pattern is "/faces/*"
+ // and the request-uri is "/context/faces").
+ int slashPos = servletPath.lastIndexOf('/');
+ int extensionPos = servletPath.lastIndexOf('.');
+ if (extensionPos > -1 && extensionPos > slashPos)
+ {
+ String extension = servletPath.substring(extensionPos);
+ return FacesServletMapping.createExtensionMapping(extension);
+ }
+ else
+ {
+ // There is no extension in the given servletPath and therefore
+ // we assume that it's an exact match using prefix-based mapping.
+ return FacesServletMapping.createPrefixMapping(servletPath);
+ }
+ }
+ }
+
+ protected String[] getContextSuffix(FacesContext context)
+ {
+ String defaultSuffix = context.getExternalContext().getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
+ if (defaultSuffix == null)
+ {
+ defaultSuffix = ViewHandler.DEFAULT_SUFFIX;
+ }
+ return defaultSuffix.split(" ");
+ }
+
+ protected String getFaceletsContextSuffix(FacesContext context)
+ {
+ String defaultSuffix = context.getExternalContext().getInitParameter(ViewHandler.FACELETS_SUFFIX_PARAM_NAME);
+ if (defaultSuffix == null)
+ {
+ defaultSuffix = ViewHandler.DEFAULT_FACELETS_SUFFIX;
+ }
+ return defaultSuffix;
+ }
+
+
+
+ protected String[] getFaceletsViewMappings(FacesContext context)
+ {
+ String faceletsViewMappings= context.getExternalContext().getInitParameter(ViewHandler.FACELETS_VIEW_MAPPINGS_PARAM_NAME);
+ if(faceletsViewMappings == null) //consider alias facelets.VIEWMAPPINGS
+ {
+ faceletsViewMappings= context.getExternalContext().getInitParameter("facelets.VIEWMAPPINGS");
+ }
+
+ return faceletsViewMappings == null ? null : faceletsViewMappings.split(";");
+ }
+
+ /**
+ * Return the normalized viewId according to the algorithm specified in 7.5.2
+ * by stripping off any number of occurrences of the prefix mapping from the viewId.
+ * <p/>
+ * For example, both /faces/view.xhtml and /faces/faces/faces/view.xhtml would both return view.xhtml
+ * F
+ */
+ protected String handlePrefixMapping(String viewId, String prefix)
+ {
+ /* If prefix mapping (such as "/faces/*") is used for FacesServlet, normalize the viewId according to the following
+ algorithm, or its semantic equivalent, and return it.
+
+ Remove any number of occurrences of the prefix mapping from the viewId. For example, if the incoming value
+ was /faces/faces/faces/view.xhtml the result would be simply view.xhtml.
+ */
+ String uri = viewId;
+ prefix = prefix + '/'; //need to make sure its really /faces/* and not /facesPage.xhtml
+ while (uri.startsWith(prefix))
+ {
+ uri = uri.substring(prefix.length() - 1); //cut off only /faces, leave the trailing '/' char for the next iteration
+ }
+ //now delete any remaining leading '/'
+ // TODO: CJH: I don't think this is correct, considering that getActionURL() expects everything to
+ // start with '/', and in the suffix case we only mess with the suffix and leave leading
+ // slashes alone. Please review...
+ /*if(uri.startsWith("/"))
+ {
+ uri = uri.substring(1);
+ }*/
+
+ return uri;
+ }
+
+ /**
+ * Return the viewId with any non-standard suffix stripped off and replaced with
+ * the default suffix configured for the specified context.
+ * <p/>
+ * For example, an input parameter of "/foo.jsf" may return "/foo.jsp".
+ */
+ protected String handleSuffixMapping(FacesContext context, String requestViewId)
+ {
+ String[] faceletsViewMappings = getFaceletsViewMappings(context);
+ String[] jspDefaultSuffixes = getContextSuffix(context);
+
+ int slashPos = requestViewId.lastIndexOf('/');
+ int extensionPos = requestViewId.lastIndexOf('.');
+
+ //Try to locate any resource that match with the expected id
+ for (String defaultSuffix : jspDefaultSuffixes)
+ {
+ StringBuilder builder = new StringBuilder(requestViewId);
+
+ if (extensionPos > -1 && extensionPos > slashPos)
+ {
+ builder.replace(extensionPos, requestViewId.length(), defaultSuffix);
+ }
+ else
+ {
+ builder.append(defaultSuffix);
+ }
+ String candidateViewId = builder.toString();
+
+ if( faceletsViewMappings != null && faceletsViewMappings.length > 0 )
+ {
+ for (String mapping : faceletsViewMappings)
+ {
+ if(mapping.startsWith("/"))
+ {
+ continue; //skip this entry, its a prefix mapping
+ }
+ if(mapping.equals(candidateViewId))
+ {
+ return candidateViewId;
+ }
+ if(mapping.startsWith(".")) //this is a wildcard entry
+ {
+ builder.setLength(0); //reset/reuse the builder object
+ builder.append(candidateViewId);
+ builder.replace(candidateViewId.lastIndexOf('.'), candidateViewId.length(), mapping);
+ String tempViewId = builder.toString();
+ if(checkResourceExists(context,tempViewId))
+ return tempViewId;
+ }
+ }
+ }
+
+ // forced facelets mappings did not match or there were no entries in faceletsViewMappings array
+ if(checkResourceExists(context,candidateViewId))
+ return candidateViewId;
+
+ }
+
+ //jsp suffixes didn't match, try facelets suffix
+ String faceletsDefaultSuffix = this.getFaceletsContextSuffix(context);
+ StringBuilder builder = new StringBuilder(requestViewId);
+
+ if (extensionPos > -1 && extensionPos > slashPos)
+ {
+ builder.replace(extensionPos, requestViewId.length(), faceletsDefaultSuffix);
+ }
+ else
+ {
+ builder.append(faceletsDefaultSuffix);
+ }
+
+ String candidateViewId = builder.toString();
+ if(checkResourceExists(context,candidateViewId))
+ return candidateViewId;
+
+ if(checkResourceExists(context,requestViewId))
+ return requestViewId;
+
+ return null;
+ }
+
+ protected boolean checkResourceExists(FacesContext context, String viewId)
+ {
+ try
+ {
+ if (context.getExternalContext().getResource(viewId) != null)
+ {
+ return true;
+ }
+ }
+ catch(MalformedURLException e)
+ {
+ //ignore and move on
+ }
+ return false;
+ }
+}
Added: myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/FacesServletMapping.java
URL: http://svn.apache.org/viewvc/myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/FacesServletMapping.java?rev=896628&view=auto
==============================================================================
--- myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/FacesServletMapping.java (added)
+++ myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/FacesServletMapping.java Wed Jan 6 19:18:08 2010
@@ -0,0 +1,158 @@
+/*
+ * 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.myfaces.shared.application;
+
+/**
+ * Represents a mapping entry of the FacesServlet in the web.xml
+ * configuration file.
+ */
+public class FacesServletMapping
+{
+
+ /**
+ * The path ("/faces", for example) which has been specified in the
+ * url-pattern of the FacesServlet mapping.
+ */
+ private String prefix;
+
+ /**
+ * The extension (".jsf", for example) which has been specified in the
+ * url-pattern of the FacesServlet mapping.
+ */
+ private String extension;
+
+ /**
+ * Creates a new FacesServletMapping object using prefix mapping.
+ *
+ * @param path The path ("/faces", for example) which has been specified
+ * in the url-pattern of the FacesServlet mapping.
+ * @return a newly created FacesServletMapping
+ */
+ public static FacesServletMapping createPrefixMapping(String path)
+ {
+ FacesServletMapping mapping = new FacesServletMapping();
+ mapping.setPrefix(path);
+ return mapping;
+ }
+
+ /**
+ * Creates a new FacesServletMapping object using extension mapping.
+ *
+ * @param path The extension (".jsf", for example) which has been
+ * specified in the url-pattern of the FacesServlet mapping.
+ * @return a newly created FacesServletMapping
+ */
+ public static FacesServletMapping createExtensionMapping(
+ String extension)
+ {
+ FacesServletMapping mapping = new FacesServletMapping();
+ mapping.setExtension(extension);
+ return mapping;
+ }
+
+ /**
+ * Returns the path ("/faces", for example) which has been specified in
+ * the url-pattern of the FacesServlet mapping. If this mapping is based
+ * on an extension, <code>null</code> will be returned. Note that this
+ * path is not the same as the specified url-pattern as the trailing
+ * "/*" is omitted.
+ *
+ * @return the path which has been specified in the url-pattern
+ */
+ public String getPrefix()
+ {
+ return prefix;
+ }
+
+ /**
+ * Sets the path ("/faces/", for example) which has been specified in
+ * the url-pattern.
+ *
+ * @param path The path which has been specified in the url-pattern
+ */
+ public void setPrefix(String path)
+ {
+ this.prefix = path;
+ }
+
+ /**
+ * Returns the extension (".jsf", for example) which has been specified
+ * in the url-pattern of the FacesServlet mapping. If this mapping is
+ * not based on an extension, <code>null</code> will be returned.
+ *
+ * @return the extension which has been specified in the url-pattern
+ */
+ public String getExtension()
+ {
+ return extension;
+ }
+
+ /**
+ * Sets the extension (".jsf", for example) which has been specified in
+ * the url-pattern of the FacesServlet mapping.
+ *
+ * @param extension The extension which has been specified in the url-pattern
+ */
+ public void setExtension(String extension)
+ {
+ this.extension = extension;
+ }
+
+ /**
+ * Indicates whether this mapping is based on an extension (e.g.
+ * ".jsp").
+ *
+ * @return <code>true</code>, if this mapping is based is on an
+ * extension, <code>false</code> otherwise
+ */
+ public boolean isExtensionMapping()
+ {
+ return extension != null;
+ }
+
+ /**
+ * Indicates whether this mapping is based on a prefix (e.g.
+ * /faces/*").
+ *
+ * @return <code>true</code>, if this mapping is based is on a
+ * prefix, <code>false</code> otherwise
+ */
+ public boolean isPrefixMapping()
+ {
+ return prefix != null;
+ }
+
+ /**
+ * Returns the url-pattern entry for this servlet mapping.
+ *
+ * @return the url-pattern entry for this servlet mapping
+ */
+ public String getUrlPattern()
+ {
+ if (isExtensionMapping())
+ {
+ return "*" + extension;
+ }
+ else
+ {
+ return prefix + "/*";
+ }
+ }
+
+}
\ No newline at end of file
Added: myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/InvalidViewIdException.java
URL: http://svn.apache.org/viewvc/myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/InvalidViewIdException.java?rev=896628&view=auto
==============================================================================
--- myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/InvalidViewIdException.java (added)
+++ myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/InvalidViewIdException.java Wed Jan 6 19:18:08 2010
@@ -0,0 +1,64 @@
+/*
+ * 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.myfaces.shared.application;
+
+/**
+ * @author Mathias Broekelmann (latest modification by $Author: mbr $)
+ * @version $Revision: 517404 $ $Date: 2007-03-12 15:17:24 -0600 (Mon, 12 Mar 2007) $
+ */
+public class InvalidViewIdException extends RuntimeException
+{
+
+ /**
+ *
+ */
+ public InvalidViewIdException()
+ {
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param message
+ */
+ public InvalidViewIdException(String message)
+ {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param cause
+ */
+ public InvalidViewIdException(Throwable cause)
+ {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public InvalidViewIdException(String message, Throwable cause)
+ {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+}
Added: myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/ViewHandlerSupport.java
URL: http://svn.apache.org/viewvc/myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/ViewHandlerSupport.java?rev=896628&view=auto
==============================================================================
--- myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/ViewHandlerSupport.java (added)
+++ myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/application/ViewHandlerSupport.java Wed Jan 6 19:18:08 2010
@@ -0,0 +1,49 @@
+/*
+ * 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.myfaces.shared.application;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * TODO: RENAME - This class is now used by ViewDeclarationLanguageBase
+ *
+ * A utility class to isolate a ViewHandler implementation from the underlying
+ * request/response framework.
+ * <p>
+ * For example, an implementation of this interface might support javax.servlet,
+ * javax.portlet, or some other mechanism.
+ *
+ * @author Mathias Broekelmann (latest modification by $Author: lu4242 $)
+ * @version $Revision: 887436 $ $Date: 2009-12-04 16:11:25 -0700 (Fri, 04 Dec 2009) $
+ */
+public interface ViewHandlerSupport
+{
+ String calculateViewId(FacesContext context, String viewId);
+
+ String calculateAndCheckViewId(FacesContext context, String viewId);
+
+ /**
+ * Return a string containing a webapp-relative URL that the user can invoke
+ * to render the specified view.
+ * <p>
+ * URLs and ViewIds are not quite the same; for example a url of "/foo.jsf"
+ * or "/faces/foo.jsp" may be needed to access the view "/foo.jsp".
+ */
+ String calculateActionURL(FacesContext facesContext, String viewId);
+}
Added: myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/JspViewDeclarationLanguageBase.java
URL: http://svn.apache.org/viewvc/myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/JspViewDeclarationLanguageBase.java?rev=896628&view=auto
==============================================================================
--- myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/JspViewDeclarationLanguageBase.java (added)
+++ myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/JspViewDeclarationLanguageBase.java Wed Jan 6 19:18:08 2010
@@ -0,0 +1,351 @@
+/*
+ * 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.myfaces.shared.view;
+
+import java.beans.BeanInfo;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.Resource;
+import javax.faces.application.StateManager;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+import javax.faces.view.StateManagementStrategy;
+import javax.faces.view.ViewMetadata;
+
+import org.apache.myfaces.shared.application.DefaultViewHandlerSupport;
+import org.apache.myfaces.shared.application.ViewHandlerSupport;
+import org.apache.myfaces.shared.config.MyfacesConfig;
+import org.apache.myfaces.shared.renderkit.html.util.JavascriptUtils;
+
+
+public abstract class JspViewDeclarationLanguageBase extends ViewDeclarationLanguageBase
+{
+ private static final Logger log = Logger.getLogger(JspViewDeclarationLanguageBase.class.getName());
+
+ private static final String FORM_STATE_MARKER = "<!-...@-->";
+ private static final String AFTER_VIEW_TAG_CONTENT_PARAM = JspViewDeclarationLanguageBase.class
+ + ".AFTER_VIEW_TAG_CONTENT";
+ private static final int FORM_STATE_MARKER_LEN = FORM_STATE_MARKER.length();
+
+ private ViewHandlerSupport _cachedViewHandlerSupport;
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public BeanInfo getComponentMetadata(FacesContext context, Resource componentResource)
+ {
+ throw new UnsupportedOperationException();
+ }
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Resource getScriptComponentResource(FacesContext context, Resource componentResource)
+ {
+ throw new UnsupportedOperationException();
+ }
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void renderView(FacesContext context, UIViewRoot view) throws IOException
+ {
+ //Try not to use native objects in this class. Both MyFaces and the bridge
+ //provide implementations of buildView but they do not override this class.
+ checkNull(context, "context");
+ checkNull(view, "view");
+
+ // do not render the view if the rendered attribute for the view is false
+ if (!view.isRendered())
+ {
+ if (log.isLoggable(Level.FINEST))
+ log.finest("View is not rendered");
+ return;
+ }
+
+ ExternalContext externalContext = context.getExternalContext();
+
+ String viewId = context.getViewRoot().getViewId();
+
+ if (log.isLoggable(Level.FINEST))
+ log.finest("Rendering JSP view: " + viewId);
+
+
+ // handle character encoding as of section 2.5.2.2 of JSF 1.1
+ if(null != externalContext.getSession(false))
+ {
+ externalContext.getSessionMap().put(ViewHandler.CHARACTER_ENCODING_KEY, externalContext.getResponseCharacterEncoding());
+ }
+
+ // render the view in this method (since JSF 1.2)
+ RenderKitFactory renderFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ RenderKit renderKit = renderFactory.getRenderKit(context, view.getRenderKitId());
+
+ ResponseWriter responseWriter = context.getResponseWriter();
+ if (responseWriter == null)
+ {
+ responseWriter = renderKit.createResponseWriter(externalContext.getResponseOutputWriter(), null, externalContext.getRequestCharacterEncoding());
+ context.setResponseWriter(responseWriter);
+ }
+
+ ResponseWriter oldResponseWriter = responseWriter;
+ StateMarkerAwareWriter stateAwareWriter = null;
+
+ StateManager stateManager = context.getApplication().getStateManager();
+ if (stateManager.isSavingStateInClient(context))
+ {
+ stateAwareWriter = new StateMarkerAwareWriter();
+
+ // Create a new response-writer using as an underlying writer the stateAwareWriter
+ // Effectively, all output will be buffered in the stateAwareWriter so that later
+ // this writer can replace the state-markers with the actual state.
+ responseWriter = oldResponseWriter.cloneWithWriter(stateAwareWriter);
+ context.setResponseWriter(responseWriter);
+ }
+
+ actuallyRenderView(context, view);
+
+ if(oldResponseWriter != null)
+ {
+ context.setResponseWriter(oldResponseWriter);
+ }
+
+
+ // We're done with the document - now we can write all content
+ // to the response, properly replacing the state-markers on the way out
+ // by using the stateAwareWriter
+ if (stateManager.isSavingStateInClient(context))
+ {
+ stateAwareWriter.flushToWriter(externalContext.getResponseOutputWriter());
+ }
+ else
+ {
+ stateManager.saveView(context);
+ }
+
+ // Final step - we output any content in the wrappedResponse response from above to the response,
+ // removing the wrappedResponse response from the request, we don't need it anymore
+ ViewResponseWrapper afterViewTagResponse = (ViewResponseWrapper) externalContext.getRequestMap()
+ .get(AFTER_VIEW_TAG_CONTENT_PARAM);
+ externalContext.getRequestMap().remove(AFTER_VIEW_TAG_CONTENT_PARAM);
+
+ if (afterViewTagResponse != null)
+ {
+ afterViewTagResponse.flushToWriter(externalContext.getResponseOutputWriter(), externalContext.getResponseCharacterEncoding());
+ }
+
+ //TODO sobryan: Is this right?
+ context.getResponseWriter().flush();
+ }
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ViewMetadata getViewMetadata(FacesContext context, String viewId)
+ {
+ // Not necessary given that this method always returns null, but staying true to
+ // the spec.
+
+ checkNull(context, "context");
+ //checkNull(viewId, "viewId");
+
+ // JSP impl must return null.
+
+ return null;
+ }
+
+ protected void setAfterViewTagResponseWrapper(ExternalContext ec, ViewResponseWrapper wrapper)
+ {
+ ec.getRequestMap().put(AFTER_VIEW_TAG_CONTENT_PARAM, wrapper);
+ }
+
+ /**
+ * Render the view now - properly setting and resetting the response writer
+ */
+ private void actuallyRenderView(FacesContext facesContext, UIViewRoot viewToRender)
+ throws IOException
+ {
+ // Set the new ResponseWriter into the FacesContext, saving the old one aside.
+ ResponseWriter responseWriter = facesContext.getResponseWriter();
+
+ // Now we actually render the document
+ // Call startDocument() on the ResponseWriter.
+ responseWriter.startDocument();
+
+ // Call encodeAll() on the UIViewRoot
+ viewToRender.encodeAll(facesContext);
+
+ // Call endDocument() on the ResponseWriter
+ responseWriter.endDocument();
+
+ responseWriter.flush();
+ }
+
+ @Override
+ public StateManagementStrategy getStateManagementStrategy(FacesContext context, String viewId)
+ {
+ return null;
+ }
+
+ @Override
+ protected String calculateViewId(FacesContext context, String viewId)
+ {
+ if (_cachedViewHandlerSupport == null)
+ {
+ _cachedViewHandlerSupport = new DefaultViewHandlerSupport();
+ }
+
+ return _cachedViewHandlerSupport.calculateViewId(context, viewId);
+ }
+
+ /**
+ * Writes the response and replaces the state marker tags with the state information for the current context
+ */
+ private static class StateMarkerAwareWriter extends Writer
+ {
+ private StringBuilder buf;
+
+ public StateMarkerAwareWriter()
+ {
+ this.buf = new StringBuilder();
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ }
+
+ @Override
+ public void flush() throws IOException
+ {
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException
+ {
+ if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0))
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ else if (len == 0)
+ {
+ return;
+ }
+ buf.append(cbuf, off, len);
+ }
+
+ public StringBuilder getStringBuilder()
+ {
+ return buf;
+ }
+
+ public void flushToWriter(Writer writer) throws IOException
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ StateManager stateManager = facesContext.getApplication().getStateManager();
+
+ StringWriter stateWriter = new StringWriter();
+ ResponseWriter realWriter = facesContext.getResponseWriter();
+ facesContext.setResponseWriter(realWriter.cloneWithWriter(stateWriter));
+
+ Object serializedView = stateManager.saveView(facesContext);
+
+ stateManager.writeState(facesContext, serializedView);
+ facesContext.setResponseWriter(realWriter);
+
+ StringBuilder contentBuffer = getStringBuilder();
+ String state = stateWriter.getBuffer().toString();
+
+ ExternalContext extContext = facesContext.getExternalContext();
+ if (JavascriptUtils.isJavascriptAllowed(extContext)
+ && MyfacesConfig.getCurrentInstance(extContext).isViewStateJavascript())
+ {
+ // If javascript viewstate is enabled no state markers were written
+ write(contentBuffer, 0, contentBuffer.length(), writer);
+ writer.write(state);
+ }
+ else
+ {
+ // If javascript viewstate is disabled state markers must be replaced
+ int lastFormMarkerPos = 0;
+ int formMarkerPos = 0;
+ // Find all state markers and write out actual state instead
+ while ((formMarkerPos = contentBuffer.indexOf(JspViewDeclarationLanguageBase.FORM_STATE_MARKER, formMarkerPos)) > -1)
+ {
+ // Write content before state marker
+ write(contentBuffer, lastFormMarkerPos, formMarkerPos, writer);
+ // Write state and move position in buffer after marker
+ writer.write(state);
+ formMarkerPos += JspViewDeclarationLanguageBase.FORM_STATE_MARKER_LEN;
+ lastFormMarkerPos = formMarkerPos;
+ }
+ // Write content after last state marker
+ if (lastFormMarkerPos < contentBuffer.length())
+ {
+ write(contentBuffer, lastFormMarkerPos, contentBuffer.length(), writer);
+ }
+ }
+
+ }
+
+ /**
+ * Writes the content of the specified StringBuffer from index <code>beginIndex</code> to index
+ * <code>endIndex - 1</code>.
+ *
+ * @param contentBuffer
+ * the <code>StringBuffer</code> to copy content from
+ * @param beginIndex
+ * the beginning index, inclusive.
+ * @param endIndex
+ * the ending index, exclusive
+ * @param writer
+ * the <code>Writer</code> to write to
+ * @throws IOException
+ * if an error occurs writing to specified <code>Writer</code>
+ */
+ private void write(StringBuilder contentBuffer, int beginIndex, int endIndex, Writer writer) throws IOException
+ {
+ int index = beginIndex;
+ int bufferSize = 2048;
+ char[] bufToWrite = new char[bufferSize];
+
+ while (index < endIndex)
+ {
+ int maxSize = Math.min(bufferSize, endIndex - index);
+
+ contentBuffer.getChars(index, index + maxSize, bufToWrite, 0);
+ writer.write(bufToWrite, 0, maxSize);
+
+ index += bufferSize;
+ }
+ }
+ }
+
+
+}
Added: myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/ViewDeclarationLanguageBase.java
URL: http://svn.apache.org/viewvc/myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/ViewDeclarationLanguageBase.java?rev=896628&view=auto
==============================================================================
--- myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/ViewDeclarationLanguageBase.java (added)
+++ myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/ViewDeclarationLanguageBase.java Wed Jan 6 19:18:08 2010
@@ -0,0 +1,147 @@
+/*
+ * 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.myfaces.shared.view;
+
+import javax.faces.application.Application;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.view.ViewDeclarationLanguage;
+
+import org.apache.myfaces.shared.application.InvalidViewIdException;
+
+/**
+ * @author Simon Lessard (latest modification by $Author: slessard $)
+ * @version $Revision: 696523 $ $Date: 2009-03-22 15:03:20 -0400 (mer., 17 sept. 2008) $
+ *
+ * @since 2.0
+ */
+public abstract class ViewDeclarationLanguageBase extends ViewDeclarationLanguage
+{
+
+ /**
+ * Process the specification required algorithm that is generic to all PDL.
+ *
+ * @param context
+ * @param viewId
+ */
+ public UIViewRoot createView(FacesContext context, String viewId)
+ {
+ checkNull(context, "context");
+ //checkNull(viewId, "viewId");
+
+ try
+ {
+ viewId = calculateViewId(context, viewId);
+
+ Application application = context.getApplication();
+
+ // Create a new UIViewRoot object instance using Application.createComponent(UIViewRoot.COMPONENT_TYPE).
+ UIViewRoot newViewRoot = (UIViewRoot) application.createComponent(UIViewRoot.COMPONENT_TYPE);
+ UIViewRoot oldViewRoot = context.getViewRoot();
+ if (oldViewRoot == null)
+ {
+ // If not, this method must call calculateLocale() and calculateRenderKitId(), and store the results
+ // as the values of the locale and renderKitId, proeprties, respectively, of the newly created
+ // UIViewRoot.
+ ViewHandler handler = application.getViewHandler();
+ newViewRoot.setLocale(handler.calculateLocale(context));
+ newViewRoot.setRenderKitId(handler.calculateRenderKitId(context));
+ }
+ else
+ {
+ // If there is an existing UIViewRoot available on the FacesContext, this method must copy its locale
+ // and renderKitId to this new view root
+ newViewRoot.setLocale(oldViewRoot.getLocale());
+ newViewRoot.setRenderKitId(oldViewRoot.getRenderKitId());
+ }
+
+ // TODO: VALIDATE - The spec is silent on the following line, but I feel bad if I don't set it
+ newViewRoot.setViewId(viewId);
+
+ return newViewRoot;
+ }
+ catch (InvalidViewIdException e)
+ {
+ // If no viewId could be identified, or the viewId is exactly equal to the servlet mapping,
+ // send the response error code SC_NOT_FOUND with a suitable message to the client.
+ sendSourceNotFound(context, e.getMessage());
+
+ // TODO: VALIDATE - Spec is silent on the return value when an error was sent
+ return null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public UIViewRoot restoreView(FacesContext context, String viewId)
+ {
+ checkNull(context, "context");
+ //checkNull(viewId, "viewId");
+
+ Application application = context.getApplication();
+
+ ViewHandler applicationViewHandler = application.getViewHandler();
+
+ String renderKitId = applicationViewHandler.calculateRenderKitId(context);
+
+ UIViewRoot viewRoot = application.getStateManager().restoreView(context, viewId, renderKitId);
+
+ return viewRoot;
+ }
+
+ /**
+ * Calculates the effective view identifier for the specified raw view identifier.
+ *
+ * @param context le current FacesContext
+ * @param viewId the raw view identifier
+ *
+ * @return the effective view identifier
+ */
+ protected abstract String calculateViewId(FacesContext context, String viewId);
+
+ /**
+ * Send a source not found to the client. Although it can be considered ok in JSP mode,
+ * I think it's pretty lame to have this kind of requirement at VDL level considering VDL
+ * represents the page --> JSF tree link, not the transport layer required to send a
+ * SC_NOT_FOUND.
+ *
+ * @param context le current FacesContext
+ * @param message the message associated with the error
+ */
+ protected abstract void sendSourceNotFound(FacesContext context, String message);
+
+ /**
+ * Check if the specified value of a param is <code>null</code>.
+ *
+ * @param o the parameter's value
+ * @param param the parameter's name
+ *
+ * @throws NullPointerException if the value is <code>null</code>
+ */
+ protected void checkNull(final Object o, final String param)
+ {
+ if (o == null)
+ {
+ throw new NullPointerException(param + " can not be null.");
+ }
+ }
+}
Added: myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/ViewResponseWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/ViewResponseWrapper.java?rev=896628&view=auto
==============================================================================
--- myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/ViewResponseWrapper.java (added)
+++ myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/view/ViewResponseWrapper.java Wed Jan 6 19:18:08 2010
@@ -0,0 +1,27 @@
+/*
+ * 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.myfaces.shared.view;
+
+import java.io.IOException;
+import java.io.Writer;
+
+public interface ViewResponseWrapper
+{
+ void flushToWriter(Writer writer,String encoding) throws IOException;
+}