001: package xdoclet.modules.ojb;
002:
003: /* Copyright 2003-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.util.*;
019:
020: import xjavadoc.*;
021: import xdoclet.XDocletException;
022: import xdoclet.tagshandler.AbstractProgramElementTagsHandler;
023: import xdoclet.tagshandler.ClassTagsHandler;
024: import xdoclet.tagshandler.MethodTagsHandler;
025: import xdoclet.tagshandler.XDocletTagshandlerMessages;
026: import xdoclet.util.Translator;
027: import xdoclet.util.TypeConversionUtil;
028:
029: /**
030: * @author <a href="mailto:tomdz@users.sourceforge.net">Thomas Dudziak (tomdz@users.sourceforge.net)</a>
031: * @created March 22, 2003
032: * @xdoclet.taghandler namespace="OjbMember"
033: */
034: public class OjbMemberTagsHandler extends
035: AbstractProgramElementTagsHandler {
036:
037: /**
038: * Returns the name of the current member which is the name in the case of a field, or the property name for an
039: * accessor method.
040: *
041: * @return The member name
042: * @exception XDocletException if an error occurs
043: */
044: public static String getMemberName() throws XDocletException {
045: if (getCurrentField() != null) {
046: return getCurrentField().getName();
047: } else if (getCurrentMethod() != null) {
048: return MethodTagsHandler
049: .getPropertyNameFor(getCurrentMethod());
050: } else {
051: return null;
052: }
053: }
054:
055: /**
056: * Returns the type of the current member which is the type in the case of a field, the return type for a getter
057: * method, or the type of the parameter for a setter method.
058: *
059: * @return The member type
060: * @exception XDocletException if an error occurs
061: */
062: public static XClass getMemberType() throws XDocletException {
063: if (getCurrentField() != null) {
064: return getCurrentField().getType();
065: } else if (getCurrentMethod() != null) {
066: XMethod method = getCurrentMethod();
067:
068: if (MethodTagsHandler.isGetterMethod(method)) {
069: return method.getReturnType().getType();
070: } else if (MethodTagsHandler.isSetterMethod(method)) {
071: XParameter param = (XParameter) method.getParameters()
072: .iterator().next();
073:
074: return param.getType();
075: }
076: }
077: return null;
078: }
079:
080: /**
081: * Returns the dimension of the type of the current member.
082: *
083: * @return The member dimension
084: * @exception XDocletException if an error occurs
085: * @see OjbMemberTagsHandler#getMemberType()
086: */
087: public static int getMemberDimension() throws XDocletException {
088: if (getCurrentField() != null) {
089: return getCurrentField().getDimension();
090: } else if (getCurrentMethod() != null) {
091: XMethod method = getCurrentMethod();
092:
093: if (MethodTagsHandler.isGetterMethod(method)) {
094: return method.getReturnType().getDimension();
095: } else if (MethodTagsHandler.isSetterMethod(method)) {
096: XParameter param = (XParameter) method.getParameters()
097: .iterator().next();
098:
099: return param.getDimension();
100: }
101: }
102: return 0;
103: }
104:
105: /**
106: * The <code>isField</code> processes the template body if the current member is a field.
107: *
108: * @param template a <code>String</code> value
109: * @param attributes a <code>Properties</code> value
110: * @exception XDocletException if an error occurs
111: * @doc:tag type="content"
112: */
113: public void isField(String template, Properties attributes)
114: throws XDocletException {
115: if (getCurrentField() != null) {
116: generate(template);
117: }
118: }
119:
120: /**
121: * The <code>isMethod</code> processes the template body if the current member is a method.
122: *
123: * @param template a <code>String</code> value
124: * @param attributes a <code>Properties</code> value
125: * @exception XDocletException if an error occurs
126: * @doc:tag type="block"
127: */
128: public void isMethod(String template, Properties attributes)
129: throws XDocletException {
130: if (getCurrentMethod() != null) {
131: generate(template);
132: }
133: }
134:
135: /**
136: * The <code>forAllMembers</code> method iterates through all fields of the current class. In contrast to the <code>FieldTagsHandler.forAllFields</code>
137: * method, this method operates on both fields and accessors (get/set/is-methods). In addition, the method
138: * automatically includes all supertype-fields (i.e., accessors for base interfaces) if the corresponding attribute
139: * is set (superclasses). The fields can optionally be limited to those posessing a specified tag.
140: *
141: * @param template a <code>String</code> value
142: * @param attributes a <code>Properties</code> value
143: * @exception XDocletException if an error occurs
144: * @doc:tag type="block"
145: * @doc.param name="class" optional="true" description="Specifies the type to be searched. If not
146: * specified, then the current type is used."
147: * @doc.param name="superclasses" optional="true" description="Specifies whether super types shall
148: * be processed as well."
149: * @doc.param name="sort" optional="true" values="true,false" description="If true then sort the
150: * fields list."
151: * @doc.param name="tagName" optional="true" description="Specifies a tag that all fields must
152: * posess in order to be processed."
153: * @doc.param name="paramName" optional="true" description="Specifies a param that the given tag
154: * must have."
155: * @doc.param name="value" optional="true" description="Specifies the value that the param must
156: * have."
157: */
158: public void forAllMembers(String template, Properties attributes)
159: throws XDocletException {
160: if (getCurrentClass() == null) {
161: return;
162: }
163:
164: String className = attributes.getProperty("class");
165: XClass type = null;
166:
167: if ((className == null) || (className.length() == 0)) {
168: type = getCurrentClass();
169: } else {
170: XClass curType;
171:
172: for (Iterator it = ClassTagsHandler.getAllClasses()
173: .iterator(); it.hasNext();) {
174: curType = (XClass) it.next();
175: if (className.equals(curType.getQualifiedName())) {
176: type = curType;
177: break;
178: }
179: }
180: if (type == null) {
181: throw new XDocletException(Translator.getString(
182: XDocletModulesOjbMessages.class,
183: XDocletModulesOjbMessages.COULD_NOT_FIND_TYPE,
184: new String[] { className }));
185: }
186: }
187:
188: String tagName = attributes.getProperty("tagName");
189: String paramName = attributes.getProperty("paramName");
190: String paramValue = attributes.getProperty("value");
191: boolean super Types = TypeConversionUtil.stringToBoolean(
192: attributes.getProperty("superclasses"), true);
193: boolean sort = TypeConversionUtil.stringToBoolean(attributes
194: .getProperty("sort"), true);
195: ArrayList allMemberNames = new ArrayList();
196: HashMap allMembers = new HashMap();
197:
198: if (super Types) {
199: addMembersInclSupertypes(allMemberNames, allMembers, type,
200: tagName, paramName, paramValue);
201: } else {
202: addMembers(allMemberNames, allMembers, type, tagName,
203: paramName, paramValue);
204: }
205: if (sort) {
206: Collections.sort(allMemberNames);
207: }
208: for (Iterator it = allMemberNames.iterator(); it.hasNext();) {
209: XMember member = (XMember) allMembers.get(it.next());
210:
211: if (member instanceof XField) {
212: setCurrentField((XField) member);
213: } else if (member instanceof XMethod) {
214: setCurrentMethod((XMethod) member);
215: }
216: generate(template);
217: if (member instanceof XField) {
218: setCurrentField(null);
219: } else if (member instanceof XMethod) {
220: setCurrentMethod(null);
221: }
222: }
223: }
224:
225: /**
226: * Iterates over all tags of current member and evaluates the template for each one.
227: *
228: * @param template The template to be evaluated
229: * @param attributes The attributes of the template tag
230: * @exception XDocletException If an error occurs
231: * @doc.tag type="block"
232: * @doc.param name="tagName" optional="false" description="The tag name."
233: * @doc.param name="paramName" optional="true" description="The parameter name."
234: */
235: public void forAllMemberTags(String template, Properties attributes)
236: throws XDocletException {
237: if (getCurrentField() != null) {
238: forAllMemberTags(
239: template,
240: attributes,
241: FOR_FIELD,
242: XDocletTagshandlerMessages.ONLY_CALL_FIELD_NOT_NULL,
243: new String[] { "forAllMemberTags" });
244: } else if (getCurrentMethod() != null) {
245: forAllMemberTags(
246: template,
247: attributes,
248: FOR_METHOD,
249: XDocletTagshandlerMessages.ONLY_CALL_METHOD_NOT_NULL,
250: new String[] { "forAllMemberTags" });
251: }
252: }
253:
254: /**
255: * Iterates over all tokens in current member tag with the name tagName and evaluates the body for every token.
256: *
257: * @param template The body of the block tag
258: * @param attributes The attributes of the template tag
259: * @exception XDocletException If an error occurs
260: * @doc.tag type="block"
261: * @doc.param name="tagName" optional="false" description="The tag name."
262: * @doc.param name="delimiter" description="delimiter for the StringTokenizer. consult javadoc for
263: * java.util.StringTokenizer default is ','"
264: * @doc.param name="skip" description="how many tokens to skip on start"
265: */
266: public void forAllMemberTagTokens(String template,
267: Properties attributes) throws XDocletException {
268: if (getCurrentField() != null) {
269: forAllMemberTagTokens(template, attributes, FOR_FIELD);
270: } else if (getCurrentMethod() != null) {
271: forAllMemberTagTokens(template, attributes, FOR_METHOD);
272: }
273: }
274:
275: /**
276: * Returns the name of the member which is the name in the case of a field, or the property name for an accessor
277: * method.
278: *
279: * @param attributes The attributes of the template tag
280: * @return The member name
281: * @exception XDocletException if an error occurs
282: * @doc.tag type="content"
283: */
284: public String memberName(Properties attributes)
285: throws XDocletException {
286: return getMemberName();
287: }
288:
289: /**
290: * Evaluates the body if current member has no tag with the specified name.
291: *
292: * @param template The body of the block tag
293: * @param attributes The attributes of the template tag
294: * @exception XDocletException Description of Exception
295: * @doc.tag type="block"
296: * @doc.param name="tagName" optional="false" description="The tag name."
297: * @doc.param name="paramName" description="The parameter name. If not specified, then the raw
298: * content of the tag is returned."
299: * @doc.param name="paramNum" description="The zero-based parameter number. It's used if the user
300: * used the space-separated format for specifying parameters."
301: * @doc.param name="error" description="Show this error message if no tag found."
302: */
303: public void ifDoesntHaveMemberTag(String template,
304: Properties attributes) throws XDocletException {
305: boolean result = false;
306:
307: if (getCurrentField() != null) {
308: if (!hasTag(attributes, FOR_FIELD)) {
309: result = true;
310: generate(template);
311: }
312: } else if (getCurrentMethod() != null) {
313: if (!hasTag(attributes, FOR_METHOD)) {
314: result = true;
315: generate(template);
316: }
317: }
318: if (!result) {
319: String error = attributes.getProperty("error");
320:
321: if (error != null) {
322: getEngine().print(error);
323: }
324: }
325: }
326:
327: /**
328: * Evaluates the body if the current class has at least one member with at least one tag with the specified name.
329: *
330: * @param template The body of the block tag
331: * @param attributes The attributes of the template tag
332: * @exception XDocletException Description of Exception
333: * @doc.tag type="block"
334: * @doc.param name="tagName" optional="false" description="The tag name."
335: * @doc.param name="paramName" description="The parameter name. If not specified, then the raw
336: * content of the tag is returned."
337: * @doc.param name="error" description="Show this error message if no tag found."
338: */
339: public void ifHasMemberWithTag(String template,
340: Properties attributes) throws XDocletException {
341: ArrayList allMemberNames = new ArrayList();
342: HashMap allMembers = new HashMap();
343: boolean hasTag = false;
344:
345: addMembers(allMemberNames, allMembers, getCurrentClass(), null,
346: null, null);
347: for (Iterator it = allMemberNames.iterator(); it.hasNext();) {
348: XMember member = (XMember) allMembers.get(it.next());
349:
350: if (member instanceof XField) {
351: setCurrentField((XField) member);
352: if (hasTag(attributes, FOR_FIELD)) {
353: hasTag = true;
354: }
355: setCurrentField(null);
356: } else if (member instanceof XMethod) {
357: setCurrentMethod((XMethod) member);
358: if (hasTag(attributes, FOR_METHOD)) {
359: hasTag = true;
360: }
361: setCurrentMethod(null);
362: }
363: if (hasTag) {
364: generate(template);
365: break;
366: }
367: }
368: }
369:
370: /**
371: * Evaluates the body if current member has at least one tag with the specified name.
372: *
373: * @param template The body of the block tag
374: * @param attributes The attributes of the template tag
375: * @exception XDocletException Description of Exception
376: * @doc.tag type="block"
377: * @doc.param name="tagName" optional="false" description="The tag name."
378: * @doc.param name="paramName" description="The parameter name. If not specified, then the raw
379: * content of the tag is returned."
380: * @doc.param name="paramNum" description="The zero-based parameter number. It's used if the user
381: * used the space-separated format for specifying parameters."
382: * @doc.param name="error" description="Show this error message if no tag found."
383: */
384: public void ifHasMemberTag(String template, Properties attributes)
385: throws XDocletException {
386: boolean result = false;
387:
388: if (getCurrentField() != null) {
389: if (hasTag(attributes, FOR_FIELD)) {
390: result = true;
391: generate(template);
392: }
393: } else if (getCurrentMethod() != null) {
394: if (hasTag(attributes, FOR_METHOD)) {
395: result = true;
396: generate(template);
397: }
398: }
399: if (!result) {
400: String error = attributes.getProperty("error");
401:
402: if (error != null) {
403: getEngine().print(error);
404: }
405: }
406: }
407:
408: /**
409: * Returns the value of the tag/parameter combination for the current member tag
410: *
411: * @param attributes The attributes of the template tag
412: * @return Description of the Returned Value
413: * @exception XDocletException Description of Exception
414: * @doc.tag type="content"
415: * @doc.param name="tagName" optional="false" description="The tag name."
416: * @doc.param name="paramName" description="The parameter name. If not specified, then the raw
417: * content of the tag is returned."
418: * @doc.param name="paramNum" description="The zero-based parameter number. It's used if the user
419: * used the space-separated format for specifying parameters."
420: * @doc.param name="values" description="The valid values for the parameter, comma separated. An
421: * error message is printed if the parameter value is not one of the values."
422: * @doc.param name="default" description="The default value is returned if parameter not specified
423: * by user for the tag."
424: */
425: public String memberTagValue(Properties attributes)
426: throws XDocletException {
427: if (getCurrentField() != null) {
428: // setting field to true will override the for_class value.
429: attributes.setProperty("field", "true");
430: return getExpandedDelimitedTagValue(attributes, FOR_FIELD);
431: } else if (getCurrentMethod() != null) {
432: return getExpandedDelimitedTagValue(attributes, FOR_METHOD);
433: } else {
434: return null;
435: }
436: }
437:
438: /**
439: * Evaluates the body if value for the member tag equals the specified value.
440: *
441: * @param template The body of the block tag
442: * @param attributes The attributes of the template tag
443: * @exception XDocletException If an error occurs
444: * @doc.tag type="block"
445: * @doc.param name="tagName" optional="false" description="The tag name."
446: * @doc.param name="paramName" description="The parameter name. If not specified, then the raw
447: * content of the tag is returned."
448: * @doc.param name="paramNum" description="The zero-based parameter number. It's used if the user
449: * used the space-separated format for specifying parameters."
450: * @doc.param name="value" optional="false" description="The expected value."
451: */
452: public void ifMemberTagValueEquals(String template,
453: Properties attributes) throws XDocletException {
454: if (getCurrentField() != null) {
455: if (isTagValueEqual(attributes, FOR_FIELD)) {
456: generate(template);
457: }
458: } else if (getCurrentMethod() != null) {
459: if (isTagValueEqual(attributes, FOR_METHOD)) {
460: generate(template);
461: }
462: }
463: }
464:
465: /**
466: * Retrieves the members of the type and of its super types.
467: *
468: * @param memberNames Will receive the names of the members (for sorting)
469: * @param members Will receive the members
470: * @param type The type to process
471: * @param tagName An optional tag for filtering the types
472: * @param paramName The feature to be added to the MembersInclSupertypes attribute
473: * @param paramValue The feature to be added to the MembersInclSupertypes attribute
474: * @throws XDocletException If an error occurs
475: */
476: private void addMembersInclSupertypes(Collection memberNames,
477: HashMap members, XClass type, String tagName,
478: String paramName, String paramValue)
479: throws XDocletException {
480: addMembers(memberNames, members, type, tagName, paramName,
481: paramValue);
482: if (type.getInterfaces() != null) {
483: for (Iterator it = type.getInterfaces().iterator(); it
484: .hasNext();) {
485: addMembersInclSupertypes(memberNames, members,
486: (XClass) it.next(), tagName, paramName,
487: paramValue);
488: }
489: }
490: if (!type.isInterface() && (type.getSuperclass() != null)) {
491: addMembersInclSupertypes(memberNames, members, type
492: .getSuperclass(), tagName, paramName, paramValue);
493: }
494: }
495:
496: /**
497: * Retrieves the members of the given type.
498: *
499: * @param memberNames Will receive the names of the members (for sorting)
500: * @param members Will receive the members
501: * @param type The type to process
502: * @param tagName An optional tag for filtering the types
503: * @param paramName The feature to be added to the Members attribute
504: * @param paramValue The feature to be added to the Members attribute
505: * @throws XDocletException If an error occurs
506: */
507: private void addMembers(Collection memberNames, HashMap members,
508: XClass type, String tagName, String paramName,
509: String paramValue) throws XDocletException {
510: if (!type.isInterface() && (type.getFields() != null)) {
511: XField field;
512:
513: for (Iterator it = type.getFields().iterator(); it
514: .hasNext();) {
515: field = (XField) it.next();
516: if (!field.isFinal() && !field.isStatic()
517: && !field.isTransient()) {
518: if (checkTagAndParam(field.getDoc(), tagName,
519: paramName, paramValue)) {
520: // already processed ?
521: if (!members.containsKey(field.getName())) {
522: memberNames.add(field.getName());
523: members.put(field.getName(), field);
524: }
525: }
526: }
527: }
528: }
529:
530: if (type.getMethods() != null) {
531: XMethod method;
532: String propertyName;
533:
534: for (Iterator it = type.getMethods().iterator(); it
535: .hasNext();) {
536: method = (XMethod) it.next();
537: if (!method.isConstructor() && !method.isNative()
538: && !method.isStatic()) {
539: if (checkTagAndParam(method.getDoc(), tagName,
540: paramName, paramValue)) {
541: if (MethodTagsHandler.isGetterMethod(method)
542: || MethodTagsHandler
543: .isSetterMethod(method)) {
544: propertyName = MethodTagsHandler
545: .getPropertyNameFor(method);
546: if (!members.containsKey(propertyName)) {
547: memberNames.add(propertyName);
548: members.put(propertyName, method);
549: }
550: }
551: }
552: }
553: }
554: }
555: }
556:
557: /**
558: * Determines whether the given documentation part contains the specified tag with the given parameter having the
559: * given value.
560: *
561: * @param doc The documentation part
562: * @param tagName The tag to be searched for
563: * @param paramName The parameter that the tag is required to have
564: * @param paramValue The value of the parameter
565: * @return boolean Whether the documentation part has the tag and parameter
566: */
567: private boolean checkTagAndParam(XDoc doc, String tagName,
568: String paramName, String paramValue) {
569: if (tagName == null) {
570: return true;
571: }
572: if (!doc.hasTag(tagName)) {
573: return false;
574: }
575: if (paramName == null) {
576: return true;
577: }
578: if (!doc.getTag(tagName).getAttributeNames()
579: .contains(paramName)) {
580: return false;
581: }
582: return (paramValue == null)
583: || paramValue.equals(doc.getTagAttributeValue(tagName,
584: paramName));
585: }
586: }
|