Coverage Report - de.smartics.properties.impl.config.domain.key.envapp.EnvAppDefinitionKeyHelper
 
Classes in this File Line Coverage Branch Coverage Complexity
EnvAppDefinitionKeyHelper
0%
0/55
0%
0/26
3
 
 1  
 /*
 2  
  * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * 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,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package de.smartics.properties.impl.config.domain.key.envapp;
 17  
 
 18  
 import static de.smartics.properties.api.config.domain.key.ApplicationId.ANY_APP;
 19  
 import static de.smartics.properties.api.config.domain.key.EnvironmentId.ANY_ENV;
 20  
 
 21  
 import java.io.Serializable;
 22  
 import java.util.StringTokenizer;
 23  
 
 24  
 import javax.annotation.concurrent.ThreadSafe;
 25  
 
 26  
 import de.smartics.properties.api.config.domain.key.ApplicationId;
 27  
 import de.smartics.properties.api.config.domain.key.ConfigurationKey;
 28  
 import de.smartics.properties.api.config.domain.key.EnvironmentId;
 29  
 import de.smartics.properties.spi.config.definition.DefinitionKeyHelper;
 30  
 import de.smartics.properties.spi.config.domain.key.ConfigurationKeyContextManager;
 31  
 import de.smartics.util.lang.Arg;
 32  
 
 33  
 /**
 34  
  * Derives a {@link ConfigurationKey} from a path found in a definition file.
 35  
  */
 36  
 @ThreadSafe
 37  
 public final class EnvAppDefinitionKeyHelper implements Serializable,
 38  
     DefinitionKeyHelper
 39  
 {
 40  
   // ********************************* Fields *********************************
 41  
 
 42  
   // --- constants ------------------------------------------------------------
 43  
 
 44  
   /**
 45  
    * The class version identifier.
 46  
    */
 47  
   private static final long serialVersionUID = 1L;
 48  
 
 49  
   // --- members --------------------------------------------------------------
 50  
 
 51  
   /**
 52  
    * The context to evaluate the configuration keys from properties file paths.
 53  
    *
 54  
    * @serial
 55  
    */
 56  
   private final EnvAppPropertiesDefinitionContext context;
 57  
 
 58  
   // ****************************** Initializer *******************************
 59  
 
 60  
   // ****************************** Constructors ******************************
 61  
 
 62  
   /**
 63  
    * Convenience constructor using the default TLDs and not registering any
 64  
    * environments, nodes or groups.
 65  
    */
 66  
   public EnvAppDefinitionKeyHelper()
 67  
   {
 68  0
     this(new EnvAppPropertiesDefinitionContext());
 69  0
   }
 70  
 
 71  
   /**
 72  
    * Default constructor.
 73  
    *
 74  
    * @param context the context to evaluate the configuration keys from
 75  
    *          properties file paths.
 76  
    * @throws NullPointerException if {@code context} is <code>null</code>.
 77  
    */
 78  
   public EnvAppDefinitionKeyHelper(
 79  
       final EnvAppPropertiesDefinitionContext context)
 80  
     throws NullPointerException
 81  0
   {
 82  0
     this.context = Arg.checkNotNull("context", context);
 83  0
   }
 84  
 
 85  
   // ****************************** Inner Classes *****************************
 86  
 
 87  
   // ********************************* Methods ********************************
 88  
 
 89  
   // --- init -----------------------------------------------------------------
 90  
 
 91  
   // --- get&set --------------------------------------------------------------
 92  
 
 93  
   // --- business -------------------------------------------------------------
 94  
 
 95  
   /**
 96  
    * Parses the given path to create a configuration key.
 97  
    * <p>
 98  
    * The expected syntax is as follows:
 99  
    * </p>
 100  
    * <ol>
 101  
    * <li><code>/environment</code></li>
 102  
    * <li><code>/environment/node</code></li>
 103  
    * <li><code>/environment/node/group</code></li>
 104  
    * <li><code>/environment/node/group/application</code></li>
 105  
    * <li><code>/environment/node/group/application/version</code></li>
 106  
    * <li><code>/environment/group</code></li>
 107  
    * <li><code>/environment/group/application</code></li>
 108  
    * <li><code>/environment/group/application/version</code></li>
 109  
    * <li><code>/group</code></li>
 110  
    * <li><code>/group/application</code></li>
 111  
    * <li><code>/group/application/version</code></li>
 112  
    * </ol>
 113  
    * <p>
 114  
    * A file ending with properties following the path will be chopped.
 115  
    * </p>
 116  
    * <p>
 117  
    * The parser has to determine whether a part of the path is a
 118  
    * <code>environment</code>, a <code>node</code> or a <code>group</code>.
 119  
    * Since a <code>node</code> is always prefixed by an <code>environment</code>
 120  
    * only the following two cases have to be dealt with:
 121  
    * </p>
 122  
    * <ol>
 123  
    * <li><code>environment</code> vs. <code>group</code></li>
 124  
    * <li><code>node</code> vs. <code>group</code></li>
 125  
    * </ol>
 126  
    * <p>
 127  
    * <code>group</code>s start with
 128  
    * </p>
 129  
    * <ol>
 130  
    * <li>A TLD as registered by default by
 131  
    * {@link AbstractPropertiesDefinitionContext#DEFAULT_TLDS} or explicitly
 132  
    * registered with {@link AbstractPropertiesDefinitionContext}</li>
 133  
    * <li>Two letters followed by a dot (<code>.</code>)</li>
 134  
    * <li>Any sequence of characters that is explicitly registered as a group in
 135  
    * the <code>definition.xml</code> file</li>
 136  
    * </ol>
 137  
    * <p>
 138  
    * <code>environment</code>s and <code>node</code>s do not start as
 139  
    * <code>groups</code> except they are explicitly registered in the
 140  
    * <code>definition.xml</code> file.
 141  
    * </p>
 142  
    *
 143  
    * @param pathWithFile the path to parse.
 144  
    * @return the configuration key.
 145  
    * @throws IllegalArgumentException if the given {@code path} is not valid
 146  
    *           according to the rules given above.
 147  
    */
 148  
   @Override
 149  
   public ConfigurationKey<?> parse(final String pathWithFile)
 150  
     throws IllegalArgumentException
 151  
   {
 152  0
     final ConfigurationKey<?> explicitKey = fetchExplicitKey(pathWithFile);
 153  0
     if (explicitKey != null)
 154  
     {
 155  0
       return explicitKey;
 156  
     }
 157  
 
 158  0
     final String path = chopFile(pathWithFile);
 159  
 
 160  0
     final StringTokenizer tokenizer = new StringTokenizer(path, "/");
 161  0
     if (tokenizer.hasMoreTokens())
 162  
     {
 163  
       final ConfigurationKey<?> key;
 164  
 
 165  0
       final String token = tokenizer.nextToken();
 166  0
       if (isGroup(token))
 167  
       {
 168  0
         key = parseApplicationKey(token, tokenizer);
 169  
       }
 170  
       else
 171  
       {
 172  0
         key = parseEnvironmentKey(token, tokenizer);
 173  
       }
 174  
 
 175  0
       return key;
 176  
     }
 177  
 
 178  0
     return ConfigurationKeyContextManager.INSTANCE.context()
 179  
         .configurationKeyFactory().createDefaultKey();
 180  
     // throw new IllegalArgumentException(
 181  
     // "Path '" + path + "' does not contain an environment or group.");
 182  
   }
 183  
 
 184  
   private static String chopFile(final String pathWithFile)
 185  
   {
 186  0
     if (pathWithFile.endsWith(".properties"))
 187  
     {
 188  0
       final int lastSlash = pathWithFile.lastIndexOf('/');
 189  0
       if (lastSlash != -1)
 190  
       {
 191  0
         final String path = pathWithFile.substring(0, lastSlash);
 192  0
         return path;
 193  
       }
 194  
 
 195  0
       return "";
 196  
     }
 197  0
     return pathWithFile;
 198  
   }
 199  
 
 200  
   private ConfigurationKey<?> fetchExplicitKey(final String path)
 201  
   {
 202  0
     ConfigurationKey<?> key = context.getKey(path);
 203  0
     if (key == null)
 204  
     {
 205  0
       key = context.getKey(null);
 206  
     }
 207  0
     return key;
 208  
   }
 209  
 
 210  
   private boolean isGroup(final String token)
 211  
   {
 212  0
     if (context.isRegisteredEnvironment(token)
 213  
         || context.isRegisteredNode(token))
 214  
     {
 215  0
       return false;
 216  
     }
 217  
 
 218  0
     return context.isGroup(token);
 219  
   }
 220  
 
 221  
   private ConfigurationKey<?> parseEnvironmentKey(final String environment,
 222  
       final StringTokenizer tokenizer)
 223  
   {
 224  
     final EnvironmentId envId;
 225  
     final ApplicationId appId;
 226  0
     if (tokenizer.hasMoreTokens())
 227  
     {
 228  0
       final String token = tokenizer.nextToken();
 229  0
       if (isGroup(token))
 230  
       {
 231  0
         envId = new EnvironmentId(environment);
 232  0
         appId = parseAppId(token, tokenizer);
 233  
       }
 234  
       else
 235  
       {
 236  0
         envId = new EnvironmentId(environment, token);
 237  0
         if (tokenizer.hasMoreTokens())
 238  
         {
 239  0
           appId = parseAppId(tokenizer.nextToken(), tokenizer);
 240  
         }
 241  
         else
 242  
         {
 243  0
           appId = ANY_APP;
 244  
         }
 245  
       }
 246  0
     }
 247  
     else
 248  
     {
 249  0
       envId = new EnvironmentId(environment);
 250  0
       appId = ANY_APP;
 251  
     }
 252  
 
 253  0
     final ConfigurationKey<?> key = new EnvAppConfigurationKey(envId, appId);
 254  
 
 255  0
     return key;
 256  
   }
 257  
 
 258  
   private ApplicationId parseAppId(final String group,
 259  
       final StringTokenizer tokenizer)
 260  
   {
 261  0
     String artifact = null;
 262  0
     String version = null;
 263  0
     if (tokenizer.hasMoreTokens())
 264  
     {
 265  0
       artifact = tokenizer.nextToken();
 266  0
       if (tokenizer.hasMoreTokens())
 267  
       {
 268  0
         version = tokenizer.nextToken();
 269  
       }
 270  
     }
 271  
 
 272  0
     return new ApplicationId(group, artifact, version);
 273  
   }
 274  
 
 275  
   private ConfigurationKey<?> parseApplicationKey(final String group,
 276  
       final StringTokenizer tokenizer)
 277  
   {
 278  0
     final EnvironmentId envId = ANY_ENV;
 279  0
     final ApplicationId appId = parseAppId(group, tokenizer);
 280  
 
 281  0
     return new EnvAppConfigurationKey(envId, appId);
 282  
   }
 283  
 
 284  
   // --- object basics --------------------------------------------------------
 285  
 
 286  
 }