| /* |
| * 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.cassandra.cql3.functions; |
| |
| import java.lang.invoke.MethodHandle; |
| import java.lang.invoke.MethodHandles; |
| import java.lang.reflect.Method; |
| import java.nio.ByteBuffer; |
| import java.util.List; |
| |
| import com.datastax.driver.core.CodecRegistry; |
| import com.datastax.driver.core.DataType; |
| import com.datastax.driver.core.ProtocolVersion; |
| import com.datastax.driver.core.TypeCodec; |
| import com.datastax.driver.core.exceptions.InvalidTypeException; |
| import org.apache.cassandra.cql3.CQL3Type; |
| import org.apache.cassandra.db.marshal.AbstractType; |
| import org.apache.cassandra.transport.Server; |
| |
| /** |
| * Helper class for User Defined Functions + Aggregates. |
| */ |
| public final class UDHelper |
| { |
| // TODO make these c'tors and methods public in Java-Driver - see https://datastax-oss.atlassian.net/browse/JAVA-502 |
| private static final MethodHandle methodParseOne; |
| private static final CodecRegistry codecRegistry; |
| static |
| { |
| try |
| { |
| Class<?> cls = Class.forName("com.datastax.driver.core.DataTypeClassNameParser"); |
| Method m = cls.getDeclaredMethod("parseOne", String.class, ProtocolVersion.class, CodecRegistry.class); |
| m.setAccessible(true); |
| methodParseOne = MethodHandles.lookup().unreflect(m); |
| codecRegistry = new CodecRegistry(); |
| } |
| catch (Exception e) |
| { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| static TypeCodec<Object>[] codecsFor(DataType[] dataType) |
| { |
| TypeCodec<Object>[] codecs = new TypeCodec[dataType.length]; |
| for (int i = 0; i < dataType.length; i++) |
| codecs[i] = codecFor(dataType[i]); |
| return codecs; |
| } |
| |
| static TypeCodec<Object> codecFor(DataType dataType) |
| { |
| return codecRegistry.codecFor(dataType); |
| } |
| |
| /** |
| * Construct an array containing the Java classes for the given Java Driver {@link com.datastax.driver.core.DataType}s. |
| * |
| * @param dataTypes array with UDF argument types |
| * @param calledOnNullInput whether to allow {@code null} as an argument value |
| * @return array of same size with UDF arguments |
| */ |
| public static Class<?>[] javaTypes(TypeCodec<Object>[] dataTypes, boolean calledOnNullInput) |
| { |
| Class<?>[] paramTypes = new Class[dataTypes.length]; |
| for (int i = 0; i < paramTypes.length; i++) |
| { |
| Class<?> clazz = asJavaClass(dataTypes[i]); |
| if (!calledOnNullInput) |
| { |
| // only care about classes that can be used in a data type |
| if (clazz == Integer.class) |
| clazz = int.class; |
| else if (clazz == Long.class) |
| clazz = long.class; |
| else if (clazz == Byte.class) |
| clazz = byte.class; |
| else if (clazz == Short.class) |
| clazz = short.class; |
| else if (clazz == Float.class) |
| clazz = float.class; |
| else if (clazz == Double.class) |
| clazz = double.class; |
| else if (clazz == Boolean.class) |
| clazz = boolean.class; |
| } |
| paramTypes[i] = clazz; |
| } |
| return paramTypes; |
| } |
| |
| /** |
| * Construct an array containing the Java Driver {@link com.datastax.driver.core.DataType}s for the |
| * C* internal types. |
| * |
| * @param abstractTypes list with UDF argument types |
| * @return array with argument types as {@link com.datastax.driver.core.DataType} |
| */ |
| public static DataType[] driverTypes(List<AbstractType<?>> abstractTypes) |
| { |
| DataType[] argDataTypes = new DataType[abstractTypes.size()]; |
| for (int i = 0; i < argDataTypes.length; i++) |
| argDataTypes[i] = driverType(abstractTypes.get(i)); |
| return argDataTypes; |
| } |
| |
| /** |
| * Returns the Java Driver {@link com.datastax.driver.core.DataType} for the C* internal type. |
| */ |
| public static DataType driverType(AbstractType abstractType) |
| { |
| CQL3Type cqlType = abstractType.asCQL3Type(); |
| try |
| { |
| return (DataType) methodParseOne.invoke(cqlType.getType().toString(), |
| ProtocolVersion.fromInt(Server.CURRENT_VERSION), |
| codecRegistry); |
| } |
| catch (RuntimeException | Error e) |
| { |
| // immediately rethrow these... |
| throw e; |
| } |
| catch (Throwable e) |
| { |
| throw new RuntimeException("cannot parse driver type " + cqlType.getType().toString(), e); |
| } |
| } |
| |
| public static Object deserialize(TypeCodec<?> codec, int protocolVersion, ByteBuffer value) |
| { |
| return codec.deserialize(value, ProtocolVersion.fromInt(protocolVersion)); |
| } |
| |
| public static ByteBuffer serialize(TypeCodec<?> codec, int protocolVersion, Object value) |
| { |
| if (!codec.getJavaType().getRawType().isAssignableFrom(value.getClass())) |
| throw new InvalidTypeException("Invalid value for CQL type " + codec.getCqlType().getName().toString()); |
| |
| return ((TypeCodec)codec).serialize(value, ProtocolVersion.fromInt(protocolVersion)); |
| } |
| |
| public static Class<?> asJavaClass(TypeCodec<?> codec) |
| { |
| return codec.getJavaType().getRawType(); |
| } |
| |
| public static boolean isNullOrEmpty(AbstractType<?> type, ByteBuffer bb) |
| { |
| return bb == null || |
| (bb.remaining() == 0 && type.isEmptyValueMeaningless()); |
| } |
| } |