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#3.4-The-<field>-element">3.4-The-<field>-element</a>
* <ul>Supported short names:
* <li>java.lang.Object -> other</li>
* <li>java.lang.String -> string</li>
* <li>java.math.BigDecimal -> big-decimal</li>
* <li>java.util.Date -> date</li>
* <li>java.util.Locale -> 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