View Javadoc

1   /*
2    * Copyright 2010-2011 Ning, Inc.
3    *
4    * Ning licenses this file to you under the Apache License, version 2.0
5    * (the "License"); you may not use this file except in compliance with the
6    * License.  You may obtain a copy of the License at:
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package com.ning.metrics.goodwill.access;
18  
19  import com.mogwee.executors.Executors;
20  
21  import java.util.Collections;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.concurrent.ConcurrentHashMap;
25  import java.util.concurrent.ExecutionException;
26  import java.util.concurrent.TimeUnit;
27  
28  public class CachingGoodwillAccessor extends Accessor
29  {
30      private static final int DEFAULT_CACHE_TIMEOUT_IN_SECONDS = 90;
31      private final Object cacheMonitor = new Object();
32  
33      private final ConcurrentHashMap<String, GoodwillSchema> knownSchemata = new ConcurrentHashMap<String, GoodwillSchema>();
34      private final GoodwillAccessor delegate;
35  
36      public CachingGoodwillAccessor(final String host, final int port)
37      {
38          this(host, port, DEFAULT_CACHE_TIMEOUT_IN_SECONDS);
39      }
40  
41      public CachingGoodwillAccessor(final String host, final int port, final int cacheTimeoutInSeconds)
42      {
43          super(host, port);
44  
45          delegate = new GoodwillAccessor(host, port);
46  
47          Executors.newScheduledThreadPool(1, "GoodwillCacheRefresher").scheduleWithFixedDelay(new Runnable()
48          {
49              @Override
50              public void run()
51              {
52                  refreshSchemataCache();
53              }
54          }, 0, cacheTimeoutInSeconds, TimeUnit.SECONDS);
55      }
56  
57      /**
58       * Invalidate and refresh the cache
59       * <p/>
60       * This is blocking and returns when the cache has been updated
61       */
62      public void refreshSchemataCache()
63      {
64          try {
65              final List<GoodwillSchema> schemata = delegate.getSchemata().get();
66  
67              // If Goodwill is down - keep the old cache around
68              if (schemata == null) {
69                  return;
70              }
71  
72              final Map<String,GoodwillSchema> newSchemataCache = new ConcurrentHashMap<String, GoodwillSchema>();
73              for (final GoodwillSchema schema : schemata) {
74                  newSchemataCache.put(schema.getName(), schema);
75              }
76  
77              synchronized (cacheMonitor) {
78                  knownSchemata.clear();
79                  knownSchemata.putAll(newSchemataCache);
80              }
81          }
82          catch (InterruptedException e) {
83              log.warn("Interrupted while refreshing the cache");
84              Thread.currentThread().interrupt();
85          }
86          catch (ExecutionException e) {
87              log.warn("Unable to refresh schemata cache: {}", e.getLocalizedMessage());
88          }
89      }
90  
91      /**
92       * Given a schema name, get the associated GoodwillSchema. This method tries hard to find it, i.e. it will refresh the
93       * cache if the schema is not in the cache.
94       *
95       * @param schemaName name of the schema to find
96       * @return GoodwillSchema describing the schema
97       */
98      public GoodwillSchema getSchema(final String schemaName)
99      {
100         GoodwillSchema schema = knownSchemata.get(schemaName);
101         if (schema == null) {
102             refreshSchemataCache();
103             schema = knownSchemata.get(schemaName);
104         }
105 
106         return schema;
107     }
108 
109     public List<GoodwillSchema> getSchemata()
110     {
111         return Collections.list(knownSchemata.elements());
112     }
113 
114     /**
115      * Close the underlying http client
116      */
117     public synchronized void close()
118     {
119         delegate.close();
120     }
121 }