| /* |
| * 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.examples.servicegrid; |
| |
| import java.util.Date; |
| import java.util.concurrent.Callable; |
| import org.apache.ignite.Ignite; |
| import org.apache.ignite.IgniteException; |
| import org.apache.ignite.IgniteLogger; |
| import org.apache.ignite.Ignition; |
| import org.apache.ignite.examples.ExampleNodeStartup; |
| import org.apache.ignite.examples.ExamplesUtils; |
| import org.apache.ignite.resources.LoggerResource; |
| import org.apache.ignite.services.ServiceCallContext; |
| import org.apache.ignite.services.ServiceCallInterceptor; |
| import org.apache.ignite.services.ServiceConfiguration; |
| import org.apache.ignite.services.ServiceContext; |
| |
| /** |
| * The example shows how to add a middleware layer for distributed services in Ignite. |
| * <p> |
| * To start remote nodes, run {@link ExampleNodeStartup} in another JVM. It will start |
| * a node with {@code examples/config/example-ignite.xml} configuration. |
| * <p> |
| * NOTE:<br/> |
| * Starting {@code ignite.sh} directly will not work, as distributed services (and interceptors) |
| * cannot be peer-deployed and classes must be in the classpath for each node. |
| */ |
| public class ServiceMiddlewareExample { |
| /** Service name. */ |
| private static final String SVC_NAME = "MapService"; |
| |
| /** |
| * Executes example. |
| * |
| * @param args Command line arguments, none required. |
| * @throws Exception If example execution failed. |
| */ |
| public static void main(String[] args) throws Exception { |
| // Mark this node as client node. |
| Ignition.setClientMode(true); |
| |
| try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) { |
| if (!ExamplesUtils.hasServerNodes(ignite)) |
| return; |
| |
| ServiceCallInterceptor audit = new Audit(); |
| ServiceCallInterceptor access = (mtd, args0, ctx, next) -> { |
| ServiceCallContext callCtx = ctx.currentCallContext(); |
| |
| if (callCtx == null || callCtx.attribute("user") == null || callCtx.attribute("user").isEmpty()) |
| throw new SecurityException("Anonymous access is restricted."); |
| |
| return next.call(); |
| }; |
| |
| ServiceConfiguration cfg = new ServiceConfiguration() |
| .setName(SVC_NAME) |
| .setService(new SimpleMapServiceImpl<>()) |
| .setTotalCount(1) |
| .setInterceptors(audit, access); |
| |
| try { |
| ignite.services().deploy(cfg); |
| |
| // Create proxy without context. |
| SimpleMapService<Object, Object> proxy = |
| ignite.services().serviceProxy(SVC_NAME, SimpleMapService.class, false); |
| |
| try { |
| System.out.println("Try to call the proxy method without context."); |
| // The method call will be intercepted with a SecurityException because no username was provided. |
| proxy.put(0, 0); |
| } |
| catch (IgniteException expected) { |
| expected.printStackTrace(); |
| } |
| |
| // Create a service call context with the username. |
| ServiceCallContext callCtx = ServiceCallContext.builder().put("user", "John").build(); |
| |
| // Bind it to the service proxy. |
| proxy = ignite.services().serviceProxy(SVC_NAME, SimpleMapService.class, false, callCtx); |
| |
| System.out.println("Call the proxy method with context."); |
| |
| for (int i = 0; i < 10; i++) |
| proxy.put(i, i); |
| |
| for (int i = 0; i < 5; i++) |
| proxy.get(i * 2); |
| |
| System.out.println("Map size: " + proxy.size()); |
| } |
| finally { |
| ignite.services().cancelAll(); |
| } |
| } |
| } |
| |
| /** */ |
| private static class Audit implements ServiceCallInterceptor { |
| /** Serial version UID. */ |
| private static final long serialVersionUID = 0L; |
| |
| /** Injected Ignite logger. */ |
| @LoggerResource |
| private IgniteLogger log; |
| |
| /** {@inheritDoc} */ |
| @Override public Object invoke(String mtd, Object[] args, ServiceContext ctx, Callable<Object> next) throws Exception { |
| String srvcName = ctx.name(); |
| ServiceCallContext callCtx = ctx.currentCallContext(); |
| String user = callCtx == null ? null : callCtx.attribute("user"); |
| |
| recordEvent(user, srvcName, mtd, "start"); |
| |
| try { |
| // Execute service method. |
| Object res = next.call(); |
| |
| // Record finish event after execution of the service method. |
| recordEvent(user, srvcName, mtd, "result " + res); |
| |
| return res; |
| } |
| catch (Exception e) { |
| log.error("Intercepted error", e); |
| |
| // Record error. |
| recordEvent(user, srvcName, mtd, "error: " + e.getMessage()); |
| |
| // Re-throw exception to initiator. |
| throw e; |
| } |
| } |
| |
| /** |
| * Record an event to current server node console output. |
| */ |
| private void recordEvent(String user, String svc, String mtd, String msg) { |
| System.out.printf("[%tT][%s][%s][%s] %s%n", new Date(), user, svc, mtd, msg); |
| } |
| } |
| } |