001: package org.tigris.scarab.util;
002:
003: /* ================================================================
004: * Copyright (c) 2000-2003 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 CollabNet <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 CollabNet.
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 CollabNet.
047: */
048:
049: import java.util.ArrayList;
050: import java.util.List;
051:
052: import org.apache.commons.lang.StringUtils;
053: import org.apache.fulcrum.pool.InitableRecyclable;
054: import org.tigris.scarab.om.Issue;
055: import org.tigris.scarab.om.Module;
056:
057: /**
058: *
059: * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
060: * @version $Id: EmailLink.java 9476 2005-03-16 22:56:11Z dabbous $
061: */
062: public class EmailLink implements InitableRecyclable, SkipFiltering {
063: private String label;
064: private String attributeText;
065: private String alternateText;
066: private Integer currentModuleId;
067: private Module currentModule;
068: private boolean isOmitModule;
069: private boolean isOmitIssueType;
070: private boolean overrideSecurity;
071:
072: private boolean disposed = false;
073:
074: /** An ArrayList that contains all the path info if any. */
075: private List pathInfo = new ArrayList();
076:
077: /** HTTP protocol. */
078: public static final String HTTP = "http";
079:
080: /** HTTPS protocol. */
081: public static final String HTTPS = "https";
082:
083: /**
084: * Constructor to allow factory instantiation of
085: * EmailLinks. setCurrentModule must be called before
086: * first use.
087: */
088: public EmailLink() {
089: }
090:
091: /**
092: * Constructor.
093: */
094: public EmailLink(Module currentModule) {
095: setCurrentModule(currentModule);
096: }
097:
098: public void init(Object obj) {
099: if (obj instanceof Module) {
100: setCurrentModule((Module) obj);
101: }
102: }
103:
104: public Module getCurrentModule() {
105: return this .currentModule;
106: }
107:
108: public void setCurrentModule(Module cM) {
109: currentModuleId = cM.getModuleId();
110: this .currentModule = cM;
111: }
112:
113: public void refresh() {
114: label = null;
115: attributeText = null;
116: alternateText = null;
117: currentModuleId = null;
118: currentModule = null;
119: isOmitModule = false;
120: isOmitIssueType = false;
121: this .pathInfo.clear();
122: }
123:
124: private String convertAndTrim(String value) {
125: String tmp = null;
126: if (value != null) {
127: tmp = value.trim();
128: tmp = tmp.toLowerCase();
129: }
130: return tmp;
131: }
132:
133: /**
134: * Add a key value pair (in the form of a 2 object array) to the provided
135: * list
136: *
137: * @param list List to add to.
138: * @param name A String with the name to add.
139: * @param value A String with the value to add.
140: */
141: protected void addPair(List list, String name, String value) {
142: Object[] tmp = new Object[2];
143:
144: tmp[0] = convertAndTrim(name);
145: tmp[1] = value;
146:
147: list.add(tmp);
148: }
149:
150: /**
151: * Adds a name=value pair to the path_info string.
152: *
153: * @param name A String with the name to add.
154: * @param value A String with the value to add.
155: */
156: public EmailLink addPathInfo(String name, String value) {
157: addPair(pathInfo, name, value);
158: return this ;
159: }
160:
161: /**
162: * Adds a name=value pair to the path_info string.
163: *
164: * @param name A String with the name to add.
165: * @param value An Object with the value to add.
166: */
167: public EmailLink addPathInfo(String name, Object value) {
168: addPathInfo(name, value.toString());
169: return this ;
170: }
171:
172: /**
173: * Adds a name=value pair to the path_info string.
174: *
175: * @param name A String with the name to add.
176: * @param value A double with the value to add.
177: */
178: public EmailLink addPathInfo(String name, double value) {
179: addPathInfo(name, Double.toString(value));
180: return this ;
181: }
182:
183: /**
184: * Adds a name=value pair to the path_info string.
185: *
186: * @param name A String with the name to add.
187: * @param value An int with the value to add.
188: */
189: public EmailLink addPathInfo(String name, int value) {
190: addPathInfo(name, Integer.toString(value));
191: return this ;
192: }
193:
194: /**
195: * Adds a name=value pair to the path_info string.
196: *
197: * @param name A String with the name to add.
198: * @param value A long with the value to add.
199: */
200: public EmailLink addPathInfo(String name, long value) {
201: addPathInfo(name, Long.toString(value));
202: return this ;
203: }
204:
205: /**
206: * Adds a name=value pair to the path_info string.
207: *
208: * @param name A String with the name to add.
209: * @param value A double with the value to add.
210: */
211: public EmailLink addPathInfo(String name, boolean value) {
212: addPathInfo(name, (value ? "true" : "false"));
213: return this ;
214: }
215:
216: public EmailLink setPathInfo(String key, String value) {
217: removePathInfo(key);
218: addPathInfo(key, value);
219: return this ;
220: }
221:
222: /**
223: * Helper method to remove one or more pairs by its name (ie key).
224: * It is intended to be used with <tt>queryData</tt> and <tt>pathInfo</tt>.
225: * @param pairs the list of pairs to look over for removal.
226: * @param name the name of the pair(s) to remove.
227: */
228: protected void removePairByName(List pairs, String name) {
229: name = convertAndTrim(name);
230: // CAUTION: the dynamic evaluation of the size is on purpose because
231: // elements may be removed on the fly.
232: for (int i = 0; i < pairs.size(); i++) {
233: Object[] pair = (Object[]) pairs.get(i);
234: if (name.equals(pair[0])) {
235: pairs.remove(i);
236: }
237: }
238: }
239:
240: /**
241: * Removes all the path info elements.
242: */
243: public void removePathInfo() {
244: this .pathInfo.clear();
245: }
246:
247: /**
248: * Removes a name=value pair from the path info.
249: *
250: * @param name A String with the name to be removed.
251: */
252: public void removePathInfo(String name) {
253: removePairByName(pathInfo, name);
254: }
255:
256: /**
257: * Gets the server name.
258: *
259: * @return A String with the server name.
260: */
261: public String getServerName() {
262: String domain = null;
263: if (currentModule != null) {
264: domain = currentModule.getHttpDomain();
265: if (domain == null || domain.length() == 0) {
266: domain = "check.Scarab.properties";
267: }
268: }
269:
270: return domain;
271: }
272:
273: /**
274: * Gets the server port.
275: *
276: * @return A the server port, or <code>-1</code> if unknown.
277: */
278: public int getServerPort() {
279: int result = -1;
280: if (currentModule != null) {
281: try {
282: String port = currentModule.getPort();
283: if (StringUtils.isNotEmpty(port)) {
284: result = Integer.parseInt(port);
285: }
286: } catch (Exception e) {
287: Log.get().debug(e);
288: }
289: }
290: return result;
291: }
292:
293: /**
294: * Gets the server scheme (HTTP or HTTPS).
295: *
296: * @return A String with the server scheme.
297: */
298: public String getServerScheme() {
299: String result = null;
300: try {
301: if (currentModule != null) {
302: result = currentModule.getScheme();
303: }
304: } catch (Exception e) {
305: Log.get().debug(e);
306: }
307: return result;
308: }
309:
310: /**
311: * Gets the server scriptName (/scarab/issues).
312: *
313: * @return A String with the server scriptName.
314: */
315: public String getScriptName() {
316: String result = null;
317: try {
318: if (currentModule != null) {
319: result = currentModule.getScriptName();
320: }
321: } catch (Exception e) {
322: Log.get().debug(e);
323: }
324: return result;
325: }
326:
327: /**
328: * Does this URI have path info.
329: */
330: public boolean hasPathInfo() {
331: return !pathInfo.isEmpty();
332: }
333:
334: /**
335: * This method takes a Vector of key/value arrays and writes it to the
336: * supplied StringBuffer as encoded path info.
337: *
338: * @param pairs A Vector of key/value arrays.
339: * @return a String to which encoded path info is written
340: */
341: protected String renderPathInfo(List pairs) {
342: return renderPairs(pairs, '/', '/');
343: }
344:
345: /**
346: * This method takes a List of key/value arrays and converts it
347: * into a URL encoded key/value pair format with the appropriate
348: * separator.
349: *
350: * @return a String to which the pairs are written to.
351: * @param pairs A List of key/value arrays.
352: * @param pairSep the character to use as a separator between pairs.
353: * For example for a query-like rendering it would be '&'.
354: * @param keyValSep the character to use as a separator between
355: * key and value. For example for a query-like rendering, it would be '='.
356: */
357: protected String renderPairs(List pairs, char pairSep,
358: char keyValSep) {
359: boolean first = true;
360: StringBuffer out = new StringBuffer();
361: final int count = pairs.size();
362: for (int i = 0; i < count; i++) {
363: Object[] pair = (Object[]) pairs.get(i);
364:
365: if (first) {
366: first = false;
367: } else {
368: out.append(pairSep);
369: }
370:
371: out.append(ScarabUtil.urlEncode((String) pair[0]));
372: out.append(keyValSep);
373: out.append(ScarabUtil.urlEncode((String) pair[1]));
374: }
375: return out.toString();
376: }
377:
378: /**
379: * Builds the URL with all of the data URL-encoded as well as
380: * encoded using HttpServletResponse.encodeUrl().
381: *
382: * <p>
383: * <code><pre>
384: * DynamicURI dui = new DynamicURI (data, "UserScreen" );
385: * dui.addPathInfo("user","jon");
386: * dui.toString();
387: * </pre></code>
388: *
389: * The above call to toString() would return the String:
390: *
391: * <p>
392: * http://www.server.com/servlets/Turbine/screen/UserScreen/user/jon
393: *
394: * @return A String with the built URL.
395: */
396: public String toString() {
397: StringBuffer output = new StringBuffer();
398: output.append(getServerScheme());
399: output.append("://");
400: output.append(getServerName());
401: int port = getServerPort();
402: if (port >= 0
403: && ((HTTP.equals(getServerScheme()) && port != 80) || (HTTPS
404: .equals(getServerScheme()) && port != 443))) {
405: output.append(':');
406: output.append(port);
407: }
408:
409: output.append(getScriptName());
410:
411: if (this .hasPathInfo()) {
412: output.append('/');
413: output.append(renderPathInfo(this .pathInfo));
414: }
415: return output.toString();
416: }
417:
418: /**
419: * Causes the link to not include the module id. Useful for templates
420: * where a module is not required or desired.
421: *
422: * @return a <code>EmailLink</code> value
423: */
424: public EmailLink omitModule() {
425: isOmitModule = true;
426: return this ;
427: }
428:
429: /**
430: * Sets the template variable used by the Template Service. The
431: * module id of the new selected module is given.
432: *
433: * @param t A String with the template name.
434: * @return A EmailLink.
435: */
436: public EmailLink setPage(String t) {
437: addPathInfo(ScarabConstants.TEMPLATE, t);
438:
439: if (!isOmitModule) {
440: addPathInfo(ScarabConstants.CURRENT_MODULE, currentModuleId);
441: }
442: return this ;
443: }
444:
445: /**
446: * Sets the action= value for this URL.
447: *
448: * <p>By default it adds the information to the path_info instead
449: * of the query data.
450: *
451: * @param action A String with the action value.
452: * @return A EmailLink (self).
453: */
454: public EmailLink setAction(String action) {
455: addPathInfo(ScarabConstants.ACTION, action);
456: return this ;
457: }
458:
459: /**
460: * Returns a short link for viewing a single issue
461: *
462: * @param issue an <code>Issue</code> value
463: * @return a <code>String</code> value
464: * @exception Exception if an error occurs
465: */
466: public EmailLink getIssueIdLink(Issue issue) throws Exception {
467: this .addPathInfo(ScarabConstants.ID, issue.getUniqueId());
468: return this ;
469: }
470:
471: // ****************************************************************
472: // ****************************************************************
473: // Implementation of Recyclable
474: // ****************************************************************
475: // ****************************************************************
476:
477: /**
478: * Recycles the object by removing its disposed flag.
479: */
480: public void recycle() {
481: disposed = false;
482: }
483:
484: /**
485: * Disposes the object by setting its disposed flag.
486: */
487: public void dispose() {
488: refresh();
489: disposed = true;
490: }
491:
492: /**
493: * Checks whether the object is disposed.
494: *
495: * @return true, if the object is disposed.
496: */
497: public boolean isDisposed() {
498: return disposed;
499: }
500: }
|