/* * Copyright 2015 Eediom Inc. * * 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.araqne.log.api.http.impl; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; 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.Validate; import org.araqne.httpd.HttpContext; import org.araqne.httpd.HttpService; import org.araqne.log.api.http.HttpPostListener; import org.araqne.log.api.http.HttpPostLog; import org.araqne.log.api.http.HttpPostLogService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component(name = "http-post-log-service") @Provides public class HttpPostLogServiceImpl extends HttpServlet implements HttpPostLogService { private static final long serialVersionUID = 1L; private final Logger slog = LoggerFactory.getLogger(HttpPostLogServiceImpl.class); @Requires private HttpService httpd; // callback name to listener mappings private ConcurrentHashMap<String, Set<HttpPostListener>> callbackMap; @Validate public void start() { HttpContext context = httpd.ensureContext("webconsole"); context.addServlet("log", this, "/log/*"); callbackMap = new ConcurrentHashMap<String, Set<HttpPostListener>>(); } @Invalidate public void stop() { if (httpd != null) { HttpContext context = httpd.ensureContext("webconsole"); context.removeServlet("log"); } callbackMap.clear(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (slog.isDebugEnabled()) { slog.debug("araqne logapi http: post path [{}] content-type [{}], content-length [{}]", new Object[] { req.getPathInfo(), req.getContentType(), req.getContentLength() }); } ByteArrayOutputStream bos = new ByteArrayOutputStream(8096); byte[] b = new byte[8096]; while (true) { int len = req.getInputStream().read(b); if (len < 0) break; bos.write(b, 0, len); } String callback = req.getPathInfo().substring(1); Set<HttpPostListener> set = callbackMap.get(callback); if (set == null) return; for (HttpPostListener listener : set) { try { HttpPostLog log = new HttpPostLog(); log.setCallback(callback); log.setClientIp(req.getRemoteAddr()); log.setData(bos.toString("utf-8")); listener.onPost(log); } catch (Throwable t) { slog.warn("araqne logapi http: post listener should not throw any exception", t); } } } @Override public void addListener(String callback, HttpPostListener listener) { Set<HttpPostListener> s = new CopyOnWriteArraySet<HttpPostListener>(); Set<HttpPostListener> old = callbackMap.putIfAbsent(callback, s); if (old != null) s = old; s.add(listener); } @Override public void removeListener(String callback, HttpPostListener listener) { Set<HttpPostListener> s = new CopyOnWriteArraySet<HttpPostListener>(); Set<HttpPostListener> old = callbackMap.putIfAbsent(callback, s); if (old != null) s = old; s.remove(listener); } }