Added UrlBuilder class to handle building urls for site links

This commit is contained in:
rjy7 2010-05-27 14:20:59 +00:00
parent 916a7a5d62
commit 0e545d65c4
15 changed files with 231 additions and 172 deletions

View file

@ -235,7 +235,7 @@ public class ContactMailController extends FreeMarkerHttpServlet {
email.put("comments", comments);
email.put("ip", ipAddr);
if ( !(originalReferer == null || originalReferer.equals("none")) ) {
email.put("referrer", Routes.urlDecode(originalReferer));
email.put("referrer", UrlBuilder.urlDecode(originalReferer));
}
return mergeBodyToTemplate(template, email);

View file

@ -25,6 +25,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.Portal;
import edu.cornell.mannlib.vitro.webapp.controller.ContactMailServlet;
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Routes;
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
import edu.cornell.mannlib.vitro.webapp.view.fileList.ScriptList;
import edu.cornell.mannlib.vitro.webapp.view.fileList.StylesheetList;
@ -54,6 +55,7 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
protected Portal portal;
protected int portalId;
protected String appName;
protected UrlBuilder urlBuilder;
protected Map<String, Object> root = new HashMap<String, Object>();
public void doGet( HttpServletRequest request, HttpServletResponse response )
@ -94,6 +96,7 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
vreq = new VitroRequest(request);
this.response = response;
portal = vreq.getPortal();
urlBuilder = new UrlBuilder(portal);
// RY Can this be removed? Do templates need it? Ideally, they should not.
// Only needed for some weird stuff in search box that I think is only used in old default theme.
@ -169,29 +172,22 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
// view to control which links go where, and the link text and title.
Map<String, String> urls = new HashMap<String, String>();
urls.put("home", Routes.getHomeUrl(portal));
urls.put("home", urlBuilder.getHomeUrl());
String bannerImage = portal.getBannerImage();
if ( ! StringUtils.isEmpty(bannerImage)) {
root.put("bannerImage", Routes.getUrl(themeDir + "site_icons/" + bannerImage));
root.put("bannerImage", UrlBuilder.getUrl(themeDir + "site_icons/" + bannerImage));
}
Map<String, String> portalParam = new HashMap<String, String>();
portalParam.put("home", "" + portalId);
urls.put("about", Routes.getUrl(Routes.ABOUT, portalParam));
urls.put("about", urlBuilder.getPortalUrl(Routes.ABOUT));
if (ContactMailServlet.getSmtpHostFromProperties() != null) {
urls.put("contact", Routes.getUrl(Routes.CONTACT, portalParam));
urls.put("contact", urlBuilder.getPortalUrl(Routes.CONTACT));
}
urls.put("search", Routes.getUrl(Routes.SEARCH));
urls.put("termsOfUse", Routes.getUrl(Routes.TERMS_OF_USE, portalParam));
urls.put("login", Routes.getUrl(Routes.LOGIN));
Map<String, String> logoutParams = new HashMap<String, String>(portalParam);
logoutParams.put("loginSubmitMode", "Log Out");
urls.put("logout", Routes.getUrl(Routes.LOGOUT, logoutParams));
urls.put("siteAdmin", Routes.getUrl(Routes.SITE_ADMIN));
urls.put("search", urlBuilder.getPortalUrl(Routes.SEARCH));
urls.put("termsOfUse", urlBuilder.getPortalUrl(Routes.TERMS_OF_USE));
urls.put("login", urlBuilder.getPortalUrl(Routes.LOGIN));
urls.put("logout", urlBuilder.getLogoutUrl());
urls.put("siteAdmin", urlBuilder.getPortalUrl(Routes.LOGIN));
setSharedVariable("urls", urls);
}
@ -242,7 +238,7 @@ public class FreeMarkerHttpServlet extends VitroHttpServlet {
// attribute from the string passed in by the template automatically add the context path.
setSharedVariable("stylesheetDir", themeDir + "/css");
String themeDirWithContext = Routes.getUrl(themeDir);
String themeDirWithContext = UrlBuilder.getUrl(themeDir);
// This value is used only in stylesheets.ftl and already contains the context path.
root.put("stylesheetPath", themeDirWithContext + "/css");

View file

@ -53,7 +53,7 @@ public class FreeMarkerSetup implements ServletContextListener {
FreeMarkerHttpServlet.config = cfg;
FreeMarkerHttpServlet.context = sc;
Routes.contextPath = sc.getContextPath();
UrlBuilder.contextPath = sc.getContextPath();
}

View file

@ -1,89 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.Portal;
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
public class Routes {
private Routes() {
throw new AssertionError();
}
private static final Log log = LogFactory.getLog(Routes.class.getName());
protected static String contextPath = null;
protected static final String ABOUT = "/about";
protected static final String BROWSE = "/browse";
protected static final String CONTACT = "/contact";
protected static final String SEARCH = "/search";
protected static final String TERMS_OF_USE = "/termsOfUse";
// Put these under /admin/...
// Currently login and site admin are on the same page, but they don't have to be.
protected static final String LOGIN = "/siteAdmin";
protected static final String LOGOUT = "/login_process.jsp";
protected static final String SITE_ADMIN = "/siteAdmin";
// Public values are used by view objects
public static final String INDIVIDUAL = "/individual";
public static final String INDIVIDUAL_LIST = "/entitylist"; // "/entitylist"; "/individuallist";
public static String getHomeUrl(Portal portal) {
String rootBreadCrumbUrl = portal.getRootBreadCrumbURL();
return StringUtils.isEmpty(rootBreadCrumbUrl) ? contextPath : rootBreadCrumbUrl;
}
public static String getUrl(String path) {
if ( ! path.startsWith("/") ) {
path = "/" + path;
}
return contextPath + path;
}
public static String getUrl(String path, Map<String, String> params) {
String url = getUrl(path);
String glue = "?";
for (String key : params.keySet()) {
url += glue + key + "=" + urlEncode(params.get(key));
glue = "&";
}
return url;
}
public static String urlEncode(String url) {
String encoding = "ISO-8859-1";
String encodedUrl = null;
try {
encodedUrl = URLEncoder.encode(url, encoding);
} catch (UnsupportedEncodingException e) {
log.error("Error encoding url " + url + " with encoding " + encoding + ": Unsupported encoding.");
}
return encodedUrl;
}
public static String urlDecode(String url) {
String encoding = "ISO-8859-1";
String decodedUrl = null;
try {
decodedUrl = URLDecoder.decode(url, encoding);
} catch (UnsupportedEncodingException e) {
log.error("Error decoding url " + url + " with encoding " + encoding + ": Unsupported encoding.");
}
return decodedUrl;
}
}

View file

@ -0,0 +1,162 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.Portal;
import edu.cornell.mannlib.vitro.webapp.filters.PortalPickerFilter;
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
public class UrlBuilder {
private static final Log log = LogFactory.getLog(UrlBuilder.class.getName());
private Portal portal;
// This is static so that getUrl() can be static and refer to contextPath.
// getUrl() is static so that view objects can call it without
// having to instantiate an object and inject knowledge of the context path, which
// they don't have.
protected static String contextPath = null;
private static boolean isMultiPortal = PortalPickerFilter.isPortalPickingActive();
public enum Routes {
ABOUT("/about"),
BROWSE("/browse"),
CONTACT("/contact"),
INDIVIDUAL("/individual"),
INDIVIDUAL_LIST("/entitylist"), // "/individuallist"
SEARCH("/search"),
TERMS_OF_USE("/termsOfUse"),
// put under /admin
LOGIN("/siteAdmin"),
LOGOUT("/login_process.jsp"),
SITE_ADMIN("/siteAdmin");
private final String path;
Routes(String path) {
this.path = path;
}
public String path() {
return path;
}
public String url() {
return getUrl(path);
}
public String url(Params params) {
return getUrl(path, params);
}
public String toString() {
return path();
}
}
public UrlBuilder(Portal portal) {
this.portal = portal;
}
public String getHomeUrl() {
String rootBreadCrumbUrl = portal.getRootBreadCrumbURL();
return StringUtils.isEmpty(rootBreadCrumbUrl) ? contextPath : rootBreadCrumbUrl;
}
public String getLogoutUrl() {
return getPortalUrl(Routes.LOGOUT.url(), new Params("loginSubmitMode", "logout"));
}
public Params getPortalParam() {
return new Params("home", "" + portal.getPortalId());
}
public String getPortalUrl(String path) {
return isMultiPortal ? getUrl(path, getPortalParam()) : getUrl(path);
}
public String getPortalUrl(String path, Params params) {
if (isMultiPortal) {
params.putAll(getPortalParam());
}
return getUrl(path, params);
}
public String getPortalUrl(Routes route) {
return getPortalUrl(route.path());
}
public String getPortalUrl(Routes route, Params params) {
return getPortalUrl(route.path(), params);
}
public static class Params extends HashMap<String, String> {
private static final long serialVersionUID = 1L;
public Params() { }
public Params(String...strings) {
this();
int stringCount = strings.length;
for (int i = 0; i < stringCount; i=i+2) {
// Skip the last item if there's an odd number
if (i == stringCount-1) { break; }
this.put(strings[i], strings[i+1]);
}
}
}
/********** Static utility methods **********/
public static String getUrl(String path) {
if ( ! path.startsWith("/") ) {
path = "/" + path;
}
return contextPath + path;
}
public static String getUrl(String path, Params params) {
String url = getUrl(path);
String glue = "?";
for (String key : params.keySet()) {
url += glue + key + "=" + urlEncode(params.get(key));
glue = "&";
}
return url;
}
public static String urlEncode(String url) {
String encoding = "ISO-8859-1";
String encodedUrl = null;
try {
encodedUrl = URLEncoder.encode(url, encoding);
} catch (UnsupportedEncodingException e) {
log.error("Error encoding url " + url + " with encoding " + encoding + ": Unsupported encoding.");
}
return encodedUrl;
}
public static String urlDecode(String url) {
String encoding = "ISO-8859-1";
String decodedUrl = null;
try {
decodedUrl = URLDecoder.decode(url, encoding);
} catch (UnsupportedEncodingException e) {
log.error("Error decoding url " + url + " with encoding " + encoding + ": Unsupported encoding.");
}
return decodedUrl;
}
}

View file

@ -433,5 +433,9 @@ public class PortalPickerFilter implements Filter {
prefix2portalid = null;
filterConfig = null;
}
public static boolean isPortalPickingActive() {
return isPortalPickingActive;
}
}

View file

@ -6,14 +6,14 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.Routes;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Routes;
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
public class IndividualView extends ViewObject {
private static final Log log = LogFactory.getLog(IndividualView.class.getName());
private static final String URL = Routes.INDIVIDUAL;
private static final String PATH = Routes.INDIVIDUAL.path();
private Individual individual;

View file

@ -2,19 +2,17 @@
package edu.cornell.mannlib.vitro.webapp.view;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.Routes;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Params;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Routes;
public class VClassView extends ViewObject {
private static final Log log = LogFactory.getLog(VClassView.class.getName());
private static final String URL = Routes.INDIVIDUAL_LIST;
private static final String PATH = Routes.INDIVIDUAL_LIST.path();
private VClass vclass;
@ -27,9 +25,7 @@ public class VClassView extends ViewObject {
}
public String getUrl() {
Map<String, String> params = new HashMap<String, String>();
params.put("vclassId", vclass.getURI());
return getUrl(URL, params);
return getUrl(PATH, new Params("vclassId", vclass.getURI()));
}
public int getIndividualCount() {

View file

@ -2,35 +2,26 @@
package edu.cornell.mannlib.vitro.webapp.view;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.Routes;
// RY We may want an interface that the superclass would implement.
// RY Consider using FreeMarker's object wrappers instead.
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Params;
public abstract class ViewObject {
private static final Log log = LogFactory.getLog(ViewObject.class.getName());
// RY Can probably remove this, since we're using the FreeMarkerHttpServlet methods instead
// public static String contextPath;
protected String getUrl(String path) {
return Routes.getUrl(path);
// Wrap UrlBuilder method so templates can call ${item.url}
public String getUrl(String path) {
return UrlBuilder.getUrl(path);
}
protected String getUrl(String path, Map<String, String> params) {
return Routes.getUrl(path, params);
// Wrap UrlBuilder method so templates can call ${item.url}
public String getUrl(String path, Params params) {
return UrlBuilder.getUrl(path, params);
}
protected String urlEncode(String str) {
return Routes.urlEncode(str);
}
/*
* public static List<?> wrapList(List<?> list, Class cl)
* throw error if cl not a child of ViewObject

View file

@ -17,13 +17,23 @@ public class MainMenu extends Menu {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(MainMenu.class.getName());
public MainMenu(VitroRequest vreq, int portalId) {
super(vreq, portalId);
protected VitroRequest vreq;
public MainMenu(VitroRequest vreq) {
this.vreq = vreq;
}
public void addItem(String text, String path) {
boolean active = vreq.getServletPath().equals(path);
boolean active = isActiveItem(path);
MainMenuItem i = new MainMenuItem(text, path, active);
items.add(i);
}
}
// RY NEED TO FIX: doesn't work for Home and other generated tabs:
// vreq.getServletPath() = /templates/page/basicPage.jsp
// vreq.getRequestURL() = http://localhost:8080/vivo/templates/page/basicPage.jsp
// vreq.getRequestURI() = /vivo/templates/page/basicPage.jsp
private boolean isActiveItem(String path) {
return vreq.getServletPath().equals(path);
}
}

View file

@ -5,8 +5,6 @@ package edu.cornell.mannlib.vitro.webapp.view.menu;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
/** A menu item that indicates whether it is the active item or not.
*
* @author rjy7

View file

@ -16,13 +16,9 @@ public class Menu extends ViewObject {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(Menu.class.getName());
protected VitroRequest vreq;
protected int portalId;
protected List<MenuItem> items;
public Menu(VitroRequest vreq, int portalId) {
this.vreq = vreq;
this.portalId = portalId;
public Menu() {
items = new ArrayList<MenuItem>();
}

View file

@ -12,11 +12,11 @@ public class MenuItem extends ViewObject {
private static final Log log = LogFactory.getLog(MenuItem.class.getName());
private String text;
private String url;
private String path;
public MenuItem(String linkText, String path) {
text = linkText;
url = getUrl(path);
this.path = path;
}
public String getLinkText() {
@ -24,7 +24,6 @@ public class MenuItem extends ViewObject {
}
public String getUrl() {
return url;
}
return getUrl(path);
}
}

View file

@ -24,7 +24,7 @@ public class TabMenu extends MainMenu {
private static final Log log = LogFactory.getLog(TabMenu.class.getName());
public TabMenu(VitroRequest vreq, int portalId) {
super(vreq, portalId);
super(vreq);
//Tabs stored in database
List<Tab> primaryTabs = vreq.getWebappDaoFactory().getTabDao().getPrimaryTabs(portalId);

View file

@ -2,64 +2,60 @@
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.util.HashMap;
import java.util.Map;
import junit.framework.Assert;
import org.junit.Test;
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreeMarkerHttpServlet;
import freemarker.template.Configuration;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Params;
public class RoutesTest extends AbstractTestClass {
public class UrlBuilderTest extends AbstractTestClass {
@Test
public void testGetUrl() {
Routes.contextPath = "/vivo";
UrlBuilder.contextPath = "/vivo";
String path1 = "/individual";
Assert.assertEquals("/vivo/individual", Routes.getUrl(path1));
Assert.assertEquals("/vivo/individual", UrlBuilder.getUrl(path1));
int portalId = 1;
String path2 = "/individual?home=" + portalId;
Assert.assertEquals("/vivo/individual?home=1", Routes.getUrl(path2));
Assert.assertEquals("/vivo/individual?home=1", UrlBuilder.getUrl(path2));
}
@Test
public void testGetUrlWithEmptyContext() {
Routes.contextPath = "";
UrlBuilder.contextPath = "";
String path = "/individual";
Assert.assertEquals(path, Routes.getUrl(path));
Assert.assertEquals(path, UrlBuilder.getUrl(path));
}
@Test
public void testGetUrlWithParams() {
Routes.contextPath = "/vivo";
UrlBuilder.contextPath = "/vivo";
String path = "/individual";
Map<String, String> params = new HashMap<String, String>();
Params params = new Params();
int portalId = 1;
params.put("home", "" + portalId);
params.put("name", "Tom");
Assert.assertEquals("/vivo/individual?home=1&name=Tom", Routes.getUrl(path, params));
Assert.assertEquals("/vivo/individual?home=1&name=Tom", UrlBuilder.getUrl(path, params));
}
@Test
public void testEncodeUrl() {
Routes.contextPath = "/vivo";
UrlBuilder.contextPath = "/vivo";
String path = "/individuallist";
Map<String, String> params = new HashMap<String, String>();
Params params = new Params();
String vClassUri = "http://vivoweb.org/ontology/core#FacultyMember";
params.put("vclassId", vClassUri);
Assert.assertEquals("/vivo/individuallist?vclassId=http%3A%2F%2Fvivoweb.org%2Fontology%2Fcore%23FacultyMember", Routes.getUrl(path, params));
Assert.assertEquals("/vivo/individuallist?vclassId=http%3A%2F%2Fvivoweb.org%2Fontology%2Fcore%23FacultyMember", UrlBuilder.getUrl(path, params));
}
@Test
public void testDecodeUrl() {
String vClassUri = "http://vivoweb.org/ontology/core#FacultyMember";
String vClassUriEncoded = "http%3A%2F%2Fvivoweb.org%2Fontology%2Fcore%23FacultyMember";
Assert.assertEquals(vClassUri, Routes.urlDecode(vClassUriEncoded));
Assert.assertEquals(vClassUri, UrlBuilder.urlDecode(vClassUriEncoded));
}
}