r1862 - in trunk: . topia-persistence/src/main/java/org/nuiton/topia/generator
Author: fdesbois Date: 2010-03-31 10:27:58 +0200 (Wed, 31 Mar 2010) New Revision: 1862 Log: - Evo #412 : rename BusinessTransformer to ServiceTransformer + improve html javadoc - Evo #430 : use 1.2 version of i18n Added: trunk/topia-persistence/src/main/java/org/nuiton/topia/generator/ServiceTransformer.java Removed: trunk/topia-persistence/src/main/java/org/nuiton/topia/generator/BusinessTransformer.java Modified: trunk/pom.xml Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2010-03-30 20:51:55 UTC (rev 1861) +++ trunk/pom.xml 2010-03-31 08:27:58 UTC (rev 1862) @@ -190,7 +190,7 @@ <eugene.version>2.0</eugene.version> <lutinutil.version>1.2</lutinutil.version> <processor.version>1.0.3</processor.version> - <i18n.version>1.1</i18n.version> + <i18n.version>1.2</i18n.version> <xmlrpc.version>3.1.2</xmlrpc.version> <hibernate.version>3.3.2.GA</hibernate.version> Deleted: trunk/topia-persistence/src/main/java/org/nuiton/topia/generator/BusinessTransformer.java =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/generator/BusinessTransformer.java 2010-03-30 20:51:55 UTC (rev 1861) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/generator/BusinessTransformer.java 2010-03-31 08:27:58 UTC (rev 1862) @@ -1,592 +0,0 @@ - -package org.nuiton.topia.generator; - -import java.util.ArrayList; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.nuiton.eugene.GeneratorUtil; -import org.nuiton.eugene.Template; -import org.nuiton.eugene.java.ObjectModelTransformerToJava; -import org.nuiton.eugene.models.object.ObjectModel; -import org.nuiton.eugene.models.object.ObjectModelClass; -import org.nuiton.eugene.models.object.ObjectModelInterface; -import org.nuiton.eugene.models.object.ObjectModelModifier; -import org.nuiton.eugene.models.object.ObjectModelOperation; -import org.nuiton.eugene.models.object.ObjectModelParameter; -import org.nuiton.i18n.I18n; -import org.nuiton.topia.TopiaContext; -import org.nuiton.topia.TopiaException; - -/*{generator option: parentheses = false}*/ - -/*{generator option: writeString = +}*/ - -/** - * This Template is used to create the skeleton of services for a final - * application which using Topia. - * <pre> - * Generation from a model named 'App' : - * - * - AppContext : empty super interface to used in application UI. Can - * be override in model if put in defaultPackage (ex : org.chorem.app) set - * in maven-eugene-plugin configuration. - * - * - AppContextImplementor : interface which extends AppContext to add - * technical methods for the application. Generation of methods : - * * doCatch : used to catch all exception from a service method. - * * doFinally : used to finally the try/catch of a service method - * * beginTransaction : start the transaction using rootContext. - * These three methods have to be implemented in a class which implements - * AppContextImplementor (ex : AppContextImpl). You can also add others - * methods to AppContextImplementor in the same way as AppContext. - * - * - AppException : exception class which extends RuntimeException for all - * technical exceptions which appears in service method. If you want to - * manage some specific exceptions, you have to managed them in doCatch - * implementation. - * - * Generation from interfaces with stereotype <<service>> : - * - * - Service : interface of the service defined in model. - * - * - ServiceAbstract : abstract class which contains : - * * constructor with AppContextImplementor in argument - * * for each method : the implementation of the method (skeleton with - * try/catch and beginTransaction call to open a new TopiaContext from - * AppContextImplementor). Usage of i18n keys for error messages in - * exception. - * * for each method : an abstract method used to execute the business - * code of the method : need to be implemented in subclass. - * - * Exemple of AppContextImpl : - * - * public class AppContextImpl implements AppContextImplementor { - * - * // properties for Topia configuration - * protected Properties properties; - * ... - * - * @Override - * public void doCatch(TopiaContext transaction, Exception eee, - * String message, Object... args) throws AppException { - * - * // Note that the message from service doesn't directly use _() for - * // i18 messages but n_(). In this log, the _() is used to translate - * // correctly the message. But the message must be translate when - * // catching the AppException in UI. - * if (log.isErrorEnabled()) { - * log.error(_(message, args), eee); - * } - * - * // rollback of current transaction - * if (transaction != null) { - * try { - * transaction.rollbackTransaction(); - * } catch (TopiaException ex) { - * if (log.isErrorEnabled()) { - * log.error(_("app.error.context.rollback"), ex); - * } - * } - * } - * // wrapping the exception in a AppException with message and - * // arguments for i18n translation - * throw new AppException(eee, message, args); - * } - * - * @Override - * public void doFinally(TopiaContext transaction) { - * if (transaction != null) { - * try { - * transaction.closeContext(); - * } catch (TopiaException eee) { - * if (log.isErrorEnabled()) { - * log.error(_("app.error.context.close"), eee); - * } - * } - * } - * } - * - * @Override - * public TopiaContext beginTransaction() throws TopiaException { - * TopiaContext rootContext = null; - * try { - * // You have to manage the properties using ApplicationConfig - * // or other lib to have configuration for Topia - * rootContext = TopiaContextFactory.getContext(properties); - * - * return getTopiaRootContext().beginTransaction(); - * - * // only catch exception for rootContext - * } catch (TopiaNotFoundException eee) { - * doCatch(eee, n_("app.error.context.getTopiaRootContext")); - * } - * return null; - * } - * ... - * } - * - * Exemple of ServiceImpl : - * - * public class ServiceImpl extends ServiceAbstract { - * - * public ServiceImpl(AppContextImplementor context) { - * super(context); - * } - * - * // Implementation of abstract method, the interface method is - * // called 'createMyEntity(MyEntity entity)' in this case. - * @Override - * public void executeCreateMyEntity(TopiaContext transaction, - * MyEntity entity) throws TopiaException { - * - * MyEntityDAO dao = AppDAOHelper.getMyEntityDAO(transaction); - * dao.create(entity); - * // That's it, no need to manage errors or transaction, the abstract - * // service will do this job. - * } - * } - * - * TAG_TRANSACTION - * --------------- - * - * You can use the tagValue 'transaction=false' to specify that a method doesn't - * need any TopiaContext, so no need to instantiate a new one. This tagValue - * can only be put directly in the model and not in properties file (because - * of multiple methods with same name problem). - * - * TAG_ERROR_ARGS - * -------------- - * - * You can use the tagValue 'errorArgs=false' to specify that a method doesn't - * need any arguments for error message. This tagValue can only be put directly - * in the model and not in properties file. - * - * It is smooth, isn't it :p ? - * - * TODO : may be refactor to integrate JTA or webservice or may be not in this - * transformer. - * - * TODO : find a good way to change log level - * - * </pre> - * - * Created: 23 mars 2010 - * - * @author fdesbois - * @version $Revision$ - * - * Mise a jour: $Date$ - * par : $Author$ - */ -public class BusinessTransformer extends ObjectModelTransformerToJava { - - protected String modelName; - - protected String defaultPackageName; - - protected String getContextInterfaceName() { - return modelName + "Context"; - } - - protected String getContextImplementorInterfaceName() { - return getContextInterfaceName() + "Implementor"; - } - - protected String getExceptionClassName() { - return modelName + "Exception"; - } - - protected String getServiceAbstractClassName(String serviceName) { - return serviceName + "Abstract"; - } - - @Override - public void transformFromModel(ObjectModel model) { - modelName = model.getName(); - defaultPackageName = getOutputProperties(). - getProperty(Template.PROP_DEFAULT_PACKAGE); - - ObjectModelInterface contextImplementor = - model.getInterface(defaultPackageName + "." + - getContextImplementorInterfaceName()); - - ObjectModelInterface context = - model.getInterface(defaultPackageName + "." + - getContextInterfaceName()); - - ObjectModelClass exception = createExceptionClass(); - - ObjectModelInterface newContextImplementor = - this.createInterface(getContextImplementorInterfaceName(), - defaultPackageName); - ObjectModelInterface newContext = - this.createInterface(getContextInterfaceName(), - defaultPackageName); - - this.addInterface(newContextImplementor, - newContext.getQualifiedName()); - - if (contextImplementor != null) { - // Copy of defined operations - // interfaces of contextImplementor are not copied - copyInterfaceOperations(contextImplementor, newContextImplementor); - } - - if (context != null) { - // Copy of defined operations - // interfaces of context are not copied - copyInterfaceOperations(context, newContext); - } - - ObjectModelOperation beginTransaction = - this.addOperation(newContextImplementor, - "beginTransaction", TopiaContext.class); - this.addException(beginTransaction, TopiaException.class); - - ObjectModelOperation doCatch1 = - this.addOperation(newContextImplementor, "doCatch", "void"); - this.addParameter(doCatch1, Exception.class, "eee"); - this.addParameter(doCatch1, String.class, "message"); - this.addParameter(doCatch1, "Object...", "args"); - this.addException(doCatch1, exception.getQualifiedName()); - - ObjectModelOperation doCatch2 = - this.addOperation(newContextImplementor, "doCatch", "void"); - this.addParameter(doCatch2, TopiaContext.class, "transaction"); - this.addParameter(doCatch2, Exception.class, "eee"); - this.addParameter(doCatch2, String.class, "message"); - this.addParameter(doCatch2, "Object...", "args"); - this.addException(doCatch2, exception.getQualifiedName()); - - ObjectModelOperation doFinally = - this.addOperation(newContextImplementor, "doFinally", "void"); - this.addParameter(doFinally, TopiaContext.class, "transaction"); - } - - protected ObjectModelClass createExceptionClass() { - - ObjectModelClass exception = - this.createClass(getExceptionClassName(), defaultPackageName); - - this.setSuperClass(exception, RuntimeException.class); - this.addAttribute(exception, "args", "Object[]", null, - ObjectModelModifier.PROTECTED); - - ObjectModelOperation constructor = - this.addConstructor(exception, ObjectModelModifier.PUBLIC); - - this.addParameter(constructor, Throwable.class, "eee"); - this.addParameter(constructor, String.class, "message"); - this.addParameter(constructor, "Object...", "args"); - - setOperationBody(constructor, "" - /*{ - super(message, eee); - this.args = args; - }*/ - ); - - ObjectModelOperation getArgs = - this.addOperation(exception, "getArgs", "Object[]", - ObjectModelModifier.PUBLIC); - - setOperationBody(getArgs, "" - /*{ - return args; - }*/ - ); - - ObjectModelOperation hasArgs = - this.addOperation(exception, "hasArgs", "boolean", - ObjectModelModifier.PUBLIC); - - setOperationBody(hasArgs, "" - /*{ - return args.length > 0; - }*/ - ); - - return exception; - } - - /** - * Used to simply copy the {@code source} interface signature to the - * {@code dest} interface. - * - * @param source interface - * @param dest interface - */ - protected void copyInterfaceOperations(ObjectModelInterface source, - ObjectModelInterface dest) { - for (ObjectModelOperation op : source.getOperations()) { - ObjectModelOperation newOp = - this.addOperation(dest, - op.getName(), op.getReturnType()); - setDocumentation(newOp.getReturnParameter(), - op.getReturnParameter().getDocumentation()); - for (ObjectModelParameter param : op.getParameters()) { - ObjectModelParameter newParam = - this.addParameter(newOp, param.getType(), - param.getName()); - setDocumentation(newParam, param.getDocumentation()); - } - for (String ex : op.getExceptions()) { - this.addException(newOp, ex); - } - setDocumentation(newOp, op.getDocumentation()); - } - } - - @Override - public void transformFromInterface(ObjectModelInterface interfacez) { - // skip ContextImplementor and Context interfaces - if (!interfacez.hasStereotype(TopiaGeneratorUtil.STEREOTYPE_SERVICE)) { - return; - } - - // Create INTERFACE - ObjectModelInterface serviceInterface = - this.createInterface(interfacez.getName(), - interfacez.getPackageName()); - - copyInterfaceOperations(interfacez, serviceInterface); - - - // Create ABSTRACT CLASS - ObjectModelClass service = this.createAbstractClass( - getServiceAbstractClassName(interfacez.getName()), - interfacez.getPackageName()); - - this.addInterface(service, serviceInterface.getQualifiedName()); - - // Add Logger - // FIXME in EUGene, we want the default value not to be managed - // for import. -// this.addAttribute(service, "log", -// Log.class, -// "LogFactory.getLog(" + interfacez.getName() + ".class)", -// ObjectModelModifier.PRIVATE, -// ObjectModelModifier.STATIC, -// ObjectModelModifier.FINAL); - this.addAttribute(service, "log", - Log.class, null, - ObjectModelModifier.PRIVATE, - ObjectModelModifier.FINAL); - - this.addImport(service, Log.class); - this.addImport(service, LogFactory.class); - - String contextFqn = defaultPackageName + "." + - getContextImplementorInterfaceName(); - - // Add Context Attribute + constructor - this.addAttribute(service, "context", contextFqn, null, - ObjectModelModifier.PROTECTED); - - // Constructor - ObjectModelOperation constructor = - this.addConstructor(service, ObjectModelModifier.PUBLIC); - //this.addParameter(constructor, contextFqn, "context"); - setOperationBody(constructor, "" - /*{ - //this.context = context; - // FIXME : must be fixed attribute value in EUGene - this.log = LogFactory.getLog(<%=interfacez.getName()%>.class); - }*/ - ); - - ObjectModelOperation setContext = - this.addOperation(service, "setContext", "void", - ObjectModelModifier.PUBLIC); - this.addParameter(setContext, contextFqn, "context"); - setOperationBody(setContext, "" - /*{ - this.context = context; - }*/ - ); - - // Prepare operation generations - String first = modelName.substring(0, 1); - String serviceName = - GeneratorUtil.toLowerCaseFirstLetter(interfacez.getName()); - - this.addImport(service, TopiaContext.class); - this.addImport(service, I18n.class); - this.addImport(service, ArrayList.class); - - for (ObjectModelOperation op : interfacez.getOperations()) { - - // boolean to specify if the method need a transaction or not - // Default set to true but can be override by a tagvalue on the - // method - boolean needTransaction = true; - - String transactionTag = - op.getTagValue(TopiaGeneratorUtil.TAG_TRANSACTION); - - if (transactionTag != null) { - needTransaction = Boolean.parseBoolean(transactionTag); - } - - // boolean to specify if the method need error arguments or not - // Default set to true but can be override by a tagvalue on the - // method - boolean needErrorArgs = true; - - String errorArgsTag = - op.getTagValue(TopiaGeneratorUtil.TAG_ERROR_ARGS); - - if (errorArgsTag != null) { - needErrorArgs = Boolean.parseBoolean(errorArgsTag); - } - - // Implementation of interface operation - ObjectModelOperation implOp = - this.addOperation(service, - op.getName(), op.getReturnType(), - ObjectModelModifier.PUBLIC); - this.addAnnotation(service, implOp, Override.class.getSimpleName()); - - String opName = StringUtils.capitalize(op.getName()); - - // Abstract operation to execute method content - ObjectModelOperation abstOp = - this.addOperation(service, "execute" + opName, - op.getReturnType(), - ObjectModelModifier.ABSTRACT, - ObjectModelModifier.PROTECTED); - - // Throw all exception from abstract method - // They will be catched by interface method to use doCatch - this.addException(abstOp, Exception.class); - - if (needTransaction) { - this.addParameter(abstOp, TopiaContext.class, "transaction"); - this.addException(abstOp, TopiaException.class); - } - - String toStringAppend = ""; - String separatorLog = " : "; - // Prepare operation parameters - String opParams = ""; - String separatorParams = ""; - if (needErrorArgs) { - opParams += "errorArgs"; - separatorParams = ", "; - // Add errorArgs to abstract operation - this.addParameter(abstOp, - "java.util.List<Object>", "errorArgs"); - } - - // Copy other operation parameters - for (ObjectModelParameter param : op.getParameters()) { - String paramName = param.getName(); - this.addParameter(implOp, param.getType(), param.getName()); - this.addParameter(abstOp, param.getType(), param.getName()); - - // Prepare Log - toStringAppend += - "\n\t\t\t.append(\"" + separatorLog + paramName + " = \")" + - ".append(" + paramName + ")"; - separatorLog = " _ "; - - // Prepare Abstract method params - opParams += separatorParams + param.getName(); - separatorParams = ", "; - } - - // Use buffer for operation body - StringBuilder buffer = new StringBuilder(); - - // Error key for i18n - String errorKey = StringUtils.lowerCase(modelName) + ".error." + - serviceName + "." + op.getName(); - - String doCatchParams = "eee, I18n.n_(\"" + errorKey + "\")"; - doCatchParams += needErrorArgs ? ", errorArgs.toArray()" : ""; - - // Return managment - String opReturn = ""; - String finalReturn = ""; - if (!op.getReturnType().equals("void")) { - opReturn = "return "; - finalReturn = "return null;"; - } - - if (needErrorArgs) { - // Init errorArgs - buffer.append("" - /*{ - List<Object> errorArgs = new ArrayList<Object>(); - }*/ ); - } - - if (needTransaction) { - // Open the transaction - buffer.append("" - /*{ - TopiaContext transaction = null; - try { - transaction = context.beginTransaction(); - }*/ - ); - // Add transaction in the execute operation parameters - // and doCatch parameters - opParams = "transaction, " + opParams; - doCatchParams = "transaction, " + doCatchParams; - } else { - buffer.append("" - /*{ - try { - }*/ - ); - } - - buffer.append("" - /*{ - if (log.isDebugEnabled()) { - String message = new StringBuilder("<%=first%>:[ <%=opName%> ]")<%=toStringAppend%>. - toString(); - log.debug(message); - } - - <%=opReturn%>execute<%=opName%>(<%=opParams%>); }*/); - - // Copy exceptions - for (String ex : op.getExceptions()) { - this.addException(implOp, ex); - this.addException(abstOp, ex); - // Add catch block for known exceptions we want to throw - String exName = GeneratorUtil.getSimpleName(ex); - buffer.append("" - /*{ - } catch (<%=exName%> eee) { - throw eee; }*/); - } - - buffer.append("" - /*{ - } catch (Exception eee) { - context.doCatch(<%=doCatchParams%>); }*/); - - if (needTransaction) { - // Finally block to close transaction - buffer.append("" - /*{ - } finally { - context.doFinally(transaction); }*/); - } - - buffer.append("" - /*{ - } - <%=finalReturn%> - }*/ - ); - - this.setOperationBody(implOp, buffer.toString()); - } - - } -} Copied: trunk/topia-persistence/src/main/java/org/nuiton/topia/generator/ServiceTransformer.java (from rev 1860, trunk/topia-persistence/src/main/java/org/nuiton/topia/generator/BusinessTransformer.java) =================================================================== --- trunk/topia-persistence/src/main/java/org/nuiton/topia/generator/ServiceTransformer.java (rev 0) +++ trunk/topia-persistence/src/main/java/org/nuiton/topia/generator/ServiceTransformer.java 2010-03-31 08:27:58 UTC (rev 1862) @@ -0,0 +1,594 @@ + +package org.nuiton.topia.generator; + +import java.util.ArrayList; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.eugene.GeneratorUtil; +import org.nuiton.eugene.Template; +import org.nuiton.eugene.java.ObjectModelTransformerToJava; +import org.nuiton.eugene.models.object.ObjectModel; +import org.nuiton.eugene.models.object.ObjectModelClass; +import org.nuiton.eugene.models.object.ObjectModelInterface; +import org.nuiton.eugene.models.object.ObjectModelModifier; +import org.nuiton.eugene.models.object.ObjectModelOperation; +import org.nuiton.eugene.models.object.ObjectModelParameter; +import org.nuiton.i18n.I18n; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.TopiaException; + +/*{generator option: parentheses = false}*/ + +/*{generator option: writeString = +}*/ + +/** + * This Template is used to create the skeleton of services for a final + * application which using Topia. + * <div> + * Generation from a model named 'App' : + * <ul> + * <li>AppContext : empty super interface to used in application UI. Can + * be override in model if put in defaultPackage (ex : org.chorem.app) set + * in maven-eugene-plugin configuration. + * </li> + * <li><p>AppContextImplementor : interface which extends AppContext to add + * technical methods for the application. Generation of methods :</p> + * <p>* doCatch : used to catch all exception from a service method.</p> + * <p>* doFinally : used to finally the try/catch of a service method</p> + * <p>* beginTransaction : start the transaction using rootContext.</p> + * <p>These three methods have to be implemented in a class which implements + * AppContextImplementor (ex : AppContextImpl). You can also add others + * methods to AppContextImplementor in the same way as AppContext.</p> + * </li> + * <li>AppException : exception class which extends RuntimeException for all + * technical exceptions which appears in service method. If you want to + * manage some specific exceptions, you have to managed them in doCatch + * implementation. + * </li> + * </ul> + * </div> + * <div> + * Generation from interfaces with stereotype <<service>> : + * <ul> + * <li>Service : interface of the service defined in model.</li> + * <li><p>ServiceAbstract : abstract class which contains :</p> + * <p>* constructor with AppContextImplementor in argument</p> + * <p>* for each method : the implementation of the method (skeleton with + * try/catch and beginTransaction call to open a new TopiaContext from + * AppContextImplementor). Usage of i18n keys for error messages in + * exception.</p> + * <p>* for each method : an abstract method used to execute the business + * code of the method : need to be implemented in subclass.</p> + * </li> + * </ul> + * </div> + * <div> + * Exemple of AppContextImpl :<br /> + * <pre> + * public class AppContextImpl implements AppContextImplementor { + * + * // properties for Topia configuration + * protected Properties properties; + * ... + * + * @Override + * public void doCatch(TopiaContext transaction, Exception eee, + * String message, Object... args) throws AppException { + * + * // Note that the message from service doesn't directly use _() for + * // i18 messages but n_(). In this log, the _() is used to translate + * // correctly the message. But the message must be translate when + * // catching the AppException in UI. + * if (log.isErrorEnabled()) { + * log.error(_(message, args), eee); + * } + * + * // rollback of current transaction + * if (transaction != null) { + * try { + * transaction.rollbackTransaction(); + * } catch (TopiaException ex) { + * if (log.isErrorEnabled()) { + * log.error(_("app.error.context.rollback"), ex); + * } + * } + * } + * // wrapping the exception in a AppException with message and + * // arguments for i18n translation + * throw new AppException(eee, message, args); + * } + * + * @Override + * public void doFinally(TopiaContext transaction) { + * if (transaction != null) { + * try { + * transaction.closeContext(); + * } catch (TopiaException eee) { + * if (log.isErrorEnabled()) { + * log.error(_("app.error.context.close"), eee); + * } + * } + * } + * } + * + * @Override + * public TopiaContext beginTransaction() throws TopiaException { + * TopiaContext rootContext = null; + * try { + * // You have to manage the properties using ApplicationConfig + * // or other lib to have configuration for Topia + * rootContext = TopiaContextFactory.getContext(properties); + * + * return getTopiaRootContext().beginTransaction(); + * + * // only catch exception for rootContext + * } catch (TopiaNotFoundException eee) { + * doCatch(eee, n_("app.error.context.getTopiaRootContext")); + * } + * return null; + * } + * ... + * } + * </pre> + * </div> + * <div> + * Exemple of ServiceImpl :<br /> + * <pre> + * public class ServiceImpl extends ServiceAbstract { + * + * public ServiceImpl(AppContextImplementor context) { + * super(context); + * } + * + * // Implementation of abstract method, the interface method is + * // called 'createMyEntity(MyEntity entity)' in this case. + * @Override + * public void executeCreateMyEntity(TopiaContext transaction, + * MyEntity entity) throws TopiaException { + * + * MyEntityDAO dao = AppDAOHelper.getMyEntityDAO(transaction); + * dao.create(entity); + * // That's it, no need to manage errors or transaction, the abstract + * // service will do this job. + * } + * } + * </pre> + * <div> + * <h2>TAG_TRANSACTION</h2> + * <p>You can use the tagValue 'transaction=false' to specify that a method + * doesn't need any TopiaContext, so no need to instantiate a new one. + * This tagValue can only be put directly in the model and not in properties + * file (because of multiple methods with same name problem).</p> + * </div> + * <div> + * <h2>TAG_ERROR_ARGS</h2> + * <p>You can use the tagValue 'errorArgs=false' to specify that a method doesn't + * need any arguments for error message. This tagValue can only be put directly + * in the model and not in properties file.</p> + * </div> + * <p>It is smooth, isn't it :p ?</p> + * <p>TODO : may be refactor to integrate JTA or webservice or may be not in this + * transformer.</p> + * <p>TODO : find a good way to change log level</p> + * + * Created: 23 mars 2010 + * + * @author fdesbois + * @version $Revision$ + * + * Mise a jour: $Date$ + * par : $Author$ + */ +public class ServiceTransformer extends ObjectModelTransformerToJava { + + protected String modelName; + + protected String defaultPackageName; + + protected String getContextInterfaceName() { + return modelName + "Context"; + } + + protected String getContextImplementorInterfaceName() { + return getContextInterfaceName() + "Implementor"; + } + + protected String getExceptionClassName() { + return modelName + "Exception"; + } + + protected String getServiceAbstractClassName(String serviceName) { + return serviceName + "Abstract"; + } + + @Override + public void transformFromModel(ObjectModel model) { + modelName = model.getName(); + defaultPackageName = getOutputProperties(). + getProperty(Template.PROP_DEFAULT_PACKAGE); + + ObjectModelInterface contextImplementor = + model.getInterface(defaultPackageName + "." + + getContextImplementorInterfaceName()); + + ObjectModelInterface context = + model.getInterface(defaultPackageName + "." + + getContextInterfaceName()); + + ObjectModelClass exception = createExceptionClass(); + + ObjectModelInterface newContextImplementor = + this.createInterface(getContextImplementorInterfaceName(), + defaultPackageName); + ObjectModelInterface newContext = + this.createInterface(getContextInterfaceName(), + defaultPackageName); + + this.addInterface(newContextImplementor, + newContext.getQualifiedName()); + + if (contextImplementor != null) { + // Copy of defined operations + // interfaces of contextImplementor are not copied + copyInterfaceOperations(contextImplementor, newContextImplementor); + } + + if (context != null) { + // Copy of defined operations + // interfaces of context are not copied + copyInterfaceOperations(context, newContext); + } + + ObjectModelOperation beginTransaction = + this.addOperation(newContextImplementor, + "beginTransaction", TopiaContext.class); + this.addException(beginTransaction, TopiaException.class); + + ObjectModelOperation doCatch1 = + this.addOperation(newContextImplementor, "doCatch", "void"); + this.addParameter(doCatch1, Exception.class, "eee"); + this.addParameter(doCatch1, String.class, "message"); + this.addParameter(doCatch1, "Object...", "args"); + this.addException(doCatch1, exception.getQualifiedName()); + + ObjectModelOperation doCatch2 = + this.addOperation(newContextImplementor, "doCatch", "void"); + this.addParameter(doCatch2, TopiaContext.class, "transaction"); + this.addParameter(doCatch2, Exception.class, "eee"); + this.addParameter(doCatch2, String.class, "message"); + this.addParameter(doCatch2, "Object...", "args"); + this.addException(doCatch2, exception.getQualifiedName()); + + ObjectModelOperation doFinally = + this.addOperation(newContextImplementor, "doFinally", "void"); + this.addParameter(doFinally, TopiaContext.class, "transaction"); + } + + protected ObjectModelClass createExceptionClass() { + + ObjectModelClass exception = + this.createClass(getExceptionClassName(), defaultPackageName); + + this.setSuperClass(exception, RuntimeException.class); + this.addAttribute(exception, "args", "Object[]", null, + ObjectModelModifier.PROTECTED); + + ObjectModelOperation constructor = + this.addConstructor(exception, ObjectModelModifier.PUBLIC); + + this.addParameter(constructor, Throwable.class, "eee"); + this.addParameter(constructor, String.class, "message"); + this.addParameter(constructor, "Object...", "args"); + + setOperationBody(constructor, "" + /*{ + super(message, eee); + this.args = args; + }*/ + ); + + ObjectModelOperation getArgs = + this.addOperation(exception, "getArgs", "Object[]", + ObjectModelModifier.PUBLIC); + + setOperationBody(getArgs, "" + /*{ + return args; + }*/ + ); + + ObjectModelOperation hasArgs = + this.addOperation(exception, "hasArgs", "boolean", + ObjectModelModifier.PUBLIC); + + setOperationBody(hasArgs, "" + /*{ + return args.length > 0; + }*/ + ); + + return exception; + } + + /** + * Used to simply copy the {@code source} interface signature to the + * {@code dest} interface. + * + * @param source interface + * @param dest interface + */ + protected void copyInterfaceOperations(ObjectModelInterface source, + ObjectModelInterface dest) { + setDocumentation(dest, source.getDocumentation()); + for (ObjectModelOperation op : source.getOperations()) { + ObjectModelOperation newOp = + this.addOperation(dest, + op.getName(), op.getReturnType()); + setDocumentation(newOp.getReturnParameter(), + op.getReturnParameter().getDocumentation()); + for (ObjectModelParameter param : op.getParameters()) { + ObjectModelParameter newParam = + this.addParameter(newOp, param.getType(), + param.getName()); + setDocumentation(newParam, param.getDocumentation()); + } + for (String ex : op.getExceptions()) { + this.addException(newOp, ex); + } + setDocumentation(newOp, op.getDocumentation()); + } + } + + @Override + public void transformFromInterface(ObjectModelInterface interfacez) { + // skip ContextImplementor and Context interfaces + if (!interfacez.hasStereotype(TopiaGeneratorUtil.STEREOTYPE_SERVICE)) { + return; + } + + // Create INTERFACE + ObjectModelInterface serviceInterface = + this.createInterface(interfacez.getName(), + interfacez.getPackageName()); + + copyInterfaceOperations(interfacez, serviceInterface); + + + // Create ABSTRACT CLASS + ObjectModelClass service = this.createAbstractClass( + getServiceAbstractClassName(interfacez.getName()), + interfacez.getPackageName()); + + this.addInterface(service, serviceInterface.getQualifiedName()); + + // Add Logger + // FIXME in EUGene, we want the default value not to be managed + // for import. +// this.addAttribute(service, "log", +// Log.class, +// "LogFactory.getLog(" + interfacez.getName() + ".class)", +// ObjectModelModifier.PRIVATE, +// ObjectModelModifier.STATIC, +// ObjectModelModifier.FINAL); + this.addAttribute(service, "log", + Log.class, null, + ObjectModelModifier.PRIVATE, + ObjectModelModifier.FINAL); + + this.addImport(service, Log.class); + this.addImport(service, LogFactory.class); + + String contextFqn = defaultPackageName + "." + + getContextImplementorInterfaceName(); + + // Add Context Attribute + constructor + this.addAttribute(service, "context", contextFqn, null, + ObjectModelModifier.PROTECTED); + + // Constructor + ObjectModelOperation constructor = + this.addConstructor(service, ObjectModelModifier.PUBLIC); + //this.addParameter(constructor, contextFqn, "context"); + setOperationBody(constructor, "" + /*{ + //this.context = context; + // FIXME : must be fixed attribute value in EUGene + this.log = LogFactory.getLog(<%=interfacez.getName()%>.class); + }*/ + ); + + ObjectModelOperation setContext = + this.addOperation(service, "setContext", "void", + ObjectModelModifier.PUBLIC); + this.addParameter(setContext, contextFqn, "context"); + setOperationBody(setContext, "" + /*{ + this.context = context; + }*/ + ); + + // Prepare operation generations + String first = modelName.substring(0, 1); + String serviceName = + GeneratorUtil.toLowerCaseFirstLetter(interfacez.getName()); + + this.addImport(service, TopiaContext.class); + this.addImport(service, I18n.class); + this.addImport(service, ArrayList.class); + + for (ObjectModelOperation op : interfacez.getOperations()) { + + // boolean to specify if the method need a transaction or not + // Default set to true but can be override by a tagvalue on the + // method + boolean needTransaction = true; + + String transactionTag = + op.getTagValue(TopiaGeneratorUtil.TAG_TRANSACTION); + + if (transactionTag != null) { + needTransaction = Boolean.parseBoolean(transactionTag); + } + + // boolean to specify if the method need error arguments or not + // Default set to true but can be override by a tagvalue on the + // method + boolean needErrorArgs = true; + + String errorArgsTag = + op.getTagValue(TopiaGeneratorUtil.TAG_ERROR_ARGS); + + if (errorArgsTag != null) { + needErrorArgs = Boolean.parseBoolean(errorArgsTag); + } + + // Implementation of interface operation + ObjectModelOperation implOp = + this.addOperation(service, + op.getName(), op.getReturnType(), + ObjectModelModifier.PUBLIC); + this.addAnnotation(service, implOp, Override.class.getSimpleName()); + + String opName = StringUtils.capitalize(op.getName()); + + // Abstract operation to execute method content + ObjectModelOperation abstOp = + this.addOperation(service, "execute" + opName, + op.getReturnType(), + ObjectModelModifier.ABSTRACT, + ObjectModelModifier.PROTECTED); + + // Throw all exception from abstract method + // They will be catched by interface method to use doCatch + this.addException(abstOp, Exception.class); + + if (needTransaction) { + this.addParameter(abstOp, TopiaContext.class, "transaction"); + this.addException(abstOp, TopiaException.class); + } + + String toStringAppend = ""; + String separatorLog = " : "; + // Prepare operation parameters + String opParams = ""; + String separatorParams = ""; + if (needErrorArgs) { + opParams += "errorArgs"; + separatorParams = ", "; + // Add errorArgs to abstract operation + this.addParameter(abstOp, + "java.util.List<Object>", "errorArgs"); + } + + // Copy other operation parameters + for (ObjectModelParameter param : op.getParameters()) { + String paramName = param.getName(); + this.addParameter(implOp, param.getType(), param.getName()); + this.addParameter(abstOp, param.getType(), param.getName()); + + // Prepare Log + toStringAppend += + "\n\t\t\t.append(\"" + separatorLog + paramName + " = \")" + + ".append(" + paramName + ")"; + separatorLog = " _ "; + + // Prepare Abstract method params + opParams += separatorParams + param.getName(); + separatorParams = ", "; + } + + // Use buffer for operation body + StringBuilder buffer = new StringBuilder(); + + // Error key for i18n + String errorKey = StringUtils.lowerCase(modelName) + ".error." + + serviceName + "." + op.getName(); + + String doCatchParams = "eee, I18n.n_(\"" + errorKey + "\")"; + doCatchParams += needErrorArgs ? ", errorArgs.toArray()" : ""; + + // Return managment + String opReturn = ""; + String finalReturn = ""; + if (!op.getReturnType().equals("void")) { + opReturn = "return "; + finalReturn = "return null;"; + } + + if (needErrorArgs) { + // Init errorArgs + buffer.append("" + /*{ + List<Object> errorArgs = new ArrayList<Object>(); + }*/ ); + } + + if (needTransaction) { + // Open the transaction + buffer.append("" + /*{ + TopiaContext transaction = null; + try { + transaction = context.beginTransaction(); + }*/ + ); + // Add transaction in the execute operation parameters + // and doCatch parameters + opParams = "transaction, " + opParams; + doCatchParams = "transaction, " + doCatchParams; + } else { + buffer.append("" + /*{ + try { + }*/ + ); + } + + buffer.append("" + /*{ + if (log.isDebugEnabled()) { + String message = new StringBuilder("<%=first%>:[ <%=opName%> ]")<%=toStringAppend%>. + toString(); + log.debug(message); + } + + <%=opReturn%>execute<%=opName%>(<%=opParams%>); }*/); + + // Copy exceptions + for (String ex : op.getExceptions()) { + this.addException(implOp, ex); + this.addException(abstOp, ex); + // Add catch block for known exceptions we want to throw + String exName = GeneratorUtil.getSimpleName(ex); + buffer.append("" + /*{ + } catch (<%=exName%> eee) { + throw eee; }*/); + } + + buffer.append("" + /*{ + } catch (Exception eee) { + context.doCatch(<%=doCatchParams%>); }*/); + + if (needTransaction) { + // Finally block to close transaction + buffer.append("" + /*{ + } finally { + context.doFinally(transaction); }*/); + } + + buffer.append("" + /*{ + } + <%=finalReturn%> + }*/ + ); + + this.setOperationBody(implOp, buffer.toString()); + } + + } +} Property changes on: trunk/topia-persistence/src/main/java/org/nuiton/topia/generator/ServiceTransformer.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL" Added: svn:mergeinfo +
participants (1)
-
fdesbois@users.nuiton.org