001: //** Copyright Statement ***************************************************
002: //The Salmon Open Framework for Internet Applications (SOFIA)
003: // Copyright (C) 1999 - 2002, Salmon LLC
004: //
005: // This program is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU General Public License version 2
007: // as published by the Free Software Foundation;
008: //
009: // This program is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: // GNU General Public License for more details.
013: //
014: // You should have received a copy of the GNU General Public License
015: // along with this program; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: //
018: // For more information please visit http://www.salmonllc.com
019: //** End Copyright Statement ***************************************************
020: package com.salmonllc.sitemap;
021:
022: import java.io.File;
023: import java.io.FileOutputStream;
024: import java.io.IOException;
025: import java.io.PrintWriter;
026: import java.util.Enumeration;
027: import java.util.Hashtable;
028: import java.util.StringTokenizer;
029: import java.util.Vector;
030:
031: import javax.servlet.http.HttpServletRequest;
032:
033: import com.salmonllc.html.HttpServletRequestWrapper;
034: import com.salmonllc.properties.Props;
035: import com.salmonllc.util.MessageLog;
036: import com.salmonllc.util.URLGenerator;
037:
038: /**
039: * SOFIA site map implementation
040: *
041: */
042: public class SiteMap {
043: private Hashtable _nameMap = new Hashtable();
044: private Hashtable _actionMap = new Hashtable();
045: private Hashtable _uriMap = new Hashtable();
046: private Vector _list = new Vector();
047: private String _appName;
048:
049: private class SiteMapEntry {
050: String name;
051: String uri;
052: String context;
053: boolean secure;
054: boolean useForward;
055: String popupFeatures;
056: }
057:
058: /**
059: * Creates an empty SiteMap Object pointing to a particular application
060: */
061: public SiteMap(String applicationName) {
062: _appName = applicationName;
063: }
064:
065: /**
066: * Returns the SiteMap object associated with a particular application
067: */
068: public static SiteMap getSiteMap(String applicationName) {
069: try {
070: return SiteMapParser.getSiteMap(applicationName);
071: } catch (IOException e) {
072: MessageLog.writeErrorMessage("SiteMap.getSiteMap()", e,
073: null);
074: return null;
075: }
076: }
077:
078: /**
079: * Returns the url for a specified logical site map entry
080: * @param req The HttpServletRequest used for this lookup
081: * @param logicalName The name of the entry in the site map
082: * @return The absolute url to the page
083: */
084: public String getSiteMapURL(HttpServletRequest req,
085: String logicalName) {
086: return getSiteMapURL(req, logicalName, null, true);
087: }
088:
089: /**
090: * Returns the url for a specified logical site map entry
091: * @param req The HttpServletRequest used for this lookup
092: * @param logicalName The name of the entry in the site map
093: * @param additionalParms Any additional parameters that need to be appended to the url
094: * @return The absolute url to the page
095: */
096: public String getSiteMapURL(HttpServletRequest req,
097: String logicalName, String additionalParms) {
098: return getSiteMapURL(req, logicalName, additionalParms, true);
099: }
100:
101: /**
102: * Returns the url for a specified logical site map entry
103: * @param req The HttpServletRequest used for this lookup
104: * @param logicalName The name of the entry in the site map
105: * @param additionalParms Any additional parameters that need to be appended to the url
106: * @param javaScriptOK True to allow JavaScript in the URL (for popup windows)
107: * @return The absolute url to the page
108: */
109: public String getSiteMapURL(HttpServletRequest req,
110: String logicalName, String additionalParms,
111: boolean javaScriptOK) {
112: return getSiteMapURL(req, logicalName, additionalParms,
113: javaScriptOK, false);
114: }
115:
116: /**
117: * Returns the url for a specified logical site map entry
118: * @param req The HttpServletRequest used for this lookup
119: * @param logicalName The name of the entry in the site map
120: * @param additionalParms Any additional parameters that need to be appended to the url
121: * @param javaScriptOK True to allow JavaScript in the URL (for popup windows)
122: * @param doForwardOK True or false, the url being generated is in a contect where a forward can be used
123: * @return The absolute url to the page
124: */
125: public String getSiteMapURL(HttpServletRequest req,
126: String logicalName, String additionalParms,
127: boolean javaScriptOK, boolean doForwardOK) {
128:
129: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
130: if (entry == null)
131: return null;
132: String url = "";
133:
134: if (entry.uri.startsWith("http")
135: || entry.uri.startsWith("mailto:"))
136: url = entry.uri;
137: else {
138: if (!entry.useForward || !doForwardOK) {
139: if (entry.secure)
140: url = URLGenerator.generateSecureServerURL(req);
141: else
142: url = URLGenerator.generateServerURL(req);
143: }
144: if (getContext(logicalName) != null) {
145: url += "/" + getContext(logicalName);
146: } else {
147: if (req instanceof HttpServletRequestWrapper
148: && ((HttpServletRequestWrapper) req)
149: .getPortletWrapppedRequest() != null)
150: url += "/" + _appName;
151: else
152: url += getApplicationNameFromURL(_appName, req);
153: }
154:
155: if (!entry.uri.startsWith("/"))
156: url = url + "/";
157:
158: url += entry.uri;
159: }
160:
161: if (additionalParms != null) {
162: String baseURL = parseURL(url);
163: String[] baseParms = parseParms(url);
164: String baseHashParms = baseParms[1];
165: String baseQuestParms = baseParms[0];
166:
167: String addURL = parseURL(additionalParms);
168: String addParms[] = parseParms(additionalParms);
169: String addHashParms = addParms[1];
170: String addQuestParms = addParms[0];
171:
172: url = baseURL;
173: if (addURL != null && addURL.length() > 0) {
174: if (baseURL.endsWith("/") && addURL.startsWith("/"))
175: url += addURL.substring(1);
176: else
177: url += addURL;
178: }
179:
180: if (baseQuestParms != null || addQuestParms != null) {
181: url += "?";
182: if (baseQuestParms != null
183: && !baseQuestParms.equals("")) {
184: url += baseQuestParms;
185: if (addQuestParms != null
186: && !addQuestParms.equals(""))
187: url += "&" + addQuestParms;
188: } else
189: url += addQuestParms;
190: }
191:
192: if (baseHashParms != null)
193: url += "#" + baseHashParms;
194: else if (addHashParms != null)
195: url += "#" + addHashParms;
196: }
197:
198: if (entry.popupFeatures != null && javaScriptOK) {
199: if (entry.popupFeatures.equals("default"))
200: url = "javascript:void window.open('" + url + "');";
201: else
202: url = "javascript:void window.open('" + url + "','"
203: + logicalName + "','" + entry.popupFeatures
204: + "');";
205: }
206: return url;
207: }
208:
209: private String[] parseParms(String url) {
210: String st[] = new String[2];
211: int posQuest = url.indexOf("?");
212: int posHash = url.indexOf("#");
213: if (posQuest == -1 && posHash == -1)
214: return st;
215: else if (posQuest > -1 && posHash == -1)
216: st[0] = url.substring(posQuest + 1);
217: else if (posQuest == -1 && posHash > -1)
218: st[1] = url.substring(posHash + 1);
219: else {
220: if (posQuest < posHash) {
221: st[0] = url.substring(posQuest + 1, posHash);
222: st[1] = url.substring(posHash + 1);
223: } else {
224: st[1] = url.substring(posHash + 1, posQuest);
225: st[0] = url.substring(posQuest + 1);
226: }
227: }
228: return st;
229: }
230:
231: /**
232: * Adds popup window javascript to a url entry if it indicates so in the site map
233: * @return
234: */
235: public String addJavaScriptToUrl(String logicalName, String url) {
236: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
237: if (entry == null)
238: return url;
239: if (entry.popupFeatures != null) {
240: if (entry.popupFeatures.equals("default"))
241: url = "javascript:void window.open('" + url + "','"
242: + logicalName + "');";
243: else
244: url = "javascript:void window.open('" + url + "','"
245: + logicalName + "','" + entry.popupFeatures
246: + "');";
247: }
248: return url;
249: }
250:
251: private String getApplicationNameFromURL(String appName,
252: HttpServletRequest req) {
253: String servletPath = req.getRequestURI();
254: String servletName = req.getServletPath();
255: if (servletName != null) {
256: int pos = servletName.lastIndexOf("/");
257: if (pos != -1)
258: servletName = servletName.substring(pos);
259: } else
260: servletName = "";
261:
262: int pos = -1;
263: if (servletPath != null)
264: pos = servletPath.indexOf(servletName);
265: if (pos < 1)
266: servletPath = "";
267: else
268: servletPath = servletPath.substring(1, pos);
269: if (servletPath != null) {
270: pos = servletPath.indexOf("/");
271: if (pos > -1)
272: servletPath = servletPath.substring(0, pos);
273: }
274:
275: if (servletPath == null)
276: return "";
277: else if (servletPath.length() > 0) {
278: if (servletPath.equals(appName))
279: return "/" + servletPath;
280: else
281: return "";
282: } else
283: return servletPath;
284: }
285:
286: /**
287: * Return true if the entry uses https
288: */
289: public boolean isSecure(String logicalName) {
290: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
291: if (entry == null)
292: return false;
293: else
294: return entry.secure;
295: }
296:
297: /**
298: * Returns true if the entry uses a forward instead of a redirect
299: */
300: public boolean useForward(String logicalName) {
301: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
302: if (entry == null)
303: return false;
304: else
305: return entry.useForward;
306: }
307:
308: /**
309: * Returns true if the entry uses javascript to open a window as a popup
310: */
311: public boolean useJavascript(String logicalName) {
312: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
313: if (entry == null)
314: return false;
315: else
316: return entry.popupFeatures != null;
317: }
318:
319: /**
320: * Returns the URI relative to the web application root or null if there is no entry
321: */
322: public String getURI(String logicalName) {
323: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
324: if (entry == null)
325: return null;
326: else
327: return entry.uri;
328: }
329:
330: /**
331: * Returns the Context relative to the web application root or null if there is no entry
332: */
333: public String getContext(String logicalName) {
334: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
335: if (entry == null)
336: return null;
337: else
338: return entry.context;
339: }
340:
341: /**
342: * Returns the Popup window features for the specified entry
343: */
344: public String getPopupFeatures(String logicalName) {
345: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
346: if (entry == null)
347: return null;
348: else
349: return entry.popupFeatures;
350: }
351:
352: /**
353: * Sets the URI relative to the web application for the entry
354: */
355: public void setURI(String logicalName, String URI) {
356: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
357: if (entry != null)
358: entry.uri = URI;
359: }
360:
361: /**
362: * Sets the context relative to the web application for the entry
363: */
364: public void setContext(String logicalName, String context) {
365: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
366: if (entry != null)
367: entry.context = context;
368: }
369:
370: /**
371: * Sets the Popup Features for the page or null to open in the same window
372: */
373: public void setPopupFeatures(String logicalName,
374: String popupFeatures) {
375: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
376: if (entry != null)
377: entry.popupFeatures = popupFeatures;
378: }
379:
380: /**
381: * Sets whether the URI entry is secure
382: */
383: public void setSecure(String logicalName, boolean secure) {
384: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
385: if (entry != null)
386: entry.secure = secure;
387: }
388:
389: /**
390: * Puts an entry into the site map. If the entry already exists it will be overwritten
391: * @param logicalName The logical name of the site map entry
392: * @param uri The URI of the page to go to when the entry is invoked
393: * @param useForward true if the site map entry should use a forward instead of a redirect
394: * @param secure true if the site map entry should jump to a secure url (https)
395: */
396: public synchronized void putEntry(String logicalName, String uri,
397: String popupFeatures, boolean useForward, boolean secure,
398: String context) {
399: SiteMapEntry entry = new SiteMapEntry();
400: entry.name = logicalName;
401: if (!uri.startsWith("/") && !uri.startsWith("http")
402: && !uri.startsWith("mailto:"))
403: uri = "/" + uri;
404: int pos1 = uri.indexOf("?");
405: int pos2 = uri.indexOf("#");
406: int pos = -1;
407: if (pos1 != -1 && pos2 != -1)
408: pos = pos1 < pos2 ? pos1 : pos2;
409: else if (pos1 != -1)
410: pos = pos1;
411: else if (pos2 != -1)
412: pos = pos2;
413: String uriEntry = uri;
414: if (pos > -1)
415: uriEntry = uri.substring(0, pos);
416:
417: entry.uri = uri;
418: entry.secure = secure;
419: entry.useForward = useForward;
420: entry.popupFeatures = popupFeatures;
421: entry.context = context;
422: if (!_nameMap.containsKey(logicalName))
423: _list.addElement(logicalName);
424: _nameMap.put(logicalName, entry);
425: _uriMap.put(uriEntry, entry);
426: }
427:
428: /**
429: * Removes an entry from the list
430: * @param logicalName
431: */
432: public synchronized void removeEntry(String logicalName) {
433: for (int i = 0; i < _list.size(); i++) {
434: if (((String) _list.elementAt(i)).equals(logicalName)) {
435: _list.remove(i);
436: SiteMapEntry entry = (SiteMapEntry) _nameMap
437: .get(logicalName);
438: _nameMap.remove(entry.name);
439: _uriMap.remove(entry.uri);
440: }
441: }
442: }
443:
444: /**
445: * Sets whether the URI entry uses a forward
446: */
447: public void setUseForward(String logicalName, boolean useForward) {
448: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(logicalName);
449: if (entry != null)
450: entry.useForward = useForward;
451: }
452:
453: /**
454: * Returns the logical name for the site map entry given the URI of a particulat page or null if that URI isn't found in the site map
455: * @param URI The URI for the page not including the servername and web application name
456: */
457: public String getEntryName(String URI) {
458: if (URI == null)
459: return null;
460: if (!URI.startsWith("/"))
461: URI = "/" + URI;
462: SiteMapEntry entry = (SiteMapEntry) _uriMap.get(URI);
463: if (entry != null)
464: return entry.name;
465: else
466: return null;
467: }
468:
469: /**
470: * Returns a list of entry names
471: */
472: public Enumeration getEntryNames() {
473: return _list.elements();
474: }
475:
476: /**
477: * Writes out the sitemap object to an xml file in the properties path
478: */
479: public synchronized void update() throws IOException {
480: String fileName = Props.getPropsPath();
481: if (!fileName.endsWith(File.separator))
482: fileName += File.separator;
483: String test=fileName+"System.map";
484: if (new File(test).exists())
485: fileName=test;
486: else
487: fileName += _appName + ".map";
488: PrintWriter pw = new PrintWriter(new FileOutputStream(fileName));
489: pw.println("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
490: pw.println("<!DOCTYPE sitemap PUBLIC \"SOFIA Site Map\" \"http://www.salmonllc.com/sofiaExamples/sitemap.dtd\">");
491: pw.println("<siteMap>");
492: Enumeration enum = getEntryNames();
493: while (enum.hasMoreElements()) {
494: String key = (String) enum.nextElement();
495: SiteMapEntry entry = (SiteMapEntry) _nameMap.get(key);
496: pw.println(" <entry>");
497:
498: pw.print(" <name>");
499: pw.print(entry.name);
500: pw.println("</name>");
501:
502: pw.print(" <uri>");
503: pw.print(entry.uri);
504: pw.println("</uri>");
505:
506: pw.print(" <useForward>");
507: pw.print(entry.useForward ? "true" : "false");
508: pw.println("</useForward>");
509:
510: pw.print(" <secure>");
511: pw.print(entry.secure ? "true" : "false");
512: pw.println("</secure>");
513:
514: if (entry.popupFeatures != null) {
515: pw.print(" <popupFeatures>");
516: pw.print(entry.popupFeatures);
517: pw.println("</popupFeatures>");
518: }
519:
520: String[] actions = getActionEntries(key);
521: for (int i = 0; i < actions.length; i++) {
522: pw.println(" <action>");
523: pw.print(" <actionName>");
524: pw.print(actions[i]);
525: pw.println("</actionName>");
526: pw.print(" <actionEntry>");
527: pw.print(getActionEntry(entry.name, actions[i]));
528: pw.println("</actionEntry>");
529: pw.println(" </action>");
530: }
531: if (entry.context != null) {
532: pw.print(" <context>");
533: pw.print(entry.context);
534: pw.println("</context>");
535: }
536: pw.println(" </entry>");
537: pw.println();
538: }
539: pw.println("</siteMap>");
540: pw.close();
541:
542: }
543:
544: /**
545: * Adds an action to a site map entry
546: * @param entryName The name of the entry to add the action for
547: * @param actionName The identifier for the action
548: * @param actionEntry Another site map entry that this action will invoke
549: */
550: public void addActionEntry(String entryName, String actionName,
551: String actionEntry) {
552: String key = entryName + "-+-" + actionName;
553: _actionMap.put(key, actionEntry);
554: String allEntries = (String) _actionMap.get(entryName);
555: if (allEntries == null)
556: allEntries = "";
557: String lookup = actionName + "|";
558: if (allEntries.indexOf(lookup) == -1) {
559: allEntries += lookup;
560: _actionMap.put(entryName, allEntries);
561: }
562: }
563:
564: /**
565: * Returns a string array of all the action names for an entry.
566: */
567: public String[] getActionEntries(String entryName) {
568: String val = (String) _actionMap.get(entryName);
569: if (val == null || val.length() == 0)
570: return new String[0];
571:
572: Vector v = new Vector();
573: StringTokenizer st = new StringTokenizer(val, "|", false);
574: while (st.hasMoreTokens()) {
575: String tok = st.nextToken();
576: if (tok.length() > 0)
577: v.add(tok);
578: }
579: String ret[] = new String[v.size()];
580: v.copyInto(ret);
581: return ret;
582: }
583:
584: /**
585: * Returns the site map entry associated with a particular action
586: * @param entryName The name of the site map entry
587: * @param actionName The name of the action for that particular entry
588: * @return the name of the entry or null if not found
589: */
590: public String getActionEntry(String entryName, String actionName) {
591: String key = entryName + "-+-" + actionName;
592: return (String) _actionMap.get(key);
593: }
594:
595: /**
596: * Generates a Java source code final class with constants for each sitemap entry
597: * @return
598: */
599: /**
600: * Generates a Java source code final class with constants for each sitemap entry
601: * @return
602: */
603: public String generateConstants(String className) {
604: StringBuffer sb = new StringBuffer();
605: String packageNm = "";
606: String actualClassName = "";
607: int pos = className.lastIndexOf(".");
608: if (pos == -1)
609: actualClassName = className;
610: else {
611: packageNm = "package " + className.substring(0, pos)
612: + ";\r\n\r\n";
613: actualClassName = className.substring(pos + 1);
614: }
615:
616: sb.append(packageNm);
617: sb.append("public final class ");
618: sb.append(actualClassName);
619: sb.append(" {\r\n\r\n");
620: for (int i = 0; i < _list.size(); i++) {
621: String name = (String) _list.elementAt(i);
622: sb.append(" public static final String ");
623:
624: char lastChar = '_';
625: for (int j = 0; j < name.length(); j++) {
626: char c = name.charAt(j);
627: if (Character.isLetterOrDigit(c)) {
628: if (Character.isUpperCase(c)) {
629: if (Character.isLetterOrDigit(lastChar)
630: && Character.isLowerCase(lastChar)) {
631: lastChar = '_';
632: sb.append('_');
633: }
634: }
635: sb.append(Character.toUpperCase(c));
636: lastChar = c;
637: } else {
638: sb.append('_');
639: lastChar = '_';
640: }
641: }
642:
643: sb.append(" = \"");
644: sb.append(name);
645: sb.append("\";\r\n");
646:
647: String st[] = getActionEntries(name);
648:
649: for (int j = 0; j < st.length; j++) {
650: sb.append(" public static final String ");
651: for (int k = 0; k < name.length(); k++) {
652: char c = name.charAt(k);
653: if (Character.isLetterOrDigit(c))
654: sb.append(Character.toUpperCase(c));
655: else
656: sb.append("_");
657: }
658: sb.append("_");
659: for (int k = 0; k < st[j].length(); k++) {
660: char c = st[j].charAt(k);
661: if (Character.isLetterOrDigit(c))
662: sb.append(Character.toUpperCase(c));
663: else
664: sb.append("_");
665: }
666: sb.append(" = \"");
667: sb.append(st[j]);
668: sb.append("\";\r\n");
669: }
670: }
671: sb.append("\r\n}");
672: return sb.toString();
673:
674: }
675:
676: private String parseURL(String url) {
677: int pos1 = url.indexOf("?");
678: int pos2 = url.indexOf("#");
679: if (pos1 != -1 || pos2 != -1) {
680: int pos = pos1;
681: if (pos1 == -1)
682: pos = pos2;
683: else if (pos2 == -1)
684: pos = pos1;
685: else if (pos2 > pos1)
686: pos = pos1;
687: else if (pos2 < pos1)
688: pos = pos2;
689: return url.substring(0, pos);
690: } else
691: return url;
692: }
693:
694: }
|