/*
* Copyright 2006 Werner Guttmann
*
* Licensed 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.exolab.castor.builder.factory;
import org.castor.xml.JavaNaming;
import org.castor.xml.JavaNamingImpl;
import org.exolab.castor.builder.BuilderConfiguration;
import org.exolab.castor.builder.info.CollectionInfo;
import org.exolab.castor.builder.info.FieldInfo;
import org.exolab.castor.builder.info.XMLInfo;
import org.exolab.castor.builder.info.NodeType;
import org.exolab.castor.builder.info.nature.XMLInfoNature;
import org.exolab.castor.builder.types.XSListType;
import org.exolab.castor.builder.types.XSClass;
import org.exolab.castor.builder.types.XSType;
import org.exolab.javasource.JClass;
import org.exolab.javasource.JSourceCode;
/**
* A factory for creating XMLFieldHandler instances as embedded in descriptors classes
* generated throughout code generation.
*
* @author <a href="mailto:werner DOT guttmann AT gmx DOT net">Werner Guttmann</a>
* @version $Revision: 6469 $ $Date: 2006-04-13 07:37:49 -0600 (Thu, 13 Apr 2006) $
*/
public final class XMLFieldHandlerFactory {
/**
* The XML code generator configuration.
*/
private BuilderConfiguration _config;
/**
* Creates an instance of this factory.
* @param config The XML code generator configuration.
*/
public XMLFieldHandlerFactory(final BuilderConfiguration config) {
_config = config;
}
/**
* Creates the XMLFieldHandler for the given FieldInfo.
*
* @param member the member for which to create an XMLFieldHandler
* @param xsType the XSType (XML Schema Type) of this field
* @param localClassName unqualified (no package) name of this class
* @param jsc the source code to which we'll add this XMLFieldHandler
* @param forGeneralizedHandler Whether to generate a generalized field
* handler
*/
public void createXMLFieldHandler(final FieldInfo member,
final XSType xsType, final String localClassName,
final JSourceCode jsc, final boolean forGeneralizedHandler) {
XMLInfoNature xmlNature = new XMLInfoNature(member);
boolean any = false;
boolean isEnumerated = false;
// -- a hack, I know, I will change later (kv)
if (member.getName().equals("_anyObject")) {
any = true;
}
if (xsType.getType() == XSType.CLASS) {
isEnumerated = ((XSClass) xsType).isEnumerated();
}
jsc.add("handler = new org.exolab.castor.xml.XMLFieldHandler() {");
jsc.indent();
createGetValueMethod(member, xsType, localClassName, jsc);
NodeType nodeType = xmlNature.getNodeType();
boolean isAttribute = (nodeType == NodeType.ATTRIBUTE);
boolean isContent = (nodeType == NodeType.TEXT);
createSetValueMethod(member, xsType, localClassName, jsc, any, isAttribute, isContent);
createResetMethod(member, localClassName, jsc);
createNewInstanceMethod(member, xsType, jsc, forGeneralizedHandler, any, isEnumerated);
jsc.unindent();
jsc.add("};");
} // --end of XMLFieldHandler
/**
* Creates the getValue() method of the corresponsing XMLFieldHandler.
*
* @param member The member element.
* @param xsType The XSType instance
* @param jsc The source code to which to append the 'getValue' method.
* @param localClassName Name of the object instance as used locally
*/
private void createGetValueMethod(final FieldInfo member, final XSType xsType,
final String localClassName, final JSourceCode jsc) {
// -- getValue(Object) method
XMLInfoNature xmlNature = new XMLInfoNature(member);
if (_config.useJava50()) {
jsc.add("@Override");
}
jsc.add("public java.lang.Object getValue( java.lang.Object object ) ");
jsc.indent();
jsc.add("throws IllegalStateException");
jsc.unindent();
jsc.add("{");
jsc.indent();
jsc.add(localClassName);
jsc.append(" target = (");
jsc.append(localClassName);
jsc.append(") object;");
// -- handle primitives
if ((!xsType.isEnumerated()) && (xsType.getJType().isPrimitive())
&& (!xmlNature.isMultivalued())) {
jsc.add("if (!target." + member.getHasMethodName() + "()) { return null; }");
}
// -- Return field value
jsc.add("return ");
String value = "target." + member.getReadMethodName() + "()";
if (xmlNature.isMultivalued()) {
jsc.append(value); // --Be careful : different for attributes
} else {
jsc.append(xsType.createToJavaObjectCode(value));
}
jsc.append(";");
jsc.unindent();
jsc.add("}");
// --end of getValue(Object) method
}
/**
* Creates the setValue() method of the corresponsing XMLFieldHandler.
*
* @param member The member element.
* @param xsType The XSType instance
* @param localClassName Name of the object instance as used locally
* @param jsc The source code to which to append the 'setValue' method.
* @param any Whether to create a setValue() method for <xs:any>
* @param isAttribute Whether to create a setValue() method for an
* attribute.
* @param isContent Whether to create a setValue() method for XML content.
*/
private void createSetValueMethod(final FieldInfo member,
final XSType xsType, final String localClassName,
final JSourceCode jsc, final boolean any, final boolean isAttribute,
final boolean isContent) {
if (_config.useJava50()) {
jsc.add("@Override");
}
jsc.add("public void setValue( java.lang.Object object, java.lang.Object value) ");
jsc.indent();
jsc.add("throws IllegalStateException, IllegalArgumentException");
jsc.unindent();
jsc.add("{");
jsc.indent();
jsc.add("try {");
jsc.indent();
jsc.add(localClassName);
jsc.append(" target = (");
jsc.append(localClassName);
jsc.append(") object;");
// -- check for null primitives
XMLInfoNature xmlNature = new XMLInfoNature(member);
if (xsType.isPrimitive() && !_config.usePrimitiveWrapper()) {
if ((!xmlNature.isRequired()) && (!xsType.isEnumerated())
&& (!xmlNature.isMultivalued())) {
jsc
.add("// if null, use delete method for optional primitives ");
jsc.add("if (value == null) {");
jsc.indent();
jsc.add("target.");
jsc.append(member.getDeleteMethodName());
jsc.append("();");
jsc.add("return;");
jsc.unindent();
jsc.add("}");
} else {
jsc.add("// ignore null values for non optional primitives");
jsc.add("if (value == null) { return; }");
jsc.add("");
}
} // if primitive
jsc.add("target.");
jsc.append(member.getWriteMethodName());
jsc.append("( ");
if (xsType.isPrimitive() && !_config.usePrimitiveWrapper()) {
jsc.append(xsType.createFromJavaObjectCode("value"));
} else if (any) {
jsc.append(" value ");
} else {
jsc.append("(");
jsc.append(xsType.getJType().toString());
// special handling for the type package
// when we are dealing with attributes
// This is a temporary solution since we need to handle
// the 'types' in specific handlers in the future
// i.e add specific FieldHandler in org.exolab.castor.xml.handlers
// dateTime is not concerned by the following since it is directly
// handle by DateFieldHandler
if ((isAttribute | isContent) && xsType.isDateTime()
&& xsType.getType() != XSType.DATETIME_TYPE) {
jsc.append(".parse");
jsc.append(_config.getJavaNaming().toJavaClassName(xsType.getName()));
jsc.append("((java.lang.String) value))");
} else {
jsc.append(") value");
}
}
jsc.append(");");
jsc.unindent();
jsc.add("} catch (java.lang.Exception ex) {");
jsc.indent();
jsc.add("throw new IllegalStateException(ex.toString());");
jsc.unindent();
jsc.add("}");
jsc.unindent();
jsc.add("}");
// --end of setValue(Object, Object) method
}
/**
* Creates the resetValue() method of the corresponsing XMLFieldHandler.
*
* @param member The member element.
* @param jsc The source code to which to append the 'resetValue' method.
* @param localClassName Name of the object instance as used locally
*/
private void createResetMethod(final FieldInfo member,
final String localClassName,
final JSourceCode jsc) {
// -- reset method (handle collections only)
if (new XMLInfoNature(member).isMultivalued()) {
CollectionInfo cInfo = (CollectionInfo) member;
// FieldInfo content = cInfo.getContent();
jsc.add("public void resetValue(Object object)"
+ " throws IllegalStateException, IllegalArgumentException {");
jsc.indent();
jsc.add("try {");
jsc.indent();
jsc.add(localClassName);
jsc.append(" target = (");
jsc.append(localClassName);
jsc.append(") object;");
String cName = _config.getJavaNaming().toJavaClassName(cInfo.getElementName());
// if (cInfo instanceof CollectionInfoJ2) {
// jsc.add("target.clear" + cName + "();");
// } else {
jsc.add("target.removeAll" + cName + "();");
// }
jsc.unindent();
jsc.add("} catch (java.lang.Exception ex) {");
jsc.indent();
jsc.add("throw new IllegalStateException(ex.toString());");
jsc.unindent();
jsc.add("}");
jsc.unindent();
jsc.add("}");
}
// -- end of reset method
}
/**
* Creates the newInstance() method of the corresponsing XMLFieldHandler.
*
* @param member The member element.
* @param xsType The XSType instance
* @param jsc The source code to which to append the 'newInstance' method.
* @param forGeneralizedHandler Whether to generate a generalized field
* handler
* @param any Whether to create a newInstance() method for <xs:any>
* @param isEnumerated Whether to create a newInstance() method for an
* enumeration.
*/
private void createNewInstanceMethod(final FieldInfo member,
final XSType xsType, final JSourceCode jsc,
final boolean forGeneralizedHandler, final boolean any,
final boolean isEnumerated) {
boolean isAbstract = false;
// Commented out according to CASTOR-1340
// if (member.getDeclaringClassInfo() != null) {
// isAbstract = member.getDeclaringClassInfo().isAbstract();
// }
// check whether class of member is declared as abstract
XMLInfoNature xmlNature = new XMLInfoNature(member);
if (xmlNature.getSchemaType() != null
&& xmlNature.getSchemaType().getJType() instanceof JClass) {
JClass jClass = (JClass) xmlNature.getSchemaType().getJType();
isAbstract = jClass.getModifiers().isAbstract();
}
if (!isAbstract && xsType.getJType() instanceof JClass) {
JClass jClass = (JClass) xsType.getJType();
isAbstract = jClass.getModifiers().isAbstract();
}
if (!isAbstract && xmlNature.getSchemaType() instanceof XSListType) {
XSListType xsList = (XSListType) xmlNature.getSchemaType();
if (xsList.getContentType().getJType() instanceof JClass) {
JClass componentType = (JClass) xsList.getContentType().getJType();
if (componentType.getModifiers().isAbstract()) {
isAbstract = componentType.getModifiers().isAbstract();
}
}
}
if (_config.useJava50()) {
jsc.add("@Override");
jsc.add("@SuppressWarnings(\"unused\")");
}
jsc.add("public java.lang.Object newInstance(java.lang.Object parent) {");
jsc.indent();
jsc.add("return ");
if (any || forGeneralizedHandler || isEnumerated
|| xsType.isPrimitive()
|| xsType.getJType().isArray()
|| (xsType.getType() == XSType.STRING_TYPE)
|| isAbstract) {
jsc.append("null;");
} else {
jsc.append(xsType.newInstanceCode());
}
jsc.unindent();
jsc.add("}");
}
}