001: package org.tigris.scarab.util;
002:
003: /* ================================================================
004: * Copyright (c) 2000-2002 CollabNet. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowlegement: "This product includes
019: * software developed by Collab.Net <http://www.Collab.Net/>."
020: * Alternately, this acknowlegement may appear in the software itself, if
021: * and wherever such third-party acknowlegements normally appear.
022: *
023: * 4. The hosted project names must not be used to endorse or promote
024: * products derived from this software without prior written
025: * permission. For written permission, please contact info@collab.net.
026: *
027: * 5. Products derived from this software may not use the "Tigris" or
028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
029: * prior written permission of Collab.Net.
030: *
031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
034: * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042: *
043: * ====================================================================
044: *
045: * This software consists of voluntary contributions made by many
046: * individuals on behalf of Collab.Net.
047: */
048:
049: import java.util.Iterator;
050: import java.util.List;
051:
052: import org.apache.commons.lang.StringUtils;
053: import org.apache.turbine.RunData;
054: import org.tigris.scarab.om.Module;
055:
056: /**
057: * A Utility class for code that doesn't really go other places.
058: *
059: * @author <a href="mailto:jon@collab.net">Jon Scott Stevens</a>
060: * @version $Id: ScarabUtil.java 10281 2006-09-07 23:47:01Z jorgeuriarte $
061: */
062: public class ScarabUtil {
063:
064: /**
065: * System global initialization.
066: * Useful for random stuff that needs initialization early.
067: *
068: */
069: public static void initializeScarab() {
070: }
071:
072: /**
073: * Finds the first value for the named request parameter. This is
074: * useful to handle the case when there are more than one of the
075: * named key fields present on a screen.
076: *
077: * @param runData Source of the export format information.
078: * @param name The name of the request parameter to get a value
079: * for.
080: * @return The format type, or <code>null</code> if indeterminate.
081: */
082: public static String findValue(RunData runData, String name) {
083: String[] possibilities = runData.getParameters().getStrings(
084: name);
085: if (possibilities != null) {
086: for (int i = 0; i < possibilities.length; i++) {
087: if (StringUtils.isNotEmpty(possibilities[i])) {
088: return possibilities[i];
089: }
090: }
091: }
092: return null;
093: }
094:
095: /**
096: * It uses the IssueIdParser to convert all issue id's into links.
097: * The output is enclosed into a <,pre>...<,/pre> bracket pair so that
098: * simple markup (line breaks, white spaces) is preserved.
099: */
100: public static String linkifyText(String input, ScarabLink link,
101: Module module) throws Exception {
102: StringBuffer sb = new StringBuffer(input.length() * 2);
103:
104: // THIS STUFF REALLY BELONGS IN ScarabGlobalTool.textToHtml
105: // ALSO REMOVED BECAUSE OF RADEOX
106: // first get rid of any HTML crap
107: String output = input;//ReferenceInsertionFilter.filter(input);
108: //output = perlUtil.substitute(REGEX_NEWLINETOBR,output);
109: //output = perlUtil.substitute(REGEX_MAILTO,output);
110: //output = perlUtil.substitute(REGEX_URL,output);
111:
112: List result = IssueIdParser.tokenizeText(module, output);
113: String engine = module.getCommentRenderingEngine();
114: if (engine.equals("plaintext")) {
115: sb.append("<pre>");
116: }
117: for (Iterator itr = result.iterator(); itr.hasNext();) {
118: Object tmp = itr.next();
119: if (tmp instanceof String) {
120: sb.append(tmp);
121: } else {
122: List tmpList = (List) tmp;
123: link.addPathInfo("id", (String) tmpList.get(1));
124: link.setLabel((String) tmpList.get(0));
125: String bar = link.setAlternateText(
126: (String) tmpList.get(0)).toString();
127: sb.append(bar);
128: }
129: }
130: if (engine.equals("plaintext")) {
131: sb.append("</pre>");
132: }
133: return sb.toString();
134: }
135:
136: /**
137: * Check whether Object array contains passed in object.
138: */
139: public static final boolean contains(Object[] array, Object obj) {
140: boolean contains = false;
141: if (array != null && array.length > 0) {
142: for (int i = 0; i < array.length; i++) {
143: Object element = array[i];
144: if (obj.equals(element)) {
145: contains = true;
146: break;
147: }
148: }
149: }
150: return contains;
151: }
152:
153: /**
154: * Hack to replace the string "\n" with EOL characters...
155: * string.replaceAll("\\n","\n") does not work.
156: *
157: * Originally part of SimpleHandler but useful as utility method.
158: */
159: public static String fixEOLs(final String str) {
160: final int idx = str.indexOf("\\n");
161: if (idx != -1) {
162: return str.substring(0, idx) + "\n"
163: + fixEOLs(str.substring(idx + "\\n".length()));
164: } else {
165: return str;
166: }
167: }
168:
169: /**
170: * URL encodes <code>in</code>. If the string is null, nothing will be
171: * written. This method is faster than urlEncodeSlow if the string to
172: * encode does not contain any characters needing encoding. It adds some
173: * penalty for strings which actually need to be encoded. for short strings
174: * ~20 characters the upside is a 75% decrease. while the penalty is a 10%
175: * increase. As many query parameters do not need encoding even in i18n
176: * applications it should be much better to delay the byte conversion.
177: *
178: * @param in the String to encode.
179: * @return the url-encoded string.
180: */
181: public static final String urlEncode(String in) {
182: if (in == null) {
183: return null;
184: }
185:
186: if (in.length() == 0) {
187: return "";
188: }
189:
190: StringBuffer out = new StringBuffer(in.length());
191: char[] chars = in.toCharArray();
192:
193: for (int i = 0; i < chars.length; i++) {
194: char c = chars[i];
195:
196: if (c < 128 && safe[c]) {
197: out.append(c);
198: } else if (c == ' ') {
199: out.append('+');
200: } else {
201: // since we need to encode we will give up on
202: // doing it the fast way and convert to bytes.
203: return out.append(
204: urlEncodeSlow(in.substring(i).getBytes()))
205: .toString();
206: }
207: }
208: return out.toString();
209: }
210:
211: /**
212: * URL encodes <code>in</code>. Code 'borrowed' from DynamicURI.java in
213: * the Jakarta Turbine 3 package. We use this code instead of
214: * java.net.Encoder because Encoder.encode is deprecated and we don't feel
215: * like putting a dependency on JDK 1.4.1. This should work fine for our
216: * purposes.
217: *
218: * @param in a non-empty String to encode.
219: * @return the url-encoded string.
220: */
221: private static final String urlEncodeSlow(byte[] bytes) {
222: StringBuffer out = new StringBuffer(bytes.length * 2);
223:
224: for (int i = 0; i < bytes.length; i++) {
225: char c = (char) bytes[i];
226:
227: if (c < 128 && safe[c]) {
228: out.append(c);
229: } else if (c == ' ') {
230: out.append('+');
231: } else {
232: byte toEscape = bytes[i];
233: out.append('%');
234: int low = (toEscape & 0x0f);
235: int high = ((toEscape & 0xf0) >> 4);
236: out.append(HEXADECIMAL[high]);
237: out.append(HEXADECIMAL[low]);
238: }
239: }
240: return out.toString();
241: }
242:
243: /**
244: * Array mapping hexadecimal values to the corresponding ASCII characters.
245: */
246: private static final char[] HEXADECIMAL = { '0', '1', '2', '3',
247: '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
248:
249: /**
250: * Characters that need not be encoded. This is much faster than using a
251: * BitSet, and for such a small array the space cost seems justified.
252: */
253: private static boolean[] safe = new boolean[128];
254:
255: /** Static initializer for {@link #safe} */
256: static {
257: for (int i = 'a'; i <= 'z'; i++) {
258: safe[i] = true;
259: }
260: for (int i = 'A'; i <= 'Z'; i++) {
261: safe[i] = true;
262: }
263: for (int i = '0'; i <= '9'; i++) {
264: safe[i] = true;
265: }
266:
267: safe['-'] = true;
268: safe['_'] = true;
269: safe['.'] = true;
270: safe['!'] = true;
271: safe['~'] = true;
272: safe['*'] = true;
273: safe['\''] = true;
274: safe['('] = true;
275: safe[')'] = true;
276: }
277:
278: public static String filterNonXml(String input) {
279: char output[] = new char[input.length()];
280: for (int i = 0; i < input.length(); i++) {
281: char ch = input.charAt(i);
282: if (isXMLCharacter(ch)) {
283: output[i] = ch;
284: } else {
285: output[i] = ' ';
286: }
287: }
288: return new String(output);
289: }
290:
291: private static boolean isXMLCharacter(int c) {
292:
293: if (c == '\n')
294: return true;
295: if (c == '\r')
296: return true;
297: if (c == '\t')
298: return true;
299:
300: if (c < 0x20)
301: return false;
302: if (c <= 0xD7FF)
303: return true;
304: if (c < 0xE000)
305: return false;
306: if (c <= 0xFFFD)
307: return true;
308: if (c < 0x10000)
309: return false;
310: if (c <= 0x10FFFF)
311: return true;
312:
313: return false;
314: }
315:
316: }
|