001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.core.urltemplates;
020:
021: import java.util.Iterator;
022: import java.util.regex.Matcher;
023: import java.util.regex.Pattern;
024:
025: /**
026: * The identified tokens and the text between the
027: * matching tokens in the template are all returned.
028: */
029: public class TemplateTokenizer implements Iterator {
030:
031: private static final String PATTERN = "\\{[\\w[\\-:_]]+\\}";
032: private static final Pattern pattern = Pattern.compile(PATTERN);
033:
034: private CharSequence _template;
035: private Matcher _matcher;
036: private int _endPrevios = 0;
037:
038: // The current matched token value. If non-null and literal == null,
039: // should be returned at the next call to next()
040: private String _token;
041:
042: // The current literal string. If non-null, non-empty, should be
043: // returned at the next call to next()
044: private String _literal;
045:
046: public TemplateTokenizer(CharSequence template) {
047: _template = template;
048: _matcher = pattern.matcher(_template);
049: }
050:
051: /**
052: * Returns true if there are more literals or tokens/delimiters.
053: */
054: public boolean hasNext() {
055: if (_matcher == null) {
056: return false;
057: }
058: if (_literal != null || _token != null) {
059: return true;
060: }
061: if (_matcher.find()) {
062: _literal = _template.subSequence(_endPrevios,
063: _matcher.start()).toString();
064: _token = _matcher.group();
065: _endPrevios = _matcher.end();
066: } else if (_endPrevios < _template.length()) {
067: // We're at the end
068: _literal = _template.subSequence(_endPrevios,
069: _template.length()).toString();
070: _endPrevios = _template.length();
071:
072: // Remove the matcher so it doesn't reset itself
073: _matcher = null;
074: }
075: return _literal != null || _token != null;
076: }
077:
078: /**
079: * Returns the next literal string or token/delimiter.
080: */
081: public Object next() {
082: String result = null;
083:
084: if (_literal != null) {
085: result = _literal;
086: _literal = null;
087: } else if (_token != null) {
088: result = _token;
089: _token = null;
090: }
091: return result;
092: }
093:
094: /**
095: * Returns true if the call to next() will return a token rather
096: * than a literal.
097: */
098: public boolean isTokenNext() {
099: return _literal == null && _token != null;
100: }
101:
102: /**
103: * Not supported.
104: */
105: public void remove() {
106: throw new UnsupportedOperationException();
107: }
108: }
|