View Javadoc
1   package org.codehaus.plexus.interpolation;
2   
3   /*
4    * Copyright 2001-2008 Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import org.codehaus.plexus.interpolation.util.ValueSourceUtils;
20  
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.List;
24  import java.util.Stack;
25  
26  /**
27   * {@link RecursionInterceptor} implementation that provides support for expressions
28   * with multiple synonyms, such as project.build.directory == pom.build.directory ==
29   * build.directory in Maven's POM.
30   *
31   * @author jdcasey
32   * @version $Id$
33   */
34  public class PrefixAwareRecursionInterceptor
35      implements RecursionInterceptor
36  {
37  
38      public static final String DEFAULT_START_TOKEN = "\\$\\{";
39  
40      public static final String DEFAULT_END_TOKEN = "\\}";
41  
42      private Stack<String> nakedExpressions = new Stack<String>();
43  
44      private final String[] possiblePrefixes;
45  
46      private boolean watchUnprefixedExpressions = true;
47  
48      /**
49       * Use the specified expression prefixes to detect synonyms, and specify whether
50       * unprefixed expressions can be considered synonyms.
51       *
52       * @param possiblePrefixes           The collection of expression prefixes supported
53       * @param watchUnprefixedExpressions Whether to consider unprefixed expressions as synonyms
54       */
55      public PrefixAwareRecursionInterceptor( Collection<String> possiblePrefixes, boolean watchUnprefixedExpressions )
56      {
57          this.possiblePrefixes = possiblePrefixes.toArray( new String[possiblePrefixes.size()]) ;
58          this.watchUnprefixedExpressions = watchUnprefixedExpressions;
59      }
60  
61      /**
62       * Use the specified expression prefixes to detect synonyms. Consider
63       * unprefixed expressions synonyms as well.
64       *
65       * @param possiblePrefixes The collection of expression prefixes supported
66       */
67      public PrefixAwareRecursionInterceptor( Collection<String> possiblePrefixes )
68      {
69          this.possiblePrefixes = possiblePrefixes.toArray( new String[possiblePrefixes.size()]) ;
70      }
71  
72      public boolean hasRecursiveExpression( String expression )
73      {
74          String realExpr = ValueSourceUtils.trimPrefix( expression, possiblePrefixes, watchUnprefixedExpressions );
75          return realExpr != null && nakedExpressions.contains( realExpr );
76  
77      }
78  
79      public void expressionResolutionFinished( String expression )
80      {
81          nakedExpressions.pop();
82      }
83  
84      public void expressionResolutionStarted( String expression )
85      {
86          String realExpr = ValueSourceUtils.trimPrefix( expression, possiblePrefixes, watchUnprefixedExpressions );
87          nakedExpressions.push( realExpr );
88      }
89  
90      /**
91       * When an expression is determined to be a recursive reference, this method
92       * returns the sublist of tracked expressions that participate in this cycle.
93       * Otherwise, if the expression isn't present in the in-process stack, return
94       * {@link Collections#EMPTY_LIST}. Also, if the expression doesn't have a matched
95       * prefix from this interceptor's list, and unprefixed expressions aren't allowed
96       * then return {@link Collections#EMPTY_LIST}.
97       */
98      public List getExpressionCycle( String expression )
99      {
100         String expr = ValueSourceUtils.trimPrefix( expression, possiblePrefixes, watchUnprefixedExpressions );
101 
102         if ( expr == null )
103         {
104             return Collections.EMPTY_LIST;
105         }
106 
107         int idx = nakedExpressions.indexOf( expr );
108         if ( idx < 0 )
109         {
110             return Collections.EMPTY_LIST;
111         }
112         else
113         {
114             return nakedExpressions.subList( idx, nakedExpressions.size() );
115         }
116     }
117 
118     public void clear()
119     {
120         nakedExpressions.clear();
121     }
122 }