blob: b44b5128d43200157832558917e6839ca96ee86e [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.myfaces.buildtools.maven2.plugin.builder.qdox;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.myfaces.buildtools.maven2.plugin.builder.IOUtils;
import org.apache.myfaces.buildtools.maven2.plugin.builder.ModelBuilder;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.AttributeMeta;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ClassMeta;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ComponentMeta;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ConverterMeta;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.FacetHolder;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.FacetMeta;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.MethodSignatureMeta;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.Model;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyHolder;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.PropertyMeta;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.RenderKitMeta;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.RendererMeta;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.TagMeta;
import org.apache.myfaces.buildtools.maven2.plugin.builder.model.ValidatorMeta;
import org.codehaus.plexus.components.io.fileselectors.FileInfo;
import org.codehaus.plexus.components.io.fileselectors.FileSelector;
import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
import com.thoughtworks.qdox.JavaDocBuilder;
import com.thoughtworks.qdox.model.AbstractJavaEntity;
import com.thoughtworks.qdox.model.Annotation;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.Type;
/**
* An implementation of the ModelBuilder interface that uses the Qdox java
* source-parsing library to scan a list of specified source directories for
* java files.
* <p>
* The java source files found can use either java15 annotations or doclet
* annotations to indicate what data should be added to the Model.
*/
public class QdoxModelBuilder implements ModelBuilder
{
private final Log log = LogFactory.getLog(QdoxModelBuilder.class);
private static final String DOC_CONVERTER = "JSFConverter";
private static final String DOC_VALIDATOR = "JSFValidator";
private static final String DOC_COMPONENT = "JSFComponent";
private static final String DOC_RENDERER = "JSFRenderer";
private static final String DOC_RENDERKIT = "JSFRenderKit";
private static final String DOC_RENDERERS = "JSFRenderers";
private static final String DOC_PROPERTY = "JSFProperty";
private static final String DOC_FACET = "JSFFacet";
//This property is used in special cases where properties
//does not have methods defined on component class, like binding
//in jsf 1.1 (in 1.2 has component counterpart). In fact, all
//properties must be defined with JSFProperty
private static final String DOC_JSP_PROPERTY = "JSFJspProperty";
private static final String DOC_JSP_PROPERTIES = "JSFJspProperties";
private static final String DOC_TAG = "JSFJspTag";
private static final String DOC_JSP_ATTRIBUTE = "JSFJspAttribute";
private static class JavaClassComparator implements Comparator
{
public int compare(Object arg0, Object arg1)
{
JavaClass c0 = (JavaClass) arg0;
JavaClass c1 = (JavaClass) arg1;
return (c0.getFullyQualifiedName().compareTo(c1.getFullyQualifiedName()));
}
}
/**
* Scan the source tree for doc-annotations, and build Model objects
* containing info extracted from the doc-annotation attributes and
* introspected info about the item the annotation is attached to.
*/
public void buildModel(Model model, MavenProject project)
throws MojoExecutionException
{
buildModel(model, project.getCompileSourceRoots());
}
/**
* @since 1.0.2
*/
public void buildModel(Model model, MavenProject project, String includes, String excludes)
throws MojoExecutionException
{
if (StringUtils.isNotEmpty(includes) ||
StringUtils.isNotEmpty(excludes))
{
buildModel(model, project.getCompileSourceRoots(),includes, excludes);
}
else
{
buildModel(model, project.getCompileSourceRoots());
}
}
/**
* @since 1.0.2
*/
public void buildModel(Model model, List sourceDirs, String includes, String excludes)
throws MojoExecutionException
{
String currModelId = model.getModelId();
if (currModelId == null)
{
throw new MojoExecutionException("Model must have id set");
}
//System.out.println("includes:"+includes+" excludes:"+excludes);
JavaDocBuilder builder = new JavaDocBuilder();
IncludeExcludeFileSelector selector =
new IncludeExcludeFileSelector();
if (StringUtils.isNotEmpty(excludes))
{
selector.setExcludes(excludes.split(","));
}
if (StringUtils.isNotEmpty(includes))
{
selector.setIncludes(includes.split(","));
}
for (Iterator i = sourceDirs.iterator(); i.hasNext();)
{
File srcDir = new File((String) i.next());
//Scan all files on directory and add to builder
addFileToJavaDocBuilder(builder, selector, srcDir);
}
JavaClass[] classes = builder.getClasses();
buildModel(model, sourceDirs, classes);
}
private void addFileToJavaDocBuilder(JavaDocBuilder builder,
FileSelector selector, File path)
{
addFileToJavaDocBuilder(builder,selector, path, path.getPath());
}
private void addFileToJavaDocBuilder(JavaDocBuilder builder,
FileSelector selector, File path, String basePath)
{
if (path.isDirectory())
{
File[] files = path.listFiles();
//Scan all files in directory
for (int i = 0; i < files.length; i++)
{
addFileToJavaDocBuilder(builder, selector, files[i], basePath);
}
}
else
{
File file = path;
try
{
String name = file.getPath();
while (name.startsWith("/"))
{
name = name.substring(1);
}
while (name.startsWith("\\"))
{
name = name.substring(1);
}
SourceFileInfo fileInfo = new SourceFileInfo(file,name);
if (selector.isSelected(fileInfo))
{
//System.out.println("file:"+name);
builder.addSource(file);
}
}
catch (FileNotFoundException e)
{
log.error("Error reading file: "+file.getName()+" "+e.getMessage());
}
catch (IOException e)
{
log.error("Error reading file: "+file.getName()+" "+e.getMessage());
}
}
}
private class SourceFileInfo implements FileInfo
{
private File file;
private String name;
/**
* Creates a new instance.
*/
public SourceFileInfo( File file )
{
this( file, file.getPath().replace( '\\', '/' ) );
}
/**
* Creates a new instance.
*/
public SourceFileInfo( File file, String name )
{
this.file = file;
this.name = name;
}
/**
* Sets the resources file.
*/
public void setFile( File file )
{
this.file = file;
}
/**
* Returns the resources file.
*/
public File getFile()
{
return file;
}
/**
* Sets the resources name.
*/
public void setName( String name )
{
this.name = name;
}
public String getName()
{
return name;
}
public InputStream getContents() throws IOException
{
return new FileInputStream( getFile() );
}
public boolean isDirectory()
{
return file.isDirectory();
}
public boolean isFile()
{
return file.isFile();
}
}
/**
* Scan the source tree for doc-annotations, and build Model objects
* containing info extracted from the doc-annotation attributes and
* introspected info about the item the annotation is attached to.
*/
public void buildModel(Model model, List sourceDirs)
throws MojoExecutionException
{
String currModelId = model.getModelId();
if (currModelId == null)
{
throw new MojoExecutionException("Model must have id set");
}
JavaDocBuilder builder = new JavaDocBuilder();
// need a File object representing the original source tree
//
// TODO: make this more flexible, so specific classes can
// be included and excluded.
for (Iterator i = sourceDirs.iterator(); i.hasNext();)
{
String srcDir = (String) i.next();
builder.addSourceTree(new File(srcDir));
}
JavaClass[] classes = builder.getClasses();
buildModel(model, sourceDirs, classes);
}
protected void buildModel(Model model, List sourceDirs, JavaClass[] classes)
throws MojoExecutionException
{
String currModelId = model.getModelId();
// Sort the class array so that they are processed in a
// predictable order, regardless of how the source scanning
// returned them.
Arrays.sort(classes, new JavaClassComparator());
Map processedClasses = new HashMap();
for (int i = 0; i < classes.length; ++i)
{
JavaClass clazz = classes[i];
processClass(processedClasses, clazz, model);
}
// Post-process the list of components which we added in this run.
// Note that model has all the inherited components in it too, so
// we need to skip them.
//
// Hmm..as noted elsewhere, JavaClass objects representing parent
// classes are accessable via getParentClazz(). Presumably they are
// not in the array returned by builder.getClasses() though..
for (Iterator it = model.getComponents().iterator(); it.hasNext();)
{
ComponentMeta component = (ComponentMeta) it.next();
if (!component.getModelId().equals(currModelId))
{
continue;
}
initComponentAncestry(processedClasses, model, component);
//Check if the component class java file exists in the source dirs
String classname = component.getClassName();
String classfile = StringUtils.replace(classname,".","/")+".java";
if (!IOUtils.existsSourceFile(classfile, sourceDirs))
{
component.setGeneratedComponentClass(Boolean.TRUE);
}
// Check if the tag class java file exists in the source dirs
if (isTagClassMissing(component.getTagClass(), sourceDirs))
{
component.setGeneratedTagClass(Boolean.TRUE);
}
}
// post-process the list of converters
for (Iterator it = model.getConverters().iterator(); it.hasNext();)
{
ConverterMeta converter = (ConverterMeta) it.next();
if (!converter.getModelId().equals(currModelId))
{
continue;
}
initConverterAncestry(processedClasses, model, converter);
// TODO: why is there no check for Converter class existence here??
// ANS: there is no automatic generation of converter class.
// Check if the tag class java file exists in the source dirs
if (isTagClassMissing(converter.getTagClass(), sourceDirs))
{
converter.setGeneratedTagClass(Boolean.TRUE);
}
}
// post-process the list of validators
for (Iterator it = model.getValidators().iterator(); it.hasNext();)
{
ValidatorMeta validator = (ValidatorMeta) it.next();
if (!validator.getModelId().equals(currModelId))
{
continue;
}
initValidatorAncestry(processedClasses, model, validator);
//Check if the validator class file exists
if (!IOUtils.existsSourceFile(StringUtils.replace(
validator.getClassName(),".","/")+".java", sourceDirs))
{
validator.setGeneratedComponentClass(Boolean.TRUE);
}
// Check if the tag class java file exists in the source dirs
if (isTagClassMissing(validator.getTagClass(), sourceDirs))
{
validator.setGeneratedTagClass(Boolean.TRUE);
}
}
// post-process the list of tags
for (Iterator it = model.getTags().iterator(); it.hasNext();)
{
TagMeta tag = (TagMeta) it.next();
// nothing to do at the moment
}
}
/**
* Returns true if the tagClassName is not null, but the corresponding
* source file cannot be found in the specified source dirs.
*/
private boolean isTagClassMissing(String tagClassName, List sourceDirs)
{
if (tagClassName == null)
{
return false;
}
String tagClassFile = StringUtils.replace(tagClassName,".","/")+".java";
return !IOUtils.existsSourceFile(tagClassFile, sourceDirs);
}
/**
* Set the parentClassName and interfaceClassNames properties of the
* provided modelItem object.
*/
private void processClass(Map processedClasses, JavaClass clazz, Model model)
throws MojoExecutionException
{
if (processedClasses.containsKey(clazz.getFullyQualifiedName()))
{
return;
}
// first, check that the parent type and all interfaces have been
// processed.
JavaClass parentClazz = clazz.getSuperJavaClass();
if (parentClazz != null)
{
processClass(processedClasses, parentClazz, model);
}
JavaClass[] classes = clazz.getImplementedInterfaces();
for (int i = 0; i < classes.length; ++i)
{
JavaClass iclazz = classes[i];
processClass(processedClasses, iclazz, model);
}
// ok, now we can mark this class as processed.
processedClasses.put(clazz.getFullyQualifiedName(), clazz);
log.info("processed class:" + clazz.getFullyQualifiedName());
DocletTag tag;
Annotation anno;
// converters
tag = clazz.getTagByName(DOC_CONVERTER, false);
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processConverter(props, (AbstractJavaEntity)tag.getContext(), clazz, model);
}
anno = getAnnotation(clazz, DOC_CONVERTER);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processConverter(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
}
// validators
tag = clazz.getTagByName(DOC_VALIDATOR, false);
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processValidator(props, (AbstractJavaEntity)tag.getContext(), clazz, model);
}
anno = getAnnotation(clazz, DOC_VALIDATOR);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processValidator(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
}
// components
tag = clazz.getTagByName(DOC_COMPONENT, false);
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processComponent(props, (AbstractJavaEntity)tag.getContext(), clazz, model);
}
anno = getAnnotation(clazz, DOC_COMPONENT);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processComponent(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
}
//tag
tag = clazz.getTagByName(DOC_TAG, false);
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processTag(props, (AbstractJavaEntity)tag.getContext(), clazz, model);
}
anno = getAnnotation(clazz, DOC_TAG);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processTag(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
}
// renderKit
tag = clazz.getTagByName(DOC_RENDERKIT, false);
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processRenderKit(props, (AbstractJavaEntity)tag.getContext(), clazz, model);
}
anno = getAnnotation(clazz, DOC_RENDERKIT);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processRenderKit(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
}
// renderer
DocletTag [] tags = clazz.getTagsByName(DOC_RENDERER, false);
for (int i = 0; i < tags.length; i++)
{
tag = tags[i];
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processRenderer(props, (AbstractJavaEntity)tag.getContext(), clazz, model);
}
}
anno = getAnnotation(clazz, DOC_RENDERER);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processRenderer(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
}
anno = getAnnotation(clazz, DOC_RENDERERS);
if (anno != null)
{
Object jspProps = anno.getNamedParameter("renderers");
if (jspProps instanceof Annotation)
{
Annotation jspPropertiesAnno = (Annotation) jspProps;
Map props = jspPropertiesAnno.getNamedParameterMap();
processRenderer(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
}
else
{
List jspPropsList = (List) jspProps;
for (int i = 0; i < jspPropsList.size();i++)
{
Annotation ranno = (Annotation) jspPropsList.get(i);
Map props = ranno.getNamedParameterMap();
processRenderer(props, (AbstractJavaEntity)anno.getContext(), clazz, model);
}
}
}
}
private Annotation getAnnotation(AbstractJavaEntity entity, String annoName)
{
Annotation[] annos = entity.getAnnotations();
if (annos == null)
{
return null;
}
// String wanted = ANNOTATION_BASE + "." + annoName;
for (int i = 0; i < annos.length; ++i)
{
Annotation thisAnno = annos[i];
// Ideally, here we would check whether the fully-qualified name of
// the annotation
// class matches ANNOTATION_BASE + "." + annoName. However it
// appears that qdox 1.6.3
// does not correctly expand @Foo using the class import statements;
// method
// Annotation.getType.getJavaClass.getFullyQualifiedName still just
// returns the short
// class name. So for now, just check for the short name.
String thisAnnoName = thisAnno.getType().getJavaClass().getName();
//Make short name for recognizing, if returns long
int containsPoint = thisAnnoName.lastIndexOf('.');
if (containsPoint != -1)
{
thisAnnoName = thisAnnoName.substring(containsPoint+1);
}
if (thisAnnoName.equals(annoName))
{
return thisAnno;
}
}
return null;
}
private String getFullyQualifiedClassName(JavaClass clazz, String fqn)
{
//QDox 1.9 bug. getFullyQualifiedName does not resolve
//correctly classes like javax.servlet.jsp.tagext.TagSupport as parent
//of a class with @JSFJspTag. The temporal solution is scan
//the imports, looking for this type and if it is found replace it.
//Fixed on 1.9.1, but better let the code as is
/*
if (fqn.indexOf('.') == -1)
{
String [] imports = clazz.getSource().getImports();
for (int i = 0; i < imports.length; i++)
{
if (imports[i].endsWith(fqn))
{
fqn = imports[i];
}
}
}*/
return fqn;
}
/**
* Remove all leading whitespace and a quotemark if it exists.
* <p>
* Qdox comments like <code>foo val= "bar"</code> return a value with
* leading whitespace and quotes, so remove them.
*/
private String clean(Object srcObj)
{
if (srcObj == null)
{
return null;
}
String src = srcObj.toString();
int start = 0;
int end = src.length();
if (end == 0)
{
return src;
}
if (src.equals("\"\""))
{
return "\"\"";
}
while (start <= end)
{
char c = src.charAt(start);
if (!Character.isWhitespace(c) && (c != '"'))
{
break;
}
++start;
}
while (end >= start)
{
char c = src.charAt(end - 1);
if (!Character.isWhitespace(c) && (c != '"'))
{
break;
}
--end;
}
return src.substring(start, end);
}
/**
* Get the named attribute from a doc-annotation.
*
* Param clazz is the class the annotation is attached to; only used when
* reporting errors.
*/
private String getString(JavaClass clazz, String key, Map map, String dflt)
{
String val = clean(map.get(key));
if (val != null)
{
return val;
}
else
{
return dflt;
}
}
/**
* Get the named attribute from a doc-annotation and convert to a boolean.
*
* Param clazz is the class the annotation is attached to; only used when
* reporting errors.
*/
private Boolean getBoolean(JavaClass clazz, String key, Map map,
Boolean dflt)
{
String val = clean(map.get(key));
if (val == null)
{
return dflt;
}
// TODO: report problem if the value does not look like "true" or
// "false",
// rather than silently converting it to false.
return Boolean.valueOf(val);
}
/**
* Set the basic data on a ClassMeta.
* <p>
* There is one property not set here: the parentClassName. See method
* initComponentAncestry for further details.
*/
private void initClassMeta(Model model, JavaClass clazz,
ClassMeta modelItem, String classNameOverride)
{
modelItem.setModelId(model.getModelId());
modelItem.setSourceClassName(clazz.getFullyQualifiedName());
JavaClass realParentClass = clazz.getSuperJavaClass();
if (realParentClass != null)
{
String fqn = realParentClass.getFullyQualifiedName();
if ((fqn != null) && !fqn.startsWith("java.lang"))
{
fqn = getFullyQualifiedClassName(clazz,fqn);
modelItem.setSourceClassParentClassName(fqn);
}
}
// JSF Entity class.
if (StringUtils.isEmpty(classNameOverride))
{
modelItem.setClassName(clazz.getFullyQualifiedName());
}
else
{
modelItem.setClassName(classNameOverride);
}
// interfaces metadata is inherited from
JavaClass[] classes = clazz.getImplementedInterfaces();
List ifaceNames = new ArrayList();
for (int i = 0; i < classes.length; ++i)
{
JavaClass iclazz = classes[i];
ComponentMeta ifaceComponent = model
.findComponentByClassName(iclazz.getFullyQualifiedName());
if (ifaceComponent != null)
{
ifaceNames.add(ifaceComponent.getClassName());
}
}
modelItem.setInterfaceClassNames(ifaceNames);
}
/**
* For each component, try to find its "logical" parent component,
* ie the nearest superclass that is also annotated as a component
* and therefore has an entry in the model.
* <p>
* In most cases this could be done at the time the component is
* processed. The processClass() method does try to process the
* classes that qdox discovers in ancestor->descendant order.
* <p>
* However there is one case where this just doesn't work. Therefore
* a two-pass approach is used: first create a ComponentMeta for
* each component, and then on a second pass find the matching
* parent for each one.
* <p>
* The problem case is where an annotated java class extends a
* generated one. In this case when walking up the ancestry tree of
* the hand-written class we find an entry for which there is no
* ComponentMeta entry. We do not know whether this is because the
* parent exists but is not annotated, or whether a ComponentMeta
* for that parent will be generated once we have processed some
* other class that happens to have the matching annotation.
*/
private void initComponentAncestry(Map javaClassByName, Model model, ClassMeta modelItem)
{
JavaClass clazz = (JavaClass) javaClassByName.get(modelItem.getSourceClassName());
JavaClass parentClazz = clazz.getSuperJavaClass();
while (parentClazz != null)
{
String parentClazzName = parentClazz.getFullyQualifiedName();
parentClazzName = getFullyQualifiedClassName(clazz,parentClazzName);
ComponentMeta parentComponent = model
.findComponentByClassName(parentClazzName);
if (parentComponent != null)
{
modelItem.setParentClassName(parentComponent.getClassName());
break;
}
parentClazz = parentClazz.getSuperJavaClass();
}
}
/**
* Same as initComponentAncestry but for validators.
*/
private void initValidatorAncestry(Map javaClassByName, Model model, ClassMeta modelItem)
{
JavaClass clazz = (JavaClass) javaClassByName.get(modelItem.getSourceClassName());
JavaClass parentClazz = clazz.getSuperJavaClass();
while (parentClazz != null)
{
String parentClazzName = parentClazz.getFullyQualifiedName();
parentClazzName = getFullyQualifiedClassName(clazz,parentClazzName);
ValidatorMeta parentComponent = model
.findValidatorByClassName(parentClazzName);
if (parentComponent != null)
{
modelItem.setParentClassName(parentComponent.getClassName());
break;
}
parentClazz = parentClazz.getSuperJavaClass();
}
}
/**
* Same as initComponentAncestry but for converters
*/
private void initConverterAncestry(Map javaClassByName, Model model, ClassMeta modelItem)
{
JavaClass clazz = (JavaClass) javaClassByName.get(modelItem.getSourceClassName());
JavaClass parentClazz = clazz.getSuperJavaClass();
while (parentClazz != null)
{
String parentClazzName = parentClazz.getFullyQualifiedName();
parentClazzName = getFullyQualifiedClassName(clazz,parentClazzName);
ConverterMeta parentComponent = model
.findConverterByClassName(parentClazzName);
if (parentComponent != null)
{
modelItem.setParentClassName(parentComponent.getClassName());
break;
}
parentClazz = parentClazz.getSuperJavaClass();
}
}
private void processConverter(Map props, AbstractJavaEntity ctx,
JavaClass clazz, Model model)
{
String longDescription = clazz.getComment();
String descDflt = getFirstSentence(longDescription);
if ((descDflt == null) || (descDflt.length() < 2))
{
descDflt = "no description";
}
String shortDescription = getString(clazz, "desc", props, descDflt);
String converterIdDflt = null;
JavaField fieldConverterId = clazz
.getFieldByName("CONVERTER_ID");
if (fieldConverterId != null)
{
String value = fieldConverterId.getInitializationExpression();
converterIdDflt = clean(value.substring(value.indexOf('"')));
}
String converterId = getString(clazz, "id", props, converterIdDflt);
// Check for both "class" and "clazz" in order to support
// doclet and real annotations.
String classNameOverride = getString(clazz, "class", props, null);
classNameOverride = getString(clazz,"clazz",props,classNameOverride);
String componentName = getString(clazz, "name", props, null);
String bodyContent = getString(clazz, "bodyContent", props, null);
String tagClass = getString(clazz, "tagClass", props, null);
String tagSuperclass = getString(clazz, "tagSuperclass", props, null);
String serialuidtag = getString(clazz, "serialuidtag", props, null);
Boolean configExcluded = getBoolean(clazz,"configExcluded",props,null);
ConverterMeta converter = new ConverterMeta();
initClassMeta(model, clazz, converter, classNameOverride);
converter.setName(componentName);
converter.setBodyContent(bodyContent);
converter.setTagClass(tagClass);
converter.setTagSuperclass(tagSuperclass);
converter.setConverterId(converterId);
converter.setDescription(shortDescription);
converter.setLongDescription(longDescription);
converter.setSerialuidtag(serialuidtag);
converter.setConfigExcluded(configExcluded);
// Now here walk the component looking for property annotations.
processComponentProperties(clazz, converter);
model.addConverter(converter);
}
private void processValidator(Map props, AbstractJavaEntity ctx,
JavaClass clazz, Model model)
{
String longDescription = clazz.getComment();
String descDflt = getFirstSentence(longDescription);
if ((descDflt == null) || (descDflt.length() < 2))
{
descDflt = "no description";
}
String shortDescription = getString(clazz, "desc", props, descDflt);
String validatorIdDflt = null;
JavaField fieldConverterId = clazz
.getFieldByName("VALIDATOR_ID");
if (fieldConverterId != null)
{
String value = fieldConverterId.getInitializationExpression();
validatorIdDflt = clean(value.substring(value.indexOf('"')));
}
String validatorId = getString(clazz, "id", props, validatorIdDflt);
// Check for both "class" and "clazz" in order to support
// doclet and real annotations.
String classNameOverride = getString(clazz, "class", props, null);
classNameOverride = getString(clazz,"clazz",props,classNameOverride);
String componentName = getString(clazz, "name", props, null);
String bodyContent = getString(clazz, "bodyContent", props, null);
String tagClass = getString(clazz, "tagClass", props, null);
String tagSuperclass = getString(clazz, "tagSuperclass", props, null);
String serialuidtag = getString(clazz, "serialuidtag", props, null);
Boolean configExcluded = getBoolean(clazz,"configExcluded",props,null);
ValidatorMeta validator = new ValidatorMeta();
initClassMeta(model, clazz, validator, classNameOverride);
validator.setName(componentName);
validator.setBodyContent(bodyContent);
validator.setTagClass(tagClass);
validator.setTagSuperclass(tagSuperclass);
validator.setValidatorId(validatorId);
validator.setDescription(shortDescription);
validator.setLongDescription(longDescription);
validator.setSerialuidtag(serialuidtag);
validator.setConfigExcluded(configExcluded);
// Now here walk the component looking for property annotations.
processComponentProperties(clazz, validator);
model.addValidator(validator);
}
private void processRenderKit(Map props, AbstractJavaEntity ctx,
JavaClass clazz, Model model)
{
String renderKitId = getString(clazz, "renderKitId", props, null);
String renderKitClass = getString(clazz, "class", props, clazz
.getFullyQualifiedName());
renderKitClass = getString(clazz,"clazz",props,renderKitClass);
RenderKitMeta renderKit = model.findRenderKitById(renderKitId);
if (renderKit == null)
{
renderKit = new RenderKitMeta();
renderKit.setClassName(renderKitClass);
renderKit.setRenderKitId(renderKitId);
model.addRenderKit(renderKit);
}
else
{
renderKit.setClassName(renderKitClass);
renderKit.setRenderKitId(renderKitId);
}
}
private void processRenderer(Map props, AbstractJavaEntity ctx,
JavaClass clazz, Model model)
{
String longDescription = clazz.getComment();
String descDflt = getFirstSentence(longDescription);
if ((descDflt == null) || (descDflt.length() < 2))
{
descDflt = "no description";
}
String shortDescription = getString(clazz, "desc", props, descDflt);
String renderKitId = getString(clazz, "renderKitId", props, null);
String rendererClass = getString(clazz, "class", props, clazz
.getFullyQualifiedName());
rendererClass = getString(clazz,"clazz",props,rendererClass);
String componentFamily = getString(clazz,"family", props,null);
String rendererType = getString(clazz,"type", props,null);
RenderKitMeta renderKit = model.findRenderKitById(renderKitId);
if (renderKit == null)
{
renderKit = new RenderKitMeta();
renderKit.setRenderKitId(renderKitId);
model.addRenderKit(renderKit);
}
RendererMeta renderer = new RendererMeta();
renderer.setClassName(rendererClass);
renderer.setDescription(shortDescription);
renderer.setComponentFamily(componentFamily);
renderer.setRendererType(rendererType);
renderKit.addRenderer(renderer);
}
private void processTag(Map props, AbstractJavaEntity ctx,
JavaClass clazz, Model model) throws MojoExecutionException
{
String longDescription = clazz.getComment();
String descDflt = getFirstSentence(longDescription);
if ((descDflt == null) || (descDflt.length() < 2))
{
descDflt = "no description";
}
String shortDescription = getString(clazz, "desc", props, descDflt);
String tagName = getString(clazz, "name", props, null);
String classNameOverride = getString(clazz, "class", props, null);
classNameOverride = getString(clazz,"clazz",props,classNameOverride);
String bodyContent = getString(clazz, "bodyContent", props, "JSP");
String tagHandler = getString(clazz, "tagHandler", props, null);
TagMeta tag = new TagMeta();
initClassMeta(model, clazz, tag, classNameOverride);
tag.setName(tagName);
tag.setBodyContent(bodyContent);
tag.setDescription(shortDescription);
tag.setLongDescription(longDescription);
tag.setTagHandler(tagHandler);
processTagAttributes(clazz, tag);
model.addTag(tag);
}
private void processComponent(Map props, AbstractJavaEntity ctx,
JavaClass clazz, Model model) throws MojoExecutionException
{
String componentTypeDflt = null;
JavaField fieldComponentType = clazz.getFieldByName("COMPONENT_TYPE");
if (fieldComponentType != null)
{
componentTypeDflt = clean(fieldComponentType
.getInitializationExpression());
}
String componentTypeFamily = null;
JavaField fieldComponentFamily = clazz
.getFieldByName("COMPONENT_FAMILY");
if (fieldComponentFamily != null)
{
componentTypeFamily = clean(fieldComponentFamily
.getInitializationExpression());
}
String rendererTypeDflt = null;
JavaField fieldRendererType = clazz
.getFieldByName("DEFAULT_RENDERER_TYPE");
if (fieldRendererType != null)
{
rendererTypeDflt = clean(fieldRendererType
.getInitializationExpression());
}
String componentName = getString(clazz, "name", props, null);
// Check for both "class" and "clazz" in order to support
// doclet and real annotations.
String classNameOverride = getString(clazz, "class", props, null);
classNameOverride = getString(clazz,"clazz",props,classNameOverride);
Boolean template = getBoolean(clazz,"template",props, null);
String longDescription = clazz.getComment();
String descDflt = getFirstSentence(longDescription);
if ((descDflt == null) || (descDflt.length() < 2))
{
descDflt = "no description";
}
String shortDescription = getString(clazz, "desc", props, descDflt);
String bodyContent = getString(clazz, "bodyContent", props, null);
String componentFamily = getString(clazz, "family", props,
componentTypeFamily);
String componentType = getString(clazz, "type", props,
componentTypeDflt);
String rendererType = getString(clazz, "defaultRendererType", props,
rendererTypeDflt);
Boolean canHaveChildren = getBoolean(clazz, "canHaveChildren", props, null);
Boolean configExcluded = getBoolean(clazz,"configExcluded",props,null);
String tagClass = getString(clazz, "tagClass", props, null);
String tagSuperclass = getString(clazz, "tagSuperclass", props, null);
String tagHandler = getString(clazz, "tagHandler", props, null);
String defaultEventName = getString(clazz, "defaultEventName", props, null);
String serialuid = getString(clazz, "serialuid", props, null);
String implementsValue = getString(clazz, "implements", props, null);
implementsValue = getString(clazz, "implementz", props, implementsValue);
ComponentMeta component = new ComponentMeta();
initClassMeta(model, clazz, component, classNameOverride);
component.setName(componentName);
component.setBodyContent(bodyContent);
component.setDescription(shortDescription);
component.setLongDescription(longDescription);
component.setConfigExcluded(configExcluded);
component.setType(componentType);
component.setFamily(componentFamily);
component.setRendererType(rendererType);
component.setChildren(canHaveChildren);
component.setSerialuid(serialuid);
component.setImplements(implementsValue);
component.setTemplate(template);
component.setDefaultEventName(defaultEventName);
JavaClass[] interfaces = clazz.getImplementedInterfaces();
for (int i = 0; i < interfaces.length; ++i)
{
JavaClass iface = interfaces[i];
if (iface.getFullyQualifiedName().equals(
"javax.faces.component.NamingContainer"))
{
component.setNamingContainer(Boolean.TRUE);
break;
}
}
component.setTagClass(tagClass);
component.setTagSuperclass(tagSuperclass);
component.setTagHandler(tagHandler);
// Now here walk the component looking for property annotations.
processComponentProperties(clazz, component);
processComponentFacets(clazz, component);
model.addComponent(component);
}
private void processTagAttributes(JavaClass clazz,
TagMeta ctag)
{
JavaMethod[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; ++i)
{
JavaMethod method = methods[i];
DocletTag tag = method.getTagByName(DOC_JSP_ATTRIBUTE);
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processTagAttribute(props, (AbstractJavaEntity)tag.getContext(), clazz,
method, ctag);
}
Annotation anno = getAnnotation(method, DOC_JSP_ATTRIBUTE);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processTagAttribute(props, (AbstractJavaEntity)anno.getContext(), clazz,
method, ctag);
}
}
DocletTag[] jspProperties = clazz.getTagsByName(DOC_JSP_ATTRIBUTE);
for (int i = 0; i < jspProperties.length; ++i)
{
//We have here only doclets, because this part is only for
//solve problems with binding property on 1.1
DocletTag tag = jspProperties[i];
Map props = tag.getNamedParameterMap();
processTagAttribute(props, (AbstractJavaEntity)tag.getContext(), clazz,
ctag);
}
}
private void processTagAttribute(Map props, AbstractJavaEntity ctx,
JavaClass clazz, JavaMethod method, TagMeta tag)
{
Boolean required = getBoolean(clazz, "required", props, null);
Boolean rtexprvalue = getBoolean(clazz, "rtexprvalue", props, null);
String longDescription = ctx.getComment();
String descDflt = getFirstSentence(longDescription);
if ((descDflt == null) || (descDflt.length() < 2))
{
descDflt = "no description";
}
String shortDescription = getString(clazz, "desc", props, descDflt);
Type returnType = null;
if (method.getName().startsWith("set"))
{
returnType = method.getParameters()[0].getType();
}
else
{
returnType = method.getReturns();
}
String fullyQualifiedReturnType = returnType.getJavaClass().getFullyQualifiedName();
fullyQualifiedReturnType = getFullyQualifiedClassName(clazz,fullyQualifiedReturnType);
if (returnType.isArray() && (fullyQualifiedReturnType.indexOf('[') == -1))
{
for (int i = 0; i < returnType.getDimensions();i++)
{
fullyQualifiedReturnType = fullyQualifiedReturnType + "[]";
}
}
String className = getString(clazz,"className",props, fullyQualifiedReturnType);
String deferredValueType = getString(clazz, "deferredValueType", props, null);
String deferredMethodSignature = getString(clazz, "deferredMethodSignature", props, null);
Boolean exclude = getBoolean(clazz, "exclude", props, null);
AttributeMeta a = new AttributeMeta();
a.setName(methodToPropName(method.getName()));
a.setClassName(className);
a.setRequired(required);
a.setRtexprvalue(rtexprvalue);
a.setDescription(shortDescription);
a.setLongDescription(longDescription);
a.setDeferredValueType(deferredValueType);
a.setDeferredMethodSignature(deferredMethodSignature);
a.setExclude(exclude);
tag.addAttribute(a);
}
private void processTagAttribute(Map props, AbstractJavaEntity ctx,
JavaClass clazz, TagMeta tag)
{
Boolean required = getBoolean(clazz, "required", props, null);
Boolean rtexprvalue = getBoolean(clazz, "rtexprvalue", props, null);
String longDescription = getString(clazz, "longDescription", props, null);
String descDflt = longDescription;
if ((descDflt == null) || (descDflt.length() < 2))
{
descDflt = "no description";
}
String shortDescription = getString(clazz, "desc", props, descDflt);
String name = getString(clazz, "name", props, descDflt);
String className = getString(clazz, "className", props, descDflt);
String deferredValueType = getString(clazz, "deferredValueType", props, null);
String deferredMethodSignature = getString(clazz, "deferredMethodSignature", props, null);
Boolean exclude = getBoolean(clazz, "exclude", props, null);
AttributeMeta a = new AttributeMeta();
a.setName(name);
a.setClassName(className);
a.setRequired(required);
a.setRtexprvalue(rtexprvalue);
a.setDescription(shortDescription);
a.setLongDescription(longDescription);
a.setDeferredValueType(deferredValueType);
a.setDeferredMethodSignature(deferredMethodSignature);
a.setExclude(exclude);
tag.addAttribute(a);
}
/**
* Look for any methods on the specified class that are annotated as being
* component properties, and add metadata about them to the model.
*/
private void processComponentProperties(JavaClass clazz,
PropertyHolder component)
{
JavaMethod[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; ++i)
{
JavaMethod method = methods[i];
DocletTag tag = method.getTagByName(DOC_PROPERTY);
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processComponentProperty(props, (AbstractJavaEntity)tag.getContext(), clazz,
method, component);
}
Annotation anno = getAnnotation(method, DOC_PROPERTY);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processComponentProperty(props, (AbstractJavaEntity)anno.getContext(), clazz,
method, component);
}
}
Type [] interfaces = clazz.getImplements();
//Scan interfaces for properties to be added to this component
//This feature allow us to have groups of functions.
for (int i = 0; i < interfaces.length;++i)
{
JavaClass intf = interfaces[i].getJavaClass();
//If the interfaces has a JSFComponent Doclet,
//this is managed in other way
if (intf.getTagByName(DOC_COMPONENT, false) == null)
{
JavaMethod[] intfmethods = intf.getMethods();
for (int j = 0; j < intfmethods.length; ++j)
{
JavaMethod intfmethod = intfmethods[j];
DocletTag tag = intfmethod.getTagByName(DOC_PROPERTY);
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processInterfaceComponentProperty(props, (AbstractJavaEntity)tag.getContext(),
clazz, intfmethod, component);
}
Annotation anno = getAnnotation(intfmethod, DOC_PROPERTY);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processInterfaceComponentProperty(props, (AbstractJavaEntity)anno.getContext(),
clazz, intfmethod, component);
}
}
}
}
//Scan for properties defined only on jsp (special case on myfaces 1.1,
//this feature should not be used on typical situations)
DocletTag[] jspProperties = clazz.getTagsByName(DOC_JSP_PROPERTY);
for (int i = 0; i < jspProperties.length; ++i)
{
//We have here only doclets, because this part is only for
//solve problems with binding property on 1.1
DocletTag tag = jspProperties[i];
Map props = tag.getNamedParameterMap();
processComponentJspProperty(props, (AbstractJavaEntity)tag.getContext(), clazz,
component);
}
Annotation jspPropertyAnno = getAnnotation(clazz, DOC_JSP_PROPERTY);
if (jspPropertyAnno != null)
{
Map props = jspPropertyAnno.getNamedParameterMap();
processComponentJspProperty(props, (AbstractJavaEntity)jspPropertyAnno.getContext(),
clazz, component);
}
Annotation jspAnno = getAnnotation(clazz, DOC_JSP_PROPERTIES);
if (jspAnno != null)
{
Object jspProps = jspAnno.getNamedParameter("properties");
if (jspProps instanceof Annotation)
{
Annotation jspPropertiesAnno = (Annotation) jspProps;
Map props = jspPropertiesAnno.getNamedParameterMap();
processComponentJspProperty(props, (AbstractJavaEntity)jspAnno.getContext(), clazz,
component);
}
else
{
List jspPropsList = (List) jspProps;
for (int i = 0; i < jspPropsList.size();i++)
{
Annotation anno = (Annotation) jspPropsList.get(i);
Map props = anno.getNamedParameterMap();
processComponentJspProperty(props, (AbstractJavaEntity)jspAnno.getContext(), clazz,
component);
}
}
}
}
private void processComponentFacets(JavaClass clazz,
FacetHolder component)
{
JavaMethod[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; ++i)
{
JavaMethod method = methods[i];
DocletTag tag = method.getTagByName(DOC_FACET);
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processComponentFacet(props, (AbstractJavaEntity)tag.getContext(), clazz,
method, component);
}
Annotation anno = getAnnotation(method, DOC_FACET);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processComponentFacet(props, (AbstractJavaEntity)anno.getContext(), clazz,
method, component);
}
}
Type [] interfaces = clazz.getImplements();
//Scan interfaces for properties to be added to this component
//This feature allow us to have groups of functions.
for (int i = 0; i < interfaces.length;++i)
{
JavaClass intf = interfaces[i].getJavaClass();
//If the interfaces has a JSFComponent Doclet,
//this is managed in other way
if (intf.getTagByName(DOC_COMPONENT, false) == null)
{
JavaMethod[] intfmethods = intf.getMethods();
for (int j = 0; j < intfmethods.length; ++j)
{
JavaMethod intfmethod = intfmethods[j];
DocletTag tag = intfmethod.getTagByName(DOC_FACET);
if (tag != null)
{
Map props = tag.getNamedParameterMap();
processInterfaceComponentFacet(props, (AbstractJavaEntity)tag.getContext(),
clazz, intfmethod, component);
}
Annotation anno = getAnnotation(intfmethod, DOC_FACET);
if (anno != null)
{
Map props = anno.getNamedParameterMap();
processInterfaceComponentFacet(props, (AbstractJavaEntity)anno.getContext(),
clazz, intfmethod, component);
}
}
}
}
}
private void processInterfaceComponentProperty(Map props, AbstractJavaEntity ctx,
JavaClass clazz, JavaMethod method, PropertyHolder component)
{
this.processComponentProperty(props, ctx, clazz, method, component);
PropertyMeta property = component.getProperty(methodToPropName(method.getName()));
//Try to get the method from the component clazz to see if this
//has an implementation
JavaMethod clazzMethod = clazz.getMethodBySignature(method.getName(), null , false);
if (clazzMethod == null)
{
//The method should be generated!
property.setGenerated(Boolean.TRUE);
}
}
private void processInterfaceComponentFacet(Map props, AbstractJavaEntity ctx,
JavaClass clazz, JavaMethod method, FacetHolder component)
{
this.processComponentFacet(props, ctx, clazz, method, component);
FacetMeta facet = component.getFacet(methodToPropName(method.getName()));
//Try to get the method from the component clazz to see if this
//has an implementation
JavaMethod clazzMethod = clazz.getMethodBySignature(method.getName(), null , false);
if (clazzMethod == null)
{
//The method should be generated!
facet.setGenerated(Boolean.TRUE);
}
}
private void processComponentProperty(Map props, AbstractJavaEntity ctx,
JavaClass clazz, JavaMethod method, PropertyHolder component)
{
Boolean required = getBoolean(clazz, "required", props, null);
Boolean transientProp = getBoolean(clazz, "transient", props, null);
transientProp = getBoolean(clazz, "istransient", props, transientProp);
Boolean stateHolder = getBoolean(clazz, "stateHolder", props, null);
Boolean literalOnly = getBoolean(clazz, "literalOnly", props, null);
Boolean tagExcluded = getBoolean(clazz, "tagExcluded", props, null);
Boolean localMethod = getBoolean(clazz, "localMethod",props,null);
Boolean setMethod = getBoolean(clazz, "setMethod",props,null);
String localMethodScope = getString(clazz, "localMethodScope",props,null);
String setMethodScope = getString(clazz, "setMethodScope",props,null);
Boolean inheritedTag = getBoolean(clazz, "inheritedTag",props,null);
String longDescription = ctx.getComment();
String descDflt = getFirstSentence(longDescription);
if ((descDflt == null) || (descDflt.length() < 2))
{
descDflt = "no description";
}
String shortDescription = getString(clazz, "desc", props, descDflt);
String returnSignature = getString(clazz, "returnSignature", props, null);
String methodSignature = getString(clazz, "methodSignature", props, null);
String defaultValue = getString(clazz,"defaultValue",props,null);
String jspName = getString(clazz,"jspName",props,null);
Boolean rtexprvalue = getBoolean(clazz, "rtexprvalue",props,null);
String clientEvent = getString(clazz, "clientEvent",props,null);
String deferredValueType = getString(clazz, "deferredValueType", props, null);
Type returnType = null;
if (method.getName().startsWith("set"))
{
returnType = method.getParameters()[0].getType();
}
else
{
returnType = method.getReturns();
}
String fullyQualifiedReturnType = returnType.getJavaClass().getFullyQualifiedName();
fullyQualifiedReturnType = getFullyQualifiedClassName(clazz, fullyQualifiedReturnType);
if (returnType.isArray() && (fullyQualifiedReturnType.indexOf('[') == -1))
{
for (int i = 0; i < returnType.getDimensions();i++)
{
fullyQualifiedReturnType = fullyQualifiedReturnType + "[]";
}
}
PropertyMeta p = new PropertyMeta();
p.setName(methodToPropName(method.getName()));
p.setClassName(fullyQualifiedReturnType);
p.setRequired(required);
p.setTransient(transientProp);
p.setStateHolder(stateHolder);
p.setLiteralOnly(literalOnly);
p.setTagExcluded(tagExcluded);
p.setDescription(shortDescription);
p.setLongDescription(longDescription);
p.setDefaultValue(defaultValue);
p.setLocalMethod(localMethod);
p.setLocalMethodScope(localMethodScope);
p.setSetMethod(setMethod);
p.setSetMethodScope(setMethodScope);
p.setJspName(jspName);
p.setRtexprvalue(rtexprvalue);
p.setDeferredValueType(deferredValueType);
p.setClientEvent(clientEvent);
p.setInheritedTag(inheritedTag);
if (returnSignature != null)
{
MethodSignatureMeta signature = new MethodSignatureMeta();
signature.setReturnType(returnSignature);
if (methodSignature != null)
{
String[] params = StringUtils.split(methodSignature,',');
if (params != null)
{
for (int i = 0; i < params.length; i++)
{
signature.addParameterType(params[i].trim());
}
}
}
p.setMethodBindingSignature(signature);
}
//If the method is abstract this should be generated
if (method.isAbstract())
{
p.setGenerated(Boolean.TRUE);
}
component.addProperty(p);
}
private void processComponentFacet(Map props, AbstractJavaEntity ctx,
JavaClass clazz, JavaMethod method, FacetHolder component)
{
Boolean required = getBoolean(clazz, "required", props, null);
String longDescription = ctx.getComment();
String descDflt = getFirstSentence(longDescription);
if ((descDflt == null) || (descDflt.length() < 2))
{
descDflt = "no description";
}
String shortDescription = getString(clazz, "desc", props, descDflt);
FacetMeta p = new FacetMeta();
p.setName(methodToPropName(method.getName()));
p.setRequired(required);
p.setDescription(shortDescription);
p.setLongDescription(longDescription);
//If the method is abstract this should be generated
if (method.isAbstract())
{
p.setGenerated(Boolean.TRUE);
}
component.addFacet(p);
}
private void processComponentJspProperty(Map props, AbstractJavaEntity ctx,
JavaClass clazz, PropertyHolder component)
{
Boolean required = getBoolean(clazz, "required", props, null);
Boolean transientProp = getBoolean(clazz, "transient", props, null);
Boolean stateHolder = getBoolean(clazz, "stateHolder", props, null);
Boolean literalOnly = getBoolean(clazz, "literalOnly", props, null);
Boolean tagExcluded = getBoolean(clazz, "tagExcluded", props, null);
Boolean inheritedTag = getBoolean(clazz, "inheritedTag", props, null);
String longDescription = getString(clazz, "longDesc", props, null);
String descDflt = longDescription;
if ((descDflt == null) || (descDflt.length() < 2))
{
descDflt = "no description";
}
String shortDescription = getString(clazz, "desc", props, descDflt);
String returnType = getString(clazz, "returnType", props, null);
String name = getString(clazz, "name", props, null);
PropertyMeta p = new PropertyMeta();
p.setName(name);
p.setClassName(returnType);
p.setRequired(required);
p.setTransient(transientProp);
p.setStateHolder(stateHolder);
p.setLiteralOnly(literalOnly);
p.setTagExcluded(tagExcluded);
p.setInheritedTag(inheritedTag);
p.setDescription(shortDescription);
p.setLongDescription(longDescription);
p.setGenerated(Boolean.FALSE);
component.addProperty(p);
}
/**
* Convert a method name to a property name.
*/
static String methodToPropName(String methodName)
{
StringBuffer name = new StringBuffer();
if (methodName.startsWith("get") || methodName.startsWith("set"))
{
name.append(methodName.substring(3));
}
else if (methodName.startsWith("is"))
{
name.append(methodName.substring(2));
}
else
{
throw new IllegalArgumentException("Invalid annotated method name "
+ methodName);
}
// Handle following styles of property name
// getfooBar --> fooBar
// getFooBar --> fooBar
// getURL --> url
// getURLLocation --> urlLocation
for (int i = 0; i < name.length(); ++i)
{
char c = name.charAt(i);
if (Character.isUpperCase(c))
{
name.setCharAt(i, Character.toLowerCase(c));
}
else
{
if (i > 1)
{
// reset the previous char to uppercase
c = name.charAt(i - 1);
name.setCharAt(i - 1, Character.toUpperCase(c));
}
break;
}
}
return name.toString();
}
/**
* Given the full javadoc for a component, extract just the "first
* sentence".
* <p>
* Initially, just find the first dot, and strip out any linefeeds. Later,
* try to handle "e.g." and similar (see javadoc algorithm for sentence
* detection).
*/
private String getFirstSentence(String doc)
{
if (doc == null)
{
return null;
}
int index = doc.indexOf('.');
if (index == -1)
{
return doc;
}
// abc.
return doc.substring(0, index);
}
}