| /* |
| * 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); |
| } |
| } |