blob: 36674d48f50b267b7c2ec3a3785f210a489d0551 [file] [log] [blame]
/*
* 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.affinity;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.apache.ignite.internal.processors.cache.GridCacheDefaultAffinityKeyMapper;
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;
/**
* Optional wrapper for cache keys to provide support
* for custom affinity mapping. The value returned by
* {@link #affinityKey(Object)} method will be used for key-to-node
* affinity.
* <p>
* Note that the {@link #equals(Object)} and {@link #hashCode()} methods
* delegate directly to the wrapped cache key provided by {@link #key()}
* method.
* <p>
* This class is optional and does not have to be used. It only provides
* extra convenience whenever custom affinity mapping is required. Here is
* an example of how {@code Person} objects can be collocated with
* {@code Company} objects they belong to:
* <pre name="code" class="java">
* Object personKey = new AffinityKey(myPersonId, myCompanyId);
*
* // Both, the company and the person objects will be cached on the same node.
* cache.put(myCompanyId, new Company(..));
* cache.put(personKey, new Person(..));
* </pre>
* <p>
* For more information and examples of cache affinity refer to
* {@link AffinityKeyMapper} and {@link AffinityKeyMapped @AffinityKeyMapped}
* documentation.
* @see AffinityKeyMapped
* @see AffinityKeyMapper
* @see AffinityFunction
*/
public class AffinityKey<K> implements Externalizable {
/** */
private static final long serialVersionUID = 0L;
/** Key. */
@GridToStringInclude(sensitive = true)
private K key;
/** Affinity key. */
@AffinityKeyMapped
@GridToStringInclude(sensitive = true)
private Object affKey;
/**
* Empty constructor.
*/
public AffinityKey() {
// No-op.
}
/**
* Initializes key wrapper for a given key. If affinity key
* is not initialized, then this key will be used for affinity.
*
* @param key Key.
*/
public AffinityKey(K key) {
A.notNull(key, "key");
this.key = key;
}
/**
* Initializes key together with its affinity key counter-part.
*
* @param key Key.
* @param affKey Affinity key.
*/
public AffinityKey(K key, Object affKey) {
A.notNull(key, "key");
this.key = key;
this.affKey = affKey;
}
/**
* Gets wrapped key.
*
* @return Wrapped key.
*/
public K key() {
return key;
}
/**
* Sets wrapped key.
*
* @param key Wrapped key.
*/
public void key(K key) {
this.key = key;
}
/**
* Gets affinity key to use for affinity mapping. If affinity key is not provided,
* then {@code key} value will be returned.
* <p>
* This method is annotated with {@link AffinityKeyMapped} and will be picked up
* by {@link GridCacheDefaultAffinityKeyMapper} automatically.
*
* @param <T> Type of affinity key.
*
* @return Affinity key to use for affinity mapping.
*/
public <T> T affinityKey() {
A.notNull(key, "key");
return (T)(affKey == null ? key : affKey);
}
/**
* Sets affinity key to use for affinity mapping. If affinity key is not provided,
* then {@code key} value will be returned.
*
* @param affKey Affinity key to use for affinity mapping.
*/
public void affinityKey(Object affKey) {
this.affKey = affKey;
}
/** {@inheritDoc} */
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(key);
out.writeObject(affKey);
}
/** {@inheritDoc} */
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
key = (K)in.readObject();
affKey = in.readObject();
}
/**
* Hash code implementation which delegates to the underlying {@link #key()}. Note, however,
* that different subclasses of {@link AffinityKey} will produce different hash codes.
* <p>
* Users should override this method if different behavior is desired.
*
* @return Hash code.
*/
@Override public int hashCode() {
A.notNull(key, "key");
return 31 * key.hashCode() + getClass().getName().hashCode();
}
/**
* Equality check which delegates to the underlying key equality. Note, however, that
* different subclasses of {@link AffinityKey} will never be equal.
* <p>
* Users should override this method if different behavior is desired.
*
* @param obj Object to check for equality.
* @return {@code True} if objects are equal.
*/
@Override public boolean equals(Object obj) {
A.notNull(key, "key");
return obj != null && getClass() == obj.getClass() && key.equals(((AffinityKey)obj).key);
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(AffinityKey.class, this);
}
}