Update of 
/cvsroot/xdoclet-plugins/xdoclet-plugins/plugin-castor/src/main/java/org/xdoclet/plugin/castor
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10948

Added Files:
        CastorMappingXMLPlugin.java CastorMappingXMLPlugin.jelly 
Log Message:
Initial ersion of castor plugin

--- NEW FILE: CastorMappingXMLPlugin.java ---
/*
 * Copyright (c) 2003
 * XDoclet Team
 * All rights reserved.
 */
package org.xdoclet.plugin.castor;

import java.io.File;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;

import org.generama.JellyTemplateEngine;
import org.generama.QDoxCapableMetadataProvider;
import org.generama.WriterMapper;

import org.generama.defaults.QDoxPlugin;

import org.xdoclet.plugin.castor.qtags.TagLibrary;

import org.xdoclet.predicate.HasTag;

import com.thoughtworks.qdox.model.AbstractJavaEntity;
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;

/**
 * Plugin producing castor-mapping file.
 *
 * @author Diogo Quintela
 */
public class CastorMappingXMLPlugin extends QDoxPlugin {
    /** Constant: "castor.field" resolution in methods */
    private static final int METHODS = 1 << 0;
    /** Constant: "castor.field" resolution in fields */
    private static final int FIELDS = 1 << 1;
    /** Delimiter for file list for include files */
    private static final String INCLUDE_DELIM = ",";
    /** Name for extra class mapping merge file */
    private static final String CLASS_MAPPING_MERGE = "class-mappings.xml";
    /** Short name resolving map */
    private static final Map shortNamesMap;

    static {
        Map namesMap = new HashMap();
        namesMap.put("java.lang.Object", "other");
        namesMap.put("java.lang.String", "string");
        namesMap.put("java.math.BigDecimal", "big-decimal");
        namesMap.put("java.util.Date", "date");
        namesMap.put("java.util.Locale", "locale");
        shortNamesMap = Collections.unmodifiableMap(namesMap);
    }

    /** List of included files to insert in mapping file */
    private Collection includes;
    /** Cache of classes the we should generate a mapping for */
    private Collection mappingClasses;
    /** Directory of merge file(s) */
    private File mergeDir;
    /** Description for mapping file */
    private String description;
    /** Default name for generated file */
    private String fileName = "mapping.xml";
    /**
     * Auto extends affects the way the field and methods in classes that have 
superclasses work.  If auto
     * extends is set, a mapping for a class will include self methods and 
field, and super classes' method
     * and fields until a super classe as also a "castor.class" tag. If unset, 
all fields and methods will
     * be included in hierarchy, even if the working class extends another 
class that sould also have a
     * mapping.
     */
    private boolean autoExtends = true;
    /**
     * Short Names affects the type name resolving mechanism, replacing well 
known java-types by their short
     * name. See <a
     * 
href="http://castor.codehaus.org/xml-mapping.html&num;3.4-The-&lt;field&gt;-element";>3.4-The-&lt;field&gt;-element</a>
     * <ul>Supported short names:
     * <li>java.lang.Object -&gt; other</li>
     * <li>java.lang.String -&gt; string</li>
     * <li>java.math.BigDecimal -&gt; big-decimal</li>
     * <li>java.util.Date -&gt; date</li>
     * <li>java.util.Locale -&gt; locale</li>
     * </ul>
     */
    private boolean shortNames = true;
    /** Where shall we extract field information for mapping fields ? */
    private int resolveType = METHODS | FIELDS;

    /**
     * Creates a new MappingXMLPlugin object.
     *
     * @param jellyTemplateEngine Jelly engine
     * @param metadataProvider The provider
     * @param writerMapper The abstraction for generation
     */
    public CastorMappingXMLPlugin(JellyTemplateEngine jellyTemplateEngine,
        QDoxCapableMetadataProvider metadataProvider, WriterMapper 
writerMapper) {
        super(jellyTemplateEngine, metadataProvider, writerMapper);
        new TagLibrary(metadataProvider);
        this.setMultioutput(false);
    }

    /**
     * Setter for shortNames property
     *
     * @param shortNames The value for the property
     *
     * @see #shortNames
     */
    public void setShortNames(boolean shortNames) {
        this.shortNames = shortNames;
    }

    /**
     * Setter for autoExtends property
     *
     * @param autoExtends The value for the property
     *
     * @see #autoExtends
     */
    public void setAutoExtends(boolean autoExtends) {
        this.autoExtends = autoExtends;
    }

    /**
     * Add properties to Jelly context
     *
     * @param map The context map
     */
    protected void populateContextMap(Map map) {
        super.populateContextMap(map);
        map.put("mappingmergefile", CLASS_MAPPING_MERGE);
    }

    /**
     * Setter for an include file list separated by ','
     *
     * @param includesLst Include file list
     *
     * @throws NullPointerException if includesLst == null
     */
    public void setIncludes(String includesLst) {
        if (includesLst == null) {
            throw new NullPointerException();
        }

        String[] files = includesLst.split(INCLUDE_DELIM);

        if ((files != null) && (files.length > 0)) {
            includes = new ArrayList();

            for (int i = 0; i < files.length; i++) {
                if (files[i].trim().length() > 0) {
                    includes.add(files[i].trim());
                }
            }
        }
    }

    /**
     * Getter for list of include files
     *
     * @return The collection of files
     */
    public Collection getIncludes() {
        return includes;
    }

    /**
     * Getter for description property
     *
     * @return The value for the property
     */
    public String getDescription() {
        return this.description;
    }

    /**
     * Setter for description property
     *
     * @param description The value for the property
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * User setter for capture "castor.field" info in fields only. By default 
we'll capture that info in
     * fields and methods
     *
     * @param fieldOnly The flag indication the pretension
     */
    public void setFieldsOnly(boolean fieldOnly) {
        if (fieldOnly) {
            resolveType = FIELDS;
        }
    }

    /**
     * User setter for capture "castor.field" info in methods only (setters or 
getters). By default we'll
     * capture that info in fields and methods
     *
     * @param methodsOnly The flag indication the pretension
     */
    public void setMethodsOnly(boolean methodsOnly) {
        if (methodsOnly) {
            resolveType = METHODS;
        }
    }

    /**
     * Getter for mergerDir property
     *
     * @return The value of the property
     */
    public File getMergedir() {
        return mergeDir;
    }

    /**
     * Gets the collection of classes for which a mapping entry should be 
generated. Filters the data
     * providers list with a predicate for "castor.class" tag existence
     *
     * @return Collection of classes for which a mapping entry should be 
generated
     */
    public Collection getMappingClasses() {
        if (mappingClasses == null) {
            mappingClasses = 
CollectionUtils.select(metadataProvider.getMetadata(),
                    new HasTag("castor.class", null, null, false));
        }

        return mappingClasses;
    }

    /**
     * Resolves the mapping fields that should be included in the mapping file. 
The field and method
     * resolution in recursive in class hierarchy based in castor.class#extends 
tag value and autoExtends
     * property. See references for further description.
     *
     * @param mappingClass The mapping class that we are inquiring the list
     *
     * @return The list of JavaField's and JavaMethod's that should be queued 
for processing
     *
     * @see #autoExtends
     * @see #getExtends(JavaClass)
     * @see #getFieldsRecursive(JavaClass)
     * @see #getMethodsRecursive(JavaClass)
     */
    public Collection getMappingFields(JavaClass mappingClass) {
        List retList = new ArrayList();
        AbstractJavaEntity[][] resolve = {getFieldsRecursive(mappingClass), 
getMethodsRecursive(mappingClass)};
        DocletTag tag;

        for (int i = 0; i < resolve.length; i++) {
            for (int j = 0; (resolve[i] != null) && (j < resolve[i].length); 
j++) {
                tag = resolve[i][j].getTagByName("castor.field");

                if (tag != null) {
                    retList.add(resolve[i][j]);
                }
            }
        }

        return retList;
    }

    /**
     * An utility method to resolve the mapping methods to include in mapping 
field generation. We travel the
     * class hierarchy and will include all methods as found until the stop 
condition described in [EMAIL PROTECTED]
     * #getExtends(JavaClass)} is found.
     *
     * @param mappingClass The mapping classe to resolve the methods for
     *
     * @return The array of JavaMethods
     *
     * @see #autoExtends
     * @see #getExtends(JavaClass)
     */
    private JavaMethod[] getMethodsRecursive(JavaClass mappingClass) {
        List methodLst = new ArrayList();

        if ((resolveType & METHODS) == METHODS) {
            String extendsValue = null;
            JavaClass curJavaClass = mappingClass;

            while ((curJavaClass != null) && (extendsValue == null)) {
                methodLst.addAll(Arrays.asList(curJavaClass.getMethods()));
                extendsValue = curJavaClass.getNamedParameter("castor.class", 
"extends");
                curJavaClass = curJavaClass.getSuperJavaClass();

                if (autoExtends && (curJavaClass != null) && (extendsValue == 
null) &&
                        (curJavaClass.getTagByName("castor.class") != null)) {
                    extendsValue = curJavaClass.getFullyQualifiedName();
                }
            }
        }

        return (JavaMethod[]) methodLst.toArray(new JavaMethod[0]);
    }

    /**
     * An utility method to resolve the mapping field to include in mapping 
field generation. We travel the
     * class hierarchy and will include all fields as found until the stop 
condition described in [EMAIL PROTECTED]
     * #getExtends(JavaClass)} is found.
     *
     * @param mappingClass The mapping classe to resolve the fields for
     *
     * @return The array of JavaField
     *
     * @see #autoExtends
     * @see #getExtends(JavaClass)
     */
    private JavaField[] getFieldsRecursive(JavaClass mappingClass) {
        List fieldLst = new ArrayList();

        if ((resolveType & FIELDS) == FIELDS) {
            String extendsValue = null;
            JavaClass curJavaClass = mappingClass;

            while ((curJavaClass != null) && (extendsValue == null)) {
                fieldLst.addAll(Arrays.asList(curJavaClass.getFields()));
                extendsValue = curJavaClass.getNamedParameter("castor.class", 
"extends");
                curJavaClass = curJavaClass.getSuperJavaClass();

                if (autoExtends && (curJavaClass != null) && (extendsValue == 
null) &&
                        (curJavaClass.getTagByName("castor.class") != null)) {
                    extendsValue = curJavaClass.getFullyQualifiedName();
                }
            }
        }

        return (JavaField[]) fieldLst.toArray(new JavaField[0]);
    }

    /**
     * An utility method to resolve the type for the mapping field. If the tag 
name "castor.field#type" is
     * ofered will use it,  otherwise try to guess it from the associated 
types. As we support
     * "castor.field" in methods (setters or getters) and in field, we delegate 
the business logic in
     * dealing with it to the plugin
     *
     * @param fieldOrMethod An JavaMethod or JavaField
     *
     * @return The type of the refered field
     */
    public String getType(AbstractJavaEntity fieldOrMethod) {
        try {
            Type type = null;
            String fieldType = fieldOrMethod.getNamedParameter("castor.field", 
"type");

            if (fieldOrMethod instanceof JavaField) {
                type = ((JavaField) fieldOrMethod).getType();
            } else if (fieldOrMethod instanceof JavaMethod) {
                type = ((JavaMethod) fieldOrMethod).getPropertyType();
            }

            if ((fieldType == null) && (type != null)) {
                if (shortNames && shortNamesMap.containsKey(type.toString())) {
                    fieldType = (String) shortNamesMap.get(type.toString());
                } else {
                    StringBuffer retBuf = new StringBuffer(type.getValue());

                    if ("int".equals(retBuf.toString())) {
                        retBuf.append("eger");
                    }

                    int dimensions = type.getDimensions();

                    for (int i = 0; i < dimensions; i++) {
                        retBuf.append("[]");
                    }

                    fieldType = retBuf.toString();
                }
            }

            return fieldType;
        } catch (Throwable t) {
            t.printStackTrace();
            return null;
        }
    }

    /**
     * Getter for DTD's id
     *
     * @return DTD's id
     */
    public String getPublicId() {
        return "-//EXOLAB/Castor Mapping DTD Version 1.0//EN";
    }

    /**
     * Getter for DTD's location
     *
     * @return DTD's location
     */
    public String getSystemId() {
        return "http://castor.codehaus.org/mapping.dtd";;
        /*
         * Castor site moved: http://castor.codehaus.org/news.html#item20
         * <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Object Mapping DTD 
Version 1.0//EN"
         *                   "http://castor.exolab.org/mapping.dtd";
         */
    }

    /**
     * Setter for mergeDir property
     *
     * @param mergeDir The value for the property
     */
    public void setMergedir(File mergeDir) {
        this.mergeDir = mergeDir;
    }

    /**
     * An utility method to resolve the mapping extends field. We'll look for a 
"extends" tag within the
     * class hierarchy, or we'll use the nearest class that will be included in 
mapping file, depending of
     * autoExtends property value.
     *
     * @param mappingClass The mapping classe to resolve the value for
     *
     * @return The value to use, or null to keep it blank
     *
     * @see #autoExtends
     */
    public String getExtends(JavaClass mappingClass) {
        String extendsValue = null;
        JavaClass curJavaClass = mappingClass;

        while ((curJavaClass != null) && (extendsValue == null)) {
            extendsValue = curJavaClass.getNamedParameter("castor.class", 
"extends");
            curJavaClass = curJavaClass.getSuperJavaClass();

            if (autoExtends && (curJavaClass != null) && (extendsValue == null) 
&&
                    (curJavaClass.getTagByName("castor.class") != null)) {
                extendsValue = curJavaClass.getFullyQualifiedName();
            }
        }

        return extendsValue;
    }

    /**
     * An utility method to obtains the expected field name in mapping file. As 
we support "castor.field" in
     * methods (setters or getters) and in field, we delegate the business 
logic in dealing with it to the
     * plugin
     *
     * @param fieldOrMethod An JavaMethod or JavaField
     *
     * @return The name of the refered field
     */
    public String getName(AbstractJavaEntity fieldOrMethod) {
        String fieldName = null;

        if (fieldOrMethod instanceof JavaField) {
            fieldName = fieldOrMethod.getName();
        } else if (fieldOrMethod instanceof JavaMethod) {
            fieldName = ((JavaMethod) fieldOrMethod).getPropertyName();
        }

        return fieldName;
    }

    /**
     * Utility method called from jelly script to resolve a mergeFile reference
     *
     * @param mergeFile The mergeFile to look for
     *
     * @return A File for mergeFile
     */
    public File getMergeFile(String mergeFile) {
        if ((mergeFile != null) && (mergeDir != null) && 
mergeDir.isDirectory()) {
            // The listing of mergeDir's files avoid possibly security issues 
in path resolving (paranoid?)
            File[] files = mergeDir.listFiles();

            for (int i = 0; i < files.length; i++) {
                if (mergeFile.trim().equals(files[i].getName())) {
                    return files[i];
                }
            }
        }

        return null;
    }

    /**
     * Setter for fileName property
     *
     * @param fileName The value for the property
     *
     * @throws NullPointerException if fileName == null
     */
    public void setFilename(String fileName) {
        if (fileName == null) {
            throw new NullPointerException();
        }

        this.fileName = fileName;
    }

    /**
     * Overrides pluggin start. Used for late setting of generated file name, 
in case the user whishes to
     * change it
     */
    public void start() {
        setFilereplace(fileName);
        super.start();
    }
}
--- NEW FILE: CastorMappingXMLPlugin.jelly ---
<?xml version="1.0" encoding="UTF-8"?>
<j:jelly xmlns:j="jelly:core" xmlns:x="jelly:xml" xmlns:jsl="jelly:jsl">
        <x:doctype name="mapping" publicId="${plugin.publicId}" 
systemId="${plugin.systemId}" trim="true" />
        <x:comment>${dontedit}</x:comment>
        <mapping>
            <j:if test="${plugin.description != null}">
                <description>${plugin.description}</description>
            </j:if>
            <j:forEach var="includesFile" items="${plugin.includes}">
                <include href="${includesFile}" />
            </j:forEach>
                <j:import 
uri="org/xdoclet/plugin/castor/mappingxml/Classes.jelly" inherit="true"/>
                <!-- class-mappings.xml merge contents... START -->
                <j:if test="${plugin.getMergeFile(mappingmergefile).exists()}">
                        <x:parse var="extraMappings" 
xml="${plugin.getMergeFile(mappingmergefile)}"/>
                </j:if>
                <jsl:stylesheet select="$extraMappings">
                        <jsl:template match="*" trim="false">
                                <jsl:copy>
                                        <jsl:applyTemplates/>
                                </jsl:copy>
                        </jsl:template>
                </jsl:stylesheet>
                <!-- class-mappings.xml merge contents... END -->
        </mapping>
</j:jelly>



-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
_______________________________________________
xdoclet-plugins-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xdoclet-plugins-commits

Reply via email to