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.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    
030    import javax.faces.component.UIComponent;
031    import javax.faces.context.FacesContext;
032    import javax.faces.el.ValueBinding;
033    import javax.faces.webapp.UIComponentTag;
034    import javax.servlet.jsp.JspException;
035    import javax.servlet.jsp.tagext.TagSupport;
036    
037    /**
038     * Register an TabChangedListener instance on the UIComponent
039     * associated with the closest parent UIComponent custom action.
040     */
041    @Tag(name = "tabChangeListener", bodyContent = BodyContent.EMPTY)
042    public class TabChangeListenerTag extends TagSupport {
043    
044      private static final long serialVersionUID = -419199086962377873L;
045    
046      private static final Log LOG = LogFactory.getLog(TabChangeListenerTag.class);
047    
048      /**
049       * <p>The fully qualified class name of the {@link TabChangeListener}
050       * instance to be created.</p>
051       */
052      private String type;
053      private String binding;
054    
055      /**
056       * Fully qualified Java class name of a TabChangeListener to be
057       * created and registered.
058       */
059      @TagAttribute(required = true)
060      public void setType(String type) {
061        this.type = type;
062      }
063    
064      /**
065       * The value binding expression to a TabChangeListener.
066       */
067      @TagAttribute
068      public void setBinding(String binding) {
069        this.binding = binding;
070      }
071    
072    
073      /**
074       * <p>Create a new instance of the specified {@link TabChangeListener}
075       * class, and register it with the {@link javax.faces.component.UIComponent} instance associated
076       * with our most immediately surrounding {@link javax.faces.webapp.UIComponentTag} instance, if
077       * the {@link javax.faces.component.UIComponent} instance was created by this execution of the
078       * containing JSP page.</p>
079       *
080       * @throws JspException if a JSP error occurs
081       */
082      public int doStartTag() throws JspException {
083    
084        // Locate our parent UIComponentTag
085        UIComponentTag tag =
086            UIComponentTag.getParentUIComponentTag(pageContext);
087        if (tag == null) {
088          // TODO Message resource i18n
089          throw new JspException("Not nested in faces tag");
090        }
091    
092        if (!tag.getCreated()) {
093          return (SKIP_BODY);
094        }
095    
096        UIComponent component = tag.getComponentInstance();
097        if (component == null) {
098          // TODO Message resource i18n
099          throw new JspException("Component Instance is null");
100        }
101        if (!(component instanceof TabChangeSource)) {
102          // TODO Message resource i18n
103          throw new JspException("Component " + component.getClass().getName() + " is not instanceof TabChangeSource");
104        }
105        TabChangeSource changeSource = (TabChangeSource) component;
106    
107        TabChangeListener handler = null;
108        ValueBinding valueBinding = null;
109        if (binding != null && UIComponentTag.isValueReference(binding)) {
110          valueBinding = ComponentUtil.createValueBinding(binding);
111          if (valueBinding != null) {
112            Object obj = valueBinding.getValue(FacesContext.getCurrentInstance());
113            if (obj != null && obj instanceof TabChangeListener) {
114              handler = (TabChangeListener) obj;
115            }
116          }
117        }
118    
119        if (handler == null && type != null) {
120          handler = createTabChangeListener(type);
121          if (handler != null && valueBinding != null) {
122            valueBinding.setValue(FacesContext.getCurrentInstance(), handler);
123          }
124        }
125        if (handler != null) {
126          if (valueBinding != null) {
127            changeSource.addTabChangeListener(new TabChangeListenerValueBindingDelegate(type, valueBinding));
128          } else {
129            changeSource.addTabChangeListener(handler);
130          }
131        }
132        // TODO else LOG.warn?
133        return (SKIP_BODY);
134      }
135    
136    
137      /**
138       * <p>Release references to any acquired resources.
139       */
140      public void release() {
141        this.type = null;
142        this.binding = null;
143      }
144    
145      /**
146       * <p>Create and return a new {@link TabChangeListener} to be registered
147       * on our surrounding {@link javax.faces.component.UIComponent}.</p>
148       *
149       * @throws javax.servlet.jsp.JspException if a new instance cannot be created
150       */
151      protected TabChangeListener createTabChangeListener(String className) throws JspException {
152        try {
153          Class clazz = getClass().getClassLoader().loadClass(className);
154          return ((TabChangeListener) clazz.newInstance());
155        } catch (Exception e) {
156          throw new JspException(e);
157        }
158      }
159    }