/* * Copyright 2010 NCHOVY * * 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.krakenapps.base.impl; import java.util.ArrayList; import java.util.Date; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.felix.ipojo.annotations.Component; import org.apache.felix.ipojo.annotations.Invalidate; import org.apache.felix.ipojo.annotations.Provides; import org.apache.felix.ipojo.annotations.Requires; import org.apache.felix.ipojo.annotations.ServiceProperty; import org.krakenapps.base.RemoteLogger; import org.krakenapps.base.RemoteLoggerFactoryInfo; import org.krakenapps.base.SentryProxy; import org.krakenapps.base.SentryProxyRegistry; import org.krakenapps.log.api.Log; import org.krakenapps.log.api.LoggerRegistry; import org.krakenapps.log.api.SimpleLog; import org.krakenapps.rpc.RpcConnection; import org.krakenapps.rpc.RpcContext; import org.krakenapps.rpc.RpcException; import org.krakenapps.rpc.RpcMethod; import org.krakenapps.rpc.RpcSession; import org.krakenapps.rpc.RpcSessionEventCallback; import org.krakenapps.rpc.SimpleRpcService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component(name = "base-rpc-service") @Provides public class BaseRpcService extends SimpleRpcService { private Logger slogger = LoggerFactory.getLogger(BaseRpcService.class.getName()); private BundleContext bc; @SuppressWarnings("unused") @ServiceProperty(name = "rpc.name", value = "kraken-base") private String rpcName; @Requires private SentryProxyRegistry sentryRegistry; @Requires private LoggerRegistry loggerRegistry; private ConcurrentMap<RpcSession, SentryProxy> commandSessions = new ConcurrentHashMap<RpcSession, SentryProxy>(); public BaseRpcService(BundleContext bc) { this.bc = bc; } @RpcMethod(name = "hello") public void hello(String guid) { RpcConnection connection = RpcContext.getSession().getConnection(); // validateGuid(guid, connection); // create reverse connection RpcSession sentryCommandSession; try { sentryCommandSession = connection.createSession("kraken-sentry"); } catch (Exception e) { slogger.info("kraken-base: hello failed", e); throw new RpcException("kraken-base: cannot open [" + guid + "] sentry rpc service"); } // register sentry proxy SentryProxy sentry = new SentryProxyImpl(bc, guid, sentryCommandSession, loggerRegistry, sentryRegistry); sentryRegistry.register(sentry); commandSessions.putIfAbsent(sentryCommandSession, sentry); sentryCommandSession.addListener(new RpcSessionEventCallback() { @Override public void sessionClosed(RpcSession session) { SentryProxy sentry = commandSessions.remove(session); if (sentry == null) return; // unregister sentry slogger.info("kraken-sentry: command session [{}] closed", sentry.getGuid()); sentry.close(); } }); slogger.info("kraken-base: sentry {} connected, session {}", guid, sentryCommandSession); // grab all logger factories try { sentry.syncLoggerFactories(); sentry.syncLoggers(); } catch (InterruptedException e1) { throw new RpcException("logger factory sync interrupted"); } // make log channel sentry.requestLogChannel(); } private void validateGuid(String guid, RpcConnection connection) { String cn = null; for (String token : connection.getPeerCertificate().getSubjectDN().getName().split(", ")) { if (token.indexOf("=") == -1) continue; if (token.split("=")[0].equals("CN")) cn = token.split("=")[1]; } if (!guid.equals(cn)) { slogger.error("kraken base: connection [{}] certificate mismatch, CN [{}], GUID [{}]", new Object[] { connection.getRemoteAddress(), cn, guid }); throw new IllegalStateException("subject does not match"); } } @RpcMethod(name = "setLogChannel") public void setLogChannel(String guid, String nonce) { SentryProxy sentry = sentryRegistry.getSentry(guid); if (sentry == null) throw new RpcException("sentry not found"); RpcConnection logChannel = RpcContext.getConnection(); RpcSession logSession = RpcContext.getSession(); sentry.setLogSession(nonce, logSession); slogger.info("kraken-base: log channel [guid={}, remote={}] opened", guid, logChannel.getRemoteAddress()); } @RpcMethod(name = "onLog") public void onLog(String guid, String loggerName, Map<String, Object> logData) { SentryProxy sentry = sentryRegistry.getSentry(guid); if (sentry == null) throw new RpcException("sentry not found"); try { RemoteLogger logger = (RemoteLogger) sentry.getConnectedLogger(loggerName); if (logger == null) { slogger.warn("kraken-base: connected logger [{}] not found, maybe previous disconnect was incomplete", loggerName); return; } Log log = parse(logger, logData); logger.onLog(log); if (slogger.isTraceEnabled()) slogger.trace("kraken-base: log received, sentry [{}], logger [{}], date [{}], msg [{}]", new Object[] { guid, loggerName, log.getDate(), log.getMessage() }); } catch (Exception e) { slogger.warn("kraken-base: onLog callback failed", e); } } @SuppressWarnings("unchecked") private Log parse(RemoteLogger logger, Map<String, Object> logData) { Date date = (Date) logData.get("date"); String message = (String) logData.get("msg"); Map<String, Object> params = (Map<String, Object>) logData.get("params"); return new SimpleLog(date, logger.getFullName(), (String) logData.get("type"), message, params); } @Invalidate public void stop() { slogger.info("kraken-base: unregistering all remote logger and factories"); if (sentryRegistry != null) { for (String guid : new ArrayList<String>(sentryRegistry.getSentryGuids())) { SentryProxy proxy = sentryRegistry.getSentry(guid); proxy.close(); } } slogger.info("kraken-base: disconnecting all sentry command sessions"); for (RpcSession session : commandSessions.keySet()) { session.getConnection().close(); } commandSessions.clear(); } @RpcMethod(name = "factoryAdded") public void factoryAdded(String guid, Map<String, Object> factory) { SentryProxy proxy = sentryRegistry.getSentry(guid); RemoteLoggerFactoryInfo info = LoggerFactoryResponseParser.parseFactory(factory); proxy.registerLoggerFactory(info); } @RpcMethod(name = "factoryRemoved") public void factoryRemoved(String guid, Map<String, Object> factory) { RemoteLoggerFactoryInfo info = LoggerFactoryResponseParser.parseFactory(factory); SentryProxy proxy = sentryRegistry.getSentry(guid); String factoryFullName = guid + "\\" + info.getName(); proxy.unregisterLoggerFactory(factoryFullName); } @RpcMethod(name = "loggerAdded") public void loggerAdded(String guid, Map<String, Object> logger) { try { SentryProxy sentry = sentryRegistry.getSentry(guid); if (sentry == null) throw new RpcException("sentry not found"); sentry.registerLogger(LoggerResponseParser.parse(sentry, logger)); } catch (Exception e) { slogger.error("kraken base: cannot add logger", e); } } @RpcMethod(name = "loggerRemoved") public void loggerRemoved(String guid, String loggerName) { try { SentryProxy sentry = sentryRegistry.getSentry(guid); if (sentry == null) throw new RpcException("sentry not found"); sentry.unregisterLogger(loggerName); } catch (Exception e) { slogger.error("kraken base: cannot remove logger", e); } } @RpcMethod(name = "loggerStarted") public void loggerStarted(String guid, String loggerName, Integer interval) { slogger.info("kraken base: logger [{}] started at sentry [{}], interval [{}]", new Object[] { loggerName, guid, interval }); SentryProxy sentry = sentryRegistry.getSentry(guid); if (sentry == null) throw new RpcException("sentry not found"); String loggerFullName = guid + "\\" + loggerName; sentry.loggerStarted(loggerFullName, interval); } @RpcMethod(name = "loggerStopped") public void loggerStopped(String guid, String loggerName) { slogger.info("kraken base: logger [{}] stopped at sentry [{}]", loggerName, guid); SentryProxy sentry = sentryRegistry.getSentry(guid); if (sentry == null) throw new RpcException("sentry not found"); String loggerFullName = guid + "\\" + loggerName; sentry.loggerStopped(loggerFullName); } }