%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.jcs.auxiliary.lateral.socket.tcp.LateralTCPSender |
|
|
1 | package org.apache.jcs.auxiliary.lateral.socket.tcp; |
|
2 | ||
3 | /* |
|
4 | * Licensed to the Apache Software Foundation (ASF) under one |
|
5 | * or more contributor license agreements. See the NOTICE file |
|
6 | * distributed with this work for additional information |
|
7 | * regarding copyright ownership. The ASF licenses this file |
|
8 | * to you under the Apache License, Version 2.0 (the |
|
9 | * "License"); you may not use this file except in compliance |
|
10 | * with the License. You may obtain a copy of the License at |
|
11 | * |
|
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
13 | * |
|
14 | * Unless required by applicable law or agreed to in writing, |
|
15 | * software distributed under the License is distributed on an |
|
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
|
17 | * KIND, either express or implied. See the License for the |
|
18 | * specific language governing permissions and limitations |
|
19 | * under the License. |
|
20 | */ |
|
21 | ||
22 | import java.io.BufferedReader; |
|
23 | import java.io.IOException; |
|
24 | import java.io.InputStreamReader; |
|
25 | import java.io.ObjectInputStream; |
|
26 | import java.io.ObjectOutputStream; |
|
27 | import java.net.InetAddress; |
|
28 | import java.net.Socket; |
|
29 | ||
30 | import org.apache.commons.logging.Log; |
|
31 | import org.apache.commons.logging.LogFactory; |
|
32 | import org.apache.jcs.auxiliary.lateral.LateralElementDescriptor; |
|
33 | import org.apache.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes; |
|
34 | import org.apache.jcs.auxiliary.lateral.socket.tcp.utils.SocketOpener; |
|
35 | import org.apache.jcs.engine.CacheElement; |
|
36 | import org.apache.jcs.engine.behavior.ICacheElement; |
|
37 | ||
38 | /** |
|
39 | * This class is based on the log4j SocketAppender class. I'm using a differnet repair structure, so |
|
40 | * it is significantly different. |
|
41 | */ |
|
42 | public class LateralTCPSender |
|
43 | { |
|
44 | 28 | private final static Log log = LogFactory.getLog( LateralTCPSender.class ); |
45 | ||
46 | private ITCPLateralCacheAttributes tcpLateralCacheAttributes; |
|
47 | ||
48 | private String remoteHost; |
|
49 | ||
50 | private InetAddress address; |
|
51 | ||
52 | 34 | int port = 1111; |
53 | ||
54 | private ObjectOutputStream oos; |
|
55 | ||
56 | private Socket socket; |
|
57 | ||
58 | 34 | int counter = 0; |
59 | ||
60 | 34 | private int sendCnt = 0; |
61 | ||
62 | // reset the ObjectOutputStream every 70 calls |
|
63 | // private static final int RESET_FREQUENCY = 70; |
|
64 | // Perhaps we need to resett every time until we move to jdk 1.4 |
|
65 | // then we can call writeUnshared to make sure |
|
66 | // that the object definetely gets across and not |
|
67 | // a stream cached version. |
|
68 | // I can't replicate an issue that was reported, so I'm not changing the |
|
69 | // reset frequency for now. |
|
70 | private final static int RESET_FREQUENCY = 70; |
|
71 | ||
72 | /** |
|
73 | * Only block for 1 second before timing out on a read. TODO: make configurable. The default 1 |
|
74 | * is way too long. |
|
75 | */ |
|
76 | private final static int timeOut = 1000; |
|
77 | ||
78 | /** Only block for 5 seconds before timing out on startup. */ |
|
79 | private final static int openTimeOut = 5000; |
|
80 | ||
81 | /** Use to synchronize multiple threads that may be trying to get. */ |
|
82 | 34 | private Object getLock = new int[0]; |
83 | ||
84 | /** |
|
85 | * Constructor for the LateralTCPSender object. |
|
86 | * <p> |
|
87 | * @param lca |
|
88 | * @exception IOException |
|
89 | */ |
|
90 | public LateralTCPSender( ITCPLateralCacheAttributes lca ) |
|
91 | throws IOException |
|
92 | 34 | { |
93 | 34 | this.setTcpLateralCacheAttributes( lca ); |
94 | ||
95 | 34 | String p1 = lca.getTcpServer(); |
96 | 34 | if ( p1 != null ) |
97 | { |
|
98 | 34 | String h2 = p1.substring( 0, p1.indexOf( ":" ) ); |
99 | 34 | int po = Integer.parseInt( p1.substring( p1.indexOf( ":" ) + 1 ) ); |
100 | 34 | if ( log.isDebugEnabled() ) |
101 | { |
|
102 | 0 | log.debug( "h2 = " + h2 ); |
103 | 0 | log.debug( "po = " + po ); |
104 | } |
|
105 | ||
106 | 34 | if ( h2 == null ) |
107 | { |
|
108 | 0 | throw new IOException( "Cannot connect to invalid address [" + h2 + ":" + po + "]" ); |
109 | } |
|
110 | ||
111 | 34 | init( h2, po ); |
112 | } |
|
113 | 20 | } |
114 | ||
115 | /** |
|
116 | * Creates a connection to a TCP server. |
|
117 | * <p> |
|
118 | * @param host |
|
119 | * @param port |
|
120 | * @throws IOException |
|
121 | */ |
|
122 | protected void init( String host, int port ) |
|
123 | throws IOException |
|
124 | { |
|
125 | 34 | this.port = port; |
126 | 34 | this.address = getAddressByName( host ); |
127 | 34 | this.setRemoteHost( host ); |
128 | ||
129 | try |
|
130 | { |
|
131 | 34 | if ( log.isInfoEnabled() ) |
132 | { |
|
133 | 34 | log.info( "Attempting connection to [" + address.getHostName() + "]" ); |
134 | } |
|
135 | ||
136 | // have time out socket open do this for us |
|
137 | 34 | socket = SocketOpener.openSocket( host, port, openTimeOut ); |
138 | ||
139 | 34 | if ( socket == null ) |
140 | { |
|
141 | 14 | throw new IOException( "Socket is null, cannot connect to " + host + ":" + port ); |
142 | } |
|
143 | ||
144 | 20 | socket.setSoTimeout( LateralTCPSender.timeOut ); |
145 | 20 | synchronized ( this ) |
146 | { |
|
147 | 20 | oos = new ObjectOutputStream( socket.getOutputStream() ); |
148 | 20 | } |
149 | } |
|
150 | 0 | catch ( java.net.ConnectException e ) |
151 | { |
|
152 | 0 | log.debug( "Remote host [" + address.getHostName() + "] refused connection." ); |
153 | 0 | throw e; |
154 | } |
|
155 | 14 | catch ( IOException e ) |
156 | { |
|
157 | 14 | log.debug( "Could not connect to [" + address.getHostName() + "]. Exception is " + e ); |
158 | 14 | throw e; |
159 | 20 | } |
160 | 20 | } |
161 | ||
162 | /** |
|
163 | * Gets the addressByName attribute of the LateralTCPSender object. |
|
164 | * <p> |
|
165 | * @param host |
|
166 | * @return The addressByName value |
|
167 | * @throws IOException |
|
168 | */ |
|
169 | private InetAddress getAddressByName( String host ) |
|
170 | throws IOException |
|
171 | { |
|
172 | try |
|
173 | { |
|
174 | 34 | return InetAddress.getByName( host ); |
175 | } |
|
176 | 0 | catch ( Exception e ) |
177 | { |
|
178 | 0 | log.error( "Could not find address of [" + host + "] ", e ); |
179 | 0 | throw new IOException( "Could not find address of [" + host + "] " + e.getMessage() ); |
180 | } |
|
181 | } |
|
182 | ||
183 | /** |
|
184 | * Sends commands to the lateral cache listener. |
|
185 | * <p> |
|
186 | * @param led |
|
187 | * @throws IOException |
|
188 | */ |
|
189 | public void send( LateralElementDescriptor led ) |
|
190 | throws IOException |
|
191 | { |
|
192 | 1419 | sendCnt++; |
193 | 1419 | if ( log.isInfoEnabled() ) |
194 | { |
|
195 | 1419 | if ( sendCnt % 100 == 0 ) |
196 | { |
|
197 | 14 | log.info( "Send Count (port " + port + ") = " + sendCnt ); |
198 | } |
|
199 | } |
|
200 | ||
201 | 1419 | if ( log.isDebugEnabled() ) |
202 | { |
|
203 | 0 | log.debug( "sending LateralElementDescriptor" ); |
204 | } |
|
205 | ||
206 | 1419 | if ( led == null ) |
207 | { |
|
208 | 0 | return; |
209 | } |
|
210 | ||
211 | 1419 | if ( address == null ) |
212 | { |
|
213 | 0 | throw new IOException( "No remote host is set for LateralTCPSender." ); |
214 | } |
|
215 | ||
216 | 1419 | if ( oos != null ) |
217 | { |
|
218 | 1419 | synchronized ( this.getLock ) |
219 | { |
|
220 | try |
|
221 | { |
|
222 | 1419 | oos.writeObject( led ); |
223 | 1419 | oos.flush(); |
224 | 1419 | if ( ++counter >= RESET_FREQUENCY ) |
225 | { |
|
226 | 14 | counter = 0; |
227 | // Failing to reset the object output stream every now and |
|
228 | // then creates a serious memory leak. |
|
229 | 14 | if ( log.isDebugEnabled() ) |
230 | { |
|
231 | 0 | log.debug( "Doing oos.reset()" ); |
232 | } |
|
233 | 14 | oos.reset(); |
234 | } |
|
235 | } |
|
236 | 0 | catch ( IOException e ) |
237 | { |
|
238 | 0 | oos = null; |
239 | 0 | log.error( "Detected problem with connection: " + e ); |
240 | 0 | throw e; |
241 | 1419 | } |
242 | 1419 | } |
243 | } |
|
244 | 1419 | } |
245 | ||
246 | /** |
|
247 | * Sends commands to the lateral cache listener and gets a response. I'm afraid that we could |
|
248 | * get into a pretty bad blocking situation here. This needs work. I just wanted to get some |
|
249 | * form of get working. However, get is not recommended for performance reasons. If you have 10 |
|
250 | * laterals, then you have to make 10 failed gets to find out none of the caches have the item. |
|
251 | * <p> |
|
252 | * @param led |
|
253 | * @return |
|
254 | * @throws IOException |
|
255 | */ |
|
256 | public ICacheElement sendAndReceive( LateralElementDescriptor led ) |
|
257 | throws IOException |
|
258 | { |
|
259 | 0 | ICacheElement ice = null; |
260 | ||
261 | 0 | if ( led == null ) |
262 | { |
|
263 | 0 | return null; |
264 | } |
|
265 | ||
266 | 0 | if ( address == null ) |
267 | { |
|
268 | 0 | throw new IOException( "No remote host is set for LateralTCPSender." ); |
269 | } |
|
270 | ||
271 | 0 | if ( oos != null ) |
272 | { |
|
273 | // Synchronized to insure that the get requests to server from this |
|
274 | // sender and the responses are processed in order, else you could |
|
275 | // return the wrong item from the cache. |
|
276 | // This is a big block of code. May need to rethink this strategy. |
|
277 | // This may not be necessary. |
|
278 | // Normal puts, etc to laterals do not have to be synchronized. |
|
279 | 0 | synchronized ( this.getLock ) |
280 | { |
|
281 | try |
|
282 | { |
|
283 | try |
|
284 | { |
|
285 | // clean up input stream, nothing should be there yet. |
|
286 | 0 | if ( socket.getInputStream().available() > 0 ) |
287 | { |
|
288 | 0 | socket.getInputStream().read( new byte[socket.getInputStream().available()] ); |
289 | } |
|
290 | } |
|
291 | 0 | catch ( IOException ioe ) |
292 | { |
|
293 | 0 | log.error( "Problem cleaning socket before send " + socket, ioe ); |
294 | 0 | throw ioe; |
295 | 0 | } |
296 | ||
297 | // write object to listener |
|
298 | 0 | oos.writeObject( led ); |
299 | 0 | oos.flush(); |
300 | ||
301 | try |
|
302 | { |
|
303 | // TODO make configurable |
|
304 | // socket.setSoTimeout( 2000 ); |
|
305 | 0 | ObjectInputStream ois = new ObjectInputStream( socket.getInputStream() ); |
306 | 0 | Object obj = ois.readObject(); |
307 | 0 | ice = (ICacheElement) obj; |
308 | 0 | if ( ice == null ) |
309 | { |
|
310 | // p( "ice is null" ); |
|
311 | // TODO: count misses |
|
312 | } |
|
313 | } |
|
314 | 0 | catch ( IOException ioe ) |
315 | { |
|
316 | 0 | String message = "Could not open ObjectInputStream to " + socket; |
317 | 0 | if ( socket != null ) |
318 | { |
|
319 | 0 | message += " SoTimeout [" + socket.getSoTimeout() + "]"; |
320 | // this is 1.4 specific -- Connected [" + socket.isConnected() + "]"; |
|
321 | } |
|
322 | 0 | log.error( message, ioe ); |
323 | 0 | throw ioe; |
324 | } |
|
325 | 0 | catch ( Exception e ) |
326 | { |
|
327 | 0 | log.error( e ); |
328 | 0 | } |
329 | ||
330 | 0 | if ( ++counter >= RESET_FREQUENCY ) |
331 | { |
|
332 | 0 | counter = 0; |
333 | // Failing to reset the object output stream every now |
|
334 | // and |
|
335 | // then creates a serious memory leak. |
|
336 | 0 | log.info( "Doing oos.reset()" ); |
337 | 0 | oos.reset(); |
338 | } |
|
339 | } |
|
340 | 0 | catch ( IOException e ) |
341 | { |
|
342 | 0 | oos = null; |
343 | 0 | log.error( "Detected problem with connection: " + e ); |
344 | 0 | throw e; |
345 | 0 | } |
346 | 0 | } |
347 | } |
|
348 | ||
349 | 0 | return ice; |
350 | } |
|
351 | ||
352 | /** |
|
353 | * Closes connection used by all LateralTCPSenders for this lateral conneciton. Dispose request |
|
354 | * should come into the facade and be sent to all lateral cache sevices. The lateral cache |
|
355 | * service will then call this method. |
|
356 | * <p> |
|
357 | * @param cache |
|
358 | * @throws IOException |
|
359 | */ |
|
360 | public void dispose( String cache ) |
|
361 | throws IOException |
|
362 | { |
|
363 | 0 | if ( log.isInfoEnabled() ) |
364 | { |
|
365 | 0 | log.info( "Dispose called for cache [" + cache + "]" ); |
366 | } |
|
367 | // WILL CLOSE CONNECTION USED BY ALL |
|
368 | 0 | oos.close(); |
369 | 0 | } |
370 | ||
371 | /** |
|
372 | * @param tcpLateralCacheAttributes The tcpLateralCacheAttributes to set. |
|
373 | */ |
|
374 | public void setTcpLateralCacheAttributes( ITCPLateralCacheAttributes tcpLateralCacheAttributes ) |
|
375 | { |
|
376 | 34 | this.tcpLateralCacheAttributes = tcpLateralCacheAttributes; |
377 | 34 | } |
378 | ||
379 | /** |
|
380 | * @return Returns the tcpLateralCacheAttributes. |
|
381 | */ |
|
382 | public ITCPLateralCacheAttributes getTcpLateralCacheAttributes() |
|
383 | { |
|
384 | 0 | return tcpLateralCacheAttributes; |
385 | } |
|
386 | ||
387 | /** |
|
388 | * @param remoteHost The remoteHost to set. |
|
389 | */ |
|
390 | public void setRemoteHost( String remoteHost ) |
|
391 | { |
|
392 | 34 | this.remoteHost = remoteHost; |
393 | 34 | } |
394 | ||
395 | /** |
|
396 | * @return Returns the remoteHost. |
|
397 | */ |
|
398 | public String getRemoteHost() |
|
399 | { |
|
400 | 0 | return remoteHost; |
401 | } |
|
402 | ||
403 | /** |
|
404 | * This is a Testing Method. It should be moved to a unit test. |
|
405 | * @param args |
|
406 | */ |
|
407 | public static void main( String args[] ) |
|
408 | { |
|
409 | try |
|
410 | { |
|
411 | 0 | LateralTCPSender lur = null; |
412 | // new LateralTCPSender( "localhost", 1111 ); |
|
413 | ||
414 | // process user input till done |
|
415 | 0 | boolean notDone = true; |
416 | 0 | String message = null; |
417 | // wait to dispose |
|
418 | 0 | BufferedReader br = new BufferedReader( class="keyword">new InputStreamReader( System.in ) ); |
419 | ||
420 | 0 | while ( notDone ) |
421 | { |
|
422 | 0 | System.out.println( "enter mesage:" ); |
423 | 0 | message = br.readLine(); |
424 | 0 | CacheElement ce = new CacheElement( "test", "test", message ); |
425 | 0 | LateralElementDescriptor led = new LateralElementDescriptor( ce ); |
426 | 0 | lur.send( led ); |
427 | 0 | } |
428 | } |
|
429 | 0 | catch ( Exception e ) |
430 | { |
|
431 | 0 | System.out.println( e.toString() ); |
432 | 0 | } |
433 | 0 | } |
434 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |