Clover coverage report - Code Coverage for hivemind release 1.0-beta-1
Coverage timestamp: Sat Jul 3 2004 09:41:37 EDT
file stats: LOC: 606   Methods: 28
NCLOC: 395   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
RegistryImpl.java 80% 89.9% 96.4% 88.2%
coverage coverage
 1   
 //  Copyright 2004 The Apache Software Foundation
 2   
 //
 3   
 // Licensed under the Apache License, Version 2.0 (the "License");
 4   
 // you may not use this file except in compliance with the License.
 5   
 // You may obtain a copy of the License at
 6   
 //
 7   
 //     http://www.apache.org/licenses/LICENSE-2.0
 8   
 //
 9   
 // Unless required by applicable law or agreed to in writing, software
 10   
 // distributed under the License is distributed on an "AS IS" BASIS,
 11   
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12   
 // See the License for the specific language governing permissions and
 13   
 // limitations under the License.
 14   
 
 15   
 package org.apache.hivemind.impl;
 16   
 
 17   
 import java.lang.reflect.Constructor;
 18   
 import java.util.HashMap;
 19   
 import java.util.Iterator;
 20   
 import java.util.List;
 21   
 import java.util.Locale;
 22   
 import java.util.Map;
 23   
 
 24   
 import org.apache.commons.logging.Log;
 25   
 import org.apache.commons.logging.LogFactory;
 26   
 import org.apache.hivemind.ApplicationRuntimeException;
 27   
 import org.apache.hivemind.ErrorHandler;
 28   
 import org.apache.hivemind.HiveMind;
 29   
 import org.apache.hivemind.HiveMindMessages;
 30   
 import org.apache.hivemind.Location;
 31   
 import org.apache.hivemind.Registry;
 32   
 import org.apache.hivemind.ShutdownCoordinator;
 33   
 import org.apache.hivemind.SymbolSource;
 34   
 import org.apache.hivemind.SymbolSourceContribution;
 35   
 import org.apache.hivemind.internal.ConfigurationPoint;
 36   
 import org.apache.hivemind.internal.RegistryInfrastructure;
 37   
 import org.apache.hivemind.internal.ServiceModelFactory;
 38   
 import org.apache.hivemind.internal.ServicePoint;
 39   
 import org.apache.hivemind.order.Orderer;
 40   
 import org.apache.hivemind.schema.Translator;
 41   
 import org.apache.hivemind.schema.rules.ClassTranslator;
 42   
 import org.apache.hivemind.schema.rules.SmartTranslator;
 43   
 import org.apache.hivemind.service.ThreadEventNotifier;
 44   
 import org.apache.hivemind.util.ToStringBuilder;
 45   
 
 46   
 /**
 47   
  * Implementation of {@link org.apache.hivemind.Registry}.
 48   
  *
 49   
  * @author Howard Lewis Ship
 50   
  */
 51   
 public final class RegistryImpl implements Registry, RegistryInfrastructure
 52   
 {
 53   
     private static final String SYMBOL_SOURCES = "hivemind.SymbolSources";
 54   
     private static final Log LOG = LogFactory.getLog(RegistryImpl.class);
 55   
 
 56   
     private static final String TRANSLATORS_CONFIGURATION_ID = "hivemind.Translators";
 57   
 
 58   
     private Map _servicePoints = new HashMap();
 59   
     private Map _configurationPoints = new HashMap();
 60   
 
 61   
     private SymbolSource[] _variableSources;
 62   
     private ErrorHandler _errorHandler;
 63   
     private Locale _locale;
 64   
     private ShutdownCoordinator _shutdownCoordinator;
 65   
 
 66   
     /**
 67   
      * Map of {@link ServiceModelFactory}, keyed on service model name,
 68   
      * loaded from <code>hivemind.ServiceModels</code> configuration point.
 69   
      */
 70   
     private Map _serviceModelFactories;
 71   
 
 72   
     /**
 73   
      * Map of Class, keyed on translator name, used to instantiate
 74   
      * new {@link org.apache.hivemind.schema.Translator}s. Loaded
 75   
      * from the <code>hivemind.Translators</code> configuration point;
 76   
      */
 77   
     private Map _translatorClasses = new HashMap();
 78   
     private Map _translatorsCache = new HashMap();
 79   
     private boolean _translatorsLoaded;
 80   
 
 81   
     private boolean _started = false;
 82   
     private boolean _shutdown = false;
 83   
 
 84   
     private ThreadEventNotifier _threadEventNotifier;
 85   
 
 86  79
     public RegistryImpl(ErrorHandler errorHandler, Locale locale)
 87   
     {
 88  79
         _errorHandler = errorHandler;
 89  79
         _locale = locale;
 90   
 
 91   
         // Seed the basic translators used to "bootstrap" the
 92   
         // processing of the hivemind.Translators configuration point.
 93   
 
 94  79
         _translatorClasses.put("class", ClassTranslator.class);
 95  79
         _translatorClasses.put("smart", SmartTranslator.class);
 96   
     }
 97   
 
 98  7
     public Locale getLocale()
 99   
     {
 100  7
         return _locale;
 101   
     }
 102   
 
 103  841
     public void addServicePoint(ServicePoint point)
 104   
     {
 105  841
         checkStarted();
 106   
 
 107  841
         _servicePoints.put(point.getExtensionPointId(), point);
 108   
     }
 109   
 
 110  582
     public void addConfigurationPoint(ConfigurationPoint point)
 111   
     {
 112  582
         checkStarted();
 113   
 
 114  582
         _configurationPoints.put(point.getExtensionPointId(), point);
 115   
     }
 116   
 
 117  786
     public ServicePoint getServicePoint(String serviceId)
 118   
     {
 119  786
         checkShutdown();
 120   
 
 121  786
         ServicePoint result = (ServicePoint) _servicePoints.get(serviceId);
 122   
 
 123  786
         if (result == null)
 124  0
             throw new ApplicationRuntimeException(ImplMessages.noSuchServicePoint(serviceId));
 125   
 
 126  786
         return result;
 127   
     }
 128   
 
 129  555
     public Object getService(String serviceId, Class serviceInterface)
 130   
     {
 131  555
         ServicePoint point = getServicePoint(serviceId);
 132   
 
 133  555
         return point.getService(serviceInterface);
 134   
     }
 135   
 
 136  357
     public ConfigurationPoint getConfigurationPoint(String configurationId)
 137   
     {
 138  357
         checkShutdown();
 139   
 
 140  356
         ConfigurationPoint result = (ConfigurationPoint) _configurationPoints.get(configurationId);
 141   
 
 142  356
         if (result == null)
 143  1
             throw new ApplicationRuntimeException(
 144   
                 ImplMessages.noSuchConfiguration(configurationId));
 145   
 
 146  355
         return result;
 147   
     }
 148   
 
 149  356
     public List getConfiguration(String configurationId)
 150   
     {
 151  356
         ConfigurationPoint point = getConfigurationPoint(configurationId);
 152   
 
 153  354
         return point.getElements();
 154   
     }
 155   
 
 156  2
     public String toString()
 157   
     {
 158  2
         ToStringBuilder builder = new ToStringBuilder(this);
 159   
 
 160  2
         builder.append("locale", _locale);
 161   
 
 162  2
         return builder.toString();
 163   
     }
 164   
 
 165   
     private static final int STATE_START = 0;
 166   
     private static final int STATE_DOLLAR = 1;
 167   
     private static final int STATE_COLLECT_SYMBOL_NAME = 2;
 168   
 
 169   
     /**
 170   
      * 
 171   
      * Note: a little cut-n-paste from {@link org.apache.tapestry.script.AbstractTokenRule}.
 172   
      */
 173  3231
     public String expandSymbols(String text, Location location)
 174   
     {
 175  3231
         StringBuffer result = new StringBuffer(text.length());
 176  3231
         char[] buffer = text.toCharArray();
 177  3231
         int state = STATE_START;
 178  3231
         int blockStart = 0;
 179  3231
         int blockLength = 0;
 180  3231
         int symbolStart = -1;
 181  3231
         int symbolLength = 0;
 182  3231
         int i = 0;
 183  3231
         int braceDepth = 0;
 184  3231
         boolean anySymbols = false;
 185   
 
 186  3231
         while (i < buffer.length)
 187   
         {
 188  91859
             char ch = buffer[i];
 189   
 
 190  91859
             switch (state)
 191   
             {
 192   
                 case STATE_START :
 193   
 
 194  91826
                     if (ch == '$')
 195   
                     {
 196  5
                         state = STATE_DOLLAR;
 197  5
                         i++;
 198  5
                         continue;
 199   
                     }
 200   
 
 201  91821
                     blockLength++;
 202  91821
                     i++;
 203  91821
                     continue;
 204   
 
 205   
                 case STATE_DOLLAR :
 206   
 
 207  5
                     if (ch == '{')
 208   
                     {
 209  5
                         state = STATE_COLLECT_SYMBOL_NAME;
 210  5
                         i++;
 211   
 
 212  5
                         symbolStart = i;
 213  5
                         symbolLength = 0;
 214  5
                         braceDepth = 1;
 215   
 
 216  5
                         continue;
 217   
                     }
 218   
 
 219   
                     // The '$' was just what it was, not the start of a ${} expression
 220   
                     // block, so include it as part of the static text block.
 221   
 
 222  0
                     blockLength++;
 223   
 
 224  0
                     state = STATE_START;
 225  0
                     continue;
 226   
 
 227   
                 case STATE_COLLECT_SYMBOL_NAME :
 228   
 
 229  28
                     if (ch != '}')
 230   
                     {
 231  23
                         if (ch == '{')
 232  0
                             braceDepth++;
 233   
 
 234  23
                         i++;
 235  23
                         symbolLength++;
 236  23
                         continue;
 237   
                     }
 238   
 
 239  5
                     braceDepth--;
 240   
 
 241  5
                     if (braceDepth > 0)
 242   
                     {
 243  0
                         i++;
 244  0
                         symbolLength++;
 245  0
                         continue;
 246   
                     }
 247   
 
 248   
                     // Hit the closing brace of a symbol.
 249   
 
 250   
                     // Degenerate case:  the string "${}".
 251   
 
 252  5
                     if (symbolLength == 0)
 253  0
                         blockLength += 3;
 254   
 
 255   
                     // Append anything up to the start of the sequence (this is static
 256   
                     // text between symbol references).
 257   
 
 258  5
                     if (blockLength > 0)
 259  1
                         result.append(buffer, blockStart, blockLength);
 260   
 
 261  5
                     if (symbolLength > 0)
 262   
                     {
 263  5
                         String variableName =
 264   
                             text.substring(symbolStart, symbolStart + symbolLength);
 265   
 
 266  5
                         result.append(expandSymbol(variableName, location));
 267   
 
 268  5
                         anySymbols = true;
 269   
                     }
 270   
 
 271  5
                     i++;
 272  5
                     blockStart = i;
 273  5
                     blockLength = 0;
 274   
 
 275   
                     // And drop into state start
 276   
 
 277  5
                     state = STATE_START;
 278   
 
 279  5
                     continue;
 280   
             }
 281   
 
 282   
         }
 283   
 
 284   
         // If get this far without seeing any variables, then just pass
 285   
         // the input back.
 286   
 
 287  3231
         if (!anySymbols)
 288  3226
             return text;
 289   
 
 290   
         // OK, to handle the end.  Couple of degenerate cases where
 291   
         // a ${...} was incomplete, so we adust the block length.
 292   
 
 293  5
         if (state == STATE_DOLLAR)
 294  0
             blockLength++;
 295   
 
 296  5
         if (state == STATE_COLLECT_SYMBOL_NAME)
 297  0
             blockLength += symbolLength + 2;
 298   
 
 299  5
         if (blockLength > 0)
 300  1
             result.append(buffer, blockStart, blockLength);
 301   
 
 302  5
         return result.toString();
 303   
     }
 304   
 
 305  5
     private String expandSymbol(String name, Location location)
 306   
     {
 307  5
         String value = valueForSymbol(name);
 308   
 
 309  5
         if (value != null)
 310  4
             return value;
 311   
 
 312  1
         _errorHandler.error(LOG, ImplMessages.noSuchSymbol(name), location, null);
 313   
 
 314  1
         return "${" + name + "}";
 315   
     }
 316   
 
 317  5
     public String valueForSymbol(String name)
 318   
     {
 319  5
         checkShutdown();
 320   
 
 321  5
         SymbolSource[] sources = getSymbolSources();
 322   
 
 323  5
         for (int i = 0; i < sources.length; i++)
 324   
         {
 325  7
             String value = sources[i].valueForSymbol(name);
 326   
 
 327  7
             if (value != null)
 328  4
                 return value;
 329   
         }
 330   
 
 331  1
         return null;
 332   
     }
 333   
 
 334  5
     private synchronized SymbolSource[] getSymbolSources()
 335   
     {
 336  5
         if (_variableSources != null)
 337  2
             return _variableSources;
 338   
 
 339  3
         List contributions = getConfiguration(SYMBOL_SOURCES);
 340   
 
 341  3
         Orderer o =
 342   
             new Orderer(
 343   
                 LogFactory.getLog(SYMBOL_SOURCES),
 344   
                 _errorHandler,
 345   
                 ImplMessages.symbolSourceContribution());
 346   
 
 347  3
         Iterator i = contributions.iterator();
 348  3
         while (i.hasNext())
 349   
         {
 350  8
             SymbolSourceContribution c = (SymbolSourceContribution) i.next();
 351   
 
 352  8
             o.add(c, c.getName(), c.getPrecedingNames(), c.getFollowingNames());
 353   
         }
 354   
 
 355  3
         List sources = o.getOrderedObjects();
 356   
 
 357  3
         int count = sources.size();
 358   
 
 359  3
         _variableSources = new SymbolSource[count];
 360   
 
 361  3
         for (int j = 0; j < count; j++)
 362   
         {
 363  8
             SymbolSourceContribution c = (SymbolSourceContribution) sources.get(j);
 364  8
             _variableSources[j] = c.getSource();
 365   
         }
 366   
 
 367  3
         return _variableSources;
 368   
     }
 369   
 
 370  78
     public void setShutdownCoordinator(ShutdownCoordinator coordinator)
 371   
     {
 372  78
         _shutdownCoordinator = coordinator;
 373   
     }
 374   
 
 375   
     /**
 376   
      * Invokes {@link ShutdownCoordinator#shutdown()}, then releases
 377   
      * the coordinator, modules and variable sources.
 378   
      */
 379  10
     public void shutdown()
 380   
     {
 381  10
         checkShutdown();
 382   
         // Allow service implementations and such to shutdown.
 383   
 
 384  9
         ShutdownCoordinator coordinatorService =
 385   
             (ShutdownCoordinator) getService("hivemind.ShutdownCoordinator",
 386   
                 ShutdownCoordinator.class);
 387   
 
 388  9
         coordinatorService.shutdown();
 389   
 
 390  9
         _shutdown = true;
 391   
 
 392   
         // Shutdown infrastructure items, such as proxies.
 393   
 
 394  9
         _shutdownCoordinator.shutdown();
 395   
 
 396  9
         _servicePoints = null;
 397  9
         _configurationPoints = null;
 398  9
         _shutdownCoordinator = null;
 399  9
         _variableSources = null;
 400  9
         _serviceModelFactories = null;
 401  9
         _threadEventNotifier = null;
 402   
     }
 403   
 
 404  1158
     private void checkShutdown()
 405   
     {
 406  1158
         if (_shutdown)
 407  2
             throw new ApplicationRuntimeException(HiveMindMessages.registryShutdown());
 408   
     }
 409   
 
 410  1501
     private void checkStarted()
 411   
     {
 412  1501
         if (_started)
 413  0
             throw new IllegalStateException(ImplMessages.registryAlreadyStarted());
 414   
     }
 415   
 
 416   
     /**
 417   
      * Starts up the Registry after all service and configuration points have been defined.
 418   
      * This locks down the Registry so that no further extension points may be added.
 419   
      * This method may only be invoked once.
 420   
      * 
 421   
      * <p>
 422   
      * In addition, the service <code>hivemind.Startup</code> is obtained and 
 423   
      * <code>run()</code> is invoked on it. This allows additional startup, provided
 424   
      * in the <code>hivemind.Startup</code> configuration point, to be executed.
 425   
      */
 426  78
     public void startup()
 427   
     {
 428  78
         checkStarted();
 429   
 
 430  78
         _started = true;
 431   
 
 432  78
         Runnable startup = (Runnable) getService("hivemind.Startup", Runnable.class);
 433   
 
 434  78
         startup.run();
 435   
     }
 436   
 
 437  399
     public synchronized ServiceModelFactory getServiceModelFactory(String name)
 438   
     {
 439  399
         if (_serviceModelFactories == null)
 440  78
             readServiceModelFactories();
 441   
 
 442  399
         ServiceModelFactory result = (ServiceModelFactory) _serviceModelFactories.get(name);
 443   
 
 444  399
         if (result == null)
 445  0
             throw new ApplicationRuntimeException(ImplMessages.unknownServiceModel(name));
 446   
 
 447  399
         return result;
 448   
     }
 449   
 
 450  78
     private void readServiceModelFactories()
 451   
     {
 452  78
         List l = getConfiguration("hivemind.ServiceModels");
 453   
 
 454  78
         _serviceModelFactories = new HashMap();
 455   
 
 456  78
         Iterator i = l.iterator();
 457   
 
 458  78
         while (i.hasNext())
 459   
         {
 460  312
             ServiceModelContribution smc = (ServiceModelContribution) i.next();
 461   
 
 462  312
             String name = smc.getName();
 463   
 
 464  312
             ServiceModelFactory old = (ServiceModelFactory) _serviceModelFactories.get(name);
 465   
 
 466  312
             if (old != null)
 467   
             {
 468  0
                 _errorHandler.error(
 469   
                     LOG,
 470   
                     ImplMessages.dupeServiceModelName(name, HiveMind.getLocation(old)),
 471   
                     HiveMind.getLocation(smc),
 472   
                     null);
 473   
 
 474  0
                 continue;
 475   
             }
 476   
 
 477  312
             _serviceModelFactories.put(name, smc.getFactory());
 478   
         }
 479   
     }
 480   
 
 481  3307
     public synchronized Translator getTranslator(String constructor)
 482   
     {
 483  3307
         Translator result = (Translator) _translatorsCache.get(constructor);
 484   
 
 485  3307
         if (result == null)
 486   
         {
 487  398
             result = constructTranslator(constructor);
 488  398
             _translatorsCache.put(constructor, result);
 489   
         }
 490   
 
 491  3307
         return result;
 492   
     }
 493   
 
 494  398
     private Translator constructTranslator(String constructor)
 495   
     {
 496  398
         String name = constructor;
 497  398
         String initializer = null;
 498   
 
 499  398
         int commax = constructor.indexOf(',');
 500   
 
 501  398
         if (commax > 0)
 502   
         {
 503  1
             name = constructor.substring(0, commax);
 504  1
             initializer = constructor.substring(commax + 1);
 505   
         }
 506   
 
 507  398
         Class translatorClass = findTranslatorClass(name);
 508   
 
 509  398
         return createTranslator(translatorClass, initializer);
 510   
     }
 511   
 
 512  398
     private Translator createTranslator(Class translatorClass, String initializer)
 513   
     {
 514  398
         try
 515   
         {
 516   
 
 517  398
             if (initializer == null)
 518  397
                 return (Translator) translatorClass.newInstance();
 519   
 
 520  1
             Constructor c = translatorClass.getConstructor(new Class[] { String.class });
 521   
 
 522  1
             return (Translator) c.newInstance(new Object[] { initializer });
 523   
         }
 524   
         catch (Exception ex)
 525   
         {
 526  0
             throw new ApplicationRuntimeException(
 527   
                 ImplMessages.translatorInstantiationFailure(translatorClass, ex),
 528   
                 ex);
 529   
         }
 530   
     }
 531   
 
 532  398
     private Class findTranslatorClass(String translatorName)
 533   
     {
 534  398
         Class result = (Class) _translatorClasses.get(translatorName);
 535   
 
 536  398
         if (result == null && !_translatorsLoaded)
 537   
         {
 538  78
             loadTranslators();
 539  78
             result = (Class) _translatorClasses.get(translatorName);
 540   
         }
 541   
 
 542  398
         if (result == null)
 543  0
             throw new ApplicationRuntimeException(
 544   
                 ImplMessages.unknownTranslatorName(translatorName, TRANSLATORS_CONFIGURATION_ID));
 545   
 
 546  398
         return result;
 547   
     }
 548   
 
 549  78
     private void loadTranslators()
 550   
     {
 551   
         // Prevent endless recursion!
 552   
 
 553  78
         _translatorsLoaded = true;
 554   
 
 555  78
         List contributions = getConfiguration(TRANSLATORS_CONFIGURATION_ID);
 556   
 
 557  78
         Map locations = new HashMap();
 558  78
         locations.put("class", null);
 559   
 
 560  78
         Iterator i = contributions.iterator();
 561  78
         while (i.hasNext())
 562   
         {
 563  936
             TranslatorContribution c = (TranslatorContribution) i.next();
 564   
 
 565  936
             String name = c.getName();
 566  936
             Location oldLocation = (Location) locations.get(name);
 567   
 
 568  936
             if (oldLocation != null)
 569   
             {
 570  0
                 _errorHandler.error(
 571   
                     LOG,
 572   
                     ImplMessages.duplicateTranslatorName(name, oldLocation),
 573   
                     c.getLocation(),
 574   
                     null);
 575   
 
 576  0
                 continue;
 577   
             }
 578   
 
 579  936
             locations.put(name, c.getLocation());
 580  936
             _translatorClasses.put(name, c.getTranslatorClass());
 581   
         }
 582   
 
 583   
     }
 584   
 
 585  2
     public synchronized void cleanupThread()
 586   
     {
 587  2
         if (_threadEventNotifier == null)
 588  2
             _threadEventNotifier =
 589   
                 (ThreadEventNotifier) getService("hivemind.ThreadEventNotifier",
 590   
                     ThreadEventNotifier.class);
 591   
 
 592  2
         _threadEventNotifier.fireThreadCleanup();
 593   
     }
 594   
 
 595  0
     public void setLocale(Locale locale)
 596   
     {
 597  0
         _locale = locale;
 598   
     }
 599   
 
 600  737
     public ErrorHandler getErrorHander()
 601   
     {
 602  737
         return _errorHandler;
 603   
     }
 604   
 
 605   
 }
 606