Package cascading.lingual.jdbc

Source Code of cascading.lingual.jdbc.JaninoFactory

/*
* Copyright (c) 2007-2014 Concurrent, Inc. All Rights Reserved.
*
* Project and contact information: http://www.cascading.org/
*
* This file is part of the Cascading project.
*
* 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 cascading.lingual.jdbc;

import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import com.google.common.base.Throwables;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.janino.ClassBodyEvaluator;
import org.codehaus.janino.Scanner;

/** Implements {@link Factory} by generating a non-abstract derived class. */
class JaninoFactory implements Factory
  {

  private static Class cachedTargetType;

  public Connection createConnection( Connection connection, Properties connectionProperties ) throws SQLException
    {
    try
      {
      return create(
        LingualConnection.class,
        new Class[]{Connection.class, Properties.class},
        new Object[]{connection, connectionProperties}
      );
      }
    catch( Throwable throwable )
      {
      if( throwable instanceof InvocationTargetException )
        throwable = ( (InvocationTargetException) throwable ).getTargetException();

      if( throwable instanceof RuntimeException )
        throw Throwables.propagate( throwable );

      if( throwable instanceof SQLException )
        throw (SQLException) throwable;

      if( throwable.getCause() instanceof SQLException )
        throw (SQLException) throwable.getCause();

      throw new SQLException( "could not create connection: " + throwable.getMessage(), throwable );
      }
    }

  static <T> T create( Class<T> abstractClass, Class[] constructorParamTypes, Object[] constructorArgs )
    throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException, CompileException
    {
    Class targetType = null;

    if( !isAbstract( abstractClass.getModifiers() ) )
      {
      targetType = abstractClass;
      }
    // we don't have to re-create the class every time. This eases the pressure on the PermGen with many open
    // connections.
    else if ( cachedTargetType == null )
      {
      final StringBuilder buf = new StringBuilder();

      buf.append( "public " )
        .append( "SC" )
        .append( "(" );

      for( int i = 0; i < constructorParamTypes.length; i++ )
        {
        Class constructorParamType = constructorParamTypes[ i ];

        if( i > 0 )
          buf.append( ", " );

        unparse( buf, constructorParamType )
          .append( " p" )
          .append( i );
        }

      buf.append( ") throws java.sql.SQLException { super(" );

      for( int i = 0; i < constructorParamTypes.length; i++ )
        {
        if( i > 0 )
          buf.append( ", " );

        buf.append( "p" )
          .append( i );
        }

      buf.append( "); }\n" );

      for( Method method : abstractClass.getMethods() )
        {
        if( isAbstract( method.getModifiers() ) )
          {
          buf.append( "public " );

          unparse( buf, method.getReturnType() )
            .append( " " )
            .append( method.getName() )
            .append( "(" );

          Class<?>[] parameterTypes = method.getParameterTypes();

          for( int i = 0; i < parameterTypes.length; i++ )
            {
            if( i > 0 )
              buf.append( ", " );

            Class<?> type = parameterTypes[ i ];

            unparse( buf, type ).append( " " ).append( "p" ).append( i );
            }

          buf.append( ") { throw new UnsupportedOperationException();}\n" );
          }
        }

      StringReader stringReader = new StringReader( buf.toString() );
      ClassLoader classLoader = JaninoFactory.class.getClassLoader();
      ClassBodyEvaluator evaluator = new ClassBodyEvaluator( new Scanner( null, stringReader ), abstractClass, new Class[ 0 ], classLoader );

      cachedTargetType = evaluator.getClazz();
      targetType = cachedTargetType;
      }
    else
      targetType = cachedTargetType;

    Constructor constructor = targetType.getConstructor( constructorParamTypes );

    // Note: that's where we instantiate <? extends LingualConnection>
    return abstractClass.cast( constructor.newInstance( constructorArgs ) );
    }

  private static <T> boolean isAbstract( int modifiers )
    {
    return ( modifiers & Modifier.ABSTRACT ) != 0;
    }

  private static StringBuilder unparse( StringBuilder buf, Class clazz )
    {
    if( clazz.isPrimitive() )
      return buf.append( clazz );
    else if( clazz.isArray() )
      return unparse( buf, clazz.getComponentType() ).append( "[]" );
    else
      return buf.append( clazz.getName() );
    }
  }
TOP

Related Classes of cascading.lingual.jdbc.JaninoFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.