KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > core > urltemplates > URLTemplate


1 /*
2  * Copyright 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  * $Header:$
17  */

18 package org.apache.beehive.netui.core.urltemplates;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Map JavaDoc;
26
27
28 /**
29  * The class to format a URL defined by url-template-config template
30  * given by values for a set of tokens.
31  */

32 public class URLTemplate
33 {
34     private static final char BEGIN_TOKEN_QUALIFIER = '{';
35     private static final char END_TOKEN_QUALIFIER = '}';
36
37     // The String form of the template.
38
private String JavaDoc _template;
39
40     // Parsed representation of the template... list of literals and tokens.
41
private ArrayList JavaDoc/*< TemplateItem >*/ _parsedTemplate = null;
42
43     private boolean _isParsed = false;
44
45     // The set of known tokens in a valid template.
46
private Collection JavaDoc/*< String >*/ _knownTokens = null;
47
48     // The set of required tokens in a valid template.
49
private Collection JavaDoc/*< String >*/ _requiredTokens = null;
50
51     private HashMap JavaDoc/*< String, String >*/ _tokenValuesMap = new HashMap JavaDoc/*< String, String >*/();
52
53     /**
54      * Create a URLTemplate from a url-template-config template.
55      *
56      * <p> Allow clients to define a set of required and known tokens for the
57      * template verification. Tokens are expected to be qualified
58      * in braces. E.g. {url:path} </p>
59      *
60      * <p> The template verification will ensure the URL template conforms to
61      * a valid format for known tokens and contains the required tokens. </p>
62      *
63      * <p> Should call verify after creating a new template. </p>
64      *
65      * @param template the string form of the template from url-template-config.
66      * @param knownTokens The set of known tokens for a valid template.
67      * @param requiredTokens The set of required tokens in a valid template.
68      */

69     public URLTemplate( String JavaDoc template, Collection JavaDoc/*< String >*/ knownTokens, Collection JavaDoc/*< String >*/ requiredTokens )
70     {
71         setTemplate( template );
72         _knownTokens = knownTokens;
73         _requiredTokens = requiredTokens;
74     }
75
76     /**
77      * Copy constructor to create a URLTemplate from an existing URLTemplate.
78      *
79      * <p> Note that this is not truly a complete copy because the Map
80      * of the replacement values for the given tokens is not copied.
81      * This copy will just have an empty map of token values so that
82      * it is "cleared" and ready to format another URL. </p>
83      *
84      * @param template the URLTemplate to copy.
85      */

86     public URLTemplate( URLTemplate template )
87     {
88         setTemplate( template.getTemplate() );
89         _knownTokens = template._knownTokens;
90         _requiredTokens = template._requiredTokens;
91         _parsedTemplate = template._parsedTemplate;
92         _isParsed = template._isParsed;
93     }
94
95     /**
96      * Reset the String form of the template.
97      *
98      * <p> Should call verify after setting a new template. </p>
99      *
100      * @param template the string form of the template from url-template-config.
101      */

102     public void setTemplate( String JavaDoc template )
103     {
104         if ( template == null || template.length() == 0 )
105         {
106             throw new IllegalStateException JavaDoc( "Template cannot be null or empty." );
107         }
108
109         if ( template.equals( _template ) ) return;
110
111         _template = template;
112         _isParsed = false;
113         _parsedTemplate = null;
114     }
115
116     /**
117      * Retrieve the String form of the template.
118      *
119      * @return the string form of the template.
120      */

121     public String JavaDoc getTemplate()
122     {
123         return _template;
124     }
125
126     /**
127      * Verification will ensure the URL template conforms to a valid format
128      * for known tokens and contains the required tokens. It will also parse
129      * the tokens and literal data into a list to improve the replacement
130      * performance when constructing the final URL string.
131      */

132     public void verify() throws IllegalStateException JavaDoc
133     {
134         // For each known token, make sure there is a leading and trailing brace
135
if ( _knownTokens != null )
136         {
137             for ( java.util.Iterator JavaDoc ii = _knownTokens.iterator(); ii.hasNext(); )
138             {
139                 String JavaDoc token = ( String JavaDoc ) ii.next();
140                 if ( token != null && token.length() > 2 )
141                 {
142                     // Strip braces from the known token
143
token = token.substring( 1, token.length() - 1 );
144                     int index = _template.indexOf( token );
145                     if ( index != -1 )
146                     {
147                         if ( _template.charAt( index - 1 ) != BEGIN_TOKEN_QUALIFIER
148                                 || _template.charAt( index + token.length() ) != END_TOKEN_QUALIFIER )
149                         {
150                             throw new IllegalStateException JavaDoc( "Template token, " + token
151                                     + ", is not correctly enclosed with braces in template: " + _template );
152                         }
153                     }
154                 }
155             }
156         }
157
158         // Parse the template into tokens and literals
159
parseTemplate();
160
161         // Check if the required tokens are present
162
if ( _requiredTokens != null )
163         {
164             for ( java.util.Iterator JavaDoc ii = _requiredTokens.iterator(); ii.hasNext(); )
165             {
166                 String JavaDoc token = ( String JavaDoc ) ii.next();
167                 String JavaDoc qualifiedToken = token;
168                 TemplateItem requiredItem = new TemplateItem( qualifiedToken, true );
169
170                 if ( !_parsedTemplate.contains( requiredItem ) )
171                 {
172                     throw new IllegalStateException JavaDoc( "Required token, " + token
173                             + ", not found in template: " + _template );
174                 }
175             }
176         }
177     }
178
179     private void parseTemplate()
180     {
181         if ( _isParsed ) return;
182
183         _parsedTemplate = new ArrayList JavaDoc/*< TemplateItem >*/();
184         TemplateTokenizer tokenizer = new TemplateTokenizer( getTemplate() );
185         for ( ; tokenizer.hasNext(); )
186         {
187             boolean isToken = tokenizer.isTokenNext();
188             String JavaDoc tokenOrLiteral = ( String JavaDoc ) tokenizer.next();
189             TemplateItem item = new TemplateItem( tokenOrLiteral, isToken );
190             _parsedTemplate.add( item );
191         }
192
193         _isParsed = true;
194     }
195
196     /**
197      * Replace a set of tokens in the template with a corresponding set of values.
198      * This assumes that there is an ordered one-to-one relationship. Tokens are
199      * expected to be qualified in braces. E.g. {url:path}
200      */

201     public void substitute( Map JavaDoc/*< String, String >*/ tokensAndValues )
202     {
203         if ( tokensAndValues != null )
204         {
205             _tokenValuesMap.putAll( tokensAndValues );
206         }
207     }
208
209     /**
210      * Replace a single token in the template with a corresponding String value.
211      * Tokens are expected to be qualified in braces. E.g. {url:path}
212      */

213     public void substitute( String JavaDoc token, String JavaDoc value )
214     {
215         _tokenValuesMap.put( token, value );
216     }
217
218     /**
219      * Replace a single token in the template with a corresponding int value.
220      * Tokens are expected to be qualified in braces. E.g. {url:port}
221      */

222     public void substitute( String JavaDoc token, int value )
223     {
224         String JavaDoc valueStr = Integer.toString( value );
225         _tokenValuesMap.put( token, valueStr );
226     }
227
228     /**
229      * Return the String representation of the template after
230      * replacing all tokens with their associated values..
231      */

232     public String JavaDoc toString()
233     {
234         // template should already have been parsed with a call to
235
if ( !_isParsed )
236         {
237             // Parse the template into tokens and literals
238
parseTemplate();
239         }
240
241         InternalStringBuilder result = new InternalStringBuilder( _template.length() + 16 );
242         for ( java.util.Iterator JavaDoc ii = _parsedTemplate.iterator(); ii.hasNext(); )
243         {
244             TemplateItem item = ( TemplateItem ) ii.next();
245             if ( item.isToken() )
246             {
247                 if ( _tokenValuesMap.containsKey( item.getValue() ) )
248                 {
249                     appendToResult( result, ( String JavaDoc ) _tokenValuesMap.get( item.getValue() ) );
250                 }
251                 else
252                 {
253                     // No value for the token so treat the token as a literal.
254
appendToResult( result, item.getValue() );
255                 }
256             }
257             else
258             {
259                 appendToResult( result, item.getValue() );
260             }
261         }
262
263         return result.toString();
264     }
265
266     // check to make sure we don't end up with "//" between components
267
// of the URL
268
private void appendToResult( InternalStringBuilder result, String JavaDoc value )
269     {
270         if ( value == null || value.length() == 0 ) return;
271
272         if ( result.length() > 0 && result.charAt( result.length() - 1 ) == '/'
273                 && value.charAt( 0 ) == '/' )
274         {
275             result.deleteCharAt( result.length() - 1 );
276         }
277         result.append( value );
278     }
279
280     protected class TemplateItem
281     {
282         private String JavaDoc value;
283         private boolean isToken = false;
284
285         public TemplateItem( String JavaDoc value, boolean isToken )
286         {
287             assert value != null : "TemplateItem value cannot be null.";
288             this.value = value;
289             this.isToken = isToken;
290         }
291
292         public String JavaDoc getValue()
293         {
294             return value;
295         }
296
297         public boolean isToken()
298         {
299             return isToken;
300         }
301
302         public boolean equals( Object JavaDoc o )
303         {
304             if ( this == o )
305             {
306                 return true;
307             }
308             if ( !( o instanceof TemplateItem ) )
309             {
310                 return false;
311             }
312
313             final TemplateItem templateItem = ( TemplateItem ) o;
314
315             if ( isToken != templateItem.isToken() )
316             {
317                 return false;
318             }
319             if ( !value.equals( templateItem.getValue() ) )
320             {
321                 return false;
322             }
323
324             return true;
325         }
326
327         public int hashCode()
328         {
329             int result;
330             result = value.hashCode();
331             result = 29 * result + ( isToken ? 1 : 0 );
332             return result;
333         }
334     }
335 }
336
Popular Tags