001    package org.apache.myfaces.tobago.taglib.component;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more
005     * contributor license agreements.  See the NOTICE file distributed with
006     * this work for additional information regarding copyright ownership.
007     * The ASF licenses this file to You under the Apache License, Version 2.0
008     * (the "License"); you may not use this file except in compliance with
009     * the License.  You may obtain a copy of the License at
010     *
011     *      http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing, software
014     * distributed under the License is distributed on an "AS IS" BASIS,
015     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    import org.apache.myfaces.tobago.apt.annotation.BodyContent;
021    import org.apache.myfaces.tobago.apt.annotation.Tag;
022    import org.apache.myfaces.tobago.apt.annotation.TagAttribute;
023    import org.apache.myfaces.tobago.component.ComponentUtil;
024    import org.apache.myfaces.tobago.event.TabChangeListener;
025    import org.apache.myfaces.tobago.event.TabChangeSource;
026    import org.apache.myfaces.tobago.event.TabChangeListenerValueBindingDelegate;
027    import org.apache.myfaces.tobago.event.TabChangeEvent;
028    
029    import org.apache.commons.logging.Log;
030    import org.apache.commons.logging.LogFactory;
031    
032    import javax.faces.component.UIComponent;
033    import javax.faces.context.FacesContext;
034    import javax.faces.el.ValueBinding;
035    import javax.faces.el.MethodBinding;
036    import javax.faces.webapp.UIComponentTag;
037    import javax.faces.application.Application;
038    import javax.servlet.jsp.JspException;
039    import javax.servlet.jsp.tagext.TagSupport;
040    
041    /**
042     * Register an TabChangedListener instance on the UIComponent
043     * associated with the closest parent UIComponent custom action.
044     */
045    @Tag(name = "tabChangeListener", bodyContent = BodyContent.EMPTY)
046    public class TabChangeListenerTag extends TagSupport {
047    
048      private static final long serialVersionUID = -419199086962377873L;
049    
050      private static final Class[] TAB_CHANGE_LISTENER_ARGS = new Class[] {TabChangeEvent.class};
051    
052      private static final Log LOG = LogFactory.getLog(TabChangeListenerTag.class);
053    
054      /**
055       * <p>The fully qualified class name of the {@link TabChangeListener}
056       * instance to be created.</p>
057       */
058      private String type;
059      private String binding;
060      private String listener;
061    
062      /**
063       * Fully qualified Java class name of a TabChangeListener to be
064       * created and registered.
065       */
066      @TagAttribute(required = true)
067      public void setType(String type) {
068        this.type = type;
069      }
070    
071      /**
072       * The value binding expression to a TabChangeListener.
073       */
074      @TagAttribute
075      public void setBinding(String binding) {
076        this.binding = binding;
077      }
078    
079    
080      /**
081       * A method binding expression to a processTabChange(TabChangeEvent tabChangeEvent) method.
082       */
083      @TagAttribute
084      public void setListener(String listener) {
085        this.listener = listener;
086      }
087    
088        /**
089       * <p>Create a new instance of the specified {@link TabChangeListener}
090       * class, and register it with the {@link javax.faces.component.UIComponent} instance associated
091       * with our most immediately surrounding {@link javax.faces.webapp.UIComponentTag} instance, if
092       * the {@link javax.faces.component.UIComponent} instance was created by this execution of the
093       * containing JSP page.</p>
094       *
095       * @throws JspException if a JSP error occurs
096       */
097      public int doStartTag() throws JspException {
098    
099        // Locate our parent UIComponentTag
100        UIComponentTag tag =
101            UIComponentTag.getParentUIComponentTag(pageContext);
102        if (tag == null) {
103          // TODO Message resource i18n
104          throw new JspException("Not nested in faces tag");
105        }
106    
107        if (!tag.getCreated()) {
108          return (SKIP_BODY);
109        }
110    
111        UIComponent component = tag.getComponentInstance();
112        if (component == null) {
113          // TODO Message resource i18n
114          throw new JspException("Component Instance is null");
115        }
116        if (!(component instanceof TabChangeSource)) {
117          // TODO Message resource i18n
118          throw new JspException("Component " + component.getClass().getName() + " is not instanceof TabChangeSource");
119        }
120        TabChangeSource changeSource = (TabChangeSource) component;
121    
122        TabChangeListener handler = null;
123        ValueBinding valueBinding = null;
124        if (binding != null && UIComponentTag.isValueReference(binding)) {
125          valueBinding = ComponentUtil.createValueBinding(binding);
126          if (valueBinding != null) {
127            Object obj = valueBinding.getValue(FacesContext.getCurrentInstance());
128            if (obj != null && obj instanceof TabChangeListener) {
129              handler = (TabChangeListener) obj;
130            }
131          }
132        }
133    
134        if (handler == null && type != null) {
135          handler = createTabChangeListener(type);
136          if (handler != null && valueBinding != null) {
137            valueBinding.setValue(FacesContext.getCurrentInstance(), handler);
138          }
139        }
140        if (handler != null) {
141          if (valueBinding != null) {
142            changeSource.addTabChangeListener(new TabChangeListenerValueBindingDelegate(type, valueBinding));
143          } else {
144            changeSource.addTabChangeListener(handler);
145          }
146        }
147    
148        if (listener != null && UIComponentTag.isValueReference(listener)) {
149          Application application = FacesContext.getCurrentInstance().getApplication();
150          MethodBinding methodBinding = application.createMethodBinding(listener, TAB_CHANGE_LISTENER_ARGS);
151          changeSource.setTabChangeListener(methodBinding);
152        }
153        // TODO else LOG.warn?
154        return (SKIP_BODY);
155      }
156    
157    
158      /**
159       * <p>Release references to any acquired resources.
160       */
161      public void release() {
162        this.type = null;
163        this.binding = null;
164      }
165    
166      /**
167       * <p>Create and return a new {@link TabChangeListener} to be registered
168       * on our surrounding {@link javax.faces.component.UIComponent}.</p>
169       *
170       * @throws javax.servlet.jsp.JspException if a new instance cannot be created
171       */
172      protected TabChangeListener createTabChangeListener(String className) throws JspException {
173        try {
174          Class clazz = getClass().getClassLoader().loadClass(className);
175          return ((TabChangeListener) clazz.newInstance());
176        } catch (Exception e) {
177          throw new JspException(e);
178        }
179      }
180    }