Skip to content

File loadjava.cpp

File List > cubrid > src > executables > loadjava.cpp

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  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.
 *
 */

/*
 * loadjava.cpp - loadjava utility
 */

#ident "$Id$"

#include "config.h"

#include <cassert>
#include <string>
#include <regex>
#include <filesystem>

#include "cubrid_getopt.h"
#include "error_code.h"
#include "message_catalog.h"
#include "utility.h"
#include "databases_file.h"
#if defined(WINDOWS)
#include "porting.h"
#endif /* WINDOWS */

namespace fs = std::filesystem;
using namespace std::regex_constants;

#define JAVA_DIR                "java"
#define JAVA_STATIC_DIR         "java_static"

#if defined(WINDOWS)
#define SEPERATOR               "\\"
#else /* ! WINDOWS */
#define SEPERATOR               "/"
#endif /* !WINDOWS */

static const std::string JAVA_PACKAGE_PATTERN = "^([a-z_]{1}[a-z0-9_]*(\\.[a-z_]{1}[a-z0-9_]*)*)$";
static const std::string SEPARATOR_STRING (SEPERATOR);

static const std::string DYNAMIC_PATH = JAVA_DIR;
static const std::string STATIC_PATH = JAVA_STATIC_DIR;

static fs::path Root;
static std::string Path;
static char *Program_name = NULL;
static char *Dbname = NULL;
std::string Src_class;
std::regex Java_package_reg (JAVA_PACKAGE_PATTERN, ECMAScript | icase | optimize);

static int Force_overwrite = false;
static std::string package_path;

static void
usage (void)
{
  fprintf (stderr, "%s", msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_LOADJAVA, LOADJAVA_MSG_USAGE));
}

static int
parse_argument (int argc, char *argv[])
{
  int error = NO_ERROR;
  struct option loadjava_option[] =
  {
    {"overwrite", 0, 0, 'y'},
    {"package", 1, 0, 'p'},
    {"jni", 0, 0, 'j'},
    {0, 0, 0, 0}
  };

  while (1)
    {
      int option_index = 0;
      int option_key = getopt_long (argc, argv, "yp:jh", loadjava_option, &option_index);
      if (option_key == -1)
    {
      break;
    }

      switch (option_key)
    {
    case 'y':
      Force_overwrite = true;
      break;
    case 'p':
    {
      // check valid package name
      if (optarg == NULL)
        {
          error = ER_FAILED;
          goto exit;
        }

      // e.g. $CUBRID/demodb/java/org/cubrid/path/
      std::string package_name (optarg);
      if (!package_name.empty())
        {
          bool is_matched = std::regex_search (package_name, Java_package_reg);
          if (!is_matched)
        {
          fprintf (stderr, "invalid java package name\n");
          return ER_FAILED;
        }
          // replace all for package name's dot to SEPARATER
          // e.g. org.cubrid.abc => org/cubrid/abc
          package_path = std::regex_replace (package_name, std::regex ("\\."), SEPARATOR_STRING);
        }
    }
    break;
    case 'j':
      Path = STATIC_PATH;
      break;
    case 'h':
      [[fallthrough]];
    default:
      error = ER_FAILED;
      goto exit;
    }
    }

  if (optind + 1 < argc)
    {
      Dbname = argv[optind];
      Src_class = argv[optind + 1];
    }
  else
    {
      error = ER_FAILED;
      goto exit;
    }

exit:
  if (error == NO_ERROR)
    {
      Program_name = argv[0];
      // e.g. $CUBRID/demodb/java or e.g. $CUBRID/demodb/java_static
      if (Path.empty())
    {
      Path = DYNAMIC_PATH;
    }
    }
  else
    {
      usage ();
    }

  return error;
}

static int
check_arguments ()
{
  DB_INFO *db = NULL;

  // check whether database exists
  if ((db = cfg_find_db (Dbname)) == NULL)
    {
      fprintf (stderr, "database '%s' does not exist.\n", Dbname);
      return ER_FAILED;
    }

  // DB path e.g. $CUBRID/demodb
  Root.assign (std::string (db->pathname));

  // check the specified source path of the java class file (jar) exists
  try
    {
      fs::path src_path (Src_class);
      if (!fs::exists (src_path))
    {
      fprintf (stderr, "loadjava fail: '%s' does not exist.\n", src_path.generic_string().c_str ());
      return ER_FAILED;
    }

      std::string ext_nm = src_path.extension().generic_string();
      if (ext_nm.empty() || ((ext_nm.compare (".class") != 0) && (ext_nm.compare (".jar") != 0)))
    {
      fprintf (stderr, "loadjava fail: The extension name of '%s' is invalid.\n", src_path.generic_string().c_str ());
      return ER_FAILED;
    }
    }
  catch (fs::filesystem_error &e)
    {
      fprintf (stderr, "loadjava fail: file operation error: %s\n", e.what ());
      return ER_FAILED;
    }

  return NO_ERROR;
}

static int
create_package_directories (const fs::path &dir_path)
{
  try
    {
      if (fs::exists (dir_path) == false)
    {
      fs::create_directories (dir_path);
      fs::permissions (dir_path,
               fs::perms::owner_all | fs::perms::group_read | fs::perms::others_read,
               fs::perm_options::add);  // mkdir (java_dir_path, 0744)
    }
    }
  catch (fs::filesystem_error &e)
    {
      fprintf (stderr, "can't create directory: %s. %s\n", dir_path.generic_string ().c_str (), e.what ());
      return ER_FAILED;
    }
  return NO_ERROR;
}

static int
check_overwrite (const std::string &package_path, const std::string &class_file_name)
{
  try
    {
      fs::path static_path = Root / STATIC_PATH / package_path / class_file_name;
      fs::path dynamic_path = Root / DYNAMIC_PATH / package_path / class_file_name;

      bool exists_static = fs::exists (static_path);
      bool exists_dynamic = fs::exists (dynamic_path);

      // check whether class name exists for either static path and dynamic path
      std::string full_class_name = package_path + class_file_name;
      if (exists_static || exists_dynamic)
    {
      if (Force_overwrite == false)
        {
          std::string full_class_name = package_path.empty () ? class_file_name : (package_path + SEPERATOR + class_file_name);
          fprintf (stdout, "'%s' is exist. overwrite? (y/n): ", full_class_name.c_str ());
          char c = getchar ();
          if (c != 'Y' && c != 'y')
        {
          fprintf (stdout, "loadjava is canceled\n");
          return ER_FAILED;
        }
        }

      // remove the previous file (to update modified time of the JAVA directory: CBRD-24695)
      if (exists_static && fs::is_directory (static_path) == false)
        {
          fs::remove (static_path);
        }

      // remove the previous file (to update modified time of the JAVA directory: CBRD-24695)
      if (exists_dynamic && fs::is_directory (dynamic_path) == false)
        {
          fs::remove (dynamic_path);
        }
    }
    }
  catch (fs::filesystem_error &e)
    {
      fprintf (stderr, "loadjava fail: file operation error: %s\n", e.what ());
      return ER_FAILED;
    }

  return NO_ERROR;
}

static int
copy_class_file (const fs::path &src_path, const fs::path &dest_path)
{
  try
    {
      const auto copyOptions = fs::copy_options::overwrite_existing;
      fs::copy (src_path, dest_path, copyOptions);
    }
  catch (fs::filesystem_error &e)
    {
      fprintf (stderr, "loadjava fail: file operation error: %s\n", e.what ());
      return ER_FAILED;
    }

  return NO_ERROR;
}

static int
do_load_java ()
{
  fs::path src_path (Src_class);
  std::string class_file_name = src_path.filename().generic_string();

  if (check_overwrite (package_path, class_file_name) != NO_ERROR)
    {
      return ER_FAILED;
    }

  fs::path package_dir = Root / Path / package_path;
  if (create_package_directories (package_dir) != NO_ERROR)
    {
      return ER_FAILED;
    }

  fs::path dest_path = package_dir / class_file_name;
  if (copy_class_file (src_path, dest_path) != NO_ERROR)
    {
      return ER_FAILED;
    }

  return NO_ERROR;
}

/*
 * main() - loadjava main function
 *   return: EXIT_SUCCESS/EXIT_FAILURE
 */
int
main (int argc, char *argv[])
{
  int status = EXIT_FAILURE;

  /* initialize message catalog for argument parsing and usage() */
  if (utility_initialize () != NO_ERROR)
    {
      return EXIT_FAILURE;
    }

  if (parse_argument (argc, argv) != NO_ERROR)
    {
      goto error;
    }

  if (check_arguments () != NO_ERROR)
    {
      goto error;
    }

  if (do_load_java () != NO_ERROR)
    {
      goto error;
    }

  status = EXIT_SUCCESS;

error:
  msgcat_final ();

  return (status);
}