Maven migration (first draft)

This commit is contained in:
Graham Triggs 2015-11-19 23:47:12 +00:00
parent 5e0329908c
commit e1ff94ccaf
2866 changed files with 1112 additions and 616 deletions

View file

@ -0,0 +1,62 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.beans;
import java.util.HashMap;
public class ButtonForm {
private String action = "";
private String label = "no label specified";
private String cssClass = null;
private HashMap<String,String> params = null;
public ButtonForm() {
action = ""; // submits to same page
cssClass = null;
label = "no label specified";
params = null;
}
public ButtonForm(String actionStr, String classStr, String labelStr, HashMap<String,String> paramMap) {
action = actionStr;
cssClass = classStr; // can be null
label = labelStr;
params = paramMap;
}
public String getAction(){
return action;
}
public void setAction(String s){
action = s;
}
public String getLabel(){
return label;
}
public void setLabel(String s){
label = s;
}
public String getCssClass(){
if (cssClass==null){
return "";
}
return "class=\""+cssClass+"\"";
}
public void setCssClass(String s){
cssClass=s;
}
public HashMap<String,String> getParams(){
return params;
}
public void setParams(HashMap<String,String> p){
params = p;
}
public void addParam(String key, String value){
if (params==null){
params = new HashMap<String,String>();
}
params.put(key, value);
}
}

View file

@ -0,0 +1,44 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.beans;
public class Checkbox {
private String name = null;
private String value = null;
private String body = null;
private boolean checked = false;
public String getName(){
return name;
}
private void setName(String name){
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public boolean getChecked (){
return checked;
}
public void setChecked (boolean checked){
this.checked = checked;
}
}

View file

@ -0,0 +1,98 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.beans;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
public class DynamicField {
private String name = null;
private String table = null;
private int maxCardinality = 1;
private int minCardinality = -1;
private int visible = -1;
private List<DynamicFieldRow> rowList = null;
private DynamicFieldRow rowTemplate = null;
private HashMap metadata = new HashMap();
private Boolean deleteable = true;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTable() {
return table;
}
public void setTable(String table) {
this.table = table;
}
public int getMaxCardinality() {
return maxCardinality;
}
public void setMaxCardinality (int maxCardinality) {
this.maxCardinality = maxCardinality;
}
public int getMinCardinality () {
return minCardinality;
}
public void setMinCardinality(int minCardinality) {
this.minCardinality = minCardinality;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public boolean getDeleteable() {
return deleteable;
}
public void setDeleteable(boolean deleteable) {
this.deleteable = deleteable;
}
public HashMap getMetadata() {
return metadata;
}
public void setMetadata(HashMap metadata) {
this.metadata = metadata;
}
public List<DynamicFieldRow> getRowList() {
return rowList;
}
public void setRowList (List<DynamicFieldRow> rowList) {
this.rowList = rowList;
}
public DynamicFieldRow getRowTemplate() {
return rowTemplate;
}
public void setRowTemplate(DynamicFieldRow dfr) {
rowTemplate = dfr;
}
}

View file

@ -0,0 +1,37 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.beans;
import java.util.Map;
public class DynamicFieldRow {
private int id = -1;
private String value = null;
private Map parameterMap = null;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Map getParameterMap() {
return parameterMap;
}
public void setParameterMap(Map parameterMap) {
this.parameterMap = parameterMap;
}
}

View file

@ -0,0 +1,323 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.beans;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpSession;
import edu.cornell.mannlib.vedit.forwarder.PageForwarder;
import edu.cornell.mannlib.vedit.listener.ChangeListener;
import edu.cornell.mannlib.vedit.listener.EditPreProcessor;
import edu.cornell.mannlib.vedit.validator.Validator;
public class EditProcessObject implements Serializable {
private String key = null;
private Class<?> beanClass = null;
private Class<?> implementationClass = null;
private boolean useRecycledBean = false;
private Object beanMask = null;
private List<Object[] /* Object[2] */> simpleMask = new LinkedList<Object[]>();
private Map<String, List<Validator>> validatorMap = new HashMap<String, List<Validator>>();
private Map<String, String> errMsgMap = new HashMap<String, String>();
private Map<String, String> defaultValueMap = new HashMap<String, String>();
private List<EditPreProcessor> preProcessorList = new LinkedList<EditPreProcessor>();
private List<ChangeListener> changeListenerList = new LinkedList<ChangeListener>();
private Object originalBean = null;
private Object newBean = null;
private String idFieldName = null;
private Class<?> idFieldClass = null;
private FormObject formObject = null;
private Object dataAccessObject = null;
private HashMap<String, Object /* DAO */> additionalDaoMap = new HashMap<String, Object>();
private Method insertMethod = null;
private Method updateMethod = null;
private Method deleteMethod = null;
private PageForwarder postInsertPageForwarder = null;
private PageForwarder postUpdatePageForwarder = null;
private PageForwarder postDeletePageForwarder = null;
private HttpSession session = null;
private String referer = null;
private String action = null;
private Map<String, String[]> requestParameterMap = null;
private Map<String, String> badValueMap = new HashMap<String, String>();
private Map<String,Object> attributeMap = new HashMap<String, Object>();
private Method getMethod = null;
//assumed to take an integer primary key argument, at least for now
public String getKey(){
return key;
}
public void setKey(String key){
this.key = key;
}
public Class<?> getBeanClass(){
return beanClass;
}
public void setBeanClass(Class<?> beanClass){
this.beanClass = beanClass;
}
public Class<?> getImplementationClass(){
return implementationClass;
}
public void setImplementationClass(Class<?> implementationClass){
this.implementationClass = implementationClass;
}
public Object getBeanMask() {
return beanMask;
}
public void setBeanMask(Object beanMask) {
this.beanMask = beanMask;
}
public List<Object[]> getSimpleMask(){
return simpleMask;
}
public void setSimpleMask(List<Object[]> simpleMask){
this.simpleMask = simpleMask;
}
public List<ChangeListener> getChangeListenerList() {
return changeListenerList;
}
public void setChangeListenerList(List<? extends ChangeListener> changeListenerList) {
this.changeListenerList = new ArrayList<ChangeListener>(changeListenerList);
}
public List<EditPreProcessor> getPreProcessorList() {
return preProcessorList;
}
public void setPreProcessorList(List<? extends EditPreProcessor> preProcessorList) {
this.preProcessorList = new ArrayList<EditPreProcessor>(preProcessorList);
}
public Object getOriginalBean(){
return originalBean;
}
public void setOriginalBean(Object originalBean){
this.originalBean = originalBean;
}
public Object getNewBean(){
return newBean;
}
public void setNewBean(Object newBean){
this.newBean = newBean;
}
public String getIdFieldName() {
return idFieldName;
}
public void setIdFieldName(String ifn) {
this.idFieldName = ifn;
}
public Class<?> getIdFieldClass() {
return idFieldClass;
}
public void setIdFieldClass(Class<?> cls) {
this.idFieldClass = cls;
}
public FormObject getFormObject() {
return formObject;
}
public void setFormObject(FormObject foo){
formObject=foo;
}
public HttpSession getSession(){
return session;
}
public boolean getUseRecycledBean(){
return useRecycledBean;
}
public void setUseRecycledBean(boolean useRecycledBean){
this.useRecycledBean = useRecycledBean;
}
public void setSession(HttpSession session){
this.session = session;
}
public String getReferer(){
return referer;
}
public void setReferer(String referer){
this.referer = referer;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public Map<String, String[]> getRequestParameterMap() {
return requestParameterMap;
}
public void setRequestParameterMap (Map<String, String[]> rpmap) {
requestParameterMap = rpmap;
}
public PageForwarder getPostInsertPageForwarder(){
return postInsertPageForwarder;
}
public void setPostInsertPageForwarder(PageForwarder pipf){
postInsertPageForwarder = pipf;
}
public PageForwarder getPostUpdatePageForwarder(){
return postUpdatePageForwarder;
}
public void setPostUpdatePageForwarder(PageForwarder pupf){
postUpdatePageForwarder = pupf;
}
public PageForwarder getPostDeletePageForwarder(){
return postDeletePageForwarder;
}
public void setPostDeletePageForwarder(PageForwarder pdpf){
postDeletePageForwarder = pdpf;
}
public Object getDataAccessObject() {
return dataAccessObject;
}
public void setDataAccessObject(Object dao) {
dataAccessObject = dao;
}
public HashMap<String, Object> getAdditionalDaoMap() {
return additionalDaoMap;
}
public void setAdditionalDaoMap(HashMap<String, Object> adm) {
additionalDaoMap = adm;
}
public Method getInsertMethod(){
return insertMethod;
}
public void setInsertMethod(Method insertMethod){
this.insertMethod = insertMethod;
}
public Method getUpdateMethod(){
return updateMethod;
}
public void setUpdateMethod(Method updateMethod){
this.updateMethod = updateMethod;
}
public Method getDeleteMethod(){
return deleteMethod;
}
public void setDeleteMethod(Method deleteMethod){
this.deleteMethod = deleteMethod;
}
public Method getGetMethod(){
return getMethod;
}
public void setGetMethod(Method getMethod){
this.getMethod = getMethod;
}
public Map<String, String> getDefaultValueMap() {
return defaultValueMap;
}
public void setDefaultValueMap(Map<String, String> dvh) {
this.defaultValueMap = dvh;
}
public Map<String, List<Validator>> getValidatorMap(){
return validatorMap;
}
public void setValidatorMap(Map<String, List<Validator>> validatorMap){
this.validatorMap = validatorMap;
}
public Map<String, String> getErrMsgMap() {
return errMsgMap;
}
public void setErrMsgMap(Map<String, String> emh){
errMsgMap = emh;
}
public Map<String, String> getBadValueMap() {
return badValueMap;
}
public void setBadValueMap(Map<String, String> bvh){
badValueMap = bvh;
}
public Map<String, Object> getAttributeMap() {
return this.attributeMap;
}
public Object getAttribute(String key) {
return this.attributeMap.get(key);
}
public void setAttribute(String key, Object value) {
this.attributeMap.put(key, value);
}
}

View file

@ -0,0 +1,54 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.beans;
public class FieldHelp {
private String description = null;
private String descriptionUri = null;
private String examples = null;
private String examplesUri = null;
private String helpUri = null;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getDescriptionUri() {
return descriptionUri;
}
public void setDescriptionUri(String descriptionUri) {
this.descriptionUri = descriptionUri;
}
public String getExamples() {
return examples;
}
public void setExamples(String examples) {
this.examples = examples;
}
public String getExamplesUri() {
return examplesUri;
}
public void setExamplesUri(String examplesUri) {
this.examplesUri = examplesUri;
}
public String getHelpUri() {
return helpUri;
}
public void setHelpUri(String helpUri) {
this.helpUri = helpUri;
}
}

View file

@ -0,0 +1,63 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.beans;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FormObject implements Serializable {
private HashMap<String, String> values = new HashMap<String, String>();
private HashMap<String, List<Option>> optionLists = new HashMap<String, List<Option>>();
private HashMap<String, List<Checkbox>> checkboxLists = new HashMap<String, List<Checkbox>>();
private Map<String, String> errorMap = new HashMap<String, String>();
private List<DynamicField> dynamicFields = new ArrayList<DynamicField>();
public HashMap<String, String> getValues(){
return values;
}
public void setValues(HashMap<String, String> values){
this.values = values;
}
public String valueByName(String name){
return values.get(name);
}
public HashMap<String, List<Option>> getOptionLists() {
return optionLists;
}
public void setOptionLists(HashMap<String, List<Option>> optionLists) {
this.optionLists = optionLists;
}
public List<Option> optionListByName(String key){
return optionLists.get(key);
}
public HashMap<String, List<Checkbox>> getCheckboxLists(){
return checkboxLists;
}
public Map<String, String> getErrorMap(){
return errorMap;
}
public void setErrorMap(Map<String, String> errorMap){
this.errorMap = errorMap;
}
public List<DynamicField> getDynamicFields() {
return dynamicFields;
}
public void setDynamicFields(List<DynamicField> dynamicFields){
this.dynamicFields = dynamicFields;
}
}

View file

@ -0,0 +1,155 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.beans;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
/**
* An immutable object that records the user's login info as a session
* attribute.
*/
public class LoginStatusBean {
private static final Log log = LogFactory.getLog(LoginStatusBean.class);
/** A bean to return when the user has not logged in. */
private static final LoginStatusBean DUMMY_BEAN = new LoginStatusBean("",
AuthenticationSource.UNKNOWN);
/** The bean is attached to the session by this name. */
private static final String ATTRIBUTE_NAME = "loginStatus";
// ----------------------------------------------------------------------
// static methods
// ----------------------------------------------------------------------
/**
* Attach this bean to the session - this means you are logged in.
*/
public static void setBean(HttpSession session, LoginStatusBean lsb) {
session.setAttribute(ATTRIBUTE_NAME, lsb);
}
/**
* Get the bean from this request, or a dummy bean if the user is not logged
* in. Never returns null.
*/
public static LoginStatusBean getBean(HttpServletRequest request) {
if (request == null) {
return DUMMY_BEAN;
}
HttpSession session = request.getSession(false);
if (session == null) {
return DUMMY_BEAN;
}
return getBean(session);
}
/**
* Get the bean from this session, or a dummy bean if the user is not logged
* in. Never returns null.
*/
public static LoginStatusBean getBean(HttpSession session) {
if (session == null) {
return DUMMY_BEAN;
}
Object o = session.getAttribute(ATTRIBUTE_NAME);
if (o == null) {
return DUMMY_BEAN;
}
if (!(o instanceof LoginStatusBean)) {
log.warn("Tried to get login status bean, but found an instance of "
+ o.getClass().getName() + ": " + o);
return DUMMY_BEAN;
}
return (LoginStatusBean) o;
}
/**
* Get the current user, or null if not logged in.
*/
public static UserAccount getCurrentUser(HttpServletRequest request) {
if (request == null) {
return null;
}
return getCurrentUser(request.getSession(false));
}
/**
* Get the current user, or null if not logged in.
*/
public static UserAccount getCurrentUser(HttpSession session) {
if (session == null) {
return null;
}
if (!getBean(session).isLoggedIn()) {
return null;
}
ServletContext ctx = session.getServletContext();
WebappDaoFactory wadf = ModelAccess.on(ctx).getWebappDaoFactory();
UserAccountsDao userAccountsDao = wadf.getUserAccountsDao();
if (userAccountsDao == null) {
log.error("No UserAccountsDao");
return null;
}
String userUri = getBean(session).getUserURI();
return userAccountsDao.getUserAccountByUri(userUri);
}
// ----------------------------------------------------------------------
// the bean
// ----------------------------------------------------------------------
public enum AuthenticationSource {
UNKNOWN, INTERNAL, EXTERNAL
}
private final String userURI;
private final AuthenticationSource authenticationSource;
public LoginStatusBean(String userURI,
AuthenticationSource authenticationSource) {
this.userURI = userURI;
this.authenticationSource = authenticationSource;
}
public String getUserURI() {
return userURI;
}
public AuthenticationSource getAuthenticationSource() {
return authenticationSource;
}
public boolean isLoggedIn() {
return authenticationSource != AuthenticationSource.UNKNOWN;
}
public boolean hasExternalAuthentication() {
return authenticationSource == AuthenticationSource.EXTERNAL;
}
@Override
public String toString() {
return "LoginStatusBean[userURI=" + userURI + ", authenticationSource="
+ authenticationSource + "]";
}
}

View file

@ -0,0 +1,59 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.beans;
import java.io.Serializable;
public class Option implements Serializable {
private String value = null;
private String body = null;
private boolean selected = false;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public boolean getSelected (){
return selected;
}
public void setSelected (boolean selected){
this.selected = selected;
}
//default constructor
public Option() {
}
public Option (String value, String body, boolean selected) {
this.value = value;
this.body = body;
this.selected = selected;
}
// construct an Option with body and value
public Option(String value, String body) {
this(value, body, false);
}
// construct an Option with equal body and value
public Option (String name){
this(name, name, false);
}
}

View file

@ -0,0 +1,210 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.controller;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.ReasoningOption.ASSERTIONS_ONLY;
import java.text.Collator;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vedit.beans.EditProcessObject;
import edu.cornell.mannlib.vedit.beans.Option;
import edu.cornell.mannlib.vedit.util.FormUtils;
import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.ReasoningOption;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
public class BaseEditController extends VitroHttpServlet {
public static final boolean FORCE_NEW = true; // when you know you're starting a new edit process
public static final String JSP_PREFIX = "/templates/edit/specific/";
protected static DateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy");
protected static final int BASE_10 = 10;
private static final Log log = LogFactory.getLog(BaseEditController.class.getName());
private static final String DEFAULT_LANDING_PAGE = Controllers.SITE_ADMIN;
protected static final String MULTIPLEXED_PARAMETER_NAME = "multiplexedParam";
private final String EPO_HASH_ATTR = "epoHash";
private final String EPO_KEYLIST_ATTR = "epoKeylist";
private final int MAX_EPOS = 5;
private final Calendar cal = Calendar.getInstance();
/* EPO is reused if the controller is passed an epoKey, e.g.
if a previous form submission failed validation, or the edit is a multistage process. */
protected EditProcessObject createEpo(HttpServletRequest request) {
return createEpo(request, false);
}
protected EditProcessObject createEpo(HttpServletRequest request, boolean forceNew) {
/* this is actually a bit of a misnomer, because we will reuse an epo
if an epoKey parameter is passed */
EditProcessObject epo = null;
HashMap epoHash = getEpoHash(request);
String existingEpoKey = request.getParameter("_epoKey");
if (!forceNew && existingEpoKey != null && epoHash.get(existingEpoKey) != null) {
epo = (EditProcessObject) epoHash.get(existingEpoKey);
epo.setKey(existingEpoKey);
epo.setUseRecycledBean(true);
} else {
LinkedList epoKeylist = getEpoKeylist(request);
if (epoHash.size() == MAX_EPOS) {
try {
epoHash.remove(epoKeylist.getFirst());
epoKeylist.removeFirst();
} catch (Exception e) {
// see JIRA issue VITRO-340, "Odd exception from backend editing"
// possible rare concurrency issue here
log.error("Error removing old EPO", e);
}
}
Random rand = new Random();
String epoKey = createEpoKey();
while (epoHash.get(epoKey) != null) {
epoKey+=Integer.toHexString(rand.nextInt());
}
epo = new EditProcessObject();
epoHash.put (epoKey,epo);
epoKeylist.add(epoKey);
epo.setKey(epoKey);
epo.setReferer( (forceNew) ? request.getRequestURL().append('?').append(request.getQueryString()).toString() : request.getHeader("Referer") );
epo.setSession(request.getSession());
}
return epo;
}
private LinkedList getEpoKeylist(HttpServletRequest request){
return (LinkedList) request.getSession().getAttribute(EPO_KEYLIST_ATTR);
}
private HashMap getEpoHash(HttpServletRequest request){
HashMap epoHash = (HashMap) request.getSession().getAttribute(EPO_HASH_ATTR);
if (epoHash == null) {
epoHash = new HashMap();
request.getSession().setAttribute(EPO_HASH_ATTR,epoHash);
//since we're making a new EPO hash, we should also make a new keylist.
LinkedList epoKeylist = new LinkedList();
request.getSession().setAttribute(EPO_KEYLIST_ATTR,epoKeylist);
}
return epoHash;
}
private String createEpoKey(){
return Long.toHexString(cal.getTimeInMillis());
}
protected void setRequestAttributes(HttpServletRequest request, EditProcessObject epo){
VitroRequest vreq = new VitroRequest(request);
request.setAttribute("epoKey",epo.getKey());
request.setAttribute("epo",epo);
request.setAttribute("globalErrorMsg",epo.getAttribute("globalErrorMsg"));
request.setAttribute("css", "<link rel=\"stylesheet\" type=\"text/css\" href=\""+vreq.getAppBean().getThemeDir()+"css/edit.css\"/>");
}
protected void populateBeanFromParams(Object bean, HttpServletRequest request) {
Map params = request.getParameterMap();
Enumeration paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()){
String key = "";
try {
key = (String) paramNames.nextElement();
} catch (ClassCastException cce) {
log.error("populateBeanFromParams() could not cast parameter name to String");
}
String value = "";
if (key.equals(MULTIPLEXED_PARAMETER_NAME)) {
String multiplexedStr = request.getParameterValues(key)[0];
Map paramMap = FormUtils.beanParamMapFromString(multiplexedStr);
Iterator paramIt = paramMap.keySet().iterator();
while (paramIt.hasNext()) {
String param = (String) paramIt.next();
String demultiplexedValue = (String) paramMap.get(param);
FormUtils.beanSet(bean, param, demultiplexedValue);
}
} else {
try {
value = (String) request.getParameterValues(key)[0];
} catch (ClassCastException cce) {
try {
value = ((Integer) params.get(key)).toString();
} catch (ClassCastException ccf) {
log.error("populateBeanFromParams() could not cast parameter name to String");
}
}
FormUtils.beanSet(bean, key, value);
}
}
}
public List<Option> getSortedList(HashMap<String,Option> hashMap, List<Option> optionList, VitroRequest vreq){
class ListComparator implements Comparator<String>{
Collator collator;
public ListComparator(Collator collator) {
this.collator = collator;
}
@Override
public int compare(String str1, String str2) {
return collator.compare(str1, str2);
}
}
List<String> bodyVal = new ArrayList<String>();
List<Option> options = new ArrayList<Option>();
Iterator<Option> itr = optionList.iterator();
while(itr.hasNext()){
Option option = itr.next();
hashMap.put(option.getBody(),option);
bodyVal.add(option.getBody());
}
Collections.sort(bodyVal, new ListComparator(vreq.getCollator()));
ListIterator<String> itrStr = bodyVal.listIterator();
while(itrStr.hasNext()){
options.add(hashMap.get(itrStr.next()));
}
return options;
}
protected WebappDaoFactory getWebappDaoFactory() {
return ModelAccess.on(getServletContext()).getWebappDaoFactory(ASSERTIONS_ONLY);
}
protected WebappDaoFactory getWebappDaoFactory(String userURI) {
return getWebappDaoFactory().getUserAwareDaoFactory(userURI);
}
public String getDefaultLandingPage(HttpServletRequest request) {
return(request.getContextPath() + DEFAULT_LANDING_PAGE);
}
}

View file

@ -0,0 +1,87 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.controller;
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.io.IOException;
/**
* This controller exists only so we can request different edit form controllers
* without having to have entries in web.xml for each.
* @author bjl23
*
*/
public class EditFrontController extends VitroHttpServlet {
private static final Log log = LogFactory.getLog(EditFrontController.class.getName());
private static final String CONTROLLER_PKG = "edu.cornell.mannlib.vitro.webapp.controller.edit";
public void doPost(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
String controllerName = request.getParameter("controller")+"RetryController";
if (controllerName==null || controllerName.length()==0) {
log.error("doPost() found no controller parameter");
}
Class controller = null;
Object controllerInstance = null;
try {
controller = Class.forName(CONTROLLER_PKG+"."+controllerName);
try {
controllerInstance = controller.getConstructor(
(Class[]) null).newInstance((Object[]) null);
((HttpServlet)controllerInstance).init(getServletConfig());
} catch (Exception e) {
String errMsg = "doPost() could not instantiate specific " +
"controller " + controllerName;
log.error(errMsg, e);
throw new RuntimeException(errMsg, e);
}
} catch (ClassNotFoundException e){
String errMsg = "doPost() could not find controller " +
CONTROLLER_PKG + "." + controllerName;
log.error(errMsg);
throw new RuntimeException(errMsg);
}
Class[] args = new Class[2];
args[0] = HttpServletRequest.class;
args[1] = HttpServletResponse.class;
try {
Method meth = controller.getDeclaredMethod("doGet",args);
Object[] methArgs = new Object[2];
methArgs[0] = request;
methArgs[1] = response;
try {
meth.invoke(controllerInstance,methArgs);
} catch (IllegalAccessException e) {
String errMsg = "doPost() encountered IllegalAccessException " +
"while invoking " + controllerName;
log.error(errMsg, e);
throw new RuntimeException(errMsg, e);
} catch (InvocationTargetException e) {
String errMsg = "doPost() encountered InvocationTargetException " +
"while invoking " + controllerName;
log.error(errMsg, e);
throw new RuntimeException(errMsg, e);
}
} catch (NoSuchMethodException e){
log.error("could not find doPost() method in " + controllerName);
throw new RuntimeException("could not find doPost() method in " +
controllerName);
}
}
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
doPost(request,response);
}
}

View file

@ -0,0 +1,511 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.controller;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vedit.beans.EditProcessObject;
import edu.cornell.mannlib.vedit.forwarder.PageForwarder;
import edu.cornell.mannlib.vedit.listener.ChangeListener;
import edu.cornell.mannlib.vedit.listener.EditPreProcessor;
import edu.cornell.mannlib.vedit.util.FormUtils;
import edu.cornell.mannlib.vedit.util.FormUtils.NegativeIntegerException;
import edu.cornell.mannlib.vedit.util.OperationUtils;
import edu.cornell.mannlib.vedit.validator.ValidationObject;
import edu.cornell.mannlib.vedit.validator.Validator;
public class OperationController extends BaseEditController {
private static final Log log = LogFactory.getLog(OperationController.class.getName());
public void doPost (HttpServletRequest request, HttpServletResponse response) {
String defaultLandingPage = getDefaultLandingPage(request);
// get the Edit Process Object which will tell us wh
HashMap epoHash = null;
EditProcessObject epo = null;
try {
epoHash = (HashMap) request.getSession().getAttribute("epoHash");
epo = (EditProcessObject) epoHash.get(request.getParameter("_epoKey"));
} catch (NullPointerException e) {
//session or edit process expired
try {
response.sendRedirect(defaultLandingPage);
} catch (IOException ioe) {
log.error(this.getClass().getName() + " IOError on redirect: ", ioe);
}
return;
}
if (epo == null) {
try {
response.sendRedirect(defaultLandingPage);
} catch (IOException ioe) {
log.error(this.getClass().getName() + " IOError on redirect: ", ioe);
}
return;
}
// if we're canceling, we don't need to do anything
if (request.getParameter("_cancel") != null){
String referer = epo.getReferer();
if (referer == null) {
try {
response.sendRedirect(defaultLandingPage);
} catch (IOException ioe) {
log.error(this.getClass().getName() + " IOError on redirect: ", ioe);
}
return;
}
else {
try {
response.sendRedirect(referer);
} catch (IOException ioe) {
log.error(this.getClass().getName() + " IOError on redirect: ", ioe);
}
return;
}
}
// reset - if reset button is of type submit
if (request.getParameter("_reset") != null) {
try {
response.sendRedirect(request.getHeader("Referer"));
} catch (IOException ioe) {
log.error(this.getClass().getName() + " IOError on redirect: ", ioe);
}
return;
}
try {
Object newObj = getNewObj(epo);
//populate this object from the req. params
boolean valid = populateObjectFromRequestParamsAndValidate(epo, newObj, request);
//run preprocessors
runPreprocessors(epo, newObj);
//applySimpleMask(epo, newObj);
//put the newObj back in the epo where other things can look at it
epo.setNewBean(newObj);
//if validation failed, go back to the form controller
if (!valid){
epo.setAttribute("globalErrorMsg", "Please correct errors highlighted below.");
retry(request, response, epo);
return;
}
String action = getAction(request);
boolean status = performEdit(epo, newObj, action);
if (status == FAILURE) {
retry(request, response, epo);
return;
}
/* put request parameters and attributes into epo where the listeners can see */
epo.setRequestParameterMap(request.getParameterMap());
notifyChangeListeners(epo, action);
/* send the user somewhere */
if (action.equals("insert")){
// Object[] args = new Object[1];
// args[0] = result;
// epo.setNewBean(epo.getGetMethod().invoke(facade,args));
PageForwarder pipf = epo.getPostInsertPageForwarder();
if (pipf != null){
pipf.doForward(request,response,epo);
return;
}
} else if (action.equals("update")){
PageForwarder pupf = epo.getPostUpdatePageForwarder();
if (pupf != null) {
pupf.doForward(request,response,epo);
return;
}
} else if (action.equals("delete")){
PageForwarder pdpf = epo.getPostDeletePageForwarder();
if (pdpf != null) {
pdpf.doForward(request,response,epo);
return;
}
}
//if no page forwarder was set, just go back to referring page:
String referer = epo.getReferer();
if (referer == null)
response.sendRedirect(defaultLandingPage);
else
response.sendRedirect(referer);
} catch (Exception e) {
log.error("Error performing edit", e);
String errMsg = (e.getMessage() != null)
? e.getMessage()
: "Error performing edit";
epo.setAttribute("globalErrorMsg", errMsg);
try {
retry(request, response, epo);
return;
} catch (IOException ioe) {
log.error(this.getClass().getName() + " IOError on redirect: ", ioe);
}
}
}
private void retry(HttpServletRequest request,
HttpServletResponse response,
EditProcessObject epo) throws IOException {
String referer = request.getHeader("Referer");
referer = (referer == null) ? epo.getReferer() : referer;
if( referer != null ){
int epoKeyIndex = referer.indexOf("_epoKey");
if (epoKeyIndex >= 0){
String url = referer.substring(0,epoKeyIndex) + "_epoKey=" +
request.getParameter("_epoKey");
response.sendRedirect(url);
return;
}
String redirectUrl = (referer.indexOf("?") > -1)
? referer + "&"
: referer + "?";
redirectUrl += "_epoKey="+request.getParameter("_epoKey");
response.sendRedirect(redirectUrl);
} else {
response.sendRedirect(getDefaultLandingPage(request));
}
return;
}
private void runPreprocessors(EditProcessObject epo, Object newObj) {
if (epo.getPreProcessorList() != null && epo.getPreProcessorList().size()>0) {
Iterator preIt = epo.getPreProcessorList().iterator();
while (preIt.hasNext()) {
try {
EditPreProcessor epp = (EditPreProcessor) preIt.next();
epp.process(newObj, epo);
} catch (ClassCastException e) {}
}
}
}
private Object getNewObj(EditProcessObject epo) {
Object newObj = null;
if (epo.getOriginalBean() != null) { // we're updating or deleting an existing bean
if (epo.getImplementationClass() != null) {
newObj = OperationUtils.cloneBean(
epo.getOriginalBean(),
epo.getImplementationClass(),
epo.getBeanClass());
} else {
newObj = OperationUtils.cloneBean(epo.getOriginalBean());
}
} else {
Class cls = epo.getBeanClass();
try {
newObj = cls.newInstance();
} catch (IllegalAccessException iae) {
throw new RuntimeException("Illegal access - see error logs.");
} catch (InstantiationException ie) {
throw new RuntimeException("Unable to instantiate " + cls.getSimpleName());
}
}
epo.setNewBean(newObj); // is this dangerous?
return newObj;
}
private boolean populateObjectFromRequestParamsAndValidate(EditProcessObject epo, Object newObj, HttpServletRequest request) {
boolean valid = true;
String currParam="";
Enumeration penum = request.getParameterNames();
while (penum.hasMoreElements()){
currParam = (String) penum.nextElement();
if (!(currParam.indexOf("_")==0)){
String currValue = request.getParameterValues(currParam)[0];
// "altnew" values come in with the same input name but at position 1 of the array
if(currValue.length()==0 && request.getParameterValues(currParam).length>1) {
currValue = request.getParameterValues(currParam)[1];
}
//validate the entry
boolean fieldValid = true;
if ( request.getParameter("_delete") == null ) { // don't do validation if we're deleting
List validatorList = (List) epo.getValidatorMap().get(currParam);
if (validatorList != null) {
Iterator valIt = validatorList.iterator();
String errMsg = "";
while (valIt.hasNext()){
Validator val = (Validator)valIt.next();
ValidationObject vo = val.validate(currValue);
if (!vo.getValid()){
valid = false;
fieldValid = false;
errMsg += vo.getMessage() + " ";
epo.getBadValueMap().put(currParam,currValue);
} else {
try {
epo.getBadValueMap().remove(currParam);
epo.getErrMsgMap().remove(currParam);
} catch (Exception e) {}
}
}
if (errMsg.length()>0) {
epo.getErrMsgMap().put(currParam,errMsg);
log.info("doPost() putting error message "+errMsg+" for "+currParam);
}
}
}
if (fieldValid){
if (currValue.length()==0) {
Map<String, String> defaultHash = epo.getDefaultValueMap();
try {
String defaultValue = defaultHash.get(currParam);
if (defaultValue != null)
currValue=defaultValue;
} catch (Exception e) {}
}
try {
FormUtils.beanSet(newObj,currParam,currValue,epo);
epo.getErrMsgMap().remove(currParam);
epo.getBadValueMap().remove(currParam);
} catch (NumberFormatException e) {
if (currValue.length()>0) {
valid = false;
epo.getErrMsgMap().put(currParam,"Please enter an integer");
epo.getBadValueMap().put(currParam,currValue);
}
} catch (NegativeIntegerException nie) {
valid = false;
epo.getErrMsgMap().put(currParam,"Please enter a positive integer");
epo.getBadValueMap().put(currParam,currValue);
} catch (IllegalArgumentException f) {
valid=false;
log.error("doPost() reports IllegalArgumentException for "+currParam);
log.debug("doPost() error message: "+f.getMessage());
epo.getErrMsgMap().put(currParam, f.getMessage());
epo.getBadValueMap().put(currParam,currValue);
}
}
}
}
return valid;
}
private String getAction(HttpServletRequest request) {
if (request.getParameter("_update") != null ) {
return "update";
} else if (request.getParameter("_delete") != null ) {
return "delete";
} else {
return "insert";
}
}
private void notifyChangeListeners(EditProcessObject epo, String action) {
List<ChangeListener> changeListeners = epo.getChangeListenerList();
if (changeListeners != null){
Iterator<ChangeListener> changeIt = changeListeners.iterator();
while (changeIt.hasNext()) {
ChangeListener cl = changeIt.next();
if (action.equals("insert"))
cl.doInserted(epo.getNewBean(),epo);
else if (action.equals("update"))
cl.doUpdated(epo.getOriginalBean(),epo.getNewBean(),epo);
else if (action.equals("delete"))
cl.doDeleted(epo.getOriginalBean(),epo);
}
}
}
private boolean SUCCESS = false;
private boolean FAILURE = !SUCCESS;
private boolean performEdit(EditProcessObject epo, Object newObj, String action) {
/* do the actual edit operation */
String partialClassName;
if (epo.getBeanClass() != null) {
partialClassName = epo.getBeanClass().getSimpleName();
} else {
partialClassName = epo.getNewBean().getClass().getSimpleName();
}
Object dataAccessObject = null;
if (epo.getDataAccessObject() != null) {
dataAccessObject = epo.getDataAccessObject();
} else {
throw new RuntimeException(OperationController.class.getName()+" needs to be passed an EPO containing a data access object with which to perform the desired operation");
}
Class[] classList = new Class[1];
classList[0] = (epo.getBeanClass() != null) ? epo.getBeanClass() : newObj.getClass();
newObj.getClass().getGenericSuperclass();
Class[] superClassList = new Class[1];
superClassList[0] = newObj.getClass().getSuperclass();
Method meth=null;
Method deleteMeth=null;
Method insertMeth=null;
// probably want to change this so it will walk up the class tree indefinitely looking for a good method to use
if ("update".equals(action)){
if (epo.getUpdateMethod() != null) {
meth = epo.getUpdateMethod();
} else {
try {
meth = dataAccessObject.getClass().getMethod("update"+partialClassName,classList);
} catch (NoSuchMethodException e) {
try {
meth = dataAccessObject.getClass().getMethod("update"+partialClassName,superClassList);
} catch (NoSuchMethodException f) {
try { // if there isn't a single update method, let's see if we can delete the old data and then insert the new
deleteMeth = dataAccessObject.getClass().getMethod("delete"+partialClassName,classList);
try {
insertMeth = dataAccessObject.getClass().getMethod("insert"+partialClassName,classList);
} catch (NoSuchMethodException ee) {
insertMeth = dataAccessObject.getClass().getMethod("insertNew"+partialClassName,classList);
}
} catch (NoSuchMethodException g) {
log.error("doPost() could not find method(s) for updating "+partialClassName);
}
}
}
}
} else if ("delete".equals(action)) {
if (epo.getDeleteMethod() != null) {
meth = epo.getDeleteMethod();
} else {
try {
meth = dataAccessObject.getClass().getMethod("delete"+partialClassName,classList);
} catch (NoSuchMethodException e) {
try {
meth = dataAccessObject.getClass().getMethod("delete"+partialClassName,superClassList);
} catch (NoSuchMethodException f) {
log.error("doPost() could not find method delete"+partialClassName+"() on "+dataAccessObject.getClass().getName());
}
}
}
} else {
if (epo.getInsertMethod() != null) {
meth = epo.getInsertMethod();
} else {
try {
meth = dataAccessObject.getClass().getMethod("insert"+partialClassName,classList);
} catch (NoSuchMethodException e) {
try {
meth = dataAccessObject.getClass().getMethod("insertNew"+partialClassName,classList);
} catch (NoSuchMethodException f) {
try {
meth = dataAccessObject.getClass().getMethod("insertNew"+partialClassName,superClassList);
} catch (NoSuchMethodException g) {
try {
meth = dataAccessObject.getClass().getMethod("insertNew"+partialClassName,superClassList);
} catch (NoSuchMethodException h) {
log.error("doPost() could not find method for inserting "+partialClassName);
}
}
}
}
}
}
Object[] insArgList = new Object[1];
insArgList[0] = newObj;
Object result = null;
if ( (meth == null) && action.equals("update") ) {
//System.out.println("OperationController performing two-stage (deletion followed by insertion) update");
try {
Object[] delArgList = new Object[1];
delArgList[0] = epo.getOriginalBean();
deleteMeth.invoke(dataAccessObject,delArgList);
insertMeth.invoke(dataAccessObject,insArgList);
} catch (InvocationTargetException e) {
log.error(this.getClass().getName()+" encountered exception performing two-stage update");
Throwable innerE = e.getTargetException();
log.error(innerE, innerE);
if (innerE.getMessage()!=null) {
//log.error(innerE.getMessage());
epo.setAttribute("globalErrorMsg",innerE.getMessage());
}
return FAILURE;
} catch (IllegalAccessException iae) {
log.error(iae, iae);
epo.setAttribute("globalErrorMessage", "Illegal access - see error logs.");
return FAILURE;
}
} else {
try {
result = meth.invoke(dataAccessObject,insArgList);
} catch (InvocationTargetException e) {
log.error(this.getClass().getName()+" encountered exception performing edit action");
Throwable innerE = e.getTargetException();
//innerE.printStackTrace();
log.error(innerE, innerE);
if (innerE.getMessage()!=null) {
//System.out.println(innerE.getMessage());
//log.error(innerE.getMessage());
epo.setAttribute("globalErrorMsg",innerE.getMessage());
}
return FAILURE;
} catch (IllegalAccessException iae) {
log.error(iae, iae);
epo.setAttribute("globalErrorMessage", "Illegal access - see error logs.");
return FAILURE;
}
}
if (result != null) {
// need to put the result of the insert in the id of the newbean
try {
Class[] setIdArgs = new Class[1];
if (epo.getIdFieldClass() != null)
setIdArgs[0] = epo.getIdFieldClass();
else
setIdArgs[0] = int.class;
String idMutator = "set";
if (epo.getIdFieldName() != null) {
idMutator += epo.getIdFieldName();
} else {
idMutator += "Id";
}
Method setIdMeth = epo.getNewBean().getClass().getMethod(idMutator,setIdArgs);
try {
Object[] idArg = new Object[1];
idArg[0] = result;
setIdMeth.invoke((Object)epo.getNewBean(),idArg);
} catch (IllegalAccessException e) {
log.error("doPost() encountered IllegalAccessException setting id of new bean");
} catch (InvocationTargetException f) {
log.error(f.getTargetException().getMessage());
}
} catch (NoSuchMethodException e) {
//log.error("doPost() could not find setId() method for "+partialClassName);
} catch (Exception f) {
//log.error("doPost() could not set id of new bean.");
}
}
return SUCCESS;
}
}

View file

@ -0,0 +1,12 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.forwarder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import edu.cornell.mannlib.vedit.beans.EditProcessObject;
public interface PageForwarder {
public void doForward(HttpServletRequest request, HttpServletResponse response, EditProcessObject epo);
}

View file

@ -0,0 +1,37 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.forwarder.impl;
import java.io.IOException;
import java.net.URLEncoder;
import edu.cornell.mannlib.vedit.forwarder.PageForwarder;
import edu.cornell.mannlib.vedit.beans.EditProcessObject;
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class UrlForwarder implements PageForwarder {
private static final Log log = LogFactory.getLog(UrlForwarder.class.getName());
private String theUrl = null;
public UrlForwarder (String theUrl) {
this.theUrl = theUrl;
}
public void doForward(HttpServletRequest request, HttpServletResponse response, EditProcessObject epo) {
try {
response.sendRedirect(response.encodeRedirectURL(theUrl));
} catch (IOException ioe) {
log.error("doForward() could not send redirect.");
}
}
}

View file

@ -0,0 +1,15 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.listener;
import edu.cornell.mannlib.vedit.beans.EditProcessObject;
public interface ChangeListener {
public void doInserted(Object newObj, EditProcessObject epo);
public void doUpdated(Object oldObj, Object newObj, EditProcessObject epo);
public void doDeleted(Object oldObj, EditProcessObject epo);
}

View file

@ -0,0 +1,11 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.listener;
import edu.cornell.mannlib.vedit.beans.EditProcessObject;
public interface EditPreProcessor {
public void process(Object o, EditProcessObject epo);
}

View file

@ -0,0 +1,223 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.tags;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.io.File;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import javax.servlet.jsp.JspWriter;
import javax.servlet.ServletException;
import edu.cornell.mannlib.vedit.beans.FormObject;
import edu.cornell.mannlib.vedit.beans.DynamicField;
import edu.cornell.mannlib.vedit.beans.DynamicFieldRow;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringEscapeUtils;
import edu.cornell.mannlib.vedit.tags.EditTag;
public class DynamicFieldsTag extends EditTag {
private char PATH_SEP = File.separatorChar;
public final String MARKUP_FILE_PATH = "templates"+PATH_SEP+"edit"+PATH_SEP+"specific"+PATH_SEP;
private String name = null;
private String type = null;
private String usePage = null;
private String preMarkup = null;
private String templateMarkup = null;
private String postMarkup = null;
public void setName( String name ) {
this.name = name;
}
public void setType( String type ) {
this.type = type;
}
public void setUsePage( String usePage ) {
this.usePage = usePage;
}
public void parseMarkup() throws JspException{
try {
int preStart = -1;
int templateStart = -1;
int postStart = -1;
InputStream fis = new FileInputStream (pageContext.getServletContext().getRealPath(new String())+PATH_SEP+MARKUP_FILE_PATH+usePage);
InputStream bis = new BufferedInputStream(fis);
BufferedReader in = new BufferedReader(new InputStreamReader(bis));
List<String> lines = new ArrayList<String>();
lines.add(""); // 0th line
int lineIndex = 0;
while (in.ready()) {
++lineIndex;
String currentLine = in.readLine();
if (currentLine != null && currentLine.indexOf("<!--") ==0 && currentLine.indexOf("@pre")>0 ) {
preStart = lineIndex;
} else if (currentLine != null && currentLine.indexOf("<!--") ==0 && currentLine.indexOf("@template")>0 ) {
templateStart = lineIndex;
} else if (currentLine != null && currentLine.indexOf("<!--") ==0 && currentLine.indexOf("@post")>0 ) {
postStart = lineIndex;
}
lines.add(currentLine);
}
in.close();
StringBuffer preMarkupB = new StringBuffer();
StringBuffer postMarkupB = new StringBuffer();
StringBuffer templateMarkupB = new StringBuffer();
if (templateStart>preStart && preStart>0) {
for (int i=preStart+1; i<templateStart; i++) {
preMarkupB.append(lines.get(i)).append("\n");
}
} else {
System.out.println("DynamicFieldsTag could not find @pre markup in "+MARKUP_FILE_PATH+usePage);
throw new JspException("DynamicFieldsTag could not parse @pre markup section");
}
preMarkup = preMarkupB.toString();
if (postStart>templateStart && templateStart>0) {
for (int i=templateStart+1; i<postStart; i++) {
templateMarkupB.append(lines.get(i)).append("\n");
}
} else {
System.out.println("DynamicFieldsTag could not find @template markup in "+MARKUP_FILE_PATH+usePage);
throw new JspException("DynamicFieldsTag could not parse @template markup section");
}
templateMarkup = templateMarkupB.toString();
if (postStart>0) {
for (int i=postStart+1; i<lines.size(); i++) {
postMarkupB.append(lines.get(i)).append("\n");
}
} else {
System.out.println("DynamicFieldsTag could not find @post markup in "+MARKUP_FILE_PATH+usePage);
throw new JspException("DynamicFieldsTag could not parse @post markup section");
}
postMarkup = postMarkupB.toString();
} catch (FileNotFoundException e) {
System.out.println("DynamicFieldsTag could not find markup file at "+pageContext.getServletContext().getRealPath(new String())+"\\"+MARKUP_FILE_PATH+usePage);
} catch (IOException ioe) {
System.out.println("DynamicFieldsTag encountered IOException reading "+pageContext.getServletContext().getRealPath(new String())+"\\"+MARKUP_FILE_PATH+usePage);
}
}
public String strReplace(String input, String pattern, String replacement) {
String[] piece = input.split(pattern);
StringBuffer output = new StringBuffer();
for (int i=0; i<piece.length; i++) {
output.append(piece[i]);
if (i<piece.length-1)
output.append(replacement);
}
return output.toString();
}
public int doEndTag() throws JspException {
try {
parseMarkup();
JspWriter out = pageContext.getOut();
HashMap values = null;
try {
FormObject foo = getFormObject();
List<DynamicField> dynfs = foo.getDynamicFields();
Iterator<DynamicField> dynIt = dynfs.iterator();
int i = 9899;
while (dynIt.hasNext()) {
DynamicField dynf = dynIt.next();
StringBuffer genTaName = new StringBuffer().append("_").append(dynf.getTable()).append("_");
genTaName.append("-1").append("_");
Iterator pparamIt = dynf.getRowTemplate().getParameterMap().keySet().iterator();
while(pparamIt.hasNext()) {
String key = (String) pparamIt.next();
String value = (String) dynf.getRowTemplate().getParameterMap().get(key);
byte[] valueInBase64 = Base64.encodeBase64(value.getBytes());
genTaName.append(key).append(":").append(new String(valueInBase64)).append(";");
}
String preWithVars = new String(preMarkup);
preWithVars = strReplace(preWithVars,type+"NN",Integer.toString(i));
preWithVars = strReplace(preWithVars,"\\$genTaName",genTaName.toString());
preWithVars = strReplace(preWithVars,"\\$fieldName",dynf.getName());
out.print(preWithVars);
Iterator<DynamicFieldRow> rowIt = dynf.getRowList().iterator();
while (rowIt.hasNext()) {
++i;
DynamicFieldRow row = rowIt.next();
if (row.getValue()==null)
row.setValue("");
if (row.getValue().length()>0) {
StringBuffer taName = new StringBuffer().append("_").append(dynf.getTable()).append("_");
taName.append(row.getId()).append("_");
Iterator paramIt = row.getParameterMap().keySet().iterator();
while(paramIt.hasNext()) {
String key = (String) paramIt.next();
String value = (String) row.getParameterMap().get(key);
byte[] valueInBase64 = Base64.encodeBase64(value.getBytes());
taName.append(key).append(":").append(new String(valueInBase64)).append(";");
}
if (row.getValue().length()>0) {
String templateWithVars = new String(templateMarkup);
templateWithVars = strReplace(templateWithVars,type+"NN",Integer.toString(i));
templateWithVars = strReplace(templateWithVars,"\\$taName",taName.toString());
templateWithVars = strReplace(templateWithVars,"\\$\\$",row.getValue());
out.print(templateWithVars);
}
}
}
out.print(postMarkup);
}
// output the row template for the javascript to clone
out.println("<!-- row template inserted by DynamicFieldsTag -->");
String hiddenTemplatePreMarkup = new String(preMarkup);
// bit of a hack to hide the template from the user:
hiddenTemplatePreMarkup = strReplace(hiddenTemplatePreMarkup,"display\\:none\\;","");
hiddenTemplatePreMarkup = strReplace(hiddenTemplatePreMarkup,"display\\:block\\;","");
hiddenTemplatePreMarkup = strReplace(hiddenTemplatePreMarkup,"display\\:inline\\;","");
hiddenTemplatePreMarkup = strReplace(hiddenTemplatePreMarkup,"style\\=\\\"","style=\"display:none;");
out.print(hiddenTemplatePreMarkup);
String hiddenTemplateTemplateMarkup = new String(templateMarkup);
hiddenTemplateTemplateMarkup = strReplace(hiddenTemplateTemplateMarkup, "\\$\\$", "");
out.print(hiddenTemplateTemplateMarkup);
out.print(postMarkup);
} catch (Exception e){
System.out.println("DynamicFieldsTag could not get the form object");
}
} catch(Exception ex) {
throw new JspException(ex.getMessage());
}
return SKIP_BODY;
}
}

View file

@ -0,0 +1,58 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.tags;
import java.util.HashMap;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
import javax.servlet.jsp.JspWriter;
import edu.cornell.mannlib.vedit.beans.EditProcessObject;
import edu.cornell.mannlib.vedit.beans.FormObject;
import org.apache.commons.lang.StringEscapeUtils;
public class EditTag extends TagSupport {
private String name = null;
public void setName( String name ) {
this.name = name;
}
public int doEndTag() throws JspException {
return SKIP_BODY;
}
public EditProcessObject getEpo() {
EditProcessObject epo = null;
String epoKey = null;
String epoKeyAttr = (String) pageContext.getRequest().getAttribute("epoKey");
if (epoKeyAttr != null) {
epoKey = epoKeyAttr;
}
else {
String epoKeyParam = (String) pageContext.getRequest().getParameter("epoKey");
if (epoKeyParam != null) {
epoKey = epoKeyParam;
}
}
HashMap epoHash = (HashMap) pageContext.getSession().getAttribute("epoHash");
try {
epo = (EditProcessObject) epoHash.get(epoKey);
} catch (NullPointerException npe) {
System.out.println("Null epoHash in edu.cornell.mannlib.vitro.edu.tags.utils.TagUtils.getEpo()");
}
return epo;
}
public FormObject getFormObject() {
FormObject foo=null;
try {
foo=getEpo().getFormObject();
} catch (NullPointerException npe) {
System.out.println("Null epo in edu.cornell.mannlib.vitro.edit.tags.utils.TagUtils.getFormObject()");
}
return foo;
}
}

View file

@ -0,0 +1,40 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.tags;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import javax.servlet.jsp.JspWriter;
import edu.cornell.mannlib.vedit.beans.FormObject;
import edu.cornell.mannlib.vedit.tags.EditTag;
import org.apache.commons.lang.StringEscapeUtils;
/** This tag allows validation error messages to be displayed on a form JSP **/
public class ErrorTag extends EditTag {
private String name = null;
public void setName( String name ) {
this.name = name;
}
public int doEndTag() throws JspException {
try {
JspWriter out = pageContext.getOut();
String errors = null;
try {
errors = (String) getFormObject().getErrorMap().get(name);
} catch (Exception e){
System.out.println("Could not get the form object from which to extract validation error message.");
}
if (errors != null){
out.print(StringEscapeUtils.escapeHtml((String) errors));
}
} catch(Exception ex) {
throw new JspException(ex.getMessage());
}
return SKIP_BODY;
}
}

View file

@ -0,0 +1,70 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.tags;
import org.apache.commons.collections.map.ListOrderedMap;
import org.apache.commons.collections.OrderedMapIterator;
import java.util.List;
import java.util.Iterator;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import edu.cornell.mannlib.vedit.beans.Option;
import edu.cornell.mannlib.vedit.tags.EditTag;
import org.apache.commons.lang.StringEscapeUtils;
public class OptionTag extends EditTag {
private String name = null;
public void setName( String name ) {
this.name = name;
}
private void outputOptionsMarkup(List optList, JspWriter out) throws IOException {
Iterator it = optList.iterator();
while (it.hasNext()){
Option opt = (Option) it.next();
if (opt.getValue() == null)
opt.setValue("");
if (opt.getBody() == null)
opt.setBody("");
out.print("<option value=\""+StringEscapeUtils.escapeHtml(opt.getValue())+"\"");
if (opt.getSelected())
out.print(" selected=\"selected\"");
out.print(">");
out.print(StringEscapeUtils.escapeHtml(opt.getBody()));
out.print("</option>\n");
}
}
public int doEndTag() throws JspException {
try {
JspWriter out = pageContext.getOut();
List optList = null;
ListOrderedMap optGroups = null;
try {
optList = (List) getFormObject().getOptionLists().get(name);
outputOptionsMarkup(optList,out);
} catch (ClassCastException e){
// maybe it's a ListOrderedMap of optgroups
optGroups = (ListOrderedMap) getFormObject().getOptionLists().get(name);
OrderedMapIterator ogKey = optGroups.orderedMapIterator();
while (ogKey.hasNext()) {
String optGroupName = (String) ogKey.next();
out.println("<optgroup label=\""+StringEscapeUtils.escapeHtml(optGroupName)+"\">");
outputOptionsMarkup((List)optGroups.get(optGroupName),out);
out.println("</optgroup>");
}
} catch (NullPointerException npe) {
System.out.println("OptionTag could not find option list for "+name);
}
} catch(Exception ex) {
ex.printStackTrace();
throw new JspException(ex.getMessage());
}
return SKIP_BODY; // EVAL_PAGE; did colnames only //EVAL_PAGE in connection pooled version;
}
}

View file

@ -0,0 +1,48 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.tags;
import java.util.HashMap;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import javax.servlet.jsp.JspWriter;
import edu.cornell.mannlib.vedit.beans.FormObject;
import org.apache.commons.lang.StringEscapeUtils;
import edu.cornell.mannlib.vedit.tags.EditTag;
public class ValueTag extends EditTag {
private String name = null;
public void setName( String name ) {
this.name = name;
}
public int doEndTag() throws JspException {
try {
JspWriter out = pageContext.getOut();
HashMap values = null;
try {
// FormObject foo = (FormObject) pageContext.getSession().getAttribute("FormObject");
// FormObject foo = TagUtils.getFormObject(pageContext);
FormObject foo = getFormObject();
values = foo.getValues();
} catch (Exception e){
System.out.println("Could not get the form object from which to build an option list");
}
if (values != null){
String value = (String) values.get(name);
if (value != null)
out.print(StringEscapeUtils.escapeHtml(value));
} else {
System.out.println("ValueTag unable to get HashMap of form values");
}
} catch(Exception ex) {
throw new JspException(ex.getMessage());
}
return SKIP_BODY;
}
}

View file

@ -0,0 +1,388 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.util;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vedit.beans.EditProcessObject;
import edu.cornell.mannlib.vedit.beans.FormObject;
import edu.cornell.mannlib.vedit.beans.Option;
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
import edu.cornell.mannlib.vitro.webapp.dao.VClassDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
public class FormUtils {
protected static final Log log = LogFactory.getLog(FormUtils.class.getName());
protected static final int BASE_10 = 10;
protected static final Class[] SUPPORTED_TYPES = { String.class,
int.class,
Integer.class,
boolean.class,
Date.class
};
protected static final List<Class> SUPPORTED_TYPE_LIST = Arrays
.asList(SUPPORTED_TYPES);
/* this class needs to be reworked */
public static void populateFormFromBean (Object bean,
String action,
FormObject foo) {
populateFormFromBean(bean,action,null,foo,new HashMap());
}
public static void populateFormFromBean (Object bean,
String action,
FormObject foo,
Map<String, String> badValuesHash) {
populateFormFromBean(bean,action,null,foo,badValuesHash);
}
/**
* Populates form objects with bean values
*/
public static void populateFormFromBean (Object bean,
String action,
EditProcessObject epo,
FormObject foo,
Map<String, String> BadValuesHash) {
Class beanClass =
(epo != null && epo.getBeanClass() != null)
? epo.getBeanClass()
: bean.getClass();
Method[] meths = beanClass.getMethods();
for (int i=0; i<meths.length; i++) {
if (meths[i].getName().indexOf("set") == 0) {
// we have a setter method
Method currMeth = meths[i];
Class[] currMethParamTypes = currMeth.getParameterTypes();
Class currMethType = currMethParamTypes[0];
if (SUPPORTED_TYPE_LIST.contains(currMethType)) {
//we only want people directly to type in ints, strings, and dates
//of course, most of the ints are probably foreign keys anyway...
String elementName = currMeth.getName().substring(
3,currMeth.getName().length());
//see if there's something in the bean using
//the related getter method
Class[] paramClass = new Class[1];
paramClass[0] = currMethType;
try {
Method getter = beanClass.getMethod(
"get" + elementName, (Class[]) null);
Object existingData = null;
try {
existingData = getter.invoke(bean, (Object[]) null);
} catch (Exception e) {
log.error ("Exception invoking getter method");
}
String value = "";
if (existingData != null){
if (existingData instanceof String){
value += existingData;
}
else if (!(existingData instanceof Integer
&& (Integer)existingData < 0)) {
value += existingData.toString();
}
}
String badValue = (String) BadValuesHash.get(elementName);
if (badValue != null) {
value = badValue;
}
foo.getValues().put(elementName, value);
} catch (NoSuchMethodException e) {
//ignore it
}
}
}
}
}
public static List<Option> makeOptionListFromBeans (List beanList,
String valueField,
String bodyField,
String selectedValue,
String selectedBody) {
return makeOptionListFromBeans (
beanList, valueField, bodyField, selectedValue, selectedBody, true);
}
public static List<Option> makeOptionListFromBeans(List beanList,
String valueField,
String bodyField,
String selectedValue,
String selectedBody,
boolean forceSelectedInclusion) {
List<Option> optList = new LinkedList();
if (beanList == null)
return optList;
Iterator beanIt = beanList.iterator();
boolean foundSelectedValueInBeans = false;
while (beanIt.hasNext()){
Object bean = beanIt.next();
String value="";
Method valueMeth = null;
Object valueObj = null;
try {
valueMeth = bean.getClass().getMethod(
"get" + valueField, (Class[]) null);
valueObj = valueMeth.invoke(bean, (Object[]) null);
} catch (Exception e) {
log.warn("Could not find method get" + valueField + " on " +
bean.getClass());
}
if (valueObj != null){
value = valueObj.toString();
}
String body="";
Method bodyMeth = null;
Object bodyObj = null;
try {
bodyMeth = bean.getClass().getMethod(
"get" + bodyField, (Class[]) null);
bodyObj = bodyMeth.invoke(bean, (Object[]) null);
} catch (Exception e) {
log.warn(" could not find method get"+bodyField);
}
if (bodyObj != null){
body = bodyObj.toString();
}
Option opt = new Option();
opt.setValue(value);
opt.setBody(body);
if (selectedValue != null){
if (selectedValue.equals(value)) {
opt.setSelected(true);
foundSelectedValueInBeans = true;
}
} else {
if (selectedBody != null){
if (selectedBody.equals(body)) {
opt.setSelected(true);
foundSelectedValueInBeans = true;
}
}
}
optList.add(opt);
}
// if the list of beans doesn't include the selected value/body,
// insert it anyway so we don't inadvertently change the value of the
// field to the first thing that happens to be in the select list
boolean skipThisStep = !forceSelectedInclusion;
// For now, if the value is a negative integer, we won't try to
// preserve it, as the bean was probably just instantiated.
// Should switch to a more robust way of handling inital bean values.
if (selectedValue == null) {
skipThisStep = true;
} else {
try {
int selectedValueInt = Integer.decode(selectedValue);
if (selectedValueInt < 0)
skipThisStep = true;
} catch (NumberFormatException e) {}
}
if (!foundSelectedValueInBeans && !skipThisStep) {
log.trace("Adding the selected option!");
Option sOpt = new Option();
sOpt.setValue(selectedValue);
if (selectedBody == null || selectedBody.length() == 0)
sOpt.setBody(selectedValue.toString());
else
sOpt.setBody(selectedBody);
sOpt.setSelected(true);
optList.add(sOpt);
}
return optList;
}
public static List<Option> makeVClassOptionList(WebappDaoFactory wadf,
String selectedVClassURI) {
List<Option> vclassOptionList = new LinkedList<Option>();
for (VClass vclass : wadf.getVClassDao().getAllVclasses()) {
Option option = new Option();
option.setValue(vclass.getURI());
option.setBody(vclass.getPickListName());
vclassOptionList.add(option);
if(selectedVClassURI != null && selectedVClassURI.equals(vclass.getURI())) {
option.setSelected(true);
}
}
return vclassOptionList;
}
public static List<Option> makeOptionListOfSubVClasses(
WebappDaoFactory wadf, String parentVClassUri,
String selectedVClassURI) {
VClassDao vClassDao = wadf.getVClassDao();
Set<String> uris = new HashSet<>(vClassDao.getAllSubClassURIs(parentVClassUri));
uris.add(parentVClassUri);
List<Option> options = new LinkedList<>();
for (String vclassUri: uris) {
VClass vclass = vClassDao.getVClassByURI(vclassUri);
Option option = new Option();
option.setValue(vclass.getURI());
option.setBody(vclass.getPickListName());
options.add(option);
if(Objects.equals(selectedVClassURI, vclass.getURI())) {
option.setSelected(true);
}
}
Collections.sort(options, new Comparator<Option>() {
@Override
public int compare(Option o1, Option o2) {
return o1.getBody().compareTo(o2.getBody());
}});
return options;
}
public static void beanSet(Object newObj, String field, String value) {
beanSet (newObj, field, value, null);
}
public static void beanSet(Object newObj,
String field,
String value,
EditProcessObject epo) {
SimpleDateFormat standardDateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
SimpleDateFormat minutesOnlyDateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm");
Class cls =
(epo != null && epo.getBeanClass() != null)
? epo.getBeanClass()
: newObj.getClass();
Class[] paramList = new Class[1];
Method setterMethod = getSetterMethod(cls, field, SUPPORTED_TYPE_LIST);
if (setterMethod == null) {
log.debug("Could not find method set" + field + " on "
+ cls.getName());
return;
}
Class argumentType = setterMethod.getParameterTypes()[0];
Object[] arglist = new Object[1];
if (int.class.equals(argumentType)
|| Integer.class.equals(argumentType)) {
arglist[0] = (int.class.equals(argumentType)) ? -1 : null;
if (!value.isEmpty()) {
int parsedInt = Integer.parseInt(value, BASE_10);
if (parsedInt < 0) {
throw new FormUtils.NegativeIntegerException();
} else {
arglist[0] = parsedInt;
}
}
} else if (Date.class.equals(argumentType)) {
// this isn't so great ; should probably be in a validator
if (value != null && value.length() > 0 && value.indexOf(":") < 1) {
value += " 00:00:00";
}
if (value != null && value.length()>0) {
try {
arglist[0] = standardDateFormat.parse(value);
} catch (ParseException p) {
try {
arglist[0] = minutesOnlyDateFormat.parse(value);
} catch (ParseException q) {
log.error(FormUtils.class.getName()+" could not parse" +
value + " to a Date object.");
throw new IllegalArgumentException(
"Please enter a date/time in one of these " +
"formats: '2007-07-07', '2007-07-07 07:07' " +
"or '2007-07-07 07:07:07'");
}
}
} else {
arglist[0] = null;
}
} else if (boolean.class.equals(argumentType)) {
arglist[0] = (value.equalsIgnoreCase("true"));
} else {
arglist[0] = value;
}
try {
setterMethod.invoke(newObj,arglist);
} catch (Exception e) {
log.error(e,e);
}
}
private static Method getSetterMethod(Class beanClass,
String fieldName,
List<Class> supportedTypes) {
for (Class clazz : supportedTypes) {
try {
Class[] argList = new Class[1];
argList[0] = clazz;
return beanClass.getMethod("set" + fieldName, argList);
} catch (NoSuchMethodException nsme) {
// just try the next type
}
}
return null;
}
/**
* Decodes a Base-64-encoded String of format
* key:value;key2:value2;key3:value, and puts the keys and values in a Map
* @param params
* @return
*/
public static Map beanParamMapFromString(String params) {
String[] param = params.split(";");
Map beanParamMap = new HashMap();
for (int i=0; i<param.length; i++) {
String[] p = param[i].split(":");
beanParamMap.put(p[0],new String(Base64.decodeBase64(p[1].getBytes())));
}
return beanParamMap;
}
public static class NegativeIntegerException extends RuntimeException {}
}

View file

@ -0,0 +1,153 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vedit.beans.EditProcessObject;
public class OperationUtils {
private static final Log log = LogFactory.getLog(OperationUtils.class
.getName());
public static void beanSetAndValidate(Object newObj, String field,
String value, EditProcessObject epo) {
Class<?> cls = (epo.getBeanClass() != null) ? epo.getBeanClass() : newObj
.getClass();
Class<?>[] paramList = new Class[1];
paramList[0] = String.class;
boolean isInt = false;
boolean isBoolean = false;
Method setterMethod = null;
try {
setterMethod = cls.getMethod("set" + field, paramList);
} catch (NoSuchMethodException e) {
// let's try int
paramList[0] = int.class;
try {
setterMethod = cls.getMethod("set" + field, paramList);
isInt = true;
} catch (NoSuchMethodException f) {
// let's try boolean
paramList[0] = boolean.class;
try {
setterMethod = cls.getMethod("set" + field, paramList);
isBoolean = true;
log.debug("found boolean field " + field);
} catch (NoSuchMethodException g) {
log.error("beanSet could not find an appropriate String, int, or boolean setter method for "
+ field);
}
}
}
Object[] arglist = new Object[1];
if (isInt)
arglist[0] = Integer.decode(value);
else if (isBoolean)
arglist[0] = (value.equalsIgnoreCase("TRUE"));
else
arglist[0] = value;
try {
setterMethod.invoke(newObj, arglist);
} catch (Exception e) {
log.error("Couldn't invoke method");
log.error(e.getMessage());
log.error(field + " " + arglist[0]);
}
}
/**
* Takes a bean and clones it using reflection. Any fields without standard
* getter/setter methods will not be copied.
*/
public static Object cloneBean(Object bean) {
if (bean == null) {
throw new NullPointerException("bean may not be null.");
}
return cloneBean(bean, bean.getClass(), bean.getClass());
}
/**
* Takes a bean and clones it using reflection. Any fields without standard
* getter/setter methods will not be copied.
*/
public static Object cloneBean(final Object bean, final Class<?> beanClass,
final Class<?> iface) {
if (bean == null) {
throw new NullPointerException("bean may not be null.");
}
if (beanClass == null) {
throw new NullPointerException("beanClass may not be null.");
}
if (iface == null) {
throw new NullPointerException("iface may not be null.");
}
class CloneBeanException extends RuntimeException {
public CloneBeanException(String message, Throwable cause) {
super(message + " <" + cause.getClass().getSimpleName()
+ ">: bean=" + bean + ", beanClass="
+ beanClass.getName() + ", iface=" + iface.getName(),
cause);
}
}
Object newBean;
try {
newBean = beanClass.getConstructor().newInstance();
} catch (NoSuchMethodException e) {
throw new CloneBeanException("bean has no 'nullary' constructor.", e);
} catch (InstantiationException e) {
throw new CloneBeanException("tried to create instance of an abstract class.", e);
} catch (IllegalAccessException e) {
throw new CloneBeanException("bean constructor is not accessible.", e);
} catch (InvocationTargetException e) {
throw new CloneBeanException("bean constructor threw an exception.", e);
} catch (Exception e) {
throw new CloneBeanException("failed to instantiate a new bean.", e);
}
for (Method beanMeth : iface.getMethods()) {
String methName = beanMeth.getName();
if (!methName.startsWith("get")) {
continue;
}
if (beanMeth.getParameterTypes().length != 0) {
continue;
}
String fieldName = methName.substring(3, methName.length());
Class<?> returnType = beanMeth.getReturnType();
Method setterMethod;
try {
setterMethod = iface.getMethod("set" + fieldName, returnType);
} catch (NoSuchMethodException nsme) {
continue;
}
Object fieldVal;
try {
fieldVal = beanMeth.invoke(bean, (Object[]) null);
} catch (Exception e) {
throw new CloneBeanException("failed to invoke " + beanMeth, e);
}
try {
Object[] setArgs = new Object[1];
setArgs[0] = fieldVal;
setterMethod.invoke(newBean, setArgs);
} catch (Exception e) {
throw new CloneBeanException(
"failed to invoke " + setterMethod, e);
}
}
return newBean;
}
}

View file

@ -0,0 +1,556 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.util;
/*
Porter stemmer in Java. The original paper is in
Porter, 1980, An algorithm for suffix stripping, Program, Vol. 14,
no. 3, pp 130-137,
See also http://www.tartarus.org/~martin/PorterStemmer
History:
Release 1
Bug 1 (reported by Gonzalo Parra 16/10/99) fixed as marked below.
The words 'aed', 'eed', 'oed' leave k at 'a' for step 3, and b[k-1]
is then out outside the bounds of b.
Release 2
Similarly,
Bug 2 (reported by Steve Dyrdahl 22/2/00) fixed as marked below.
'ion' by itself leaves j = -1 in the test for 'ion' in step 5, and
b[j] is then outside the bounds of b.
Release 3
Considerably revised 4/9/00 in the light of many helpful suggestions
from Brian Goetz of Quiotix Corporation (brian@quiotix.com).
Release 4
*/
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Stemmer, implementing the Porter Stemming Algorithm
*
* The Stemmer class transforms a word into its root form. The input
* word can be provided a character at time (by calling add()), or at once
* by calling one of the various stem(something) methods.
*/
class Stemmer
{ private char[] b;
private int i, /* offset into b */
i_end, /* offset to end of stemmed word */
j, k;
private static final int INC = 50;
/* unit of size whereby b is increased */
private static final Log log = LogFactory.getLog(Stemmer.class.getName());
public Stemmer()
{ b = new char[INC];
i = 0;
i_end = 0;
}
/**
* Add a character to the word being stemmed. When you are finished
* adding characters, you can call stem(void) to stem the word.
*/
public void add(char ch)
{ if (i == b.length)
{ char[] new_b = new char[i+INC];
for (int c = 0; c < i; c++) new_b[c] = b[c];
b = new_b;
}
b[i++] = ch;
}
/** Adds wLen characters to the word being stemmed contained in a portion
* of a char[] array. This is like repeated calls of add(char ch), but
* faster.
*/
public void add(char[] w, int wLen)
{ if (i+wLen >= b.length)
{ char[] new_b = new char[i+wLen+INC];
for (int c = 0; c < i; c++) new_b[c] = b[c];
b = new_b;
}
for (int c = 0; c < wLen; c++) b[i++] = w[c];
}
/**
* After a word has been stemmed, it can be retrieved by toString(),
* or a reference to the internal buffer can be retrieved by getResultBuffer
* and getResultLength (which is generally more efficient.)
*/
public String toString() { return new String(b,0,i_end); }
/**
* Returns the length of the word resulting from the stemming process.
*/
public int getResultLength() { return i_end; }
/**
* Returns a reference to a character buffer containing the results of
* the stemming process. You also need to consult getResultLength()
* to determine the length of the result.
*/
public char[] getResultBuffer() { return b; }
/* cons(i) is true <=> b[i] is a consonant. */
private final boolean cons(int i)
{ switch (b[i])
{ case 'a': case 'e': case 'i': case 'o': case 'u': return false;
case 'y': return (i==0) ? true : !cons(i-1);
default: return true;
}
}
/* m() measures the number of consonant sequences between 0 and j. if c is
a consonant sequence and v a vowel sequence, and <..> indicates arbitrary
presence,
<c><v> gives 0
<c>vc<v> gives 1
<c>vcvc<v> gives 2
<c>vcvcvc<v> gives 3
....
*/
private final int m()
{ int n = 0;
int i = 0;
while(true)
{ if (i > j) return n;
if (! cons(i)) break; i++;
}
i++;
while(true)
{ while(true)
{ if (i > j) return n;
if (cons(i)) break;
i++;
}
i++;
n++;
while(true)
{ if (i > j) return n;
if (! cons(i)) break;
i++;
}
i++;
}
}
/* vowelinstem() is true <=> 0,...j contains a vowel */
private final boolean vowelinstem()
{ int i; for (i = 0; i <= j; i++) if (! cons(i)) return true;
return false;
}
/* doublec(j) is true <=> j,(j-1) contain a double consonant. */
private final boolean doublec(int j)
{ if (j < 1) return false;
if (b[j] != b[j-1]) return false;
return cons(j);
}
/* cvc(i) is true <=> i-2,i-1,i has the form consonant - vowel - consonant
and also if the second c is not w,x or y. this is used when trying to
restore an e at the end of a short word. e.g.
cav(e), lov(e), hop(e), crim(e), but
snow, box, tray.
*/
private final boolean cvc(int i)
{ if (i < 2 || !cons(i) || cons(i-1) || !cons(i-2)) return false;
{ int ch = b[i];
if (ch == 'w' || ch == 'x' || ch == 'y') return false;
}
return true;
}
private final boolean ends(String s)
{ int l = s.length();
int o = k-l+1;
if (o < 0) return false;
for (int i = 0; i < l; i++) if (b[o+i] != s.charAt(i)) return false;
j = k-l;
return true;
}
/* setto(s) sets (j+1),...k to the characters in the string s, readjusting
k. */
private final void setto(String s)
{ int l = s.length();
int o = j+1;
for (int i = 0; i < l; i++) b[o+i] = s.charAt(i);
k = j+l;
}
/* r(s) is used further down. */
private final void r(String s) { if (m() > 0) setto(s); }
/* step1() gets rid of plurals and -ed or -ing. e.g.
caresses -> caress
ponies -> poni
ties -> ti
caress -> caress
cats -> cat
feed -> feed
agreed -> agree
disabled -> disable
matting -> mat
mating -> mate
meeting -> meet
milling -> mill
messing -> mess
meetings -> meet
*/
private final void step1()
{ if (b[k] == 's')
{ if (ends("sses")) k -= 2; else
if (ends("ies")) setto("i"); else
if (b[k-1] != 's') k--;
}
if (ends("eed")) { if (m() > 0) k--; } else
if ((ends("ed") || ends("ing")) && vowelinstem())
{ k = j;
if (ends("at")) setto("ate"); else
if (ends("bl")) setto("ble"); else
if (ends("iz")) setto("ize"); else
if (doublec(k))
{ k--;
{ int ch = b[k];
if (ch == 'l' || ch == 's' || ch == 'z') k++;
}
}
else if (m() == 1 && cvc(k)) setto("e");
}
}
/* step2() turns terminal y to i when there is another vowel in the stem. */
private final void step2() { if (ends("y") && vowelinstem()) b[k] = 'i'; }
/* step3() maps double suffices to single ones. so -ization ( = -ize plus
-ation) maps to -ize etc. note that the string before the suffix must give
m() > 0. */
private final void step3() { if (k == 0) return; /* For Bug 1 */ switch (b[k-1])
{
case 'a': if (ends("ational")) { r("ate"); break; }
if (ends("tional")) { r("tion"); break; }
break;
case 'c': if (ends("enci")) { r("ence"); break; }
if (ends("anci")) { r("ance"); break; }
break;
case 'e': if (ends("izer")) { r("ize"); break; }
break;
case 'l': if (ends("bli")) { r("ble"); break; }
if (ends("alli")) { r("al"); break; }
if (ends("entli")) { r("ent"); break; }
if (ends("eli")) { r("e"); break; }
if (ends("ousli")) { r("ous"); break; }
break;
case 'o': if (ends("ization")) { r("ize"); break; }
if (ends("ation")) { r("ate"); break; }
if (ends("ator")) { r("ate"); break; }
break;
case 's': if (ends("alism")) { r("al"); break; }
if (ends("iveness")) { r("ive"); break; }
if (ends("fulness")) { r("ful"); break; }
if (ends("ousness")) { r("ous"); break; }
break;
case 't': if (ends("aliti")) { r("al"); break; }
if (ends("iviti")) { r("ive"); break; }
if (ends("biliti")) { r("ble"); break; }
break;
case 'g': if (ends("logi")) { r("log"); break; }
} }
/* step4() deals with -ic-, -full, -ness etc. similar strategy to step3. */
private final void step4() { switch (b[k])
{
case 'e': if (ends("icate")) { r("ic"); break; }
if (ends("ative")) { r(""); break; }
if (ends("alize")) { r("al"); break; }
break;
case 'i': if (ends("iciti")) { r("ic"); break; }
break;
case 'l': if (ends("ical")) { r("ic"); break; }
if (ends("ful")) { r(""); break; }
break;
case 's': if (ends("ness")) { r(""); break; }
break;
} }
/* step5() takes off -ant, -ence etc., in context <c>vcvc<v>. */
private final void step5()
{ if (k == 0) return; /* for Bug 1 */ switch (b[k-1])
{ case 'a': if (ends("al")) break; return;
case 'c': if (ends("ance")) break;
if (ends("ence")) break; return;
case 'e': if (ends("er")) break; return;
case 'i': if (ends("ic")) break; return;
case 'l': if (ends("able")) break;
if (ends("ible")) break; return;
case 'n': if (ends("ant")) break;
if (ends("ement")) break;
if (ends("ment")) break;
/* element etc. not stripped before the m */
if (ends("ent")) break; return;
case 'o': if (ends("ion") && j >= 0 && (b[j] == 's' || b[j] == 't')) break;
/* j >= 0 fixes Bug 2 */
if (ends("ou")) break; return;
/* takes care of -ous */
case 's': if (ends("ism")) break; return;
case 't': if (ends("ate")) break;
if (ends("iti")) break; return;
case 'u': if (ends("ous")) break; return;
case 'v': if (ends("ive")) break; return;
case 'z': if (ends("ize")) break; return;
default: return;
}
if (m() > 1) k = j;
}
/* step6() removes a final -e if m() > 1. */
private final void step6()
{ j = k;
if (b[k] == 'e')
{ int a = m();
if (a > 1 || a == 1 && !cvc(k-1)) k--;
}
if (b[k] == 'l' && doublec(k) && m() > 1) k--;
}
/** Stem the word placed into the Stemmer buffer through calls to add().
* Returns true if the stemming process resulted in a word different
* from the input. You can retrieve the result with
* getResultLength()/getResultBuffer() or toString().
*/
public void stem()
{ k = i - 1;
if (k > 1) { step1(); step2(); step3(); step4(); step5(); step6(); }
i_end = k+1; i = 0;
}
public static String StemString( String inputStr, int maxLength )
{
String outputStr="";
int previousCh=0;
char[] w = new char[maxLength];
char[] inputArray = inputStr.toCharArray();
Stemmer s = new Stemmer();
int inputArrayIndex=0, stemmerInputBufferIndex=0, ch=0;
for ( inputArrayIndex=0; inputArrayIndex<inputArray.length; inputArrayIndex++ ) {
ch = inputArray[inputArrayIndex];
if ( Character.isLetter((char) ch)) {
stemmerInputBufferIndex = 0; // start collecting letters for a new word
while ( inputArrayIndex < inputArray.length ) { // keep reading until hit character other than a letter
ch = Character.toLowerCase((char) ch);
w[stemmerInputBufferIndex] = (char) ch;
if (stemmerInputBufferIndex < maxLength-1 ) {
stemmerInputBufferIndex++;
}
if ( inputArrayIndex < inputArray.length-1 ) {
previousCh = ch;
ch = inputArray[++inputArrayIndex];
if ( !Character.isLetter((char) ch) ) { // parse the word in preparation for starting a new one
for (int c = 0; c < stemmerInputBufferIndex; c++) { // copy to stemmer internal buffer
s.add(w[c]);
}
s.stem();
{
String u;
u = s.toString();
outputStr += u;
if ( ch == '-' ) { // replace - with space
outputStr += " ";
} else if ( ch == '.' ) {
if ( Character.isDigit( (char) previousCh )) {
outputStr += ".";
} else {
outputStr += " ";
//previousCh = 32; // set to whitespace; extra spaces should be filtered out on next pass
}
} else {
Character Ch = new Character((char) ch);
outputStr += Ch.toString();
}
stemmerInputBufferIndex=0; // to avoid repeats after )
}
break;
}
} else {
break;
}
}
} else if ( Character.isWhitespace((char) ch) ) {
if ( !Character.isWhitespace((char) previousCh ) ) {
if ( previousCh != '.' ) {
Character Ch = new Character((char) ch);
outputStr += Ch.toString();
}
}
} else if ( ch == '(' ) { // open paren; copy all characters until close paren
while ( ch != ')' ) {
if ( inputArrayIndex < inputArray.length ) {
ch = inputArray[inputArrayIndex++];
} else {
log.trace ("");
log.trace("1 short of EOS in paren at pos: " + inputArrayIndex + " of " + inputStr );
break;
}
Character Ch = new Character((char) ch);
//outputStr += Ch.toString();
//System.out.print( Ch.toString() );
}
//log.trace("");
/* not needed -- just duplicates close paren
if ( ch == ')') {
Character Ch = new Character((char) ch);
outputStr += Ch.toString();
log.trace( Ch.toString() );
}
*/
stemmerInputBufferIndex=0;
} else if ( ch == ')' ) { // when is last character of input string
Character Ch = new Character((char) ch);
outputStr += Ch.toString();
log.trace( Ch.toString() );
log.trace("found close paren at position: " + inputArrayIndex + " of input term " + inputStr );
} else if ( ch == '-' ) { // replace - with space
outputStr += " ";
} else if ( ch == '.' ) {
if ( Character.isDigit( (char) previousCh )) {
outputStr += ".";
} else {
outputStr += " ";
//previousCh = 32; // set to whitespace; extra spaces should be filtered out on next pass
}
} else {
Character Ch = new Character((char) ch);
outputStr += Ch.toString();
}
previousCh = ch;
if (ch < 0) break;
}
if ( stemmerInputBufferIndex > 0 ) {
for (int c = 0; c < stemmerInputBufferIndex; c++) {
s.add(w[c]);
}
s.stem();
String u;
u = s.toString();
outputStr += u;
}
return outputStr == null ? ( outputStr.equals("") ? null : outputStr.trim() ) : outputStr.trim();
}
/*
public static void main(String[] args)
{
char[] w = new char[501];
Stemmer s = new Stemmer();
for (int i = 0; i < args.length; i++)
try
{
FileInputStream in = new FileInputStream(args[i]);
try
{ while(true)
{ int ch = in.read();
if (Character.isLetter((char) ch))
{
int j = 0;
while(true)
{ ch = Character.toLowerCase((char) ch);
w[j] = (char) ch;
if (j < 500) j++;
ch = in.read();
if (!Character.isLetter((char) ch))
{
// to test add(char ch)
for (int c = 0; c < j; c++) s.add(w[c]);
// or, to test add(char[] w, int j)
// s.add(w, j);
s.stem();
{ String u;
// and now, to test toString() :
u = s.toString();
// to test getResultBuffer(), getResultLength() :
// u = new String(s.getResultBuffer(), 0, s.getResultLength());
System.out.print(u);
}
break;
}
}
}
if (ch < 0) break;
System.out.print((char)ch);
}
}
catch (IOException e)
{ log.trace("error reading " + args[i]);
break;
}
}
catch (FileNotFoundException e)
{ log.trace("file " + args[i] + " not found");
break;
}
}
*/
public static void main(String[] args)
{
char[] w = new char[501];
Stemmer s = new Stemmer();
for (int i = 0; i < args.length; i++) {
System.out.println( StemString( args[i], 100 ));
}
}
}

View file

@ -0,0 +1,62 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.validator;
/**
* Output from a {@link Validator}. Holds the value that was tested, whether it
* was valid or not, and an optional message.
*/
public class ValidationObject {
/**
* Create an instance that indicates successful validation.
*/
public static ValidationObject success(Object validatedObject) {
ValidationObject vo = new ValidationObject();
vo.setValid(true);
vo.setMessage("");
vo.setValidatedObject(validatedObject);
return vo;
}
/**
* Create an instance that indicates failed validation.
*/
public static ValidationObject failure(Object validatedObject,
String message) {
ValidationObject vo = new ValidationObject();
vo.setValid(false);
vo.setMessage(message);
vo.setValidatedObject(validatedObject);
return vo;
}
private boolean valid = false;
private String message;
private Object validatedObject = null;
public boolean getValid(){
return valid;
}
public void setValid(boolean valid){
this.valid = valid;
}
public String getMessage(){
return message;
}
public void setMessage(String message){
this.message = message;
}
public Object getValidatedObject(){
return validatedObject;
}
public void setValidatedObject(Object validatedObject){
this.validatedObject = validatedObject;
}
}

View file

@ -0,0 +1,9 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.validator;
public interface Validator {
public ValidationObject validate(Object obj) throws IllegalArgumentException;
}

View file

@ -0,0 +1,44 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.validator.impl;
import edu.cornell.mannlib.vedit.validator.*;
import java.util.HashSet;
import java.util.Iterator;
public class EnumValuesValidator implements Validator {
private HashSet legalValues = new HashSet();
public ValidationObject validate(Object obj){
ValidationObject vo = new ValidationObject();
if (legalValues.contains((String)obj)){
vo.setValid(true);
} else {
vo.setValid(false);
if (legalValues.size()<7){
String msgString = "Please enter one of ";
Iterator valuesIt = legalValues.iterator();
while (valuesIt.hasNext()) {
String legalValue = (String) valuesIt.next();
msgString += "'"+legalValue+"'";
if (valuesIt.hasNext())
msgString += ", ";
else
msgString += ".";
}
vo.setMessage(msgString);
}
else {
vo.setMessage("Please enter a legal value.");
}
}
vo.setValidatedObject(obj);
return vo;
}
public EnumValuesValidator (String[] legalValues){
for (int i=0; i<legalValues.length; i++)
this.legalValues.add(legalValues[i]);
}
}

View file

@ -0,0 +1,56 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.validator.impl;
import edu.cornell.mannlib.vedit.validator.Validator;
import edu.cornell.mannlib.vedit.validator.ValidationObject;
public class IntValidator implements Validator {
protected int minVal = 0; // the edit framework doesn't handle negative ints
protected int maxVal = Integer.MAX_VALUE;
public ValidationObject validate (Object obj) throws IllegalArgumentException {
ValidationObject vo = new ValidationObject();
int theInt = -1;
if (obj instanceof String) {
try {
theInt = Integer.parseInt((String) obj);
} catch (NumberFormatException e) {
vo.setValid(false);
vo.setMessage("Please enter an integer");
vo.setValidatedObject(obj);
return vo;
}
} else {
try {
theInt = ((Integer) obj).intValue();
} catch (Exception e) {
vo.setValid(false);
vo.setMessage("Please enter an integer");
vo.setValidatedObject(obj);
return vo;
}
}
if ( theInt < minVal || theInt > maxVal ) {
vo.setValid(false);
vo.setMessage("Enter a number between "+minVal+" and "+maxVal);
} else {
vo.setValid(true);
}
vo.setValidatedObject(obj);
return vo;
}
public IntValidator(){}
public IntValidator (int minVal, int maxVal){
this.minVal = minVal;
this.maxVal = maxVal;
}
}

View file

@ -0,0 +1,26 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.validator.impl;
import edu.cornell.mannlib.vedit.validator.Validator;
import edu.cornell.mannlib.vedit.validator.ValidationObject;
public class RequiredFieldValidator implements Validator {
public ValidationObject validate (Object obj) throws IllegalArgumentException {
ValidationObject vo = new ValidationObject();
if (obj==null || (obj instanceof String && ((String)obj).length()==0)) {
vo.setValid(false);
vo.setMessage("Please enter a value");
} else {
vo.setValid(true);
}
vo.setValidatedObject(obj);
return vo;
}
}

View file

@ -0,0 +1,41 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.validator.impl;
import java.util.Iterator;
import org.apache.jena.iri.IRI;
import org.apache.jena.iri.IRIFactory;
import org.apache.jena.iri.Violation;
import edu.cornell.mannlib.vedit.validator.ValidationObject;
import edu.cornell.mannlib.vedit.validator.Validator;
public class UrlValidator implements Validator {
public ValidationObject validate (Object obj) throws IllegalArgumentException {
ValidationObject vo = new ValidationObject();
if (!(obj instanceof String)){
throw new IllegalArgumentException("Expected instance of String");
}
IRIFactory factory = IRIFactory.jenaImplementation();
IRI iri = factory.create((String) obj);
if (iri.hasViolation(false) ) {
String errorStr = "";
Iterator<Violation> violIt = iri.violations(false);
while(violIt.hasNext()) {
errorStr += violIt.next().getShortMessage() + " ";
}
vo.setValid(false);
vo.setMessage("Please enter a valid URL. " + errorStr);
} else {
vo.setValid(true);
}
vo.setValidatedObject(obj);
return vo;
}
}

View file

@ -0,0 +1,53 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vedit.validator.impl;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import edu.cornell.mannlib.vedit.validator.Validator;
import edu.cornell.mannlib.vedit.validator.ValidationObject;
public class XMLNameValidator implements Validator {
private final static String ERR_MSG = "Must start with a letter or '_' and use only letters, digits, '.', '-' or '_'. No spaces allowed.";
Pattern pat = null;
boolean permitEmpty = false;
public XMLNameValidator() {
pat = Pattern.compile("[A-Za-z_][A-Za-z0-9_\\-\\.]*");
}
public XMLNameValidator(boolean permitEmpty) {
this();
this.permitEmpty = permitEmpty;
}
public ValidationObject validate (Object obj) throws IllegalArgumentException {
ValidationObject vo = new ValidationObject();
String theString = null;
try {
theString = (String) obj;
} catch (ClassCastException e) {
throw new IllegalArgumentException("Expected instance of String");
}
if (permitEmpty && (theString == null || "".equals(theString))) {
vo.setValid(true);
} else {
Matcher mat = pat.matcher(theString);
if (mat.matches()){
vo.setValid(true);
} else {
vo.setValid(false);
vo.setMessage(ERR_MSG);
}
}
vo.setValidatedObject(obj);
return vo;
}
}

View file

@ -0,0 +1,317 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.application;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess.WhichService.CONFIGURATION;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import com.hp.hpl.jena.ontology.OntDocumentManager;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.modules.Application;
import edu.cornell.mannlib.vitro.webapp.modules.ComponentStartupStatus;
import edu.cornell.mannlib.vitro.webapp.modules.fileStorage.FileStorage;
import edu.cornell.mannlib.vitro.webapp.modules.imageProcessor.ImageProcessor;
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
import edu.cornell.mannlib.vitro.webapp.modules.searchIndexer.SearchIndexer;
import edu.cornell.mannlib.vitro.webapp.modules.tboxreasoner.TBoxReasonerModule;
import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ConfigurationTripleSource;
import edu.cornell.mannlib.vitro.webapp.modules.tripleSource.ContentTripleSource;
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
import edu.cornell.mannlib.vitro.webapp.startup.ComponentStartupStatusImpl;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
import edu.cornell.mannlib.vitro.webapp.triplesource.impl.BasicCombinedTripleSource;
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation;
/**
* The basic implementation of the Application interface.
*/
public class ApplicationImpl implements Application {
// ----------------------------------------------------------------------
// The instance
// ----------------------------------------------------------------------
private ServletContext ctx;
private VitroHomeDirectory homeDirectory;
private SearchEngine searchEngine;
private SearchIndexer searchIndexer;
private ImageProcessor imageProcessor;
private FileStorage fileStorage;
private ContentTripleSource contentTripleSource;
private ConfigurationTripleSource configurationTripleSource;
private TBoxReasonerModule tboxReasonerModule;
public void setServletContext(ServletContext ctx) {
this.ctx = ctx;
}
@Override
public ServletContext getServletContext() {
return ctx;
}
@Override
public VitroHomeDirectory getHomeDirectory() {
return homeDirectory;
}
public void setHomeDirectory(VitroHomeDirectory homeDirectory) {
this.homeDirectory = homeDirectory;
}
@Override
public SearchEngine getSearchEngine() {
return searchEngine;
}
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchEngine")
public void setSearchEngine(SearchEngine se) {
if (searchEngine == null) {
searchEngine = se;
} else {
throw new IllegalStateException(
"Configuration includes multiple SearchEngine instances: "
+ searchEngine + ", and " + se);
}
}
@Override
public SearchIndexer getSearchIndexer() {
return searchIndexer;
}
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasSearchIndexer")
public void setSearchIndexer(SearchIndexer si) {
if (searchIndexer == null) {
searchIndexer = si;
} else {
throw new IllegalStateException(
"Configuration includes multiple SearchIndexer instances: "
+ searchIndexer + ", and " + si);
}
}
@Override
public ImageProcessor getImageProcessor() {
return imageProcessor;
}
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasImageProcessor")
public void setImageProcessor(ImageProcessor ip) {
if (imageProcessor == null) {
imageProcessor = ip;
} else {
throw new IllegalStateException(
"Configuration includes multiple ImageProcessor instances: "
+ imageProcessor + ", and " + ip);
}
}
@Override
public FileStorage getFileStorage() {
return fileStorage;
}
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasFileStorage")
public void setFileStorage(FileStorage fs) {
if (fileStorage == null) {
fileStorage = fs;
} else {
throw new IllegalStateException(
"Configuration includes multiple FileStorage instances: "
+ fileStorage + ", and " + fs);
}
}
@Override
public ContentTripleSource getContentTripleSource() {
return contentTripleSource;
}
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasContentTripleSource")
public void setContentTripleSource(ContentTripleSource source) {
if (contentTripleSource == null) {
contentTripleSource = source;
} else {
throw new IllegalStateException(
"Configuration includes multiple instances of ContentTripleSource: "
+ contentTripleSource + ", and " + source);
}
}
@Override
public ConfigurationTripleSource getConfigurationTripleSource() {
return configurationTripleSource;
}
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasConfigurationTripleSource")
public void setConfigurationTripleSource(ConfigurationTripleSource source) {
if (configurationTripleSource == null) {
configurationTripleSource = source;
} else {
throw new IllegalStateException(
"Configuration includes multiple instances of ConfigurationTripleSource: "
+ configurationTripleSource + ", and " + source);
}
}
@Override
public TBoxReasonerModule getTBoxReasonerModule() {
return tboxReasonerModule;
}
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTBoxReasonerModule")
public void setTBoxReasonerModule(TBoxReasonerModule module) {
if (tboxReasonerModule == null) {
tboxReasonerModule = module;
} else {
throw new IllegalStateException(
"Configuration includes multiple instances of TBoxReasonerModule: "
+ tboxReasonerModule + ", and " + module);
}
}
@Validation
public void validate() throws Exception {
if (searchEngine == null) {
throw new IllegalStateException(
"Configuration did not include a SearchEngine.");
}
if (searchIndexer == null) {
throw new IllegalStateException(
"Configuration did not include a SearchIndexer.");
}
if (imageProcessor == null) {
throw new IllegalStateException(
"Configuration did not include an ImageProcessor.");
}
if (fileStorage == null) {
throw new IllegalStateException(
"Configuration did not include a FileStorage.");
}
if (contentTripleSource == null) {
throw new IllegalStateException(
"Configuration did not include a ContentTripleSource.");
}
if (configurationTripleSource == null) {
throw new IllegalStateException(
"Configuration did not include a ConfigurationTripleSource.");
}
if (tboxReasonerModule == null) {
throw new IllegalStateException(
"Configuration did not include a TBoxReasonerModule.");
}
}
@Override
public void shutdown() {
// Nothing to do.
}
// ----------------------------------------------------------------------
// Setup the major components.
//
// This must happen after the ConfigurationProperties and some other stuff.
// ----------------------------------------------------------------------
public static class ComponentsSetup implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
Application app = ApplicationUtils.instance();
StartupStatus ss = StartupStatus.getBean(ctx);
ComponentStartupStatus css = new ComponentStartupStatusImpl(this,
ss);
SearchEngine searchEngine = app.getSearchEngine();
searchEngine.startup(app, css);
ss.info(this, "Started the SearchEngine: " + searchEngine);
ImageProcessor imageProcessor = app.getImageProcessor();
imageProcessor.startup(app, css);
ss.info(this, "Started the ImageProcessor: " + imageProcessor);
FileStorage fileStorage = app.getFileStorage();
fileStorage.startup(app, css);
ss.info(this, "Started the FileStorage system: " + fileStorage);
ContentTripleSource contentTripleSource = app
.getContentTripleSource();
contentTripleSource.startup(app, css);
ss.info(this, "Started the ContentTripleSource: "
+ contentTripleSource);
ConfigurationTripleSource configurationTripleSource = app
.getConfigurationTripleSource();
configurationTripleSource.startup(app, css);
ss.info(this, "Started the ConfigurationTripleSource: "
+ configurationTripleSource);
configureJena();
prepareCombinedTripleSource(app, ctx);
}
private void configureJena() {
// we do not want to fetch imports when we wrap Models in OntModels
OntDocumentManager.getInstance().setProcessImports(false);
}
private void prepareCombinedTripleSource(Application app,
ServletContext ctx) {
ContentTripleSource contentSource = app.getContentTripleSource();
ConfigurationTripleSource configurationSource = app
.getConfigurationTripleSource();
BasicCombinedTripleSource source = new BasicCombinedTripleSource(
contentSource, configurationSource);
RDFServiceUtils.setRDFServiceFactory(ctx,
contentSource.getRDFServiceFactory());
RDFServiceUtils.setRDFServiceFactory(ctx,
configurationSource.getRDFServiceFactory(), CONFIGURATION);
ModelAccess.setCombinedTripleSource(source);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
Application app = ApplicationUtils.instance();
app.getConfigurationTripleSource().shutdown(app);
app.getContentTripleSource().shutdown(app);
app.getFileStorage().shutdown(app);
app.getImageProcessor().shutdown(app);
app.getSearchEngine().shutdown(app);
}
}
// ----------------------------------------------------------------------
// Setup the reasoners.
//
// This must happen after the FileGraphSetup.
// ----------------------------------------------------------------------
public static class ReasonersSetup implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
Application app = ApplicationUtils.instance();
StartupStatus ss = StartupStatus.getBean(ctx);
ComponentStartupStatus css = new ComponentStartupStatusImpl(this,
ss);
TBoxReasonerModule tboxReasoner = app.getTBoxReasonerModule();
tboxReasoner.startup(app, css);
ss.info(this, "Started the TBoxReasonerModule: " + tboxReasoner);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
Application app = ApplicationUtils.instance();
app.getTBoxReasonerModule().shutdown(app);
}
}
}

View file

@ -0,0 +1,113 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.application;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
import edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoader;
import edu.cornell.mannlib.vitro.webapp.utils.configuration.ConfigurationBeanLoaderException;
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableModel;
/**
* Read the application setup file and create the components it describes.
*/
public class ApplicationSetup implements ServletContextListener {
private static final String APPLICATION_SETUP_PATH = "config/applicationSetup.n3";
private ServletContext ctx;
private StartupStatus ss;
private ApplicationImpl app;
private VitroHomeDirectory vitroHomeDir;
private Path configFile;
private LockableModel configModel;
private ConfigurationBeanLoader loader;
@Override
public void contextInitialized(ServletContextEvent sce) {
try {
this.ctx = sce.getServletContext();
this.ss = StartupStatus.getBean(ctx);
this.vitroHomeDir = VitroHomeDirectory.find(ctx);
ss.info(this, vitroHomeDir.getDiscoveryMessage());
locateApplicationConfigFile();
loadApplicationConfigFile();
createConfigurationBeanLoader();
instantiateTheApplication();
app.setServletContext(this.ctx);
app.setHomeDirectory(this.vitroHomeDir);
ApplicationUtils.setInstance(app);
ss.info(this, "Application is configured.");
} catch (Exception e) {
ss.fatal(this, "Failed to initialize the Application.", e);
}
}
private void locateApplicationConfigFile() {
Path path = this.vitroHomeDir.getPath().resolve(APPLICATION_SETUP_PATH);
if (!Files.exists(path)) {
throw new IllegalStateException("'" + path + "' does not exist.");
}
if (!Files.isReadable(path)) {
throw new IllegalStateException("Can't read '" + path + "'");
}
this.configFile = path;
}
private void loadApplicationConfigFile() {
try (InputStream in = Files.newInputStream(this.configFile)) {
Model m = ModelFactory.createDefaultModel();
m.read(in, null, "N3");
this.configModel = new LockableModel(m);
} catch (Exception e) {
throw new RuntimeException("Failed to read '" + this.configFile
+ "'", e);
}
}
private void createConfigurationBeanLoader() {
this.loader = new ConfigurationBeanLoader(configModel);
}
private void instantiateTheApplication() {
try {
Set<ApplicationImpl> apps = loader.loadAll(ApplicationImpl.class);
if (apps.isEmpty()) {
throw new IllegalStateException("'" + this.configFile
+ "' does not define an instance of "
+ ApplicationImpl.class.getName());
} else if (apps.size() > 1) {
throw new IllegalStateException("'" + this.configFile
+ "' defines " + apps.size() + " instances of "
+ ApplicationImpl.class.getName());
} else {
this.app = apps.iterator().next();
}
} catch (ConfigurationBeanLoaderException e) {
throw new IllegalStateException("Failed to setup the application",
e);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// Nothing to do.
}
}

View file

@ -0,0 +1,32 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.application;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.modules.Application;
/**
* Tools for working with the current Application instance.
*/
public class ApplicationUtils {
private static final Log log = LogFactory.getLog(ApplicationUtils.class);
private static volatile Application instance;
public static Application instance() {
try {
instance.getClass();
return instance;
} catch (NullPointerException e) {
log.error("Called for Application before it was available", e);
throw new IllegalStateException(
"Called for Application before it was available", e);
}
}
static void setInstance(Application application) {
instance = application;
}
}

View file

@ -0,0 +1,54 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.application;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Obtains and provides the contents of the build.properties file.
*/
public class BuildProperties {
private static final Log log = LogFactory.getLog(BuildProperties.class);
/** Path to the file of build properties baked into the webapp. */
public static final String WEBAPP_PATH_BUILD_PROPERTIES = "/WEB-INF/resources/build.properties";
private final Map<String, String> propertyMap;
public BuildProperties(ServletContext ctx) {
Map<String, String> map = new HashMap<>();
try (InputStream stream = ctx
.getResourceAsStream(WEBAPP_PATH_BUILD_PROPERTIES)) {
if (stream == null) {
log.debug("Didn't find a resource at '"
+ WEBAPP_PATH_BUILD_PROPERTIES + "'.");
} else {
Properties props = new Properties();
props.load(stream);
for (String key : props.stringPropertyNames()) {
map.put(key, props.getProperty(key));
}
}
} catch (IOException e) {
throw new RuntimeException("Failed to load from '"
+ WEBAPP_PATH_BUILD_PROPERTIES + "'.", e);
}
propertyMap = Collections.unmodifiableMap(map);
}
public Map<String, String> getMap() {
return this.propertyMap;
}
}

View file

@ -0,0 +1,213 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.application;
import static edu.cornell.mannlib.vitro.webapp.application.BuildProperties.WEBAPP_PATH_BUILD_PROPERTIES;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.naming.InitialContext;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Encapsulates some of the info relating to the Vitro home directory.
*/
public class VitroHomeDirectory {
private static final Log log = LogFactory.getLog(VitroHomeDirectory.class);
public static VitroHomeDirectory find(ServletContext ctx) {
HomeDirectoryFinder finder = new HomeDirectoryFinder(ctx);
return new VitroHomeDirectory(ctx, finder.getPath(),
finder.getMessage());
}
private final ServletContext ctx;
private final Path path;
private final String discoveryMessage;
public VitroHomeDirectory(ServletContext ctx, Path path,
String discoveryMessage) {
this.ctx = ctx;
this.path = path;
this.discoveryMessage = discoveryMessage;
}
public ServletContext getCtx() {
return ctx;
}
public Path getPath() {
return path;
}
public String getDiscoveryMessage() {
return discoveryMessage;
}
/**
* Find something that specifies the location of the Vitro home directory.
* Look in the JDNI environment, the system properties, and the
* build.properties file.
*
* If we don't find it, fail. If we find it more than once, use the first
* one (with a warning). If it is not an existing, readable directory, fail.
*/
private static class HomeDirectoryFinder {
/** JNDI path that defines the Vitro home directory */
private static final String VHD_JNDI_PATH = "java:comp/env/vitro/home";
/** System property that defines the Vitro home directory */
private static final String VHD_SYSTEM_PROPERTY = "vitro.home";
/** build.properties property that defines the Vitro home directory */
private static final String VHD_BUILD_PROPERTY = "vitro.home";
private final ServletContext ctx;
private final List<Found> foundLocations = new ArrayList<>();
public HomeDirectoryFinder(ServletContext ctx) {
this.ctx = ctx;
getVhdFromJndi();
getVhdFromSystemProperties();
getVhdFromBuildProperties();
confirmExactlyOneResult();
confirmValidDirectory();
}
public String getMessage() {
return foundLocations.get(0).getMessage();
}
public Path getPath() {
return foundLocations.get(0).getPath();
}
public void getVhdFromJndi() {
try {
String vhdPath = (String) new InitialContext()
.lookup(VHD_JNDI_PATH);
if (vhdPath == null) {
log.debug("Didn't find a JNDI value at '" + VHD_JNDI_PATH
+ "'.");
} else {
log.debug("'" + VHD_JNDI_PATH + "' as specified by JNDI: "
+ vhdPath);
String message = String.format(
"JNDI environment '%s' was set to '%s'",
VHD_JNDI_PATH, vhdPath);
foundLocations.add(new Found(Paths.get(vhdPath), message));
}
} catch (Exception e) {
log.debug("JNDI lookup failed. " + e);
}
}
private void getVhdFromSystemProperties() {
String vhdPath = System.getProperty(VHD_SYSTEM_PROPERTY);
if (vhdPath == null) {
log.debug("Didn't find a system property value at '"
+ VHD_SYSTEM_PROPERTY + "'.");
} else {
log.debug("'" + VHD_SYSTEM_PROPERTY
+ "' as specified by system property: " + vhdPath);
String message = String.format(
"System property '%s' was set to '%s'",
VHD_SYSTEM_PROPERTY, vhdPath);
foundLocations.add(new Found(Paths.get(vhdPath), message));
}
}
private void getVhdFromBuildProperties() {
try {
Map<String, String> buildProps = new BuildProperties(ctx)
.getMap();
String vhdPath = buildProps.get(VHD_BUILD_PROPERTY);
if (vhdPath == null) {
log.debug("build properties doesn't contain a value for '"
+ VHD_BUILD_PROPERTY + "'.");
} else {
log.debug("'" + VHD_BUILD_PROPERTY
+ "' as specified by build.properties: " + vhdPath);
String message = String.format(
"In resource '%s', '%s' was set to '%s'.",
WEBAPP_PATH_BUILD_PROPERTIES, VHD_BUILD_PROPERTY,
vhdPath);
foundLocations.add(new Found(Paths.get(vhdPath), message));
}
} catch (Exception e) {
log.warn("Reading build properties failed. " + e);
}
}
private void confirmExactlyOneResult() {
if (foundLocations.isEmpty()) {
String message = String.format("Can't find a value "
+ "for the Vitro home directory. "
+ "Looked in JNDI environment at '%s'. "
+ "Looked for a system property named '%s'. "
+ "Looked in 'WEB-INF/resources/build.properties' "
+ "for '%s'.", VHD_JNDI_PATH, VHD_SYSTEM_PROPERTY,
VHD_BUILD_PROPERTY);
throw new IllegalStateException(message);
} else if (foundLocations.size() > 1) {
String message = String.format("Found multiple values for the "
+ "Vitro home directory: " + foundLocations);
log.warn(message);
}
}
private void confirmValidDirectory() {
Path vhd = getPath();
if (!Files.exists(vhd)) {
throw new IllegalStateException("Vitro home directory '" + vhd
+ "' does not exist.");
}
if (!Files.isDirectory(vhd)) {
throw new IllegalStateException("Vitro home directory '" + vhd
+ "' is not a directory.");
}
if (!Files.isReadable(vhd)) {
throw new IllegalStateException(
"Cannot read Vitro home directory '" + vhd + "'.");
}
if (!Files.isWritable(vhd)) {
throw new IllegalStateException(
"Can't write to Vitro home directory: '" + vhd + "'.");
}
}
/** We found it: where and how. */
private static class Found {
private final Path path;
private final String message;
public Found(Path path, String message) {
this.path = path;
this.message = message;
}
public Path getPath() {
return path;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return "Found[path=" + path + ", message=" + message + "]";
}
}
}
}

View file

@ -0,0 +1,163 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.http.HttpServletRequest;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
/**
* Keep a list of the active IdentifierBundleFactories in the context.
*/
public class ActiveIdentifierBundleFactories {
private static final String ATTRIBUTE_ACTIVE_FACTORIES = ActiveIdentifierBundleFactories.class
.getName();
// ----------------------------------------------------------------------
// static methods
// ----------------------------------------------------------------------
/**
* Add a new IdentifierBundleFactory to the list.
*/
public static void addFactory(ServletContextEvent sce,
IdentifierBundleFactory factory) {
if (sce == null) {
throw new NullPointerException("sce may not be null.");
}
if (factory == null) {
throw new NullPointerException("factory may not be null.");
}
addFactory(sce.getServletContext(), factory);
}
/**
* Add a new IdentifierBundleFactory to the list.
*/
public static void addFactory(ServletContext ctx,
IdentifierBundleFactory factory) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
if (factory == null) {
throw new NullPointerException("factory may not be null.");
}
getActiveFactories(ctx).addFactory(factory);
}
/**
* Just for diagnostics. Don't expose the factories themselves, only their
* names.
*/
public static List<String> getFactoryNames(ServletContext ctx) {
List<String> names = new ArrayList<String>();
ActiveIdentifierBundleFactories actFact = getActiveFactories(ctx);
for (IdentifierBundleFactory factory : actFact.factories) {
names.add(factory.toString());
}
return names;
}
/**
* Get the Identifiers from the list of factories. This might return an
* empty bundle, but it never returns null.
*
* This is package access, and should only be called by RequestIdentifiers.
* Everyone else should ask RequestIdentifiers to fetch them from the
* request.
*/
static IdentifierBundle getIdentifierBundle(HttpServletRequest request) {
return getActiveFactories(request).getBundleForRequest(request);
}
/**
* Get the Identifiers that would be created if this user were to log in.
*/
public static IdentifierBundle getUserIdentifierBundle(
HttpServletRequest request, UserAccount userAccount) {
return getActiveFactories(request).getBundleForUser(userAccount);
}
/**
* Get the singleton instance from the servlet context. If there isn't one,
* create one. This never returns null.
*/
private static ActiveIdentifierBundleFactories getActiveFactories(
HttpServletRequest req) {
if (req == null) {
throw new NullPointerException("req may not be null.");
}
return getActiveFactories(req.getSession().getServletContext());
}
/**
* Get the singleton instance from the servlet context. If there isn't one,
* create one. This never returns null.
*/
private static ActiveIdentifierBundleFactories getActiveFactories(
ServletContext ctx) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
Object obj = ctx.getAttribute(ATTRIBUTE_ACTIVE_FACTORIES);
if (obj == null) {
obj = new ActiveIdentifierBundleFactories();
ctx.setAttribute(ATTRIBUTE_ACTIVE_FACTORIES, obj);
}
if (!(obj instanceof ActiveIdentifierBundleFactories)) {
throw new IllegalStateException("Expected to find an instance of "
+ ActiveIdentifierBundleFactories.class.getName()
+ " in the context, but found an instance of "
+ obj.getClass().getName() + " instead.");
}
return (ActiveIdentifierBundleFactories) obj;
}
// ----------------------------------------------------------------------
// the instance
// ----------------------------------------------------------------------
private final List<IdentifierBundleFactory> factories = new ArrayList<IdentifierBundleFactory>();
private void addFactory(IdentifierBundleFactory factory) {
factories.add(factory);
}
/**
* Run through the active factories and get all Identifiers for this
* request.
*/
private IdentifierBundle getBundleForRequest(HttpServletRequest request) {
IdentifierBundle ib = new ArrayIdentifierBundle();
for (IdentifierBundleFactory ibf : factories) {
ib.addAll(ibf.getIdentifierBundle(request));
}
return ib;
}
/**
* Get all Identifiers that would be created if this User logged in.
*/
private IdentifierBundle getBundleForUser(UserAccount userAccount) {
IdentifierBundle ib = new ArrayIdentifierBundle();
for (IdentifierBundleFactory ibf : factories) {
if (ibf instanceof UserBasedIdentifierBundleFactory) {
UserBasedIdentifierBundleFactory ubibf = (UserBasedIdentifierBundleFactory) ibf;
ib.addAll(ubibf.getIdentifierBundleForUser(userAccount));
}
}
return ib;
}
}

View file

@ -0,0 +1,21 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
/**
* Most common implementation of a List of Identifiers (IdentifierBundle).
*/
public class ArrayIdentifierBundle extends ArrayList<Identifier> implements
IdentifierBundle {
public ArrayIdentifierBundle(Collection<? extends Identifier> ids) {
super(ids);
}
public ArrayIdentifierBundle(Identifier... ids) {
this(Arrays.asList(ids));
}
}

View file

@ -0,0 +1,30 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier;
/**
* Indicates who the user is and what roles/groups they belong to.
* The objects returned by this could be anything. For example, RoleBacedPolicy
* looks for RoleBacedPolicy.AuthRole objects.
*
* This is a marker interface to indicate that a object is an identifier,
* implementations of Identifier may provide any sort of identifying functionality or
* methods.
*
* <h3>Justification for a methodless interface</h3>
* This is better than using Object since having method signatures that have
* Identifier at least indicates the intent of the parameter, even if it is the
* same to the compiler.
*
* Policy objects are expected to examine the IdentiferBundle to find the
* information needed to make a decision. There is no set pattern as to
* what will and will not be a configuration of Identifiers that will create
* a AUTHORIZED decision. Reflection, Pattern Matching or something similar
* will be needed.
*
* We have no compile time information about what will structures will map
* to which Authorization, let's not pretend that we do.
*/
public interface Identifier {
}

View file

@ -0,0 +1,13 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier;
import java.util.List;
/**
* A group of Identifiers, very commonly used in method signatures
* since a session will usually have more than one associated identifier.
*/
public interface IdentifierBundle extends List <Identifier>{
/* this is just typed List, and just barely. */
}

View file

@ -0,0 +1,17 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier;
import javax.servlet.http.HttpServletRequest;
/**
* Creates an IdentifierBundle for a ServletRequest/HttpSession. Useful for
* getting the identifiers that should be associated with a request.
*/
public interface IdentifierBundleFactory {
/**
* Return the IdentifierBundle from this factory. May return an empty
* bundle, but never returns null.
*/
public IdentifierBundle getIdentifierBundle(HttpServletRequest request);
}

View file

@ -0,0 +1,56 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
/**
* Build a list of Identifiers that apply to the current request and cache them
* in the request.
*/
public class RequestIdentifiers {
private static final String ATTRIBUTE_ID_BUNDLE = RequestIdentifiers.class
.getName();
// ----------------------------------------------------------------------
// static methods
// ----------------------------------------------------------------------
/**
* If the currently applicable Identifiers have been cached in the request,
* get them. If not, assemble them from the active factories, and cache them
* in the request.
*
* This method might return an empty bundle, but it never returns null.
*/
public static IdentifierBundle getIdBundleForRequest(ServletRequest request) {
if (!(request instanceof HttpServletRequest)) {
return new ArrayIdentifierBundle();
}
HttpServletRequest hreq = (HttpServletRequest) request;
Object obj = hreq.getAttribute(ATTRIBUTE_ID_BUNDLE);
if (obj == null) {
obj = ActiveIdentifierBundleFactories.getIdentifierBundle(hreq);
hreq.setAttribute(ATTRIBUTE_ID_BUNDLE, obj);
}
if (!(obj instanceof IdentifierBundle)) {
throw new IllegalStateException("Expected to find an instance of "
+ IdentifierBundle.class.getName()
+ " in the request, but found an instance of "
+ obj.getClass().getName() + " instead.");
}
return (IdentifierBundle) obj;
}
/**
* The login status has changed, so discard the cached Identifiers.
*/
public static void resetIdentifiers(ServletRequest request) {
request.removeAttribute(ATTRIBUTE_ID_BUNDLE);
}
}

View file

@ -0,0 +1,27 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier;
public abstract class RoleIdentifier implements Identifier {
public abstract String getRole();
public abstract String getUri();
public static String getUri( Identifier id){
if( id == null ) return null;
if( id instanceof RoleIdentifier ){
return ((RoleIdentifier)id).getUri();
}else{
return null;
}
}
public static String getUri( IdentifierBundle idb){
for( Identifier id : idb ){
if (id instanceof RoleIdentifier) {
RoleIdentifier roleId = (RoleIdentifier) id;
return roleId.getUri();
}
}
return null;
}
}

View file

@ -0,0 +1,18 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
/**
* Creates an IdentifierBundle based only on the characteristics of the current
* user, without considering other aspects of the current request.
*/
public interface UserBasedIdentifierBundleFactory extends
IdentifierBundleFactory {
/**
* Get the IdentifierBundle for this user. If user is null, return an empty
* bundle. Never returns null.
*/
public IdentifierBundle getIdentifierBundleForUser(UserAccount user);
}

View file

@ -0,0 +1,36 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.common;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.Identifier;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
/**
* A base class for the Identifiers created by the
* CommonIdentifierBundleFactory.
*/
public abstract class AbstractCommonIdentifier {
/**
* Get all of the instances of this class of Identifier from this bundle.
*/
protected static <T extends Identifier> Collection<T> getIdentifiersForClass(
IdentifierBundle ids, Class<T> clazz) {
if ((ids == null) || (clazz == null)) {
return Collections.emptySet();
}
Set<T> set = new HashSet<T>();
for (Identifier id : ids) {
if (clazz.isAssignableFrom(id.getClass())) {
set.add(clazz.cast(id));
}
}
return set;
}
}

View file

@ -0,0 +1,45 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.common;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.Identifier;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
/**
* The current user is associated with this Individual page, and has editing
* rights relating to it.
*
* Subclasses exist to indicate how that association is created, as either a
* Self-Editor or a Proxy Editor. In some cases (e.g., the MyProfile link) the
* distinction is important.
*/
public abstract class HasAssociatedIndividual extends AbstractCommonIdentifier
implements Identifier {
private static Collection<HasAssociatedIndividual> getIdentifiers(
IdentifierBundle ids) {
return getIdentifiersForClass(ids, HasAssociatedIndividual.class);
}
public static Collection<String> getIndividualUris(IdentifierBundle ids) {
Set<String> set = new HashSet<String>();
for (HasAssociatedIndividual id : getIdentifiers(ids)) {
set.add(id.getAssociatedIndividualUri());
}
return set;
}
private final String associatedIndividualUri;
public HasAssociatedIndividual(String associatedIndividualUri) {
this.associatedIndividualUri = associatedIndividualUri;
}
public String getAssociatedIndividualUri() {
return associatedIndividualUri;
}
}

View file

@ -0,0 +1,72 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.common;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.Identifier;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.permissions.Permission;
/**
* The current user has this Permission, through one or more PermissionSets.
*/
public class HasPermission extends AbstractCommonIdentifier implements
Identifier, Comparable<HasPermission> {
public static Collection<HasPermission> getIdentifiers(IdentifierBundle ids) {
return getIdentifiersForClass(ids, HasPermission.class);
}
public static Collection<Permission> getPermissions(IdentifierBundle ids) {
Set<Permission> set = new HashSet<Permission>();
for (HasPermission id : getIdentifiers(ids)) {
set.add(id.getPermission());
}
return set;
}
private final Permission permission; // never null
public HasPermission(Permission permission) {
if (permission == null) {
throw new NullPointerException("permission may not be null.");
}
this.permission = permission;
}
public Permission getPermission() {
return permission;
}
@Override
public String toString() {
return "HasPermission[" + permission + "]";
}
@Override
public int hashCode() {
return permission.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof HasPermission)) {
return false;
}
HasPermission that = (HasPermission) obj;
return this.permission.equals(that.permission);
}
@Override
public int compareTo(HasPermission that) {
return this.permission.compareTo(that.permission);
}
}

View file

@ -0,0 +1,81 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.common;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.Identifier;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet;
/**
* The current user has this Permission, through one or more PermissionSets.
*/
public class HasPermissionSet extends AbstractCommonIdentifier implements
Identifier, Comparable<HasPermissionSet> {
public static Collection<HasPermissionSet> getIdentifiers(IdentifierBundle ids) {
return getIdentifiersForClass(ids, HasPermissionSet.class);
}
public static Collection<PermissionSet> getPermissionSets(IdentifierBundle ids) {
Set<PermissionSet> set = new HashSet<>();
for (HasPermissionSet id : getIdentifiers(ids)) {
set.add(id.getPermissionSet());
}
return set;
}
public static Collection<String> getPermissionSetUris(IdentifierBundle ids) {
Set<String> set = new HashSet<>();
for (HasPermissionSet id : getIdentifiers(ids)) {
set.add(id.getPermissionSet().getUri());
}
return set;
}
private final PermissionSet permissionSet; // never null
public HasPermissionSet(PermissionSet permissionSet) {
if (permissionSet == null) {
throw new NullPointerException("permissionSet may not be null.");
}
this.permissionSet = permissionSet;
}
public PermissionSet getPermissionSet() {
return permissionSet;
}
@Override
public String toString() {
return "HasPermissionSet[" + permissionSet.getLabel() + "]";
}
@Override
public int hashCode() {
return permissionSet.getUri().hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof HasPermissionSet)) {
return false;
}
HasPermissionSet that = (HasPermissionSet) obj;
return this.permissionSet.getUri().equals(that.permissionSet.getUri());
}
@Override
public int compareTo(HasPermissionSet that) {
return this.permissionSet.getUri().compareTo(
that.permissionSet.getUri());
}
}

View file

@ -0,0 +1,41 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.common;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
/**
* The current user has this Individual page as their profile, and has
* self-editing rights relating to it.
*/
public class HasProfile extends HasAssociatedIndividual {
private static Collection<HasProfile> getIdentifiers(IdentifierBundle ids) {
return getIdentifiersForClass(ids, HasProfile.class);
}
public static Collection<String> getProfileUris(IdentifierBundle ids) {
Set<String> set = new HashSet<String>();
for (HasProfile id : getIdentifiers(ids)) {
set.add(id.getAssociatedIndividualUri());
}
return set;
}
public HasProfile(String associatedIndividualUri) {
super(associatedIndividualUri);
}
public String getProfileUri() {
return getAssociatedIndividualUri();
}
@Override
public String toString() {
return "HasProfile[" + getAssociatedIndividualUri() + "]";
}
}

View file

@ -0,0 +1,41 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.common;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
/**
* The current user has a Proxy relationship to this Individual page, and has
* proxy editing rights relating to it.
*/
public class HasProxyEditingRights extends HasAssociatedIndividual {
private static Collection<HasProxyEditingRights> getIdentifiers(IdentifierBundle ids) {
return getIdentifiersForClass(ids, HasProxyEditingRights.class);
}
public static Collection<String> getProxiedPageUris(IdentifierBundle ids) {
Set<String> set = new HashSet<String>();
for (HasProxyEditingRights id : getIdentifiers(ids)) {
set.add(id.getAssociatedIndividualUri());
}
return set;
}
public HasProxyEditingRights(String associatedIndividualUri) {
super(associatedIndividualUri);
}
public String getProxiedPageUri() {
return getAssociatedIndividualUri();
}
@Override
public String toString() {
return "HasProxyEditingRights[" + getAssociatedIndividualUri() + "]";
}
}

View file

@ -0,0 +1,232 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.common;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletContext;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.RDFNode;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.Identifier;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
/**
* The current user is blacklisted for this reason.
*/
public class IsBlacklisted extends AbstractCommonIdentifier implements
Identifier {
private static final Log log = LogFactory.getLog(IsBlacklisted.class);
private final static String BLACKLIST_SPARQL_DIR = "/admin/selfEditBlacklist";
private static final String NOT_BLACKLISTED = null;
// ----------------------------------------------------------------------
// static methods
// ----------------------------------------------------------------------
/**
* If this individual is blacklisted, return an appropriate Identifier.
* Otherwise, return null.
*/
public static IsBlacklisted getInstance(Individual individual,
ServletContext context) {
if (individual == null) {
throw new NullPointerException("individual may not be null.");
}
if (context == null) {
throw new NullPointerException("context may not be null.");
}
String reasonForBlacklisting = checkForBlacklisted(individual, context);
IsBlacklisted id = new IsBlacklisted(individual.getURI(),
reasonForBlacklisting);
if (id.isBlacklisted()) {
return id;
} else {
return null;
}
}
/**
* Runs through .sparql files in the BLACKLIST_SPARQL_DIR.
*
* The first that returns one or more rows will be cause the user to be
* blacklisted.
*
* The first variable from the first solution set will be returned.
*/
private static String checkForBlacklisted(Individual ind,
ServletContext context) {
String realPath = context.getRealPath(BLACKLIST_SPARQL_DIR);
File blacklistDir = new File(realPath);
if (!blacklistDir.isDirectory() || !blacklistDir.canRead()) {
log.debug("cannot read blacklist directory " + realPath);
return NOT_BLACKLISTED;
}
log.debug("checking directlry " + realPath
+ " for blacklisting sparql query files");
File[] files = blacklistDir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".sparql");
}
});
String reasonForBlacklist = NOT_BLACKLISTED;
for (File file : files) {
try {
reasonForBlacklist = runSparqlFileForBlacklist(file, ind,
context);
if (reasonForBlacklist != NOT_BLACKLISTED)
break;
} catch (RuntimeException ex) {
log.error(
"Could not run blacklist check query for file "
+ file.getAbsolutePath() + File.separatorChar
+ file.getName(), ex);
}
}
return reasonForBlacklist;
}
/**
* Runs the SPARQL query in the file with the uri of the individual
* substituted in.
*
* The URI of ind will be substituted into the query where ever the token
* "?individualURI" is found.
*
* If there are any solution sets, then the URI of the variable named
* "cause" will be returned. Make sure that it is a resource with a URI.
* Otherwise null will be returned.
*/
private static String runSparqlFileForBlacklist(File file, Individual ind,
ServletContext context) {
if (!file.canRead()) {
log.debug("cannot read blacklisting SPARQL file " + file.getName());
return NOT_BLACKLISTED;
}
String queryString = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
byte b[] = new byte[fis.available()];
fis.read(b);
queryString = new String(b);
} catch (IOException ioe) {
log.debug(ioe);
return NOT_BLACKLISTED;
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
log.warn("could not close file", e);
}
}
}
if (StringUtils.isEmpty(queryString)) {
log.debug(file.getName() + " is empty");
return NOT_BLACKLISTED;
}
OntModel model = ModelAccess.on(context).getOntModel();
queryString = queryString.replaceAll("\\?individualURI",
"<" + ind.getURI() + ">");
log.debug(queryString);
Query query = QueryFactory.create(queryString);
QueryExecution qexec = QueryExecutionFactory.create(query, model);
try {
ResultSet results = qexec.execSelect();
while (results.hasNext()) {
QuerySolution solution = results.nextSolution();
if (solution.contains("cause")) {
RDFNode node = solution.get("cause");
if (node.isResource()) {
return node.asResource().getURI();
} else if (node.isLiteral()) {
return node.asLiteral().getString();
}
} else {
log.error("Query solution must contain a variable "
+ "\"cause\" of type Resource or Literal.");
return NOT_BLACKLISTED;
}
}
} finally {
qexec.close();
}
return NOT_BLACKLISTED;
}
public static Collection<IsBlacklisted> getIdentifiers(IdentifierBundle ids) {
return getIdentifiersForClass(ids, IsBlacklisted.class);
}
public static Collection<String> getBlacklistReasons(IdentifierBundle ids) {
Set<String> set = new HashSet<String>();
for (IsBlacklisted id : getIdentifiers(ids)) {
if (id.isBlacklisted()) {
set.add(id.getReasonForBlacklisting());
}
}
return set;
}
// ----------------------------------------------------------------------
// the Identifier
// ----------------------------------------------------------------------
private final String associatedIndividualUri;
private final String reasonForBlacklisting;
public IsBlacklisted(String associatedIndividualUri,
String reasonForBlacklisting) {
this.associatedIndividualUri = associatedIndividualUri;
this.reasonForBlacklisting = reasonForBlacklisting;
}
public String getAssociatedIndividualUri() {
return associatedIndividualUri;
}
public boolean isBlacklisted() {
return reasonForBlacklisting != NOT_BLACKLISTED;
}
public String getReasonForBlacklisting() {
return reasonForBlacklisting;
}
@Override
public String toString() {
return "IsBlacklisted[" + associatedIndividualUri + ", "
+ reasonForBlacklisting + "]";
}
}

View file

@ -0,0 +1,28 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.common;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.Identifier;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
/**
* The current user is a root user.
*/
public class IsRootUser extends AbstractCommonIdentifier implements Identifier {
public static final IsRootUser INSTANCE = new IsRootUser();
public static boolean isRootUser(IdentifierBundle ids) {
return !getIdentifiersForClass(ids, IsRootUser.class).isEmpty();
}
/** Enforce the singleton pattern. */
private IsRootUser() {
// Nothing to initialize.
}
@Override
public String toString() {
return "IsRootUser";
}
}

View file

@ -0,0 +1,66 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.common;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.Identifier;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
/**
* The current user has this URI.
*/
public class IsUser extends AbstractCommonIdentifier implements Identifier {
public static Collection<IsUser> getIdentifiers(IdentifierBundle ids) {
return getIdentifiersForClass(ids, IsUser.class);
}
public static Collection<String> getUserUris(IdentifierBundle ids) {
Set<String> set = new HashSet<String>();
for (IsUser id : getIdentifiers(ids)) {
set.add(id.getUri());
}
return set;
}
private final String uri; // never null
public IsUser(String uri) {
if (uri == null) {
throw new NullPointerException("uri may not be null.");
}
this.uri = uri;
}
public String getUri() {
return uri;
}
@Override
public int hashCode() {
return uri.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof IsUser)) {
return false;
}
IsUser that = (IsUser) obj;
return this.uri.equals(that.uri);
}
@Override
public String toString() {
return "IsUser[" + uri + "]";
}
}

View file

@ -0,0 +1,38 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.factory;
import javax.servlet.ServletContext;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundleFactory;
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
/**
* Some fields and methods that are helpful to IdentifierBundleFactory classes.
*/
public abstract class BaseIdentifierBundleFactory implements
IdentifierBundleFactory {
protected final ServletContext ctx;
protected final WebappDaoFactory wdf;
protected final UserAccountsDao uaDao;
protected final IndividualDao indDao;
public BaseIdentifierBundleFactory(ServletContext ctx) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
this.ctx = ctx;
this.wdf = ModelAccess.on(ctx).getWebappDaoFactory();
this.uaDao = wdf.getUserAccountsDao();
this.indDao = wdf.getIndividualDao();
}
@Override
public String toString() {
return this.getClass().getSimpleName() + " - " + hashCode();
}
}

View file

@ -0,0 +1,32 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.factory;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.UserBasedIdentifierBundleFactory;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
/**
* Some fields and methods that are helpful to IdentifierBundleFactory classes.
*/
public abstract class BaseUserBasedIdentifierBundleFactory extends
BaseIdentifierBundleFactory implements UserBasedIdentifierBundleFactory {
public BaseUserBasedIdentifierBundleFactory(ServletContext ctx) {
super(ctx);
}
@Override
public final IdentifierBundle getIdentifierBundle(HttpServletRequest request) {
return getIdentifierBundleForUser(LoginStatusBean
.getCurrentUser(request));
}
@Override
public abstract IdentifierBundle getIdentifierBundleForUser(UserAccount user);
}

View file

@ -0,0 +1,90 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.factory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ArrayIdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasPermission;
import edu.cornell.mannlib.vitro.webapp.auth.permissions.Permission;
import edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionRegistry;
import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
/**
* Figure out what Permissions the user is entitled to have.
*/
public class HasPermissionFactory extends BaseUserBasedIdentifierBundleFactory {
private static final Log log = LogFactory
.getLog(HasPermissionFactory.class);
public HasPermissionFactory(ServletContext ctx) {
super(ctx);
}
@Override
public IdentifierBundle getIdentifierBundleForUser(UserAccount user) {
if (user == null) {
return createPublicPermissions();
} else {
return createUserPermissions(user);
}
}
private IdentifierBundle createPublicPermissions() {
Set<String> permissionUris = new HashSet<String>();
for (PermissionSet ps : uaDao.getAllPermissionSets()) {
if (ps.isForPublic()) {
permissionUris.addAll(ps.getPermissionUris());
}
}
log.debug("Permission URIs: " + permissionUris);
return new ArrayIdentifierBundle(
getIdentifiersFromPermissions(getPermissionsForUris(permissionUris)));
}
private IdentifierBundle createUserPermissions(UserAccount user) {
Set<String> permissionUris = new HashSet<String>();
for (String psUri : user.getPermissionSetUris()) {
PermissionSet ps = uaDao.getPermissionSetByUri(psUri);
if (ps != null) {
permissionUris.addAll(ps.getPermissionUris());
}
}
log.debug("user permission sets: " + user.getPermissionSetUris());
log.debug("Permission URIs: " + permissionUris);
return new ArrayIdentifierBundle(
getIdentifiersFromPermissions(getPermissionsForUris(permissionUris)));
}
private Collection<Permission> getPermissionsForUris(
Collection<String> permissionUris) {
List<Permission> permissions = new ArrayList<Permission>();
PermissionRegistry registry = PermissionRegistry.getRegistry(ctx);
for (String uri : permissionUris) {
permissions.add(registry.getPermission(uri));
}
return permissions;
}
private List<HasPermission> getIdentifiersFromPermissions(
Collection<Permission> permissions) {
List<HasPermission> ids = new ArrayList<HasPermission>();
for (Permission permission : permissions) {
ids.add(new HasPermission(permission));
}
return ids;
}
}

View file

@ -0,0 +1,42 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.factory;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ArrayIdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasPermissionSet;
import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
/**
* Figure out what PermissionSets the user is entitled to have.
*/
public class HasPermissionSetFactory extends
BaseUserBasedIdentifierBundleFactory {
private static final Log log = LogFactory
.getLog(HasPermissionFactory.class);
public HasPermissionSetFactory(ServletContext ctx) {
super(ctx);
}
@Override
public IdentifierBundle getIdentifierBundleForUser(UserAccount user) {
IdentifierBundle ids = new ArrayIdentifierBundle();
if (user != null) {
for (String psUri : user.getPermissionSetUris()) {
PermissionSet ps = uaDao.getPermissionSetByUri(psUri);
if (ps != null) {
ids.add(new HasPermissionSet(ps));
}
}
}
return ids;
}
}

View file

@ -0,0 +1,68 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.factory;
import java.util.ArrayList;
import java.util.Collection;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ArrayIdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.Identifier;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasProfile;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.IsBlacklisted;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.SelfEditingConfiguration;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
/**
* Find all of the individuals that are associated with the current user, and
* create either an IsBlacklisted or HasAssociatedIndividual for each one.
*/
public class HasProfileOrIsBlacklistedFactory extends
BaseUserBasedIdentifierBundleFactory {
private static final Log log = LogFactory
.getLog(HasProfileOrIsBlacklistedFactory.class);
public HasProfileOrIsBlacklistedFactory(ServletContext ctx) {
super(ctx);
}
@Override
public IdentifierBundle getIdentifierBundleForUser(UserAccount user) {
ArrayIdentifierBundle ids = new ArrayIdentifierBundle();
for (Individual ind : getAssociatedIndividuals(user)) {
// If they are blacklisted, this factory will return an identifier
Identifier id = IsBlacklisted.getInstance(ind, ctx);
if (id != null) {
ids.add(id);
} else {
ids.add(new HasProfile(ind.getURI()));
}
}
return ids;
}
/**
* Get all Individuals associated with the current user as SELF.
*/
private Collection<Individual> getAssociatedIndividuals(UserAccount user) {
Collection<Individual> individuals = new ArrayList<Individual>();
if (user == null) {
log.debug("No Associated Individuals: not logged in.");
return individuals;
}
SelfEditingConfiguration sec = SelfEditingConfiguration.getBean(ctx);
individuals.addAll(sec.getAssociatedIndividuals(indDao, user));
return individuals;
}
}

View file

@ -0,0 +1,35 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.factory;
import javax.servlet.ServletContext;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ArrayIdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasProxyEditingRights;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
/**
* Find out what Profiles the User can edit through proxy.
*/
public class HasProxyEditingRightsFactory extends
BaseUserBasedIdentifierBundleFactory {
public HasProxyEditingRightsFactory(ServletContext ctx) {
super(ctx);
}
@Override
public IdentifierBundle getIdentifierBundleForUser(UserAccount user) {
ArrayIdentifierBundle ids = new ArrayIdentifierBundle();
if (user != null) {
for (String proxiedUri : user.getProxiedIndividualUris()) {
ids.add(new HasProxyEditingRights(proxiedUri));
}
}
return ids;
}
}

View file

@ -0,0 +1,30 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.factory;
import javax.servlet.ServletContext;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ArrayIdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.IsRootUser;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
/**
* If the user is logged in as a Root User, create an identifier.
*/
public class IsRootUserFactory extends BaseUserBasedIdentifierBundleFactory {
public IsRootUserFactory(ServletContext ctx) {
super(ctx);
}
@Override
public IdentifierBundle getIdentifierBundleForUser(UserAccount user) {
if ((user != null) && user.isRootUser()) {
return new ArrayIdentifierBundle(IsRootUser.INSTANCE);
} else {
return new ArrayIdentifierBundle();
}
}
}

View file

@ -0,0 +1,30 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.identifier.factory;
import javax.servlet.ServletContext;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ArrayIdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.IsUser;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
/**
* If the user is logged in, create an Identifier.
*/
public class IsUserFactory extends BaseUserBasedIdentifierBundleFactory {
public IsUserFactory(ServletContext ctx) {
super(ctx);
}
@Override
public IdentifierBundle getIdentifierBundleForUser(UserAccount user) {
if (user == null) {
return new ArrayIdentifierBundle();
} else {
return new ArrayIdentifierBundle(new IsUser(user.getUri()));
}
}
}

View file

@ -0,0 +1,26 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
/**
* This is what the PermissionRegistry hands out if you ask for a Permission
* that it doesn't know about. Nothing is authorized by this Permission.
*/
public class BrokenPermission extends Permission {
public BrokenPermission(String uri) {
super(uri);
}
@Override
public boolean isAuthorized(RequestedAction whatToAuth) {
return false;
}
@Override
public String toString() {
return "BrokenPermission[" + uri + "]";
}
}

View file

@ -0,0 +1,127 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionBean;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayDataProperty;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayDataPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayObjectProperty;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
/**
* Is the user authorized to display properties that are marked as restricted to
* a certain "Role Level"?
*/
public class DisplayByRolePermission extends Permission {
private static final Log log = LogFactory
.getLog(DisplayByRolePermission.class);
public static final String NAMESPACE = "java:"
+ DisplayByRolePermission.class.getName() + "#";
private final String roleName;
private final RoleLevel roleLevel;
public DisplayByRolePermission(String roleName, RoleLevel roleLevel) {
super(NAMESPACE + roleName);
if (roleName == null) {
throw new NullPointerException("role may not be null.");
}
if (roleLevel == null) {
throw new NullPointerException("roleLevel may not be null.");
}
this.roleName = roleName;
this.roleLevel = roleLevel;
}
@Override
public boolean isAuthorized(RequestedAction whatToAuth) {
boolean result;
if (whatToAuth instanceof DisplayDataProperty) {
result = isAuthorized((DisplayDataProperty) whatToAuth);
} else if (whatToAuth instanceof DisplayObjectProperty) {
result = isAuthorized((DisplayObjectProperty) whatToAuth);
} else if (whatToAuth instanceof DisplayDataPropertyStatement) {
result = isAuthorized((DisplayDataPropertyStatement) whatToAuth);
} else if (whatToAuth instanceof DisplayObjectPropertyStatement) {
result = isAuthorized((DisplayObjectPropertyStatement) whatToAuth);
} else {
result = false;
}
if (result) {
log.debug(this + " authorizes " + whatToAuth);
} else {
log.debug(this + " does not authorize " + whatToAuth);
}
return result;
}
/**
* The user may see this data property if they are allowed to see its
* predicate.
*/
private boolean isAuthorized(DisplayDataProperty action) {
String predicateUri = action.getDataProperty().getURI();
return canDisplayPredicate(new Property(predicateUri));
}
/**
* The user may see this object property if they are allowed to see its
* predicate.
*/
private boolean isAuthorized(DisplayObjectProperty action) {
return canDisplayPredicate(action.getObjectProperty());
}
/**
* The user may see this data property if they are allowed to see its
* subject and its predicate.
*/
private boolean isAuthorized(DisplayDataPropertyStatement action) {
DataPropertyStatement stmt = action.getDataPropertyStatement();
String subjectUri = stmt.getIndividualURI();
String predicateUri = stmt.getDatapropURI();
return canDisplayResource(subjectUri)
&& canDisplayPredicate(new Property(predicateUri));
}
/**
* The user may see this data property if they are allowed to see its
* subject, its predicate, and its object.
*/
private boolean isAuthorized(DisplayObjectPropertyStatement action) {
String subjectUri = action.getSubjectUri();
String objectUri = action.getObjectUri();
Property op = action.getProperty();
return canDisplayResource(subjectUri) && canDisplayPredicate(op)
&& canDisplayResource(objectUri);
}
private boolean canDisplayResource(String resourceUri) {
return PropertyRestrictionBean.getBean().canDisplayResource(
resourceUri, this.roleLevel);
}
private boolean canDisplayPredicate(Property predicate) {
return PropertyRestrictionBean.getBean().canDisplayPredicate(predicate,
this.roleLevel);
}
@Override
public String toString() {
return "DisplayByRolePermission['" + roleName + "']";
}
}

View file

@ -0,0 +1,105 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionBean;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractDataPropertyStatementAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractObjectPropertyStatementAction;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
/**
* Is the user authorized to edit properties that are marked as restricted to a
* certain "Role Level"?
*/
public class EditByRolePermission extends Permission {
private static final Log log = LogFactory
.getLog(EditByRolePermission.class);
public static final String NAMESPACE = "java:"
+ EditByRolePermission.class.getName() + "#";
private final String roleName;
private final RoleLevel roleLevel;
public EditByRolePermission(String roleName, RoleLevel roleLevel) {
super(NAMESPACE + roleName);
if (roleName == null) {
throw new NullPointerException("role may not be null.");
}
if (roleLevel == null) {
throw new NullPointerException("roleLevel may not be null.");
}
this.roleName = roleName;
this.roleLevel = roleLevel;
}
/**
* If the requested action is to edit a property statement, we might
* authorize it based on their role level.
*/
@Override
public boolean isAuthorized(RequestedAction whatToAuth) {
boolean result;
if (whatToAuth instanceof AbstractDataPropertyStatementAction) {
result = isAuthorized((AbstractDataPropertyStatementAction) whatToAuth);
} else if (whatToAuth instanceof AbstractObjectPropertyStatementAction) {
result = isAuthorized((AbstractObjectPropertyStatementAction) whatToAuth);
} else {
result = false;
}
if (result) {
log.debug(this + " authorizes " + whatToAuth);
} else {
log.debug(this + " does not authorize " + whatToAuth);
}
return result;
}
/**
* The user may add, edit, or delete this data property if they are allowed
* to modify its subject and its predicate.
*/
private boolean isAuthorized(AbstractDataPropertyStatementAction action) {
String subjectUri = action.getSubjectUri();
Property predicate = action.getPredicate();
return canModifyResource(subjectUri) && canModifyPredicate(predicate);
}
/**
* The user may add, edit, or delete this data property if they are allowed
* to modify its subject, its predicate, and its object.
*/
private boolean isAuthorized(AbstractObjectPropertyStatementAction action) {
String subjectUri = action.getSubjectUri();
Property predicate = action.getPredicate();
String objectUri = action.getObjectUri();
return canModifyResource(subjectUri) && canModifyPredicate(predicate)
&& canModifyResource(objectUri);
}
private boolean canModifyResource(String resourceUri) {
return PropertyRestrictionBean.getBean().canModifyResource(resourceUri,
roleLevel);
}
private boolean canModifyPredicate(Property predicate) {
return PropertyRestrictionBean.getBean().canModifyPredicate(predicate,
roleLevel);
}
@Override
public String toString() {
return "EditByRolePermission['" + roleName + "']";
}
}

View file

@ -0,0 +1,76 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
/**
* Interface that describes a unit of authorization, or permission to perform
* requested actions.
*/
public abstract class Permission implements Comparable<Permission> {
protected final String uri;
protected Permission(String uri) {
if (uri == null) {
throw new NullPointerException("uri may not be null.");
}
this.uri = uri;
}
/**
* Get the URI that identifies this Permission object.
*/
public String getUri() {
return uri;
}
/**
* Is a user with this Permission authorized to perform this
* RequestedAction?
*/
public abstract boolean isAuthorized(RequestedAction whatToAuth);
@Override
public int compareTo(Permission that) {
return this.uri.compareTo(that.uri);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null) {
return false;
}
if (!obj.getClass().equals(this.getClass())) {
return false;
}
Permission that = (Permission) obj;
return this.uri.equals(that.uri);
}
@Override
public int hashCode() {
return uri.hashCode();
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "['" + uri + "']";
}
/**
* A concrete Permission instance that authorizes nothing.
*/
static Permission NOT_AUTHORIZED = new Permission("java:"
+ Permission.class.getName() + "#NOT_AUTHORIZED") {
@Override
public boolean isAuthorized(RequestedAction whatToAuth) {
return false;
}
};
}

View file

@ -0,0 +1,216 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* A collection of Permission objects, keyed by URI. Resides in the
* ServletContext.
*
* This is not thread-safe, so Permissions should be added only during context
* initialization.
*/
public class PermissionRegistry {
private static final Log log = LogFactory.getLog(PermissionRegistry.class);
// ----------------------------------------------------------------------
// The factory
// ----------------------------------------------------------------------
private static final String ATTRIBUTE_NAME = PermissionRegistry.class
.getName();
/**
* Has the registry been created yet?
*/
public static boolean isRegistryCreated(ServletContext ctx) {
return ctx.getAttribute(ATTRIBUTE_NAME) instanceof PermissionRegistry;
}
/**
* Create the registry and store it in the context.
*/
public static void createRegistry(ServletContext ctx,
Collection<? extends Permission> permissions) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
if (permissions == null) {
throw new NullPointerException("permissions may not be null.");
}
if (ctx.getAttribute(ATTRIBUTE_NAME) != null) {
throw new IllegalStateException(
"PermissionRegistry has already been set.");
}
PermissionRegistry registry = new PermissionRegistry();
registry.addPermissions(permissions);
ctx.setAttribute(ATTRIBUTE_NAME, registry);
}
/**
* Get the registry from the context. If there isn't one, throw an
* exception.
*/
public static PermissionRegistry getRegistry(ServletContext ctx) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
Object o = ctx.getAttribute(ATTRIBUTE_NAME);
if (o == null) {
throw new IllegalStateException(
"PermissionRegistry has not been set.");
} else if (!(o instanceof PermissionRegistry)) {
throw new IllegalStateException("PermissionRegistry was set to an "
+ "invalid object: " + o);
}
return (PermissionRegistry) o;
}
// ----------------------------------------------------------------------
// The instance
// ----------------------------------------------------------------------
private final Map<String, Permission> map = new HashMap<>();
/**
* This class is not thread-safe, so permissions should be added only during
* context initialization.
*/
public void addPermissions(Collection<? extends Permission> permissions) {
for (Permission p : permissions) {
addPermission(p);
}
}
/**
* This class is not thread-safe, so permissions should be added only during
* context initialization.
*/
public void addPermission(Permission p) {
String uri = p.getUri();
if (map.containsKey(uri)) {
throw new IllegalStateException("A Permission is already "
+ "registered with this URI: '" + uri + "'.");
}
map.put(uri, p);
}
/**
* Is there a Permission registered with this URI?
*/
public boolean isPermission(String uri) {
return map.containsKey(uri);
}
/**
* Get the permission that is registered with this URI. If there is no such
* Permission, return a BrokenPermission that always denies authorization.
*
* If you want to know whether an actual Permission has been registered at
* this URI, call isPermission() instead.
*/
public Permission getPermission(String uri) {
Permission p = map.get(uri);
if (p == null) {
log.warn("No Permission is registered for '" + uri + "'");
return new BrokenPermission(uri);
}
return p;
}
// ----------------------------------------------------------------------
// Setup class
// ----------------------------------------------------------------------
public static class Setup implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
StartupStatus ss = StartupStatus.getBean(ctx);
try {
List<Permission> permissions = new ArrayList<Permission>();
permissions.addAll(SimplePermission.getAllInstances());
permissions.addAll(createDisplayByRolePermissions());
permissions.addAll(createEditByRolePermissions());
permissions.addAll(createPublishByRolePermissions());
PermissionRegistry.createRegistry(ctx, permissions);
ss.info(this, "Created the PermissionRegistry with "
+ permissions.size() + " permissions.");
} catch (Exception e) {
ss.fatal(this, "Failed to initialize the PermissionRegistry.",
e);
}
}
/**
* There is no DisplayByRolePermission for self-editors. They get the
* same rights as PUBLIC. Other permissions give them their self-editing
* privileges.
*/
private Collection<Permission> createDisplayByRolePermissions() {
List<Permission> list = new ArrayList<Permission>();
list.add(new DisplayByRolePermission("Admin", RoleLevel.DB_ADMIN));
list.add(new DisplayByRolePermission("Curator", RoleLevel.CURATOR));
list.add(new DisplayByRolePermission("Editor", RoleLevel.EDITOR));
list.add(new DisplayByRolePermission("Public", RoleLevel.PUBLIC));
return list;
}
/**
* There is no EditByRolePermission for PUBLIC or for self-editors. A
* property may be given an edit-level of "PUBLIC", but that may also
* simply be the default assigned to it when editing, and we don't want
* to recognize that.
*
* Other permissions give self-editors their editing privileges.
*/
private Collection<Permission> createEditByRolePermissions() {
List<Permission> list = new ArrayList<Permission>();
list.add(new EditByRolePermission("Admin", RoleLevel.DB_ADMIN));
list.add(new EditByRolePermission("Curator", RoleLevel.CURATOR));
list.add(new EditByRolePermission("Editor", RoleLevel.EDITOR));
return list;
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
sce.getServletContext().removeAttribute(ATTRIBUTE_NAME);
}
/**
* There is no PublishByRolePermission for self-editors. They get the
* same rights as PUBLIC. Other permissions give them their self-editing
* privileges.
*/
private Collection<Permission> createPublishByRolePermissions() {
List<Permission> list = new ArrayList<Permission>();
list.add(new PublishByRolePermission("Admin", RoleLevel.DB_ADMIN));
list.add(new PublishByRolePermission("Curator", RoleLevel.CURATOR));
list.add(new PublishByRolePermission("Editor", RoleLevel.EDITOR));
list.add(new PublishByRolePermission("Public", RoleLevel.PUBLIC));
return list;
}
}
}

View file

@ -0,0 +1,20 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import static edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary.VITRO_AUTH;
/**
* Constants and static methods to help manipulate PermissionSet instances.
*/
public class PermissionSets {
public static final String URI_SELF_EDITOR = VITRO_AUTH + "SELF_EDITOR";
public static final String URI_EDITOR = VITRO_AUTH + "EDITOR";
public static final String URI_CURATOR = VITRO_AUTH + "CURATOR";
public static final String URI_DBA = VITRO_AUTH + "ADMIN";
/** No need to create an instance. */
private PermissionSets() {
// Nothing to initialize.
}
}

View file

@ -0,0 +1,124 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* Load the initial configuration of PermissionSets and Permissions.
*
* The UserAccounts model must be created before this runs.
*
* The PermissionRegistry must be created before this runs.
*/
public class PermissionSetsSmokeTest implements ServletContextListener {
@SuppressWarnings("unused")
private static final Log log = LogFactory
.getLog(PermissionSetsSmokeTest.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
StartupStatus ss = StartupStatus.getBean(ctx);
try {
new SmokeTester(this, ctx, ss).test();
} catch (Exception e) {
ss.fatal(this, "Found a problem while testing the PermissionSets",
e);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// Nothing to tear down.
}
// ----------------------------------------------------------------------
// SmokeTester class
// ----------------------------------------------------------------------
private static class SmokeTester {
private ServletContextListener listener;
private final ServletContext ctx;
private final StartupStatus ss;
private final UserAccountsDao uaDao;
public SmokeTester(ServletContextListener listener, ServletContext ctx,
StartupStatus ss) {
this.listener = listener;
this.ctx = ctx;
this.ss = ss;
this.uaDao = ModelAccess.on(ctx).getWebappDaoFactory()
.getUserAccountsDao();
}
public void test() {
checkForPermissionSetsWithoutLabels();
checkForReferencesToNonexistentPermissionSets();
checkForReferencesToNonexistentPermissions();
warnIfNoPermissionSetsForNewUsers();
}
private void checkForPermissionSetsWithoutLabels() {
for (PermissionSet ps : uaDao.getAllPermissionSets()) {
if (ps.getLabel().isEmpty()) {
ss.warning(listener, "This PermissionSet has no label: "
+ ps.getUri());
}
}
}
private void checkForReferencesToNonexistentPermissionSets() {
for (UserAccount user : uaDao.getAllUserAccounts()) {
for (String psUri : user.getPermissionSetUris()) {
if (uaDao.getPermissionSetByUri(psUri) == null) {
ss.warning(listener, "The user '" + user.getFirstName()
+ " " + user.getLastName()
+ "' has the PermissionSet '" + psUri
+ "', but the PermissionSet doesn't exist.");
}
}
}
}
private void checkForReferencesToNonexistentPermissions() {
PermissionRegistry registry = PermissionRegistry.getRegistry(ctx);
for (PermissionSet ps : uaDao.getAllPermissionSets()) {
for (String pUri : ps.getPermissionUris()) {
if (!registry.isPermission(pUri)) {
ss.warning(listener,
"The PermissionSet '" + ps.getLabel()
+ "' has the Permission '" + pUri
+ "', but the Permission "
+ "is not found in the registry.");
}
}
}
}
private void warnIfNoPermissionSetsForNewUsers() {
for (PermissionSet ps : uaDao.getAllPermissionSets()) {
if (ps.isForNewUsers()) {
return;
}
}
ss.warning(listener, "No PermissionSet has been declared to be a "
+ "PermissionSet for new users.");
}
}
}

View file

@ -0,0 +1,125 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionBean;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.publish.PublishDataProperty;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.publish.PublishDataPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.publish.PublishObjectProperty;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.publish.PublishObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
/**
* Is the user authorized to publish properties that are marked as restricted to
* a certain "Role Level"?
*/
public class PublishByRolePermission extends Permission {
private static final Log log = LogFactory
.getLog(PublishByRolePermission.class);
public static final String NAMESPACE = "java:"
+ PublishByRolePermission.class.getName() + "#";
private final String roleName;
private final RoleLevel roleLevel;
public PublishByRolePermission(String roleName, RoleLevel roleLevel) {
super(NAMESPACE + roleName);
if (roleName == null) {
throw new NullPointerException("role may not be null.");
}
if (roleLevel == null) {
throw new NullPointerException("roleLevel may not be null.");
}
this.roleName = roleName;
this.roleLevel = roleLevel;
}
@Override
public boolean isAuthorized(RequestedAction whatToAuth) {
boolean result;
if (whatToAuth instanceof PublishDataProperty) {
result = isAuthorized((PublishDataProperty) whatToAuth);
} else if (whatToAuth instanceof PublishObjectProperty) {
result = isAuthorized((PublishObjectProperty) whatToAuth);
} else if (whatToAuth instanceof PublishDataPropertyStatement) {
result = isAuthorized((PublishDataPropertyStatement) whatToAuth);
} else if (whatToAuth instanceof PublishObjectPropertyStatement) {
result = isAuthorized((PublishObjectPropertyStatement) whatToAuth);
} else {
result = false;
}
if (result) {
log.debug(this + " authorizes " + whatToAuth);
} else {
log.debug(this + " does not authorize " + whatToAuth);
}
return result;
}
/**
* The user may publish this data property if they are allowed to publish
* its predicate.
*/
private boolean isAuthorized(PublishDataProperty action) {
String predicateUri = action.getDataProperty().getURI();
return canPublishPredicate(new Property(predicateUri));
}
/**
* The user may publish this object property if they are allowed to publish
* its predicate.
*/
private boolean isAuthorized(PublishObjectProperty action) {
return canPublishPredicate(action.getObjectProperty());
}
/**
* The user may publish this data property if they are allowed to publish
* its subject and its predicate.
*/
private boolean isAuthorized(PublishDataPropertyStatement action) {
String subjectUri = action.getSubjectUri();
String predicateUri = action.getPredicateUri();
return canPublishResource(subjectUri)
&& canPublishPredicate(new Property(predicateUri));
}
/**
* The user may publish this data property if they are allowed to publish
* its subject, its predicate, and its object.
*/
private boolean isAuthorized(PublishObjectPropertyStatement action) {
String subjectUri = action.getSubjectUri();
Property predicate = action.getPredicate();
String objectUri = action.getObjectUri();
return canPublishResource(subjectUri) && canPublishPredicate(predicate)
&& canPublishResource(objectUri);
}
private boolean canPublishResource(String resourceUri) {
return PropertyRestrictionBean.getBean().canPublishResource(
resourceUri, this.roleLevel);
}
private boolean canPublishPredicate(Property predicate) {
return PropertyRestrictionBean.getBean().canPublishPredicate(predicate,
this.roleLevel);
}
@Override
public String toString() {
return "PublishByRolePermission['" + roleName + "']";
}
}

View file

@ -0,0 +1,154 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.permissions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.SimpleRequestedAction;
/**
* A class of simple permissions. Each instance holds a RequestedAction, and
* will only authorize that RequestedAction (or one with the same URI).
*/
public class SimplePermission extends Permission {
private static final Log log = LogFactory.getLog(SimplePermission.class);
private static final String NAMESPACE = "java:"
+ SimplePermission.class.getName() + "#";
private static final Map<String, SimplePermission> allInstances = new HashMap<String, SimplePermission>();
public static final SimplePermission ACCESS_SPECIAL_DATA_MODELS = new SimplePermission(
NAMESPACE + "AccessSpecialDataModels");
public static final SimplePermission DO_BACK_END_EDITING = new SimplePermission(
NAMESPACE + "DoBackEndEditing");
public static final SimplePermission DO_FRONT_END_EDITING = new SimplePermission(
NAMESPACE + "DoFrontEndEditing");
public static final SimplePermission EDIT_ONTOLOGY = new SimplePermission(
NAMESPACE + "EditOntology");
public static final SimplePermission EDIT_OWN_ACCOUNT = new SimplePermission(
NAMESPACE + "EditOwnAccount");
public static final SimplePermission EDIT_SITE_INFORMATION = new SimplePermission(
NAMESPACE + "EditSiteInformation");
public static final SimplePermission ENABLE_DEVELOPER_PANEL = new SimplePermission(
NAMESPACE + "EnableDeveloperPanel");
public static final SimplePermission LOGIN_DURING_MAINTENANCE = new SimplePermission(
NAMESPACE + "LoginDuringMaintenance");
public static final SimplePermission MANAGE_MENUS = new SimplePermission(
NAMESPACE + "ManageMenus");
public static final SimplePermission MANAGE_OWN_PROXIES = new SimplePermission(
NAMESPACE + "ManageOwnProxies");
public static final SimplePermission MANAGE_PROXIES = new SimplePermission(
NAMESPACE + "ManageProxies");
public static final SimplePermission MANAGE_SEARCH_INDEX = new SimplePermission(
NAMESPACE + "ManageSearchIndex");
public static final SimplePermission MANAGE_USER_ACCOUNTS = new SimplePermission(
NAMESPACE + "ManageUserAccounts");
public static final SimplePermission QUERY_FULL_MODEL = new SimplePermission(
NAMESPACE + "QueryFullModel");
public static final SimplePermission QUERY_USER_ACCOUNTS_MODEL = new SimplePermission(
NAMESPACE + "QueryUserAccountsModel");
public static final SimplePermission REFRESH_VISUALIZATION_CACHE = new SimplePermission(
NAMESPACE + "RefreshVisualizationCache");
public static final SimplePermission SEE_CONFIGURATION = new SimplePermission(
NAMESPACE + "SeeConfiguration");
public static final SimplePermission SEE_INDVIDUAL_EDITING_PANEL = new SimplePermission(
NAMESPACE + "SeeIndividualEditingPanel");
public static final SimplePermission SEE_REVISION_INFO = new SimplePermission(
NAMESPACE + "SeeRevisionInfo");
public static final SimplePermission SEE_SITE_ADMIN_PAGE = new SimplePermission(
NAMESPACE + "SeeSiteAdminPage");
public static final SimplePermission SEE_STARTUP_STATUS = new SimplePermission(
NAMESPACE + "SeeStartupStatus");
public static final SimplePermission SEE_VERBOSE_PROPERTY_INFORMATION = new SimplePermission(
NAMESPACE + "SeeVerbosePropertyInformation");
public static final SimplePermission USE_ADVANCED_DATA_TOOLS_PAGES = new SimplePermission(
NAMESPACE + "UseAdvancedDataToolsPages");
public static final SimplePermission USE_INDIVIDUAL_CONTROL_PANEL = new SimplePermission(
NAMESPACE + "UseIndividualControlPanel");
public static final SimplePermission USE_SPARQL_QUERY_PAGE = new SimplePermission(
NAMESPACE + "UseSparqlQueryPage");
public static final SimplePermission USE_SPARQL_QUERY_API = new SimplePermission(
NAMESPACE + "UseSparqlQueryApi");
public static final SimplePermission USE_SPARQL_UPDATE_API = new SimplePermission(
NAMESPACE + "UseSparqlUpdateApi");
// ----------------------------------------------------------------------
// These instances are "catch all" permissions to cover poorly defined
// groups of actions until better definitions were found. Don't add usages
// of these, and remove existing usages where possible.
// ----------------------------------------------------------------------
public static final SimplePermission USE_BASIC_AJAX_CONTROLLERS = new SimplePermission(
NAMESPACE + "UseBasicAjaxControllers");
public static final SimplePermission USE_MISCELLANEOUS_ADMIN_PAGES = new SimplePermission(
NAMESPACE + "UseMiscellaneousAdminPages");
public static final SimplePermission USE_MISCELLANEOUS_CURATOR_PAGES = new SimplePermission(
NAMESPACE + "UseMiscellaneousCuratorPages");
public static final SimplePermission USE_MISCELLANEOUS_PAGES = new SimplePermission(
NAMESPACE + "UseMiscellaneousPages");
// ----------------------------------------------------------------------
// These instances are permissions that can be specified for a given page created/managed through page management,
// e.g. this page is viewable only by admins, this page is viewable to anyone who is logged in, etc.
// ----------------------------------------------------------------------
public static final SimplePermission PAGE_VIEWABLE_ADMIN = new SimplePermission(
NAMESPACE + "PageViewableAdmin");
public static final SimplePermission PAGE_VIEWABLE_CURATOR = new SimplePermission(
NAMESPACE + "PageViewableCurator");
public static final SimplePermission PAGE_VIEWABLE_LOGGEDIN = new SimplePermission(
NAMESPACE + "PageViewableLoggedIn");
public static final SimplePermission PAGE_VIEWABLE_EDITOR = new SimplePermission(
NAMESPACE + "PageViewableEditor");
public static final SimplePermission PAGE_VIEWABLE_PUBLIC = new SimplePermission(
NAMESPACE + "PageViewablePublic");
public static List<SimplePermission> getAllInstances() {
return new ArrayList<SimplePermission>(allInstances.values());
}
//private final String localName;
public final RequestedAction ACTION;
public SimplePermission(String uri) {
super(uri);
if (uri == null) {
throw new NullPointerException("uri may not be null.");
}
this.ACTION = new SimpleRequestedAction(uri);
if (allInstances.containsKey(this.uri)) {
throw new IllegalStateException("A SimplePermission named '"
+ this.uri + "' already exists.");
}
allInstances.put(uri, this);
}
@Override
public boolean isAuthorized(RequestedAction whatToAuth) {
if (whatToAuth != null) {
if (ACTION.getURI().equals(whatToAuth.getURI())) {
log.debug(this + " authorizes " + whatToAuth);
return true;
}
}
log.debug(this + " does not authorize " + whatToAuth);
return false;
}
@Override
public String toString() {
return "SimplePermission['" + uri+ "']";
}
}

View file

@ -0,0 +1,61 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import javax.servlet.ServletContext;
import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionBean;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
/**
* A base class with utility methods for policies involving self-editing.
*/
public abstract class BaseSelfEditingPolicy {
protected final ServletContext ctx;
protected final RoleLevel roleLevel;
public BaseSelfEditingPolicy(ServletContext ctx, RoleLevel roleLevel) {
this.ctx = ctx;
this.roleLevel = roleLevel;
}
protected boolean canModifyResource(String uri) {
return PropertyRestrictionBean.getBean().canModifyResource(uri,
roleLevel);
}
protected boolean canModifyPredicate(Property predicate) {
return PropertyRestrictionBean.getBean().canModifyPredicate(predicate,
roleLevel);
}
protected PolicyDecision cantModifyResource(String uri) {
return inconclusiveDecision("No access to admin resources; cannot modify "
+ uri);
}
protected PolicyDecision cantModifyPredicate(Property predicate) {
return inconclusiveDecision("No access to admin predicates; cannot modify "
+ predicate.getURI());
}
protected PolicyDecision userNotAuthorizedToStatement() {
return inconclusiveDecision("User has no access to this statement.");
}
/** An INCONCLUSIVE decision with a message like "PolicyClass: message". */
protected PolicyDecision inconclusiveDecision(String message) {
return new BasicPolicyDecision(Authorization.INCONCLUSIVE, getClass()
.getSimpleName() + ": " + message);
}
/** An AUTHORIZED decision with a message like "PolicyClass: message". */
protected PolicyDecision authorizedDecision(String message) {
return new BasicPolicyDecision(Authorization.AUTHORIZED, getClass()
.getSimpleName() + ": " + message);
}
}

View file

@ -0,0 +1,58 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
/**
* Represents the result of querying a Policy for permission to perform
* a RequestedAction.
*/
public class BasicPolicyDecision implements PolicyDecision{
String debuggingInfo;
String message;
String StackTrace;
Authorization authorized;
public BasicPolicyDecision( Authorization authorized, String message) {
super();
this.message = message;
this.authorized = authorized;
}
public Authorization getAuthorized() {
return authorized;
}
public BasicPolicyDecision setAuthorized(Authorization auth) {
this.authorized = auth;
return this;
}
public String getDebuggingInfo() {
return debuggingInfo;
}
public BasicPolicyDecision setDebuggingInfo(String debuggingInfo) {
this.debuggingInfo = debuggingInfo;
return this;
}
public String getMessage() {
return message;
}
public BasicPolicyDecision setMessage(String message) {
this.message = message;
return this;
}
public String getStackTrace() {
return StackTrace;
}
public void setStackTrace(String stackTrace) {
StackTrace = stackTrace;
}
public String toString(){
return authorized + ": " + message;
}
}

View file

@ -0,0 +1,23 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import java.util.List;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
/**
* Policy decision that is made from some analysis of a set of decisions.
* @author bdc34
*
*/
public class CompositPolicyDecision extends BasicPolicyDecision implements PolicyDecision {
List<PolicyDecision> subDecisions;
public CompositPolicyDecision(Authorization auth, String message, List<PolicyDecision> subDecisions){
super( auth, message);
this.subDecisions = subDecisions;
}
}

View file

@ -0,0 +1,179 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import java.util.Collection;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasAssociatedIndividual;
import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionBean;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayDataProperty;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayDataPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayObjectProperty;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.display.DisplayObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
/**
* Permit display of various data if it relates to the user's associated
* individual.
*
* This policy is only to handle the case where a user would not be able to see
* data except for their self-editing status. If the data would be visible
* without that status, we assume that some other policy will grant access.
*/
public class DisplayRestrictedDataToSelfPolicy implements PolicyIface {
private static final Log log = LogFactory
.getLog(DisplayRestrictedDataToSelfPolicy.class);
private final ServletContext ctx;
public DisplayRestrictedDataToSelfPolicy(ServletContext ctx) {
this.ctx = ctx;
}
/**
* If the requested action is to display a property or a property statement,
* we might authorize it based on their role level.
*/
@Override
public PolicyDecision isAuthorized(IdentifierBundle whoToAuth,
RequestedAction whatToAuth) {
if (whoToAuth == null) {
return defaultDecision("whomToAuth was null");
}
if (whatToAuth == null) {
return defaultDecision("whatToAuth was null");
}
Collection<String> associated = HasAssociatedIndividual
.getIndividualUris(whoToAuth);
if (associated.isEmpty()) {
return defaultDecision("not self-editing for anyone");
}
if (whatToAuth instanceof DisplayDataProperty) {
return defaultDecision("DataProperties have no associated 'self'");
} else if (whatToAuth instanceof DisplayObjectProperty) {
return defaultDecision("ObjectProperties have no associated 'self'");
}
PolicyDecision result;
if (whatToAuth instanceof DisplayDataPropertyStatement) {
result = isAuthorized((DisplayDataPropertyStatement) whatToAuth,
associated);
} else if (whatToAuth instanceof DisplayObjectPropertyStatement) {
result = isAuthorized((DisplayObjectPropertyStatement) whatToAuth,
associated);
} else {
result = defaultDecision("Unrecognized action");
}
log.debug("decision for '" + whatToAuth + "' is " + result);
return result;
}
/**
* The user may see this data property statement if the subject and the
* predicate are both viewable by self-editors, and the subject is one of
* the associated individuals (the "selves").
*/
private PolicyDecision isAuthorized(DisplayDataPropertyStatement action,
Collection<String> individuals) {
DataPropertyStatement stmt = action.getDataPropertyStatement();
String subjectUri = stmt.getIndividualURI();
Property predicate = new Property(stmt.getDatapropURI());
if (canDisplayResource(subjectUri) && canDisplayPredicate(predicate)
&& isAboutAssociatedIndividual(individuals, subjectUri)) {
return authorized("user may view DataPropertyStatement "
+ subjectUri + " ==> " + predicate.getURI());
} else {
return defaultDecision("user may not view DataPropertyStatement "
+ subjectUri + " ==> " + predicate.getURI());
}
}
/**
* The user may see this data property statement if the subject, the
* predicate, and the object are all viewable by self-editors, and either
* the subject or the object is one of the associated individuals (the
* "selves").
*/
private PolicyDecision isAuthorized(DisplayObjectPropertyStatement action,
Collection<String> individuals) {
String subjectUri = action.getSubjectUri();
Property predicate = action.getProperty();
String objectUri = action.getObjectUri();
if (canDisplayResource(subjectUri)
&& canDisplayPredicate(predicate)
&& canDisplayResource(objectUri)
&& isAboutAssociatedIndividual(individuals, subjectUri,
objectUri)) {
return authorized("user may view ObjectPropertyStatement "
+ subjectUri + " ==> " + predicate.getURI() + " ==> "
+ objectUri);
} else {
return defaultDecision("user may not view ObjectPropertyStatement "
+ subjectUri + " ==> " + predicate.getURI() + " ==> "
+ objectUri);
}
}
/** If the user is explicitly authorized, return this. */
private PolicyDecision authorized(String message) {
String className = this.getClass().getSimpleName();
return new BasicPolicyDecision(Authorization.AUTHORIZED, className
+ ": " + message);
}
/** If the user isn't explicitly authorized, return this. */
private PolicyDecision defaultDecision(String message) {
return new BasicPolicyDecision(Authorization.INCONCLUSIVE, message);
}
private boolean canDisplayResource(String uri) {
return PropertyRestrictionBean.getBean().canDisplayResource(uri,
RoleLevel.SELF);
}
private boolean canDisplayPredicate(Property predicate) {
return PropertyRestrictionBean.getBean().canDisplayPredicate(predicate,
RoleLevel.SELF);
}
private boolean isAboutAssociatedIndividual(Collection<String> selves,
String subjectUri) {
for (String self : selves) {
if (self.equals(subjectUri)) {
return true;
}
}
return false;
}
private boolean isAboutAssociatedIndividual(Collection<String> selves,
String subjectUri, String objectUri) {
for (String self : selves) {
if (self.equals(subjectUri) || self.equals(objectUri)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + " - " + hashCode();
}
}

View file

@ -0,0 +1,56 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasPermission;
import edu.cornell.mannlib.vitro.webapp.auth.permissions.Permission;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
/**
* The user is authorized to perform the RequestedAction if one of his
* Permissions will authorize it.
*/
public class PermissionsPolicy implements PolicyIface {
private static final Log log = LogFactory.getLog(PermissionsPolicy.class);
@Override
public PolicyDecision isAuthorized(IdentifierBundle whoToAuth,
RequestedAction whatToAuth) {
if (whoToAuth == null) {
return defaultDecision("whomToAuth was null");
}
if (whatToAuth == null) {
return defaultDecision("whatToAuth was null");
}
for (Permission p : HasPermission.getPermissions(whoToAuth)) {
if (p.isAuthorized(whatToAuth)) {
log.debug("Permission " + p + " approves request " + whatToAuth);
return new BasicPolicyDecision(Authorization.AUTHORIZED,
"PermissionsPolicy: approved by " + p);
} else {
log.trace("Permission " + p + " denies request " + whatToAuth);
}
}
log.debug("No permission will approve " + whatToAuth);
return defaultDecision("no permission will approve " + whatToAuth);
}
/** If the user isn't explicitly authorized, return this. */
private PolicyDecision defaultDecision(String message) {
return new BasicPolicyDecision(Authorization.INCONCLUSIVE, message);
}
@Override
public String toString() {
return "PermissionsPolicy - " + hashCode();
}
}

View file

@ -0,0 +1,176 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import static edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization.INCONCLUSIVE;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings;
import edu.cornell.mannlib.vitro.webapp.utils.developer.Key;
/**
* If enabled in the developer settings (and log levels), log each
* PolicyDecision (subject to restrictions).
*
* Some restrictions apply to the logger as a whole. Others apply to the
* particular policy or the particular decision.
*/
public class PolicyDecisionLogger {
private static final Log log = LogFactory
.getLog(PolicyDecisionLogger.class);
private static final Pattern NEVER_MATCHES = Pattern.compile("^__NEVER__$");
private static final BasicPolicyDecision NULL_DECISION = new BasicPolicyDecision(
INCONCLUSIVE, "The decision was null.");
private final DeveloperSettings settings;
private final RequestedAction whatToAuth;
private final IdentifierBundle whoToAuth;
private final boolean enabled;
private final Pattern policyRestriction;
private final boolean skipInconclusive;
private final boolean includeIdentifiers;
public PolicyDecisionLogger(IdentifierBundle whoToAuth,
RequestedAction whatToAuth) {
this.settings = DeveloperSettings.getInstance();
this.whoToAuth = whoToAuth;
this.whatToAuth = whatToAuth;
this.enabled = figureEnabled();
this.policyRestriction = figurePolicyRestriction();
this.skipInconclusive = figureSkipInconclusive();
this.includeIdentifiers = figureIncludeIdentifiers();
}
private boolean figureEnabled() {
return log.isInfoEnabled()
&& settings.getBoolean(Key.AUTHORIZATION_LOG_DECISIONS_ENABLE)
&& passesUserRestriction() && passesActionRestriction();
}
/**
* The identifier bundle passes if there is no restriction, or if the
* restriction pattern is found within concatenated string of the identifier
* bundle.
*
* If the restriction is invalid, the action fails.
*/
private boolean passesUserRestriction() {
Pattern userRestriction = compilePatternFromSetting(Key.AUTHORIZATION_LOG_DECISIONS_USER_RESTRICTION);
return userRestriction == null
|| userRestriction.matcher(String.valueOf(whoToAuth)).find();
}
/**
* The requested action passes if there is no restriction, or if the
* restriction pattern is found within the class name of the action.
*
* If the restriction is invalid, the action fails.
*/
private boolean passesActionRestriction() {
Pattern actionRestriction = compilePatternFromSetting(Key.AUTHORIZATION_LOG_DECISIONS_ACTION_RESTRICTION);
return actionRestriction == null
|| actionRestriction.matcher(String.valueOf(whatToAuth)).find();
}
/**
* Only compile the policy restriction pattern once.
*/
private Pattern figurePolicyRestriction() {
return compilePatternFromSetting(Key.AUTHORIZATION_LOG_DECISIONS_POLICY_RESTRICTION);
}
/**
* Do we log inconclusive decisions?
*/
private boolean figureSkipInconclusive() {
return settings
.getBoolean(Key.AUTHORIZATION_LOG_DECISIONS_SKIP_INCONCLUSIVE);
}
/**
* Do we include Identifiers in the log record?
*/
private boolean figureIncludeIdentifiers() {
return settings
.getBoolean(Key.AUTHORIZATION_LOG_DECISIONS_ADD_IDENTIFERS);
}
/**
* If no pattern was provided, return null. If an invalid pattern was
* provided, return a pattern that never matches.
*/
private Pattern compilePatternFromSetting(Key key) {
String setting = settings.getString(key);
if (setting.isEmpty()) {
return null;
} else {
try {
return Pattern.compile(setting);
} catch (Exception e) {
return NEVER_MATCHES;
}
}
}
/**
* If the logger and the policy and the decision all pass the restrictions,
* write to the log. A null decision is treated as inconclusive.
*/
public void log(PolicyIface policy, PolicyDecision pd) {
if (passesRestrictions(String.valueOf(policy), pd)) {
if (this.includeIdentifiers) {
log.info(String.format(
"Decision on %s by %s was %s; user is %s",
this.whatToAuth, policy, pd, this.whoToAuth));
} else {
log.info(String.format("Decision on %s by %s was %s",
this.whatToAuth, policy, pd));
}
}
}
private boolean passesRestrictions(String policyString, PolicyDecision pd) {
if (pd == null) {
pd = NULL_DECISION;
}
return enabled && passesPolicyRestriction(policyString)
&& passesConclusiveRestriction(pd);
}
private boolean passesPolicyRestriction(String policyString) {
return this.policyRestriction == null
|| this.policyRestriction.matcher(policyString).find();
}
private boolean passesConclusiveRestriction(PolicyDecision pd) {
return !(skipInconclusive && isInconclusive(pd));
}
private boolean isInconclusive(PolicyDecision pd) {
return pd == null || pd.getAuthorized() == INCONCLUSIVE;
}
public void logNoDecision(PolicyDecision pd) {
if (enabled) {
if (this.includeIdentifiers) {
log.info(pd.getMessage() + "; user is " + this.whoToAuth);
} else {
log.info(pd.getMessage());
}
}
}
}

View file

@ -0,0 +1,337 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import static edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction.SOME_URI;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ActiveIdentifierBundleFactories;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.RequestIdentifiers;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddDataPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropDataPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
/**
* A collection of static methods to help determine whether requested actions
* are authorized by current policy.
*/
public class PolicyHelper {
private static final Log log = LogFactory.getLog(PolicyHelper.class);
/**
* Are these actions authorized for the current user by the current
* policies?
*/
public static boolean isAuthorizedForActions(HttpServletRequest req,
AuthorizationRequest... actions) {
return isAuthorizedForActions(req, AuthorizationRequest.andAll(actions));
}
/**
* Are these actions authorized for the current user by the current
* policies?
*/
public static boolean isAuthorizedForActions(HttpServletRequest req,
Iterable<? extends AuthorizationRequest> actions) {
return isAuthorizedForActions(req, AuthorizationRequest.andAll(actions));
}
/**
* Are these actions authorized for the current user by the current
* policies?
*/
private static boolean isAuthorizedForActions(HttpServletRequest req,
AuthorizationRequest ar) {
PolicyIface policy = ServletPolicyList.getPolicies(req);
IdentifierBundle ids = RequestIdentifiers.getIdBundleForRequest(req);
return ar.isAuthorized(ids, policy);
}
/**
* Are these actions authorized for these identifiers by these policies?
*/
public static boolean isAuthorizedForActions(IdentifierBundle ids,
PolicyIface policy, AuthorizationRequest ar) {
return ar.isAuthorized(ids, policy);
}
/**
* Is the email/password authorized for these actions? This should be used
* when a controller or something needs allow actions if the user passes in
* their email and password.
*
* It may be better to check this as part of a servlet Filter and add an
* identifier bundle.
*/
public static boolean isAuthorizedForActions(HttpServletRequest req,
String email, String password, AuthorizationRequest ar) {
if (password == null || email == null || password.isEmpty()
|| email.isEmpty()) {
return false;
}
try {
Authenticator auth = Authenticator.getInstance(req);
UserAccount user = auth.getAccountForInternalAuth(email);
if (user == null) {
log.debug("No account for '" + email + "'");
return false;
}
String uri = user.getUri();
log.debug("userAccount is '" + uri + "'");
if (!auth.isCurrentPassword(user, password)) {
log.debug(String.format("UNAUTHORIZED, password not accepted "
+ "for %s, account URI: %s", email, uri));
return false;
}
log.debug(String.format("password accepted for %s, "
+ "account URI: %s", email, uri));
// figure out if that account can do the actions
IdentifierBundle ids = ActiveIdentifierBundleFactories
.getUserIdentifierBundle(req, user);
PolicyIface policy = ServletPolicyList.getPolicies(req);
return ar.isAuthorized(ids, policy);
} catch (Exception ex) {
log.error("Error while attempting to authorize actions " + ar, ex);
return false;
}
}
/**
* Do the current policies authorize the current user to add this statement
* to this model?
*
* The statement is expected to be fully-populated, with no null fields.
*/
public static boolean isAuthorizedToAdd(HttpServletRequest req,
Statement stmt, OntModel modelToBeModified) {
if ((req == null) || (stmt == null) || (modelToBeModified == null)) {
return false;
}
Resource subject = stmt.getSubject();
com.hp.hpl.jena.rdf.model.Property predicate = stmt.getPredicate();
RDFNode objectNode = stmt.getObject();
if ((subject == null) || (predicate == null) || (objectNode == null)) {
return false;
}
RequestedAction action;
if (objectNode.isResource()) {
Property property = new Property(predicate.getURI());
property.setDomainVClassURI(SOME_URI);
property.setRangeVClassURI(SOME_URI);
action = new AddObjectPropertyStatement(modelToBeModified,
subject.getURI(), property, objectNode.asResource()
.getURI());
} else {
action = new AddDataPropertyStatement(modelToBeModified,
subject.getURI(), predicate.getURI(), objectNode
.asLiteral().getString());
}
return isAuthorizedForActions(req, action);
}
/**
* Do the current policies authorize the current user to drop this statement
* from this model?
*
* The statement is expected to be fully-populated, with no null fields.
*/
public static boolean isAuthorizedToDrop(HttpServletRequest req,
Statement stmt, OntModel modelToBeModified) {
if ((req == null) || (stmt == null) || (modelToBeModified == null)) {
return false;
}
Resource subject = stmt.getSubject();
com.hp.hpl.jena.rdf.model.Property predicate = stmt.getPredicate();
RDFNode objectNode = stmt.getObject();
if ((subject == null) || (predicate == null) || (objectNode == null)) {
return false;
}
RequestedAction action;
if (objectNode.isResource()) {
Property property = new Property(predicate.getURI());
property.setDomainVClassURI(SOME_URI);
property.setRangeVClassURI(SOME_URI);
action = new DropObjectPropertyStatement(modelToBeModified,
subject.getURI(), property, objectNode.asResource()
.getURI());
} else {
action = new DropDataPropertyStatement(modelToBeModified,
subject.getURI(), predicate.getURI(), objectNode
.asLiteral().getString());
}
return isAuthorizedForActions(req, action);
}
/**
* Do the current policies authorize the current user to modify this model
* by adding all of the statments in the additions model and dropping all of
* the statements in the retractions model?
*
* This differs from the other calls to "isAuthorized..." because we always
* expect the answer to be true. If the answer is false, it should be logged
* as an error.
*
* Even if a statement fails the test, continue to test the others, so the
* log will contain a full record of all failures. This is no more expensive
* than if all statements succeeded.
*/
public static boolean isAuthorizedAsExpected(HttpServletRequest req,
Model additions, Model retractions, OntModel modelBeingModified) {
if (req == null) {
log.warn("Can't evaluate authorization if req is null");
return false;
}
if (additions == null) {
log.warn("Can't evaluate authorization if additions model is null");
return false;
}
if (retractions == null) {
log.warn("Can't evaluate authorization if retractions model is null");
return false;
}
if (modelBeingModified == null) {
log.warn("Can't evaluate authorization if model being modified is null");
return false;
}
/*
* The naive way to test the additions is to test each statement against
* the JenaOntModel. However, some of the statements may not be
* authorized unless others are added first. The client code should not
* need to know which sequence will be successful. The client code only
* cares that such a sequence does exist.
*
* There are 3 obvious ways to test this, ranging from the most rigorous
* (and most costly) to the least costly (and least rigorous).
*
* 1. Try all sequences to find one that works. First, try to add each
* statement to the modelBeingModified. If any statement succeeds,
* construct a temporary model that joins that statement to the
* modelBeingModified. Now try the remaining statements against that
* temporary model, adding the statement each time we are successful. If
* we eventually find all of the statements authorized, declare success.
* This is logically rigorous, but could become geometrically expensive
* as statements are repeatedly tried against incremented models. O(n!).
*
* 2. Try each statement on the assumption that all of the others have
* already been added. So for each statement we create a temporary
* modeol that joins the other additions to the JenaOntModel. If all
* statements pass this test, declare success. This is logically flawed
* since it is possible that two statements would circularly authorize
* each other, but that neither statement could be added first. However,
* that seems like a small risk, and the algorithm is considerably less
* expensive. O(n).
*
* 3. Try each statement on the assumption that all of the statements
* (including itself) have already been added. If all statements pass
* this test, declare success. This has the additional minor flaw of
* allowing a statement to authorize its own addition, but this seems
* very unlikely. This is about as expensive as choice 2., but much
* simpler to code.
*
* For now, I am going with choice 3.
*/
boolean result = true;
OntModel modelToTestAgainst = ModelFactory
.createOntologyModel(OntModelSpec.OWL_MEM);
modelToTestAgainst.addSubModel(additions);
modelToTestAgainst.addSubModel(modelBeingModified);
StmtIterator addStmts = additions.listStatements();
try {
while (addStmts.hasNext()) {
Statement stmt = addStmts.next();
if (isAuthorizedToAdd(req, stmt, modelToTestAgainst)) {
if (log.isDebugEnabled()) {
log.debug("Last-chance authorization check: "
+ "authorized to add statement: "
+ formatStatement(stmt));
}
} else {
log.warn("Last-chance authorization check reveals not "
+ "authorized to add statement: "
+ formatStatement(stmt));
result = false;
}
}
} finally {
addStmts.close();
}
/*
* For retractions, there is no such conundrum. Assume that all of the
* additions have been added, and check the authorization of each
* retraction.
*/
StmtIterator dropStmts = retractions.listStatements();
try {
while (dropStmts.hasNext()) {
Statement stmt = dropStmts.next();
if (isAuthorizedToDrop(req, stmt, modelToTestAgainst)) {
if (log.isDebugEnabled()) {
log.debug("Last-chance authorization check: "
+ "authorized to drop statement: "
+ formatStatement(stmt));
}
} else {
log.warn("Last-chance authorization check reveals not "
+ "authorized to drop statement: "
+ formatStatement(stmt));
result = false;
}
}
} finally {
dropStmts.close();
}
return result;
}
private static String formatStatement(Statement stmt) {
if (stmt == null) {
return "null statement";
}
return "<" + stmt.getSubject() + "> <" + stmt.getPredicate() + "> <"
+ stmt.getObject() + ">";
}
/**
* No need to instantiate this helper class - all methods are static.
*/
private PolicyHelper() {
// nothing to do.
}
}

View file

@ -0,0 +1,66 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
/**
* This is a List of Policy Objects that implements PolciyIface. The intent
* is to make it easy to query a list of policies for a PolicyDecision.
*
* The Policy objects in the PolicyList are queried for authorization in order
* and return the first AUTHORIZED or UNAUTHROIZED decision. INCONCLUSIVE
* or null decisions will be ignored and the next policy on the list will
* be queried.
*/
public class PolicyList extends ArrayList<PolicyIface> implements PolicyIface{
private static final Log log = LogFactory.getLog(PolicyList.class.getName());
public PolicyList(){
super();
}
public PolicyList(Collection<PolicyIface> policies) {
super(policies);
}
@Override
public PolicyDecision isAuthorized(IdentifierBundle whoToAuth, RequestedAction whatToAuth) {
PolicyDecision pd = null;
PolicyDecisionLogger logger = new PolicyDecisionLogger(whoToAuth, whatToAuth);
for(PolicyIface policy : this){
try{
pd = policy.isAuthorized(whoToAuth, whatToAuth);
logger.log(policy, pd);
if( pd != null ){
if( pd.getAuthorized() == Authorization.AUTHORIZED )
return pd;
if( pd.getAuthorized() == Authorization.UNAUTHORIZED )
return pd;
if( pd.getAuthorized() == Authorization.INCONCLUSIVE )
continue;
} else{
log.debug("policy " + policy.toString() + " returned a null PolicyDecision");
}
}catch(Throwable th){
log.error("ignoring exception in policy " + policy.toString(), th );
}
}
pd = new BasicPolicyDecision(Authorization.INCONCLUSIVE,
"No policy returned a conclusive decision on " + whatToAuth);
logger.logNoDecision(pd);
return pd;
}
}

View file

@ -0,0 +1,71 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
/**
* Allow us to store policies in a Request, in addition to those in the
* ServletContext
*/
public class RequestPolicyList extends PolicyList {
private static final String ATTRIBUTE_POLICY_ADDITIONS = RequestPolicyList.class
.getName();
private static final Log log = LogFactory.getLog(RequestPolicyList.class);
/**
* Get a copy of the current list of policies. This includes the policies in
* the ServletContext, followed by any stored in the request. This method may
* return an empty list, but it never returns null.
*/
public static PolicyList getPolicies(HttpServletRequest request) {
ServletContext ctx = request.getSession().getServletContext();
PolicyList list = ServletPolicyList.getPolicies(ctx);
list.addAll(getPoliciesFromRequest(request));
return list;
}
public static void addPolicy(ServletRequest request, PolicyIface policy) {
PolicyList policies = getPoliciesFromRequest(request);
if (!policies.contains(policy)) {
policies.add(policy);
log.debug("Added policy: " + policy.toString());
} else {
log.warn("Ignored attempt to add redundent policy.");
}
}
/**
* Get the current list of policy additions from the request, or create one
* if there is none. This method may return an empty list, but it never
* returns null.
*/
private static PolicyList getPoliciesFromRequest(ServletRequest request) {
if (request == null) {
throw new NullPointerException("request may not be null.");
}
Object obj = request.getAttribute(ATTRIBUTE_POLICY_ADDITIONS);
if (obj == null) {
obj = new PolicyList();
request.setAttribute(ATTRIBUTE_POLICY_ADDITIONS, obj);
}
if (!(obj instanceof PolicyList)) {
throw new IllegalStateException("Expected to find an instance of "
+ PolicyList.class.getName()
+ " in the context, but found an instance of "
+ obj.getClass().getName() + " instead.");
}
return (PolicyList) obj;
}
}

View file

@ -0,0 +1,70 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractObjectPropertyStatementAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.EditObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary;
/**
* Don't allow user to edit or drop the HomeMenuItem statement.
*/
public class RestrictHomeMenuItemEditingPolicy implements PolicyIface {
@Override
public PolicyDecision isAuthorized(IdentifierBundle whoToAuth,
RequestedAction whatToAuth) {
if (whatToAuth instanceof EditObjectPropertyStatement) {
return isAuthorized((EditObjectPropertyStatement) whatToAuth);
} else if (whatToAuth instanceof DropObjectPropertyStatement) {
return isAuthorized((DropObjectPropertyStatement) whatToAuth);
} else {
return notHandled();
}
}
private PolicyDecision isAuthorized(
AbstractObjectPropertyStatementAction whatToAuth) {
if (whatToAuth.getPredicateUri()
.equals(DisplayVocabulary.HAS_ELEMENT)
&& whatToAuth.getObjectUri().equals(
DisplayVocabulary.HOME_MENU_ITEM)) {
return notAuthorized();
} else {
return notHandled();
}
}
private BasicPolicyDecision notHandled() {
return new BasicPolicyDecision(Authorization.INCONCLUSIVE,
"Doesn't handle this type of request");
}
private BasicPolicyDecision notAuthorized() {
return new BasicPolicyDecision(Authorization.UNAUTHORIZED,
"Can't edit home menu item.");
}
public static class Setup implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletPolicyList.addPolicyAtFront(sce.getServletContext(),
new RestrictHomeMenuItemEditingPolicy());
}
@Override
public void contextDestroyed(ServletContextEvent ctx) {
// Nothing to do here.
}
}
}

View file

@ -0,0 +1,197 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import java.util.TreeSet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.IsRootUser;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* If the user has an IsRootUser identifier, they can do anything!
*
* On setup, check to see that the specified root user exists. If not, create
* it. If we can't create it, abort.
*
* If any other root users exist, warn about them.
*/
public class RootUserPolicy implements PolicyIface {
private static final Log log = LogFactory.getLog(RootUserPolicy.class);
private static final String PROPERTY_ROOT_USER_EMAIL = "rootUser.emailAddress";
private static final String ROOT_USER_INITIAL_PASSWORD = "rootPassword";
/**
* This is the entire policy. If you are a root user, you are authorized.
*/
@Override
public PolicyDecision isAuthorized(IdentifierBundle whoToAuth,
RequestedAction whatToAuth) {
if (IsRootUser.isRootUser(whoToAuth)) {
return new BasicPolicyDecision(Authorization.AUTHORIZED,
"RootUserPolicy: approved");
} else {
return new BasicPolicyDecision(Authorization.INCONCLUSIVE,
"not root user");
}
}
@Override
public String toString() {
return "RootUserPolicy - " + hashCode();
}
// ----------------------------------------------------------------------
// Setup class
// ----------------------------------------------------------------------
public static class Setup implements ServletContextListener {
private ServletContext ctx;
private StartupStatus ss;
private UserAccountsDao uaDao;
private String configuredRootUser;
private boolean configuredRootUserExists;
private TreeSet<String> otherRootUsers;
@Override
public void contextInitialized(ServletContextEvent sce) {
ctx = sce.getServletContext();
ss = StartupStatus.getBean(ctx);
try {
uaDao = ModelAccess.on(ctx).getWebappDaoFactory()
.getUserAccountsDao();
configuredRootUser = getRootEmailFromConfig();
otherRootUsers = getEmailsOfAllRootUsers();
configuredRootUserExists = otherRootUsers
.remove(configuredRootUser);
if (configuredRootUserExists) {
if (otherRootUsers.isEmpty()) {
informThatRootUserExists();
} else {
complainAboutMultipleRootUsers();
}
} else {
createRootUser();
if (!otherRootUsers.isEmpty()) {
complainAboutWrongRootUsers();
}
}
ServletPolicyList.addPolicy(ctx, new RootUserPolicy());
} catch (Exception e) {
ss.fatal(this, "Failed to set up the RootUserPolicy", e);
}
}
private String getRootEmailFromConfig() {
String email = ConfigurationProperties.getBean(ctx).getProperty(
PROPERTY_ROOT_USER_EMAIL);
if (email == null) {
throw new IllegalStateException(
"runtime.properties must contain a value for '"
+ PROPERTY_ROOT_USER_EMAIL + "'");
} else {
return email;
}
}
private TreeSet<String> getEmailsOfAllRootUsers() {
TreeSet<String> rootUsers = new TreeSet<String>();
for (UserAccount ua : uaDao.getAllUserAccounts()) {
if (ua.isRootUser()) {
rootUsers.add(ua.getEmailAddress());
}
}
return rootUsers;
}
/**
* TODO The first and last name should be left blank, so the user will
* be forced to edit them. However, that's not in place yet.
*/
private void createRootUser() {
if (!Authenticator.isValidEmailAddress(configuredRootUser)) {
throw new IllegalStateException("Value for '"
+ PROPERTY_ROOT_USER_EMAIL
+ "' is not a valid email address: '"
+ configuredRootUser + "'");
}
if (null != uaDao.getUserAccountByEmail(configuredRootUser)) {
throw new IllegalStateException("Can't create root user - "
+ "an account already exists with email address '"
+ configuredRootUser + "'");
}
UserAccount ua = new UserAccount();
ua.setEmailAddress(configuredRootUser);
ua.setFirstName("root");
ua.setLastName("user");
ua.setMd5Password(Authenticator
.applyMd5Encoding(ROOT_USER_INITIAL_PASSWORD));
ua.setPasswordChangeRequired(true);
ua.setStatus(Status.ACTIVE);
ua.setRootUser(true);
uaDao.insertUserAccount(ua);
StartupStatus.getBean(ctx).info(this,
"Created root user '" + configuredRootUser + "'");
}
private void informThatRootUserExists() {
ss.info(this, "Root user is " + configuredRootUser);
}
private void complainAboutMultipleRootUsers() {
for (String other : otherRootUsers) {
ss.warning(this, "runtime.properties specifies '"
+ configuredRootUser + "' as the value for '"
+ PROPERTY_ROOT_USER_EMAIL
+ "', but the system also contains this root user: "
+ other);
}
ss.warning(this, "For security, "
+ "it is best to delete unneeded root user accounts.");
}
private void complainAboutWrongRootUsers() {
for (String other : otherRootUsers) {
ss.warning(this, "runtime.properties specifies '"
+ configuredRootUser + "' as the value for '"
+ PROPERTY_ROOT_USER_EMAIL
+ "', but the system contains this root user instead: "
+ other);
}
ss.warning(this, "Creating root user '" + configuredRootUser + "'");
ss.warning(this, "For security, "
+ "it is best to delete unneeded root user accounts.");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// Nothing to destroy
}
}
}

View file

@ -0,0 +1,161 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasAssociatedIndividual;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractDataPropertyStatementAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractObjectPropertyStatementAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.resource.AbstractResourceAction;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
/**
* Policy to use for Vivo Self-Editing based on NetId for use at Cornell. All
* methods in this class should be thread safe and side effect free.
*/
public class SelfEditingPolicy extends BaseSelfEditingPolicy implements
PolicyIface {
public SelfEditingPolicy(ServletContext ctx) {
super(ctx, RoleLevel.SELF);
}
@Override
public PolicyDecision isAuthorized(IdentifierBundle whoToAuth,
RequestedAction whatToAuth) {
if (whoToAuth == null) {
return inconclusiveDecision("whoToAuth was null");
}
if (whatToAuth == null) {
return inconclusiveDecision("whatToAuth was null");
}
List<String> userUris = new ArrayList<String>(
HasAssociatedIndividual.getIndividualUris(whoToAuth));
if (userUris.isEmpty()) {
return inconclusiveDecision("Not self-editing.");
}
if (whatToAuth instanceof AbstractObjectPropertyStatementAction) {
return isAuthorizedForObjectPropertyAction(userUris,
(AbstractObjectPropertyStatementAction) whatToAuth);
}
if (whatToAuth instanceof AbstractDataPropertyStatementAction) {
return isAuthorizedForDataPropertyAction(userUris,
(AbstractDataPropertyStatementAction) whatToAuth);
}
if (whatToAuth instanceof AbstractResourceAction) {
return isAuthorizedForResourceAction((AbstractResourceAction) whatToAuth);
}
return inconclusiveDecision("Does not authorize "
+ whatToAuth.getClass().getSimpleName() + " actions");
}
/**
* The user can edit a object property if it is not restricted and if it is
* about him.
*/
private PolicyDecision isAuthorizedForObjectPropertyAction(
List<String> userUris, AbstractObjectPropertyStatementAction action) {
String subject = action.getSubjectUri();
Property predicate = action.getPredicate();
String object = action.getObjectUri();
if (!canModifyResource(subject)) {
return cantModifyResource(subject);
}
if (!canModifyPredicate(predicate)) {
return cantModifyPredicate(predicate);
}
if (!canModifyResource(object)) {
return cantModifyResource(object);
}
if (userCanEditAsSubjectOrObjectOfStmt(userUris, subject, object)) {
return authorizedDecision("User is subject or object of statement.");
} else {
return userNotAuthorizedToStatement();
}
}
/**
* The user can edit a data property if it is not restricted and if it is
* about him.
*/
private PolicyDecision isAuthorizedForDataPropertyAction(
List<String> userUris, AbstractDataPropertyStatementAction action) {
String subject = action.getSubjectUri();
Property predicate = action.getPredicate();
if (!canModifyResource(subject)) {
return cantModifyResource(subject);
}
if (!canModifyPredicate(predicate)) {
return cantModifyPredicate(predicate);
}
if (userCanEditAsSubjectOfStmt(userUris, subject)) {
return authorizedDecision("User is subject of statement.");
} else {
return userNotAuthorizedToStatement();
}
}
/**
* The user can add or remove resources if they are not restricted.
*/
private PolicyDecision isAuthorizedForResourceAction(
AbstractResourceAction action) {
String uri = action.getSubjectUri();
if (!canModifyResource(uri)) {
return cantModifyResource(uri);
} else {
return authorizedDecision("May add/remove resource.");
}
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
private boolean userCanEditAsSubjectOfStmt(List<String> userUris,
String subject) {
for (String userUri : userUris) {
if (userUri.equals(subject)) {
return true;
}
}
return false;
}
private boolean userCanEditAsSubjectOrObjectOfStmt(List<String> userUris,
String subject, String object) {
for (String userUri : userUris) {
if (userUri.equals(subject)) {
return true;
}
if (userUri.equals(object)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return "SelfEditingPolicy - " + hashCode();
}
}

View file

@ -0,0 +1,122 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy;
import java.util.ListIterator;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
/**
* This maintains a PolicyList in the ServletContext. As a rule, however, this
* is only used as the basis for the RequestPolicyList. Client code that wants
* to access the current list of policies should look there.
*/
public class ServletPolicyList {
private static final String ATTRIBUTE_POLICY_LIST = ServletPolicyList.class.getName();
private static final Log log = LogFactory.getLog(ServletPolicyList.class);
/**
* Get a copy of the current list of policies. This method may return an
* empty list, but it never returns null.
*/
public static PolicyIface getPolicies(HttpServletRequest hreq) {
return getPolicies(hreq.getSession().getServletContext());
}
/**
* Get a copy of the current list of policies. This method may return an
* empty list, but it never returns null.
*/
public static PolicyList getPolicies(ServletContext sc) {
return new PolicyList(getPolicyList(sc));
}
/**
* Add the policy to the end of the list.
*/
public static void addPolicy(ServletContext sc, PolicyIface policy) {
if (policy == null) {
return;
}
PolicyList policies = getPolicyList(sc);
if (!policies.contains(policy)) {
policies.add(policy);
log.debug("Added policy: " + policy.toString());
} else {
log.warn("Ignored attempt to add redundant policy.");
}
}
/**
* Add the policy to the front of the list. It may be moved further down the
* list by other policies that are later added using this method.
*/
public static void addPolicyAtFront(ServletContext sc, PolicyIface policy) {
if (policy == null) {
return;
}
PolicyList policies = getPolicyList(sc);
if (!policies.contains(policy)) {
policies.add(0, policy);
log.debug("Added policy at front: " + policy.toString());
} else {
log.warn("Ignored attempt to add redundant policy.");
}
}
/**
* Replace the first instance of this class of policy in the list. If no
* instance is found, add the policy to the end of the list.
*/
public static void replacePolicy(ServletContext sc, PolicyIface policy) {
if (policy == null) {
return;
}
Class<?> clzz = policy.getClass();
PolicyList policies = getPolicyList(sc);
ListIterator<PolicyIface> it = policies.listIterator();
while (it.hasNext()) {
if (clzz.isAssignableFrom(it.next().getClass())) {
it.set(policy);
return;
}
}
addPolicy(sc, policy);
}
/**
* Get the current PolicyList from the context, or create one if there is
* none. This method may return an empty list, but it never returns null.
*/
private static PolicyList getPolicyList(ServletContext ctx) {
if (ctx == null) {
throw new NullPointerException("ctx may not be null.");
}
Object obj = ctx.getAttribute(ATTRIBUTE_POLICY_LIST);
if (obj == null) {
obj = new PolicyList();
ctx.setAttribute(ATTRIBUTE_POLICY_LIST, obj);
}
if (!(obj instanceof PolicyList)) {
throw new IllegalStateException("Expected to find an instance of "
+ PolicyList.class.getName()
+ " in the context, but found an instance of "
+ obj.getClass().getName() + " instead.");
}
return (PolicyList) obj;
}
}

View file

@ -0,0 +1,207 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.bean;
import java.util.Arrays;
import java.util.Collection;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* Assists the role-based policies in determining whether a property or resource
* may be displayed, modified, or published in linked open data.
*
* There is a singleton bean that holds the current threshold role levels for
* displaying, modifying, or publishing restricted properties.
*
* Create this bean after the context models are in place.
*
* Add PropertyRestrictionListener to your EditProcessObject if you are editing
* a property, to ensure that the bean stays current.
*/
public abstract class PropertyRestrictionBean {
private static final Log log = LogFactory
.getLog(PropertyRestrictionBean.class);
private static final PropertyRestrictionBean NULL = new PropertyRestrictionBeanNull();
protected static volatile PropertyRestrictionBean instance = NULL;
protected static final Collection<String> PROHIBITED_NAMESPACES = Arrays
.asList(new String[] { VitroVocabulary.vitroURI, "" });
protected static final Collection<String> PERMITTED_EXCEPTIONS = Arrays
.asList(new String[] { VitroVocabulary.MONIKER,
VitroVocabulary.MODTIME, VitroVocabulary.IND_MAIN_IMAGE,
VitroVocabulary.LINK, VitroVocabulary.PRIMARY_LINK,
VitroVocabulary.ADDITIONAL_LINK,
VitroVocabulary.LINK_ANCHOR, VitroVocabulary.LINK_URL });
// ----------------------------------------------------------------------
// static methods
// ----------------------------------------------------------------------
public static PropertyRestrictionBean getBean() {
return instance;
}
// ----------------------------------------------------------------------
// instance methods
// ----------------------------------------------------------------------
/**
* Any resource can be displayed.
*
* (Someday we may want to implement display restrictions based on VClass.)
*/
public abstract boolean canDisplayResource(String resourceUri,
RoleLevel userRole);
/**
* A resource cannot be modified if its namespace is in the prohibited list
* (but some exceptions are allowed).
*
* (Someday we may want to implement modify restrictions based on VClass.)
*/
public abstract boolean canModifyResource(String resourceUri,
RoleLevel userRole);
/**
* Any resource can be published.
*
* (Someday we may want to implement publish restrictions based on VClass.)
*/
public abstract boolean canPublishResource(String resourceUri,
RoleLevel userRole);
/**
* If display of a predicate is restricted, the user's role must be at least
* as high as the restriction level.
*/
public abstract boolean canDisplayPredicate(Property predicate,
RoleLevel userRole);
/**
* A predicate cannot be modified if its namespace is in the prohibited list
* (some exceptions are allowed).
*
* If modification of a predicate is restricted, the user's role must be at
* least as high as the restriction level.
*/
public abstract boolean canModifyPredicate(Property predicate,
RoleLevel userRole);
/**
* If publishing of a predicate is restricted, the user's role must be at
* least as high as the restriction level.
*/
public abstract boolean canPublishPredicate(Property predicate,
RoleLevel userRole);
/**
* The threshold values for this property may have changed.
*/
public abstract void updateProperty(PropertyRestrictionLevels levels);
// ----------------------------------------------------------------------
// The null implementation
// ----------------------------------------------------------------------
/**
* A placeholder for when the bean instance is not set.
*/
private static class PropertyRestrictionBeanNull extends
PropertyRestrictionBean {
@Override
public boolean canDisplayResource(String resourceUri, RoleLevel userRole) {
warn();
return false;
}
@Override
public boolean canModifyResource(String resourceUri, RoleLevel userRole) {
warn();
return false;
}
@Override
public boolean canPublishResource(String resourceUri, RoleLevel userRole) {
warn();
return false;
}
@Override
public boolean canDisplayPredicate(Property predicate,
RoleLevel userRole) {
warn();
return false;
}
@Override
public boolean canModifyPredicate(Property predicate, RoleLevel userRole) {
warn();
return false;
}
@Override
public boolean canPublishPredicate(Property predicate,
RoleLevel userRole) {
warn();
return false;
}
@Override
public void updateProperty(PropertyRestrictionLevels levels) {
warn();
}
private void warn() {
try {
throw new IllegalStateException();
} catch (IllegalStateException e) {
log.warn("No PropertyRestrictionBean in place.", e);
}
}
}
// ----------------------------------------------------------------------
// Setup class
// ----------------------------------------------------------------------
/**
* Create the bean at startup and remove it at shutdown.
*/
public static class Setup implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
StartupStatus ss = StartupStatus.getBean(ctx);
try {
instance = new PropertyRestrictionBeanImpl(
PROHIBITED_NAMESPACES, PERMITTED_EXCEPTIONS,
ModelAccess.on(ctx));
} catch (Exception e) {
ss.fatal(this,
"could not set up PropertyRestrictionBean", e);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
instance = NULL;
}
}
}

View file

@ -0,0 +1,252 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.bean;
import static edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionLevels.Which.DISPLAY;
import static edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionLevels.Which.MODIFY;
import static edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionLevels.Which.PUBLISH;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.rdf.model.impl.Util;
import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionLevels.Which;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.beans.DataProperty;
import edu.cornell.mannlib.vitro.webapp.beans.FauxProperty;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
import edu.cornell.mannlib.vitro.webapp.dao.PropertyDao.FullPropertyKey;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess;
/**
* On creation, populate a map of PropertyRestrictionLevels.
*
* When a change is detected, update the map accordingly.
*
* ------------------------------
*
* How is authorization determined?
*
* Resources are easy. If they aren't in a prohibited namespace, or are an
* exception to the prohibition, they are accessible.
*
* Properties are harder. The prohibited namespace and exceptions still apply,
* but if we pass that test, then we check the threshold map.
*
* When a test is made, we look for thresholds in the map. First we look for the
* full key of domain-base-range, in case we are testing a faux property. Faux
* properties are recorded in the map with the full key.
*
* If we don't find the full key, then perhaps we are testing a faux property
* that has no settings, or perhaps we are testing an object property. We look
* for the partial key of null-base-null, which covers both of these cases,
* since object properties (and data properties) are recorded the map with a
* partial key.
*
* Similarly, if we find a null threshold value in the full key, we look back to
* the partial key for a threshold.
*
* If we find no non-null threshold value then the property is unrestricted for
* that feature.
*
* -----------------------------
*
* It would perhaps be a silly optimization, but if we find a key with 3 null
* thresholds, we could remove it from the map without changing the behavior.
*/
public class PropertyRestrictionBeanImpl extends PropertyRestrictionBean {
private static final Log log = LogFactory
.getLog(PropertyRestrictionBeanImpl.class);
private final Set<String> prohibitedNamespaces;
private final Set<String> permittedExceptions;
private final Map<FullPropertyKey, PropertyRestrictionLevels> thresholdMap = new ConcurrentHashMap<>();
public PropertyRestrictionBeanImpl(Collection<String> prohibitedNamespaces,
Collection<String> permittedExceptions, ContextModelAccess models) {
Objects.requireNonNull(prohibitedNamespaces,
"prohibitedNamespaces may not be null.");
this.prohibitedNamespaces = Collections.unmodifiableSet(new TreeSet<>(
prohibitedNamespaces));
Objects.requireNonNull(permittedExceptions,
"permittedExceptions may not be null.");
this.permittedExceptions = Collections.unmodifiableSet(new TreeSet<>(
permittedExceptions));
Objects.requireNonNull(models, "models may not be null.");
populateThresholdMap(models.getWebappDaoFactory());
}
private void populateThresholdMap(WebappDaoFactory wadf) {
for (ObjectProperty oProp : wadf.getObjectPropertyDao()
.getAllObjectProperties()) {
addObjectPropertyToMap(oProp);
for (FauxProperty fProp : wadf.getFauxPropertyDao()
.getFauxPropertiesForBaseUri(oProp.getURI())) {
addFauxPropertyToMap(fProp);
}
}
for (DataProperty dProp : wadf.getDataPropertyDao()
.getAllDataProperties()) {
addDataPropertyToMap(dProp);
}
}
private void addObjectPropertyToMap(ObjectProperty oProp) {
FullPropertyKey key = new FullPropertyKey(oProp.getURI());
PropertyRestrictionLevels levels = new PropertyRestrictionLevels(key,
oProp.getHiddenFromDisplayBelowRoleLevel(),
oProp.getProhibitedFromUpdateBelowRoleLevel(),
oProp.getHiddenFromPublishBelowRoleLevel());
thresholdMap.put(key, levels);
}
private void addFauxPropertyToMap(FauxProperty fProp) {
FullPropertyKey key = new FullPropertyKey(fProp.getDomainURI(),
fProp.getBaseURI(), fProp.getRangeURI());
PropertyRestrictionLevels levels = new PropertyRestrictionLevels(key,
fProp.getHiddenFromDisplayBelowRoleLevel(),
fProp.getProhibitedFromUpdateBelowRoleLevel(),
fProp.getHiddenFromPublishBelowRoleLevel());
thresholdMap.put(key, levels);
}
private void addDataPropertyToMap(DataProperty dProp) {
FullPropertyKey key = new FullPropertyKey(dProp.getURI());
PropertyRestrictionLevels levels = new PropertyRestrictionLevels(key,
dProp.getHiddenFromDisplayBelowRoleLevel(),
dProp.getProhibitedFromUpdateBelowRoleLevel(),
dProp.getHiddenFromPublishBelowRoleLevel());
thresholdMap.put(key, levels);
}
@Override
public boolean canDisplayResource(String resourceUri, RoleLevel userRole) {
return (resourceUri != null) && (userRole != null);
}
@Override
public boolean canModifyResource(String resourceUri, RoleLevel userRole) {
if (resourceUri == null || userRole == null) {
return false;
}
if (prohibitedNamespaces.contains(namespace(resourceUri))
&& !permittedExceptions.contains(resourceUri)) {
return false;
}
return true;
}
@Override
public boolean canPublishResource(String resourceUri, RoleLevel userRole) {
return (resourceUri != null) && (userRole != null);
}
@Override
public boolean canDisplayPredicate(Property predicate, RoleLevel userRole) {
if (predicate == null || predicate.getURI() == null) {
return false;
}
return isAuthorized(userRole, getThreshold(predicate, DISPLAY));
}
@Override
public boolean canModifyPredicate(Property predicate, RoleLevel userRole) {
if (predicate == null || predicate.getURI() == null) {
return false;
}
return isAuthorized(userRole, getPropertyModifyThreshold(predicate));
}
@Override
public boolean canPublishPredicate(Property predicate, RoleLevel userRole) {
if (predicate == null || predicate.getURI() == null) {
return false;
}
return isAuthorized(userRole, getThreshold(predicate, PUBLISH));
}
@Override
public void updateProperty(PropertyRestrictionLevels levels) {
thresholdMap.put(levels.getKey(), levels);
}
private boolean isAuthorized(RoleLevel userRole, RoleLevel thresholdRole) {
if (userRole == null) {
return false;
}
if (thresholdRole == null) {
return true;
}
return userRole.compareTo(thresholdRole) >= 0;
}
private RoleLevel getPropertyModifyThreshold(Property p) {
if (prohibitedNamespaces.contains(namespace(p.getURI()))
&& !permittedExceptions.contains(p.getURI())) {
return RoleLevel.NOBODY;
}
return getThreshold(p, MODIFY);
}
private RoleLevel getThreshold(Property p, Which which) {
RoleLevel qualifiedLevel = getThreshold(new FullPropertyKey(p), which);
if (qualifiedLevel != null) {
return qualifiedLevel;
}
RoleLevel bareLevel = getThreshold(new FullPropertyKey(p.getURI()),
which);
return bareLevel;
}
private RoleLevel getThreshold(FullPropertyKey key, Which which) {
PropertyRestrictionLevels levels = thresholdMap.get(key);
if (levels == null) {
return null;
} else {
return levels.getLevel(which);
}
}
private String namespace(String uri) {
return uri.substring(0, Util.splitNamespace(uri));
}
@Override
public String toString() {
SortedSet<FullPropertyKey> keys = new TreeSet<>(
new Comparator<FullPropertyKey>() {
@Override
public int compare(FullPropertyKey o1, FullPropertyKey o2) {
return o1.toString().compareTo(o2.toString());
}
});
keys.addAll(thresholdMap.keySet());
StringBuilder buffer = new StringBuilder();
for (FullPropertyKey key : keys) {
buffer.append(key + " " + thresholdMap.get(key).getLevel(DISPLAY)
+ " " + thresholdMap.get(key).getLevel(MODIFY) + " "
+ thresholdMap.get(key).getLevel(PUBLISH) + "\n");
}
return buffer.toString();
}
}

View file

@ -0,0 +1,68 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.bean;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.dao.PropertyDao.FullPropertyKey;
/**
* The threshold levels for operations on a given property.
*
* This is based on the assumption that the FullPropertyKey is sufficient to
* distinguish all properties. An object property and a data property may not
* share the same key. A faux property must have a different key from any object
* property.
*/
public class PropertyRestrictionLevels {
private final FullPropertyKey key;
private final RoleLevel displayThreshold;
private final RoleLevel modifyThreshold;
private final RoleLevel publishThreshold;
public enum Which {
DISPLAY, MODIFY, PUBLISH
}
public PropertyRestrictionLevels(FullPropertyKey key,
RoleRestrictedProperty p) {
this(key, p.getHiddenFromDisplayBelowRoleLevel(), p
.getProhibitedFromUpdateBelowRoleLevel(), p
.getHiddenFromPublishBelowRoleLevel());
}
public PropertyRestrictionLevels(FullPropertyKey key,
RoleLevel displayThreshold, RoleLevel modifyThreshold,
RoleLevel publishThreshold) {
this.key = key;
this.displayThreshold = displayThreshold;
this.modifyThreshold = modifyThreshold;
this.publishThreshold = publishThreshold;
}
public FullPropertyKey getKey() {
return key;
}
public RoleLevel getLevel(Which which) {
if (which == null) {
return null;
} else {
switch (which) {
case DISPLAY:
return displayThreshold;
case MODIFY:
return modifyThreshold;
default:
return publishThreshold;
}
}
}
@Override
public String toString() {
return "PropertyRestrictionLevels[key=" + key + ", display="
+ displayThreshold + ", modify=" + modifyThreshold
+ ", publish=" + publishThreshold + "]";
}
}

View file

@ -0,0 +1,67 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.bean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vedit.beans.EditProcessObject;
import edu.cornell.mannlib.vedit.listener.ChangeListener;
import edu.cornell.mannlib.vitro.webapp.dao.PropertyDao.FullPropertyKey;
/**
* Add this ChangeListener to your EditProcessObject when modifying the
* ontology, and we will refresh the PropertyRestrictionPolicyHelper bean as
* appropriate.
*/
public class PropertyRestrictionListener implements ChangeListener {
private static final Log log = LogFactory
.getLog(PropertyRestrictionListener.class);
/**
* If the deleted property had a non-null restriction, rebuild the bean.
*/
@Override
public void doDeleted(Object oldObj, EditProcessObject epo) {
if (oldObj instanceof RoleRestrictedProperty) {
RoleRestrictedProperty p = (RoleRestrictedProperty) oldObj;
FullPropertyKey key = new FullPropertyKey(p);
updateLevels(new PropertyRestrictionLevels(key, p));
} else {
log.warn("Not an instance of RoleRestrictedProperty: " + oldObj);
}
}
/**
* Update the inserted property.
*/
@Override
public void doInserted(Object newObj, EditProcessObject epo) {
if (newObj instanceof RoleRestrictedProperty) {
RoleRestrictedProperty p = (RoleRestrictedProperty) newObj;
FullPropertyKey key = new FullPropertyKey(p);
updateLevels(new PropertyRestrictionLevels(key, p));
} else {
log.warn("Not an instance of RoleRestrictedProperty: " + newObj);
}
}
/**
* Update the changed property.
*/
@Override
public void doUpdated(Object oldObj, Object newObj, EditProcessObject epo) {
if (newObj instanceof RoleRestrictedProperty) {
RoleRestrictedProperty newP = (RoleRestrictedProperty) newObj;
FullPropertyKey key = new FullPropertyKey(newP);
updateLevels(new PropertyRestrictionLevels(key, newP));
} else {
log.warn("Not instances of RoleRestrictedProperty: " + oldObj
+ ", " + newObj);
}
}
private void updateLevels(PropertyRestrictionLevels levels) {
PropertyRestrictionBean.getBean().updateProperty(levels);
}
}

View file

@ -0,0 +1,23 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.bean;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
/**
* A property or faux property whose usage can be restricted according to the
* user's role level.
*/
public interface RoleRestrictedProperty {
String getDomainVClassURI();
String getRangeVClassURI();
String getURI();
RoleLevel getHiddenFromDisplayBelowRoleLevel();
RoleLevel getProhibitedFromUpdateBelowRoleLevel();
RoleLevel getHiddenFromPublishBelowRoleLevel();
}

View file

@ -0,0 +1,10 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces;
public enum Authorization {
AUTHORIZED, //explicitly authorized
UNAUTHORIZED, //explicitly not authorized
INCONCLUSIVE;
}

View file

@ -0,0 +1,16 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces;
/**
* Object to represent a decision from a policy. The intent is
* that the message would be presented to users to indicate why
* they are not authorized for some action.
*/
public interface PolicyDecision {
public Authorization getAuthorized();
public String getStackTrace();
public String getMessage();
public String getDebuggingInfo();
}

View file

@ -0,0 +1,19 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
/**
* Represents the process of mapping an identifier that represents a user or
* principle and a action they are requesting to true, representing authorized or
* false, representing unauthorized.
*
* @author bdc34
*
*/
public interface PolicyIface {
public PolicyDecision isAuthorized(IdentifierBundle whoToAuth, RequestedAction whatToAuth);
}

View file

@ -0,0 +1,62 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.setup;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ActiveIdentifierBundleFactories;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundleFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.factory.HasPermissionFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.factory.HasPermissionSetFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.factory.HasProfileOrIsBlacklistedFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.factory.HasProxyEditingRightsFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.factory.IsRootUserFactory;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.factory.IsUserFactory;
import edu.cornell.mannlib.vitro.webapp.auth.policy.DisplayRestrictedDataToSelfPolicy;
import edu.cornell.mannlib.vitro.webapp.auth.policy.PermissionsPolicy;
import edu.cornell.mannlib.vitro.webapp.auth.policy.SelfEditingPolicy;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ServletPolicyList;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
/**
* Set up the common policy family, with Identifier factories.
*/
public class CommonPolicyFamilySetup implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
StartupStatus ss = StartupStatus.getBean(ctx);
try {
policy(ctx, new PermissionsPolicy());
policy(ctx, new DisplayRestrictedDataToSelfPolicy(ctx));
policy(ctx, new SelfEditingPolicy(ctx));
factory(ctx, new IsUserFactory(ctx));
factory(ctx, new IsRootUserFactory(ctx));
factory(ctx, new HasProfileOrIsBlacklistedFactory(ctx));
factory(ctx, new HasPermissionSetFactory(ctx));
factory(ctx, new HasPermissionFactory(ctx));
factory(ctx, new HasProxyEditingRightsFactory(ctx));
} catch (Exception e) {
ss.fatal(this, "could not run CommonPolicyFamilySetup", e);
}
}
private void policy(ServletContext ctx, PolicyIface policy) {
ServletPolicyList.addPolicy(ctx, policy);
}
private void factory(ServletContext ctx, IdentifierBundleFactory factory) {
ActiveIdentifierBundleFactories.addFactory(ctx, factory);
}
@Override
public void contextDestroyed(ServletContextEvent sce) { /* nothing */
}
}

View file

@ -0,0 +1,63 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.specialrelationships;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.policy.BasicPolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionBean;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
/**
* A collection of building-block methods so we can code a policy based on the
* relationship of the object being edited to the identity of the user doing the
* editing.
*/
public abstract class AbstractRelationshipPolicy implements PolicyIface {
private static final Log log = LogFactory
.getLog(AbstractRelationshipPolicy.class);
protected final ServletContext ctx;
public AbstractRelationshipPolicy(ServletContext ctx) {
this.ctx = ctx;
}
protected boolean canModifyResource(String uri) {
return PropertyRestrictionBean.getBean().canModifyResource(uri,
RoleLevel.SELF);
}
protected boolean canModifyPredicate(Property predicate) {
return PropertyRestrictionBean.getBean().canModifyPredicate(predicate,
RoleLevel.SELF);
}
protected PolicyDecision cantModifyResource(String uri) {
return inconclusiveDecision("No access to admin resources; cannot modify "
+ uri);
}
protected PolicyDecision cantModifyPredicate(String uri) {
return inconclusiveDecision("No access to admin predicates; cannot modify "
+ uri);
}
protected PolicyDecision userNotAuthorizedToStatement() {
return inconclusiveDecision("User has no access to this statement.");
}
/** An INCONCLUSIVE decision with a message like "PolicyClass: message". */
protected PolicyDecision inconclusiveDecision(String message) {
return new BasicPolicyDecision(Authorization.INCONCLUSIVE, getClass()
.getSimpleName() + ": " + message);
}
}

View file

@ -0,0 +1,205 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.policy.specialrelationships;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Selector;
import com.hp.hpl.jena.rdf.model.SimpleSelector;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.shared.Lock;
import edu.cornell.mannlib.vitro.webapp.auth.policy.BasicPolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
/**
* Look for relationships within an OntModel. Types of resources, links between
* resources, and links between resources via a context node.
*
* Also provides some convenience methods for test lists of URIs and for
* creating PolicyDecisions.
*/
public class RelationshipChecker {
private static final Log log = LogFactory.getLog(RelationshipChecker.class);
protected static final String NS_CORE = "http://vivoweb.org/ontology/core#";
protected static final String NS_OBO = "http://purl.obolibrary.org/obo/";
protected static final String URI_RELATES = NS_CORE + "relates";
protected static final String URI_RELATED_BY = NS_CORE + "relatedBy";
protected static final String URI_INHERES_IN = NS_OBO + "RO_0000052";
protected static final String URI_REALIZES = NS_OBO + "BFO_0000055";
private final OntModel ontModel;
public RelationshipChecker(OntModel ontModel) {
this.ontModel = ontModel;
}
/**
* Are there any URIs that appear in both of these lists?
*/
public boolean anyUrisInCommon(List<String> list1, List<String> list2) {
List<String> urisInCommon = new ArrayList<String>(list1);
urisInCommon.retainAll(list2);
return !urisInCommon.isEmpty();
}
/**
* Is this resource a member of this type? That is, is there an statement of
* the form: <resourceUri> rdfs:type <typeUri>
*/
public boolean isResourceOfType(String resourceUri, String typeUri) {
Selector selector = createSelector(resourceUri,
VitroVocabulary.RDF_TYPE, typeUri);
StmtIterator stmts = null;
ontModel.enterCriticalSection(Lock.READ);
try {
stmts = ontModel.listStatements(selector);
if (stmts.hasNext()) {
log.debug("resource '" + resourceUri + "' is of type '"
+ typeUri + "'");
return true;
} else {
log.debug("resource '" + resourceUri + "' is not of type '"
+ typeUri + "'");
return false;
}
} finally {
if (stmts != null) {
stmts.close();
}
ontModel.leaveCriticalSection();
}
}
/**
* Get a list of the object URIs that satisfy this statement:
*
* <resourceUri> <propertyUri> <objectUri>
*
* May return an empty list, but never returns null.
*/
public List<String> getObjectsOfProperty(String resourceUri,
String propertyUri) {
List<String> list = new ArrayList<String>();
Selector selector = createSelector(resourceUri, propertyUri, null);
StmtIterator stmts = null;
ontModel.enterCriticalSection(Lock.READ);
try {
stmts = ontModel.listStatements(selector);
while (stmts.hasNext()) {
list.add(stmts.next().getObject().toString());
}
log.debug("Objects of property '" + propertyUri + "' on resource '"
+ resourceUri + "': " + list);
return list;
} finally {
if (stmts != null) {
stmts.close();
}
ontModel.leaveCriticalSection();
}
}
/**
* Get a list of the object URIs that satisfy these statements:
*
* <resourceUri> <linkUri> <contextNodeUri>
*
* <contextNodeUri> <propertyUri> <objectUri>
*
* May return an empty list, but never returns null.
*/
public List<String> getObjectsOfLinkedProperty(String resourceUri,
String linkUri, String propertyUri) {
List<String> list = new ArrayList<String>();
Selector selector = createSelector(resourceUri, linkUri, null);
StmtIterator stmts = null;
ontModel.enterCriticalSection(Lock.READ);
try {
stmts = ontModel.listStatements(selector);
while (stmts.hasNext()) {
RDFNode contextNode = stmts.next().getObject();
if (contextNode.isResource()) {
log.debug("found context node for '" + resourceUri + "': "
+ contextNode);
list.addAll(getObjectsOfProperty(contextNode.asResource()
.getURI(), propertyUri));
}
}
log.debug("Objects of linked properties '" + linkUri + "' ==> '"
+ propertyUri + "' on '" + resourceUri + "': " + list);
return list;
} finally {
if (stmts != null) {
stmts.close();
}
ontModel.leaveCriticalSection();
}
}
/**
* Get a list of URIs for object that link to the specified resource, by
* means of the specified properties, through a linking node of the
* specified type.
*
* So we're looking for object URIs that statisfy these statements:
*
* <resourceUri> <property1Uri> <linkNodeUri>
*
* <linkNodeUri> rdfs:type <linkNodeTypeUri>
*
* <linkNodeUri> <property2Uri> <objectUri>
*/
public List<String> getObjectsThroughLinkingNode(String resourceUri,
String property1Uri, String linkNodeTypeUri, String property2Uri) {
List<String> list = new ArrayList<String>();
for (String linkNodeUri : getObjectsOfProperty(resourceUri, property1Uri)) {
if (isResourceOfType(linkNodeUri, linkNodeTypeUri)) {
list.addAll(getObjectsOfProperty(linkNodeUri, property2Uri));
}
}
return list;
}
public Selector createSelector(String subjectUri, String predicateUri,
String objectUri) {
Resource subject = (subjectUri == null) ? null : ontModel
.getResource(subjectUri);
return createSelector(subject, predicateUri, objectUri);
}
public Selector createSelector(Resource subject, String predicateUri,
String objectUri) {
Property predicate = (predicateUri == null) ? null : ontModel
.getProperty(predicateUri);
RDFNode object = (objectUri == null) ? null : ontModel
.getResource(objectUri);
return new SimpleSelector(subject, predicate, object);
}
/** An AUTHORIZED decision with a message like "PolicyClass: message". */
protected PolicyDecision authorizedDecision(String message) {
return new BasicPolicyDecision(Authorization.AUTHORIZED, getClass()
.getSimpleName() + ": " + message);
}
}

View file

@ -0,0 +1,125 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.requestedAction;
import java.util.Arrays;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
/**
* A base class for RequestedAction that permits boolean operations on them.
*
* A null request is ignored, so in "and" it is equivalent to true, while in
* "or" it is equivalent to false.
*/
public abstract class AuthorizationRequest {
// ----------------------------------------------------------------------
// Constants
// ----------------------------------------------------------------------
public static final AuthorizationRequest AUTHORIZED = new AuthorizationRequest() {
@Override
public boolean isAuthorized(IdentifierBundle ids, PolicyIface policy) {
return true;
}
};
public static final AuthorizationRequest UNAUTHORIZED = new AuthorizationRequest() {
@Override
public boolean isAuthorized(IdentifierBundle ids, PolicyIface policy) {
return false;
}
};
// ----------------------------------------------------------------------
// Static convenience methods
// ----------------------------------------------------------------------
public static AuthorizationRequest andAll(AuthorizationRequest... ars) {
return andAll(Arrays.asList(ars));
}
public static AuthorizationRequest andAll(
Iterable<? extends AuthorizationRequest> ars) {
AuthorizationRequest result = AUTHORIZED;
for (AuthorizationRequest ar : ars) {
result = result.and(ar);
}
return result;
}
// ----------------------------------------------------------------------
// The abstract class
// ----------------------------------------------------------------------
public AuthorizationRequest and(AuthorizationRequest that) {
if (that == null) {
return this;
} else {
return new AndAuthorizationRequest(this, that);
}
}
public AuthorizationRequest or(AuthorizationRequest that) {
if (that == null) {
return this;
} else {
return new OrAuthorizationRequest(this, that);
}
}
public abstract boolean isAuthorized(IdentifierBundle ids,
PolicyIface policy);
// ----------------------------------------------------------------------
// Subclasses for boolean operations
// ----------------------------------------------------------------------
private static class AndAuthorizationRequest extends AuthorizationRequest {
private final AuthorizationRequest ar1;
private final AuthorizationRequest ar2;
private AndAuthorizationRequest(AuthorizationRequest ar1,
AuthorizationRequest ar2) {
this.ar1 = ar1;
this.ar2 = ar2;
}
@Override
public boolean isAuthorized(IdentifierBundle ids, PolicyIface policy) {
return ar1.isAuthorized(ids, policy)
&& ar2.isAuthorized(ids, policy);
}
@Override
public String toString() {
return "(" + ar1 + " && " + ar2 + ")";
}
}
private static class OrAuthorizationRequest extends AuthorizationRequest {
private final AuthorizationRequest ar1;
private final AuthorizationRequest ar2;
private OrAuthorizationRequest(AuthorizationRequest ar1,
AuthorizationRequest ar2) {
this.ar1 = ar1;
this.ar2 = ar2;
}
@Override
public boolean isAuthorized(IdentifierBundle ids, PolicyIface policy) {
return ar1.isAuthorized(ids, policy)
|| ar2.isAuthorized(ids, policy);
}
@Override
public String toString() {
return "(" + ar1 + " || " + ar2 + ")";
}
}
}

View file

@ -0,0 +1,41 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.requestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
/* Represents a request to perform an action. */
public abstract class RequestedAction extends AuthorizationRequest {
public static String ACTION_NAMESPACE = "java:";
public static String SOME_URI = "?SOME_URI";
public static Property SOME_PREDICATE = new Property(SOME_URI);
public static String SOME_LITERAL = "?SOME_LITERAL";
/**
* In its most basic form, a RequestAction needs to have an identifier.
* Sometimes this will be enough.
*/
public String getURI() {
return ACTION_NAMESPACE + this.getClass().getName();
}
/**
* For authorization, just ask the Policy. INCONCLUSIVE is not good enough.
*/
@Override
public final boolean isAuthorized(IdentifierBundle ids, PolicyIface policy) {
PolicyDecision decision = policy.isAuthorized(ids, this);
return decision.getAuthorized() == Authorization.AUTHORIZED;
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}

View file

@ -0,0 +1,48 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.requestedAction;
/**
* A RequestedAction that can be recognized by a SimplePermission.
*/
public class SimpleRequestedAction extends RequestedAction {
private final String uri;
public SimpleRequestedAction(String uri) {
if (uri == null) {
throw new NullPointerException("uri may not be null.");
}
this.uri = uri;
}
@Override
public String getURI() {
return uri;
}
@Override
public int hashCode() {
return uri.hashCode();
}
@Override
public boolean equals(Object o) {
if (o instanceof SimpleRequestedAction) {
SimpleRequestedAction that = (SimpleRequestedAction) o;
return equivalent(this.uri, that.uri);
}
return false;
}
private boolean equivalent(Object o1, Object o2) {
return (o1 == null) ? (o2 == null) : o1.equals(o2);
}
@Override
public String toString() {
return "SimpleRequestedAction['" + uri + "']";
}
}

View file

@ -0,0 +1,11 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.admin;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.AdminRequestedAction;
/** Should we allow the user to create a user account? */
public class AddNewUser extends RequestedAction implements AdminRequestedAction{
// no members
}

View file

@ -0,0 +1,19 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.admin;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.AdminRequestedAction;
/** Should we allow the user to load an ontology? */
public class LoadOntology extends RequestedAction implements AdminRequestedAction{
protected String ontologyUrl;
public String getOntologyUrl() {
return ontologyUrl;
}
public void setOntologyUrl(String ontologyUrl) {
this.ontologyUrl = ontologyUrl;
}
}

View file

@ -0,0 +1,10 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.auth.requestedAction.admin;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.RequestedAction;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.AdminRequestedAction;
public class RebuildTextIndex extends RequestedAction implements AdminRequestedAction{
// no members
}

Some files were not shown because too many files have changed in this diff Show more