/* * Copyright 2013 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.logdb.client.http.impl; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.net.ConnectException; import java.net.HttpURLConnection; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URL; import java.util.concurrent.CopyOnWriteArraySet; import org.araqne.logdb.client.Message; import org.json.JSONArray; import org.json.JSONTokener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 로그프레소 서버에서 전송되는 비동기적 트랩 전문을 수신합니다. * * @author xeraph@eediom.com * */ public class TrapReceiver extends Thread { private final Logger logger = LoggerFactory.getLogger(TrapReceiver.class); private boolean doStop; private String host; private int port; private String cookie; private CopyOnWriteArraySet<TrapListener> listeners; private HttpURLConnection con; public TrapReceiver(String host, String cookie) { this(host, 80, cookie); } public TrapReceiver(String host, int port, String cookie) { this.host = host; this.port = port; this.cookie = cookie; this.listeners = new CopyOnWriteArraySet<TrapListener>(); } @Override public void run() { try { logger.trace("logdb client: trap thread started"); while (!doStop) { receiveTrap(); } } catch (SocketException e) { if (e.getMessage().equalsIgnoreCase("socket closed")) return; } catch (Throwable t) { logger.error("logdb client: trap receiver error", t); } finally { logger.trace("logdb client: trap thread stopped"); } } private void receiveTrap() throws SocketException { InputStream is = null; try { con = (HttpURLConnection) new URL("http://" + host + ":" + port + "/msgbus/trap").openConnection(); con.setRequestProperty("Content-Type", "text/json"); con.setRequestProperty("Cookie", cookie); con.setConnectTimeout(5000); con.setReadTimeout(5000); is = con.getInputStream(); ByteArrayOutputStream bos = null; if (con.getContentLength() > 0) bos = new ByteArrayOutputStream(con.getContentLength()); else bos = new ByteArrayOutputStream(); byte[] b = new byte[8096]; while (true) { int read = is.read(b); if (read < 0) break; bos.write(b, 0, read); } String text = new String(bos.toByteArray(), "utf-8"); if (text.isEmpty()) return; JSONTokener tokenizer = new JSONTokener(new StringReader(text)); JSONArray container = (JSONArray) tokenizer.nextValue(); for (int i = 0; i < container.length(); i++) { JSONArray obj = container.getJSONArray(i); Message msg = MessageCodec.decode(obj.toString()); invokeTrapCallbacks(msg); } } catch (SocketTimeoutException e) { logger.debug("logdb client: socket timeout"); } catch (ConnectException e) { throw e; } catch (SocketException e) { if (e.getMessage().equalsIgnoreCase("socket closed")) throw e; logger.error("logdb client: cannot fetch trap", e); } catch (Throwable t) { logger.error("logdb client: cannot fetch trap", t); } finally { if (is != null) { try { is.close(); } catch (IOException e) { } } if (con != null) { con.disconnect(); con = null; } } } private void invokeTrapCallbacks(Message msg) { for (TrapListener listener : listeners) { try { listener.onTrap(msg); } catch (Throwable t) { logger.error("logdb client: listener should not throw any exception", t); } } } public void addListener(TrapListener listener) { listeners.add(listener); } public void removeListener(TrapListener listener) { listeners.remove(listener); } public void close() { try { doStop = true; if (con != null) con.disconnect(); interrupt(); join(); } catch (InterruptedException e) { } } }