/** * 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.db.marshal; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.cassandra.config.ConfigurationException; import org.apache.cassandra.utils.ByteBufferUtil; /* * The encoding of a CompositeType column name should be: * <component><component><component> ... * where <component> is: * <length of value><value><'end-of-component' byte> * where <length of value> is a 2 bytes unsigned short the and the * 'end-of-component' byte should always be 0 for actual column name. * However, it can set to 1 for query bounds. This allows to query for the * equivalent of 'give me the full super-column'. That is, if during a slice * query uses: * start = <3><"foo".getBytes()><0> * end = <3><"foo".getBytes()><1> * then he will be sure to get *all* the columns whose first component is "foo". * If for a component, the 'end-of-component' is != 0, there should not be any * following component. The end-of-component can also be -1 to allow * non-inclusive query. For instance: * start = <3><"foo".getBytes()><-1> * allows to query everything that is greater than <3><"foo".getBytes()>, but * not <3><"foo".getBytes()> itself. */ public class CompositeType extends AbstractCompositeType { // package protected for unit tests sake final List<AbstractType> types; // interning instances private static final Map<List<AbstractType>, CompositeType> instances = new HashMap<List<AbstractType>, CompositeType>(); public static CompositeType getInstance(TypeParser parser) throws ConfigurationException { return getInstance(parser.getTypeParameters()); } public static synchronized CompositeType getInstance(List<AbstractType> types) throws ConfigurationException { if (types == null || types.isEmpty()) throw new ConfigurationException("Nonsensical empty parameter list for CompositeType"); CompositeType ct = instances.get(types); if (ct == null) { ct = new CompositeType(types); instances.put(types, ct); } return ct; } private CompositeType(List<AbstractType> types) { this.types = types; } protected AbstractType getNextComparator(int i, ByteBuffer bb) { return types.get(i); } protected AbstractType getNextComparator(int i, ByteBuffer bb1, ByteBuffer bb2) { return types.get(i); } protected AbstractType getAndAppendNextComparator(int i, ByteBuffer bb, StringBuilder sb) { return types.get(i); } protected ParsedComparator parseNextComparator(int i, String part) { return new StaticParsedComparator(types.get(i), part); } protected AbstractType validateNextComparator(int i, ByteBuffer bb) throws MarshalException { if (i >= types.size()) throw new MarshalException("Too many bytes for comparator"); return types.get(i); } private static class StaticParsedComparator implements ParsedComparator { final AbstractType type; final String part; StaticParsedComparator(AbstractType type, String part) { this.type = type; this.part = part; } public AbstractType getAbstractType() { return type; } public String getRemainingPart() { return part; } public int getComparatorSerializedSize() { return 0; } public void serializeComparator(ByteBuffer bb) {} } @Override public String toString() { return getClass().getName() + TypeParser.stringifyTypeParameters(types); } }