001/* 002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 * $Id: ActionService.java 28460 2008-01-03 15:34:05Z sfermigier $ 018 */ 019 020package org.nuxeo.ecm.platform.actions; 021 022import java.util.ArrayList; 023import java.util.Iterator; 024import java.util.List; 025 026import org.apache.commons.logging.Log; 027import org.apache.commons.logging.LogFactory; 028import org.nuxeo.ecm.platform.actions.ejb.ActionManager; 029import org.nuxeo.runtime.model.ComponentContext; 030import org.nuxeo.runtime.model.ComponentInstance; 031import org.nuxeo.runtime.model.ComponentName; 032import org.nuxeo.runtime.model.DefaultComponent; 033 034/** 035 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 036 */ 037public class ActionService extends DefaultComponent implements ActionManager { 038 039 public static final ComponentName ID = new ComponentName("org.nuxeo.ecm.platform.actions.ActionService"); 040 041 private static final long serialVersionUID = -5256555810901945824L; 042 043 private static final Log log = LogFactory.getLog(ActionService.class); 044 045 private ActionContributionHandler actions; 046 047 private FilterContributionHandler filters; 048 049 @Override 050 public void activate(ComponentContext context) { 051 filters = new FilterContributionHandler(); 052 actions = new ActionContributionHandler(filters); 053 } 054 055 @Override 056 public void deactivate(ComponentContext context) { 057 actions = null; 058 filters = null; 059 } 060 061 /** 062 * Return the action registry 063 * 064 * @deprecated since 5.5: use interface methods on ActionManager instead of public methods on ActionService. 065 */ 066 @Deprecated 067 public final ActionRegistry getActionRegistry() { 068 return actions.getRegistry(); 069 } 070 071 /** 072 * Return the action filter registry 073 * 074 * @deprecated since 5.5: use interface methods on ActionManager instead of public methods on ActionService. 075 */ 076 @Deprecated 077 public final ActionFilterRegistry getFilterRegistry() { 078 return filters.getRegistry(); 079 } 080 081 private void applyFilters(ActionContext context, List<Action> actions) { 082 Iterator<Action> it = actions.iterator(); 083 while (it.hasNext()) { 084 Action action = it.next(); 085 if (!checkFilters(context, action)) { 086 it.remove(); 087 } 088 } 089 } 090 091 private boolean checkFilters(ActionContext context, Action action) { 092 if (action == null) { 093 return false; 094 } 095 if (log.isDebugEnabled()) { 096 log.debug(String.format("Checking access for action '%s'...", action.getId())); 097 } 098 099 boolean granted = checkFilters(action, action.getFilterIds(), context); 100 if (granted) { 101 if (log.isDebugEnabled()) { 102 log.debug(String.format("Granting access for action '%s'", action.getId())); 103 } 104 } else { 105 if (log.isDebugEnabled()) { 106 log.debug(String.format("Denying access for action '%s'", action.getId())); 107 } 108 } 109 return granted; 110 } 111 112 @Override 113 public List<Action> getActions(String category, ActionContext context) { 114 return getActions(category, context, true); 115 } 116 117 @Override 118 public List<Action> getAllActions(String category) { 119 return getActionRegistry().getActions(category); 120 } 121 122 @Override 123 public List<Action> getActions(String category, ActionContext context, boolean hideUnavailableActions) { 124 List<Action> actions = getActionRegistry().getActions(category); 125 if (hideUnavailableActions) { 126 applyFilters(context, actions); 127 return actions; 128 } else { 129 List<Action> allActions = new ArrayList<Action>(); 130 allActions.addAll(actions); 131 applyFilters(context, actions); 132 133 for (Action a : allActions) { 134 a.setAvailable(actions.contains(a)); 135 } 136 return allActions; 137 } 138 } 139 140 @Override 141 public Action getAction(String actionId, ActionContext context, boolean hideUnavailableAction) { 142 Action action = getActionRegistry().getAction(actionId); 143 if (action != null) { 144 if (hideUnavailableAction) { 145 if (!checkFilters(context, action)) { 146 return null; 147 } 148 } else { 149 if (!checkFilters(context, action)) { 150 action.setAvailable(false); 151 } 152 } 153 } 154 return action; 155 } 156 157 @Override 158 public Action getAction(String actionId) { 159 return getActionRegistry().getAction(actionId); 160 } 161 162 @Override 163 public boolean isRegistered(String actionId) { 164 return getActionRegistry().getAction(actionId) != null; 165 } 166 167 @Override 168 public boolean isEnabled(String actionId, ActionContext context) { 169 Action action = getActionRegistry().getAction(actionId); 170 if (action != null) { 171 return isEnabled(action, context); 172 } 173 return false; 174 } 175 176 public boolean isEnabled(Action action, ActionContext context) { 177 ActionFilterRegistry filterReg = getFilterRegistry(); 178 for (String filterId : action.getFilterIds()) { 179 ActionFilter filter = filterReg.getFilter(filterId); 180 if (filter != null && !filter.accept(action, context)) { 181 return false; 182 } 183 } 184 return true; 185 } 186 187 @Override 188 public ActionFilter[] getFilters(String actionId) { 189 Action action = getActionRegistry().getAction(actionId); 190 if (action == null) { 191 return null; 192 } 193 ActionFilterRegistry filterReg = getFilterRegistry(); 194 List<String> filterIds = action.getFilterIds(); 195 if (filterIds != null && !filterIds.isEmpty()) { 196 ActionFilter[] filters = new ActionFilter[filterIds.size()]; 197 for (int i = 0; i < filters.length; i++) { 198 String filterId = filterIds.get(i); 199 filters[i] = filterReg.getFilter(filterId); 200 } 201 return filters; 202 } 203 return null; 204 } 205 206 @Override 207 public boolean checkFilter(String filterId, ActionContext context) { 208 ActionFilterRegistry filterReg = getFilterRegistry(); 209 ActionFilter filter = filterReg.getFilter(filterId); 210 if (filter == null) { 211 return false; 212 } 213 return filter.accept(null, context); 214 } 215 216 @Override 217 public boolean checkFilters(List<String> filterIds, ActionContext context) { 218 return checkFilters(null, filterIds, context); 219 } 220 221 protected boolean checkFilters(Action action, List<String> filterIds, ActionContext context) { 222 ActionFilterRegistry filterReg = getFilterRegistry(); 223 for (String filterId : filterIds) { 224 ActionFilter filter = filterReg.getFilter(filterId); 225 if (filter == null) { 226 continue; 227 } 228 if (!filter.accept(action, context)) { 229 // denying filter found => ignore following filters 230 if (log.isDebugEnabled()) { 231 log.debug(String.format("Filter '%s' denied access", filterId)); 232 } 233 return false; 234 } 235 if (log.isDebugEnabled()) { 236 log.debug(String.format("Filter '%s' granted access", filterId)); 237 } 238 } 239 return true; 240 } 241 242 @Override 243 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 244 if ("actions".equals(extensionPoint)) { 245 actions.addContribution((Action) contribution); 246 } else if ("filters".equals(extensionPoint)) { 247 if (contribution.getClass() == FilterFactory.class) { 248 registerFilterFactory((FilterFactory) contribution); 249 } else { 250 filters.addContribution((DefaultActionFilter) contribution); 251 } 252 } else if ("typeCompatibility".equals(extensionPoint)) { 253 actions.getRegistry().getTypeCategoryRelations().add((TypeCompatibility) contribution); 254 } 255 } 256 257 @Override 258 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 259 if ("actions".equals(extensionPoint)) { 260 actions.removeContribution((Action) contribution); 261 } else if ("filters".equals(extensionPoint)) { 262 if (contribution.getClass() == FilterFactory.class) { 263 unregisterFilterFactory((FilterFactory) contribution); 264 } else { 265 filters.removeContribution((DefaultActionFilter) contribution); 266 } 267 } 268 } 269 270 /** 271 * @deprecated seems not used in Nuxeo - should be removed - and anyway the merge is not done 272 * @param ff 273 */ 274 @Deprecated 275 protected void registerFilterFactory(FilterFactory ff) { 276 getFilterRegistry().removeFilter(ff.id); 277 try { 278 ActionFilter filter = (ActionFilter) Thread.currentThread().getContextClassLoader().loadClass(ff.className).newInstance(); 279 filter.setId(ff.id); 280 getFilterRegistry().addFilter(filter); 281 } catch (ReflectiveOperationException e) { 282 log.error("Failed to create action filter", e); 283 } 284 } 285 286 /** 287 * @deprecated seems not used in Nuxeo - should be removed - and anyway the merge is not done 288 * @param ff 289 */ 290 @Deprecated 291 public void unregisterFilterFactory(FilterFactory ff) { 292 getFilterRegistry().removeFilter(ff.id); 293 } 294 295 @Override 296 public void remove() { 297 } 298 299}