1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 1999 by Sun Microsystems, Inc.
23 * All rights reserved.
24 *
25 */
26
27//  AttributePattern.java: Models a pattern for attribute matching.
28//  Author:           James Kempf
29//  Created On:       Tue Feb  3 15:26:30 1998
30//  Last Modified By: James Kempf
31//  Last Modified On: Thu Aug  6 14:33:57 1998
32//  Update Count:     19
33//
34
35package com.sun.slp;
36
37import java.util.*;
38import java.io.*;
39
40/**
41 * The AttributePattern class models an attribute pattern. It handles
42 * wildcard matching of lowercased, space-compressed strings. Each
43 * element in the parts vector is a PatternPart object. A PatternPart
44 * object is a pattern consisting of (maximally) a beginning wildcard and
45 * string pattern. A PatternPart may be lacking the
46 * any of these, but will always have at least one.
47 *
48 * @author James Kempf
49 */
50
51class AttributePattern extends AttributeString {
52
53    private static final String WILDCARD = "*";
54
55    private Vector parts = new Vector();
56
57    /**
58     * The PatternPart class models a single component of a pattern.
59     * It may have a beginning wildcard and string
60     * pattern in the middle. Any of the parts may be missing, but it will
61     * always have at least one.
62     *
63     * @author James Kempf
64     */
65
66
67    private class PatternPart extends Object {
68
69	boolean wildcard = false;
70	String pattern = "";
71
72	PatternPart(boolean wc, String str) {
73	    wildcard = wc;
74	    pattern = str;
75
76	}
77    }
78
79    AttributePattern(String str, Locale locale) {
80
81	super(str, locale);
82
83	// Parse out wildcards into PatternPart objects.
84
85	// If there's no wildcards, simply insert the string in as the pattern.
86
87	if (cstring.indexOf(WILDCARD) == -1) {
88	    parts.addElement(new PatternPart(false, cstring));
89
90	} else {
91
92	    // Parse the patterns into parts.
93
94	    StringTokenizer tk = new StringTokenizer(cstring, WILDCARD, true);
95
96	    while (tk.hasMoreTokens()) {
97		String middle = "";
98		boolean wc = false;
99
100		String tok = tk.nextToken();
101
102		// Beginning wildcard, or, if none, then the middle.
103
104		if (tok.equals(WILDCARD)) {
105		    wc = true;
106
107		    // Need to look for middle.
108
109		    if (tk.hasMoreTokens()) {
110			middle = tk.nextToken();
111
112		    }
113
114		} else {
115		    middle = tok;
116
117		}
118
119		// Note that there may be a terminal pattern part that just
120		//  consists of a wildcard.
121
122		parts.addElement(new PatternPart(wc, middle));
123	    }
124	}
125    }
126
127    boolean isWildcarded() {
128	return (parts.size() > 1);
129
130    }
131
132    // Match the AttributeString object against this pattern,
133    //  returning true if they match.
134
135    public boolean match(AttributeString str) {
136	String cstring = str.cstring;
137	int offset = 0, len = cstring.length();
138	int i = 0, n = parts.size();
139	boolean match = true;
140
141	// March through the parts, matching against the string.
142
143	for (; i < n; i++) {
144	    PatternPart p = (PatternPart)parts.elementAt(i);
145
146	    // If there's a wildcard, check the remainder of the string for
147	    //  the pattern.
148
149	    if (p.wildcard) {
150
151		// Note that if the pattern string is empty (""), then this
152		//  will return offset, but on the next iteration, it will
153		//  fall out of the loop because an empty pattern string
154		//  can only occur at the end (like "foo*").
155
156		if ((offset = cstring.indexOf(p.pattern, offset)) == -1) {
157
158		    // The pattern was not found. Break out of the loop.
159
160		    match = false;
161		    break;
162		}
163
164		offset += p.pattern.length();
165
166		// We are at the end of the string.
167
168		if (offset >= len) {
169
170		    // If we are not at the end of the pattern, then we may not
171		    //  have a match.
172
173		    if (i < (n - 1)) {
174
175			// If there is one more in the pattern, and it is
176			// a pure wildcard, then we *do* have a match.
177
178			if (i == (n - 2)) {
179			    p = (PatternPart)parts.elementAt(i+1);
180
181			    if (p.wildcard == true &&
182			       p.pattern.length() <= 0) {
183				break;
184
185			    }
186			}
187
188			match = false;
189
190		    }
191
192		    // Break out of the loop, no more string to analyze.
193
194		    break;
195		}
196
197	    } else {
198
199		// The pattern string must match the beginning part of the
200		// argument string.
201
202		if (!cstring.regionMatches(offset,
203					   p.pattern,
204					   0,
205					   p.
206					   pattern.length())) {
207		    match = false;
208		    break;
209
210		}
211
212		// Bump up offset by the pattern length, and exit if
213		// we're beyond the end of the string.
214
215		offset += p.pattern.length();
216
217		if (offset >= len) {
218		    break;
219
220		}
221	    }
222	}
223
224	return match;
225    }
226}
227