/* * 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.internal.processors.query; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cache.QueryIndexType; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.S; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; /** * Descriptor of type. */ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor { /** Space. */ private final String space; /** */ private String name; /** */ private String tblName; /** Value field names and types with preserved order. */ @GridToStringInclude private final Map<String, Class<?>> fields = new LinkedHashMap<>(); /** */ @GridToStringExclude private final Map<String, GridQueryProperty> props = new HashMap<>(); /** Map with upper cased property names to help find properties based on SQL INSERT and MERGE queries. */ private final Map<String, GridQueryProperty> uppercaseProps = new HashMap<>(); /** Mutex for operations on indexes. */ private final Object idxMux = new Object(); /** */ @GridToStringInclude private final Map<String, QueryIndexDescriptorImpl> idxs = new HashMap<>(); /** Aliases. */ private Map<String, String> aliases; /** */ private QueryIndexDescriptorImpl fullTextIdx; /** */ private Class<?> keyCls; /** */ private Class<?> valCls; /** */ private String keyTypeName; /** */ private String valTypeName; /** */ private boolean valTextIdx; /** */ private int typeId; /** */ private String affKey; /** */ private String keyFieldName; /** */ private String valFieldName; /** Obsolete. */ private volatile boolean obsolete; /** * Constructor. * * @param space Cache name. */ public QueryTypeDescriptorImpl(String space) { this.space = space; } /** * @return Space. */ public String space() { return space; } /** {@inheritDoc} */ @Override public String name() { return name; } /** * Sets type name. * * @param name Name. */ public void name(String name) { this.name = name; } /** * Gets table name for type. * @return Table name. */ @Override public String tableName() { return tblName != null ? tblName : name; } /** * Sets table name for type. * * @param tblName Table name. */ public void tableName(String tblName) { this.tblName = tblName; } /** {@inheritDoc} */ @Override public Map<String, Class<?>> fields() { return fields; } /** {@inheritDoc} */ @Override public GridQueryProperty property(String name) { GridQueryProperty res = props.get(name); if (res == null) res = uppercaseProps.get(name.toUpperCase()); return res; } /** * @return Properties. */ public Map<String, GridQueryProperty> properties() { return props; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public <T> T value(String field, Object key, Object val) throws IgniteCheckedException { assert field != null; GridQueryProperty prop = property(field); if (prop == null) throw new IgniteCheckedException("Failed to find field '" + field + "' in type '" + name + "'."); return (T)prop.value(key, val); } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public void setValue(String field, Object key, Object val, Object propVal) throws IgniteCheckedException { assert field != null; GridQueryProperty prop = property(field); if (prop == null) throw new IgniteCheckedException("Failed to find field '" + field + "' in type '" + name + "'."); prop.setValue(key, val, propVal); } /** {@inheritDoc} */ @Override public Map<String, GridQueryIndexDescriptor> indexes() { synchronized (idxMux) { return Collections.<String, GridQueryIndexDescriptor>unmodifiableMap(idxs); } } /** {@inheritDoc} */ @Override public int typeId() { return typeId; } /** * @param typeId Type ID. */ public void typeId(int typeId) { this.typeId = typeId; } /** * Get index by name. * * @param name Name. * @return Index. */ @Nullable public QueryIndexDescriptorImpl index(String name) { synchronized (idxMux) { return idxs.get(name); } } /** * @return Raw index descriptors. */ public Collection<QueryIndexDescriptorImpl> indexes0() { synchronized (idxMux) { return new ArrayList<>(idxs.values()); } } /** {@inheritDoc} */ @Override public GridQueryIndexDescriptor textIndex() { return fullTextIdx; } /** * Add index. * * @param idx Index. * @throws IgniteCheckedException If failed. */ public void addIndex(QueryIndexDescriptorImpl idx) throws IgniteCheckedException { synchronized (idxMux) { if (idxs.put(idx.name(), idx) != null) throw new IgniteCheckedException("Index with name '" + idx.name() + "' already exists."); } } /** * Drop index. * * @param idxName Index name. */ public void dropIndex(String idxName) { synchronized (idxMux) { idxs.remove(idxName); } } /** * Chedk if particular field exists. * * @param field Field. * @return {@code True} if exists. */ public boolean hasField(String field) { return props.containsKey(field) || QueryUtils.VAL_FIELD_NAME.equalsIgnoreCase(field); } /** * Adds field to text index. * * @param field Field name. * @throws IgniteCheckedException If failed. */ public void addFieldToTextIndex(String field) throws IgniteCheckedException { if (fullTextIdx == null) fullTextIdx = new QueryIndexDescriptorImpl(this, null, QueryIndexType.FULLTEXT, 0); fullTextIdx.addField(field, 0, false); } /** {@inheritDoc} */ @Override public Class<?> valueClass() { return valCls; } /** * Sets value class. * * @param valCls Value class. */ public void valueClass(Class<?> valCls) { A.notNull(valCls, "Value class must not be null"); this.valCls = valCls; } /** {@inheritDoc} */ @Override public Class<?> keyClass() { return keyCls; } /** * Set key class. * * @param keyCls Key class. */ public void keyClass(Class<?> keyCls) { this.keyCls = keyCls; } /** {@inheritDoc} */ @Override public String keyTypeName() { return keyTypeName; } /** * Set key type name. * * @param keyTypeName Key type name. */ public void keyTypeName(String keyTypeName) { this.keyTypeName = keyTypeName; } /** {@inheritDoc} */ @Override public String valueTypeName() { return valTypeName; } /** * Set value type name. * * @param valTypeName Value type name. */ public void valueTypeName(String valTypeName) { this.valTypeName = valTypeName; } /** * Adds property to the type descriptor. * * @param prop Property. * @param failOnDuplicate Fail on duplicate flag. * @throws IgniteCheckedException In case of error. */ public void addProperty(GridQueryProperty prop, boolean failOnDuplicate) throws IgniteCheckedException { String name = prop.name(); if (props.put(name, prop) != null && failOnDuplicate) throw new IgniteCheckedException("Property with name '" + name + "' already exists."); if (uppercaseProps.put(name.toUpperCase(), prop) != null && failOnDuplicate) throw new IgniteCheckedException("Property with upper cased name '" + name + "' already exists."); fields.put(name, prop.type()); } /** {@inheritDoc} */ @Override public boolean valueTextIndex() { return valTextIdx; } /** * Sets if this value should be text indexed. * * @param valTextIdx Flag value. */ public void valueTextIndex(boolean valTextIdx) { this.valTextIdx = valTextIdx; } /** {@inheritDoc} */ @Override public String affinityKey() { return affKey; } /** * @param affKey Affinity key field. */ public void affinityKey(String affKey) { this.affKey = affKey; } /** * @return Aliases. */ public Map<String, String> aliases() { return aliases != null ? aliases : Collections.<String, String>emptyMap(); } /** * @param aliases Aliases. */ public void aliases(Map<String, String> aliases) { this.aliases = aliases; } /** * @return {@code True} if obsolete. */ public boolean obsolete() { return obsolete; } /** * Mark index as obsolete. */ public void markObsolete() { obsolete = true; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(QueryTypeDescriptorImpl.class, this); } /** * Sets key field name. * @param keyFieldName Key field name. */ public void keyFieldName(String keyFieldName) { this.keyFieldName = keyFieldName; } /** {@inheritDoc} */ @Override public String keyFieldName() { return keyFieldName; } /** * Sets value field name. * @param valueFieldName value field name. */ public void valueFieldName(String valueFieldName) { this.valFieldName = valueFieldName; } /** {@inheritDoc} */ @Override public String valueFieldName() { return valFieldName; } }