/* * Copyright (c) 2015 Huawei, Inc and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.usc; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.local.LocalChannel; import io.netty.channel.local.LocalEventLoopGroup; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.util.AttributeKey; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Future; import org.opendaylight.usc.manager.UscManagerService; import org.opendaylight.usc.manager.UscTopologyService; import org.opendaylight.usc.manager.api.UscShardService; import org.opendaylight.usc.plugin.UscPlugin; import org.opendaylight.usc.plugin.model.UscChannelImpl; import org.opendaylight.usc.util.UscServiceUtils; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.AddChannelInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.AddChannelOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.AddChannelOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.RemoveChannelInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.RemoveChannelOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.RemoveChannelOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.RemoveSessionInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.RemoveSessionOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.RemoveSessionOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.UscChannelService; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.ViewChannelInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.ViewChannelOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.ViewChannelOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.view.channel.output.Topology; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.view.channel.output.TopologyBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.view.channel.output.TopologyKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.SendMessageInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.SendMessageOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.SendMessageOutputBuilder; import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Implementation of the YANG RPCs defined in module usc. Service provides rpc * for viewing the usc topology. */ public class UscChannelServiceImpl implements UscChannelService { private static final Logger LOG = LoggerFactory.getLogger(UscChannelServiceImpl.class); @SuppressWarnings("rawtypes") private UscShardService shardService; private UscTopologyService topoService; public static final AttributeKey<String> CLIENT_KEY = AttributeKey.valueOf("client_key"); private ConcurrentMap<String, Channel> connectList = new ConcurrentHashMap<String, Channel>(); private ConcurrentMap<String, EventLoopGroup> groupList = new ConcurrentHashMap<String, EventLoopGroup>(); /** * Create a UscService and initialize the Shard Service */ public UscChannelServiceImpl() { shardService = UscServiceUtils.getService(UscShardService.class); if (shardService == null) { LOG.error("Failed to get UscShardService!"); } topoService = UscServiceUtils.getService(UscTopologyService.class); } /** * Implements rpc call for viewing the usc topology. */ @Override public Future<RpcResult<AddChannelOutput>> addChannel(AddChannelInput input) { String hostname = input.getChannel().getHostname(); int port = input.getChannel().getPort(); AddChannelOutputBuilder builder = new AddChannelOutputBuilder(); boolean isTcp = input.getChannel().isTcp(); String result = connectDevice(hostname, port, isTcp, input.getChannel().isRemote()); builder.setResult(result); return RpcResultBuilder.success(builder.build()).buildFuture(); } private String connectDevice(String hostname, int port, boolean isTcp, boolean remote) { Bootstrap clientBootStrap = getNewBootstrap(); InetSocketAddress address = new InetSocketAddress(hostname, port); try { UscPlugin plugin = null; if(isTcp) plugin = UscManagerService.getInstance().getPluginTcp(); else plugin = UscManagerService.getInstance().getPluginUdp(); Channel clientChannel = plugin.connect(clientBootStrap, address, remote).sync().channel(); clientChannel.attr(CLIENT_KEY).set(hostname + ":" + port + isTcp); connectList.put(hostname + ":" + port + isTcp, clientChannel); groupList.put(hostname + ":" + port + isTcp, clientBootStrap.group()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return "Failed to Connect device(" + hostname + ":" + port + ")!error is " + e.getMessage(); } return "Succeed to connect device(" + hostname + ":" + port + ")!"; } private Bootstrap getNewBootstrap() { Bootstrap ret = new Bootstrap(); EventLoopGroup localGroup = new LocalEventLoopGroup(); // set up client bootstrap ret.group(localGroup); ret.channel(LocalChannel.class); ret.handler(new ChannelInitializer<LocalChannel>() { @Override public void initChannel(LocalChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler("Manager Test 1", LogLevel.TRACE)); } }); return ret; } private void closeConnect(EventLoopGroup localGroup) { localGroup.shutdownGracefully(); // allow some time for all ports to close; try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public Future<RpcResult<RemoveChannelOutput>> removeChannel(RemoveChannelInput input) { String hostname = input.getChannel().getHostname(); boolean isTcp = input.getChannel().isTcp(); LOG.debug("Beginning of removeChannel: connectList is " + connectList + "; groupList is " + groupList); Iterator it = connectList.entrySet().iterator(); while(it.hasNext()) { Map.Entry<String, Channel> item = (Map.Entry<String, Channel>)it.next(); String connectionName = item.getKey(); if(connectionName.contains(hostname) && connectionName.contains(Boolean.toString(isTcp))) { Channel clientChannel = connectList.get(connectionName); clientChannel.close(); it.remove(); } } it = groupList.entrySet().iterator(); while(it.hasNext()) { Map.Entry<String, EventLoopGroup> item = (Map.Entry<String, EventLoopGroup>)it.next(); String groupName = item.getKey(); if(groupName.contains(hostname) && groupName.contains(Boolean.toString(isTcp))) { EventLoopGroup group = item.getValue(); closeConnect(group); it.remove(); } } UscPlugin plugin = null; if(isTcp) plugin = UscManagerService.getInstance().getPluginTcp(); else plugin = UscManagerService.getInstance().getPluginUdp(); String result = "Failed to remove channel(" + hostname + ": " + isTcp + ")!"; InetSocketAddress address = new InetSocketAddress(hostname, 9999); UscChannelImpl channelImpl = plugin.retrieveChannelImpl(address); if(channelImpl != null) { LOG.info("address is" + address + ", Channel is " + channelImpl.getChannel()); channelImpl.getChannel().close(); result = "Succeed to remove channel(" + hostname + ": " + isTcp + ")!"; } LOG.debug("End of removeChannel: connectList is " + connectList + "; groupList is " + groupList); RemoveChannelOutputBuilder builder = new RemoveChannelOutputBuilder(); builder.setResult(result); return RpcResultBuilder.success(builder.build()).buildFuture(); } @Override public Future<RpcResult<RemoveSessionOutput>> removeSession(RemoveSessionInput input) { String hostname = input.getChannel().getHostname(); int port = input.getChannel().getPort(); boolean isTcp = input.getChannel().isTcp(); LOG.debug("Beginning of removeSession: connectList is " + connectList + "; groupList is " + groupList); Channel clientChannel = connectList.get(hostname + ":" + port + isTcp); EventLoopGroup group = groupList.get(hostname + ":" + port + isTcp); String result = ""; LOG.info("connectList number is " + connectList.size()); if (clientChannel == null) { result = "Failed to remove channel(" + hostname + ":" + port + ")!"; } else { // plugin.closeAgentInternalConnection(clientChannel); closeConnect(group); clientChannel.close(); connectList.remove(hostname + ":" + port + isTcp); groupList.remove(hostname + ":" + port + isTcp); result = "Succeed to remove session (" + hostname + ":" + port + ")!"; } LOG.debug("End of removeSession: connectList is " + connectList + "; groupList is " + groupList); RemoveSessionOutputBuilder builder = new RemoveSessionOutputBuilder(); builder.setResult(result); return RpcResultBuilder.success(builder.build()).buildFuture(); } @SuppressWarnings("unchecked") @Override public Future<RpcResult<ViewChannelOutput>> viewChannel(ViewChannelInput input) { if (topoService == null || shardService == null) { LOG.error("USC Topology Service is not initialized, currently can't process this rpc request."); return (Future<RpcResult<ViewChannelOutput>>) RpcResultBuilder.failed() .withError(ErrorType.RPC, "Internal error,For details please see the log.").build(); } // Build Output // there only one whole topology org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.usc.channel.rev150101.usc.topology.Topology topo = topoService .getWholeUscTopology(); if (topo == null) { return (Future<RpcResult<ViewChannelOutput>>) RpcResultBuilder.failed() .withError(ErrorType.RPC, "Internal error,For details please see the log.").build(); } ViewChannelOutputBuilder outputBuilder = new ViewChannelOutputBuilder(); TopologyBuilder topoBuilder = new TopologyBuilder(); TopologyKey topoKey = new TopologyKey(topo.getTopologyId()); Topology outputTopo = topoBuilder.setChannel(topo.getChannel()).setKey(topoKey).setNode(topo.getNode()) .setTopologyId(topo.getTopologyId()).build(); List<Topology> outputTopologyList = new ArrayList<Topology>(); outputTopologyList.add(outputTopo); outputBuilder.setTopology(outputTopologyList); ViewChannelOutput output = outputBuilder.build(); // Return Results return RpcResultBuilder.success(output).buildFuture(); } @Override public Future<RpcResult<SendMessageOutput>> sendMessage(SendMessageInput input){ String hostname = input.getChannel().getHostname(); int port = input.getChannel().getPort(); boolean isTcp = input.getChannel().isTcp(); Channel clientChannel = connectList.get(hostname + ":" + port + isTcp); String result = ""; // outputConnectList(); ByteBuf payload = Unpooled.buffer(10000); payload.writeBytes(input.getChannel().getContent().getBytes()); if (clientChannel == null) { result = "Failed to send request to device(" + hostname + ":" + port + "), since it is not found!"; } else { clientChannel.writeAndFlush(payload); result = "Succeed to send request to device(" + hostname + ":" + port + "),content is " + input.getChannel().getContent(); } SendMessageOutputBuilder builder = new SendMessageOutputBuilder(); builder.setResult(result); return RpcResultBuilder.success(builder.build()).buildFuture(); } }