McCodeGen.java

/*
 *  IronJacamar, a Java EE Connector Architecture implementation
 *  Copyright 2016, Red Hat Inc, and individual contributors
 *  as indicated by the @author tags. See the copyright.txt file in the
 *  distribution for a full listing of individual contributors.
 *
 *  This is free software; you can redistribute it and/or modify it
 *  under the terms of the Eclipse Public License 1.0 as
 *  published by the Free Software Foundation.
 *
 *  This software is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse
 *  Public License for more details.
 *
 *  You should have received a copy of the Eclipse Public License
 *  along with this software; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 *  02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.ironjacamar.codegenerator.code;

import org.ironjacamar.codegenerator.BasicType;
import org.ironjacamar.codegenerator.Definition;
import org.ironjacamar.codegenerator.MethodForConnection;

import java.io.IOException;
import java.io.Writer;

/**
 * A managed connection CodeGen.
 *
 * @author Jeff Zhang
 * @version $Revision: $
 */
public class McCodeGen extends AbstractCodeGen
{

   /**
    * Output class
    *
    * @param def definition
    * @param out Writer
    * @throws IOException ioException
    */
   @Override
   public void writeClassBody(Definition def, Writer out) throws IOException
   {
      int indent = 1;
      out.write("public class " + getClassName(def) + " implements ManagedConnection");
      writeLeftCurlyBracket(out, 0);
      writeEol(out);

      writeWithIndent(out, indent, "/** The logger */\n");
      writeWithIndent(out, indent, "private static Logger log = Logger.getLogger(" + getSelfClassName(def) + ");\n\n");

      writeWithIndent(out, indent, "/** The logwriter */\n");
      writeWithIndent(out, indent, "private PrintWriter logwriter;\n\n");

      writeWithIndent(out, indent, "/** ManagedConnectionFactory */\n");
      writeWithIndent(out, indent, "private " + def.getMcfDefs().get(getNumOfMcf()).getMcfClass() + " mcf;\n\n");

      writeWithIndent(out, indent, "/** Listeners */\n");
      writeWithIndent(out, indent, "private List<ConnectionEventListener> listeners;\n\n");

      writeWithIndent(out, indent, "/** Connections */\n");
      if (def.getMcfDefs().get(getNumOfMcf()).isUseCciConnection())
         writeWithIndent(out, indent,
               "private Set<" + def.getMcfDefs().get(getNumOfMcf()).getCciConnClass() + "> connections;\n\n");
      else
         writeWithIndent(out, indent,
               "private Set<" + def.getMcfDefs().get(getNumOfMcf()).getConnImplClass() + "> connections;\n\n");

      if (def.isSupportEis())
      {
         writeWithIndent(out, indent, "/** Socket */\n");
         writeWithIndent(out, indent, "private Socket socket;\n\n");
      }

      //constructor
      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent, " * Default constructor\n");
      writeWithIndent(out, indent, " * @param mcf mcf\n");
      writeWithIndent(out, indent, " */\n");

      writeWithIndent(out, indent,
            "public " + getClassName(def) + "(" + def.getMcfDefs().get(getNumOfMcf()).getMcfClass() + " mcf)");
      if (def.isSupportEis())
      {
         out.write(" throws ResourceException");
      }
      writeLeftCurlyBracket(out, indent);
      writeWithIndent(out, indent + 1, "this.mcf = mcf;\n");
      writeWithIndent(out, indent + 1, "this.logwriter = null;\n");
      writeWithIndent(out, indent + 1,
            "this.listeners = Collections.synchronizedList(new ArrayList<ConnectionEventListener>(1));\n");
      if (def.getMcfDefs().get(getNumOfMcf()).isUseCciConnection())
         writeWithIndent(out, indent + 1,
               "this.connections = new HashSet<" + def.getMcfDefs().get(getNumOfMcf()).getCciConnClass() + ">();");
      else
         writeWithIndent(out, indent + 1,
               "this.connections = new HashSet<" + def.getMcfDefs().get(getNumOfMcf()).getConnImplClass() + ">();");

      if (def.isSupportEis())
      {
         writeEol(out);
         writeWithIndent(out, indent + 1, "this.socket = null; // TODO: Initialize me");
      }

      writeRightCurlyBracket(out, indent);
      writeEol(out);

      writeConnection(def, out, indent);
      writeLifecycle(def, out, indent);
      writeConnectionEventListener(def, out, indent);
      writeLogWriter(def, out, indent);
      writeTransaction(def, out, indent);
      writeMetaData(def, out, indent);
      writeMethod(def, out, indent);

      writeRightCurlyBracket(out, 0);
   }

   /**
    * Output class import
    *
    * @param def definition
    * @param out Writer
    * @throws IOException ioException
    */
   @Override
   public void writeImport(Definition def, Writer out) throws IOException
   {
      out.write("package " + def.getRaPackage() + ";\n\n");

      if (def.isSupportEis())
      {
         out.write("import java.io.IOException;\n");
      }
      out.write("import java.io.PrintWriter;\n");

      if (def.isSupportEis())
      {
         out.write("import java.net.Socket;\n");
      }

      out.write("import java.util.ArrayList;\n");
      out.write("import java.util.Collections;\n");
      out.write("import java.util.HashSet;\n");
      out.write("import java.util.List;\n");
      out.write("import java.util.Set;\n");
      importLogging(def, out);
      out.write("import javax.resource.NotSupportedException;\n");
      out.write("import javax.resource.ResourceException;\n");
      out.write("import javax.resource.spi.ConnectionEvent;\n");
      out.write("import javax.resource.spi.ConnectionEventListener;\n");
      out.write("import javax.resource.spi.ConnectionRequestInfo;\n");
      out.write("import javax.resource.spi.LocalTransaction;\n");
      out.write("import javax.resource.spi.ManagedConnection;\n");
      out.write("import javax.resource.spi.ManagedConnectionMetaData;\n\n");
      out.write("import javax.security.auth.Subject;\n");
      out.write("import javax.transaction.xa.XAResource;\n\n");
   }

   /**
    * get this class name
    *
    * @param def definition
    * @return String class name
    */
   @Override
   public String getClassName(Definition def)
   {
      return def.getMcfDefs().get(getNumOfMcf()).getMcClass();
   }

   /**
    * Output Connection method
    *
    * @param def    definition
    * @param out    Writer
    * @param indent space number
    * @throws IOException ioException
    */
   private void writeConnection(Definition def, Writer out, int indent) throws IOException
   {
      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent, " * Creates a new connection handle for the underlying physical connection \n");
      writeWithIndent(out, indent, " * represented by the ManagedConnection instance. \n");
      writeWithIndent(out, indent, " *\n");
      writeWithIndent(out, indent, " * @param subject Security context as JAAS subject\n");
      writeWithIndent(out, indent, " * @param cxRequestInfo ConnectionRequestInfo instance\n");
      writeWithIndent(out, indent, " * @return generic Object instance representing the connection handle. \n");
      writeWithIndent(out, indent, " * @throws ResourceException generic exception if operation fails\n");
      writeWithIndent(out, indent, " */\n");

      writeWithIndent(out, indent, "public Object getConnection(Subject subject,\n");
      writeWithIndent(out, indent + 1, "ConnectionRequestInfo cxRequestInfo) throws ResourceException");
      writeLeftCurlyBracket(out, indent);
      writeLogging(def, out, indent + 1, "trace", "getConnection");
      writeIndent(out, indent + 1);
      if (def.getMcfDefs().get(getNumOfMcf()).isUseCciConnection())
         out.write(def.getMcfDefs().get(getNumOfMcf()).getCciConnClass() + " connection = new " +
               def.getMcfDefs().get(getNumOfMcf()).getCciConnClass() + "();\n");
      else
         out.write(def.getMcfDefs().get(getNumOfMcf()).getConnImplClass() + " connection = new " +
               def.getMcfDefs().get(getNumOfMcf()).getConnImplClass() + "(this, mcf);\n");
      writeWithIndent(out, indent + 1, "connections.add(connection);\n");
      writeWithIndent(out, indent + 1, "return connection;");
      writeRightCurlyBracket(out, indent);
      writeEol(out);

      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent, " * Used by the container to change the association of an \n");
      writeWithIndent(out, indent, " * application-level connection handle with a ManagedConneciton instance.\n");
      writeWithIndent(out, indent, " *\n");
      writeWithIndent(out, indent, " * @param connection Application-level connection handle\n");
      writeWithIndent(out, indent, " * @throws ResourceException generic exception if operation fails\n");
      writeWithIndent(out, indent, " */\n");

      writeWithIndent(out, indent, "public void associateConnection(Object connection) throws ResourceException");
      writeLeftCurlyBracket(out, indent);
      writeLogging(def, out, indent + 1, "trace", "associateConnection", "connection\n");
      writeWithIndent(out, indent + 1, "if (connection == null)\n");
      writeWithIndent(out, indent + 2, "throw new ResourceException(\"Null connection handle\");\n\n");
      writeWithIndent(out, indent + 1, "if (!(connection instanceof ");
      if (def.getMcfDefs().get(getNumOfMcf()).isUseCciConnection())
         out.write(def.getMcfDefs().get(getNumOfMcf()).getCciConnClass());
      else
         out.write(def.getMcfDefs().get(getNumOfMcf()).getConnImplClass());
      out.write("))\n");
      writeWithIndent(out, indent + 2, "throw new ResourceException(\"Wrong connection handle\");\n\n");
      if (def.getMcfDefs().get(getNumOfMcf()).isUseCciConnection())
         writeWithIndent(out, indent + 1, def.getMcfDefs().get(getNumOfMcf()).getCciConnClass());
      else
         writeWithIndent(out, indent + 1, def.getMcfDefs().get(getNumOfMcf()).getConnImplClass());
      out.write(" handle = (");
      if (def.getMcfDefs().get(getNumOfMcf()).isUseCciConnection())
         out.write(def.getMcfDefs().get(getNumOfMcf()).getCciConnClass());
      else
         out.write(def.getMcfDefs().get(getNumOfMcf()).getConnImplClass());
      out.write(")connection;\n");
      writeWithIndent(out, indent + 1, "handle.setManagedConnection(this);\n");
      writeWithIndent(out, indent + 1, "connections.add(handle);");
      writeRightCurlyBracket(out, indent);
      writeEol(out);
   }

   /**
    * Output Lifecycle method
    *
    * @param def    definition
    * @param out    Writer
    * @param indent space number
    * @throws IOException ioException
    */
   private void writeLifecycle(Definition def, Writer out, int indent) throws IOException
   {
      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent,
            " * Application server calls this method to force any cleanup on the ManagedConnection instance.\n");
      writeWithIndent(out, indent, " *\n");
      writeWithIndent(out, indent, " * @throws ResourceException generic exception if operation fails\n");
      writeWithIndent(out, indent, " */\n");

      writeWithIndent(out, indent, "public void cleanup() throws ResourceException");
      writeLeftCurlyBracket(out, indent);
      writeLogging(def, out, indent + 1, "trace", "cleanup");
      writeWithIndent(out, indent + 1, "for (");
      if (def.getMcfDefs().get(getNumOfMcf()).isUseCciConnection())
         out.write(def.getMcfDefs().get(getNumOfMcf()).getCciConnClass());
      else
         out.write(def.getMcfDefs().get(getNumOfMcf()).getConnImplClass());
      out.write(" connection : connections)");
      writeLeftCurlyBracket(out, indent + 1);
      writeWithIndent(out, indent + 2, "connection.setManagedConnection(null);");
      writeRightCurlyBracket(out, indent + 1);
      writeWithIndent(out, indent + 1, "connections.clear();\n");
      writeRightCurlyBracket(out, indent);
      writeEol(out);

      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent, " * Destroys the physical connection to the underlying resource manager.\n");
      writeWithIndent(out, indent, " *\n");
      writeWithIndent(out, indent, " * @throws ResourceException generic exception if operation fails\n");
      writeWithIndent(out, indent, " */\n");

      writeWithIndent(out, indent, "public void destroy() throws ResourceException");
      writeLeftCurlyBracket(out, indent);
      writeLogging(def, out, indent + 1, "trace", "destroy");

      if (def.isSupportEis())
      {
         writeEol(out);
         writeWithIndent(out, indent + 1, "if (socket != null)");
         writeLeftCurlyBracket(out, indent + 1);

         writeWithIndent(out, indent + 2, "try");
         writeLeftCurlyBracket(out, indent + 2);
         writeWithIndent(out, indent + 3, "socket.close();");
         writeRightCurlyBracket(out, indent + 2);
         writeWithIndent(out, indent + 2, "catch (IOException ioe)");
         writeLeftCurlyBracket(out, indent + 2);
         writeWithIndent(out, indent + 3, "// Ignore");
         writeRightCurlyBracket(out, indent + 2);
         writeRightCurlyBracket(out, indent + 1);
      }

      writeRightCurlyBracket(out, indent);
      writeEol(out);
   }

   /**
    * Output ConnectionEventListener method
    *
    * @param def    definition
    * @param out    Writer
    * @param indent space number
    * @throws IOException ioException
    */
   private void writeConnectionEventListener(Definition def, Writer out, int indent) throws IOException
   {
      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent, " * Adds a connection event listener to the ManagedConnection instance.\n");
      writeWithIndent(out, indent, " *\n");
      writeWithIndent(out, indent, " * @param listener A new ConnectionEventListener to be registered\n");
      writeWithIndent(out, indent, " */\n");

      writeWithIndent(out, indent, "public void addConnectionEventListener(ConnectionEventListener listener)");
      writeLeftCurlyBracket(out, indent);
      writeLogging(def, out, indent + 1, "trace", "addConnectionEventListener", "listener");
      writeWithIndent(out, indent + 1, "if (listener == null)\n");
      writeWithIndent(out, indent + 2, "throw new IllegalArgumentException(\"Listener is null\");\n");
      writeWithIndent(out, indent + 1, "listeners.add(listener);");
      writeRightCurlyBracket(out, indent);
      writeEol(out);

      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent,
            " * Removes an already registered connection event listener from the ManagedConnection instance.\n");
      writeWithIndent(out, indent, " *\n");
      writeWithIndent(out, indent, " * @param listener already registered connection event listener to be removed\n");
      writeWithIndent(out, indent, " */\n");

      writeWithIndent(out, indent, "public void removeConnectionEventListener(ConnectionEventListener listener)");
      writeLeftCurlyBracket(out, indent);
      writeLogging(def, out, indent + 1, "trace", "removeConnectionEventListener", "listener");
      writeWithIndent(out, indent + 1, "if (listener == null)\n");
      writeWithIndent(out, indent + 2, "throw new IllegalArgumentException(\"Listener is null\");\n");
      writeWithIndent(out, indent + 1, "listeners.remove(listener);");
      writeRightCurlyBracket(out, indent);
      writeEol(out);

      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent, " * Close handle\n");
      writeWithIndent(out, indent, " *\n");
      writeWithIndent(out, indent, " * @param handle The handle\n");
      writeWithIndent(out, indent, " */\n");
      writeWithIndent(out, indent, "void closeHandle(");
      if (def.getMcfDefs().get(getNumOfMcf()).isUseCciConnection())
         out.write(def.getMcfDefs().get(getNumOfMcf()).getCciConnClass() + " handle)");
      else
         out.write(def.getMcfDefs().get(getNumOfMcf()).getConnInterfaceClass() + " handle)");
      writeLeftCurlyBracket(out, indent);
      writeWithIndent(out, indent + 1, "connections.remove((");
      if (def.getMcfDefs().get(getNumOfMcf()).isUseCciConnection())
         out.write(def.getMcfDefs().get(getNumOfMcf()).getCciConnClass());
      else
         out.write(def.getMcfDefs().get(getNumOfMcf()).getConnImplClass());
      out.write(")handle);\n");
      writeWithIndent(out, indent + 1,
            "ConnectionEvent event = new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED);\n");
      writeWithIndent(out, indent + 1, "event.setConnectionHandle(handle);\n");
      writeWithIndent(out, indent + 1, "for (ConnectionEventListener cel : listeners)");
      writeLeftCurlyBracket(out, indent + 1);
      writeWithIndent(out, indent + 2, "cel.connectionClosed(event);");
      writeRightCurlyBracket(out, indent + 1);

      writeRightCurlyBracket(out, indent);
      writeEol(out);
   }

   /**
    * Output Transaction method
    *
    * @param def    definition
    * @param out    Writer
    * @param indent space number
    * @throws IOException ioException
    */
   private void writeTransaction(Definition def, Writer out, int indent) throws IOException
   {
      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent, " * Returns an <code>javax.resource.spi.LocalTransaction</code> instance.\n");
      writeWithIndent(out, indent, " *\n");
      writeWithIndent(out, indent, " * @return LocalTransaction instance\n");
      writeWithIndent(out, indent, " * @throws ResourceException generic exception if operation fails\n");
      writeWithIndent(out, indent, " */\n");

      writeWithIndent(out, indent, "public LocalTransaction getLocalTransaction() throws ResourceException");
      writeLeftCurlyBracket(out, indent);
      if (def.getSupportTransaction().equals("NoTransaction"))
      {
         writeWithIndent(out, indent + 1, "throw new NotSupportedException(\"getLocalTransaction() not supported\");");
      }
      else
      {
         writeLogging(def, out, indent + 1, "trace", "getLocalTransaction");
         writeWithIndent(out, indent + 1, "return null;");
      }
      writeRightCurlyBracket(out, indent);
      writeEol(out);

      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent, " * Returns an <code>javax.transaction.xa.XAresource</code> instance. \n");
      writeWithIndent(out, indent, " *\n");
      writeWithIndent(out, indent, " * @return XAResource instance\n");
      writeWithIndent(out, indent, " * @throws ResourceException generic exception if operation fails\n");
      writeWithIndent(out, indent, " */\n");

      writeWithIndent(out, indent, "public XAResource getXAResource() throws ResourceException");
      writeLeftCurlyBracket(out, indent);
      if (def.getSupportTransaction().equals("NoTransaction"))
      {
         writeWithIndent(out, indent + 1, "throw new NotSupportedException(\"getXAResource() not supported\");");
      }
      else
      {
         writeLogging(def, out, indent + 1, "trace", "getXAResource");
         writeWithIndent(out, indent + 1, "return null;");
      }

      writeRightCurlyBracket(out, indent);
      writeEol(out);
   }

   /**
    * Output MetaData method
    *
    * @param def    definition
    * @param out    Writer
    * @param indent space number
    * @throws IOException ioException
    */
   private void writeMetaData(Definition def, Writer out, int indent) throws IOException
   {
      writeWithIndent(out, indent, "/**\n");
      writeWithIndent(out, indent,
            " * Gets the metadata information for this connection's underlying EIS resource manager instance. \n");
      writeWithIndent(out, indent, " *\n");
      writeWithIndent(out, indent, " * @return ManagedConnectionMetaData instance\n");
      writeWithIndent(out, indent, " * @throws ResourceException generic exception if operation fails\n");
      writeWithIndent(out, indent, " */\n");

      writeWithIndent(out, indent, "public ManagedConnectionMetaData getMetaData() throws ResourceException");
      writeLeftCurlyBracket(out, indent);
      writeLogging(def, out, indent + 1, "trace", "getMetaData");

      writeWithIndent(out, indent + 1, "return new " + def.getMcfDefs().get(getNumOfMcf()).getMcMetaClass() + "();");

      writeRightCurlyBracket(out, indent);
      writeEol(out);
   }

   /**
    * Output methods
    *
    * @param def    definition
    * @param out    Writer
    * @param indent space number
    * @throws IOException ioException
    */
   private void writeMethod(Definition def, Writer out, int indent) throws IOException
   {
      if (def.getMcfDefs().get(getNumOfMcf()).isDefineMethodInConnection())
      {
         if (def.getMcfDefs().get(getNumOfMcf()).getMethods().size() > 0)
         {
            for (MethodForConnection method : def.getMcfDefs().get(getNumOfMcf()).getMethods())
            {
               writeMethodSignature(out, indent, method);
               writeLeftCurlyBracket(out, indent);
               writeLogging(def, out, indent + 1, "trace", method.getMethodName());

               if (!method.getReturnType().equals("void"))
               {
                  writeEol(out);
                  if (BasicType.isPrimitiveType(method.getReturnType()))
                  {
                     writeWithIndent(out, indent + 1, "return " + BasicType.defaultValue(method.getReturnType()) + ";");
                  }
                  else
                  {
                     writeWithIndent(out, indent + 1, "return null;");
                  }
               }

               writeRightCurlyBracket(out, indent);
            }
         }
      }
      else
      {
         writeSimpleMethodSignature(out, indent, " * Call me", "void callMe()");
         writeLeftCurlyBracket(out, indent);
         writeLogging(def, out, indent + 1, "trace", "callMe");
         writeRightCurlyBracket(out, indent);
      }
   }
}