All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.driver.mapping.MappingManager Maven / Gradle / Ivy

There is a newer version: 3.11.5
Show newest version
/*
 *      Copyright (C) 2012-2015 DataStax Inc.
 *
 *   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 com.datastax.driver.mapping;

import com.datastax.driver.core.ProtocolVersion;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.mapping.annotations.Accessor;
import com.datastax.driver.mapping.annotations.Table;
import com.datastax.driver.mapping.annotations.UDT;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * Mapping manager from which to obtain entity mappers.
 */
public class MappingManager {

    private final Session session;
    final boolean isCassandraV1;

    private volatile Map, Mapper> mappers = Collections.emptyMap();
    private volatile Map, MappedUDTCodec> udtCodecs = Collections.emptyMap();
    private volatile Map, Object> accessors = Collections.emptyMap();

    /**
     * Creates a new {@code MappingManager} using the provided {@code Session}.
     * 

* Note that this constructor forces the initialization of the session (see * {@link #MappingManager(Session, ProtocolVersion)} if that is a problem for you). * * @param session the {@code Session} to use. */ public MappingManager(Session session) { this(session, getProtocolVersion(session)); } private static ProtocolVersion getProtocolVersion(Session session) { session.init(); return session.getCluster().getConfiguration().getProtocolOptions().getProtocolVersion(); } /** * Creates a new {@code MappingManager} using the provided {@code Session}. *

* This constructor is only provided for backward compatibility: before 2.1.7, {@code MappingManager} could be * built from an uninitialized session; since 2.1.7, the mapper needs to know the active protocol version to * adapt its internal requests, so {@link #MappingManager(Session)} will now initialize the session if needed. * If you rely on the session not being initialized, use this constructor and provide the version manually. * * @param session the {@code Session} to use. * @param protocolVersion the protocol version that will be used with this session. * @since 2.1.7 */ public MappingManager(Session session, ProtocolVersion protocolVersion) { this.session = session; // This is not strictly correct because we could connect to C* 2.0 with the v1 protocol. // But mappers need to make a decision early so that generated queries are compatible, and we don't know in advance // which nodes might join the cluster later. // At least if protocol >=2 we know there won't be any 1.2 nodes ever. this.isCassandraV1 = (protocolVersion == ProtocolVersion.V1); } /** * The underlying {@code Session} used by this manager. *

* Note that you can get obtain the {@code Cluster} object corresponding * to that session using {@code getSession().getCluster()}. *

* It is inadvisable to close the returned Session while this manager and * its mappers are in use. * * @return the underlying session used by this manager. */ public Session getSession() { return session; } /** * Creates a {@code Mapper} for the provided class (that must be annotated by a * {@link Table} annotation). *

* The {@code MappingManager} only ever keeps one Mapper for each class, and so calling this * method multiple times on the same class will always return the same object. *

* If the type of any field in the class is an {@link UDT}-annotated classes, a codec for that * class will automatically be created and registered with the underlying {@code Cluster}. * This works recursively with UDTs nested in other UDTs or in collections. * * @param the type of the class to map. * @param klass the (annotated) class for which to return the mapper. * @return the {@code Mapper} object for class {@code klass}. */ public Mapper mapper(Class klass) { return getMapper(klass); } /** * Creates a {@code TypeCodec} for the provided class (that must be annotated by * a {@link UDT} annotation). *

* This method also registers the codec against the underlying {@code Cluster}. * In addition, the codecs for any nested UDTs will also be created and registered. *

* You don't need to call this method explicitly if you already call {@link #mapper(Class)} * for a class that references this UDT class (creating a mapper will automatically * process all UDTs that it uses). * * @param the type of the class to map. * @param klass the (annotated) class for which to return the codec. * @return the codec that maps the provided class to the corresponding user-defined type. */ public TypeCodec udtCodec(Class klass) { return getUDTCodec(klass); } /** * Creates an accessor object based on the provided interface (that must be annotated by * a {@link Accessor} annotation). *

* The {@code MappingManager} only ever keep one Accessor for each class, and so calling this * method multiple time on the same class will always return the same object. * * @param the type of the accessor class. * @param klass the (annotated) class for which to create an accessor object. * @return the accessor object for class {@code klass}. */ public T createAccessor(Class klass) { return getAccessor(klass); } @SuppressWarnings("unchecked") private Mapper getMapper(Class klass) { Mapper mapper = (Mapper) mappers.get(klass); if (mapper == null) { synchronized (mappers) { mapper = (Mapper) mappers.get(klass); if (mapper == null) { EntityMapper entityMapper = AnnotationParser.parseEntity(klass, ReflectionMapper.factory(), this); mapper = new Mapper(this, klass, entityMapper); Map, Mapper> newMappers = new HashMap, Mapper>(mappers); newMappers.put(klass, mapper); mappers = newMappers; } } } return mapper; } @SuppressWarnings("unchecked") TypeCodec getUDTCodec(Class mappedClass) { MappedUDTCodec codec = (MappedUDTCodec) udtCodecs.get(mappedClass); if (codec == null) { synchronized (udtCodecs) { codec = (MappedUDTCodec) udtCodecs.get(mappedClass); if (codec == null) { codec = AnnotationParser.parseUDT(mappedClass, ReflectionMapper.factory(), this); session.getCluster().getConfiguration().getCodecRegistry().register(codec); HashMap, MappedUDTCodec> newCodecs = new HashMap, MappedUDTCodec>(udtCodecs); newCodecs.put(mappedClass, codec); udtCodecs = newCodecs; } } } return codec; } @SuppressWarnings("unchecked") private T getAccessor(Class klass) { T accessor = (T) accessors.get(klass); if (accessor == null) { synchronized (accessors) { accessor = (T) accessors.get(klass); if (accessor == null) { AccessorMapper mapper = AnnotationParser.parseAccessor(klass, AccessorReflectionMapper.factory(), this); mapper.prepare(this); accessor = mapper.createProxy(); Map, Object> newAccessors = new HashMap, Object>(accessors); newAccessors.put(klass, accessor); accessors = newAccessors; } } } return accessor; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy