content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You 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.apache.carbondata.presto;
  
  import java.lang.reflect.*;
  import java.util.Map;
  
  import org.apache.carbondata.hive.CarbonHiveSerDe;
  import org.apache.carbondata.hive.MapredCarbonInputFormat;
  import org.apache.carbondata.hive.MapredCarbonOutputFormat;
  
  import com.google.inject.Module;
  import io.airlift.units.DataSize;
  import io.prestosql.plugin.hive.HiveConnectorFactory;
  import io.prestosql.plugin.hive.HiveStorageFormat;
  import io.prestosql.spi.connector.Connector;
  import io.prestosql.spi.connector.ConnectorContext;
  import sun.misc.Unsafe;
  
  import static io.airlift.units.DataSize.Unit.MEGABYTE;
  
  /**
   * Build Carbondata Connector
   * It will be called by CarbondataPlugin
   */
  public class CarbondataConnectorFactory extends HiveConnectorFactory {
  
    static {
      try {
        setCarbonEnum();
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
  
    public CarbondataConnectorFactory(String connectorName) {
      this(connectorName, EmptyModule.class);
    }
  
    public CarbondataConnectorFactory(String connectorName, Class<? extends Module> module) {
      super(connectorName, module);
    }
  
  
    @Override
    public Connector create(
        String catalogName,
        Map<String, String> config,
        ConnectorContext context) {
      return InternalCarbonDataConnectorFactory
          .createConnector(catalogName, config, context, new EmptyModule());
    }
  
    /**
     * Set the Carbon format enum to HiveStorageFormat, its a hack but for time being it is best
     * choice to avoid lot of code change.
     *
     * @throws Exception
     */
    private static void setCarbonEnum() throws Exception {
      for (HiveStorageFormat format : HiveStorageFormat.values()) {
        if ("CARBON".equals(format.name()) || "ORG.APACHE.CARBONDATA.FORMAT".equals(format.name())
            || "CARBONDATA".equals(format.name())) {
          return;
        }
      }
      addHiveStorageFormatsForCarbondata("CARBON");
      addHiveStorageFormatsForCarbondata("ORG.APACHE.CARBONDATA.FORMAT");
      addHiveStorageFormatsForCarbondata("CARBONDATA");
    }
  
    private static void addHiveStorageFormatsForCarbondata(String storedAs) throws Exception {
      Constructor<?> constructor = Unsafe.class.getDeclaredConstructors()[0];
      constructor.setAccessible(true);
      Unsafe unsafe = (Unsafe) constructor.newInstance();
      HiveStorageFormat enumValue =
          (HiveStorageFormat) unsafe.allocateInstance(HiveStorageFormat.class);
  
      Field nameField = Enum.class.getDeclaredField("name");
      makeAccessible(nameField);
      nameField.set(enumValue, storedAs);
  
      Field ordinalField = Enum.class.getDeclaredField("ordinal");
      makeAccessible(ordinalField);
      ordinalField.setInt(enumValue, HiveStorageFormat.values().length);
  
      Field serdeField = HiveStorageFormat.class.getDeclaredField("serde");
      makeAccessible(serdeField);
      serdeField.set(enumValue, CarbonHiveSerDe.class.getName());
  
      Field inputFormatField = HiveStorageFormat.class.getDeclaredField("inputFormat");
      makeAccessible(inputFormatField);
      inputFormatField.set(enumValue, MapredCarbonInputFormat.class.getName());
  
      Field outputFormatField = HiveStorageFormat.class.getDeclaredField("outputFormat");
      makeAccessible(outputFormatField);
      outputFormatField.set(enumValue, MapredCarbonOutputFormat.class.getName());
  
      Field estimatedWriterSystemMemoryUsageField =
          HiveStorageFormat.class.getDeclaredField("estimatedWriterSystemMemoryUsage");
      makeAccessible(estimatedWriterSystemMemoryUsageField);
      estimatedWriterSystemMemoryUsageField.set(enumValue, new DataSize((long) 256, MEGABYTE));
  
      Field values = HiveStorageFormat.class.getDeclaredField("$VALUES");
      makeAccessible(values);
      HiveStorageFormat[] hiveStorageFormats =
          new HiveStorageFormat[HiveStorageFormat.values().length + 1];
      HiveStorageFormat[] src = (HiveStorageFormat[]) values.get(null);
      System.arraycopy(src, 0, hiveStorageFormats, 0, src.length);
      hiveStorageFormats[src.length] = enumValue;
      values.set(null, hiveStorageFormats);
    }
  
    private static void makeAccessible(Field field) throws Exception {
      field.setAccessible(true);
      Field modifiersField = Field.class.getDeclaredField("modifiers");
      modifiersField.setAccessible(true);
      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    }
  
  }
  