| /* |
| * 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.view.facelets.compiler; |
| |
| import org.apache.myfaces.util.lang.ArrayUtils; |
| import org.apache.myfaces.util.WebConfigParamUtils; |
| import org.apache.myfaces.view.facelets.tag.AbstractTagLibrary; |
| import org.apache.myfaces.view.facelets.tag.TagLibrary; |
| import org.apache.myfaces.view.facelets.tag.composite.CompositeComponentResourceTagHandler; |
| import org.apache.myfaces.view.facelets.tag.composite.CompositeResouceWrapper; |
| |
| import javax.faces.FacesException; |
| import javax.faces.application.Resource; |
| import javax.faces.application.ResourceHandler; |
| import javax.faces.application.ViewHandler; |
| import javax.faces.context.ExternalContext; |
| import javax.faces.context.FacesContext; |
| import javax.faces.view.facelets.ComponentConfig; |
| import javax.faces.view.facelets.FaceletHandler; |
| import javax.faces.view.facelets.Tag; |
| import javax.faces.view.facelets.TagConfig; |
| import javax.faces.view.facelets.TagHandler; |
| import java.lang.reflect.Method; |
| import java.net.URL; |
| import java.util.logging.Logger; |
| import java.util.regex.Pattern; |
| import org.apache.myfaces.config.element.facelets.FaceletBehaviorTag; |
| import org.apache.myfaces.config.element.facelets.FaceletComponentTag; |
| import org.apache.myfaces.config.element.facelets.FaceletConverterTag; |
| import org.apache.myfaces.config.element.facelets.FaceletFunction; |
| import org.apache.myfaces.config.element.facelets.FaceletHandlerTag; |
| import org.apache.myfaces.config.element.facelets.FaceletSourceTag; |
| import org.apache.myfaces.config.element.facelets.FaceletTag; |
| import org.apache.myfaces.config.element.facelets.FaceletTagLibrary; |
| import org.apache.myfaces.config.element.facelets.FaceletValidatorTag; |
| import org.apache.myfaces.util.lang.Assert; |
| import org.apache.myfaces.util.lang.ClassUtils; |
| import org.apache.myfaces.util.lang.StringUtils; |
| |
| /** |
| * Handles creating a {@link org.apache.myfaces.view.facelets.tag.TagLibrary TagLibrary} |
| * from a {@link java.net.URL URL} source. |
| * |
| * @author Jacob Hookom |
| * @version $Id$ |
| */ |
| public final class TagLibraryConfig |
| { |
| protected final static Logger log = Logger.getLogger(TagLibraryConfig.class.getName()); |
| |
| private static class TagLibraryImpl extends AbstractTagLibrary |
| { |
| private String _compositeLibraryName; |
| |
| private final ResourceHandler _resourceHandler; |
| private Pattern _acceptPatterns; |
| private String _extension; |
| private String[] _defaultSuffixesArray; |
| |
| public TagLibraryImpl(FacesContext facesContext, String namespace) |
| { |
| super(namespace); |
| _compositeLibraryName = null; |
| _resourceHandler = facesContext.getApplication().getResourceHandler(); |
| ExternalContext externalContext = facesContext.getExternalContext(); |
| |
| _acceptPatterns = loadAcceptPattern(externalContext); |
| |
| _extension = loadFaceletExtension(externalContext); |
| |
| String defaultSuffixes = WebConfigParamUtils.getStringInitParameter(externalContext, |
| ViewHandler.DEFAULT_SUFFIX_PARAM_NAME, ViewHandler.DEFAULT_SUFFIX ); |
| |
| _defaultSuffixesArray = StringUtils.splitShortString(defaultSuffixes, ' '); |
| |
| boolean faceletsExtensionFound = false; |
| for (String ext : _defaultSuffixesArray) |
| { |
| if (_extension.equals(ext)) |
| { |
| faceletsExtensionFound = true; |
| break; |
| } |
| } |
| if (!faceletsExtensionFound) |
| { |
| _defaultSuffixesArray = (String[]) ArrayUtils.concat(_defaultSuffixesArray, new String[]{_extension}); |
| } |
| } |
| |
| /** |
| * Load and compile a regular expression pattern built from the Facelet view mapping parameters. |
| * |
| * @param context |
| * the application's external context |
| * |
| * @return the compiled regular expression |
| */ |
| private Pattern loadAcceptPattern(ExternalContext context) |
| { |
| assert context != null; |
| |
| String mappings = context.getInitParameter(ViewHandler.FACELETS_VIEW_MAPPINGS_PARAM_NAME); |
| if (mappings == null) |
| { |
| return null; |
| } |
| |
| // Make sure the mappings contain something |
| mappings = mappings.trim(); |
| if (mappings.length() == 0) |
| { |
| return null; |
| } |
| |
| return Pattern.compile(toRegex(mappings)); |
| } |
| |
| private String loadFaceletExtension(ExternalContext context) |
| { |
| assert context != null; |
| |
| String suffix = context.getInitParameter(ViewHandler.FACELETS_SUFFIX_PARAM_NAME); |
| if (suffix == null) |
| { |
| suffix = ViewHandler.DEFAULT_FACELETS_SUFFIX; |
| } |
| else |
| { |
| suffix = suffix.trim(); |
| if (suffix.length() == 0) |
| { |
| suffix = ViewHandler.DEFAULT_FACELETS_SUFFIX; |
| } |
| } |
| |
| return suffix; |
| } |
| |
| /** |
| * Convert the specified mapping string to an equivalent regular expression. |
| * |
| * @param mappings |
| * le mapping string |
| * |
| * @return an uncompiled regular expression representing the mappings |
| */ |
| private String toRegex(String mappings) |
| { |
| assert mappings != null; |
| |
| // Get rid of spaces |
| mappings = mappings.replaceAll("\\s", ""); |
| |
| // Escape '.' |
| mappings = mappings.replaceAll("\\.", "\\\\."); |
| |
| // Change '*' to '.*' to represent any match |
| mappings = mappings.replaceAll("\\*", ".*"); |
| |
| // Split the mappings by changing ';' to '|' |
| mappings = mappings.replaceAll(";", "|"); |
| |
| return mappings; |
| } |
| |
| public boolean handles(String resourceName) |
| { |
| if (resourceName == null) |
| { |
| return false; |
| } |
| // Check extension first as it's faster than mappings |
| if (resourceName.endsWith(_extension)) |
| { |
| // If the extension matches, it's a Facelet viewId. |
| return true; |
| } |
| |
| // Otherwise, try to match the view identifier with the facelet mappings |
| return _acceptPatterns != null && _acceptPatterns.matcher(resourceName).matches(); |
| } |
| |
| @Override |
| public boolean containsTagHandler(String ns, String localName) |
| { |
| boolean result = super.containsTagHandler(ns, localName); |
| |
| if (!result && _compositeLibraryName != null && containsNamespace(ns)) |
| { |
| for (String defaultSuffix : _defaultSuffixesArray) |
| { |
| String resourceName = localName + defaultSuffix; |
| if (handles(resourceName)) |
| { |
| Resource compositeComponentResource = _resourceHandler.createResource( |
| resourceName, _compositeLibraryName); |
| |
| if (compositeComponentResource != null) |
| { |
| URL url = compositeComponentResource.getURL(); |
| return (url != null); |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| @Override |
| public TagHandler createTagHandler(String ns, String localName, TagConfig tag) throws FacesException |
| { |
| TagHandler tagHandler = super.createTagHandler(ns, localName, tag); |
| |
| if (tagHandler == null && _compositeLibraryName != null && containsNamespace(ns)) |
| { |
| for (String defaultSuffix : _defaultSuffixesArray) |
| { |
| String resourceName = localName + defaultSuffix; |
| if (handles(resourceName)) |
| { |
| // MYFACES-3308 If a composite component exists, it requires to |
| // be always resolved. In other words, it should always exists a default. |
| // The call here for resourceHandler.createResource, just try to get |
| // the Resource and if it does not exists, it just returns null. |
| // The intention of this code is just create an instance and pass to |
| // CompositeComponentResourceTagHandler. Then, its values |
| // (resourceName, libraryName) will be used to derive the real instance |
| // to use in a view, based on the locale used. |
| Resource compositeComponentResource = new CompositeResouceWrapper( |
| _resourceHandler.createResource(resourceName, _compositeLibraryName)); |
| |
| if (compositeComponentResource != null) |
| { |
| ComponentConfig componentConfig = new ComponentConfigWrapper(tag, |
| "javax.faces.NamingContainer", null); |
| |
| return new CompositeComponentResourceTagHandler( |
| componentConfig, compositeComponentResource); |
| } |
| } |
| } |
| } |
| return tagHandler; |
| } |
| |
| public void setCompositeLibrary(String compositeLibraryName) |
| { |
| _compositeLibraryName = compositeLibraryName; |
| } |
| |
| public void putConverter(String name, String id) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(id, "id"); |
| this.addConverter(name, id); |
| } |
| |
| public void putConverter(String name, String id, Class<? extends TagHandler> handlerClass) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(id, "id"); |
| Assert.notNull(handlerClass, "handlerClass"); |
| this.addConverter(name, id, handlerClass); |
| } |
| |
| public void putValidator(String name, String id) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(id, "id"); |
| this.addValidator(name, id); |
| } |
| |
| public void putValidator(String name, String id, Class<? extends TagHandler> handlerClass) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(id, "id"); |
| Assert.notNull(handlerClass, "handlerClass"); |
| this.addValidator(name, id, handlerClass); |
| } |
| |
| public void putTagHandler(String name, Class<? extends TagHandler> type) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(type, "type"); |
| this.addTagHandler(name, type); |
| } |
| |
| public void putComponentFromResourceId(String name, String resourceId) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(resourceId, "resourceId"); |
| this.addComponentFromResourceId(name, resourceId); |
| } |
| |
| public void putComponent(String name, String componentType, String rendererType) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(componentType, "componentType"); |
| this.addComponent(name, componentType, rendererType); |
| } |
| |
| public void putComponent(String name, String componentType, String rendererType, |
| Class<? extends TagHandler> handlerClass) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(componentType, "componentType"); |
| Assert.notNull(handlerClass, "handlerClass"); |
| this.addComponent(name, componentType, rendererType, handlerClass); |
| } |
| |
| public void putUserTag(String name, URL source) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(source, "source"); |
| this.addUserTag(name, source); |
| } |
| |
| public void putFunction(String name, Method method) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(method, "method"); |
| this.addFunction(name, method); |
| } |
| |
| public void putBehavior(String name, String id) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(id, "id"); |
| this.addBehavior(name, id); |
| } |
| |
| public void putBehavior(String name, String id, Class<? extends TagHandler> handlerClass) |
| { |
| Assert.notNull(name, "name"); |
| Assert.notNull(id, "id"); |
| Assert.notNull(handlerClass, "handlerClass"); |
| this.addBehavior(name, id, handlerClass); |
| } |
| } |
| |
| private static class ComponentConfigWrapper implements ComponentConfig |
| { |
| protected final TagConfig parent; |
| protected final String componentType; |
| protected final String rendererType; |
| |
| public ComponentConfigWrapper(TagConfig parent, String componentType, String rendererType) |
| { |
| this.parent = parent; |
| this.componentType = componentType; |
| this.rendererType = rendererType; |
| } |
| |
| @Override |
| public String getComponentType() |
| { |
| return this.componentType; |
| } |
| |
| @Override |
| public String getRendererType() |
| { |
| return this.rendererType; |
| } |
| |
| @Override |
| public FaceletHandler getNextHandler() |
| { |
| return this.parent.getNextHandler(); |
| } |
| |
| @Override |
| public Tag getTag() |
| { |
| return this.parent.getTag(); |
| } |
| |
| @Override |
| public String getTagId() |
| { |
| return this.parent.getTagId(); |
| } |
| } |
| |
| public TagLibraryConfig() |
| { |
| super(); |
| } |
| |
| public static TagLibrary create(FacesContext facesContext, FaceletTagLibrary faceletTagLibrary) |
| { |
| if (StringUtils.isNotEmpty(faceletTagLibrary.getLibraryClass())) |
| { |
| TagLibrary t = null; |
| Class<?> type; |
| try |
| { |
| type = createClass(TagLibrary.class, faceletTagLibrary.getLibraryClass()); |
| t = (TagLibrary) type.newInstance(); |
| } |
| catch (Exception ex) |
| { |
| throw new FacesException("Cannot instantiate TagLibrary", ex); |
| } |
| // No further processing required. |
| return t; |
| } |
| |
| TagLibraryImpl impl = new TagLibraryImpl(facesContext, faceletTagLibrary.getNamespace()); |
| |
| impl.setCompositeLibrary(faceletTagLibrary.getCompositeLibraryName()); |
| |
| for (FaceletFunction ff : faceletTagLibrary.getFunctions()) |
| { |
| try |
| { |
| Class<?> functionClass = createClass(Object.class, ff.getFunctionClass()); |
| impl.putFunction(ff.getFunctionName(), createMethod(functionClass, ff.getFunctionSignature())); |
| } |
| catch (Exception ex) |
| { |
| throw new FacesException("Cannot instantiate Function Class", ex); |
| } |
| } |
| |
| for (FaceletTag ft : faceletTagLibrary.getTags()) |
| { |
| try |
| { |
| if (ft.isHandlerTag()) |
| { |
| FaceletHandlerTag tag = (FaceletHandlerTag) ft.getTagDefinition(); |
| if (tag.getHandlerClass() != null) |
| { |
| Class<? extends TagHandler> handlerClass = |
| createClass(TagHandler.class, tag.getHandlerClass()); |
| impl.putTagHandler(ft.getName(), handlerClass); |
| } |
| } |
| else if (ft.isComponentTag()) |
| { |
| FaceletComponentTag tag = (FaceletComponentTag) ft.getTagDefinition(); |
| if (tag.getHandlerClass() != null) |
| { |
| Class<? extends TagHandler> handlerClass = |
| createClass(TagHandler.class, tag.getHandlerClass()); |
| impl.putComponent(ft.getName(), tag.getComponentType(), tag.getRendererType(), handlerClass); |
| } |
| else if (tag.getResourceId() != null) |
| { |
| impl.putComponentFromResourceId(ft.getName(), tag.getResourceId()); |
| } |
| else |
| { |
| impl.putComponent(ft.getName(), tag.getComponentType(), tag.getRendererType()); |
| } |
| } |
| else if (ft.isSourceTag()) |
| { |
| FaceletSourceTag tag = (FaceletSourceTag) ft.getTagDefinition(); |
| impl.putUserTag(ft.getName(), new URL(tag.getSource())); |
| } |
| else if (ft.isConverterTag()) |
| { |
| FaceletConverterTag tag = (FaceletConverterTag) ft.getTagDefinition(); |
| if (tag.getHandlerClass() != null) |
| { |
| Class<? extends TagHandler> handlerClass = |
| createClass(TagHandler.class, tag.getHandlerClass()); |
| impl.putConverter(ft.getName(), tag.getConverterId(), handlerClass); |
| } |
| else |
| { |
| impl.putConverter(ft.getName(), tag.getConverterId()); |
| } |
| } |
| else if (ft.isValidatorTag()) |
| { |
| FaceletValidatorTag tag = (FaceletValidatorTag) ft.getTagDefinition(); |
| if (tag.getHandlerClass() != null) |
| { |
| Class<? extends TagHandler> handlerClass = |
| createClass(TagHandler.class, tag.getHandlerClass()); |
| impl.putValidator(ft.getName(), tag.getValidatorId(), handlerClass); |
| } |
| else |
| { |
| impl.putValidator(ft.getName(), tag.getValidatorId()); |
| } |
| } |
| else if (ft.isBehaviorTag()) |
| { |
| FaceletBehaviorTag tag = (FaceletBehaviorTag) ft.getTagDefinition(); |
| if (tag.getHandlerClass() != null) |
| { |
| Class<? extends TagHandler> handlerClass = |
| createClass(TagHandler.class, tag.getHandlerClass()); |
| impl.putBehavior(ft.getName(), tag.getBehaviorId(), handlerClass); |
| } |
| else |
| { |
| impl.putBehavior(ft.getName(), tag.getBehaviorId()); |
| } |
| } |
| } |
| catch (Exception ex) |
| { |
| throw new FacesException("Cannot instantiate Tag "+ft.getName()+" from namespace "+ |
| faceletTagLibrary.getNamespace(), ex); |
| } |
| } |
| return impl; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static <T> Class<? extends T> createClass(Class<T> type, String name) throws Exception |
| { |
| Class<? extends T> factory = (Class<? extends T>) ClassUtils.forName(name); |
| if (!type.isAssignableFrom(factory)) |
| { |
| throw new Exception(name + " must be an instance of " + type.getName()); |
| } |
| return factory; |
| } |
| |
| private static Method createMethod(Class<?> type, String s) throws Exception |
| { |
| int pos = s.indexOf(' '); |
| if (pos == -1) |
| { |
| throw new Exception("Must Provide Return Type: " + s); |
| } |
| else |
| { |
| int pos2 = s.indexOf('(', pos + 1); |
| if (pos2 == -1) |
| { |
| throw new Exception("Must provide a method name, followed by '(': " + s); |
| } |
| else |
| { |
| String mn = s.substring(pos + 1, pos2).trim(); |
| pos = s.indexOf(')', pos2 + 1); |
| if (pos == -1) |
| { |
| throw new Exception("Must close parentheses, ')' missing: " + s); |
| } |
| else |
| { |
| String[] ps = s.substring(pos2 + 1, pos).trim().split(","); |
| Class<?>[] pc; |
| if (ps.length == 1 && "".equals(ps[0])) |
| { |
| pc = new Class[0]; |
| } |
| else |
| { |
| pc = new Class[ps.length]; |
| for (int i = 0; i < pc.length; i++) |
| { |
| pc[i] = ClassUtils.forName(ps[i].trim()); |
| } |
| } |
| try |
| { |
| return type.getMethod(mn, pc); |
| } |
| catch (NoSuchMethodException e) |
| { |
| throw new Exception("No Function Found on type: " + type.getName() + " with signature: " + s); |
| } |
| |
| } |
| |
| } |
| } |
| } |
| |
| } |