Coverage Report - com.javaforge.bobber.plugin.archetype.BobberArchetype
 
Classes in this File Line Coverage Branch Coverage Complexity
BobberArchetype
0%
0/211
0%
0/84
11
 
 1  
 /*
 2  
  * Copyright 2001-2005 The Apache Software Foundation.
 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  
 
 17  
 package com.javaforge.bobber.plugin.archetype;
 18  
 
 19  
 import com.javaforge.bobber.archetype.model.Template;
 20  
 import com.javaforge.bobber.archetype.model.Variable;
 21  
 import com.javaforge.bobber.archetype.model.io.xpp3.BobberArchetypeXpp3Reader;
 22  
 
 23  
 import java.io.File;
 24  
 import java.io.FileOutputStream;
 25  
 import java.io.FileWriter;
 26  
 import java.io.IOException;
 27  
 import java.io.InputStream;
 28  
 import java.io.InputStreamReader;
 29  
 import java.io.StringWriter;
 30  
 import java.io.Writer;
 31  
 import java.net.MalformedURLException;
 32  
 import java.net.URL;
 33  
 import java.net.URLClassLoader;
 34  
 import java.util.ArrayList;
 35  
 import java.util.Enumeration;
 36  
 import java.util.Iterator;
 37  
 import java.util.List;
 38  
 import java.util.Map;
 39  
 import java.util.StringTokenizer;
 40  
 import java.util.jar.JarEntry;
 41  
 import java.util.jar.JarFile;
 42  
 import java.util.zip.ZipEntry;
 43  
 
 44  
 import org.apache.maven.archetype.Archetype;
 45  
 import org.apache.maven.archetype.ArchetypeDescriptorException;
 46  
 import org.apache.maven.archetype.ArchetypeNotFoundException;
 47  
 import org.apache.maven.archetype.ArchetypeTemplateProcessingException;
 48  
 import org.apache.maven.artifact.Artifact;
 49  
 import org.apache.maven.artifact.factory.ArtifactFactory;
 50  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 51  
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
 52  
 import org.apache.maven.artifact.resolver.ArtifactResolver;
 53  
 import org.apache.maven.settings.MavenSettingsBuilder;
 54  
 import org.apache.velocity.VelocityContext;
 55  
 import org.codehaus.plexus.components.interactivity.InputHandler;
 56  
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 57  
 import org.codehaus.plexus.util.FileUtils;
 58  
 import org.codehaus.plexus.util.IOUtil;
 59  
 import org.codehaus.plexus.util.StringUtils;
 60  
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 61  
 import org.codehaus.plexus.velocity.VelocityComponent;
 62  
 
 63  
 //source blatantly copied from org.apache.maven.archetype.DefaultArchetype. Also stole code from DefaultPluginVersionManager.java
 64  
 
 65  
 //and maven-model for the mdo
 66  0
 public class BobberArchetype
 67  
         extends AbstractLogEnabled
 68  
         implements Archetype
 69  
 {
 70  
 
 71  0
     private static final String NEW_LINE = System.getProperty("line.separator");
 72  
 
 73  
     // ----------------------------------------------------------------------
 74  
     // Components
 75  
     // ----------------------------------------------------------------------
 76  
 
 77  
     /** @component */
 78  
     private VelocityComponent velocity;
 79  
 
 80  
     /** @component */
 81  
     private ArtifactResolver artifactResolver;
 82  
 
 83  
     /** @component */
 84  
     private InputHandler inputHandler;
 85  
 
 86  
     /** @component */
 87  
     private ArtifactFactory artifactFactory;
 88  
 
 89  
 
 90  
     /** @component */
 91  
     private MavenSettingsBuilder settingsBuilder;
 92  
     private static final int MESSAGE_LINE_LENGTH = 80;
 93  
 
 94  
 
 95  
     public void createArchetype(String archetypeGroupId, String archetypeArtifactId, String archetypeVersion,
 96  
                                 ArtifactRepository localRepository, List remoteRepositories, Map parameters)
 97  
             throws ArchetypeNotFoundException, ArchetypeDescriptorException, ArchetypeTemplateProcessingException
 98  
     {
 99  
 
 100  
         // ---------------------------------------------------------------------
 101  
         //locate the archetype file
 102  
         // ---------------------------------------------------------------------
 103  0
         Artifact archetypeArtifact = artifactFactory.createArtifact(archetypeGroupId, archetypeArtifactId,
 104  
                 archetypeVersion, Artifact.SCOPE_RUNTIME, "jar");
 105  
 
 106  
         try
 107  
         {
 108  0
             artifactResolver.resolve(archetypeArtifact, remoteRepositories, localRepository);
 109  
         }
 110  0
         catch (ArtifactResolutionException e)
 111  
         {
 112  0
             throw new ArchetypeDescriptorException("Error attempting to download archetype: " + e.getMessage(), e);
 113  0
         }
 114  
 
 115  
         // ----------------------------------------------------------------------
 116  
         // Load the archetype descriptor
 117  
         // ----------------------------------------------------------------------
 118  
 
 119  0
         BobberArchetypeXpp3Reader builder = new BobberArchetypeXpp3Reader();
 120  
 
 121  
         com.javaforge.bobber.archetype.model.BobberArchetype archetype;
 122  
 
 123  
         JarFile archetypeJarFile;
 124  
 
 125  
         try
 126  
         {
 127  
 
 128  0
             archetypeJarFile = new JarFile(archetypeArtifact.getFile());
 129  
 
 130  0
             final ZipEntry zipEntry = archetypeJarFile.getEntry(ARCHETYPE_DESCRIPTOR);
 131  0
             InputStream is = archetypeJarFile.getInputStream(zipEntry);
 132  
 
 133  0
             if (is == null)
 134  
             {
 135  0
                 throw new ArchetypeDescriptorException(
 136  
                         "The " + ARCHETYPE_DESCRIPTOR + " descriptor cannot be found.");
 137  
             }
 138  
 
 139  0
             archetype = builder.read(new InputStreamReader(is));
 140  
 
 141  0
             archetypeJarFile.close();
 142  
         }
 143  0
         catch (IOException e)
 144  
         {
 145  0
             throw new ArchetypeDescriptorException("Error reading the " + ARCHETYPE_DESCRIPTOR + " descriptor.", e);
 146  
         }
 147  0
         catch (XmlPullParserException e)
 148  
         {
 149  0
             throw new ArchetypeDescriptorException("Error reading the " + ARCHETYPE_DESCRIPTOR + " descriptor.", e);
 150  0
         }
 151  
 
 152  
         // ----------------------------------------------------------------------
 153  
         //
 154  
         // ----------------------------------------------------------------------
 155  
 
 156  0
         String basedir = (String) parameters.get("basedir");
 157  
 
 158  0
         String artifactId = (String) parameters.get("artifactId");
 159  
 
 160  0
         File pomFile = new File(basedir, ARCHETYPE_POM);
 161  
 
 162  
         File outputDirectoryFile;
 163  
 
 164  0
         if (pomFile.exists() && archetype.isAllowPartial())
 165  
         {
 166  0
             outputDirectoryFile = new File(basedir);
 167  
         }
 168  
         else
 169  
         {
 170  0
             outputDirectoryFile = new File(basedir, artifactId);
 171  
 
 172  
             // TODO temporarily allow partial generation, remove it later
 173  0
             if (!archetype.isAllowPartial() &&
 174  
                     outputDirectoryFile.exists() &&
 175  
                     outputDirectoryFile.listFiles().length > 0)
 176  
             {
 177  0
                 throw new ArchetypeTemplateProcessingException(
 178  
                         outputDirectoryFile.getName() + " already exists - please run from a clean directory");
 179  
             }
 180  
 
 181  0
             outputDirectoryFile.mkdir();
 182  
 
 183  
         }
 184  
 
 185  0
         String outputDirectory = outputDirectoryFile.getAbsolutePath();
 186  
 
 187  
         // ----------------------------------------------------------------------
 188  
         // Set up the Velocity context
 189  
         // ----------------------------------------------------------------------
 190  
 
 191  0
         VelocityContext context = new VelocityContext();
 192  
 
 193  0
         String packageName = (String) parameters.get("package");
 194  
 
 195  0
         addParamToContext("package", packageName, context);
 196  0
         addParamToContext("packagePath", StringUtils.replace(packageName, ".", "/"), context);
 197  
 
 198  0
         for (Iterator iterator = parameters.keySet().iterator(); iterator.hasNext();)
 199  
         {
 200  0
             String key = (String) iterator.next();
 201  
 
 202  0
             Object value = parameters.get(key);
 203  0
             addParamToContext(key, value, context);
 204  0
         }
 205  
 
 206  
         //add in the specified system properties
 207  
         //if this were a mojo could have set the settings using the ${settings} expression. Since it is not need to get it from the settings builder
 208  
 
 209  
 
 210  0
         boolean inInteractiveMode = false;
 211  
         try
 212  
         {
 213  0
             inInteractiveMode = settingsBuilder.buildSettings().getInteractiveMode().booleanValue();
 214  
             //TODO there must be a cleaner way of doing this
 215  0
             String temp = System.getProperty("interactive", null);
 216  0
             if (temp != null)
 217  
             {
 218  0
                 inInteractiveMode = Boolean.valueOf(temp).booleanValue();
 219  
             }
 220  0
             getLogger().info("Interactive is: " + inInteractiveMode);
 221  
         }
 222  0
         catch (Exception ie)
 223  
         {
 224  0
             throw new ArchetypeTemplateProcessingException("unable to read settings ", ie);
 225  0
         }
 226  0
         if (inInteractiveMode)
 227  
         {
 228  0
             getLogger().info("Please enter the values for the following archetype variables:");
 229  
         }
 230  
 
 231  
 
 232  0
         final List variables = archetype.getVariables();
 233  0
         processVariables(variables.iterator(), context, inInteractiveMode);
 234  
 
 235  
         // ---------------------------------------------------------------------
 236  
         // Get Logger and display all parameters used
 237  
         // ---------------------------------------------------------------------
 238  0
         if (getLogger().isInfoEnabled())
 239  
         {
 240  0
             Object[] keys = context.getKeys();
 241  0
             if (keys.length > 0)
 242  
             {
 243  0
                 getLogger().info("----------------------------------------------------------------------------");
 244  
 
 245  0
                 getLogger().info("Using following parameters for creating Archetype: " + archetypeArtifactId + ":" +
 246  
                         archetypeVersion);
 247  
 
 248  0
                 getLogger().info("----------------------------------------------------------------------------");
 249  
 
 250  0
                 for (int i = 0; i < keys.length; i++)
 251  
                 {
 252  
 
 253  0
                     String parameterName = (String) keys[i];
 254  
 
 255  0
                     Object parameterValue = context.get(parameterName);
 256  
 
 257  0
                     getLogger().info("Parameter: " + parameterName + " = " + parameterValue);
 258  
                 }
 259  
             }
 260  
             else
 261  
             {
 262  0
                 getLogger().info("No Parameters found for creating Archetype");
 263  
             }
 264  
         }
 265  
 
 266  
         // ----------------------------------------------------------------------
 267  
         // Extract the archetype to the chosen directory
 268  
         // ----------------------------------------------------------------------
 269  
 
 270  
         try
 271  
         {
 272  0
             archetypeJarFile = new JarFile(archetypeArtifact.getFile());
 273  0
             Enumeration entries = archetypeJarFile.entries();
 274  
 
 275  0
             while (entries.hasMoreElements())
 276  
             {
 277  0
                 JarEntry entry = (JarEntry) entries.nextElement();
 278  0
                 String path = entry.getName();
 279  0
                 if (!path.startsWith(ARCHETYPE_RESOURCES) || path.endsWith(".vm"))
 280  
                 {
 281  0
                     continue;
 282  
                 }
 283  
 
 284  0
                 File t = new File(outputDirectory, path.substring(19));
 285  0
                 if (entry.isDirectory())
 286  
                 {
 287  
                     // Assume directories are stored parents first then children.
 288  0
                     getLogger().debug("Extracting directory: " + entry.getName() + " to " + t.getAbsolutePath());
 289  0
                     t.mkdir();
 290  0
                     continue;
 291  
                 }
 292  
 
 293  0
                 getLogger().debug("Extracting file: " + entry.getName() + " to " + t.getAbsolutePath());
 294  0
                 t.createNewFile();
 295  0
                 IOUtil.copy(archetypeJarFile.getInputStream(entry), new FileOutputStream(t));
 296  0
             }
 297  
 
 298  0
             archetypeJarFile.close();
 299  
 
 300  
             //remove the archetype descriptor
 301  0
             File t = new File(outputDirectory, ARCHETYPE_DESCRIPTOR);
 302  0
             t.delete();
 303  
         }
 304  0
         catch (IOException ioe)
 305  
         {
 306  0
             throw new ArchetypeTemplateProcessingException("Error extracting archetype", ioe);
 307  0
         }
 308  
 
 309  
         // ----------------------------------------------------------------------
 310  
         // Process the templates
 311  
         // ----------------------------------------------------------------------
 312  
 
 313  
         // use the out of the box codehaus velocity component that loads templates
 314  
         //from the class path
 315  0
         ClassLoader old = Thread.currentThread().getContextClassLoader();
 316  
         try
 317  
         {
 318  0
             URL[] urls = new URL[1];
 319  0
             urls[0] = archetypeArtifact.getFile().toURI().toURL();
 320  0
             URLClassLoader archetypeJarLoader = new URLClassLoader(urls);
 321  
 
 322  0
             Thread.currentThread().setContextClassLoader(archetypeJarLoader);
 323  0
             for (Iterator i = archetype.getTemplates().iterator(); i.hasNext();)
 324  
             {
 325  0
                 final Template template = (Template) i.next();
 326  
 
 327  
                 // Check the optional 'condition' property on the template.
 328  
                 // If present and the variable it points to is 'true', then
 329  
                 // continue processing. If it's false, then skip.
 330  
                 // If condition is not specified, assume the template should
 331  
                 // be processed.
 332  0
                 boolean shouldProcess = true;
 333  0
                 String condition = template.getDependsOnVar();
 334  0
                 String requiredValue = null;
 335  0
                 List options = new ArrayList();
 336  0
                 if (StringUtils.isNotEmpty(condition))
 337  
                 {
 338  
                     //Crappy logic processing -- for now
 339  0
                     boolean not = false;
 340  
                     //Allow very simple matching logic to match templates against variable values
 341  0
                     int x = condition.indexOf("!=");
 342  0
                     getLogger().debug("Processing Condition : " + condition);
 343  0
                     if (x > -1)
 344  
                     {
 345  0
                         not = true;
 346  0
                         requiredValue = condition.substring(x + 2).trim();
 347  0
                         options = getListOfValues(requiredValue);
 348  0
                         condition = condition.substring(0, x).trim();
 349  
                     }
 350  
                     else
 351  
                     {
 352  0
                         x = condition.indexOf("=");
 353  0
                         if (x > -1)
 354  
                         {
 355  0
                             requiredValue = condition.substring(x + 1);
 356  0
                             options = getListOfValues(requiredValue);
 357  0
                             condition = condition.substring(0, x);
 358  
                         }
 359  
                     }
 360  0
                     getLogger().debug("Not Expr: " + not);
 361  0
                     getLogger().debug("Condition Value: '" + condition + "'");
 362  0
                     getLogger().debug("Required Value: '" + requiredValue + "'");
 363  0
                     final Variable var = (Variable) findVariable(condition, variables);
 364  0
                     if (var != null)
 365  
                     {
 366  0
                         final String strValue = (String) context.get(var.getName());
 367  0
                         getLogger().debug("Variable Value is: '" + strValue + "'");
 368  0
                         if (requiredValue == null)
 369  
                         {
 370  0
                             if (!Boolean.valueOf(strValue).booleanValue())
 371  
                             {
 372  0
                                 shouldProcess = false;
 373  
                             }
 374  
                         }
 375  
                         else
 376  
                         {
 377  0
                             if (!options.contains(strValue))
 378  
                             {
 379  0
                                 shouldProcess = false;
 380  
                             }
 381  
                         }
 382  
 
 383  0
                     }
 384  
                     else
 385  
                     {
 386  0
                         getLogger().debug("Variable Value is: null");
 387  0
                         shouldProcess = false;
 388  
                     }
 389  0
                     if (not)
 390  
                     {
 391  0
                         shouldProcess = !shouldProcess;
 392  
                     }
 393  
                 }
 394  
 
 395  0
                 if (shouldProcess)
 396  
                 {
 397  0
                     processTemplate(template, outputDirectory, context);
 398  
                 }
 399  
                 else
 400  
                 {
 401  0
                     getLogger().debug("Condition not met, skipping " + template.getOutput());
 402  
                 }
 403  0
             }
 404  
 
 405  
         }
 406  0
         catch (MalformedURLException mfe)
 407  
         {
 408  0
             throw new ArchetypeTemplateProcessingException("Error loading archetype resources into the classpath", mfe);
 409  
         }
 410  
         finally
 411  
         {
 412  0
             Thread.currentThread().setContextClassLoader(old);
 413  0
         }
 414  
 
 415  
         // ----------------------------------------------------------------------
 416  
         // Log message on Archetype creation
 417  
         // ----------------------------------------------------------------------
 418  0
         if (getLogger().isInfoEnabled())
 419  
         {
 420  0
             getLogger().info("Archetype created in dir: " + outputDirectory);
 421  
         }
 422  
 
 423  0
     }
 424  
 
 425  
     protected void addParamToContext(String key, Object value, VelocityContext context)
 426  
     {
 427  0
         getLogger().info("Adding Parameter to template Context: " + key + "=" + value);
 428  0
         context.put(key, value);
 429  
 
 430  0
     }
 431  
 
 432  
     protected void processVariables(Iterator variables, VelocityContext context, final boolean interactiveMode) throws ArchetypeTemplateProcessingException
 433  
     {
 434  0
         while (variables.hasNext())
 435  
         {
 436  0
             Variable var = (Variable) variables.next();
 437  0
             String val = System.getProperty(var.getName(), var.getDefvalue());
 438  
 
 439  0
             if (interactiveMode)
 440  
             {
 441  
 
 442  0
                 StringBuffer message = new StringBuffer();
 443  0
                 message.append(var.getName()).append(": ")
 444  
                         .append(NEW_LINE)
 445  
                         .append(StringUtils.repeat("*", MESSAGE_LINE_LENGTH))
 446  
                         .append(NEW_LINE)
 447  
                         .append(NEW_LINE)
 448  
                         .append(StringUtils.center(var.getDescription(), MESSAGE_LINE_LENGTH))
 449  
                         .append(NEW_LINE)
 450  
                         .append(StringUtils.leftPad("[default: " + val + "]", MESSAGE_LINE_LENGTH))
 451  
                         .append(NEW_LINE)
 452  
                         .append(StringUtils.repeat("*", MESSAGE_LINE_LENGTH));
 453  0
                 getLogger().info(message.toString());
 454  
                 try
 455  
                 {
 456  0
                     String answer = inputHandler.readLine();
 457  0
                     if (!StringUtils.isEmpty(answer))
 458  
                     {
 459  0
                         val = answer;
 460  
                     }
 461  
                 }
 462  0
                 catch (IOException ie)
 463  
                 {
 464  0
                     throw new ArchetypeTemplateProcessingException(ie);
 465  0
                 }
 466  0
                 context.put(var.getName(), val);
 467  0
             }
 468  
             else
 469  
             {
 470  0
                 context.put(var.getName(), val);
 471  
             }
 472  
 
 473  0
             if (val.toLowerCase().equals("false") || val.toLowerCase().equals("n"))
 474  
             {
 475  0
                 if (var.getVariables() != null)
 476  
                 {
 477  
                     //keep processing the variables picking up the default values
 478  0
                     processVariables(var.getVariables().iterator(), context, interactiveMode);
 479  
 
 480  
                 }
 481  
             }
 482  0
             else if (var.getVariables() != null)
 483  
             {
 484  
                 //keep processing the variables picking up the default values
 485  0
                 processVariables(var.getVariables().iterator(), context, interactiveMode);
 486  
 
 487  
             }
 488  0
         }
 489  
 
 490  0
     }
 491  
 
 492  
     protected List getListOfValues(String s)
 493  
     {
 494  0
         List options = new ArrayList();
 495  0
         for (StringTokenizer stringTokenizer = new StringTokenizer(s, "|"); stringTokenizer.hasMoreTokens();)
 496  
         {
 497  0
             options.add(stringTokenizer.nextToken());
 498  
         }
 499  0
         return options;
 500  
     }
 501  
 
 502  
     protected void processTemplate(Template template, String outputDirectory, VelocityContext context)
 503  
             throws ArchetypeTemplateProcessingException
 504  
     {
 505  
         File outFile;
 506  
 
 507  
 
 508  
         try
 509  
         {
 510  0
             StringWriter wout = new StringWriter();
 511  
 
 512  0
             velocity.getEngine().evaluate(context, wout, "output value", template.getOutput());
 513  0
             outFile = new File(outputDirectory, wout.toString());
 514  0
             getLogger().debug(outFile.getAbsolutePath());
 515  0
             FileUtils.forceMkdir(outFile.getParentFile());
 516  0
             getLogger().debug("Created directory: " + outFile.getParentFile() + ", Dir exists = " + outFile.getParentFile().exists());
 517  
 
 518  
         }
 519  0
         catch (Exception e)
 520  
         {
 521  0
             e.printStackTrace();
 522  0
             throw new ArchetypeTemplateProcessingException("error evaluating output file name " + template.getOutput(), e);
 523  0
         }
 524  
 
 525  
 
 526  0
         Writer writer = null;
 527  
         try
 528  
         {
 529  0
             getLogger().info("Processing Template: " + template.getFile());
 530  0
             String templateLocation = ARCHETYPE_RESOURCES + "/" + template.getFile();
 531  
 
 532  0
             writer = new FileWriter(outFile);
 533  0
             velocity.getEngine().mergeTemplate(templateLocation, context, writer);
 534  0
             writer.flush();
 535  
 
 536  
         }
 537  0
         catch (Exception e)
 538  
         {
 539  0
             throw new ArchetypeTemplateProcessingException("Error merging velocity templates", e);
 540  
         }
 541  
         finally
 542  
         {
 543  0
             IOUtil.close(writer);
 544  0
             getLogger().info("Written Template to: " + outFile + ", file exists = " + outFile.exists());
 545  0
         }
 546  
 
 547  
         // Delete archetype-originated folders in case the output path is also templated.
 548  
         // Otherwise, there will be a processed folder AND the original folder.
 549  
         try
 550  
         {
 551  0
             final File templateFile = new File(outputDirectory, template.getFile());
 552  0
             final String templateDir = FileUtils.dirname(templateFile.getCanonicalPath());
 553  0
             final String outputDir = FileUtils.dirname(outFile.getCanonicalPath());
 554  0
             if (getLogger().isDebugEnabled())
 555  
             {
 556  0
                 getLogger().debug("TemplateDir=" + templateDir);
 557  0
                 getLogger().debug("OutputDir=" + outputDir);
 558  
             }
 559  0
             if (!outputDir.startsWith(templateDir))
 560  
             {
 561  0
                 getLogger().debug("Deleting Template Dir:" + templateDir);
 562  0
                 FileUtils.forceDelete(templateDir);
 563  
             }
 564  
         }
 565  0
         catch (IOException e)
 566  
         {
 567  0
             throw new ArchetypeTemplateProcessingException("Failed to cleanup the working dir.", e);
 568  0
         }
 569  0
     }
 570  
 
 571  
 
 572  
     /**
 573  
      * Find the  variable.
 574  
      *
 575  
      * @param variableName name
 576  
      * @param variables    all variables of the artifact
 577  
      * @return variable value or null of not found
 578  
      */
 579  
     protected Object findVariable(String variableName, List variables)
 580  
     {
 581  
 
 582  0
         for (int i = 0; i < variables.size(); i++)
 583  
         {
 584  0
             Variable var = (Variable) variables.get(i);
 585  0
             if (variableName.equals(var.getName()))
 586  
             {
 587  0
                 return var;
 588  
             }
 589  0
             else if (var.getVariables() != null)
 590  
             {
 591  0
                 Object o = findVariable(variableName, var.getVariables());
 592  0
                 if (o != null)
 593  
                 {
 594  0
                     return o;
 595  
                 }
 596  
             }
 597  
         }
 598  
 
 599  0
         return null;
 600  
     }
 601  
 
 602  
 }
 603  
 
 604  
 
 605