1 52 53 package com.go.teaservlet; 54 55 import java.io.Serializable ; 56 import java.util.*; 57 import java.net.*; 58 import java.rmi.Remote ; 59 import java.rmi.RemoteException ; 60 import java.lang.ref.*; 61 import com.go.trove.io.*; 62 import com.go.trove.log.Log; 63 import com.go.trove.util.*; 64 import com.go.trove.util.tq.*; 65 import com.go.tea.runtime.TemplateLoader; 66 import com.go.tea.runtime.Substitution; 67 import com.go.teaservlet.util.cluster.*; 68 import javax.servlet.ServletException ; 69 70 71 108 public class RegionCachingApplication implements AdminApp { 109 private Log mLog; 110 private int mCacheSize; 111 private long mDefaultTTL; 112 private long mTimeout; 113 private String [] mHeaders; 114 private int mCompressLevel; 115 116 private ClusterManager mClusterManager; 117 private ClusterCacheInfo mInfo; 118 119 private Map mTemplateKeys = new IdentityMap(); 121 122 private List mDepots = new ArrayList(10); 128 129 private TransactionQueue mTQ; 131 132 155 public void init(ApplicationConfig config) throws ServletException { 156 mLog = config.getLog(); 157 158 PropertyMap props = config.getProperties(); 159 mCacheSize = props.getInt("cache.size", 500); 160 mDefaultTTL = props.getNumber 161 ("default.ttl", new Long (5000)).longValue(); 162 mTimeout = props.getNumber("timeout", new Long (500)).longValue(); 163 164 PropertyMap tqProps = props.subMap("transactionQueue"); 165 166 int maxPool = tqProps.getInt("max.threads", 100); 167 ThreadPool tp = new ThreadPool(config.getName(), maxPool); 168 tp.setTimeout(5000); 169 tp.setIdleTimeout(60000); 170 171 mTQ = new TransactionQueue(tp, config.getName() + " TQ", 100, 100); 172 mTQ.applyProperties(tqProps); 173 174 String headers = props.getString("headers"); 175 176 if (headers == null) { 177 mHeaders = null; 178 } 179 else { 180 StringTokenizer st = new StringTokenizer(headers, " ;,"); 181 int count = st.countTokens(); 182 if (count == 0) { 183 mHeaders = null; 184 } 185 else { 186 mHeaders = new String [count]; 187 for (int i=0; i<count; i++) { 188 mHeaders[i] = st.nextToken(); 189 } 190 } 191 } 192 193 mCompressLevel = props.getInt("gzip", 0); 194 195 if (mCompressLevel < 0) { 196 mLog.warn("GZIP compression lowest level is 0. Level " + 197 mCompressLevel + " interpretted as 0"); 198 mCompressLevel = 0; 199 } 200 else if (mCompressLevel > 9) { 201 mLog.warn("GZIP compression highest level is 9. Level " + 202 mCompressLevel + " interpretted as 9"); 203 mCompressLevel = 9; 204 } 205 206 initCluster(config); 207 } 208 209 public void destroy() { 210 if (mClusterManager != null) { 211 mClusterManager.killAuto(); 212 } 213 } 214 215 218 public Object createContext(ApplicationRequest request, 219 ApplicationResponse response) { 220 return new RegionCachingContextImpl(this, request, response); 221 } 222 223 226 public Class getContextType() { 227 return RegionCachingContext.class; 228 } 229 230 public AppAdminLinks getAdminLinks() { 231 232 AppAdminLinks links = new AppAdminLinks(mLog.getName()); 233 links.addAdminLink("Depot","system.teaservlet.Depot"); 234 return links; 235 } 236 237 238 void cache(ApplicationRequest request, 239 ApplicationResponse response, 240 Substitution s) 241 throws Exception  242 { 243 cache(request, response, mDefaultTTL, null, s); 244 } 245 246 void cache(ApplicationRequest request, 247 ApplicationResponse response, 248 long ttlMillis, 249 Substitution s) 250 throws Exception  251 { 252 cache(request, response, ttlMillis, null, s); 253 } 254 255 void cache(ApplicationRequest request, 256 ApplicationResponse response, 257 long ttlMillis, 258 Object key, 259 Substitution s) 260 throws Exception  261 { 262 TemplateKey templateKey = getTemplateKey(request.getTemplate()); 263 264 Object [] keyElements = { 265 templateKey, 266 s.getIdentifier(), 267 getHeaderValues(request), 268 request.getQueryString(), 269 key, 270 }; 271 272 key = new MultiKey(keyElements); 273 274 ApplicationResponse.Command c = 275 new CacheCommand(s, templateKey, ttlMillis, key); 276 if (!response.insertCommand(c)) { 277 c.execute(request, response); 278 } 279 } 280 281 void nocache(ApplicationRequest request, 282 ApplicationResponse response, 283 Substitution s) 284 throws Exception  285 { 286 ApplicationResponse.Command c = new NoCacheCommand(s); 287 if (!response.insertCommand(c)) { 288 c.execute(request, response); 289 } 290 } 291 292 private TemplateKey getTemplateKey(TemplateLoader.Template template) { 293 synchronized (mTemplateKeys) { 294 TemplateKey key = (TemplateKey)mTemplateKeys.get(template); 295 if (key == null) { 296 key = new TemplateKey(template); 297 mTemplateKeys.put(template, key); 298 } 299 return key; 300 } 301 } 302 303 private String [] getHeaderValues(ApplicationRequest request) { 304 if (mHeaders == null) { 305 return null; 306 } 307 308 String [] headers = (String [])mHeaders.clone(); 309 for (int i = headers.length; --i >= 0; ) { 310 headers[i] = request.getHeader(headers[i]); 311 } 312 313 return headers; 314 } 315 316 Depot getDepot(TemplateLoader.Template template) { 317 return getDepot(getTemplateKey(template)); 318 } 319 320 Depot getDepot(TemplateKey key) { 321 TemplateLoader depotKey = key.getTemplateLoader(); 322 if (depotKey == null) { 323 return null; 324 } 325 326 DepotLink link; 327 Object linkKey; 328 Depot depot; 329 330 synchronized (mDepots) { 331 int size = mDepots.size(); 332 if (size == 1) { 333 link = (DepotLink)mDepots.get(0); 334 linkKey = link.get(); 335 if (linkKey == null) { 336 mDepots.clear(); 338 } 339 else if (linkKey == depotKey) { 340 return link.mDepot; 341 } 342 } 343 else if (size > 1) { 344 depot = null; 345 Iterator it = mDepots.iterator(); 346 while (it.hasNext()) { 347 link = (DepotLink)it.next(); 348 linkKey = link.get(); 349 if (linkKey == null) { 350 it.remove(); 352 } 353 else if (linkKey == depotKey) { 354 depot = link.mDepot; 355 } 357 } 358 if (depot != null) { 359 return depot; 360 } 361 } 362 363 depot = new Depot(null, mCacheSize, mTQ, mTimeout); 365 mDepots.add(new DepotLink(depotKey, depot)); 366 } 367 368 return depot; 369 } 370 371 372 private void initCluster(ApplicationConfig config) { 373 374 try { 375 String clusterName = config.getInitParameter("cluster.name"); 376 if (clusterName != null) { 377 mInfo = new ClusterCacheInfoImpl(clusterName, null); 378 mClusterManager = ClusterManager 379 .createClusterManager(config.getProperties(), mInfo); 380 } 381 } 382 catch(Exception e) { 383 mLog.warn("Failed to create ClusterManager."); 384 mLog.warn(e); 385 } 386 } 387 388 private static class TemplateKey extends WeakReference { 390 TemplateKey(TemplateLoader.Template template) { 391 super(template); 392 } 393 394 public boolean equals(Object obj) { 395 if (this == obj) { 396 return true; 397 } 398 if (obj instanceof TemplateKey) { 399 TemplateKey other = (TemplateKey)obj; 400 Object t = this.get(); 401 if (t != null) { 402 return t == other.get(); 403 } 404 } 405 return false; 406 } 407 408 public int hashCode() { 409 Object t = get(); 410 return (t == null) ? 0 : t.hashCode(); 411 } 412 413 public String toString() { 414 TemplateLoader.Template t = (TemplateLoader.Template)get(); 415 if (t != null) { 416 return t.getName(); 417 } 418 else { 419 return super.toString(); 420 } 421 } 422 423 TemplateLoader getTemplateLoader() { 424 TemplateLoader.Template t = (TemplateLoader.Template)get(); 425 return (t != null) ? t.getTemplateLoader() : null; 426 } 427 } 428 429 private static class DepotLink extends WeakReference { 430 final Depot mDepot; 431 432 DepotLink(TemplateLoader loader, Depot depot) { 433 super(loader); 434 mDepot = depot; 435 } 436 } 437 438 private class CacheCommand implements ApplicationResponse.Command { 439 final Substitution mSub; 440 final TemplateKey mTemplateKey; 441 final long mTTLMillis; 442 final Object mKey; 443 444 CacheCommand(Substitution s, TemplateKey templateKey, 445 long ttlMillis, Object key) { 446 mSub = s.detach(); 447 mTemplateKey = templateKey; 448 mTTLMillis = ttlMillis; 449 mKey = key; 450 } 451 452 public void execute(ApplicationRequest request, 453 ApplicationResponse response) 454 throws Exception  455 { 456 DetachedDataFactory factory = 457 new DetachedDataFactory(this, response); 458 459 ApplicationResponse.DetachedData data; 460 Depot depot = getDepot(mTemplateKey); 461 462 if (depot != null) { 463 data = (ApplicationResponse.DetachedData) 464 depot.get(factory, mKey); 465 if (mCompressLevel > 0 && !factory.mCalled) { 466 if (data != null && request.isCompressionAccepted()) { 470 try { 471 data.compress(mCompressLevel); 472 } 473 catch (UnsatisfiedLinkError e) { 474 mCompressLevel = 0; 476 mLog.error(e); 477 } 478 } 479 } 480 } 481 else { 482 data = (ApplicationResponse.DetachedData)factory.create(mKey); 485 } 486 487 if (data != null) { 488 data.playback(request, response); 489 } 490 } 491 492 Log getLog() { 493 return mLog; 494 } 495 } 496 497 private static class DetachedDataFactory 498 implements Depot.PerishablesFactory 499 { 500 boolean mCalled; 501 502 private CacheCommand mCommand; 503 private ApplicationResponse mResponse; 504 505 DetachedDataFactory(CacheCommand c, ApplicationResponse response) { 506 mCommand = c; 507 mResponse = response; 508 } 509 510 public Object create(Object xxx) throws InterruptedException { 511 mCalled = true; 512 try { 513 return mResponse.execDetached(mCommand.mSub); 514 } 515 catch (InterruptedException e) { 516 mCommand.getLog().error(e); 517 throw e; 518 } 519 catch (Exception e) { 520 mCommand.getLog().error(e); 521 throw new InterruptedException (e.getMessage()); 522 } 523 } 524 525 public long getValidDuration() { 526 return mCommand.mTTLMillis; 527 } 528 }; 529 530 private class NoCacheCommand implements ApplicationResponse.Command { 531 private Substitution mSub; 532 533 NoCacheCommand(Substitution s) { 534 mSub = s.detach(); 535 } 536 537 public void execute(ApplicationRequest request, 538 ApplicationResponse response) { 539 try { 540 mSub.detach().substitute(response.getHttpContext()); 541 } 542 catch (Exception e) { 543 mLog.error(e); 544 } 545 } 546 } 547 548 private class RegionCachingContextImpl 549 implements RegionCachingContext { 550 551 private final RegionCachingApplication mApp; 552 private final ApplicationRequest mRequest; 553 private final ApplicationResponse mResponse; 554 555 public RegionCachingContextImpl(RegionCachingApplication app, 556 ApplicationRequest request, 557 ApplicationResponse response) { 558 mApp = app; 559 mRequest = request; 560 mResponse = response; 561 } 562 563 569 public void cache(Substitution s) throws Exception { 570 mApp.cache(mRequest, mResponse, s); 571 } 572 573 580 public void cache(long ttlMillis, Substitution s) throws Exception { 581 mApp.cache(mRequest, mResponse, ttlMillis, s); 582 } 583 584 593 public void cache(long ttlMillis, Object key, Substitution s) 594 throws Exception  595 { 596 mApp.cache(mRequest, mResponse, ttlMillis, key, s); 597 } 598 599 public void nocache(Substitution s) throws Exception { 600 mApp.nocache(mRequest, mResponse, s); 601 } 602 603 public RegionCachingApplication.RegionCacheInfo getRegionCacheInfo() { 604 return new RegionCacheInfo(mApp.getDepot(mRequest.getTemplate())); 605 } 606 607 public RegionCachingApplication.ClusterCacheInfo getClusterCacheInfo() { 608 mClusterManager.resolveServerNames(); 609 return mInfo; 610 } 611 } 612 613 public interface ClusterCacheInfo extends Clustered { 614 615 public RegionCachingApplication.RegionCacheInfo getRegionCacheInfo() 616 throws RemoteException ; 617 } 618 619 public class ClusterCacheInfoImpl extends ClusterHook 620 implements RegionCachingApplication.ClusterCacheInfo { 621 622 ClusterCacheInfoImpl(String cluster, String server) 623 throws RemoteException { 624 super(cluster, server); 625 } 626 627 public RegionCachingApplication.RegionCacheInfo getRegionCacheInfo() 628 throws RemoteException { 629 int size = -1; 630 List depotList = RegionCachingApplication.this.mDepots; 631 if (depotList != null && (size = depotList.size()) > 0) { 632 DepotLink link = (DepotLink)depotList.get(0); 633 if (link != null) { 634 return new RegionCacheInfo(link.mDepot); 635 } 636 } 637 return null; 638 } 639 } 640 641 645 public class RegionCacheInfo implements Serializable { 646 647 private int size; 648 649 RegionCacheInfo(Depot depot) { 650 size = depot.size(); 652 } 653 654 public int getSize() { 655 return size; 656 } 657 } 658 } 659
| Popular Tags
|