001// Copyright 2007, 2008, 2011, 2012 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.javadoc; 016 017import java.io.IOException; 018import java.util.Locale; 019import java.util.Set; 020import java.util.regex.Matcher; 021import java.util.regex.Pattern; 022 023import org.apache.commons.lang.StringEscapeUtils; 024import org.apache.tapestry5.ioc.internal.util.CollectionFactory; 025 026import com.sun.javadoc.FieldDoc; 027import com.sun.javadoc.SeeTag; 028import com.sun.javadoc.Tag; 029 030public class ParameterDescription 031{ 032 public final FieldDoc field; 033 034 public final String name; 035 036 public final String type; 037 038 public final String defaultValue; 039 040 public final String defaultPrefix; 041 042 public final boolean required; 043 044 public final boolean allowNull; 045 046 public final boolean cache; 047 048 public final String since; 049 050 public final boolean deprecated; 051 052 private static final Pattern SPECIAL_CONTENT = Pattern.compile("(?:</?(\\p{Alpha}+)>)|(?:&\\p{Alpha}+;)"); 053 private static final Set<String> PASS_THROUGH_TAGS = CollectionFactory.newSet("b", "em", "i", "code", "strong"); 054 055 056 public ParameterDescription(final FieldDoc fieldDoc, final String name, final String type, final String defaultValue, final String defaultPrefix, 057 final boolean required, final boolean allowNull, final boolean cache, final String since, final boolean deprecated) 058 { 059 this.field = fieldDoc; 060 this.name = name; 061 this.type = type; 062 this.defaultValue = defaultValue; 063 this.defaultPrefix = defaultPrefix; 064 this.required = required; 065 this.allowNull = allowNull; 066 this.cache = cache; 067 this.since = since; 068 this.deprecated = deprecated; 069 } 070 071 /** 072 * Extracts the description, converting Text and @link nodes as needed into markup text. 073 * 074 * @return markup text, ready for writing 075 * @throws IOException 076 */ 077 public String extractDescription() throws IOException 078 { 079 StringBuilder builder = new StringBuilder(); 080 081 for (Tag tag : field.inlineTags()) 082 { 083 if (tag.name().equals("Text")) 084 { 085 appendContentSafe(builder, tag.text()); 086 continue; 087 } 088 089 if (tag.name().equals("@link")) 090 { 091 SeeTag seeTag = (SeeTag) tag; 092 093 String label = seeTag.label(); 094 if (label != null && !label.equals("")) 095 { 096 builder.append(StringEscapeUtils.escapeHtml(label)); 097 continue; 098 } 099 100 if (seeTag.referencedClassName() != null) 101 builder.append(StringEscapeUtils.escapeHtml(seeTag.referencedClassName())); 102 103 if (seeTag.referencedMemberName() != null) 104 { 105 builder.append('#'); 106 builder.append(StringEscapeUtils.escapeHtml(seeTag.referencedMemberName())); 107 } 108 } 109 else if (tag.name().equals("@code")) 110 { 111 builder.append("<code>"); 112 builder.append(StringEscapeUtils.escapeHtml(tag.text())); 113 builder.append("</code>"); 114 } 115 } 116 117 String text = builder.toString(); 118 119 // Fix it up a little. 120 121 // Remove any simple open or close tags found in the text, as well as any XML entities. 122 123 return text.trim(); 124 } 125 126 private static void appendContentSafe(final StringBuilder sb, final String string){ 127 Matcher m = SPECIAL_CONTENT.matcher(string); 128 int index = 0; 129 while (index < string.length()){ 130 boolean match = m.find(index); 131 if (match){ 132 if (index != m.start()){ 133 sb.append(StringEscapeUtils.escapeHtml(string.substring(index, m.start()))); 134 } 135 String tagName = m.group(1); 136 if (tagName!= null){ 137 if(PASS_THROUGH_TAGS.contains(tagName.toLowerCase(Locale.US))){ 138 sb.append(m.group()); 139 } 140 }else{ 141 sb.append(m.group()); 142 } 143 index = m.end(); 144 }else{ 145 sb.append(StringEscapeUtils.escapeHtml(string.substring(index))); 146 break; 147 } 148 } 149 } 150}