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