1 /*
2 * Copyright 2004,2004 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
17 package org.apache.bsf.util;
18
19 import java.beans.Introspector;
20 import java.io.BufferedReader;
21 import java.io.File;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.Reader;
27 import java.io.StringReader;
28 import java.net.MalformedURLException;
29 import java.net.URL;
30 import java.util.StringTokenizer;
31 import java.util.Vector;
32
33 /**
34 * Deals with strings (probably need to elaborate some more).
35 *
36 * @author Matthew J. Duftler
37 */
38 public class StringUtils
39 {
40 public static final String lineSeparator =
41 System.getProperty("line.separator", "\n");
42 public static final String lineSeparatorStr = cleanString(lineSeparator);
43
44 public static String classNameToVarName(String className)
45 {
46 // Might represent an array.
47 int arrayDim = 0;
48
49 while (className.endsWith("[]"))
50 {
51 className = className.substring(0, className.length() - 2);
52 arrayDim++;
53 }
54
55 int iLastPeriod = className.lastIndexOf('.');
56 String varName = Introspector.decapitalize(
57 iLastPeriod != -1
58 ? className.substring(iLastPeriod + 1)
59 : className);
60
61 if (arrayDim > 0)
62 {
63 varName += "_" + arrayDim + "D";
64 }
65
66 return getValidIdentifierName(varName);
67 }
68 // Ensure that escape sequences are passed through properly.
69 public static String cleanString(String str)
70 {
71 if (str == null)
72 return null;
73 else
74 {
75 char[] charArray = str.toCharArray();
76 StringBuffer sBuf = new StringBuffer();
77
78 for (int i = 0; i < charArray.length; i++)
79 switch (charArray[i])
80 {
81 case '\"' : sBuf.append("\\\"");
82 break;
83 case '\\' : sBuf.append("\\\\");
84 break;
85 case '\n' : sBuf.append("\\n");
86 break;
87 case '\r' : sBuf.append("\\r");
88 break;
89 default : sBuf.append(charArray[i]);
90 break;
91 }
92
93 return sBuf.toString();
94 }
95 }
96 /**
97 * Get a string consisting of <code>numberOfChars</code> theChars.
98 *
99 * @return a string consisting of <code>numberOfChars</code> theChars.
100 */
101 public static String getChars(int numberOfChars, char theChar)
102 {
103 if (numberOfChars <= 0)
104 return "";
105
106 StringBuffer sRet = new StringBuffer(numberOfChars);
107
108 for (int i = 0; i < numberOfChars; i++)
109 sRet.append(theChar);
110
111 return sRet.toString();
112 }
113 /*
114 This method will return the correct name for a class object representing
115 a primitive, a single instance of a class, as well as n-dimensional arrays
116 of primitives or instances. This logic is needed to handle the string returned
117 from Class.getName(). If the class object represents a single instance (or
118 a primitive), Class.getName() returns the fully-qualified name of the class
119 and no further work is needed. However, if the class object represents an
120 array (of n dimensions), Class.getName() returns a Descriptor (the Descriptor
121 grammar is defined in section 4.3 of the Java VM Spec). This method will
122 parse the Descriptor if necessary.
123 */
124 public static String getClassName(Class targetClass)
125 {
126 String className = targetClass.getName();
127
128 return targetClass.isArray() ? parseDescriptor(className) : className;
129 }
130 public static String getCommaListFromVector(Vector sourceVector)
131 {
132 StringBuffer strBuf = new StringBuffer();
133
134 for (int i = 0; i < sourceVector.size(); i++)
135 {
136 strBuf.append((i > 0 ? ", " : "") +
137 sourceVector.elementAt(i));
138 }
139
140 return strBuf.toString();
141 }
142 /*
143 Returns a Reader for reading from the specified resource, if the resource
144 points to a stream.
145 */
146 public static Reader getContentAsReader(URL url) throws SecurityException,
147 IllegalArgumentException,
148 IOException
149 {
150 if (url == null)
151 {
152 throw new IllegalArgumentException("URL cannot be null.");
153 }
154
155 try
156 {
157 Object content = url.getContent();
158
159 if (content == null)
160 {
161 throw new IllegalArgumentException("No content.");
162 }
163
164 if (content instanceof InputStream)
165 {
166 Reader in = new InputStreamReader((InputStream)content);
167
168 if (in.ready())
169 {
170 return in;
171 }
172 else
173 {
174 throw new FileNotFoundException();
175 }
176 }
177 else
178 {
179 throw new IllegalArgumentException((content instanceof String)
180 ? (String)content
181 : "This URL points to a: " +
182 StringUtils.getClassName(content.getClass()));
183 }
184 }
185 catch (SecurityException e)
186 {
187 throw new SecurityException("Your JVM's SecurityManager has disallowed this.");
188 }
189 catch (FileNotFoundException e)
190 {
191 throw new FileNotFoundException("This file was not found: " + url);
192 }
193 }
194 /*
195 Shorthand for: IOUtils.getStringFromReader(getContentAsReader(url)).
196 */
197 public static String getContentAsString(URL url) throws SecurityException,
198 IllegalArgumentException,
199 IOException
200 {
201 return IOUtils.getStringFromReader(getContentAsReader(url));
202 }
203 // Handles multi-line strings.
204 public static String getSafeString(String scriptStr)
205 {
206 BufferedReader in = new BufferedReader(new StringReader(scriptStr));
207 StringBuffer strBuf = new StringBuffer();
208 String tempLine,
209 previousLine = null;
210
211 try
212 {
213 while ((tempLine = in.readLine()) != null)
214 {
215 if (previousLine != null)
216 {
217 strBuf.append("\"" + previousLine + lineSeparatorStr + "\" +" +
218 lineSeparator);
219 }
220
221 previousLine = cleanString(tempLine);
222 }
223 }
224 catch (IOException e)
225 {
226 }
227
228 strBuf.append("\"" + (previousLine != null ? previousLine : "") + "\"" +
229 lineSeparator);
230
231 return strBuf.toString();
232 }
233 /*
234 */
235 public static URL getURL(URL contextURL, String spec) throws MalformedURLException
236 {
237 return getURL(contextURL, spec, 1);
238 }
239 /*
240 The recursiveDepth argument is used to insure that the algorithm gives up
241 after hunting 2 levels up in the contextURL's path.
242 */
243 private static URL getURL(URL contextURL, String spec, int recursiveDepth)
244 throws MalformedURLException
245 {
246 URL url = null;
247
248 try
249 {
250 url = new URL(contextURL, spec);
251
252 try
253 {
254 url.openStream();
255 }
256 catch (IOException ioe1)
257 {
258 throw new MalformedURLException("This file was not found: " + url);
259 }
260 }
261 catch (MalformedURLException e1)
262 {
263 url = new URL("file", "", spec);
264
265 try
266 {
267 url.openStream();
268 }
269 catch (IOException ioe2)
270 {
271 if (contextURL != null)
272 {
273 String contextFileName = contextURL.getFile();
274 String parentName = new File(contextFileName).getParent();
275
276 if (parentName != null && recursiveDepth < 3)
277 {
278 return getURL(new URL("file", "", parentName + '/'),
279 spec,
280 recursiveDepth + 1);
281 }
282 }
283
284 throw new MalformedURLException("This file was not found: " + url);
285 }
286 }
287
288 return url;
289 }
290 public static String getValidIdentifierName(String identifierName)
291 {
292 if (identifierName == null || identifierName.length() == 0)
293 return null;
294
295 StringBuffer strBuf = new StringBuffer();
296
297 char[] chars = identifierName.toCharArray();
298
299 strBuf.append(Character.isJavaIdentifierStart(chars[0])
300 ? chars[0]
301 : '_'
302 );
303
304 for (int i = 1; i < chars.length; i++)
305 {
306 strBuf.append(Character.isJavaIdentifierPart(chars[i])
307 ? chars[i]
308 : '_'
309 );
310 }
311
312 return strBuf.toString();
313 }
314 public static boolean isValidIdentifierName(String identifierName)
315 {
316 if (identifierName == null || identifierName.length() == 0)
317 return false;
318
319 char[] chars = identifierName.toCharArray();
320
321 if (!Character.isJavaIdentifierStart(chars[0]))
322 return false;
323
324 for (int i = 1; i < chars.length; i++)
325 if (!Character.isJavaIdentifierPart(chars[i]))
326 return false;
327
328 return true;
329 }
330 public static boolean isValidPackageName(String packageName)
331 {
332 if (packageName == null)
333 return false;
334 else if (packageName.length() == 0)
335 // Empty is ok.
336 return true;
337
338 StringTokenizer strTok = new StringTokenizer(packageName, ".", true);
339
340 // Should have an odd number of tokens (including '.' delimiters).
341 if (strTok.countTokens() % 2 != 1)
342 return false;
343
344 // Must start with a valid identifier name.
345 if (!isValidIdentifierName(strTok.nextToken()))
346 return false;
347
348 // ... followed by 0 or more of ".ValidIdentifier".
349 while (strTok.hasMoreTokens())
350 {
351 // Must be a '.'.
352 if (!strTok.nextToken().equals("."))
353 return false;
354
355 // Must be a valid identifier name.
356 if (strTok.hasMoreTokens())
357 {
358 if (!isValidIdentifierName(strTok.nextToken()))
359 return false;
360 }
361 else
362 return false;
363 }
364
365 return true;
366 }
367 /*
368 See the comment above for getClassName(targetClass)...
369 */
370 private static String parseDescriptor(String className)
371 {
372 char[] classNameChars = className.toCharArray();
373 int arrayDim = 0;
374 int i = 0;
375
376 while (classNameChars[i] == '[')
377 {
378 arrayDim++;
379 i++;
380 }
381
382 StringBuffer classNameBuf = new StringBuffer();
383
384 switch (classNameChars[i++])
385 {
386 case 'B' : classNameBuf.append("byte");
387 break;
388 case 'C' : classNameBuf.append("char");
389 break;
390 case 'D' : classNameBuf.append("double");
391 break;
392 case 'F' : classNameBuf.append("float");
393 break;
394 case 'I' : classNameBuf.append("int");
395 break;
396 case 'J' : classNameBuf.append("long");
397 break;
398 case 'S' : classNameBuf.append("short");
399 break;
400 case 'Z' : classNameBuf.append("boolean");
401 break;
402 case 'L' : classNameBuf.append(classNameChars,
403 i, classNameChars.length - i - 1);
404 break;
405 }
406
407 for (i = 0; i < arrayDim; i++)
408 classNameBuf.append("[]");
409
410 return classNameBuf.toString();
411 }
412 }