/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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 org.jkiss.dbeaver.ext.oracle.oci;
import org.jkiss.dbeaver.Log;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.core.DBeaverCore;
import org.jkiss.dbeaver.ext.oracle.model.OracleConstants;
import org.jkiss.dbeaver.ui.TextUtils;
import org.jkiss.dbeaver.utils.WinRegistry;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.IOUtils;
import org.jkiss.utils.StandardConstants;
import java.io.*;
import java.util.*;
public class OCIUtils
{
private static final Log log = Log.getLog(OCIUtils.class);
public static final String WIN_REG_ORACLE = "SOFTWARE\\ORACLE";
public static final String WIN_REG_ORA_HOME = "ORACLE_HOME";
public static final String WIN_REG_ORA_HOME_NAME = "ORACLE_HOME_NAME";
public static final String TNSNAMES_FILE_NAME = "tnsnames.ora";
public static final String TNSNAMES_FILE_PATH = "network/admin/";
//public static final String DRIVER_NAME_OCI = "oracle_oci";
/**
* A list of Oracle client homes found in the system.
* The first one is always a current Oracle home (from PATH)
*/
private static final List<OracleHomeDescriptor> oraHomes = new ArrayList<>();
private static boolean oraHomesSearched = false;
/*
static {
findOraHomes();
}
*/
public static List<OracleHomeDescriptor> getOraHomes()
{
checkOraHomes();
return oraHomes;
}
private static boolean checkOraHomes() {
if (!oraHomesSearched) {
findOraHomes();
oraHomesSearched = true;
}
return !oraHomes.isEmpty();
}
public static OracleHomeDescriptor getOraHome(String oraHome) {
if (CommonUtils.isEmpty(oraHome) || !checkOraHomes()) {
return null;
}
for (OracleHomeDescriptor home : oraHomes) {
// file name case insensitivity on Windows platform
if (equalsFileName(home.getHomeId(), oraHome)) {
return home;
}
}
return null;
}
public static OracleHomeDescriptor getOraHomeByName(String oraHomeName) {
if (CommonUtils.isEmpty(oraHomeName) || !checkOraHomes()) {
return null;
}
for (OracleHomeDescriptor home : oraHomes) {
// file name case insensitivity on Windows platform
if (equalsFileName(home.getDisplayName(), oraHomeName)) {
return home;
}
}
return null;
}
private static boolean equalsFileName(String file1, String file2) {
if (DBeaverCore.getInstance().getLocalSystem().isWindows()) {
return file1.equalsIgnoreCase(file2);
}
else {
return file1.equals(file2);
}
}
public static OracleHomeDescriptor addOraHome(String oraHome) throws DBException
{
if (CommonUtils.isEmpty(oraHome)) {
return null;
}
oraHome = CommonUtils.removeTrailingSlash(oraHome);
boolean contains = false;
for (OracleHomeDescriptor home : oraHomes) {
// file name case insensitivity on Windows platform
if (equalsFileName(home.getHomeId(), oraHome)) {
contains = true;
break;
}
}
if (!contains) {
OracleHomeDescriptor homeDescriptor = new OracleHomeDescriptor(oraHome);
oraHomes.add(0, homeDescriptor);
return homeDescriptor;
}
return null;
}
/**
* Searches Oracle home locations.
*/
private static void findOraHomes()
{
// read system environment variables
String path = System.getenv(OracleConstants.VAR_PATH);
if (path != null) {
for (String token : path.split(System.getProperty(StandardConstants.ENV_PATH_SEPARATOR))) {
if (token.toLowerCase().contains("oracle")) {
token = CommonUtils.removeTrailingSlash(token);
if (token.toLowerCase().endsWith("bin")) {
String oraHome = token.substring(0, token.length() - 3);
try {
addOraHome(oraHome);
} catch (DBException ex) {
log.warn("Wrong Oracle client home " + oraHome, ex);
}
}
}
}
}
String oraHome = System.getenv(OracleConstants.VAR_ORA_HOME);
if (oraHome == null) {
oraHome = System.getenv(OracleConstants.VAR_ORACLE_HOME);
}
if (oraHome != null) {
try {
addOraHome(oraHome);
} catch (DBException ex) {
log.warn("Wrong Oracle client home " + oraHome, ex);
}
}
// find Oracle homes in Windows registry
if (DBeaverCore.getInstance().getLocalSystem().isWindows()) {
try {
List<String> oracleKeys = WinRegistry.readStringSubKeys(WinRegistry.HKEY_LOCAL_MACHINE, WIN_REG_ORACLE);
if (oracleKeys != null) {
for (String oracleKey : oracleKeys) {
Map<String, String> valuesMap = WinRegistry.readStringValues(WinRegistry.HKEY_LOCAL_MACHINE, WIN_REG_ORACLE + "\\" + oracleKey);
if (valuesMap != null) {
for (String key : valuesMap.keySet()) {
if (WIN_REG_ORA_HOME.equals(key)) {
try {
oraHome = valuesMap.get(key);
addOraHome(oraHome);
} catch (DBException ex) {
log.warn("Wrong Oracle client home " + oraHome, ex);
}
break;
}
}
}
}
}
} catch (Exception e) {
log.warn("Error reading Windows registry", e);
}
}
}
public static String readWinRegistry(String oraHome, String name) {
if (DBeaverCore.getInstance().getLocalSystem().isWindows()) {
try {
List<String> oracleKeys = WinRegistry.readStringSubKeys(WinRegistry.HKEY_LOCAL_MACHINE, WIN_REG_ORACLE);
if (oracleKeys != null) {
for (String oracleKey : oracleKeys) {
String home = WinRegistry.readString(WinRegistry.HKEY_LOCAL_MACHINE, WIN_REG_ORACLE + "\\" + oracleKey, WIN_REG_ORA_HOME);
if (oraHome.equals(home)) {
String value = WinRegistry.readString(WinRegistry.HKEY_LOCAL_MACHINE, WIN_REG_ORACLE + "\\" + oracleKey, name);
if (value != null) {
return value;
}
}
}
}
} catch (Exception e) {
log.warn("Error reading Windows registry", e);
}
}
return null;
}
/*
public static boolean isOciDriver(DBPDriver driver)
{
return DRIVER_NAME_OCI.equals(driver.getId());
}
*/
/**
* Returns an installed Oracle client full version
* @return oracle version
*/
public static String getFullOraVersion(String oraHome, boolean isInstantClient)
{
String sqlplus =
(isInstantClient ? CommonUtils.makeDirectoryName(oraHome) : CommonUtils.makeDirectoryName(oraHome) + "bin/") +
"sqlplus -version";
try {
Process p = Runtime.getRuntime().exec(sqlplus);
try {
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
try {
String line;
while ((line = input.readLine()) != null) {
if (line.startsWith("SQL*Plus: Release ")) {
return line.substring(18, line.indexOf(" ", 19));
}
}
} finally {
IOUtils.close(input);
}
} finally {
p.destroy();
}
}
catch (Exception ex) {
log.warn("Error reading Oracle client version from " + sqlplus, ex);
}
return null;
}
@Nullable
public static File findTnsNamesFile(@Nullable File oraHome, boolean checkTnsAdmin)
{
File tnsNamesFile = null;
if (checkTnsAdmin) {
String tnsAdmin = System.getenv(OracleConstants.VAR_TNS_ADMIN);
if (tnsAdmin != null) {
tnsNamesFile = new File (tnsAdmin, TNSNAMES_FILE_NAME);
}
}
if ((tnsNamesFile == null || !tnsNamesFile.exists()) && oraHome != null) {
tnsNamesFile = new File (oraHome, TNSNAMES_FILE_PATH + TNSNAMES_FILE_NAME);
if (!tnsNamesFile.exists()) {
tnsNamesFile = new File (oraHome, TNSNAMES_FILE_NAME);
}
}
if (tnsNamesFile != null && tnsNamesFile.exists()) {
return tnsNamesFile;
} else {
return null;
}
}
/**
* Reads TNS names from a specified Oracle home or system variable TNS_ADMIN.
*/
public static Map<String, String> readTnsNames(@Nullable File oraHome, boolean checkTnsAdmin)
{
File tnsNamesFile = findTnsNamesFile(oraHome, checkTnsAdmin);
if (tnsNamesFile != null) {
return parseTnsNames(tnsNamesFile);
} else {
return Collections.emptyMap();
}
}
/**
* Reads TNS names from a specified file.
*/
private static Map<String, String> parseTnsNames(File tnsnamesOra)
{
Map<String, String> aliases = new TreeMap<>();
if (tnsnamesOra.exists()) {
try {
BufferedReader reader = new BufferedReader(new FileReader(tnsnamesOra));
StringBuilder tnsDescription = new StringBuilder();
String curAlias = null;
String line;
while ((line = reader.readLine()) != null) {
final String trimmedLine = line.trim();
if (trimmedLine.isEmpty() || trimmedLine.startsWith("#") ) {
continue;
}
if (!line.startsWith(" ") && !line.startsWith("\t") && !line.startsWith("(") && line.contains("=")) {
final int divPos = line.indexOf("=");
if (divPos < 0) {
continue;
}
final String alias = line.substring(0, divPos);
if (alias.equalsIgnoreCase("IFILE")) {
String filePath = line.substring(divPos + 1).trim();
File extFile = new File(filePath);
if (!extFile.exists()) {
extFile = new File(tnsnamesOra.getParent(), filePath);
}
aliases.putAll(parseTnsNames(extFile));
} else {
if (curAlias != null) {
aliases.put(curAlias, getPlainTnsDescription(tnsDescription.toString()));
}
curAlias = alias.trim();
tnsDescription.setLength(0);
tnsDescription.append(line.substring(divPos + 1));
}
} else {
if (curAlias != null) {
tnsDescription.append(line);
}
}
}
if (curAlias != null) {
aliases.put(curAlias, getPlainTnsDescription(tnsDescription.toString()));
}
} catch (IOException e) {
// do nothing
log.debug(e);
}
} else {
log.debug("TNS names file '" + tnsnamesOra + "' doesn't exist");
}
return aliases;
}
private static String getPlainTnsDescription(String line) {
return TextUtils.compactWhiteSpaces(line.trim());
}
public static boolean isInstantClient(String oraHome)
{
File root = new File(System.mapLibraryName(CommonUtils.makeDirectoryName(oraHome) + "oci"));
File bin = new File(System.mapLibraryName(CommonUtils.makeDirectoryName(oraHome) + "bin/" + "oci"));
return root.exists() && !bin.exists();
}
}