blob: c8d5d56adeae9dea4ea6dbaf1cbcb9eda9bbd221 [file] [log] [blame]
/*
* 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.taglibs.rdc.core;
import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.taglibs.rdc.RDCUtils;
/**
* A basic template using the default atomic FSM, meant to slash component
* development effort.
*
* @author Rahul Akolkar
*/
public class RDCTemplate extends BaseModel {
// Serial Version UID
private static final long serialVersionUID = 1L;
// Error messages (to be i18n'zed)
private static final String ERR_BAD_PROP = "Did not populate " +
" following property(ies) for RDC template instance with id \"{0}\"" +
" : \"{1}\" as properties defined in BaseModel should not be " +
"populated via the grammars/constraints/dynamic attributes. " +
"Rename these.";
private static final String ERR_BEAN_POPULATE = "Failure while " +
"populationg RDC template instance with id \"{0}\", with message " +
"\"{1}\"";
// Logging
private static Log log = LogFactory.getLog(RDCTemplate.class);
/** The instance specific data that is passed in */
protected Object data;
/** The fully qualified class name of the model bean for this
* instance of the RDC template */
protected String bean;
/** The fragment that will override any or all of the
* default fsm as needed for this instance of the template */
protected String fsmFragment;
/** The instance specific constraints on the value to be collected. */
protected Map constraints;
/** The instance specific dynamic tag attributes. */
protected Map dynamicAttributes;
/** The property that governs whether we will attempt to populate this
* template instance with the grammars that will be passed in */
protected boolean populateGrammars;
/**
* Sets default values for all data members
*/
public RDCTemplate() {
super();
this.data = null;
this.bean = RDCTemplate.class.getName();
this.fsmFragment = null;
this.constraints = null;
this.dynamicAttributes = null;
this.populateGrammars = false;
}
/**
* Get the data value that was passed in
*
* @return data
*/
public Object getData() {
return this.data;
}
/**
* Sets the data value
*
* @param data
*/
public void setData(Object data) {
if (data != null) {
this.data = data;
}
}
/**
* Get the data value that was passed in
*
* @return string bean
*/
public String getBean() {
return bean;
}
/**
* Sets the bean value
*
* @param bean The value bean
*/
public void setBean(String bean) {
if (bean != null) {
this.bean = bean;
}
}
/**
* Get the tag fragment URI overriding the default FSM
* defined in <fsm-run>
*
* @return fsmTagFragment
*/
public String getFsmFragment() {
return this.fsmFragment;
}
/**
* Set the tag fragment URI overriding the default FSM
* defined in <fsm-run>
*
* @param fsmFragment The URI to the tag fragment
*/
public void setFsmFragment(String fsmFragment) {
if (fsmFragment != null) {
this.fsmFragment = fsmFragment;
}
}
/**
* Get the constraints on the value to be collected. Only
* those constraints passed in via the constraints attribute
* of this instance of the template tag will be returned.
*
* @return constraints
*/
public Map getConstraints() {
return this.constraints;
}
/**
* Set the constraints on the value to be collected
*
* @param constraints
*/
public void setConstraints(Map constraints) {
if (constraints != null) {
this.constraints = constraints;
if (this.constraints.size() > 0) {
populate(this.constraints);
}
}
}
/**
* Set the dynamic attributes data received from this tag instance
*
* @param dynamicAttributes The dynamic attributes name value map
*/
public void setDynamicAttributes(Map dynamicAttributes) {
if (dynamicAttributes != null) {
this.dynamicAttributes = dynamicAttributes;
if (this.dynamicAttributes.size() > 0) {
populate(this.dynamicAttributes);
}
}
}
/**
* Sets the grammar(s). The param can be an array of some combination
* of Grammar objects and string URIs or a Grammar object or a string URI.
*
* @param grammar The grammar to set
*/
public void setGrammar(Object grammar) {
Map grammarMap = new HashMap();
if (grammar != null) {
if (grammar instanceof Object[]) {
Object[] grammarsArray = (Object []) grammar;
for (int i=0; i < grammarsArray.length; i++) {
Object grammarObj = grammarsArray[i];
if (grammarObj instanceof Grammar) {
addGrammar((Grammar)grammarObj, grammarMap);
} else if (grammarObj instanceof String) {
// Assume voice and external (not inline)
addGrammar(new Grammar((String)grammarObj,
Boolean.FALSE, Boolean.FALSE, null), null);
}
}
} else if (grammar instanceof Grammar) {
addGrammar((Grammar)grammar, grammarMap);
} else if (grammar instanceof String) {
// Assume voice and external (not inline)
addGrammar(new Grammar((String)grammar, Boolean.FALSE,
Boolean.FALSE, null), null);
}
}
if (populateGrammars && grammarMap.size() > 0) {
populate(grammarMap);
}
initComponentGrammars();
}
/**
* Hook for instances to prepare grammars for first round trip
*/
public void initComponentGrammars() {
// hook for subclasses
}
/**
* Add grammar object
*/
private void addGrammar(Grammar grammar, Map grammarMap) {
this.grammars.add(grammar);
if (populateGrammars && grammarMap != null) {
String name = grammar.getName();
// We cannot populate anonymous grammars
if (!RDCUtils.isStringEmpty(name)) {
grammarMap.put(name, grammar);
}
}
}
/**
* Populate this bean with supplied property value pairs
*/
private void populate(Map props2values) {
Map safeProps = new HashMap(props2values);
Set badProps = props2values.keySet();
badProps.retainAll(illegalProperties);
if (badProps.size() > 0) {
// tsk tsk ... how could you do that
Object[] badPropsArr = badProps.toArray();
String badPropsStr = "";
for (int i = 0; i < badPropsArr.length; i++) {
String badProp = (String)badPropsArr[i];
safeProps.remove(badProp);
badPropsStr += "\"" + badProp + "\", ";
}
MessageFormat msgFormat = new MessageFormat(ERR_BAD_PROP);
log.warn(msgFormat.format(new Object[] {getId(), badPropsStr}));
}
try {
BeanUtils.populate(this, safeProps);
} catch (Exception e) {
MessageFormat msgFormat = new MessageFormat(ERR_BEAN_POPULATE);
log.warn(msgFormat.format(new Object[] {getId(), e.getMessage()}));
}
}
/** Ensure that the grammars and constraints population mechanism is
* not misused */
private static final Set illegalProperties = new HashSet();
/*
* Strictly illegal properties are those defined in BaseModel. Beyond
* that, we are willing to trust the user ;-)
*/
static {
Field[] fields = BaseModel.class.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
String fieldName = fields[i].getName();
illegalProperties.add(fieldName);
}
}
}