001/* 002 * Copyright (c) 2013 - 2016 TDP Ltd All Rights Reserved. 003 * TDP Ltd grants permission, free of charge, to any person obtaining copies 004 * of this software and its associated documentation files (the "Software"), 005 * to deal in the Software without restriction, including to use, copy, adapt, 006 * publish, distribute, display, perform, sublicense, and sell copies of the 007 * Software, subject to the following condition: You must include the above 008 * copyright notice and this permission notice in all full or partial copies 009 * of the Software. 010 * TDP LTD PROVIDES THE SOFTWARE "AS IS," WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, 011 * INCLUDING WITHOUT THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 012 * PARTICULAR PURPOSE, AND NON-INFRINGMENT. TDP LTD, THE AUTHORS OF THE SOFTWARE, 013 * AND THE OWNERS OF COPYRIGHT IN THE SOFTWARE ARE NOT LIABLE FOR ANY CLAIM, DAMAGES, 014 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING 015 * FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 016 * THE SOFTWARE. 017 */ 018 019package cz.tdp.kshield.notification; 020 021import java.util.concurrent.atomic.AtomicBoolean; 022import java.util.concurrent.atomic.AtomicInteger; 023 024import org.apache.commons.logging.Log; 025import org.apache.commons.logging.LogFactory; 026 027/** 028 * Common Abstract WebSocket Endpoint class 029 */ 030public abstract class AbstractWebSocketEndpoint implements KShieldEndpoint 031{ 032 private static final Log log = LogFactory.getLog(AbstractWebSocketEndpoint.class); 033 034 private static final AtomicInteger counter = new AtomicInteger(1); 035 private final int wsId = counter.getAndIncrement(); 036 037 private final AtomicBoolean initialized = new AtomicBoolean(false); 038 039 private String ipAddress; 040 private String user; 041 private String kshieldAuth; 042 private String lastError; 043 044 /** 045 * Implement this to provide kshieldAuthManager functionality to WebSocket instance 046 * @return reference to kshieldAuthManager 047 */ 048 protected abstract KShieldAuthManager kshieldAuthManager(); 049 050 public AbstractWebSocketEndpoint() { 051 super(); 052 } 053 054 @Override 055 public boolean isActive() { 056 return ipAddress != null; 057 } 058 059 @Override 060 public void signal() { 061 if (isActive()) { 062 send(poll()); 063 } 064 } 065 066 @Override 067 public String toString() { 068 return "user="+user+", kshield="+kshieldAuth+", id=" + wsId + (lastError!=null?" ["+lastError+"]":""); 069 } 070 071 protected void onErrorImpl(Throwable e) { 072 onCloseImpl(); 073 074 lastError = e.getMessage(); 075 076 log.trace("WebSocket error: ", e); 077 } 078 079 protected String onMessageImpl(String message) { 080 if (message.startsWith("POLL")) { 081 if (log.isDebugEnabled()) { 082 log.debug("WebSocket [id="+wsId+"] message: " + message); 083 } 084 085 handleMessage(message); 086 087 if (isActive()) { 088 if (!initialized.getAndSet(true)) { 089 kshieldAuthManager().addEndpoint(ipAddress, this); 090 } 091 092 return poll(); 093 } 094 } 095 096 // echo - for testing purposes 097 return message; 098 } 099 100 private void handleMessage(String message) { 101 if (!initialized.get()) { 102 final String[] tokens = message.split("[:]"); 103 104 if (tokens.length > 1) { 105 ipAddress = token(tokens, 1); 106 user = token(tokens, 2); 107 kshieldAuth = token(tokens, 3); 108 } 109 } 110 } 111 112 protected abstract void send(String message); 113 114 protected void onOpenImpl() { 115 reset(); 116 } 117 118 protected void onCloseImpl() { 119 if (ipAddress != null) { 120 kshieldAuthManager().removeEndpoint(ipAddress, this); 121 } 122 123 reset(); 124 } 125 126 protected void reset() { 127 ipAddress = null; 128 user = null; 129 kshieldAuth = null; 130 lastError = null; 131 132 initialized.set(false); 133 } 134 135 private String poll() { 136 return kshieldAuthManager().poll(ipAddress, kshieldAuth, isNotEmpty(user)); 137 } 138 139 private String token(String[] tokens, int idx) { 140 if (idx < tokens.length) { 141 return trimToNull(tokens[idx]); 142 } 143 144 return null; 145 } 146 147 private String trimToNull(String str) { 148 if (isEmpty(str) || "null".equals(str)) { 149 return null; 150 } 151 return str.trim(); 152 } 153 154 private boolean isEmpty(String str) { 155 return str == null || str.trim().isEmpty(); 156 } 157 158 protected boolean isNotEmpty(String str) { 159 return str != null && !str.isEmpty(); 160 } 161}