Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.gridgain.grid.spi.GridSpiAdapter Maven / Gradle / Ivy
/*
Copyright (C) GridGain Systems. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* _________ _____ __________________ _____
* __ ____/___________(_)______ /__ ____/______ ____(_)_______
* _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \
* / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / /
* \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/
*/
package org.gridgain.grid.spi;
import org.gridgain.grid.*;
import org.gridgain.grid.events.*;
import org.gridgain.grid.kernal.*;
import org.gridgain.grid.kernal.managers.communication.*;
import org.gridgain.grid.kernal.managers.eventstorage.*;
import org.gridgain.grid.logger.*;
import org.gridgain.grid.resources.*;
import org.gridgain.grid.spi.swapspace.*;
import org.gridgain.grid.util.json.*;
import org.gridgain.grid.util.typedef.*;
import org.gridgain.grid.util.typedef.internal.*;
import org.jetbrains.annotations.*;
import javax.management.*;
import java.io.*;
import java.nio.*;
import java.text.*;
import java.util.*;
import static org.gridgain.grid.events.GridEventType.*;
/**
* This class provides convenient adapter for SPI implementations.
*/
public abstract class GridSpiAdapter implements GridSpi, GridSpiManagementMBean, GridSpiJsonConfigurable {
/** Instance of SPI annotation. */
private GridSpiInfo spiAnn;
/** */
private ObjectName spiMBean;
/** SPI start timestamp. */
private long startTstamp;
/** */
@GridLoggerResource
private GridLogger log;
/** */
@GridMBeanServerResource
private MBeanServer jmx;
/** */
@GridHomeResource
private String ggHome;
/** */
@GridLocalNodeIdResource
private UUID nodeId;
/** SPI name. */
private String name;
/** Authenticator. */
private volatile Authenticator auth = new Authenticator() {
@Override public boolean authenticateNode(UUID nodeId, Map attrs) {
return false;
}
};
/** Grid SPI context. */
private volatile GridSpiContext spiCtx = new GridDummySpiContext(null, auth);
/** Discovery listener. */
private GridLocalEventListener paramsLsnr;
/**
* Creates new adapter and initializes it from the current (this) class.
* SPI name will be initialized to the simple name of the class
* (see {@link Class#getSimpleName()}).
*/
protected GridSpiAdapter() {
for (Class> cls = getClass(); cls != null; cls = cls.getSuperclass())
if ((spiAnn = cls.getAnnotation(GridSpiInfo.class)) != null)
break;
assert spiAnn != null : "Every SPI must have @GridSpiInfo annotation.";
name = U.getSimpleName(getClass());
}
/**
* Starts startup stopwatch.
*/
protected void startStopwatch() {
startTstamp = U.currentTimeMillis();
}
/** {@inheritDoc} */
@Override public final String getAuthor() {
return spiAnn.author();
}
/** {@inheritDoc} */
@Override public final String getVendorUrl() {
return spiAnn.url();
}
/** {@inheritDoc} */
@Override public final String getVendorEmail() {
return spiAnn.email();
}
/** {@inheritDoc} */
@Override public final String getVersion() {
return spiAnn.version();
}
/** {@inheritDoc} */
@Override public final String getStartTimestampFormatted() {
return DateFormat.getDateTimeInstance().format(new Date(startTstamp));
}
/** {@inheritDoc} */
@Override public final String getUpTimeFormatted() {
return X.timeSpan2HMSM(getUpTime());
}
/** {@inheritDoc} */
@Override public final long getStartTimestamp() {
return startTstamp;
}
/** {@inheritDoc} */
@Override public final long getUpTime() {
return startTstamp == 0 ? 0 : U.currentTimeMillis() - startTstamp;
}
/** {@inheritDoc} */
@Override public UUID getLocalNodeId() {
return nodeId;
}
/** {@inheritDoc} */
@Override public final String getGridGainHome() {
return ggHome;
}
/** {@inheritDoc} */
@Override public String getName() {
return name;
}
/**
* Sets SPI name.
*
* @param name SPI name.
*/
@GridSpiConfiguration(optional = true)
public void setName(String name) {
this.name = name;
}
/** {@inheritDoc} */
@Override public final void onContextInitialized(final GridSpiContext spiCtx) throws GridSpiException {
assert spiCtx != null;
auth = new Authenticator() {
@Override public boolean authenticateNode(UUID nodeId, Map attrs) throws GridException {
return spiCtx.authenticateNode(nodeId, attrs);
}
};
this.spiCtx = spiCtx;
spiCtx.addLocalEventListener(paramsLsnr = new GridLocalEventListener() {
@Override public void onEvent(GridEvent evt) {
assert evt instanceof GridDiscoveryEvent : "Invalid event [expected=" + EVT_NODE_JOINED +
", actual=" + evt.type() + ", evt=" + evt + ']';
GridNode node = spiCtx.node(((GridDiscoveryEvent)evt).eventNodeId());
if (node != null)
try {
checkConfigurationConsistency(spiCtx, node, false);
checkConfigurationConsistency0(spiCtx, node, false);
}
catch(GridSpiException e) {
U.error(log, "Spi consistency check failed [node=" + node.id() + ", spi=" + getName() + ']', e);
}
}
}, EVT_NODE_JOINED);
for (GridNode node : spiCtx.remoteNodes()) {
checkConfigurationConsistency(spiCtx, node, true);
checkConfigurationConsistency0(spiCtx, node, true);
}
onContextInitialized0(spiCtx);
}
/**
* Method to be called in the end of onContextInitialized method.
*
* @param spiCtx SPI context.
* @throws GridSpiException In case of errors.
*/
protected void onContextInitialized0(final GridSpiContext spiCtx) throws GridSpiException {
// No-op.
}
/** {@inheritDoc} */
@Override public final void onContextDestroyed() {
onContextDestroyed0();
if (spiCtx != null && paramsLsnr != null)
spiCtx.removeLocalEventListener(paramsLsnr);
GridNode locNode = spiCtx == null ? null : spiCtx.localNode();
// Set dummy no-op context.
spiCtx = new GridDummySpiContext(locNode, auth);
}
/**
* Method to be called in the beginning of onContextDestroyed() method.
*/
protected void onContextDestroyed0() {
// No-op.
}
/**
* This method returns SPI internal instances that need to be injected as well.
* Usually these will be instances provided to SPI externally by user, e.g. during
* SPI configuration.
*
* @return Internal SPI objects that also need to be injected.
*/
public Collection injectables() {
return Collections.emptyList();
}
/**
* Gets SPI context.
*
* @return SPI context.
*/
protected GridSpiContext getSpiContext() {
return spiCtx;
}
/** {@inheritDoc} */
@Override public Map getNodeAttributes() throws GridSpiException {
return Collections.emptyMap();
}
/**
* Throws exception with uniform error message if given parameter's assertion condition
* is {@code false}.
*
* @param cond Assertion condition to check.
* @param condDesc Description of failed condition. Note that this description should include
* JavaBean name of the property (not a variable name) as well condition in
* Java syntax like, for example:
*
* ...
* assertParameter(dirPath != null, "dirPath != null");
* ...
*
* Note that in case when variable name is the same as JavaBean property you
* can just copy Java condition expression into description as a string.
* @throws GridSpiException Thrown if given condition is {@code false}
*/
protected final void assertParameter(boolean cond, String condDesc) throws GridSpiException {
if (!cond)
throw new GridSpiException("SPI parameter failed condition check: " + condDesc);
}
/**
* Gets uniformly formatted message for SPI start.
*
* @return Uniformly formatted message for SPI start.
* @throws GridSpiException If SPI is missing {@link GridSpiInfo} annotation.
*/
protected final String startInfo() throws GridSpiException {
GridSpiInfo ann = getClass().getAnnotation(GridSpiInfo.class);
if (ann == null)
throw new GridSpiException("@GridSpiInfo annotation is missing for the SPI.");
return "SPI started ok [startMs=" + getUpTime() + ", spiMBean=" + spiMBean + ']';
}
/**
* Gets uniformly format message for SPI stop.
*
* @return Uniformly format message for SPI stop.
*/
protected final String stopInfo() {
return "SPI stopped ok.";
}
/**
* Gets uniformed string for configuration parameter.
*
* @param name Parameter name.
* @param val Parameter value.
* @return Uniformed string for configuration parameter.
*/
protected final String configInfo(String name, Object val) {
assert name != null;
return "Using parameter [" + name + '=' + val + ']';
}
/**
* @param msg Error message.
* @param locVal Local node value.
* @return Error text.
*/
private static String format(String msg, Object locVal) {
return msg + U.nl() +
">>> => Local node: " + locVal + U.nl();
}
/**
* @param msg Error message.
* @param locVal Local node value.
* @param rmtVal Remote node value.
* @return Error text.
*/
private static String format(String msg, Object locVal, Object rmtVal) {
return msg + U.nl() +
">>> => Local node: " + locVal + U.nl() +
">>> => Remote node: " + rmtVal + U.nl();
}
/**
* Registers SPI MBean. Note that SPI can only register one MBean.
*
* @param gridName Grid name. If null, then name will be empty.
* @param impl MBean implementation.
* @param mbeanItf MBean interface (if {@code null}, then standard JMX
* naming conventions are used.
* @param Type of the MBean
* @throws GridSpiException If registration failed.
*/
protected final void registerMBean(String gridName, T impl, Class mbeanItf)
throws GridSpiException {
assert mbeanItf == null || mbeanItf.isInterface();
assert jmx != null;
try {
spiMBean = U.registerMBean(jmx, gridName, "SPIs", getName(), impl, mbeanItf);
if (log.isDebugEnabled())
log.debug("Registered SPI MBean: " + spiMBean);
}
catch (JMException e) {
throw new GridSpiException("Failed to register SPI MBean: " + spiMBean, e);
}
}
/**
* Unregisters MBean.
*
* @throws GridSpiException If bean could not be unregistered.
*/
protected final void unregisterMBean() throws GridSpiException {
// Unregister SPI MBean.
if (spiMBean != null) {
assert jmx != null;
try {
jmx.unregisterMBean(spiMBean);
if (log.isDebugEnabled())
log.debug("Unregistered SPI MBean: " + spiMBean);
}
catch (JMException e) {
throw new GridSpiException("Failed to unregister SPI MBean: " + spiMBean, e);
}
}
}
/**
* @return {@code true} if this check is optional.
*/
private boolean checkOptional() {
GridSpiConsistencyChecked ann = U.getAnnotation(getClass(), GridSpiConsistencyChecked.class);
return ann != null && ann.optional();
}
/**
* @return {@code true} if this check is enabled.
*/
private boolean checkEnabled() {
return U.getAnnotation(getClass(), GridSpiConsistencyChecked.class) != null;
}
/**
* Method which is called in the end of checkConfigurationConsistency() method. May be overriden in SPIs.
*
* @param spiCtx SPI context.
* @param node Remote node.
* @param starting If this node is starting or not.
* @throws GridSpiException in case of errors.
*/
protected void checkConfigurationConsistency0(GridSpiContext spiCtx, GridNode node, boolean starting)
throws GridSpiException {
// No-op.
}
/**
* Checks remote node SPI configuration and prints warnings if necessary.
*
* @param spiCtx SPI context.
* @param node Remote node.
* @param starting Flag indicating whether this method is called during SPI start or not.
* @throws GridSpiException If check fatally failed.
*/
@SuppressWarnings("IfMayBeConditional")
private void checkConfigurationConsistency(GridSpiContext spiCtx, GridNode node, boolean starting)
throws GridSpiException {
assert spiCtx != null;
assert node != null;
if (U.isVisorNode(node)) {
if (log.isDebugEnabled())
log.debug("Skipping configuration consistency check for Visor node: " + node);
return;
}
/*
* Optional SPI means that we should not print warning if SPIs are different but
* still need to compare attributes if SPIs are the same.
*/
boolean optional = checkOptional();
boolean enabled = checkEnabled();
if (!enabled)
return;
String clsAttr = createSpiAttributeName(GridNodeAttributes.ATTR_SPI_CLASS);
String verAttr = createSpiAttributeName(GridNodeAttributes.ATTR_SPI_VER);
String name = getName();
SB sb = new SB();
/*
* If there are any attributes do compare class and version
* (do not print warning for the optional SPIs).
*/
/* Check SPI class and version. */
String locCls = spiCtx.localNode().attribute(clsAttr);
String rmtCls = node.attribute(clsAttr);
assert locCls != null : "Local SPI class name attribute not found: " + clsAttr;
boolean isSpiConsistent = false;
if (rmtCls == null) {
if (!optional && starting)
throw new GridSpiException("Remote SPI with the same name is not configured [name=" + name +
", loc=" + locCls + ']');
sb.a(format(">>> Remote SPI with the same name is not configured: " + name, locCls));
}
else if (!locCls.equals(rmtCls)) {
if (!optional && starting)
throw new GridSpiException("Remote SPI with the same name is of different type [name=" + name +
", loc=" + locCls + ", rmt=" + rmtCls + ']');
sb.a(format(">>> Remote SPI with the same name is of different type: " + name, locCls, rmtCls));
}
else
isSpiConsistent = true;
if (optional && !isSpiConsistent)
return;
// It makes no sense to compare inconsistent SPIs attributes.
if (isSpiConsistent) {
List attrs = getConsistentAttributeNames();
// Process all SPI specific attributes.
for (String attr: attrs) {
// Ignore class and version attributes processed above.
if (!attr.equals(clsAttr) && !attr.equals(verAttr)) {
// This check is considered as optional if no attributes
Object rmtVal = node.attribute(attr);
Object locVal = spiCtx.localNode().attribute(attr);
if (locVal == null && rmtVal == null)
continue;
if (locVal == null || rmtVal == null || !locVal.equals(rmtVal))
sb.a(format(">>> Remote node has different " + getName() + " SPI attribute " +
attr, locVal, rmtVal));
}
}
}
if (sb.length() > 0) {
String msg;
if (starting)
msg = U.nl() + U.nl() +
">>> +--------------------------------------------------------------------+" + U.nl() +
">>> + Courtesy notice that starting node has inconsistent configuration. +" + U.nl() +
">>> + Ignore this message if you are sure that this is done on purpose. +" + U.nl() +
">>> +--------------------------------------------------------------------+" + U.nl() +
">>> Remote Node ID: " + node.id().toString().toUpperCase() + U.nl() + sb;
else
msg = U.nl() + U.nl() +
">>> +-------------------------------------------------------------------+" + U.nl() +
">>> + Courtesy notice that joining node has inconsistent configuration. +" + U.nl() +
">>> + Ignore this message if you are sure that this is done on purpose. +" + U.nl() +
">>> +-------------------------------------------------------------------+" + U.nl() +
">>> Remote Node ID: " + node.id().toString().toUpperCase() + U.nl() + sb;
U.courtesy(log, msg);
}
}
/**
* Returns back a list of attributes that should be consistent
* for this SPI. Consistency means that remote node has to
* have the same attribute with the same value.
*
* @return List or attribute names.
*/
protected List getConsistentAttributeNames() {
return Collections.emptyList();
}
/**
* Creates new name for the given attribute. Name contains
* SPI name prefix.
*
* @param attrName SPI attribute name.
* @return New name with SPI name prefix.
*/
protected String createSpiAttributeName(String attrName) {
return U.spiAttribute(this, attrName);
}
/** {@inheritDoc} */
@GridSpiConfiguration(optional = true)
@Override public void setJson(String json) {
assert json != null;
try {
GridJsonDeserializer.inject(this, json);
}
catch (GridException e) {
throw new GridRuntimeException(e);
}
}
/**
* Temporarily SPI context.
*/
private static class GridDummySpiContext implements GridSpiContext {
/** */
private final GridNode locNode;
/** */
private final Authenticator auth;
/**
* Create temp SPI context.
*
* @param locNode Local node.
* @param auth Authenticator.
*/
GridDummySpiContext(GridNode locNode, Authenticator auth) {
this.locNode = locNode;
this.auth = auth;
}
/** {@inheritDoc} */
@Override public void addLocalEventListener(GridLocalEventListener lsnr, int... types) {
/* No-op. */
}
/** {@inheritDoc} */
@Override public void addMessageListener(GridMessageListener lsnr, String topic) {
/* No-op. */
}
/** {@inheritDoc} */
@Override public void recordEvent(GridEvent evt) {
/* No-op. */
}
/** {@inheritDoc} */
@Override public void registerPort(int port, GridPortProtocol proto) {
/* No-op. */
}
/** {@inheritDoc} */
@Override public void deregisterPort(int port, GridPortProtocol proto) {
/* No-op. */
}
/** {@inheritDoc} */
@Override public void deregisterPorts() {
/* No-op. */
}
/** {@inheritDoc} */
@Override public V get(String cacheName, K key) throws GridException {
return null;
}
/** {@inheritDoc} */
@Override public V put(String cacheName, K key, V val, long ttl) throws GridException {
return null;
}
/** {@inheritDoc} */
@Override public V putIfAbsent(String cacheName, K key, V val, long ttl) throws GridException {
return null;
}
/** {@inheritDoc} */
@Override public V remove(String cacheName, K key) throws GridException {
return null;
}
/** {@inheritDoc} */
@Override public boolean containsKey(String cacheName, K key) {
return false;
}
/** {@inheritDoc} */
@Override public void writeToSwap(String spaceName, Object key, @Nullable Object val,
@Nullable ClassLoader ldr) throws GridException {
/* No-op. */
}
/** {@inheritDoc} */
@Override public T readFromSwap(String spaceName, GridSwapKey key, @Nullable ClassLoader ldr)
throws GridException {
return null;
}
/** {@inheritDoc} */
@Nullable @Override public T readFromOffheap(String spaceName, int part, Object key, byte[] keyBytes,
@Nullable ClassLoader ldr) throws GridException {
return null;
}
/** {@inheritDoc} */
@Override public boolean removeFromOffheap(@Nullable String spaceName, int part, Object key,
@Nullable byte[] keyBytes) throws GridException {
return false;
}
/** {@inheritDoc} */
@Override public void writeToOffheap(@Nullable String spaceName, int part, Object key,
@Nullable byte[] keyBytes, Object val, @Nullable byte[] valBytes, @Nullable ClassLoader ldr)
throws GridException {
// No-op.
}
/** {@inheritDoc} */
@Override public int partition(String cacheName, Object key) {
return -1;
}
/** {@inheritDoc} */
@Override public void removeFromSwap(String spaceName, Object key, @Nullable ClassLoader ldr)
throws GridException {
// No-op.
}
/** {@inheritDoc} */
@Override public Collection nodes() {
return locNode == null ? Collections.emptyList() : Collections.singletonList(locNode);
}
/** {@inheritDoc} */
@Override public GridNode localNode() {
return locNode;
}
/** {@inheritDoc} */
@Nullable @Override
public GridNode node(UUID nodeId) {
return null;
}
/** {@inheritDoc} */
@Override public Collection remoteNodes() {
return Collections.emptyList();
}
/** {@inheritDoc} */
@Override public boolean pingNode(UUID nodeId) {
return locNode != null && nodeId.equals(locNode.id());
}
/** {@inheritDoc} */
@Override public boolean removeLocalEventListener(GridLocalEventListener lsnr) {
return false;
}
/** {@inheritDoc} */
@Override public boolean isEventRecordable(int... types) {
return true;
}
/** {@inheritDoc} */
@Override public boolean removeMessageListener(GridMessageListener lsnr, String topic) {
return false;
}
/** {@inheritDoc} */
@Override public void send(GridNode node, Serializable msg, String topic) {
/* No-op. */
}
/** {@inheritDoc} */
@Override public boolean authenticateNode(UUID nodeId, Map attrs) throws GridException {
return auth.authenticateNode(nodeId, attrs);
}
/** {@inheritDoc} */
@Override public GridHashIdResolversValidationResult validateHashIdResolvers(GridNode node) {
return null;
}
/** {@inheritDoc} */
@Override public boolean writeDelta(UUID nodeId, Class> msgCls,
ByteBuffer buf) {
return false;
}
/** {@inheritDoc} */
@Override public boolean readDelta(UUID nodeId, Class> msgCls,
ByteBuffer buf) {
return false;
}
}
/**
*
*/
private interface Authenticator {
/**
* Delegates to real implementation whenever possible.
*
* @param nodeId Node ID.
* @param attrs Attributes.
* @return {@code True} if passed authentication.
* @throws GridException If failed.
*/
public boolean authenticateNode(UUID nodeId, Map attrs) throws GridException;
}
}