/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// BuildComponentFromTagImpl.java
package nonjsp.application;
import javax.faces.component.UICommand;
import javax.faces.component.UIComponent;
import javax.faces.component.UISelectOne;
import javax.faces.el.MethodBinding;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Hashtable;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import nonjsp.util.Util;
/**
* <B>BuildComponentFromTagImpl</B> is a class ...
* <p/>
* Copy of com.sun.faces.tree.BuildComponentFromTagImpl in order to remove
* demo dependancy on RI.
*
*/
public class BuildComponentFromTagImpl extends Object
implements BuildComponentFromTag {
//
// Protected Constants
//
protected static String PARENT = "faces.parent:";
protected static String PARENT_SELECTONE = PARENT +
"javax.faces.UISelectOne";
/**
* stores model value of the form temporarily to support implicit mapping
* of components to properties in the bean.
*/
protected static String FORM_MODELREF = "faces.FORM_MODELREF";
protected static Log log = LogFactory.getLog(
BuildComponentFromTagImpl.class);
//
// Class Variables
//
//
// Instance Variables
//
// Attribute Instance Variables
// Relationship Instance Variables
/** Store the mapping between shortTagName and component class */
protected Hashtable classMap;
//
// Constructors and Initializers
//
public BuildComponentFromTagImpl() {
super();
initializeClassMap();
}
//
// Class methods
//
//
// General Methods
//
/** This is a total RAD hack. */
private void initializeClassMap() {
classMap = new Hashtable(30);
// PENDING(edburns): read this from a persistent store
classMap.put("Form", "javax.faces.component.UIForm");
classMap.put("Command_Button", "javax.faces.component.UICommand");
classMap.put("Command_Link", "javax.faces.component.UICommand");
classMap.put("SelectBoolean_Checkbox",
"javax.faces.component.UISelectBoolean");
classMap.put("RadioGroup", "javax.faces.component.UISelectOne");
classMap.put("SelectOne_Radio", PARENT_SELECTONE);
classMap.put("SelectOne_Listbox", "javax.faces.component.UISelectOne");
classMap.put("SelectOne_Option", PARENT_SELECTONE);
classMap.put("Output_Text", "javax.faces.component.UIOutput");
classMap.put("TextEntry_Input", "javax.faces.component.UIInput");
classMap.put("TextEntry_Secret", "javax.faces.component.UIInput");
classMap.put("TextEntry_TextArea", "javax.faces.component.UIInput");
classMap.put("Errors", "javax.faces.component.UIOutput");
}
protected boolean isSupportedTag(String shortTagName) {
return (null != classMap.get(shortTagName));
}
/**
* @return the property name in the UIComponent class that corresponds to
* the attrName.
*/
private String mapAttrNameToPropertyName(String attrName) {
if (null == attrName) {
return attrName;
}
if (attrName.equals("converter")) {
attrName = "converterReference";
}
if (attrName.equals("selectedValueModel")) {
attrName = "selectedModelReference";
}
return attrName;
}
/**
* @return the property name in the UIComponent class that corresponds to
* the attrName.
*/
private boolean attrRequiresSpecialTreatment(String attrName) {
boolean result = false;
if (null == attrName) {
return result;
}
if (attrName.equals("valueChangeListener") ||
attrName.equals("actionListener") ||
attrName.equals("action") ||
attrName.equals("required") ||
attrName.equals("format") ||
attrName.equals("rangeMaximum") ||
attrName.equals("lengthMaximum") ||
attrName.equals("value")) {
result = true;
}
return result;
}
private void handleSpecialAttr(UIComponent child, String attrName,
String attrValue)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException,
NoSuchMethodException {
Class[] stringArg = {String.class};
Method attrMethod = null;
Object objValue = attrValue;
if (attrName.equals("valueChangeListener")) {
try {
attrMethod =
child.getClass().getMethod("addValueChangeListener",
stringArg);
} catch (SecurityException e) {
log.trace("handleSpecialAttr: " + e);
}
} else if (attrName.equals("actionListener")) {
try {
attrMethod =
child.getClass()
.getMethod("addActionListener", stringArg);
} catch (SecurityException e) {
log.trace("handleSpecialAttr: " + e);
}
} else if (attrName.equals("action")) {
try {
Class[] mbArgs = {MethodBinding.class};
attrMethod = child.getClass().getMethod("setAction",
mbArgs);
objValue = new ConstantMethodBinding(attrValue);
} catch (SecurityException e) {
log.trace("handleSpecialAttr: " + e);
}
} else if ((child instanceof UICommand) && attrName.equals("value")) {
((UICommand) child).setValue(attrValue);
return;
}
Object[] args = {objValue};
if (null != attrMethod) {
attrMethod.invoke(child, args);
}
}
//
// Methods from BuildComponentFromTag
//
public UIComponent createComponentForTag(String shortTagName) {
UIComponent result = null;
if (!tagHasComponent(shortTagName)) {
return result;
}
String className = (String) classMap.get(shortTagName);
Class componentClass;
// PENDING(edburns): this can be way optimized
try {
componentClass = Util.loadClass(className);
result = (UIComponent) componentClass.newInstance();
} catch (IllegalAccessException iae) {
throw new RuntimeException("Can't create instance for " +
className + ": " + iae.getMessage());
} catch (InstantiationException ie) {
throw new RuntimeException("Can't create instance for " +
className + ": " + ie.getMessage());
} catch (ClassNotFoundException e) {
throw new RuntimeException("Can't find class for " +
className + ": " + e.getMessage());
}
return result;
}
public boolean tagHasComponent(String shortTagName) {
boolean result = false;
String value;
// Return true if the classMap has an entry for shortTagName, and
// the entry does not start with the string PARENT.
if (null != (value = (String) classMap.get(shortTagName))) {
result = 0 != value.indexOf(PARENT);
}
return result;
}
public boolean isNestedComponentTag(String shortTagName) {
boolean result = false;
String value;
// Return true if the classMap has an entry for shortTagName, and
// the entry DOES start with the string PARENT.
if (null != (value = (String) classMap.get(shortTagName))) {
result = 0 == value.indexOf(PARENT);
}
return result;
}
public void handleNestedComponentTag(UIComponent parent,
String shortTagName,
Attributes attrs) {
if (null == parent || null == shortTagName || null == attrs) {
return;
}
String val = (String) classMap.get(shortTagName);
if (null == val || (0 != val.indexOf(PARENT))) {
return;
}
// At this point, we know that we are in a nested tag.
// PENDING(edburns): check that parent is really the correct parent
// for this shortTagName, for now, it's just UISelectOne
UISelectOne uiSelectOne = (UISelectOne) parent;
int attrLen, i = 0;
String attrName, attrValue;
String itemLabel = null, itemValue = null, itemDesc = null;
boolean checked = false;
attrLen = attrs.getLength();
for (i = 0; i < attrLen; i++) {
attrName = mapAttrNameToPropertyName(attrs.getLocalName(i));
attrValue = attrs.getValue(i);
if (attrName.equals("value")) {
itemValue = attrValue;
}
if (attrName.equals("label")) {
itemLabel = attrValue;
}
if (attrName.equals("description")) {
itemDesc = attrValue;
}
if ((attrName.equals("checked") || attrName.equals("selected")) &&
attrValue.equals("true")) {
checked = true;
}
}
/********** PENDING(edburns): Fix this for non-jsp example
SelectItem [] oldItems = (SelectItem []) uiSelectOne.getItems();
SelectItem [] newItems = null;
if (null != oldItems) {
newItems = new SelectItem[oldItems.length + 1];
System.arraycopy(oldItems, 0, newItems, 0, oldItems.length);
newItems[oldItems.length] = new SelectItem(itemValue, itemLabel,
itemDesc);
}
else {
newItems = new SelectItem[1];
newItems[0] = new SelectItem(itemValue, itemLabel, itemDesc);
}
uiSelectOne.setItems(newItems);
// if it is checked, make sure the model knows about it.
// we should update selectedValue only if it is null
// in the model bean otherwise we would be overwriting
// the value in model bean, losing any earlier updates.
if (checked && null == uiSelectOne.getSelectedValue()) {
uiSelectOne.setSelectedValue(itemValue);
}
***************/
}
public void applyAttributesToComponentInstance(UIComponent child,
Attributes attrs) {
int attrLen, i = 0;
String attrName, attrValue;
attrLen = attrs.getLength();
for (i = 0; i < attrLen; i++) {
attrName = mapAttrNameToPropertyName(attrs.getLocalName(i));
attrValue = attrs.getValue(i);
// First, try to set it as a bean property
try {
PropertyUtils.setNestedProperty(child, attrName, attrValue);
} catch (NoSuchMethodException e) {
// If that doesn't work, see if it requires special
// treatment
try {
if (attrRequiresSpecialTreatment(attrName)) {
handleSpecialAttr(child, attrName, attrValue);
} else {
// If that doesn't work, this will.
child.getAttributes().put(attrName, attrValue);
}
} catch (IllegalAccessException innerE) {
innerE.printStackTrace();
log.trace(innerE.getMessage());
} catch (IllegalArgumentException innerE) {
innerE.printStackTrace();
log.trace(innerE.getMessage());
} catch (InvocationTargetException innerE) {
innerE.printStackTrace();
log.trace(innerE.getMessage());
} catch (NoSuchMethodException innerE) {
innerE.printStackTrace();
log.trace(innerE.getMessage());
}
} catch (IllegalArgumentException e) {
try {
if (attrRequiresSpecialTreatment(attrName)) {
handleSpecialAttr(child, attrName, attrValue);
} else {
// If that doesn't work, this will.
child.getAttributes().put(attrName, attrValue);
}
} catch (IllegalAccessException innerE) {
innerE.printStackTrace();
log.trace(innerE.getMessage());
} catch (IllegalArgumentException innerE) {
innerE.printStackTrace();
log.trace(innerE.getMessage());
} catch (InvocationTargetException innerE) {
innerE.printStackTrace();
log.trace(innerE.getMessage());
} catch (NoSuchMethodException innerE) {
innerE.printStackTrace();
log.trace(innerE.getMessage());
}
} catch (InvocationTargetException e) {
e.printStackTrace();
log.trace(e.getMessage());
} catch (IllegalAccessException e) {
e.printStackTrace();
log.trace(e.getMessage());
}
}
// cleanup: make sure we have the necessary required attributes
if (child.getId() == null) {
String gId = "foo" + Util.generateId();
child.setId(gId);
}
}
} // end of class BuildComponentFromTagImpl