http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/binary/Binarylizable.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/binary/Binarylizable.java b/modules/core/src/main/java/org/apache/ignite/binary/Binarylizable.java new file mode 100644 index 0000000..d09ffc8 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/binary/Binarylizable.java @@ -0,0 +1,48 @@ +/* + * 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.binary; + +/** + * Interface that allows to implement custom serialization + * logic for binary objects. IgniteObject is not required + * to implement this interface, in which case Ignite will automatically + * serialize binary objects using reflection. + * <p> + * This interface, in a way, is analogous to {@link java.io.Externalizable} + * interface, which allows users to override default serialization logic, + * usually for performance reasons. The only difference here is that binary + * serialization is already very fast and implementing custom serialization + * logic for binary does not provide significant performance gains. + */ +public interface Binarylizable { + /** + * Writes fields to provided writer. + * + * @param writer Binary object writer. + * @throws BinaryObjectException In case of error. + */ + public void writeBinary(BinaryWriter writer) throws BinaryObjectException; + + /** + * Reads fields from provided reader. + * + * @param reader Binary object reader. + * @throws BinaryObjectException In case of error. + */ + public void readBinary(BinaryReader reader) throws BinaryObjectException; +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/binary/package-info.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/binary/package-info.java b/modules/core/src/main/java/org/apache/ignite/binary/package-info.java new file mode 100644 index 0000000..5ebf9d8 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/binary/package-info.java @@ -0,0 +1,22 @@ +/* + * 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 description. --> + * Contains Ignite Binary Objects API classes. + */ +package org.apache.ignite.binary; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/cache/CacheKeyConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/CacheKeyConfiguration.java b/modules/core/src/main/java/org/apache/ignite/cache/CacheKeyConfiguration.java new file mode 100644 index 0000000..767b44c --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/cache/CacheKeyConfiguration.java @@ -0,0 +1,92 @@ +/* + * 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; + +import java.io.Serializable; +import org.apache.ignite.internal.util.typedef.internal.S; + +/** + * Configuration defining various aspects of cache keys without explicit usage of annotations on user classes. + */ +public class CacheKeyConfiguration implements Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** Type name. */ + private String typeName; + + /** Affinity key field name. */ + private String affKeyFieldName; + + /** + * Creates an empty cache key configuration that should be populated via setters. + */ + public CacheKeyConfiguration() { + // Convenience no-op constructor. + } + + /** + * Creates cache key configuration with given type name and affinity field name. + * + * @param typeName Type name. + * @param affKeyFieldName Affinity field name. + */ + public CacheKeyConfiguration(String typeName, String affKeyFieldName) { + this.typeName = typeName; + this.affKeyFieldName = affKeyFieldName; + } + + /** + * Sets type name for which affinity field name is being defined. + * + * @return Type name. + */ + public String getTypeName() { + return typeName; + } + + /** + * @param typeName Type name for which affinity field name is being defined. + */ + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + /** + * Gets affinity key field name. + * + * @return Affinity key field name. + */ + public String getAffinityKeyFieldName() { + return affKeyFieldName; + } + + /** + * Sets affinity key field name. + * + * @param affKeyFieldName Affinity key field name. + */ + public void setAffinityKeyFieldName(String affKeyFieldName) { + this.affKeyFieldName = affKeyFieldName; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(CacheKeyConfiguration.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java b/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java index 95a138d..2b7205b 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/CacheTypeMetadata.java @@ -23,9 +23,12 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; +import javax.cache.CacheException; import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStore; +import org.apache.ignite.internal.processors.query.GridQueryProcessor; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiTuple; /** @@ -47,6 +50,9 @@ public class CacheTypeMetadata implements Serializable { /** Value class used to store value in cache. */ private String valType; + /** Simple value type name that will be used as SQL table name.*/ + private String simpleValType; + /** Optional persistent key fields (needed only if {@link CacheJdbcPojoStore} is used). */ @GridToStringInclude private Collection<CacheTypeFieldMetadata> keyFields; @@ -75,22 +81,20 @@ public class CacheTypeMetadata implements Serializable { @GridToStringInclude private Map<String, LinkedHashMap<String, IgniteBiTuple<Class<?>, Boolean>>> grps; + /** */ + @GridToStringInclude + private Map<String,String> aliases; + /** * Default constructor. */ public CacheTypeMetadata() { keyFields = new ArrayList<>(); - valFields = new ArrayList<>(); - qryFlds = new LinkedHashMap<>(); - ascFlds = new LinkedHashMap<>(); - descFlds = new LinkedHashMap<>(); - txtFlds = new LinkedHashSet<>(); - grps = new LinkedHashMap<>(); } @@ -99,25 +103,16 @@ public class CacheTypeMetadata implements Serializable { */ public CacheTypeMetadata(CacheTypeMetadata src) { dbSchema = src.getDatabaseSchema(); - dbTbl = src.getDatabaseTable(); - keyType = src.getKeyType(); - valType = src.getValueType(); - + simpleValType = src.simpleValType; keyFields = new ArrayList<>(src.getKeyFields()); - valFields = new ArrayList<>(src.getValueFields()); - qryFlds = new LinkedHashMap<>(src.getQueryFields()); - ascFlds = new LinkedHashMap<>(src.getAscendingFields()); - descFlds = new LinkedHashMap<>(src.getDescendingFields()); - txtFlds = new LinkedHashSet<>(src.getTextFields()); - grps = new LinkedHashMap<>(src.getGroups()); } @@ -194,12 +189,28 @@ public class CacheTypeMetadata implements Serializable { } /** + * Gets simple value type. + * + * @return Simple value type. + */ + public String getSimpleValueType() { + return simpleValType; + } + + /** * Sets value type. * * @param valType Value type. */ public void setValueType(String valType) { + if (this.valType != null) + throw new CacheException("Value type can be set only once."); + this.valType = valType; + + Class<?> cls = U.classForName(valType, null); + + simpleValType = cls == null ? valType : GridQueryProcessor.typeName(cls); } /** @@ -280,7 +291,10 @@ public class CacheTypeMetadata implements Serializable { * @param ascFlds Name-to-type map for ascending-indexed fields. */ public void setAscendingFields(Map<String, Class<?>> ascFlds) { - this.ascFlds = ascFlds; + if (ascFlds == null) + this.ascFlds = ascFlds; + else + this.ascFlds.putAll(ascFlds); } /** @@ -337,6 +351,25 @@ public class CacheTypeMetadata implements Serializable { this.grps = grps; } + /** + * Sets mapping from full property name in dot notation to an alias that will be used as SQL column name. + * Example: {"parent.name" -> "parentName"}. + * + * @param aliases Aliases. + */ + public void setAliases(Map<String,String> aliases) { + this.aliases = aliases; + } + + /** + * Gets aliases mapping. + * + * @return Aliases. + */ + public Map<String,String> getAliases() { + return aliases; + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(CacheTypeMetadata.class, this); http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/cache/IgniteObject.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/IgniteObject.java b/modules/core/src/main/java/org/apache/ignite/cache/IgniteObject.java deleted file mode 100644 index ab926ce..0000000 --- a/modules/core/src/main/java/org/apache/ignite/cache/IgniteObject.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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; - -import java.io.Serializable; -import org.apache.ignite.portable.PortableException; -import org.jetbrains.annotations.Nullable; - -/** - * Ignite object. Abstracted representation of a binary object form. - */ -public interface IgniteObject extends Serializable { - /** - * Gets object type ID. - * - * @return Type ID. - */ - public int typeId(); - - /** - * Gets field value. - * - * @param fieldName Field name. - * @return Field value. - * @throws PortableException In case of any other error. - */ - @Nullable public <F> F field(String fieldName) throws PortableException; - - /** - * Checks whether field is set. - * - * @param fieldName Field name. - * @return {@code true} if field is set. - */ - public boolean hasField(String fieldName); - - /** - * Gets fully deserialized instance of portable object. - * - * @return Fully deserialized instance of portable object. - * @throws org.apache.ignite.portable.PortableInvalidClassException If class doesn't exist. - * @throws PortableException In case of any other error. - */ - @Nullable public <T> T deserialize() throws PortableException; -} http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java new file mode 100644 index 0000000..cb84c47 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java @@ -0,0 +1,217 @@ +/* + * 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; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.A; + +/** + * Query entity is a description of {@link org.apache.ignite.IgniteCache cache} entry (composed of key and value) + * in a way of how it must be indexed and can be queried. + */ +public class QueryEntity implements Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** Key type. */ + private String keyType; + + /** Value type. */ + private String valType; + + /** Fields available for query. A map from field name to type name. */ + private LinkedHashMap<String, String> fields = new LinkedHashMap<>(); + + /** Aliases. */ + private Map<String, String> aliases = new HashMap<>(); + + /** Collection of query indexes. */ + private Map<String, QueryIndex> idxs = new HashMap<>(); + + /** + * Gets key type for this query pair. + * + * @return Key type. + */ + public String getKeyType() { + return keyType; + } + + /** + * Sets key type for this query pair. + * + * @param keyType Key type. + */ + public void setKeyType(String keyType) { + this.keyType = keyType; + } + + /** + * Gets value type for this query pair. + * + * @return Value type. + */ + public String getValueType() { + return valType; + } + + /** + * Sets value type for this query pair. + * + * @param valType Value type. + */ + public void setValueType(String valType) { + this.valType = valType; + } + + /** + * Gets query fields for this query pair. The order of fields is important as it defines the order + * of columns returned by the 'select *' queries. + * + * @return Field-to-type map. + */ + public LinkedHashMap<String, String> getFields() { + return fields; + } + + /** + * Sets query fields for this query pair. The order if fields is important as it defines the + * order of columns returned by the 'select *' queries. + * + * @param fields Field-to-type map. + */ + public void setFields(LinkedHashMap<String, String> fields) { + this.fields = fields; + } + + /** + * Gets a collection of index entities. + * + * @return Collection of index entities. + */ + public Collection<QueryIndex> getIndexes() { + return idxs.values(); + } + + /** + * Gets aliases map. + * + * @return Aliases. + */ + public Map<String, String> getAliases() { + return aliases; + } + + /** + * Sets mapping from full property name in dot notation to an alias that will be used as SQL column name. + * Example: {"parent.name" -> "parentName"}. + + * @param aliases Aliases map. + */ + public void setAliases(Map<String, String> aliases) { + this.aliases = aliases; + } + + /** + * Sets a collection of index entities. + * + * @param idxs Collection of index entities. + */ + public void setIndexes(Collection<QueryIndex> idxs) { + for (QueryIndex idx : idxs) { + if (!F.isEmpty(idx.getFields())) { + if (idx.getName() == null) + idx.setName(defaultIndexName(idx)); + + if (!this.idxs.containsKey(idx.getName())) + this.idxs.put(idx.getName(), idx); + else + throw new IllegalArgumentException("Duplicate index name: " + idx.getName()); + } + } + } + + /** + * Utility method for building query entities programmatically. + */ + public void addQueryField(String fullName, String type, String alias) { + A.notNull(fullName, "fullName"); + A.notNull(type, "type"); + + fields.put(fullName, type); + + if (alias != null) + aliases.put(fullName, alias); + } + + /** + * Ensures that index with the given name exists. + * + * @param idxName Index name. + * @param idxType Index type. + */ + public void ensureIndex(String idxName, QueryIndexType idxType) { + QueryIndex idx = idxs.get(idxName); + + if (idx == null) { + idx = new QueryIndex(); + + idx.setName(idxName); + idx.setIndexType(idxType); + + idxs.put(idxName, idx); + } + else + throw new IllegalArgumentException("An index with the same name and of a different type already exists " + + "[idxName=" + idxName + ", existingIdxType=" + idx.getIndexType() + ", newIdxType=" + idxType + ']'); + } + + /** + * Generates default index name by concatenating all index field names. + * + * @param idx Index to build name for. + * @return Index name. + */ + public static String defaultIndexName(QueryIndex idx) { + StringBuilder idxName = new StringBuilder(); + + for (Map.Entry<String, Boolean> field : idx.getFields().entrySet()) { + idxName.append(field.getKey()); + + idxName.append('_'); + idxName.append(field.getValue() ? "asc_" : "desc_"); + } + + for (int i = 0; i < idxName.length(); i++) { + char ch = idxName.charAt(i); + + if (Character.isWhitespace(ch)) + idxName.setCharAt(i, '_'); + else + idxName.setCharAt(i, Character.toLowerCase(ch)); + } + + idxName.append("idx"); + + return idxName.toString(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java new file mode 100644 index 0000000..f12044d --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java @@ -0,0 +1,192 @@ +/* + * 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; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashMap; + +/** + * Contains list of fields to be indexed. It is possible to provide field name + * suffixed with index specific extension, for example for {@link QueryIndexType#SORTED sorted} index + * the list can be provided as following {@code (id, name asc, age desc)}. + */ +@SuppressWarnings("TypeMayBeWeakened") +public class QueryIndex implements Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** Index name. */ + private String name; + + /** */ + private LinkedHashMap<String, Boolean> fields; + + /** */ + private QueryIndexType type; + + /** + * Creates an empty index. Should be populated via setters. + */ + public QueryIndex() { + // Empty constructor. + } + + /** + * Creates single-field sorted ascending index. + * + * @param name Field name. + */ + public QueryIndex(String name) { + this(name, QueryIndexType.SORTED, true); + } + + /** + * Creates single-field sorted index. + * + * @param name Field name. + * @param asc Ascending flag. + */ + public QueryIndex(String name, boolean asc) { + this(name, QueryIndexType.SORTED, asc); + } + + /** + * Creates index for one field. + * If index is sorted, then ascending sorting is used by default. + * To specify sort order, use the next method. + * This constructor should also have a corresponding setter method. + */ + public QueryIndex(String field, QueryIndexType type) { + this(Arrays.asList(field), type); + } + + /** + * Creates index for one field. The last boolean parameter + * is ignored for non-sorted indexes. + */ + public QueryIndex(String field, QueryIndexType type, boolean asc) { + fields = new LinkedHashMap<>(); + fields.put(field, asc); + + this.type = type; + } + + /** + * Creates index for a collection of fields. If index is sorted, fields will be sorted in + * ascending order. + * + * @param fields Collection of fields to create an index. + * @param type Index type. + */ + public QueryIndex(Collection<String> fields, QueryIndexType type) { + this.fields = new LinkedHashMap<>(); + + for (String field : fields) + this.fields.put(field, true); + + this.type = type; + } + + /** + * Creates index for a collection of fields. The order of fields in the created index will be the same + * as iteration order in the passed map. Map value defines whether the index will be ascending. + * + * @param fields Field name to field sort direction for sorted indexes. + * @param type Index type. + */ + public QueryIndex(LinkedHashMap<String, Boolean> fields, QueryIndexType type) { + this.fields = fields; + this.type = type; + } + + /** + * Gets index name. Will be automatically set if not provided by a user. + * + * @return Index name. + */ + public String getName() { + return name; + } + + /** + * Sets index name. + * + * @param name Index name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets fields included in the index. + * + * @return Collection of index fields. + */ + public LinkedHashMap<String, Boolean> getFields() { + return fields; + } + + /** + * Sets fields included in the index. + * + * @param fields Collection of index fields. + */ + public void setFields(LinkedHashMap<String, Boolean> fields) { + this.fields = fields; + } + + /** + * @return Gets a collection of field names. + */ + public Collection<String> getFieldNames() { + return fields.keySet(); + } + + /** + * Sets a collection of field names altogether with the field sorting direction. Sorting direction will be + * ignored for non-sorted indexes. + * + * @param fields Collection of fields. + * @param asc Ascending flag. + */ + public void setFieldNames(Collection<String> fields, boolean asc) { + this.fields = new LinkedHashMap<>(); + + for (String field : fields) + this.fields.put(field, asc); + } + + /** + * Gets index type. + * + * @return Index type. + */ + public QueryIndexType getIndexType() { + return type; + } + + /** + * Sets index type. + * + * @param type Index type. + */ + public void setIndexType(QueryIndexType type) { + this.type = type; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/cache/QueryIndexType.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryIndexType.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryIndexType.java new file mode 100644 index 0000000..f9b544d --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryIndexType.java @@ -0,0 +1,38 @@ +/* + * 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; + +/** + * Index type. + */ +public enum QueryIndexType { + /** + * Sorted index. + */ + SORTED, + + /** + * Full-text index. + */ + FULLTEXT, + + /** + * Geo-spatial index. + */ + GEOSPATIAL +} http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java index ae3f21f..af0122f 100644 --- a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java @@ -18,8 +18,22 @@ package org.apache.ignite.configuration; import java.io.Serializable; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeSet; import javax.cache.Cache; +import javax.cache.CacheException; import javax.cache.configuration.CacheEntryListenerConfiguration; import javax.cache.configuration.CompleteConfiguration; import javax.cache.configuration.Factory; @@ -36,14 +50,26 @@ import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cache.CacheRebalanceMode; import org.apache.ignite.cache.CacheTypeMetadata; import org.apache.ignite.cache.CacheWriteSynchronizationMode; +import org.apache.ignite.cache.QueryEntity; +import org.apache.ignite.cache.QueryIndex; +import org.apache.ignite.cache.QueryIndexType; import org.apache.ignite.cache.affinity.AffinityFunction; import org.apache.ignite.cache.affinity.AffinityKeyMapper; import org.apache.ignite.cache.eviction.EvictionFilter; import org.apache.ignite.cache.eviction.EvictionPolicy; +import org.apache.ignite.cache.query.annotations.QueryGroupIndex; +import org.apache.ignite.cache.query.annotations.QuerySqlField; import org.apache.ignite.cache.query.annotations.QuerySqlFunction; +import org.apache.ignite.cache.query.annotations.QueryTextField; import org.apache.ignite.cache.store.CacheStore; import org.apache.ignite.cache.store.CacheStoreSessionListener; import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor; +import org.apache.ignite.internal.processors.query.GridQueryIndexType; +import org.apache.ignite.internal.util.tostring.GridToStringExclude; +import org.apache.ignite.internal.util.tostring.GridToStringInclude; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.T2; import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; @@ -51,14 +77,12 @@ import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.plugin.CachePluginConfiguration; import org.jetbrains.annotations.Nullable; -import javax.cache.Cache; -import javax.cache.configuration.CompleteConfiguration; -import javax.cache.configuration.Factory; -import javax.cache.configuration.MutableConfiguration; -import javax.cache.expiry.ExpiryPolicy; -import java.io.Serializable; -import java.util.Collection; -import java.util.HashSet; +import static org.apache.ignite.internal.processors.query.GridQueryIndexType.FULLTEXT; +import static org.apache.ignite.internal.processors.query.GridQueryIndexType.GEO_SPATIAL; +import static org.apache.ignite.internal.processors.query.GridQueryIndexType.SORTED; +import static org.apache.ignite.internal.processors.query.GridQueryProcessor._VAL; +import static org.apache.ignite.internal.processors.query.GridQueryProcessor.isGeometryClass; +import static org.apache.ignite.internal.processors.query.GridQueryProcessor.isSqlType; /** * This class defines grid cache configuration. This configuration is passed to @@ -330,7 +354,7 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { private boolean sqlEscapeAll; /** */ - private Class<?>[] indexedTypes; + private transient Class<?>[] indexedTypes; /** */ private int sqlOnheapRowCacheSize = DFLT_SQL_ONHEAP_ROW_CACHE_SIZE; @@ -347,6 +371,9 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { /** Cache store session listeners. */ private Factory<? extends CacheStoreSessionListener>[] storeSesLsnrs; + /** Query entities. */ + private Collection<QueryEntity> qryEntities; + /** Empty constructor (all values are initialized to their defaults). */ public CacheConfiguration() { /* No-op. */ @@ -411,6 +438,8 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { name = cc.getName(); nearCfg = cc.getNearConfiguration(); nodeFilter = cc.getNodeFilter(); + pluginCfgs = cc.getPluginConfigurations(); + qryEntities = cc.getQueryEntities(); rebalanceMode = cc.getRebalanceMode(); rebalanceBatchSize = cc.getRebalanceBatchSize(); rebalanceDelay = cc.getRebalanceDelay(); @@ -435,7 +464,6 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { writeBehindFlushSize = cc.getWriteBehindFlushSize(); writeBehindFlushThreadCnt = cc.getWriteBehindFlushThreadCount(); writeSync = cc.getWriteSynchronizationMode(); - pluginCfgs = cc.getPluginConfigurations(); } /** @@ -855,19 +883,19 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { * store implementation in some cases, but it can cause performance * degradation due to additional serializations and deserializations * of portable objects. You will also need to have key and value - * classes on all nodes since portables will be deserialized when + * classes on all nodes since binary will be deserialized when * store is called. * - * @return Keep portables in store flag. + * @return Keep binary in store flag. */ public Boolean isKeepPortableInStore() { return keepPortableInStore; } /** - * Sets keep portables in store flag. + * Sets keep binary in store flag. * - * @param keepPortableInStore Keep portables in store flag. + * @param keepPortableInStore Keep binary in store flag. */ public void setKeepPortableInStore(boolean keepPortableInStore) { this.keepPortableInStore = keepPortableInStore; @@ -1577,9 +1605,10 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { * * @param typeMeta Collection of type metadata. * @return {@code this} for chaining. + * @deprecated Use {@link #setQueryEntities(java.util.Collection)} instead. */ public CacheConfiguration<K, V> setTypeMetadata(Collection<CacheTypeMetadata> typeMeta) { - this.typeMeta = typeMeta; + this.typeMeta = new ArrayList<>(typeMeta); return this; } @@ -1734,21 +1763,39 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { * @return {@code this} for chaining. */ public CacheConfiguration<K, V> setIndexedTypes(Class<?>... indexedTypes) { - A.ensure(indexedTypes == null || (indexedTypes.length & 1) == 0, + A.notNull(indexedTypes, "indexedTypes"); + + int len = indexedTypes.length; + + if (len == 0) + return this; + + A.ensure((len & 1) == 0, "Number of indexed types is expected to be even. Refer to method javadoc for details."); - if (indexedTypes != null) { - int len = indexedTypes.length; + if (this.indexedTypes != null) + throw new CacheException("Indexed types can be set only once."); - Class<?>[] newIndexedTypes = new Class<?>[len]; + Class<?>[] newIndexedTypes = new Class<?>[len]; - for (int i = 0; i < len; i++) - newIndexedTypes[i] = U.box(indexedTypes[i]); + for (int i = 0; i < len; i++) { + if (indexedTypes[i] == null) + throw new NullPointerException("Indexed types array contains null at index: " + i); - this.indexedTypes = newIndexedTypes; + newIndexedTypes[i] = U.box(indexedTypes[i]); + } + + if (qryEntities == null) + qryEntities = new ArrayList<>(); + + for (int i = 0; i < len; i += 2) { + Class<?> keyCls = newIndexedTypes[i]; + Class<?> valCls = newIndexedTypes[i + 1]; + + TypeDescriptor desc = processKeyAndValueClasses(keyCls, valCls); + + qryEntities.add(convert(desc)); } - else - this.indexedTypes = null; return this; } @@ -1800,6 +1847,32 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { } /** + * Gets a collection of configured query entities. + * + * @return Query entities configurations. + */ + public Collection<QueryEntity> getQueryEntities() { + return qryEntities != null ? qryEntities : Collections.<QueryEntity>emptyList(); + } + + /** + * Sets query entities configuration. + * + * @param qryEntities Query entities. + * @return {@code this} for chaining. + */ + public CacheConfiguration<K, V> setQueryEntities(Collection<QueryEntity> qryEntities) { + if (this.qryEntities == null) + this.qryEntities = new ArrayList<>(qryEntities); + else if (indexedTypes != null) + this.qryEntities.addAll(qryEntities); + else + throw new CacheException("Query entities can be set only once."); + + return this; + } + + /** * Gets topology validator. * <p> * See {@link TopologyValidator} for details. @@ -1889,6 +1962,233 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { return cfg; } + /** + * @param desc Type descriptor. + * @return Type metadata. + */ + static QueryEntity convert(TypeDescriptor desc) { + QueryEntity entity = new QueryEntity(); + + // Key and val types. + entity.setKeyType(desc.keyClass().getName()); + entity.setValueType(desc.valueClass().getName()); + + for (ClassProperty prop : desc.props.values()) + entity.addQueryField(prop.fullName(), U.box(prop.type()).getName(), prop.alias()); + + QueryIndex txtIdx = null; + + Collection<QueryIndex> idxs = new ArrayList<>(); + + for (Map.Entry<String, GridQueryIndexDescriptor> idxEntry : desc.indexes().entrySet()) { + GridQueryIndexDescriptor idx = idxEntry.getValue(); + + if (idx.type() == FULLTEXT) { + assert txtIdx == null; + + txtIdx = new QueryIndex(); + + txtIdx.setIndexType(QueryIndexType.FULLTEXT); + + txtIdx.setFieldNames(idx.fields(), true); + txtIdx.setName(idxEntry.getKey()); + } + else { + Collection<String> grp = new ArrayList<>(); + + for (String fieldName : idx.fields()) + grp.add(idx.descending(fieldName) ? fieldName + " desc" : fieldName); + + QueryIndex sortedIdx = new QueryIndex(); + + sortedIdx.setIndexType(idx.type() == SORTED ? QueryIndexType.SORTED : QueryIndexType.GEOSPATIAL); + + LinkedHashMap<String, Boolean> fields = new LinkedHashMap<>(); + + for (String f : idx.fields()) + fields.put(f, !idx.descending(f)); + + sortedIdx.setFields(fields); + + sortedIdx.setName(idxEntry.getKey()); + + idxs.add(sortedIdx); + } + } + + if (desc.valueTextIndex()) { + if (txtIdx == null) { + txtIdx = new QueryIndex(); + + txtIdx.setIndexType(QueryIndexType.FULLTEXT); + + txtIdx.setFieldNames(Arrays.asList(_VAL), true); + } + else + txtIdx.getFields().put(_VAL, true); + } + + if (txtIdx != null) + idxs.add(txtIdx); + + if (!F.isEmpty(idxs)) + entity.setIndexes(idxs); + + return entity; + } + + /** + * @param cls Class. + * @return Masked class. + */ + private static Class<?> mask(Class<?> cls) { + assert cls != null; + + return isSqlType(cls) ? cls : Object.class; + } + + /** + * @param keyCls Key class. + * @param valCls Value class. + * @return Type descriptor. + */ + static TypeDescriptor processKeyAndValueClasses( + Class<?> keyCls, + Class<?> valCls + ) { + TypeDescriptor d = new TypeDescriptor(); + + d.keyClass(keyCls); + d.valueClass(valCls); + + processAnnotationsInClass(true, d.keyCls, d, null); + processAnnotationsInClass(false, d.valCls, d, null); + + return d; + } + + /** + * Process annotations for class. + * + * @param key If given class relates to key. + * @param cls Class. + * @param type Type descriptor. + * @param parent Parent in case of embeddable. + */ + private static void processAnnotationsInClass(boolean key, Class<?> cls, TypeDescriptor type, + @Nullable ClassProperty parent) { + if (U.isJdk(cls) || isGeometryClass(cls)) { + if (parent == null && !key && isSqlType(cls)) { // We have to index primitive _val. + String idxName = _VAL + "_idx"; + + type.addIndex(idxName, isGeometryClass(cls) ? GEO_SPATIAL : SORTED); + + type.addFieldToIndex(idxName, _VAL, 0, false); + } + + return; + } + + if (parent != null && parent.knowsClass(cls)) + throw new CacheException("Recursive reference found in type: " + cls.getName()); + + if (parent == null) { // Check class annotation at top level only. + QueryTextField txtAnnCls = cls.getAnnotation(QueryTextField.class); + + if (txtAnnCls != null) + type.valueTextIndex(true); + + QueryGroupIndex grpIdx = cls.getAnnotation(QueryGroupIndex.class); + + if (grpIdx != null) + type.addIndex(grpIdx.name(), SORTED); + + QueryGroupIndex.List grpIdxList = cls.getAnnotation(QueryGroupIndex.List.class); + + if (grpIdxList != null && !F.isEmpty(grpIdxList.value())) { + for (QueryGroupIndex idx : grpIdxList.value()) + type.addIndex(idx.name(), SORTED); + } + } + + for (Class<?> c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) { + for (Field field : c.getDeclaredFields()) { + QuerySqlField sqlAnn = field.getAnnotation(QuerySqlField.class); + QueryTextField txtAnn = field.getAnnotation(QueryTextField.class); + + if (sqlAnn != null || txtAnn != null) { + ClassProperty prop = new ClassProperty(field); + + prop.parent(parent); + + processAnnotation(key, sqlAnn, txtAnn, field.getType(), prop, type); + + type.addProperty(prop, true); + } + } + + for (Method mtd : c.getDeclaredMethods()) { + QuerySqlField sqlAnn = mtd.getAnnotation(QuerySqlField.class); + QueryTextField txtAnn = mtd.getAnnotation(QueryTextField.class); + + if (sqlAnn != null || txtAnn != null) { + if (mtd.getParameterTypes().length != 0) + throw new CacheException("Getter with QuerySqlField " + + "annotation cannot have parameters: " + mtd); + + ClassProperty prop = new ClassProperty(mtd); + + prop.parent(parent); + + processAnnotation(key, sqlAnn, txtAnn, mtd.getReturnType(), prop, type); + + type.addProperty(prop, true); + } + } + } + } + + /** + * Processes annotation at field or method. + * + * @param key If given class relates to key. + * @param sqlAnn SQL annotation, can be {@code null}. + * @param txtAnn H2 text annotation, can be {@code null}. + * @param cls Class of field or return type for method. + * @param prop Current property. + * @param desc Class description. + */ + private static void processAnnotation(boolean key, QuerySqlField sqlAnn, QueryTextField txtAnn, + Class<?> cls, ClassProperty prop, TypeDescriptor desc) { + if (sqlAnn != null) { + processAnnotationsInClass(key, cls, desc, prop); + + if (!sqlAnn.name().isEmpty()) + prop.alias(sqlAnn.name()); + + if (sqlAnn.index()) { + String idxName = prop.alias() + "_idx"; + + desc.addIndex(idxName, isGeometryClass(prop.type()) ? GEO_SPATIAL : SORTED); + + desc.addFieldToIndex(idxName, prop.fullName(), 0, sqlAnn.descending()); + } + + if (!F.isEmpty(sqlAnn.groups())) { + for (String group : sqlAnn.groups()) + desc.addFieldToIndex(group, prop.fullName(), 0, false); + } + + if (!F.isEmpty(sqlAnn.orderedGroups())) { + for (QuerySqlField.Group idx : sqlAnn.orderedGroups()) + desc.addFieldToIndex(idx.name(), prop.fullName(), idx.order(), idx.descending()); + } + } + + if (txtAnn != null) + desc.addFieldToTextIndex(prop.fullName()); + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(CacheConfiguration.class, this); @@ -1908,10 +2208,318 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> { /** {@inheritDoc} */ @Override public boolean equals(Object obj) { - if (obj == null) - return false; + return obj != null && obj.getClass().equals(this.getClass()); + } + } + + /** + * Descriptor of type. + */ + private static class TypeDescriptor { + /** Value field names and types with preserved order. */ + @GridToStringInclude + private final Map<String, Class<?>> fields = new LinkedHashMap<>(); + + /** */ + @GridToStringExclude + private final Map<String, ClassProperty> props = new LinkedHashMap<>(); + + /** */ + @GridToStringInclude + private final Map<String, IndexDescriptor> indexes = new HashMap<>(); + + /** */ + private IndexDescriptor fullTextIdx; + + /** */ + private Class<?> keyCls; + + /** */ + private Class<?> valCls; + + /** */ + private boolean valTextIdx; + + /** + * @return Indexes. + */ + public Map<String, GridQueryIndexDescriptor> indexes() { + return Collections.<String, GridQueryIndexDescriptor>unmodifiableMap(indexes); + } + + /** + * Adds index. + * + * @param idxName Index name. + * @param type Index type. + * @return Index descriptor. + */ + public IndexDescriptor addIndex(String idxName, GridQueryIndexType type) { + IndexDescriptor idx = new IndexDescriptor(type); + + if (indexes.put(idxName, idx) != null) + throw new CacheException("Index with name '" + idxName + "' already exists."); + + return idx; + } + + /** + * Adds field to index. + * + * @param idxName Index name. + * @param field Field name. + * @param orderNum Fields order number in index. + * @param descending Sorting order. + */ + public void addFieldToIndex(String idxName, String field, int orderNum, + boolean descending) { + IndexDescriptor desc = indexes.get(idxName); + + if (desc == null) + desc = addIndex(idxName, SORTED); + + desc.addField(field, orderNum, descending); + } + + /** + * Adds field to text index. + * + * @param field Field name. + */ + public void addFieldToTextIndex(String field) { + if (fullTextIdx == null) { + fullTextIdx = new IndexDescriptor(FULLTEXT); + + indexes.put(null, fullTextIdx); + } + + fullTextIdx.addField(field, 0, false); + } + + /** + * @return Value class. + */ + public Class<?> valueClass() { + return valCls; + } + + /** + * Sets value class. + * + * @param valCls Value class. + */ + void valueClass(Class<?> valCls) { + this.valCls = valCls; + } + + /** + * @return Key class. + */ + public Class<?> keyClass() { + return keyCls; + } + + /** + * Set key class. + * + * @param keyCls Key class. + */ + void keyClass(Class<?> keyCls) { + this.keyCls = keyCls; + } + + /** + * Adds property to the type descriptor. + * + * @param prop Property. + * @param failOnDuplicate Fail on duplicate flag. + */ + public void addProperty(ClassProperty prop, boolean failOnDuplicate) { + String name = prop.fullName(); + + if (props.put(name, prop) != null && failOnDuplicate) + throw new CacheException("Property with name '" + name + "' already exists."); + + fields.put(name, prop.type()); + } + + /** + * @return {@code true} If we need to have a fulltext index on value. + */ + 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 toString() { + return S.toString(TypeDescriptor.class, this); + } + } + + /** + * Index descriptor. + */ + private static class IndexDescriptor implements GridQueryIndexDescriptor { + /** Fields sorted by order number. */ + private final Collection<T2<String, Integer>> fields = new TreeSet<>( + new Comparator<T2<String, Integer>>() { + @Override public int compare(T2<String, Integer> o1, T2<String, Integer> o2) { + if (o1.get2().equals(o2.get2())) // Order is equal, compare field names to avoid replace in Set. + return o1.get1().compareTo(o2.get1()); + + return o1.get2() < o2.get2() ? -1 : 1; + } + }); + + /** Fields which should be indexed in descending order. */ + private Collection<String> descendings; + + /** */ + private final GridQueryIndexType type; + + /** + * @param type Type. + */ + private IndexDescriptor(GridQueryIndexType type) { + assert type != null; + + this.type = type; + } + + /** {@inheritDoc} */ + @Override public Collection<String> fields() { + Collection<String> res = new ArrayList<>(fields.size()); + + for (T2<String, Integer> t : fields) + res.add(t.get1()); + + return res; + } + + /** {@inheritDoc} */ + @Override public boolean descending(String field) { + return descendings != null && descendings.contains(field); + } + + /** + * Adds field to this index. + * + * @param field Field name. + * @param orderNum Field order number in this index. + * @param descending Sort order. + */ + public void addField(String field, int orderNum, boolean descending) { + fields.add(new T2<>(field, orderNum)); + + if (descending) { + if (descendings == null) + descendings = new HashSet<>(); + + descendings.add(field); + } + } + + /** {@inheritDoc} */ + @Override public GridQueryIndexType type() { + return type; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(IndexDescriptor.class, this); + } + } + + /** + * Description of type property. + */ + private static class ClassProperty { + /** */ + private final Member member; + + /** */ + private ClassProperty parent; + + /** */ + private String name; + + /** */ + private String alias; + + /** + * Constructor. + * + * @param member Element. + */ + ClassProperty(Member member) { + this.member = member; + + name = member instanceof Method && member.getName().startsWith("get") && member.getName().length() > 3 ? + member.getName().substring(3) : member.getName(); + + ((AccessibleObject) member).setAccessible(true); + } + + /** + * @param alias Alias. + */ + public void alias(String alias) { + this.alias = alias; + } + + /** + * @return Alias. + */ + String alias() { + return F.isEmpty(alias) ? name : alias; + } + + /** + * @return Type. + */ + public Class<?> type() { + return member instanceof Field ? ((Field)member).getType() : ((Method)member).getReturnType(); + } + + /** + * @param parent Parent property if this is embeddable element. + */ + public void parent(ClassProperty parent) { + this.parent = parent; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(ClassProperty.class, this); + } + + /** + * @param cls Class. + * @return {@code true} If this property or some parent relates to member of the given class. + */ + public boolean knowsClass(Class<?> cls) { + return member.getDeclaringClass() == cls || (parent != null && parent.knowsClass(cls)); + } + + /** + * @return Full name with all parents in dot notation. + */ + public String fullName() { + assert name != null; + + if (parent == null) + return name; - return obj.getClass().equals(this.getClass()); + return parent.fullName() + '.' + name; } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java index 3d38ed9..a91aa7e 100644 --- a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java @@ -31,6 +31,7 @@ import javax.net.ssl.SSLContext; import org.apache.ignite.IgniteLogger; import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.Ignition; +import org.apache.ignite.cache.CacheKeyConfiguration; import org.apache.ignite.cache.store.CacheStoreSessionListener; import org.apache.ignite.cluster.ClusterGroup; import org.apache.ignite.cluster.ClusterNode; @@ -427,6 +428,9 @@ public class IgniteConfiguration { /** Platform configuration. */ private PlatformConfiguration platformCfg; + /** Cache key configuration. */ + private CacheKeyConfiguration[] cacheKeyCfg; + /** * Creates valid grid configuration with all default values. */ @@ -463,6 +467,7 @@ public class IgniteConfiguration { atomicCfg = cfg.getAtomicConfiguration(); daemon = cfg.isDaemon(); cacheCfg = cfg.getCacheConfiguration(); + cacheKeyCfg = cfg.getCacheKeyConfiguration(); cacheSanityCheckEnabled = cfg.isCacheSanityCheckEnabled(); connectorCfg = cfg.getConnectorConfiguration(); classLdr = cfg.getClassLoader(); @@ -1950,6 +1955,25 @@ public class IgniteConfiguration { } /** + * Gets cache key configuration. + * + * @return Cache key configuration. + */ + public CacheKeyConfiguration[] getCacheKeyConfiguration() { + return cacheKeyCfg; + } + + /** + * Sets cache key configuration. + * Cache key configuration defines + * + * @param cacheKeyCfg Cache key configuration. + */ + public void setCacheKeyCfg(CacheKeyConfiguration... cacheKeyCfg) { + this.cacheKeyCfg = cacheKeyCfg; + } + + /** * Gets flag indicating whether cache sanity check is enabled. If enabled, then Ignite * will perform the following checks and throw an exception if check fails: * <ul> http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java index ebf83bd..4990dc7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java @@ -49,7 +49,7 @@ import org.apache.ignite.internal.managers.swapspace.GridSwapSpaceManager; import org.apache.ignite.internal.processors.affinity.GridAffinityProcessor; import org.apache.ignite.internal.processors.cache.CacheConflictResolutionManager; import org.apache.ignite.internal.processors.cache.GridCacheProcessor; -import org.apache.ignite.internal.processors.cache.portable.CacheObjectPortableProcessorImpl; +import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessorImpl; import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor; import org.apache.ignite.internal.processors.clock.GridClockSource; import org.apache.ignite.internal.processors.clock.GridClockSyncProcessor; @@ -830,7 +830,7 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable return res; if (cls.equals(IgniteCacheObjectProcessor.class)) - return (T)new CacheObjectPortableProcessorImpl(this); + return (T)new CacheObjectBinaryProcessorImpl(this); if (cls.equals(CacheConflictResolutionManager.class)) return null; http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index a7e62b0..88e697c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -64,7 +64,7 @@ import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteFileSystem; import org.apache.ignite.IgniteLogger; import org.apache.ignite.IgniteMessaging; -import org.apache.ignite.IgnitePortables; +import org.apache.ignite.IgniteBinary; import org.apache.ignite.IgniteQueue; import org.apache.ignite.IgniteScheduler; import org.apache.ignite.IgniteServices; @@ -102,8 +102,8 @@ import org.apache.ignite.internal.processors.cache.GridCacheProcessor; import org.apache.ignite.internal.processors.cache.GridCacheUtilityKey; import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; import org.apache.ignite.internal.processors.cache.IgniteInternalCache; -import org.apache.ignite.internal.processors.cache.portable.CacheObjectPortableProcessor; -import org.apache.ignite.internal.processors.cache.portable.CacheObjectPortableProcessorImpl; +import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessor; +import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessorImpl; import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor; import org.apache.ignite.internal.processors.clock.GridClockSyncProcessor; import org.apache.ignite.internal.processors.closure.GridClosureProcessor; @@ -157,7 +157,6 @@ import org.apache.ignite.lifecycle.LifecycleBean; import org.apache.ignite.lifecycle.LifecycleEventType; import org.apache.ignite.marshaller.MarshallerExclusions; import org.apache.ignite.marshaller.optimized.OptimizedMarshaller; -import org.apache.ignite.marshaller.portable.PortableMarshaller; import org.apache.ignite.mxbean.ClusterLocalNodeMetricsMXBean; import org.apache.ignite.mxbean.IgniteMXBean; import org.apache.ignite.mxbean.ThreadPoolMXBean; @@ -1490,6 +1489,8 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable { mgr.start(); } catch (IgniteCheckedException e) { + U.error(log, "Failed to start manager: " + mgr , e); + throw new IgniteCheckedException("Failed to start manager: " + mgr, e); } } @@ -2789,8 +2790,10 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable { } /** {@inheritDoc} */ - @Override public IgnitePortables portables() { - return ((CacheObjectPortableProcessor)ctx.cacheObjects()).portables(); + @Override public IgniteBinary binary() { + IgniteCacheObjectProcessor objProc = ctx.cacheObjects(); + + return objProc.binary(); } /** {@inheritDoc} */ @@ -3088,7 +3091,7 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable { return comp; if (cls.equals(IgniteCacheObjectProcessor.class)) - return (T)new CacheObjectPortableProcessorImpl(ctx); + return (T)new CacheObjectBinaryProcessorImpl(ctx); if (cls.equals(DiscoveryNodeValidationProcessor.class)) return (T)new OsDiscoveryNodeValidationProcessor(ctx); http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/internal/client/GridClientCompute.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/GridClientCompute.java b/modules/core/src/main/java/org/apache/ignite/internal/client/GridClientCompute.java index c907779..e7255f9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/GridClientCompute.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/GridClientCompute.java @@ -414,7 +414,7 @@ public interface GridClientCompute { public GridClientFuture<List<GridClientNode>> refreshTopologyAsync(boolean includeAttrs, boolean includeMetrics); /** - * Sets keep portables flag for the next task execution in the current thread. + * Sets keep binary flag for the next task execution in the current thread. */ public GridClientCompute withKeepPortables(); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnection.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnection.java index fedd15a..8bdb1d0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnection.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnection.java @@ -313,7 +313,7 @@ public abstract class GridClientConnection { * @param taskName Task name. * @param arg Task argument. * @param destNodeId Destination node ID. - * @param keepPortables Keep portables flag. + * @param keepPortables Keep binary flag. * @return Task execution result. * @throws GridClientConnectionResetException In case of error. * @throws GridClientClosedException If client was manually closed before request was sent over network. http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnectionManagerAdapter.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnectionManagerAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnectionManagerAdapter.java index f1a9af1..dedee10 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnectionManagerAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientConnectionManagerAdapter.java @@ -483,7 +483,7 @@ public abstract class GridClientConnectionManagerAdapter implements GridClientCo } /** - * @return Get thread local used to enable keep portables mode. + * @return Get thread local used to enable keep binary mode. */ protected ThreadLocal<Boolean> keepPortablesThreadLocal() { return null; http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientNioTcpConnection.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientNioTcpConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientNioTcpConnection.java index eee2858..24c9c70 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientNioTcpConnection.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/client/impl/connection/GridClientNioTcpConnection.java @@ -385,7 +385,7 @@ public class GridClientNioTcpConnection extends GridClientConnection { * * @param msg Message to request, * @param destId Destination node identifier. - * @param keepPortables Keep portables flag. + * @param keepPortables Keep binary flag. * @return Response object. * @throws GridClientConnectionResetException If request failed. * @throws GridClientClosedException If client was closed. @@ -1037,7 +1037,7 @@ public class GridClientNioTcpConnection extends GridClientConnection { /** Flag indicating if connected message is a forwarded. */ private final boolean forward; - /** Keep portables flag. */ + /** Keep binary flag. */ private final boolean keepPortables; /** Pending message for this future. */ @@ -1101,7 +1101,7 @@ public class GridClientNioTcpConnection extends GridClientConnection { } /** - * @return Keep portables flag. + * @return Keep binary flag. */ public boolean keepPortables() { return keepPortables; http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java index 079015c..623da66 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java @@ -31,7 +31,7 @@ import org.apache.ignite.internal.managers.deployment.GridDeploymentInfoBean; import org.apache.ignite.internal.managers.deployment.GridDeploymentRequest; import org.apache.ignite.internal.managers.deployment.GridDeploymentResponse; import org.apache.ignite.internal.managers.eventstorage.GridEventStorageMessage; -import org.apache.ignite.internal.portable.PortableObjectImpl; +import org.apache.ignite.internal.portable.BinaryObjectImpl; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheEntryInfoCollection; import org.apache.ignite.internal.processors.cache.CacheEntryPredicateContainsValue; @@ -680,7 +680,7 @@ public class GridIoMessageFactory implements MessageFactory { break; case 113: - msg = new PortableObjectImpl(); + msg = new BinaryObjectImpl(); break; http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/internal/managers/swapspace/GridSwapSpaceManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/swapspace/GridSwapSpaceManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/swapspace/GridSwapSpaceManager.java index f90cf4f..437603a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/swapspace/GridSwapSpaceManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/swapspace/GridSwapSpaceManager.java @@ -221,22 +221,6 @@ public class GridSwapSpaceManager extends GridManagerAdapter<SwapSpaceSpi> { } /** - * Writes value to swap. - * - * @param spaceName Space name. - * @param key Key. - * @param val Value. - * @param ldr Class loader (optional). - * @throws IgniteCheckedException If failed. - */ - public void write(@Nullable String spaceName, Object key, @Nullable Object val, @Nullable ClassLoader ldr) - throws IgniteCheckedException { - assert key != null; - - write(spaceName, new SwapKey(key), marshal(val), ldr); - } - - /** * Removes value from swap. * * @param spaceName Space name. @@ -284,24 +268,6 @@ public class GridSwapSpaceManager extends GridManagerAdapter<SwapSpaceSpi> { } /** - * Removes value from swap. - * - * @param spaceName Space name. - * @param key Key. - * @param c Optional closure that takes removed value and executes after actual - * removing. If there was no value in storage the closure is executed given - * {@code null} value as parameter. - * @param ldr Class loader (optional). - * @throws IgniteCheckedException If failed. - */ - public void remove(@Nullable String spaceName, Object key, @Nullable IgniteInClosure<byte[]> c, - @Nullable ClassLoader ldr) throws IgniteCheckedException { - assert key != null; - - remove(spaceName, new SwapKey(key), c, ldr); - } - - /** * Gets size in bytes for swap space. * * @param spaceName Space name. http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldImpl.java new file mode 100644 index 0000000..b8a25c1 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryFieldImpl.java @@ -0,0 +1,104 @@ +/* + * 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.portable; + +import org.apache.ignite.internal.util.tostring.GridToStringExclude; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.binary.BinaryObject; +import org.apache.ignite.binary.BinaryField; + +/** + * Implementation of portable field descriptor. + */ +public class BinaryFieldImpl implements BinaryField { + /** Well-known object schemas. */ + @GridToStringExclude + private final PortableSchemaRegistry schemas; + + /** Field name. */ + private final String fieldName; + + /** Pre-calculated field ID. */ + private final int fieldId; + + /** + * Constructor. + * + * @param schemas Schemas. + * @param fieldName Field name. + * @param fieldId Field ID. + */ + public BinaryFieldImpl(PortableSchemaRegistry schemas, String fieldName, int fieldId) { + assert schemas != null; + assert fieldName != null; + assert fieldId != 0; + + this.schemas = schemas; + this.fieldName = fieldName; + this.fieldId = fieldId; + } + + /** {@inheritDoc} */ + @Override public String name() { + return fieldName; + } + + /** {@inheritDoc} */ + @Override public boolean exists(BinaryObject obj) { + BinaryObjectEx obj0 = (BinaryObjectEx)obj; + + return fieldOrder(obj0) != PortableSchema.ORDER_NOT_FOUND; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public <T> T value(BinaryObject obj) { + BinaryObjectEx obj0 = (BinaryObjectEx)obj; + + int order = fieldOrder(obj0); + + return order != PortableSchema.ORDER_NOT_FOUND ? (T)obj0.fieldByOrder(order) : null; + } + + /** + * Get relative field offset. + * + * @param obj Object. + * @return Field offset. + */ + private int fieldOrder(BinaryObjectEx obj) { + int schemaId = obj.schemaId(); + + PortableSchema schema = schemas.schema(schemaId); + + if (schema == null) { + schema = obj.createSchema(); + + schemas.addSchema(schemaId, schema); + } + + assert schema != null; + + return schema.order(fieldId); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(BinaryFieldImpl.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/b783d2b7/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetaDataCollector.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetaDataCollector.java b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetaDataCollector.java new file mode 100644 index 0000000..b053a55 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryMetaDataCollector.java @@ -0,0 +1,263 @@ +/* + * 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.portable; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.apache.ignite.binary.BinaryObjectException; +import org.apache.ignite.binary.BinaryRawWriter; +import org.apache.ignite.binary.BinaryWriter; +import org.jetbrains.annotations.Nullable; + +/** + * Writer for meta data collection. + */ +class BinaryMetaDataCollector implements BinaryWriter { + /** */ + private final Map<String, String> meta = new HashMap<>(); + + /** */ + private final String typeName; + + /** + * @param typeName Type name. + */ + BinaryMetaDataCollector(String typeName) { + this.typeName = typeName; + } + + /** + * @return Field meta data. + */ + Map<String, String> meta() { + return meta; + } + + /** {@inheritDoc} */ + @Override public void writeByte(String fieldName, byte val) throws BinaryObjectException { + add(fieldName, byte.class); + } + + /** {@inheritDoc} */ + @Override public void writeShort(String fieldName, short val) throws BinaryObjectException { + add(fieldName, short.class); + } + + /** {@inheritDoc} */ + @Override public void writeInt(String fieldName, int val) throws BinaryObjectException { + add(fieldName, int.class); + } + + /** {@inheritDoc} */ + @Override public void writeLong(String fieldName, long val) throws BinaryObjectException { + add(fieldName, long.class); + } + + /** {@inheritDoc} */ + @Override public void writeFloat(String fieldName, float val) throws BinaryObjectException { + add(fieldName, float.class); + } + + /** {@inheritDoc} */ + @Override public void writeDouble(String fieldName, double val) throws BinaryObjectException { + add(fieldName, double.class); + } + + /** {@inheritDoc} */ + @Override public void writeChar(String fieldName, char val) throws BinaryObjectException { + add(fieldName, char.class); + } + + /** {@inheritDoc} */ + @Override public void writeBoolean(String fieldName, boolean val) throws BinaryObjectException { + add(fieldName, boolean.class); + } + + /** {@inheritDoc} */ + @Override public void writeDecimal(String fieldName, @Nullable BigDecimal val) throws BinaryObjectException { + add(fieldName, PortableClassDescriptor.Mode.DECIMAL.typeName()); + } + + /** {@inheritDoc} */ + @Override public void writeString(String fieldName, @Nullable String val) throws BinaryObjectException { + add(fieldName, String.class); + } + + /** {@inheritDoc} */ + @Override public void writeUuid(String fieldName, @Nullable UUID val) throws BinaryObjectException { + add(fieldName, UUID.class); + } + + /** {@inheritDoc} */ + @Override public void writeDate(String fieldName, @Nullable Date val) throws BinaryObjectException { + add(fieldName, Date.class); + } + + /** {@inheritDoc} */ + @Override public void writeTimestamp(String fieldName, @Nullable Timestamp val) throws BinaryObjectException { + add(fieldName, Timestamp.class); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws BinaryObjectException { + add(fieldName, Enum.class); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws BinaryObjectException { + add(fieldName, Enum[].class); + } + + /** {@inheritDoc} */ + @Override public void writeObject(String fieldName, @Nullable Object obj) throws BinaryObjectException { + add(fieldName, Object.class); + } + + /** {@inheritDoc} */ + @Override public void writeByteArray(String fieldName, @Nullable byte[] val) throws BinaryObjectException { + add(fieldName, byte[].class); + } + + /** {@inheritDoc} */ + @Override public void writeShortArray(String fieldName, @Nullable short[] val) throws BinaryObjectException { + add(fieldName, short[].class); + } + + /** {@inheritDoc} */ + @Override public void writeIntArray(String fieldName, @Nullable int[] val) throws BinaryObjectException { + add(fieldName, int[].class); + } + + /** {@inheritDoc} */ + @Override public void writeLongArray(String fieldName, @Nullable long[] val) throws BinaryObjectException { + add(fieldName, long[].class); + } + + /** {@inheritDoc} */ + @Override public void writeFloatArray(String fieldName, @Nullable float[] val) throws BinaryObjectException { + add(fieldName, float[].class); + } + + /** {@inheritDoc} */ + @Override public void writeDoubleArray(String fieldName, @Nullable double[] val) throws BinaryObjectException { + add(fieldName, double[].class); + } + + /** {@inheritDoc} */ + @Override public void writeCharArray(String fieldName, @Nullable char[] val) throws BinaryObjectException { + add(fieldName, char[].class); + } + + /** {@inheritDoc} */ + @Override public void writeBooleanArray(String fieldName, @Nullable boolean[] val) throws BinaryObjectException { + add(fieldName, boolean[].class); + } + + /** {@inheritDoc} */ + @Override public void writeDecimalArray(String fieldName, @Nullable BigDecimal[] val) throws BinaryObjectException { + add(fieldName, PortableClassDescriptor.Mode.DECIMAL_ARR.typeName()); + } + + /** {@inheritDoc} */ + @Override public void writeStringArray(String fieldName, @Nullable String[] val) throws BinaryObjectException { + add(fieldName, String[].class); + } + + /** {@inheritDoc} */ + @Override public void writeUuidArray(String fieldName, @Nullable UUID[] val) throws BinaryObjectException { + add(fieldName, UUID[].class); + } + + /** {@inheritDoc} */ + @Override public void writeDateArray(String fieldName, @Nullable Date[] val) throws BinaryObjectException { + add(fieldName, Date[].class); + } + + /** {@inheritDoc} */ + @Override public void writeTimestampArray(String fieldName, @Nullable Timestamp[] val) throws BinaryObjectException { + add(fieldName, Timestamp[].class); + } + + /** {@inheritDoc} */ + @Override public void writeObjectArray(String fieldName, @Nullable Object[] val) throws BinaryObjectException { + add(fieldName, Object[].class); + } + + /** {@inheritDoc} */ + @Override public <T> void writeCollection(String fieldName, @Nullable Collection<T> col) + throws BinaryObjectException { + add(fieldName, Collection.class); + } + + /** {@inheritDoc} */ + @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map) throws BinaryObjectException { + add(fieldName, Map.class); + } + + /** {@inheritDoc} */ + @Override public BinaryRawWriter rawWriter() { + return (BinaryRawWriter)Proxy.newProxyInstance(getClass().getClassLoader(), + new Class<?>[] { BinaryRawWriterEx.class }, + new InvocationHandler() { + @Override public Object invoke(Object proxy, Method mtd, Object[] args) throws Throwable { + return null; + } + }); + } + + /** + * @param name Field name. + * @param fieldType Field type. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + private void add(String name, Class<?> fieldType) throws BinaryObjectException { + assert fieldType != null; + + add(name, fieldType.getSimpleName()); + } + + /** + * @param name Field name. + * @param fieldTypeName Field type name. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + private void add(String name, String fieldTypeName) throws BinaryObjectException { + assert name != null; + + String oldFieldTypeName = meta.put(name, fieldTypeName); + + if (oldFieldTypeName != null && !oldFieldTypeName.equals(fieldTypeName)) { + throw new BinaryObjectException( + "Field is written twice with different types [" + + "typeName=" + typeName + + ", fieldName=" + name + + ", fieldTypeName1=" + oldFieldTypeName + + ", fieldTypeName2=" + fieldTypeName + + ']' + ); + } + } +} \ No newline at end of file
