
com.hazelcast.jet.impl.connector.HazelcastWriters Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2023, Hazelcast, Inc. 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 com.hazelcast.jet.impl.connector;
import com.hazelcast.cache.ICache;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.cluster.Address;
import com.hazelcast.collection.IList;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.HazelcastInstanceNotActiveException;
import com.hazelcast.function.BiConsumerEx;
import com.hazelcast.function.BiFunctionEx;
import com.hazelcast.function.BinaryOperatorEx;
import com.hazelcast.function.ConsumerEx;
import com.hazelcast.function.FunctionEx;
import com.hazelcast.security.impl.function.SecuredFunctions;
import com.hazelcast.internal.serialization.Data;
import com.hazelcast.internal.serialization.SerializationService;
import com.hazelcast.jet.RestartableException;
import com.hazelcast.jet.core.Processor;
import com.hazelcast.jet.core.ProcessorMetaSupplier;
import com.hazelcast.jet.core.ProcessorSupplier;
import com.hazelcast.jet.core.processor.SinkProcessors;
import com.hazelcast.jet.impl.observer.ObservableImpl;
import com.hazelcast.map.EntryProcessor;
import com.hazelcast.security.permission.RingBufferPermission;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.security.Permission;
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import static com.hazelcast.jet.core.ProcessorMetaSupplier.preferLocalParallelismOne;
import static com.hazelcast.jet.impl.connector.AsyncHazelcastWriterP.MAX_PARALLEL_ASYNC_OPS_DEFAULT;
import static com.hazelcast.jet.impl.util.ImdgUtil.asXmlString;
import static com.hazelcast.jet.impl.util.Util.checkSerializable;
import static com.hazelcast.security.PermissionsUtil.cachePutPermission;
import static com.hazelcast.security.PermissionsUtil.listAddPermission;
import static com.hazelcast.security.PermissionsUtil.mapPutPermission;
import static com.hazelcast.security.PermissionsUtil.mapUpdatePermission;
import static com.hazelcast.security.permission.ActionConstants.ACTION_CREATE;
import static com.hazelcast.security.permission.ActionConstants.ACTION_PUT;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
/**
* This is private API. Check out the {@link SinkProcessors} class for
* public factory methods.
*/
public final class HazelcastWriters {
private HazelcastWriters() {
}
@Nonnull
public static ProcessorMetaSupplier writeMapSupplier(
@Nonnull String name,
@Nullable ClientConfig clientConfig,
@Nonnull FunctionEx super T, ? extends K> toKeyFn,
@Nonnull FunctionEx super T, ? extends V> toValueFn
) {
String clientXml = asXmlString(clientConfig);
return preferLocalParallelismOne(mapPutPermission(clientXml, name),
new WriteMapP.Supplier<>(clientXml, name, toKeyFn, toValueFn));
}
@Nonnull
public static ProcessorMetaSupplier mergeMapSupplier(
@Nonnull String name,
@Nullable ClientConfig clientConfig,
@Nonnull FunctionEx super T, ? extends K> toKeyFn,
@Nonnull FunctionEx super T, ? extends V> toValueFn,
@Nonnull BinaryOperatorEx mergeFn
) {
checkSerializable(toKeyFn, "toKeyFn");
checkSerializable(toValueFn, "toValueFn");
checkSerializable(mergeFn, "mergeFn");
return updateMapSupplier(name, clientConfig, toKeyFn, (V oldValue, T item) -> {
V newValue = toValueFn.apply(item);
if (oldValue == null) {
return newValue;
}
return mergeFn.apply(oldValue, newValue);
});
}
@Nonnull
public static ProcessorMetaSupplier updateMapSupplier(
@Nonnull String name,
@Nullable ClientConfig clientConfig,
@Nonnull FunctionEx super T, ? extends K> toKeyFn,
@Nonnull BiFunctionEx super V, ? super T, ? extends V> updateFn
) {
checkSerializable(toKeyFn, "toKeyFn");
checkSerializable(updateFn, "updateFn");
String clientXml = asXmlString(clientConfig);
return ProcessorMetaSupplier.of(mapUpdatePermission(clientXml, name),
AbstractHazelcastConnectorSupplier.ofMap(clientXml,
SecuredFunctions.updateMapProcessorFn(name, clientXml, toKeyFn, updateFn)));
}
@Nonnull
public static ProcessorMetaSupplier updateMapSupplier(
@Nonnull String name,
@Nullable ClientConfig clientConfig,
@Nonnull FunctionEx super T, ? extends K> toKeyFn,
@Nonnull FunctionEx super T, ? extends EntryProcessor> toEntryProcessorFn
) {
checkSerializable(toKeyFn, "toKeyFn");
checkSerializable(toEntryProcessorFn, "toEntryProcessorFn");
String clientXml = asXmlString(clientConfig);
return ProcessorMetaSupplier.of(mapUpdatePermission(clientXml, name),
AbstractHazelcastConnectorSupplier.ofMap(clientXml,
SecuredFunctions.updateWithEntryProcessorFn(MAX_PARALLEL_ASYNC_OPS_DEFAULT, name, clientXml,
toKeyFn, toEntryProcessorFn)));
}
@Nonnull
public static ProcessorMetaSupplier updateMapSupplier(
int maxParallelAsyncOps,
@Nonnull String name,
@Nullable ClientConfig clientConfig,
@Nonnull FunctionEx super T, ? extends K> toKeyFn,
@Nonnull FunctionEx super T, ? extends EntryProcessor> toEntryProcessorFn
) {
checkSerializable(toKeyFn, "toKeyFn");
checkSerializable(toEntryProcessorFn, "toEntryProcessorFn");
String clientXml = asXmlString(clientConfig);
return ProcessorMetaSupplier.of(mapUpdatePermission(clientXml, name),
AbstractHazelcastConnectorSupplier.ofMap(clientXml,
SecuredFunctions.updateWithEntryProcessorFn(maxParallelAsyncOps, name, clientXml,
toKeyFn, toEntryProcessorFn)));
}
@Nonnull
public static ProcessorMetaSupplier writeCacheSupplier(@Nonnull String name, @Nullable ClientConfig clientConfig) {
String clientXml = asXmlString(clientConfig);
return preferLocalParallelismOne(cachePutPermission(clientXml, name),
new WriteCachePSupplier<>(clientXml, name));
}
@Nonnull
public static ProcessorMetaSupplier writeListSupplier(@Nonnull String name, @Nullable ClientConfig clientConfig) {
String clientXml = asXmlString(clientConfig);
return preferLocalParallelismOne(listAddPermission(clientXml, name),
new WriteListPSupplier<>(clientXml, name));
}
@SuppressWarnings("AnonInnerLength")
public static ProcessorMetaSupplier writeObservableSupplier(@Nonnull String name) {
return new ProcessorMetaSupplier() {
@Nonnull
@Override
public Map getTags() {
return singletonMap(ObservableImpl.OWNED_OBSERVABLE, name);
}
@Override
public int preferredLocalParallelism() {
return 1;
}
@Nonnull @Override
public Function super Address, ? extends ProcessorSupplier> get(@Nonnull List addresses) {
return address -> new WriteObservableP.Supplier(name);
}
@Override
public Permission getRequiredPermission() {
return new RingBufferPermission(name, ACTION_CREATE, ACTION_PUT);
}
@Override
public boolean isReusable() {
return true;
}
@Override
public boolean initIsCooperative() {
return true;
}
@Override
public boolean closeIsCooperative() {
return true;
}
};
}
static RuntimeException handleInstanceNotActive(HazelcastInstanceNotActiveException e, boolean isLocal) {
// if we are writing to a local instance, restarting the job should resolve the error
return isLocal ? new RestartableException(e) : e;
}
private static class WriteCachePSupplier extends AbstractHazelcastConnectorSupplier {
static final long serialVersionUID = 1L;
private final String name;
WriteCachePSupplier(@Nullable String clientXml, @Nonnull String name) {
super(clientXml);
this.name = name;
}
@Override
protected Processor createProcessor(HazelcastInstance instance, SerializationService serializationService) {
ICache cache = instance.getCacheManager().getCache(name);
FunctionEx> bufferCreator = context -> new ArrayMap<>();
BiConsumerEx, Entry> entryReceiver = (buffer, entry) -> {
Data key = serializationService.toData(entry.getKey());
Data value = serializationService.toData(entry.getValue());
buffer.add(new SimpleEntry<>(key, value));
};
ConsumerEx> bufferFlusher = buffer -> {
try {
cache.putAll(buffer);
} catch (HazelcastInstanceNotActiveException e) {
throw handleInstanceNotActive(e, isLocal());
}
buffer.clear();
};
return new WriteBufferedP<>(bufferCreator, entryReceiver, bufferFlusher, ConsumerEx.noop());
}
@Override
public List permissions() {
return singletonList(cachePutPermission(clientXml, name));
}
}
private static class WriteListPSupplier extends AbstractHazelcastConnectorSupplier {
static final long serialVersionUID = 1L;
private final String name;
WriteListPSupplier(@Nullable String clientXml, @Nonnull String name) {
super(clientXml);
this.name = name;
}
@Override
protected Processor createProcessor(HazelcastInstance instance, SerializationService serializationService) {
IList
© 2015 - 2025 Weber Informatics LLC | Privacy Policy