blob: 2cd2d753591ccb95bde7a49b78876190689bb786 [file] [log] [blame]
/*
* 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.ignite.cache.store.cassandra.common;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.regex.Pattern;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.DataType;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.exceptions.DriverException;
import com.datastax.driver.core.exceptions.InvalidQueryException;
import com.datastax.driver.core.exceptions.NoHostAvailableException;
import com.datastax.driver.core.exceptions.ReadTimeoutException;
import org.apache.ignite.internal.util.typedef.internal.U;
/**
* Helper class providing methods to work with Cassandra session and exceptions
*/
public class CassandraHelper {
/** Cassandra error message if specified keyspace doesn't exist. */
private static final Pattern KEYSPACE_EXIST_ERROR1 = Pattern.compile("Keyspace [0-9a-zA-Z_]+ does not exist");
/** Cassandra error message if trying to create table inside nonexistent keyspace. */
private static final Pattern KEYSPACE_EXIST_ERROR2 = Pattern.compile("Cannot add table '[0-9a-zA-Z_]+' to non existing keyspace.*");
/** Cassandra error message if trying to create table inside nonexistent keyspace. */
private static final Pattern KEYSPACE_EXIST_ERROR3 = Pattern.compile("Error preparing query, got ERROR INVALID: " +
"Keyspace [0-9a-zA-Z_]+ does not exist");
/** Cassandra error message if specified table doesn't exist. */
private static final Pattern TABLE_EXIST_ERROR1 = Pattern.compile("unconfigured table [0-9a-zA-Z_]+");
/** Cassandra error message if specified table doesn't exist. */
private static final String TABLE_EXIST_ERROR2 = "Error preparing query, got ERROR INVALID: unconfigured table";
/** Cassandra error message if specified table doesn't exist. */
private static final Pattern TABLE_EXIST_ERROR3 = Pattern.compile("unconfigured columnfamily [0-9a-zA-Z_]+");
/** Cassandra error message if trying to use prepared statement created from another session. */
private static final String PREP_STATEMENT_CLUSTER_INSTANCE_ERROR = "You may have used a PreparedStatement that " +
"was created with another Cluster instance";
/** Closes Cassandra driver session. */
public static void closeSession(Session driverSes) {
if (driverSes == null)
return;
Cluster cluster = driverSes.getCluster();
if (!driverSes.isClosed())
U.closeQuiet(driverSes);
if (!cluster.isClosed())
U.closeQuiet(cluster);
}
/**
* Checks if Cassandra keyspace absence error occur.
*
* @param e Exception to check.
* @return {@code true} in case of keyspace absence error.
*/
public static boolean isKeyspaceAbsenceError(Throwable e) {
while (e != null) {
if (e instanceof InvalidQueryException &&
(KEYSPACE_EXIST_ERROR1.matcher(e.getMessage()).matches() ||
KEYSPACE_EXIST_ERROR2.matcher(e.getMessage()).matches()))
return true;
e = e.getCause();
}
return false;
}
/**
* Checks if Cassandra table absence error occur.
*
* @param e Exception to check.
* @return {@code true} in case of table absence error.
*/
public static boolean isTableAbsenceError(Throwable e) {
while (e != null) {
if (e instanceof InvalidQueryException &&
(TABLE_EXIST_ERROR1.matcher(e.getMessage()).matches() ||
TABLE_EXIST_ERROR3.matcher(e.getMessage()).matches() ||
KEYSPACE_EXIST_ERROR1.matcher(e.getMessage()).matches() ||
KEYSPACE_EXIST_ERROR2.matcher(e.getMessage()).matches()))
return true;
if (e instanceof NoHostAvailableException && ((NoHostAvailableException) e).getErrors() != null) {
NoHostAvailableException ex = (NoHostAvailableException)e;
for (Map.Entry<InetSocketAddress, Throwable> entry : ex.getErrors().entrySet()) {
Throwable error = entry.getValue();
if (error instanceof DriverException &&
(error.getMessage().contains(TABLE_EXIST_ERROR2) ||
KEYSPACE_EXIST_ERROR3.matcher(error.getMessage()).matches()))
return true;
}
}
e = e.getCause();
}
return false;
}
/**
* Checks if Cassandra host availability error occur, thus host became unavailable.
*
* @param e Exception to check.
* @return {@code true} in case of host not available error.
*/
public static boolean isHostsAvailabilityError(Throwable e) {
while (e != null) {
if (e instanceof NoHostAvailableException ||
e instanceof ReadTimeoutException)
return true;
e = e.getCause();
}
return false;
}
/**
* Checks if Cassandra error occur because of prepared statement created in one session was used in another session.
*
* @param e Exception to check.
* @return {@code true} in case of invalid usage of prepared statement.
*/
public static boolean isPreparedStatementClusterError(Throwable e) {
while (e != null) {
if (e instanceof InvalidQueryException && e.getMessage().contains(PREP_STATEMENT_CLUSTER_INSTANCE_ERROR))
return true;
e = e.getCause();
}
return false;
}
/**
* Checks if two Java classes are Cassandra compatible - mapped to the same Cassandra type.
*
* @param type1 First type.
* @param type2 Second type.
* @return {@code true} if classes are compatible and {@code false} if not.
*/
public static boolean isCassandraCompatibleTypes(Class type1, Class type2) {
if (type1 == null || type2 == null)
return false;
DataType.Name t1 = PropertyMappingHelper.getCassandraType(type1);
DataType.Name t2 = PropertyMappingHelper.getCassandraType(type2);
return t1 != null && t2 != null && t1.equals(t2);
}
}