View Javadoc
1   /*
2    *    Copyright 2009-2023 the original author or authors.
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    *       https://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 org.mybatis.guice.datasource.helper;
17  
18  import com.google.inject.Injector;
19  import com.google.inject.util.Providers;
20  
21  import jakarta.inject.Inject;
22  import jakarta.inject.Provider;
23  
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.StringTokenizer;
27  
28  public final class JdbcUrlAntFormatter implements Provider<String> {
29  
30    private static final String VAR_BEGIN = "$";
31  
32    private static final String PIPE_SEPARATOR = "|";
33  
34    private final List<Provider<String>> appenders = new ArrayList<Provider<String>>();
35  
36    private final List<KeyResolver> resolvers = new ArrayList<KeyResolver>();
37  
38    /**
39     * Constructs a new JdbcUrlAntFormatter based on the provided pattern.
40     *
41     * @param pattern
42     *          the pattern for URL formatting
43     */
44    public JdbcUrlAntFormatter(final String pattern) {
45      initializeAppender(pattern);
46    }
47  
48    /**
49     * Initializes the appenders based on the given pattern.
50     *
51     * @param pattern
52     *          the pattern for URL formatting
53     */
54    private void initializeAppender(String pattern) {
55      int previousIndex = 0;
56      int currentIndex;
57      while ((currentIndex = pattern.indexOf(VAR_BEGIN, previousIndex)) >= 0) {
58        processPatternSubstring(pattern, previousIndex, currentIndex);
59        previousIndex = updatePrevPosition(pattern, currentIndex);
60      }
61      appendRemainingPatternSubstring(pattern, previousIndex);
62    }
63  
64    // Processes the substring of the pattern based on the currentIndex and previousIndex
65    private void processPatternSubstring(String pattern, int previousIndex, int currentIndex) {
66      if (currentIndex > 0) {
67        appenders.add(Providers.of(pattern.substring(previousIndex, currentIndex)));
68      }
69  
70      if (currentIndex == pattern.length() - 1) {
71        appenders.add(Providers.of(VAR_BEGIN));
72      } else if (pattern.charAt(currentIndex + 1) != '{') {
73        handleNonCurlyBracePattern(pattern, currentIndex);
74      } else {
75        handleCurlyBracePattern(pattern, currentIndex);
76      }
77    }
78  
79    // Handles patterns without curly braces
80    private void handleNonCurlyBracePattern(String pattern, int currentIndex) {
81      if (pattern.charAt(currentIndex + 1) == '$') {
82        appenders.add(Providers.of(VAR_BEGIN));
83      } else {
84        appenders.add(Providers.of(pattern.substring(currentIndex, currentIndex + 2)));
85      }
86    }
87  
88    // Handles patterns with curly braces
89    private void handleCurlyBracePattern(String pattern, int currentIndex) {
90      int endName = pattern.indexOf('}', currentIndex);
91      if (endName < 0) {
92        throw new IllegalArgumentException("Syntax error in property: " + pattern);
93      }
94      processKeyResolver(pattern, currentIndex, endName);
95    }
96  
97    // Method to append KeyResolver based on the variable
98    private void processKeyResolver(String pattern, int startPos, int endPos) {
99      StringTokenizer keyTokenizer = new StringTokenizer(pattern.substring(startPos + 2, endPos), PIPE_SEPARATOR);
100     String key = keyTokenizer.nextToken();
101     String defaultValue = keyTokenizer.hasMoreTokens() ? keyTokenizer.nextToken() : null;
102     KeyResolver resolver = new KeyResolver(key, defaultValue);
103     appenders.add(resolver);
104     resolvers.add(resolver);
105   }
106 
107   // Updates the previous position based on the current index and pattern
108   private int updatePrevPosition(String pattern, int currentIndex) {
109     if (pattern.charAt(currentIndex + 1) == '{') {
110       return pattern.indexOf('}', currentIndex) + 1;
111     } else {
112       return currentIndex + (pattern.charAt(currentIndex + 1) == '$' ? 2 : 1);
113     }
114   }
115 
116   // Appends the remaining substring of the pattern
117   private void appendRemainingPatternSubstring(String pattern, int previousIndex) {
118     if (previousIndex < pattern.length()) {
119       appenders.add(Providers.of(pattern.substring(previousIndex)));
120     }
121   }
122 
123   /**
124    * Sets the injector.
125    *
126    * @param injector
127    *          the new injector
128    */
129   @Inject
130   public void setInjector(Injector injector) {
131     for (KeyResolver resolver : resolvers) {
132       resolver.setInjector(injector);
133     }
134   }
135 
136   @Override
137   public String get() {
138     StringBuilder buffer = new StringBuilder();
139     for (Provider<String> appender : appenders) {
140       buffer.append(appender.get());
141     }
142     return buffer.toString();
143   }
144 
145   @Override
146   public String toString() {
147     return appenders.toString();
148   }
149 
150 }